文章目录
前言
我的作业是在 Google Colaboratory 上完成的,还是挺方便的。
注意:该次作业应该是听完卷积神经网络才做的
1. Implementing a Neural Network
1.1. TwoLayerNet.loss
1.1.1. Scores
首先计算得分 Scores ,即正向传播。虽然很简单,但是别忘了两个全联接层之间还有一个非线形层(RELU),直接放代码:
XW1 = X.dot(W1)
XW1pb1 = XW1 + b1
H = np.maximum(0, XW1pb1)
HW2 = H.dot(W2)
HW2pb2 = HW2 + b2
scores = HW2pb2
1.1.2. Loss
接下来是计算损失 Loss 。其实在前面的作业中我们已经推导出了 Softmax 的损失是什么了(如下),这边也差不多:
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)
但是需要注意的是:我们现在有两个特征矩阵 W1 和 W2 了,所以正则化惩罚就有两项了。
positive_scores = np.exp(scores)
softmax = positive_scores / np.sum(positive_scores, axis=1).reshape((N, 1))
loss = np.sum((-np.log(softmax))[range(N), y])
loss /= N
loss += (reg * np.sum(W1*W1) + reg * np.sum(W2*W2))
1.1.3. dW
虽然计算梯度矩阵 dW 看起来非常复杂,但是细心一点还是没问题的。
整体思路就是画出计算图(Computational Graph),根据链式法则一步一步反向传播,千万不要傻傻得想要推出损失函数对每个超参数的求导公式!
计算图如下:
完整代码如下:
W1 = np.zeros_like(W1)
dW2 = np.zeros_like(W2)
db1 = np.zeros_like(b1)
db2 = np.zeros_like(b2)
# reg = softmax + (reg * np.sum(W1*W1) + reg * np.sum(W2*W2)
dW1 += 2 * reg * W1
dW2 += 2 * reg * W2
# softmax( H * W2 + b2 )
softmax[range(N), y] -= 1.0
dsoftmax = softmax / N
# b2
db2 += np.sum(dsoftmax, axis=0)
# W2
dW2 += H.T.dot(dsoftmax)
# H = X * w1+ b1
dH = dsoftmax.dot(W2.T)
# Max gate
dH[np.where(H <= 0)] = 0.0
# b1
db1 += np.sum(dH, axis=0)
# W1
dW1 += X.T.dot(dH)
grads['W1'] = dW1
grads['b1'] = db1
grads['W2'] = dW2
grads['b2'] = db2
1.2. TwoLayerNet.train
这部分和之前的作业中写的都差不多,不赘述。
1.2.1 Create a random minibatch of training data and labels
indices = np.random.choice(num_train, batch_size, replace=True)
X_batch = X[indices]
y_batch = y[indices]
1.2.2. Update the parameters
for param in self.params:
self.params[param] -= learning_rate * grads[param]
1.3. TwoLayerNet.predict
这部分和之前的作业中写的都差不多,不赘述。
scores = self.loss(X)
y_pred = scores.argmax(axis=1)
2. Tune Your Hyperparameters
因为参数较多,所以一下子就将所有参数联合起来训练、找合理范围是不太现实的。我的做法是先在每个参数中找出能得出最高得分的范围,例如下面各个参数后面的备注,一般是找 3 次,最后得出一个较小的范围。最后将这四个较小范围联合起来训练。最后在测试集上得出了 0.529 的分数,还不错。
下面是代码:
best_acc = 0.0
best_lr = 0.0
best_bs = 0
best_r = 0.0
num_expriment = 5
hs = 78 # 76~80, 78 is best
lr = 7.4e-4 # 6.6e-4~8.2e-4, 7.4e-4 is best
r = 0.32 # 0.30~0.34, 0.32 is best
bs = 550 # 550~650, 550 is best
hs_rate = (80 - 76) / (num_expriment - 1)
lr_rate = (8.2e-4 - 6.6e-4) / (num_expriment - 1)
r_rate = (0.34 - 0.30) / (num_expriment - 1)
bs_rate = (650 - 550) / (num_expriment - 1)
for hsi in range(num_expriment):
for bsi in range(num_expriment):
for lri in range(num_expriment):
for ri in range(num_expriment):
input_size = 32 * 32 * 3
hidden_size = hs + hsi * hs_rate
num_classes = 10
net = TwoLayerNet(input_size, hidden_size, num_classes)
# Train the network
stats = net.train(X_train, y_train, X_val, y_val,
num_iters=3000, batch_size=(bs + bsi * bs_rate),
learning_rate=(lr + lri * lr_rate), learning_rate_decay=0.95,
reg=(r + ri * r_rate), verbose=False)
# Predict on the validation set
val_acc = (net.predict(X_val) == y_val).mean()
print('hs: ', (hs + hsi * hs_rate), '; lr: ', (lr + lri * lr_rate), '; r: ', (r + ri * r_rate), '; bs: ', (bs + bsi * bs_rate), '; VA: ', val_acc)
if val_acc > best_acc:
best_acc = val_acc
best_net = net
best_bs = bs + bsi * bs_rate
best_lr = lr + lri * lr_rate
best_r = r + ri * r_rate
总结
主要考察的是反向传播的思想,这点真的很重要!