绿林网

Python神经网络编程读后感锦集

Python神经网络编程读后感锦集

《Python神经网络编程》是一本由[英]塔里克·拉希德(Tariq Rashid)著作,人民邮电出版社出版的平装图书,本书定价:69.00元,页数:200,特精心收集的读后感,希望对大家能有帮助。

《Python神经网络编程》读后感(一):适合新手入门神经网络

任何机器学习入门都会做的MNIST识别,但是这本书是从零开始用python手写了一个神经网络、比较适合新手入神经网络相关方面的知识,改书对神经网络的把控还是比较精准的,最新手学习有较大的好处, 看完之后给我的感觉是对于神经网络的基本知识、神经网络背后的核心思想有了更深的理解。

最重要的是,如果你想了解神经网络的基础知识,这就是你需要的书!甚至不需要考虑其他任何事情。

《Python神经网络编程》读后感(二):Make Your Own Neural Network

先说结论,强烈推荐!

全书主要内容分为两部分:神经网络的理论基础和python编程实践。其实英文名《 Make Your Own Neural Network》更有代表性,整本书就是在教你如何一步步地搭建神经网络,层次清晰、通俗易懂。

第一部分理论从零基础开始讲起,但是由浅入深,基本涵盖了神经网络主要的理论内容。激活函数、损失函数等重要概念讲得非常形象,反向传播、梯度下降等算法的原理也讲得非常清楚。

第二部分实践也是从python的基础讲起,不过篇幅有限,内容比较简单,推荐《Python编程:从入门到实践》。围绕MNIST数据集搭建神经网络,只用了numpy和scipy比较基础的库。从写类开始,看到最后文字图像识别的测试效果,也是一件有成就感的事情。

《Python神经网络编程》读后感(三):自己动手编写Python神经网络

这是一本精心编写、给完全初学者的图书。它带领读者构建一个真正、有效的神经网络,而不需要读者具备任何复杂的数学知识和深度学习的理论。

——M Ludvig

强烈推荐本书。这本书使得人工神经网络的概念非常清晰而容易理解。读者应该尝试重复本书中给出的示例,以便让本书发挥最大的作用。我就是这么做的,效果不错!

——亚马逊美国的一位读者

如果你对人工智能或神经网络感兴趣的话,这应该是你的第一本入门书。本书对主题的介绍非常清晰,几乎涉及理解神经网络所需的所有知识,包括微积分、统计、矩阵、编程等等。

——Niyazi Kemer

这是一本优秀的入门图书,它有几个显著特点。它细致而透彻地介绍了神经网络。它用非常精简、实用的方式介绍了数学知识,特别是矩阵乘法和一些简单的微积分,使得读者能够很容易接受一次数学训练。它使用IPython作为计算平台,引导读者使用Python编写神经网络。

——Daniel Oderbolz

《Python神经网络编程》读后感(四):《python神经网络》读书笔记

之一

大约三天读完,这本书浅显易懂,非常适合入门,只有权重调整值的推导过程看得不是很透彻。

神经网络也是机器学习的一种实现,可以应用在有监督学习和无监督学习,因为中间可以有较多层,所以属于深度学习方法。

神经网络的名字很唬人,其实概念挺朴素的,是由含一个输入层一个输出层和若干隐藏层构成的有向无环图(这名字也唬人),看图像一目了然,为啥叫隐藏层呢,就是因为和输入输出没关系,看不见,有点儿神秘。每层的每个结点借助生物的概念称为神经元,各层之间神经元相互链接。

算法训练包含两个阶段:输入向输出传送叫前向馈送信号,输出向输入传送叫反向误差传播。把输入前馈计算得到输出,把输出与目标值比对计算误差,把误差反向传播修正链接权重。具体过程是:

MNIST手写数字识别

世代隐藏层隐藏层结点数学习率识别率训练时长(s)111000.10.947924.0102111000.20.951825.4991111000.30.944326.0787111000.60.920924.988311100.20.849511.4656112000.20.955897.4185212000.20.957449.0803312000.20.960278.7243412000.20.959104.7202512000.20.9627146.9687612000.20.9577162.4879

书中分别对比了不同学习率,不同隐藏层结点数和不同训练世代的模型学习效果,没有对比多隐藏层的模型,我自己添加了一层隐藏层的代码,得出的训练结果如下:

世代隐藏层隐藏层结点数学习率识别率训练时长(s)1210*100.20.767711.53681220*200.20.806617.02151230*300.20.844217.41761220*300.20.798416.78451230*200.20.841217.74631250*500.20.847120.363212100*1000.20.849631.061122100*1000.20.863565.3597

