1)该文章整理自网上的大牛和机器学习专家无私奉献的资料,具体引用的资料请看参考文献。
2)本文仅供学术交流,非商用。所以每一部分具体的参考资料并没有详细对应。如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除。
3)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢谢。
4)此属于第一版本,若有错误,还需继续修正与增删。还望大家多多指点。大家都共享一点点,一起为祖国科研的推进添砖加瓦。
自从学习了深度学习之后,你应该发现了需要学习的东西很多,并且差不多已经开始从零学习了使用 Python 和 NumPy 实现深度学习算法,这样很好,因为理解这些深度学习算法实际上到底是在做什么。但你会发现,除非应用更复杂的模型,例如卷积神经网络,或者循环神经网络,或者开始应用很大的模型,否则它就越来越不实用了,至少对大多数人而言,从零开始全部靠自己实现并不现实,尤其是做项目或者做课题等等。
幸运的是,现在有很多非常好并且成熟的深度学习软件框架,可以帮助实现这些模型。它可以做矩阵乘法,并且在建很大的应用时,通过一个数值线性代数库,它会更高效地实现矩阵乘法,总之利用一些深度学习框架会更加实用,会使工作更加有效。
那么都有哪些框架呢?
现在有许多深度学习框架,能让实现神经网络变得更简单。每个框架都针对某一用户或开发群体的,因为这些框架往往在不断进化,每个月都在进步,如果你想选择一个适合自己的框架,这里有几点意见:
TensorFlow
和 Pytorch
,虽然未来它们有可能出于某种原因选择停止开源,即便现在这个软件是以开源的形式发布的。但至少在短期内,应该是没有大问题的;python
),也取决于你在开发的应用,是计算机视觉,还是自然语言处理或者线上广告,等等。
首先可以确定的是,TensorFlow
在大多数工业领域仍然处于领先地位,PyTorch
更被学术界钟爱,但 PyTorch
正在取得进展并逐渐缩小和 TensorFlow
的差距。
数据科学家 Jeff Hale
从在线职位数量、顶会论文中的出现次数、在线搜索结果、开发者使用情况四个方面对两个框架的现状进行了调研,第一份调研结果发布于 2018 年 9 月。当时的 TensorFlow
是当时的绝对冠军,无论是在 GitHub
活跃度、谷歌搜索量、Medium
文章数、亚马逊书籍和 arXiv
论文等维度上所占的比重都是最大的。此外,TensorFlow
还拥有最多的开发者用户,相关的网上职位描述也是最多的。
可以看到在当时,相比之下,PyTorch
只能排到第三,得分比当时的第二名 Keras
还要矮上一截,TensorFlow
在绝大多数指标中都是绝对冠军。
而到了2019 年 4 月,Jeff Hale
发布了第二份调查结果。这次只过去 6 个月,结果发现,TensorFlow
虽然仍然是当时需求量最大、增长最快的框架,但 PyTorch
的起势很足,增速已经超过了原来的第二名 Keras
,。
而在谷歌搜索相对数量方面,TensorFlow
已经出现了负增长。
转眼到了 2020 年,PyTorch
已经更新到了 1.4,增加了不少新特性,与业界开始结合,在谷歌云 TPU
上运行起来也更加容易。此外,PyTorch
的社区也在不断扩大,比如最近的 OpenAI
。TensorFlow 2.0
也引入了不少新的改进,使得 API
更加精简,对大脑更加友好。此外,TensorFlow
紧密集成了 Keras
作为其前端和高级 API
。果然我早就猜到 Keras
的结局,还想吐槽一句,TensorFlow
这个文档问题还是。。。。烂的一塌糊涂。目前看来 PyTorch
在顶会论文中出现的次数最多,在 2019 NeurIPS 会议论文中,PyTorch 出现 166 次,TensorFlow 出现 74 次,这中差距不言而喻。
作为一个 TensorFlow
忠实用户,希望 TensorFlow 2.0
能挽回挽回颓势吧!!!
在讲 TensorFlow 程序的基本结构之前,先提一个启发性的问题,假设有一个损失函数 J J J 需要最小化, J w = w 2 − 10 w + 25 Jw= w^{2}-10w+25 Jw=w2−10w+25,也许你已经注意到该函数其实就是 ( w − 5 ) 2 {(w -5)}^{2} (w−5)2,所以使它最小的 w w w 值是5,但假设现在不知道这点,只有这个函数,那么如何怎样用 TensorFlow 将其最小化?
Jupyter notebook 入门我们前面讲过了,运行 Python。
import numpy as np
#导入TensorFlow
import tensorflow as tf
#接下来,让我们定义参数w,
#在TensorFlow中,你要用tf.Variable()来定义参数
w = tf.Variable(0,dtype = tf.float32)
#然后我们定义损失函数:
cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25)
#然后我们再写优化器:
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
#让我们用0.01的学习率,目标是最小化损失。
#最后下面的几行是惯用表达式:
init = tf.global_variables_initializer()
#这样就开启了一个TensorFlow session。
session = tf.Session()
#来初始化全局变量。
session.run(init)
#然后让TensorFlow评估一个变量,我们要用到:
session.run(w)
#开始训练并输出结果:
print(session.run(w))
如果运行这个程序,它评估 w w w 等于0,因为什么都还没运行,哈哈。
#现在让我们输入:
session.run(train)
#接下来在运行了一步梯度下降法后,让我们评估一下w的值,再print:
print(session.run(w))
#在一步梯度下降法之后,w现在是0.1。
现在运行梯度下降1000次迭代:
这是运行了梯度下降的1000次迭代,最后 w w w 变成了4.99999,你应该记得上面说过 ( w − 5 ) 2 {(w -5)}^{2} (w−5)2 最小化时 w w w 的最优值是5,这个结果已经很接近了是不是。
希望这个小程序能让你对 TensorFlow 程序的大致结构有了了解,如果你还是想快速学习一门编程语言,有一个方法推荐给你,就是去看看别人的代码,多看多记,就知道哪些代码是固定套路了。
这里有个地方要注意, w w w 是想要优化的参数,因此称为变量,而在定义一个损失函数时,用到了 add
和 multiply
之类的函数,那么 TensorFlow 是如何对 add
和 mutiply
,还有其它函数求导的呢?都看不到,这就是为什么只需基本实现前向传播,框架自己就能弄明白如何做反向传播和梯度计算,因为它已经内置在 add
,multiply
和平方函数中,减少了操作的成本。
对了,要是觉得这种写法不好看的话,TensorFlow 还重载了一般的加减运算等等,结果还是同样的。
这个例子是将 w w w 的一个固定函数最小化了,如果想要最小化的函数是训练集函数又如何呢?不管你有什么训练数据 x x x,当训练神经网络时,训练数据 x x x 会改变,那么如何把训练数据加入 TensorFlow 程序呢?
还是要定义 x x x,把它想做扮演训练数据的角色,当然事实上训练数据有 x x x 和 y y y,但这个例子中只有 x x x,把 x x x 定义为:
x = tf.placeholder(tf.float32,[3,1])
让它成为 [ 3 , 1 ] [3,1] [3,1] 数组,然后向量化,把 c o s t cost cost 这个二次方程的三项前有固定的系数变成数据,即:
cost = x[0][0]*w**2 +x[1][0]*w + x[2][0]
现在 x x x 变成了控制这个二次函数系数的数据,这个 placeholder 函数告诉 TensorFlow,稍后会为 x x x 提供数值。
然后再定义一个数组
coefficient = np.array([[1.],[-10.],[25.]])
这就是要接入 x x x 的数据。
最后需要用某种方式把这个系数数组接入变量 x x x,即:
feed_dict = {x:coefficients}
好了,重新运行它,希望没有语法错误,不然还得 debug
:
现在如果想改变这个二次函数的系数:
coefficient = np.array([[1.],[-10.],[25.]])
改为:
coefficient = np.array([[1.],[-20.],[100.]])
现在这个函数就变成了 ( w − 10 ) 2 {(w -10)}^{2} (w−10)2,如果重新运行, ( w − 10 ) 2 {(w -10)}^{2} (w−10)2 最小化的 w w w 值应该是10。
很好,在梯度下降1000次迭代之后,得到接近10的 w w w。
希望这让你了解了 TensorFlow 能做什么,个人觉得它最强大的就是只需说明如何计算损失函数,它就能求导,而且用一两行代码就能运用梯度优化器,Adam 优化器或者其他优化器。
还有最后一点想提一下的是,这三行(蓝色大括号部分)在 TensorFlow 里是符合表达习惯的,有些程序员会用这种形式来替代,作用基本上是一样的!!!但这个 with 结构也会在很多 TensorFlow 程序中用到,它的意思基本上和左边的相同,但是 Python 中的 with 命令更方便清理,以防在执行这个内循环时出现错误或例外。
那么这个代码到底做了什么呢?
我们看这个等式:
cost =x[0][0]*w**2 +x[1][0]*w + x[2][0]#(w-5)**2
TensorFlow 程序的核心是计算损失函数,然后 TensorFlow 自动计算出导数,以及如何最小化损失,因此这个等式或者这行代码所做的就是让 TensorFlow 建立 计算图,计算图 所做的就是取 x [ 0 ] [ 0 ] x[0][0] x[0][0],取 w w w,然后将它平方,然后 x [ 0 ] [ 0 ] x[0][0] x[0][0] 和 w 2 w^{2} w2 相乘,就得到了 x [ 0 ] [ 0 ] ∗ w 2 x[0][0]*w^{2} x[0][0]∗w2,以此类推,最终整个建立起来计算 c o s t = [ 0 ] [ 0 ] ∗ w ∗ ∗ 2 + x [ 1 ] [ 0 ] ∗ w + x [ 2 ] [ 0 ] cost = [0][0]*w**2 + x[1][0]*w + x[2][0] cost=[0][0]∗w∗∗2+x[1][0]∗w+x[2][0],最后得到了损失函数。
TensorFlow 的优点在于,通过用这个计算损失,计算图基本实现前向传播,TensorFlow 已经内置了所有必要的反向函数,回忆一下训练深度神经网络时的一组前向函数和一组反向函数,而像 TensorFlow 之类的编程框架已经内置了必要的反向函数,这也是为什么通过内置函数来计算前向函数,它也能自动用反向函数来实现反向传播,这就是为什么不需要明确实现反向传播,这是编程框架能帮你变得高效的原因之一。
在编程框架中,你可以用一行代码做很多事情,例如,不想用梯度下降法,而是想用 Adam 优化器,只要改变这行代码,就能很快换掉它,换成更好的优化算法。所有现代深度学习编程框架都支持这样的功能,让你很容易就能编写复杂的神经网络,这样在尝试不同组合时,能极大地降低操作成本!!!
简单的学习到这里就结束了,如果想继续学习更多的,可以选择一本书籍或者是一个系列专栏进行学习,然后快速进行使用,以免忘记,祝你成功!