tensorflow,以下简称tf。
版本记录:
anaconda自带的下面这些库必须先卸载了,装tensorflow的时候顺带装上它们。
不然总报错,vs2017 && vscode都会import报错,无法调试。
---
numpy-1.16.1
tensorflow-1.13.0rc2
matplotlib-3.0.2
一、定义+计算分离式设计
一开始接触容易蒙蔽。
a=tf.add(b,c)
这种东西,想当然的以为a是个返回值。
但a其实是个对象哒、
有返回值的函数可以做成对象,没返回值的也可以做成对象。
总之在tf里面,绝大部分基础操作都是作为“概念上的运算”实体化而成的对象。
通俗的说,每一个对象,存储了一条计算式。
a1=tf.add(b,c)
a2=tf.multiply(a,c)
如上面的例子,a1中存储了"b+c"这条式子。
a2中存储了"(b+c)*c"这条式子 (也可以说是存储了"a1*c",但是a1本身不具备确实的存在价值,只是中间容器罢了。)
但无论是a1还是a2,都只是式子而已,都只记录了“概念上的运算”,却并没有真正被运算出来。
所以在设计阶段,他们是没有值的!
你去print(a2),能得到的也就是"(b+c)*c"这条式子,并没有人帮你算值
#当然事实上你去print只会返回一个对象类型信息,
所有运算都集中在在tensorflow.Session()会话中处理!!
tensorflow.Session().run(a2)
此时真正对“式子”进行了“运算”。
run()函数才会给返回值。
你把上面的式子print()包起来就能看到结果了。
二、为什么tf可以自动做训练
一开始接触tf,做完一个demo我就很蒙蔽。
虽然我告诉你了要minimize谁,告诉了你怎么计算loss,但我没告诉你咋更新参数啊!!!你怎么就啥都会呢。
为什么要搞定义+计算分离的设计,和这个问题本质是相同的。
几番查找看到官网一段介绍:
用TensorFlow来训练它是非常容易的。因为TensorFlow拥有一张描述你各个计算单元的图,它可以自动地使用反向传播算法(backpropagation algorithm)来有效地确定你的变量是如何影响你想要最小化的那个成本值的。然后,TensorFlow会用你选择的优化算法来不断地修改变量以降低成本。
//参考http://www.tensorfly.cn/tfdoc/tutorials/mnist_beginners.html
突然有点明白了,因为tf能自己搞反向传播,计算任意两个标准参数之间的梯度啊!
所以你不用给他写参数更新式子,它自己就会更新。
简单的说,tf自己搞了个新宇宙。
这个宇宙内的数学规则都被重新设计了一遍。
tf里面每一个运算,都有对应的专门的类。
这些类内置好了对应的求导算法。
你从本宇宙输入的数据,都必须先变成标准化的tf宇宙的对象。
tf.tensor
tf.variable
tf.placeholder
...
所有东西在同一个标准下进行运算,自然也可以被这个标准的创建者(tf宇宙)记录、解构、求导。
举例:
直接用b=2*a是算不了b对a的梯度的。
虽然我们都知道是2,但tf不知道,因为这条式子不属于tf宇宙。
你得先把数据都变成tf里的标准形式。
例如
a=tf.get_variable('a',[1],initializer=tf.constant_initializer(1.0))
c=tf.constant(2)
这样一来,a就是一个合法的tf宇宙变量,c就是一个合法的tf宇宙常量
规范了数据不够。连乘法都不能用py自带的,要用tf里面的。
如果你直接a*c,这样相当于两条“式子”相乘,不是“值”相乘,是没有意义的。
(当然事实上可以通过重载*运算符来让它有意义,此处只是便于理解。)
必须使用tf宇宙标准形式。
b=matmul(a,c)
然后因为tf内置了对matmul()函数的求导法则,这样才能求b对a的导数,为常数2。
然后回到最开始说的,这也是为什么tf必须搞定义和计算分离。
因为它需要无数次去自动算梯度,自动更新参数。
所以它必须得知“如何求导”。
要知道“如何求导”,必须知道“如何计算”。
所以tf宇宙里的对象,保存的都是“计算过程”,即“式子”,这一信息。