可见多一层隐藏层学习想过不但没有提高,反而下降了。

相同训练世代相同学习率的识别率:

10 * 10 < 20 * 30 < 20 * 20 < 30 * 20 < 30 * 30 < 50 * 50

代码

把训练集的数组转换成图像,大概浏览一下手写的样子

转换代码:

MNIST有60,000条训练数据,书上为了获得更多的训练数据把每一条训练数据的图像分别顺时针、逆时针旋转了10度,这样就添加了两倍的训练样本。

世代隐藏层隐藏层结点数学习率识别率训练时长(s)是否训练旋转数据111000.20.951825.4991否111000.20.947170.7045是111000.10.950325.7134否111000.10.954470.7045是111000.010.913126.4683否111000.010.932972.5362是111000.050.944327.1351否111000.050.951973.1557是112000.010.906597.4234否112000.010.9338296.3523是1012000.010.96771115.5962否1012000.010.97772890.7095是

当学习率为0.2时,加入旋转训练数据的模型识别率反倒更低,将学习率减小为0.01以后增加旋转数据可以提高识别率,通过学习率0.01和0.05两个模型进一步判断学习率越小,增加旋转训练数据带来的学习了提高越多。但问题是很明显训练样本增多反而导致识别率下降。于是我怀疑我的代码有没有问题,下载了作者的代码跑,他是200个隐藏层结点、0.01的学习率跑了10个世代,github上他代码跑的结果是0.9754,我下载下来跑的是0.9779,然后我把我的代码改成一样的跑法用了2890.709569秒合48分钟,识别率是0.9777,看来没问题。然后我对比了一下10世代不用旋转数据的,识别率是0.9677,看来大样本在多世代的学习后效果才显现,另外正如书上说的,样本量大了以后可以采用更小、更谨慎的学习步长,因此将学习率减少到0.01。

另外我对比了一下我的代码和作者代码的执行效率,100个隐藏层结点0.2学习率1世代我的代码跑了71.5秒,作者的跑了74秒。

上一篇笔记中提到初始化权重的时候正态分布方差使用的是传入链接数也就是上一层结点数,而书上用的是当前结点数,我在看github上的代码时作者已经修正为上一层结点数了。

下面到了好玩儿的部分。用包含了旋转图像角度的数据训练好的200个隐藏层结点、10世代的模型,识别率为0.9771,识别我家三口写的0-9共30个数字,故意写得乱一点。正确识别了12个,识别率只有40%,在调节过程中我发现数字在图片中的位置和图片的对比度都会影响识别效果,我把测试集的对比度+0.1(值域是0.01 ~ 0.99)识别对了15个,+0.2,识别对了18个,对比度打满,识别对了18个。然后我规规矩矩写了10个数字,除了9以外都正确识别了,重写了一个圆更大的9识别正确了。

图片转换成数组用于识别

书中用旋转图像的方法增加了训练数据,我能想到的还可以移动图片位置,根据识别我手写数字的经验还有调整图片对比度的方法可以再增加一些训练数据,看看训练效果能不能再提高。

我使用了200个隐藏层结点,学习率0.005,训练10世代,对MNIST原始数据、顺时针逆时针旋转10度、上下左右各移动1个像素和对比度增加0.2减少0.1共9套数据进行训练,耗时9010.42305秒,合两个半小时,得到识别率0.9783,虽然只提高了0.0004,而且增加的训练样本是否对这个提高有作用很难说,但是能进步一点还是挺高兴的。

然后接下来的鼓捣给我带来了惊喜,识别我家三口的手写准确率有了提升:

模型增加对比度识别率MNIST+旋转+012MNIST+旋转+0.115MNIST+旋转+0.2-0.518MNIST+旋转+0.6-0.717MNIST+旋转+0.8及以上18MNIST+旋转+平移+增减对比度+012MNIST+旋转+平移+增减对比度+0.117MNIST+旋转+平移+增减对比度+0.219MNIST+旋转+平移+增减对比度+0.420MNIST+旋转+平移+增减对比度+0.5及以上19

通过以上的测试我认为平移和调整对比度对于模型的训练时有意义的,同时我还发现不是对比度越大识别率越大。

