【CS231n】Spring 2020 Assignments - Assignment1 - Softmax
文章目录
前言
我的作业是在 Google Colaboratory 上完成的,还是挺方便的。
一、Implement softmax_loss_naive(W, X, y, reg)
逻辑回归分类器(Softmax Classifier):希望正确类别得到的概率分数接近 1 ;
Softmax 损失函数(常用,也叫多项式逻辑回归):我们用 softmax 对分数进行转化处理(即不直接使用),并得到正确类别的损失函数是 − l o g P -logP −logP ;公式如下
L i = − l o g ( e s y i ∑ j e s j ) L_i = -\ log(\frac{e^{s_{y_i}}}{\sum_{j}{e^{s_j}}}) Li=− log(∑jesjesyi)
综上,损失的计算还是比较简单。先求出分数 Scores,将 Scores 正数化( e S e^S eS),再将 Scores 归一化,即除以每个数据样本在每个类的得分总和,这样就可以得出概率 P 了。那对于每个数据样本 X i X_i Xi , L i = − l o g ( e s y i ∑ j e s j ) L_i = -\ log(\frac{e^{s_{y_i}}}{\sum_{j}{e^{s_j}}}) Li=− log(∑jesjesyi)。
可是计算梯度 dW 就比较复杂了,因为这个损失函数比较复杂,可以参考下面这篇文章:
多分类器softmax——绝对简单易懂的梯度推导 by 月下花弄影
里面讲得很详细。
下面是代码:
num_train = X.shape[0]
num_classes = W.shape[1]
scores = X.dot(W)
positive_scores = np.e ** scores
softmax = positive_scores / np.sum(positive_scores, axis=1).reshape((num_train, 1))
for i in range(num_train):
for j in range(num_classes):
if j == y[i]:
loss += -np.log(softmax[i][j])
dW[:, j] += (softmax[i][j] - 1) * X[i]
else:
dW[:, j] += softmax[i][j] * X[i]
loss /= num_train
loss += reg * np.sum(W*W)
dW /= num_train
dW += 2 * reg * W
二、Implement softmax_loss_vectorized(W, X, y, reg)
这题和 SVM 的第二题差不多。损失是比较好求的,比较难的仍然是梯度矩阵。
总体思路是构造出一个矩阵,让它和 X 点乘能够得到 dW 。从上一题中我们可以看到 dW[:, j] 都需要加上 X[i] ,只不过当 j = y[i] 时的系数需要减 1 ,那么很自然的我们先将 softmax 相应的项减去1,再与 X.T 点乘即可得到 dW。当然最后别忘了除以 num_train 以及 进行正则化惩罚。
num_train = X.shape[0]
num_classes = W.shape[1]
dim = X.shape[1]
scores = X.dot(W)
positive_scores = np.e ** scores
softmax = positive_scores / np.sum(positive_scores, axis=1).reshape((num_train, 1))
loss = np.sum((-np.log(softmax))[range(num_train), y])
softmax[range(num_train), y] -= 1
dW = X.T.dot(softmax)
loss /= num_train
loss += reg * np.sum(W*W)
dW /= num_train
dW += 2 * reg * W
三、Write code that chooses the best hyperparameters
这一题的思路跟 SVM 里面的完全一样,想看思路的同学可以看我的上一篇博客。
需要注意的是,我选用的参数都是经过对比、选择最后得出来的,并不是一开始就将 learning_rate_step_size, regularization_strength_step_size, num_iters 这些参数设成这个值的。
其实研究了一下其他同学的代码之后,我尝试了一下,发现不怕耗费时间的同学真的可以将 num_iters 固定成一个比较大的值,这样训练出来的结果会准确很多,对于区间的选择也更精准。
learning_rate_step_size = (1.288000e-06 - 0.5e-7) / 15
regularization_strength_step_size = (4.200000e+04 - 1e4) / 15
lr = 1e-7 - learning_rate_step_size
regularization_strength = 1e4 - regularization_strength_step_size
best_lr = 0.
best_regularization_strength = 0.
for i in range(15):
lr += learning_rate_step_size
regularization_strength = 1e4
for j in range(15):
regularization_strength += regularization_strength_step_size
new_softmax = Softmax()
new_softmax.train(X_train, y_train, learning_rate=lr, reg=regularization_strength, num_iters=700, verbose=False)
y_train_pred = new_softmax.predict(X_train)
training_accuracy = np.mean(y_train == y_train_pred)
y_val_pred = new_softmax.predict(X_val)
validation_accuracy = np.mean(y_val == y_val_pred)
if validation_accuracy > best_val:
best_val = validation_accuracy
best_softmax = new_softmax
best_lr = lr
best_regularization_strength = regularization_strength
results[(lr, regularization_strength)] = (training_accuracy, validation_accuracy)
# Train best_softmax and update bast_value
best_softmax.train(X_train, y_train, best_lr, best_regularization_strength, num_iters=800, verbose=True)
y_val_pred = best_softmax.predict(X_val)
best_val = np.mean(y_val == y_val_pred)
print('best_lr:', best_lr, 'best_regularization_strength:', best_regularization_strength)
总结
学习CS231n对数学的要求真的蛮高的。
上一篇: zookeeper中的主要知识点
下一篇: 【OpenCV】矩阵掩模操作