cs231n第二课SVM课后作业--关于HingeLoss梯度下降的一点解答

在学习cs231n,在做到SVM这一课作业时,被梯度的代码难住了,再次翻看网上的课程笔记,细致推导才逐渐清晰。理解能力有限,这里做个简单的记录,防止以后忘记也便于温习。

https://zhuanlan.zhihu.com/p/20945670?refer=intelligentunit线性分类笔记(中)中详细介绍了多累支持向量机损失函数,该函数定义如下:

$$L_i = \sum_{j\neq y_i}max(0,s_j-s_y_i+\Delta )

cs231n svm这一课后作业中对于求梯度的代码如下:

# 估算损失函数的梯度
def svm_loss_naive(W, X, y, reg):
    dW = np.zeros(W.shape)  # initialize the gradient as zero
    # compute the loss and the gradient
    num_classes = W.shape[1] # C
    num_train = X.shape[0] # N
    loss = 0.0
    # 对于一个minibatches
    for i in xrange(num_train):
        scores = X[i].dot(W)
        correct_class_score = scores[y[i]]
        # 下面这个for循环计算损失函数,loss为该训练图像输入后的损失,注意这里的loss有叠加,最后是这个minibatches的loss
        for j in xrange(num_classes):
            if j == y[i]:
                continue
            margin = scores[j] - correct_class_score + 1  # note delta = 1
            if margin > 0:
                loss += margin
                dW[:, j] += X[i] # 数据分类错误时的梯度
                dW[:, y[i]] -= X[i] # 数据分类正确时的梯度
    # Right now the loss is a sum over all training examples, but we want it
    # to be an average instead so we divide by num_train.
    loss /= num_train
    dW /= num_train
    # Add regularization to the loss.
    loss += reg * np.sum(W * W)
    dW += reg*np.sum(W) # 这里正则化项没有除以num_train是因为这里把reg当成 lamda/num_train
    return loss, dW

该代码中需要添加的是  dW[:,j] += X[i], 和 dW[:,y[i]] -= X[i], 这两行代码保存了代价函数对W求梯度的值,注意他们所在的条件语句为if margin > 0, 即对于每个训练样本(每幅图),该代码很可能执行不止一遍。起初看网上提供的代码答案并不太懂这样的做法,后来根据损失函数似乎看出来点什么,但一直不太明朗。

这里我们做个假设,假设该分类器有六种分类,分别是 A,B,C,D,E,F,计算得到:

L_i = \sum_{j\neq y_i}max(0,s_j-s_y_i+\Delta )\\=max(0,1-2)+max(0,3-2)+max(0,4-2)+max(0,0-2)+max(0,1-2)=0+1+2+0+0

假设正确分类$$y_i = 2, 那么上面式子里的五个数分别对应 j=1,3,4,5,6,(假设j从0开始),也就是说对应的是 W[1]*X,W[3]*X,W[4]*X,W[5]*X,W[6]*X所得到的结果。W为权值矩阵,具体介绍见课程笔记,其维度为K*D,K为分类数目,D为图像维度(即像素点数),W[1]表示第1行的向量,维度为 1*D。

上述Li对W求导数,既然这里的Li有五个数子相加,我们依次求导相加。

j=1时,max(0,1-2)=0,0的导数肯定为0;

j=3时,导数\frac{\partial max(0,s_j-s_y_i)}{\partial W}只有两种情况下有值,即\frac{\partial (W[3]*X_t-W[2]*X_t)}{\partial W[3]}=X_t  和\frac{\partial (W[3]*X_t-W[2]*X_t)}{\partial W[2]}=-X_t,其他情况下因为分子部分没有对应的W[i],i=1,4,5,6项,因而均不做更新

j=4时,W[4]和W[2]做更新,\frac{\partial (W[4]*X_t-W[2]*X_t)}{\partial W[4]}=X_t  和\frac{\partial (W[4]*X_t-W[2]*X_t)}{\partial W[2]}=-X_t

j=5时,max(0,-2)=0,权值不更新

j=6时,同样不更新

最后将W[2]的两个梯度相加就是W[2]的梯度,W[3]和W[4]的梯度也已经求出。上述分析默认△为0,且是在分类出错的情况下计算所得。分类正确情况下Li=0,梯度为0,权值不做更新。

这对应着代码中以下部分

    # 对于一个minibatches
    for i in xrange(num_train):
        scores = X[i].dot(W)
        correct_class_score = scores[y[i]]
        for j in xrange(num_classes):
            if j == y[i]:
                continue
            margin = scores[j] - correct_class_score + 1  # note delta = 1
            if margin > 0:
                loss += margin
                dW[:, j] += X[i] # 数据分类错误时的梯度
                dW[:, y[i]] -= X[i] # 数据分类正确时的梯度

对于每个图片,分别遍历分类器输出向量的每个元素,即对应上文累加和公式的每个项,倘若loss不为0,则计算该项对应W[i]的偏导和W[yi]的偏导,并在每次循环的时候都做更新。

仍在学习过程中,理解和表述可能都不尽人意,再接再厉,希望能给予帮助。

发布了26 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39704651/article/details/96901332