cs231n深度学习课程笔记——(两层)神经网络

摘要

这是我学习了斯坦福大学的cs231n课程有关神经网络部分的学习笔记,是我对自己的知识的复习和自己编程过程中出错的问题总结。主要按照作业实现的思路进行总结。文中的图片都来自课程ppt,TODO代码90%是我自己编写,剩下的部分参考网上其他网友。


neural network

两层神经网络

作业要求首先实现一个两层的简单神经网络。

正向传播:

需要注意的地方:

  1. 由于使用的是softmax函数计算loss,所以需要计算指数,容易造成数值爆炸,所以对每个样本同时减去该样本特征值中国的最大值再计算指数,而减去一个常数对计算梯度无影响。
  2. 在求每个样本最大值时
a = np.max(scores, axis=1,keepdims=True)

此处的keepdims=True必不可少,否则无法完成broadcast。

# Compute the forward pass
    scores = None
    #############################################################################
    # TODO: Perform the forward pass, computing the class scores for the input. #
    # Store the result in the scores variable, which should be an array of      #
    # shape (N, C).                                                             #
    #############################################################################
    h1=X.dot(W1)+b1.T
    h12=np.maximum(0,h1)
    h1=np.maximum(0,h1)
    scores=h1.dot(W2)+b2.T
       
    # If the targets are not given then jump out, we're done
    if y is None:
      return scores

    # Compute the loss
    loss = None
    #############################################################################
    # TODO: Finish the forward pass, and compute the loss. This should include  #
    # both the data loss and L2 regularization for W1 and W2. Store the result  #
    # in the variable loss, which should be a scalar. Use the Softmax           #
    # classifier loss. So that your results match ours, multiply the            #
    # regularization loss by 0.5                                                #
    #############################################################################
    pass
    #此处为了防止指数运算数值爆炸,将得到的scores全部减去对应样本的最大值,
    #再进行指数操作,而减去一个常数对计算梯度无影响
    a = np.max(scores, axis=1,keepdims=True)  
#此处的keepdims必不可少,否则无法完成broadcast
    scores -= a
    a = np.exp(scores)

    c1 = np.sum(a, axis=1)
    c2 = 1 / c1
    c3 = a[np.arange(a.shape[0]), y]
    b1 = c2 * c3
    L1 = np.log(b1)

    loss=-np.sum(L1)
    #loss = -np.sum(np.log(a[np.arange(a.shape[0]), y] / np.sum(a, axis=1)))
    loss /= X.shape[0]
    loss += 0.5* reg * np.sum(W1 * W1)
    loss +=0.5* reg * np.sum(W2 * W2)

反向传播:

利用反向传播一步步往回计算梯度。这里的代码用了两次的db1,变量名定义的不好,与真正的b1的梯度混淆了。
需要注意的地方:

  1. 当计算dc1的时候,多做了几步将dc1从向量转化为二维矩阵,同样是因为向量不支持broadcast。感觉我用的方法很笨,希望能找到更好的方法。
  2. 在计算da的时候需要特别注意,要将a[y]和其他的元素分开计算梯度,


    softmax公式

    从公式中可以看出,a[y]就是分子的部分,分子分母都用到了a[y],所以需要将这两部分的梯度相加。
    可以看下面SVM的传播图,W有两部分传播,所以计算梯度时也需要将两部分相加,原因与softmax一样。


    SVM传播图
#将两部分梯度相加 
da[:,np.arange(da.shape[1])]=dc1
 da[np.arange(da.shape[0]),y]+=dc3    

代码:

# Backward pass: compute gradients
    grads = {}
    #############################################################################
    # TODO: Compute the backward pass, computing the derivatives of the weights #
    # and biases. Store the results in the grads dictionary. For example,       #
    # grads['W1'] should store the gradient on W1, and be a matrix of same size #
    #############################################################################
    pass
    db1=-1/b1*1/X.shape[0]
    dc2=db1*c3
    dc3=db1*c2
    dc1=dc2*(-1/np.square(c1))
    z1=np.zeros([dc1.shape[0],1])       
#这几步是将dc1从向量转化为二维矩阵,因为向量不支持broadcast
    z1[:,0]=dc1
    dc1=z1

    da=np.zeros(a.shape)
    da[:,np.arange(da.shape[1])]=dc1
    da[np.arange(da.shape[0]),y]+=dc3             
 #注意!对于求a[y]的导数时,c1和c3都用到了a[y],所以需要相加!
    dscores=a*da
    dW2=h12.T.dot(dscores)
    dh12=dscores.dot(W2.T)
    dh1=dh12*(h1>0)
    dW1=X.T.dot(dh1)
    db2=np.sum(dscores.T,axis=1)
    db1=np.sum(dh1.T,axis=1)

    dW1+=reg*W1
    dW2+=reg*W2

    grads['W1']=dW1
    grads['W2']=dW2
    grads['b1']=db1
    grads['b2']=db2