书中说他在加入旋转训练数据后识别率到达0.9787,几乎到达98%,感觉很骄傲。而我在实测我的手写数字时识别率并不令人满意。我读书的时候就想到了平移图片增加训练样本,我在上一篇笔记中把数组转换成图片查看手写数字形状的时候注释了一行# plt.axis('off'),开始把坐标轴去掉是想更清楚地看数字形状,后来注释掉了就是特地为了看一下数字与边缘的距离,我看有些数字距离边缘只有一个像素,如果移动两个像素可能会比较严重地影响数字的形状。所以我在平移的时候只移动了一个像素。然后在测试我自己的手写样本时又发现识别率和对比度有关系,就加上了对增减了对比度的样本的训练。

训练时间从最初的24秒增加到了两个半小时,还可以再通过调整训练样本的参数继续增加训练集,但我感觉已经非常接近极限了,通过调整图片位置和对比度我感觉如果只是同一个训练样本变换位置和对比度就能训练出不同的结果,就应该在模型上想办法了,继续在训练样本上做文章意义不大了。对于这本书和这个模型暂时先学习到这里吧,看书用3天,自己扩展用了3天,把书读厚这个过程收获良多。

《Python神经网络编程》读后感(五):一篇读完make your own neuralnetwork

make your own neural network

非常适合入门神经网络编程的一本书,主要是三部分: 介绍神经网络的基本原理和知识;用Python写一个神经网络训练识别手写数字;对识别手写数字的程序的一些优化。

神经网络的大的概括就是:给定输入,经过一些处理,得到输出。当不知道具体的运算处理方式时,尝试使用模型来估计其运作方式,在这个过程中可以基于模型输出和已知真实实例之间的比较来得到误差、调整参数。

常见的神经网络模型包括分类器和预测器。通俗而言,分类器是将已有数据分开;预测是根据给定输入,给出预测的输出。本质上没有太大差别。在分类过程中其实就是要找到线分开各组数据,关键就是确定这条线,也就是确定斜率。在书中给的直线分类器的例子中,就是随机一个斜率,然后用一组组正确的数据来逐步修正这个斜率:

delt A = E/x,其中A是斜率。但是这样直线的斜率只会取决于最后一个样本而不会顾及到前面的样本。为了改进,每次只要变化delt A 的一部分,这也就是学习率的由来。调节学习率,单一的训练样本就不能主导整个学习过程,也可以减少噪声的影响。复杂的分类器也是这样的思想。

神经网络,正如名字所示,灵感来自动物的神经元细胞,毕竟大脑真的很神奇。神经元的结构包括树突和轴突,电信号从一端沿着轴突再传到树突,这样就从一个神经元传到另一个神经元。简单说,生物的神经元也是接受电信号输入,再输出另一个电信号。不过生物神经元与简单的线性函数不一样,不能简单的对输入做出反应。可以这样认为,在产生输出之前,输入必须达到一个阈值。直观上,神经元不希望传递微小的噪声信号,而只传递有意识的明显的信号。 我们用激活函数来表达这种方式。

下图所示为S函数,也就是sigmoid函数,比较平滑,更自然更接近现实。

S函数简单,并且实际上非常常见。S函数也称为逻辑函数:

继续考虑对神经元进行建模。生物的神经元是可以接受许多输入的,而不仅仅是一个输入。对这些输入,我们只需要 相加,得到总和,作为S函数的输入,然后输出结果。这就是神经元的工作机制。 如果组合信号不够强大,那么S函数的效果是抑制输出信号;足够大时则激发神经元。生物神经元中每个神经元都接受来自之前的多个神经元的输入,也可能同时提供信号给多个神经元。

那么模仿时,可以构建多层神经元,每层神经元都与其前后的神经元互相连接。如图:

可以不断调整节点之间的连接强度。之所以没有弄成其他奇怪的构造而采用完全的连接,是因为这样的连接方式可以相对容易的编码成计算机指令;神经网络的学习过程将会弱化那些实际上不需要的连接。

接下来书中用2*2 3*3的简单例子,给了一些数据,来实际的体验神经网络的计算过程。

随机一些权重,输入*权重之后求和,得到下一层每个节点的输入;经过激活函数,得到该层的输出;然后继续向下一层传播,直到输出。

这个过程可以用矩阵简洁方便的计算。比如2*2的神经网络的计算过程可以表示为:

三层的也是如此。

从第一层(输入层)到第二层(隐藏层):

X是结果,W是权重矩阵,I是第一层的输入;

然后经过激活函数sigmoid得到输出:

然后继续向下一层传播:

在经过一层sigmoid得到最后的输出

Winput_hidden的维度是 hidden_layer * input_layer;

Whidden_output的维度是output_layer*hidden_layer

记住是刚好相反的,行数是下一层的节点数目,列数是本层的节点数

