[注意:考虑到这个和SVM重复很多,所以会一笔带过/省略一些]
softmax和SVM只是线性分类器分类结果的评判不同, 完全依靠打分最大来评判结果, 误差就是希望结果尽可能接近正确分类值远大于其他值.
我们将打分结果按照指数权重正则化为和为1的向量:
而这个值希望尽可能接近1, 也就是-log接近于0. 为此可知
我们推导一下求解方法:
由此,我们类似SVM实现误差函数的计算,只需要照着SVM版本就可以写出来了,比较简单:
num_train = X.shape[0]
num_class = W.shape[1]
for i in range(num_train):
score = X[i].dot(W) # 某个样本的打分
score -= np.max(score) # 打分减去最大的一个值,防止某个数太大导致指数爆炸溢出
# 按照loss直接写即可
correct_score = score[y[i]]
exp_sum = np.sum(np.exp(score)) # 指数求和
loss += np.log(exp_sum) - correct_score
# 对每个分类都算一次,得出dW
for j in xrange(num_class):
if j == y[i]:
dW[:, j] += np.exp(score[j]) / exp_sum * X[i] - X[i]
else:
dW[:, j] += np.exp(score[j]) / exp_sum * X[i]
loss /= num_train
loss += reg * np.sum(W * W)
dW /= num_train
dW += 2 * reg * W
重点还是向量化求解.和上一篇博客类似, 对于Loss, 直接减去全体正确的打分,再对整个打分做指数, 求和即可.对于dW, 我们需要类似打分结果(500*10),转化为对每个x的权重. 对非正确类别元素, 我们直接对整个打分全部指数正则化就可以了, 除此之外对正确分类项还需要额外减去Xi,对应矩阵直接减1就可以. 这样就可以得到代码: (别忘了减去最大值的正则化)
num_train = X.shape[0]
score = X.dot(W)
score -= np.max(score,axis=1).reshape(num_train,1)
# 抽出正确分值
real_score = score[range(num_train),y]
exp_score = np.exp(score)
# 求出总和分数
sum_exp_score = np.sum(exp_score,axis=1) # 和前面real_score维度一致,不需要reshape
loss = np.sum(np.log(sum_exp_score) - real_score)
loss /= num_train
loss += reg * np.sum(W * W)
# 梯度
dW_X = np.exp(score) / sum_exp_score.reshape(num_train,1) # 为了触发广播机制需要reshape
dW_X[range(num_train),y] -= 1
dW = X.T.dot(dW_X)
dW /= num_train
dW += 2 * reg * W
对超参数的验证也和前面类似, 这里略去代码:
可以看到这时准确率不如前面的SVM. 不过本来SVM和softmax就不能说谁好谁差, SVM追求能用就行, 而softmax永不满足, 在这种图片全部像素而非目标导向的识别当中, SVM的表现更好.
我们不妨对比一下SVM和softmax的可视化图形:
直观上看, softmax的模板更为平滑, 这种平滑的特性使得匹配是没了针对性, 从而降低了正确率.
问题
回答: -当W随机相当于瞎猜, 此时分类正确概率为1/10, 因为交叉熵本质上就是softmax损失的数学期望(这个期望就是所有的类别打分一致,如果不理解,我建议对比两个概念看看). 不难算出交叉熵为 -10 * 0.1 * ln(0.1).
回答: 正确, 因为假设我们有一个图像, 它性质太好了,某个打分远大于其他类别, 那么SVM下L=0(max全部为0),loss不变, 但是softmax因为其永不满足, loss一定增加.
标签:CS231N,assignment,sum,num,score,softmax,exp,np,dW From: https://www.cnblogs.com/360MEMZ/p/17299384.html