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有点低,等我以后调调,先学会写轮子把

 

posted @ 2019-02-19 22:05  #Cloud  阅读(1250)  评论(0编辑  收藏  举报