feed_dict 方法

它不止是一个方法,同时还是一个观念,让我们可以更加明确的了解到节点创立的时候,并不包含了让节点执行动作的过程,也因为 Tensorflow 这样的特性,我们可以让流程先创立好,最后等到要运算真正开始执行的时候,再放入数字即可,就好比先打造出一个游乐园,等着人进来玩游戏,详情如下简单代码:

import tensorflow astf
m= tf.add(5, 3)
n = tf.multiply(a, 3)
sess = tf.Session()
sess.run(n, feed_dict={a:15})
45

3. Graph and Board 图表和画板

如上面 「内容」 章节提及的内容,每当一个节点被创建的时候,有一个默认的 TensorBoard 板上会同样添加一个对应的节点,但是如果需要手动设置节点到我们喜欢的不同板上, Graph 对象就成了一个关键的源头方法,它可以让我们自由的创建图例,下面是对应的操作代码:

import tensorflow astf
# This addnode isputin the default TensorBoard graph
in_default_graph = tf.add(5, 3)
# We create another graph toload another node
g = tf.Graph()
with g.as_default():
a= tf.add(3, 4)
# If we want tohave nodes created in default graph, here isthe method tohelpus
default_graph = tf.get_default_graph()

大多数情况下,用一个默认的数据流图表就可以了,如果是要定义多个相互之间彼此独立的模型,则下面三种代码的写法适合参考:

import tensorflow astf
# 1. create anewgraph andignore the default graph
g1 = tf.Graph()
g2 = tf.Graph()
with g1.as_default():
a= tf.add(3, 4, name='add_a')
# define some nodes here tog1 graph
with g2.as_default():
b= tf.subtract(5, 2, name='sub_b')
# define some nodes here tog2 graph
# 2. getthe default graph andappoint the graph toanobject
g11 = tf.get_default_graph()
g12 = tf.Graph()
with g11.as_default():
c= tf.add(3, 4, name='add_c')
# define some nodes here tog11 graph
with g12.as_default():
d = tf.subtract(5, 2, name='sub_d')
# define some nodes here tog21 graph
# 3. the default graph can also beapplied along with the other graph
g21 = tf.Graph()
e= tf.add(3, 4, name='add_e')
# define some nodes here in the default graph
with g21.as_default():
f= tf.subtract(5, 2, name='sub_f')
# define some nodes here tog21 graph
sess = tf.Session()
writer = tf.summary.FileWriter('./my_graph')
writer.add_graph(g21)
# orwe can writethe code in one linebelow
# writer = tf.summary.FileWriter('./my_graph', graph=g11)
# by the way, sess.graph == tf.get_default_graph() isTrue!!
sess.close()
writer.close()

等到我们已经确定添加好所有节点到图表上之后,如果我们要把设置的结果可视化,开启 TensorBoard 的方法如上面代码最后一行,两个参数位置分别如下解释:

路径字符串: 根据我们命名的路径, tf 会自动创建一个文件夹,里面放着一个图表的描述档案,文件夹的路径则放置在我们代码启动的同一个路径下。

指明一个要被画上去的物件,可以是绘话里面的一个方法,让我们指定要被显示的绘话是什么,也可以后面使用 .add_graph() 方法添加要画上的物件。

如果一个项目比较大,图中的节点比较多,我们可能会需要使用一个大框框来涵盖所有的节点,并在图里只简单显示输入端和输出端,使得该大框框成为一个类似黑箱的存在,这时候我们需要使用到下面函数:

tf.name_scope('give_a_name_here')

搭配 with 使用的话,就会变成: with tf.name_scope(): ...indention # the belonged nodes is constructed below.

每个节点参数部分都有一个 name 标签,是用来为该节点取名字,让我们能够更为明了的在 TensorBoard 上面看出哪一个节点对应到的作用是什么,同时如果这些节点是一个占位节点,如 Variable, Constant, placeholder 等,我们还可以直接呼叫该节点的名字得到该占位节点里面值的复用。

等代码运行完毕后,找到文件夹路径,然后从命令提示资源开启该路径并键入:

tensorboard --logdir='./the_name'

我们会得到一个本地网址,复制该网址到浏览器里面打开即可。

最后,等到所有事情做完了,如果有一个 .close() 的动作,可以避免一些不必要的错误,或是我们使用 with 的方法,也可以顺利关闭代码的行为。

4. Variables 变量

继上面张量小节提到的内容,我们除了 .Constant() 可以用之外,还有两个也非常适合拿来描述变量,甚至卡位用的函数:

.placeholder()
.Variable()

有别于直接键入数字,使用这些函数的好处是我们可以非常精确的声明该数值的属性和各种细节,进而免去所有因为数据类型不同造成的错误和麻烦。完整的声明也有助于我们在构建数学模型的时候提升思路的清晰度。

.placeholder() method

