CS231N assignment3 SoftMax
CS231N Assignment3 SoftMax
Begin
本文主要介绍CS231N系列课程的第三项作业,写一个SoftMax损失的线形训练模型。
课程主页:网易云课堂CS231N系列课程
语言:Python3.6
系统:Windows10
1 SoftMax分类器
简单介绍SoftMax,它和SVM都是比较常用的线形分类器,SoftMax最终得到的损失是
反应每个分类的概率大小。如下所示:
最左边蓝色框为每个分类的分数,我们取exp可以得到红色框,再归一化得到最右边绿色
的框,标准化的值就反应它的概率情况,我们再取它的-log得到我们要的损失值。
softmax到底什么含义呢?我查了一下,一般直接max取值使直接取最大值,softmax将
其转变为概率问题,这样就会考察概率情况,更加合理~~~emmm机器学习知识还不太好,等
我再看看书多补充点解释。
2 softmax梯度
前文解释了前向传播,计算损失,训练一个模型,还需要找到梯度,如何计算梯度呢?
下图是我写的一个计算,emmm懒得敲公式
然后在网易云课堂上,写了说要考虑一个稳定性问题~~~让每一个分数值都减去最大值,
那么每个分数都变为了复数,也就到了左半轴,这样指数函数变化率就会减小。emmm
大概使考虑这样就稳定了
3 代码部分
由于都是线形分类器,所以代码的训练、预测部分都是一样的,不同的在于损失函数
的求解以及梯度的计算。如下为损失函数的计算部分
def loss(self,W,X,Y,reg):
loss = 0.0
num_train = X.shape[0]
dW = np.zeros(W.shape)
#计算分数
scores = X.dot(W)
scores = scores - np.max(scores,axis=1,keepdims=True)
#取score的exp
exp_scores = np.exp(scores)
#求行和,得到Pk的底
sum_row = np.sum(exp_scores,axis = 1,keepdims=True)
#相除得到Pk
P = exp_scores / sum_row
#计算Loss
loss = -1.0 / num_train * np.log(P[np.arange(num_train),Y]).sum()
loss += 0.5 * reg * np.sum(W*W)
#计算Dw梯度
grad = np.zeros_like(P)#生成一个和P一样的0矩阵
grad[np.arange(num_train),Y] = 1#对矩阵中Y所对应的部分加一个1,因为一会要剪
dW = X.T.dot(P - grad) #上文刚说要减,现在就减去,只有Y对应的地方有变化
dW = dW / num_train#加正则
dW += 0.5 * reg * np.sum(W*W)
return loss,dW
测试:损失为2.5589,梯度如下
其他代码如下
class Softmax():
def __init__(self):
self.W = None
pass
def loss(self,W,X,Y,reg):
loss = 0.0
num_train = X.shape[0]
dW = np.zeros(W.shape)
#计算分数
scores = X.dot(W)
scores = scores - np.max(scores,axis=1,keepdims=True)
#取score的exp
exp_scores = np.exp(scores)
#求行和,得到Pk的底
sum_row = np.sum(exp_scores,axis = 1,keepdims=True)
#相除得到Pk
P = exp_scores / sum_row
#计算Loss
loss = -1.0 / num_train * np.log(P[np.arange(num_train),Y]).sum()
loss += 0.5 * reg * np.sum(W*W)
#计算Dw梯度
grad = np.zeros_like(P)#生成一个和P一样的0矩阵
grad[np.arange(num_train),Y] = 1#对矩阵中Y所对应的部分加一个1,因为一会要剪
dW = X.T.dot(P - grad) #上文刚说要减,现在就减去,只有Y对应的地方有变化
dW = dW / num_train#加正则
dW += 0.5 * reg * np.sum(W*W)
return loss,dW
def train(self,X,Y,learning_rate=1e-3,reg=1e-5,num_iters=100,batch_size=200,verbose=False):
'''
随机梯度下降法训练分类器
输入参数:
-learning_rate学习率
-reg正则化强度
-num_iters步长值
-batch_size每一步使用的样本数量
-verbose若为真则打印过程
输出参数:
list损失值
'''
num_train,dim = X.shape
num_classes = np.max(Y) + 1
#if self.W is None:
#初始化W矩阵
self.W = 0.001 * np.random.randn(dim,num_classes)
loss_history = []
#开始训练num_iters步
for it in range(num_iters):
X_batch = None
Y_batch = None
########################
# 选取部分训练样本
# 随机生成一个序列
batch_inx = np.random.choice(num_train,batch_size)
X_batch = X[batch_inx,:]
Y_batch = Y[batch_inx]
#########################
# 计算损失与梯度
loss,grade = self.loss(self.W,X_batch,Y_batch,reg)
loss_history.append(loss)
########################
# 参数更新
# 梯度为正表示损失增大,应该减少,成负相关
self.W = self.W - learning_rate * grade
#打印结果
if verbose and it % 100 == 0:
print('iteration %d / %d : loss %f'%(it ,num_iters,loss))
return loss_history
def predict(self,X_train):
y_predict = np.zeros(X_train.shape[1])
#根据训练后的W矩阵计算分数
scores = X_train.dot(self.W)
#找到得分中最大的值作为类别
y_predict = np.argmax(scores,axis = 1)#计算每一行最大值
return y_predict
接下来我们做一步测试,训练我们用到的数据。
##############################################################
# step4 调参
# 两个参数,学习率;正则化强度
learning_rate = [1e-7,2e-7,5e-7]
regularization_strengths = [3e4,3.25e4,3.5e4]
results = {}
best_val = 0
best_svm = None
######################################
# 循环执行代码
# 对不同的学习率以及正则化强度进行测试
#
for rate in learning_rate:
for regular in regularization_strengths:
Softmax2 = Softmax()
#训练
Softmax2.train(X_train,Y_train,learning_rate=rate,reg=regular,num_iters=1000)
#预测
Y1 = Softmax2.predict(X_train)
Y2 = Softmax2.predict(X_val)
accuracy_train = np.mean(Y1==Y_train)
accuracy_val = np.mean(Y2==Y_val)
#判断优略
if best_val < accuracy_val:
best_val = accuracy_val
best_svm = Softmax2#保存当前模型
#存储数据
results[rate,regular] = (accuracy_train,accuracy_val)
#打印数据
for lr,reg in sorted(results):
accuracy_train,accuracy_val = results[(lr,reg)]
print('lr:%e reg %e train accuracy: %f val val accuracy : %f'%(lr,reg,accuracy_train,accuracy_val))
结果如下,emmm有点低,等我以后调调,先学会写轮子把