以上是整个神经网络从接受输入,然后向前传播的过程。

那么如何进行学习呢?仍然是使用误差值,也就是前向传过来得到的答案与所知正确答案之间的差值。

那么如何根据误差来更显链接的权重呢?是将误差按链接的权重分配,反向传播回来,进行修正。比如误差是4,有两条链接(0.1 0.3)指向这个节点,那么分别传回去的误差就分别是1和3.

也就是说在向前传播数据和向后传播误差的过程中,都要用到权重。将误差从输出向后传播到网络中的方法就叫做反向传播。

推广到多个节点的误差反向传播时,每个节点的误差都按比例向后传播,然后在上一层中重新组合(指向一个节点的所有链接传回来的误差的和就是传到这个节点的误差)。依据同样的方式就可以继续向上一层传播。用图来阐述更加清楚:

总的来说,神经网络是根据调整链接权重进行学习,这种方法由误差主导。在输出节点中的误差等于所需值与实际值间的差;而内部节点的误差是按照链接权重来分配误差,然后在内部节点中重组这些误差。

同样用矩阵来进行计算。严格按照上面的思路将是这样的:

但是这样并不好处理。观察上图,最重要的其实是wij*e,分子越大,分到的权重就应该越大,而这些分数的分母是归一化的分母,忽略分母之后,比例仍然在。

于是:

就可以写成:

注意这里,是原来的链接矩阵的转置!!

下面就是一个重要问题,到底如何更新权重。为什么要反向传播误差呢?因为我们要用误差来更新权重。神经网络要处理的问题往往过于复杂,无法像简单的线性分类器一样用数学的方式求得参数,暴力的解决不实际,所以最后提出的是梯度下降(gradient descent)的方法。

书中对梯度下降的比喻是摸黑下山,打着手电筒只能看到最近的一小片地方,你就选择看起来是下坡的方向走。逐步逐步走,不需要知道整个山的地貌,也可以下山。

进一步将其推广到一个复杂的函数,梯度下降的思想在于,我们不需要知道整个函数的面貌,也可以一点点朝着最低点前进。

如果将复杂的函数换成神经网络的误差函数,下山找到最小值就是要最小化误差,这样才可以改进神经网络。这就要用到上面的梯度下降算法了。

可以用二维的函数帮助理解:

随机一个起点,斜率为负的话向右走(x增大),斜率为正的话向左走(x减小)——往相反的方向增加x的值,这样可以慢慢的向最小值靠近,直到达到附近的位置。

在接近真正的最小值时,斜率会变小,需要调节步长比较小,才不会在最小值附近来回震荡。

当函数有很多参数的时候,这种方法才真正显出优势。

不过这种方法也有缺点,可能会终止在某个局部的最小值。为了避免这种情况,可以进行多次随机的初始化操作。

总之,梯度下降算法是求解函数最小值的一种很好的办法,当函数非常复杂困难,并且不能轻易使用数学代数求解时,这种方法很实用;当函数有很多参数时,这种方法依然适用,还可以容忍不完善数据,偶尔走错一步也不影响大局。

神经网络本身的输出函数不是一个误差函数,但由于误差是目标训练值与实际输出值之间的差值,因此可以很容易的把输出函数变成误差函数。

直接相减可能会出现正负误差相抵消的问题;而绝对值函数的斜率在最小值附近不连续,会让梯度下降法在v型山谷附近跳来跳去。因此最终选的是差的平方:斜率好计算,误差函数平滑连续,且越接近最小值,梯度越小。

确定了误差函数后,需要计算出误差函数相对于权重的斜率。也就是神经网络的误差E对网络链接权重wij导数。

右边只是将E表达了出来,t是真实值,o是神经网络的输出,所有节点的误差的平方和。

但是注意到,在节点n的输出on只取决于连接到这个节点的链接,也就是节点k的输出ok只取决于权重wjk,即连接到k的链接。换句话说,节点k的输出不依赖链接wjb(wjb表示由前一层第j个节点链接到该层第b个节点的权重)。也就是说,对wjk而言,我们只需要考虑节点Ok。

所以上式可以改成:

结合链式法则:

而前面那个就是个二次函数对ok的求导。

将Ok的表达式列出来,就是sigmoid函数之后得到的输出

其中oj是上一层的输出,结合了这之间的链接矩阵后,在本层进行组合(即求和),然后过一个激活函数。对sigmoid函数进行求导,可以得到:

所以继续之前的求导过程:

可以去掉前面的2,因为我们只对误差函数的方向感兴趣(想想那个二维的函数)。