前面示范代码中我们都使用了单一不变的数值作为输入,但是这样造成建构好一个模型后没办法重复使用,因为数值是一样的。这个问题被 placeholder 给解开了,它白话文的意思是: 这边有一个变量,但我还没决定好它是什么,不过我可以先对其轮廓给一个定义,例如数据类型,张量大小,该变量在图表中的名称等等。

这样模糊的状态会持续到即将运行计算环节之前,我们会使用 feed_dict 参数以字典的模式导入数值到该位置,使其最终顺利运行,如下面代码:

importnumpy asnp
importtensorflow astf
''' dtype is a necessity that we should announce in parameter.
shape is optional argument with a default None value on the other hand.'''
a = tf.placeholder(dtype=tf.int32, shape=[2], name='my_input')
b = tf.reduce_prod(a, name='prod_b')
c = tf.reduce_sum(a, name='sum_c')
d = tf.add(b, c, name='add_d')
sess = tf.Session()
the_dict = {a: np.array([5, 3], dtype=np.int32)}
sess.run(d, feed_dict=the_dict)
23
.Variable() method

它可以用来承载任意的数值,数字,向量,矩阵,多维张量等等都囊括其中,而为了让它更方便的被使用, tf 有许多创建变量的方法,常见使用的方法如下面列举:

tf.zeros(shape=(None, None, ...), dtype=np.int32)
tf.ones(shape=(None, None, ...), dtype=np.int32)
tf.random_normal(shape=(None, None, ...), mean=0.0, stddev=2.0)
tf.truncated_normal(shape=(None, None, ...), mean=0.0, stddev=1.0)
tf.random_uniform(shape=(None, None, ...), minval=0, maxval=10)
Official website for more details

因为 .Variable() 方法的好用和普遍性,我们在创建好节点后并在执行运算前,需要对它们做初始化,可以是个别的也可以是全部一起的,代码如下:

individual: tf.initialize_variables([var], name='init_var')
overall: tf.global_variables_initializer()

如果代码执行过程中希望“取代”该变量原本的值,那么有另一个方法可以使用:

.assign()

下面是上面列举方法的示范代码:

import numpy asnp
import tensorflow astf
a= tf.Variable(tf.ones(shape=[1], dtype=np.float32))
b= tf.Variable(tf.random_normal(shape=[1], dtype=np.float32,
mean=0.0, stddev=2.0))
c= a.assign(a*2)
d = tf.add(b, c, name='add_d')
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
fori in range(3):
print(sess.run(d))
sess.run(tf.assign_add(a, np.array([3], dtype=np.float32)))
[2.0879781]
[4.0879784]
[8.087978]
array([11.], dtype=float32)

如果对于某些参数我们不乐见上面示例般一轮一轮的迭代数值,可以在 .Variable() 中添加如下代码:

tf.Variable(0, trainable=False)

如此一来就可以锁定变量值。

5. Training 训练

根据上面我们描述的内容和观念,接着我们可以开始尝试编造一个模型,并且用神经网络原理训练该模型的结果逼近到我们所预期的答案上,以下是代码的逻辑步骤:

引入我们需要使用的模块包,并原地创建需要的数据和方程式

使用神经网络的线性模型 y = wx + b,并用 tf 创建变量的方法创建需要的节点

计算随机给出的数字和我们的方程式相差大小

使用 tf 里面的梯度下降其中一个方法,并设置学习效率

开始使用该方法寻找方程式的最小值

初始化完了所有的 tf 的变量后,开启 100 次循环,表示训练次数

打印出结果结束

详细代码如下展示:

import numpy asnp
import tensorflow astf
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data * 0.1+ 0.3
weight = tf.Variable(tf.random_uniform(shape=[1], minval=-1.0, maxval=1.0))
bias = tf.Variable(tf.zeros(shape=[1]))
y= weight * x_data + bias
loss = tf.reduce_mean(tf.square(y- y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
training = optimizer.minimize(loss)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
forstep in range(101):
sess.run(training)
ifstep % 10== 0:
print('Round {}, weight: {}, bias: {}'
.format(step, sess.run(weight[0]), sess.run(bias[0])))
Round 0, weight:-0.02453458309173584, bias:0.49208229780197144
Round 10, weight:0.010933060199022293, bias:0.34626200795173645
Round 20, weight:0.055091626942157745, bias:0.32332566380500793
Round 30, weight:0.07735679298639297, bias:0.3117610216140747
Round 40, weight:0.08858311176300049, bias:0.3059300184249878
Round 50, weight:0.09424349665641785, bias:0.3029899597167969
Round 60, weight:0.09709753841161728, bias:0.3015075623989105
Round 70, weight:0.09853656589984894, bias:0.3007601201534271
Round 80, weight:0.09926214069128036, bias:0.3003832697868347
Round 90, weight:0.09962794929742813, bias:0.30019325017929077
Round 100, weight:0.09981241822242737, bias:0.30009743571281433