热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【学习笔记】cs231nassignment1two_layer_net

前言大家好,我是Kay,小白一个。以下是我完成斯坦福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】

       这个 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 <&#61; 0] &#61; 0

   grads[&#39;b1&#39;] &#61; np.sum(d_f1, axis &#61; 0)

    grads[&#39;W1&#39;] &#61;np.dot(X.T, d_f1)

 

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

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

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

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

 

       【修改代码】

   prob &#61; np.exp(scores) / exp_sum

   prob[range(N), y] -&#61; 1

   d_scores &#61; prob / N

 

   grads[&#39;b2&#39;] &#61; np.sum(d_scores, axis &#61; 0)

   grads[&#39;W2&#39;] &#61; np.dot(scores_hid.T, d_scores) &#43; reg * W2

   d_f1 &#61; np.dot(d_scores, W2.T)

   d_f1[scores_hid <&#61; 0] &#61; 0

   grads[&#39;b1&#39;] &#61; np.sum(d_f1, axis &#61; 0)

    grads[&#39;W1&#39;] &#61;np.dot(X.T, d_f1) &#43; reg * W1

结果正确。

 

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

 


 
TODO4&#xff1a;完成 train 函数和 predict 函数

 

       【思路】

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

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

              三段代码都贴在这里了。

     sample_indices &#61; np.random.choice(range(num_train), batch_size)

     X_batch &#61; X[sample_indices]

     y_batch &#61;y[sample_indices]

 

     self.params[&#39;W1&#39;] -&#61; learning_rate * grads[&#39;W1&#39;]

     self.params[&#39;b1&#39;] -&#61; learning_rate * grads[&#39;b1&#39;]

     self.params[&#39;W2&#39;] -&#61; learning_rate * grads[&#39;W2&#39;]

     self.params[&#39;b2&#39;] -&#61; learning_rate * grads[&#39;b2&#39;]

 

      y_pred &#61; np.argmax(self.loss(X), axis&#61;1)

              结果Final training loss: 0.017143643532923747

 



TODO5&#xff1a;进行超参数的调参

 

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

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

 

best_val &#61; -1

input_size &#61; 32 * 32 * 3

hidden_size &#61; 100

num_classes &#61; 10

net &#61; TwoLayerNet(input_size, hidden_size,num_classes)

 

learing_rates &#61; [1e-3, 1.5e-3, 2e-3]

regularizations &#61; [0.2, 0.35, 0.5]

for lr in learing_rates:

   for reg in regularizations:

       stats &#61; net.train(X_train, y_train, X_val, y_val,

                    num_iters&#61;1500,batch_size&#61;200,

                    learning_rate&#61;lr,learning_rate_decay&#61;0.95,

                    reg&#61;reg, verbose&#61;False)

       val_acc &#61; (net.predict(X_val) &#61;&#61; y_val).mean()

       if val_acc > best_val:

           best_val &#61; val_acc

           best_net &#61; net

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

 

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

结果差强人意。

 

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

 

 


       总结

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

Delta &#61; “本地梯度”*“上沿梯度”

       有趣的是&#xff0c;

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

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

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

这三个典例&#xff0c;应该能帮助我们直观地理解 backpropagation。

    最后&#xff0c;关于缩进&#xff0c;我已经放弃治疗了。




推荐阅读
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文介绍了Python异常的捕获、传递与抛出操作,并提供了相关的操作示例。通过异常的捕获和传递,可以有效处理程序中的错误情况。同时,还介绍了如何主动抛出异常。通过本文的学习,读者可以掌握Python中异常处理的基本方法和技巧。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
author-avatar
随缘2012天王_288
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有