【学习笔记】cs231n-assignment1-two_layer_net

前言

    大家好,我是Kay,小白一个。以下是我完成斯坦福 cs231n-assignment1-two_layer_net 这份作业的做题过程、思路、踩到的哪些坑、还有一些得到的启发和心得。希望下面的文字能对所有像我这样的小白有所帮助。

       两层的网络处理方法与之前的SVM/Softmax 的处理方法类似,关键在于函数和梯度的计算。

 

TODO1:计算 scores

 

       【思路】公式是:W2 * max(0, W1*x) 用代码实现之即可。

   scores_hid = np.dot(X, W1) + b1

   scores_hid = np.maximum(0, scores_hid)

   scores =np.dot(scores_hid, W2) + b2

        结果正确。

 

 

TODO2:计算 loss

 

       【思路】用 softmax 的公式,不要忘记加上正则惩罚项。

    scores = scores - np.max(scores, axis = 1,keepdims=True)

    exp_sum = np.sum(np.exp(scores), axis = 1,keepdims=True)

    loss = -np.sum(scores[range(N), y]) +np.sum(np.log(exp_sum))

    loss = loss / N + 0.5 * reg * (np.sum(W1 *W1) + np.sum(W2 * W2))

 

        【开始 Debug】

【学习笔记】cs231n-assignment1-two_layer_net_第1张图片

       这个 bug 我是找得真是要气死自己啊!感觉公式都没记错啊!Run 了好几次 loss 还是不够小,郁闷之下跑去百度,贴了别人的代码结果 loss 也是这么多但是他们的结果很小,喵喵喵?我定眼一看,别人的 reg 都是 0.1!凭什么我给的是0.05。想哭、难受。

       改成 0.1 后,果然我的代码也是正确的。

 

       【思考提升】

       我顺手看了下别人的代码,有的人没有对scores 做处理就开 e 的幂,这是不对的哦~小心数值被爆掉哦~

 

 

TODO3:利用反向传播计算梯度

 

       【思路】画出“计算图”,一步步往回做,靠公式得到:

d_b2= 1 * d_scores

d_W2= h1 * d_scores (h1 是 max(0, f1) )

d_b1 = 1 * d_f1

d_W1= X * d_f1

 

   prob = score / exp_sum

   prob[range(N), y] -= 1

    d_scores= np.dot(X.T, prob)

    d_scores /= N

   grads['b2'] = np.sum(d_scores, axis = 0)

   grads['W2'] = np.dot(scores_hid.T, d_scores)

   d_f1 = np.dot(d_scores, W2.T)

   d_f1[scores_hid <= 0] = 0

   grads['b1'] = np.sum(d_f1, axis = 0)

    grads['W1'] =np.dot(X.T, d_f1)

 

       【开始 Debug】这里我遇到了特别多错误,果然思考还是不够严谨。

1.    d_scores 求错了,不是 np.dot(X.T, prob),不能生搬以为是 softmax 里的 dW,d_scores 就是 prob!

2.    prob 也求错了,在 softmax 里,我分子上的 scores 是有做 e 幂的,但是这里还没处理就直接拿去用了,还是一处生搬旧思想的错误。

3.    两个 dW 没有加正则项。

 

       【修改代码】

   prob = np.exp(scores) / exp_sum

   prob[range(N), y] -= 1

   d_scores = prob / N

 

   grads['b2'] = np.sum(d_scores, axis = 0)

   grads['W2'] = np.dot(scores_hid.T, d_scores) + reg * W2

   d_f1 = np.dot(d_scores, W2.T)

   d_f1[scores_hid <= 0] = 0

   grads['b1'] = np.sum(d_f1, axis = 0)

    grads['W1'] =np.dot(X.T, d_f1) + reg * W1

结果正确。

 

       【思考提升】其实像这些所谓的“小错”是很让人沮丧的,错的又不是大方向,找起bug 时又往往是从整体思路开始怀疑自己,因此找到这点小错是很耗费精力的,要怎么加快 debug 的效率呢?错的地方是思路、还是小瑕疵?这是应该训练的地方了。

 

 
TODO4:完成 train 函数和 predict 函数

 

       【思路】

              SGD:利用特定一张图像对我们的各个参数进行 update

              y_pred就是谁的分数大就取那个标签作为 y_pred

              三段代码都贴在这里了。

     sample_indices = np.random.choice(range(num_train), batch_size)

     X_batch = X[sample_indices]

     y_batch =y[sample_indices]

 

     self.params['W1'] -= learning_rate * grads['W1']

     self.params['b1'] -= learning_rate * grads['b1']

     self.params['W2'] -= learning_rate * grads['W2']

     self.params['b2'] -= learning_rate * grads['b2']

 

      y_pred = np.argmax(self.loss(X), axis=1)

              结果Final training loss: 0.017143643532923747

 


TODO5:进行超参数的调参

 

       【思路】这里的超参数有:hidden layer size, learning rate, numer of training epochs, andregularization strength

       首先,我们还是先调最重要的lr 和 reg,接着再考虑其他超参数。

 

best_val = -1

input_size = 32 * 32 * 3

hidden_size = 100

num_classes = 10

net = TwoLayerNet(input_size, hidden_size,num_classes)

 

learing_rates = [1e-3, 1.5e-3, 2e-3]

regularizations = [0.2, 0.35, 0.5]

for lr in learing_rates:

   for reg in regularizations:

       stats = net.train(X_train, y_train, X_val, y_val,

                    num_iters=1500,batch_size=200,

                    learning_rate=lr,learning_rate_decay=0.95,

                    reg=reg, verbose=False)

       val_acc = (net.predict(X_val) == y_val).mean()

       if val_acc > best_val:

           best_val = val_acc

           best_net = net

       print ("lr ",lr, "reg ", reg, "val accuracy:", val_acc)

 

print ("best validation accuracyachieved during cross-validation: ", best_val)

结果差强人意。

 

       【思考提升】老师说:“Tuning the hyperparameters and developing intuition for how theyaffect the final performance is a large part of using Neural Networks.”可是就目前而言,我还是没有认识到超参数的“重要性”?所以,我需要训练一种超参如何影响神经网络的直觉。

 

 

       总结

       这份作业要求我们掌握正向传递分数函数和损失函数,同时反向传递梯度给每个变量。

Delta = “本地梯度”*“上沿梯度”

       有趣的是,

变量间做“加法”,传回的梯度都是那份“上沿梯度”,相当于是一个广播器

变量间做“max()”,传回的梯度是那份“上沿梯度”给最大的值,其他的梯度是0,相当于是一个路由器

变量间做“乘法”,传回的梯度都是那份“上沿梯度”*对方本身的值,相当于是一个(带放大“上沿梯度”倍)交换器

这三个典例,应该能帮助我们直观地理解 backpropagation。

    最后,关于缩进,我已经放弃治疗了。


你可能感兴趣的:(CS231n)