import numpy as np
import scipy.sparse
import scipy.optimize
import struct
class SoftMax(object):
"""docstring for """
def __init__(self, num_feature, num_class, lamda):
"""构成函数
Args:
num_feature:int类型;表示每张图片特征点的个数
num_class:int类型;表示总共有多少类别
lamda:float类型;衰减因子
"""
self.num_feature=num_feature
self.num_class=num_class
self.lamda=lamda
self.theta=np.zeros((num_feature,num_class))
def ground_truth(self,lables):
"""将标签转换成ground truth矩阵
Args:
lables:ndarray类型(num_sample*1);表示mnist每张图像对应的标签
Returns:
dataset:ndarray类型,(num_sample*10);矩阵的行代表每一个样本,列表示从0~9,矩阵的值位1表示该样本的值是1对应的列数
"""
num_sample=lables.shape[0]
col=lables.flatten()
row=np.arange(num_sample)
data=np.ones(num_sample)
ground_truth=scipy.sparse.csr_matrix((data,(row,col)))
ground_truth=np.array(ground_truth.todense())
return ground_truth
def softmax_h(self,theta,input):
"""获得假设函数h
Args:
theta:ndarray类型,(num_feature*10);表示theta
input:ndarray类型,(num_sample*num_feature);表示输入数据
Returns:
h:ndarray类型,(num_sample*10);矩阵的每行对应的是该样本是0~9(就是第几列)的概率分别是多少
"""
num_sample=input.shape[0]
m=np.dot(input,theta)
m-=np.max(m,1).reshape(num_sample,1)
e=np.exp(m)
h=e/np.sum(e,1).reshape(num_sample,1)
return h
def softmax_cost(self,theta,input,lables):
"""构建损失函数
Args:
theta:ndarray类型,(num_feature*10);表示theta
input:ndarray类型,(num_sample*num_feature);表示输入数据
lables:ndarray类型(num_sample*1);表示mnist每张图像对应的标签
Returns:
cost:float类型;表示总的损失
theta:ndarray类型,(num_feature*10);表示更新后的theta
"""
num_sample=lables.shape[0]
ground_truth=self.ground_truth(lables)
theta=theta.reshape(self.num_feature,self.num_class)
h=self.softmax_h(theta,input)
cost=-(np.sum(ground_truth*np.log(h)))/num_sample+0.5*self.lamda*np.sum(theta**2)
grad_theta=-np.dot(input.T,ground_truth-h)/num_sample+self.lamda*theta
grad_theta=grad_theta.flatten()
return [cost,grad_theta]
def softmax_test(self,theta,input,lables):
"""构建损失函数
Args:
theta:ndarray类型,(num_feature*10);表示theta
input:ndarray类型,(num_sample*num_feature);表示输入数据
lables:ndarray类型(num_sample*1);表示mnist每张图像对应的标签
Returns:
accuracy:float类型;表示在测试数据上,学到的模型的正确率
"""
num_sample=lables.shape[0]
h=self.softmax_h(theta,input)
res=np.argmax(h,axis=1).reshape(num_sample,1)
accuracy=np.sum(res==lables)/float(num_sample)
return accuracy
def load_mnist_image(filename):
"""获取mnist图像的特征信息
Args:
filename:str类型;表示mnist图像数据的文件名
Returns:
dataset:ndarray类型,(num_images*784);矩阵的每一行代表一个图像信息
"""
image_file = open(filename, 'rb')
buf=image_file.read()
image_file.close()
index = 0
magic, num_images , num_rows , num_cols = struct.unpack_from('>IIII' , buf , index)
num_feature=num_rows*num_cols
index += struct.calcsize('>IIII')
dataset=np.zeros((num_images,num_feature))
for i in range(0,num_images):
im = struct.unpack_from('>784B' ,buf, index)
index += struct.calcsize('>784B')
im=np.array(im)
dataset[i,:]=im
dataset=dataset/255
return dataset
def load_mnist_labels(filename):
"""获取mnist图像标签的数据
Args:
filename:str类型;表示mnist图像标签的文件名
Returns:
dataset:ndarray类型,(num_images*1);矩阵的每一行代表一个图像表示的数值
"""
image_file = open(filename, 'rb')
buf=image_file.read()
image_file.close()
index = 0
magic, num_labels = struct.unpack_from('>II' , buf , index)
index += struct.calcsize('>II')
lens='>'+str(num_labels)+'B'
labels=struct.unpack_from(lens ,buf, index)
labels=np.array(labels).reshape(num_labels,1)
return labels
num_feature=784
num_class=10
lamda=1e-4
max_iterations = 100
train_images = load_mnist_image('./data/train-images.idx3-ubyte')
train_labels = load_mnist_labels('./data/train-labels.idx1-ubyte')
softmax_model=SoftMax(num_feature,num_class,lamda)
opt_solution = scipy.optimize.minimize(softmax_model.softmax_cost, softmax_model.theta,
args = (train_images, train_labels), method = 'L-BFGS-B',
jac = True, options = {'maxiter': max_iterations})
opt_theta = opt_solution.x.reshape(num_feature,num_class)
test_images = load_mnist_image('./data/t10k-images.idx3-ubyte')
test_labels = load_mnist_labels('./data/t10k-labels.idx1-ubyte')
accuracy=softmax_model.softmax_test(opt_theta,test_images,test_labels)
print accuracy