训练网络

采用的是部分梯度下降法,所以需要先取样。

inde = np.random.choice(xrange(X.shape[0]), batch_size, replace=True)
X_batch = X[inde, :]
y_batch = y[inde]

参数更新:

#使用momentum更新参数

      mu=0.9
      v_w1=mu*v_w1-learning_rate*grads['W1']
      self.params['W1'] +=v_w1
      v_w2 = mu * v_w2 - learning_rate * grads['W2']
      self.params['W2'] += v_w2
      v_b1 = mu * v_b1 - learning_rate * grads['b1']
      self.params['b1'] += v_b1
      v_b2 = mu * v_b2 - learning_rate * grads['b2']
      self.params['b2'] += v_b2

    #使用SGD更新参数
      # self.params['W1'] +=-learning_rate*grads['W1']
      # self.params['W2'] += -learning_rate*grads['W2']
      # self.params['b1'] += -learning_rate*grads['b1']
      # self.params['b2'] +=-learning_rate*grads['b2']

用了momentum和sgd两种,更多的方法在下面多层神经网络会有详细说明。

以上所有部分是作业中Neural_net.py文件中需要我们实现的代码,全部完整代码将在最后贴出。

筛选参数

完成了上面每个部分后就可以用数据进行训练了,下面是ipython中筛选超参数选出最好的参数代码:

best_net = None # store the best model into this   
#best parameters by Yan Wei:lr 0.000150 reg 0.040000 hs 100  val accuracy: 0.514000


#################################################################################
# TODO: Tune hyperparameters using the validation set. Store your best trained  #
# model in best_net.                                                            #
#                                                                               #
# To help debug your network, it may help to use visualizations similar to the  #
# ones we used above; these visualizations will have significant qualitative    #
# differences from the ones we saw above for the poorly tuned network.          #
#                                                                               #
# Tweaking hyperparameters by hand can be fun, but you might find it useful to  #
# write code to sweep through possible combinations of hyperparameters          #
# automatically like we did on the previous exercises.                          #
#################################################################################
pass
input_size = 32 * 32 * 3
hidden_size_2 = 50
num_classes = 10
results = {}
best_val = -1
best_stats=-1
learning_rates = [1.5e-4,2e-4,3e-4]
regularization_strengths = [0.02,0.03,0.04]
hidden_size_test=[100]

for lr in learning_rates:
    for reg in regularization_strengths:
        for hs in hidden_size_test:
            

            net2 = TwoLayerNet(input_size, hs, num_classes)

# Train the network
            stats2 = net2.train(X_train, y_train, X_val, y_val,
                        num_iters=1000, batch_size=200,
                        learning_rate=lr, learning_rate_decay=0.95,
                        reg=reg, verbose=True)

# Predict on the validation set
            val_acc2 = (net2.predict(X_val) == y_val).mean()
            print 'Validation accuracy: ', val_acc2
            print 'lr: %f  reg: %f hs: %d'%(lr,reg,hs)
            if val_acc2>best_val:
                best_val=val_acc2
                best_net=net2
                best_stats=stats2
            results[(lr,reg,hs)]=val_acc2

for lr, reg,hs in sorted(results):
    val_accuracy = results[(lr, reg,hs)]
    print 'lr %f reg %f hs %d  val accuracy: %f' % (
                lr, reg,hs, val_accuracy)
    
print 'best validation accuracy achieved during cross-validation: %f' % best_val

# Plot the loss function and train / validation accuracies
plt.subplot(2, 1, 1)
plt.plot(stats2['loss_history'])
plt.title('Loss history')
plt.xlabel('Iteration')
plt.ylabel('Loss')

plt.subplot(2, 1, 2)
plt.plot(stats2['train_acc_history'], label='train')
plt.plot(stats2['val_acc_history'], label='val')
plt.legend(['train', 'val'])
plt.title('Classification accuracy history')
plt.xlabel('Epoch')
plt.ylabel('Clasification accuracy')
plt.show()

下面是运行的一些结果截图:


一些参数的训练结果数据

loss history

accuracy

the weights of the best network

最终在测试集上的准确率为49.6%,由于时间原因只是随便挑选了几个超参数训练,所以准确率结果不高。
最后附上计算手稿,比较随意的草稿方便自己以后复习。
计算手稿

(多层)神经网络中将实现多层的神经网络。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,467评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,079评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,600评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,835评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,848评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,348评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,735评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,705评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,238评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,268评论 3 345
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,395评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,012评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,704评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,177评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,309评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,925评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,457评论 2 365

推荐阅读更多精彩内容