所以我们一直努力要得到的答案就是:

这是从输出层到隐藏层的的误差的斜率。

套进去我们可以得到从隐藏层到输入层之间的斜率:

oi其实就是输入的值。

根据相反方向来修改链接矩阵:

同样的,我们要转化成矩阵的运算:

即:

wjk是连接当前层节点j与下一层节点k的链接矩阵。ɑ是学习率,Ok是下一层节点的值,最后一项OjT 是上一层节点的输出的转置。

这是正确的点乘顺序。

以上是神经网络的原理。接下来有关准备数据要知道的事情。

观察sigmoid函数:

其输出值在0-1之间,而x过大时,激活函数会变得很平缓,也就是斜率很小,这样不利于学习新的权重。

观察上面计算更新权重值的表达式,权重的更新取决于激活函数的梯度,梯度太小限制神经网络的学习能力,也就是所谓的饱和神经网络。

因此我们不应该让输入值太大;而计算机处理太小的信号时,可能会丧失精度。因此也不能过小。

好的建议是调整输入值在0.0-1.0之间,而输入0会使输出也是0(oj),权重更新值也会变为0(上面那个复杂的式子),所以也要避开0;因此最好加上一个小的偏移。

因为我们的激活函数不能产生大于1的值,因此将训练目标值设的比较大是不合理的。而且逻辑函数的输出也无法达到1,只能是接近1;如果目标设置的过大,训练网络将会驱使更大的权重,以获得越来越大的输出,这将使得网络饱和。因此,我们应当调整输出值符合激活函数的输出范围,一般在0.0-1.0,由于0.0和 1.0也不能,也可以使用0.01-0.99.

除了输入输出,同样的道理也适用于初始权重的设置。同样要避免大的权重使得网络饱和,可以用-1.0~1.0之间随机均匀的选择。另外,如果很多信号进入一个节点,并且这些信号已经表现的不错了,那么对这些信号进行组合并应用激活函数时,应保持这些表现良好的信号。可以在一个节点传入链接数量平方根倒数的大致范围内随机采样,初始化权重。

直观上理解,如果一个节点传入的链接越多,就有越多的信号被叠加在一起,因此如果链接越多,而减小链接的范围是有意义的。实际上就是从均值为0、保准方差等于节点传入链接数量的平方根倒数的正态分布中进行采样。

另外,不管你怎么做,禁止将权重设置为相同的恒定值,特别是不要设置为0.这样,网络中每个节点都将收到相同的信号值,输出也是一样的,反向传播误差时误差也是平均分的,这将导致同等量的权重更新,又会出现相同的权重。而0 的话,输入信号归0,取决于输入信号的权重更新函数也因此为0.完全丧失更新权重的能力。

具体参考github上的代码:

https://github.com/JoJoJun/MNTST_Record_HandWritten_Numbers

主要是构建了一个神经网络类:neuralNetwok

这个类有初始化函数__init__,设定输入层节点、隐藏层节点和输出层节点数,设定学习率,设定激活函数,用随机值初始化输入层-隐藏层和隐藏层-输出层间的链接矩阵。

查询部分(query),是输入输入值,用训练好的模型(权重参数),计算得到输出值,计算过程就是前面神经网络前向传播的过程,要用到pyhon库中numpy.dot运算,以及激活函数。

训练部分(train)这是整个神经网络类的核心部分。输入是输入值和目标值。计算前项传播的部分和查询部分是相同的。得到输出后,与真实的目标值相减得到误差E,然后用第一部分推出的那个很长的式子来计算delt wij并更新权重。

整个神经网络类的结构就是如此,想要使用这个类,就在main函数中,实例化这个类,然后准备训练数据和测试数据,用一定的迭代次数来训练模型,之后用训练过的这些参数,调用query输入测试数据就可以进行测试了。

这里对原始的输入数据的处理是,将,分隔的像素值分开,处理成合适的输入范围,目标值则是一个vector,正确的数字大,其他的数字接近0.

测试数据时对输出用argmax选出得分最高的那个,就是神经网络判断的数字。

可以通过改变学习率、神经网络各层节点数、修改epoch次数、多次随机初始化等方式来找到更合适的参数。

这部分还指出了自己手写数字,然后转化成同样的28*28的像素,用自己训练得到的模型进行识别。

由于数据集有限,可以通过适当旋转已有的图片来得到新的数据。

本文由作者上传并发布(或网友转载),绿林网仅提供信息发布平台。文章仅代表作者个人观点,未经作者许可,不可转载。
点击查看全文
相关推荐
热门推荐