Tensorflow 对上一节神经网络模型的优化

Posted expedition

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tensorflow 对上一节神经网络模型的优化相关的知识,希望对你有一定的参考价值。

本节涉及的知识点:

1.在程序中查看变量的取值

2.张量

3.用张量重新组织输入数据

4.简化的神经网络模型

5.标量、多维数组

6.在TensorFlow中查看和设定张量的形态

7.用softmax函数规范可变参数

8.小结:线性问题

 

一、在程序中查看变量的取值

x = 1
y = 2.2
z = "adc"
print("x is: %d" % x)
print("y is: %f" % y)
print("z is: %s" % z)
x is: 1
y is: 2.200000
z is: adc

二、张量

import tensorflow as tf

x1 = tf.placeholder(dtype=tf.float32) 
x2 = tf.placeholder(dtype=tf.float32)
x3 = tf.placeholder(dtype=tf.float32)
print("x1: %s" % x1)
yTrain = tf.placeholder(dtype=tf.float32)

w1 = tf.Variable(0.1,dtype=tf.float32)
w2 = tf.Variable(0.1,dtype=tf.float32)
w3 = tf.Variable(0.1,dtype=tf.float32)
print("w1: %s" % w1)

n1 = x1 * w1
n2 = x2 * w2
n3 = x3 * w3
print("n1: %s" % n1)
y = n1 + n2 + n3
print("y: %s" % y)

x1: Tensor("Placeholder:0", dtype=float32)
w1: <tf.Variable ‘Variable:0‘ shape=() dtype=float32_ref>
n1: Tensor("mul:0", dtype=float32)
y: Tensor("add_1:0", dtype=float32)

 

其中,x1是一个Tensor对象,由操作“Placeholder:0”这个操作而来,这个操作就是定义x1 时

x1 = tf.placeholder(dtype=tf.float32) 

语句中的tf.placeholder函数,是定位符的一个操作。后面的数字代表该操作输出结果的编号。【一个编号可能会有多个输出结果】,“0”代表第一个输出结果的编号,大多数操作也只有一个输出结果。

w1是一个tf.Variable对象,也就是可变参数对象

n1 是一个Tensor 对象,由操作 "mul:0"得来。mul 是 乘法multiply 操作的简称,对应于定义n1时的语句 —— n1 = x1 *w1

y 是一个Tensor对象,由操作 “add_1:0” 得来,对应于定义y时的语句 y  = n1 + n2 + n3【下划线和数字1的原因是TensorFlow会把这个算式的两个加号拆成类似于n1 + (n2 + n3) 这样的两个加法操作,所以加序号以区分】

 

 

上一节神经网络模型图中的所有节点,包括输入层、隐藏层、输出层 的节点,都对传入自身的数据进行一定的计算操作并输出数据。

节点对应的计算操作在程序中是用运算符来体现的,而输出的数据在程序中体现为 Tensor 【张量】类型的一个对象,

 # 虽然张量只是代表模型图中某个节点的输出数据,但在程序中,一般用这个节点的名称来命名这个节点输出的张量

 

类似Tensor("mul:0",dtype=float32) 这样一个张量的输出信息中,括号的第一部分就是它对应的操作,第二部分对应它的输出数据类型。如果张量是由多个操作计算而来,输出信息中的操作将是其中的最后一个

技术图片

 

 

三、用张量重新组织输入数据

在之前设计的神经网络中,总共有3个分数,如果再要加一个分数项,需要改变整个网络模型。所以在通常的神经网络中,很多时候会把这一串的数据组织成一个“向量“ 来送入神经网络进行计算。

  • 这里的向量和数据几何中的向量不同,就是指一串数字,在程序中用一个 数组来表示 —— [90,85,70]
  • 这个数组是有顺序的,可以约定每一项所对应的值。
  • 向量中有几个数字,一般就叫做 ”几维向量“, 如 [90,85,70] 就是一个 三维向量

 

把输入数据改为张量的形式:

import tensorflow as tf
x = tf.placeholder(shape=[3], dtype=tf.float32)
#命名参数shape,这是表示变量x的形态的,[3]表示输入占位符x的数据将是一个含有3个数字的数组,也就是一个三维张量 

yTrain = tf.placeholder(shape=[], dtype=tf.float32)
#yTrain 是一个普通数字,不是张量,如果要给它一个形态的话,可以用[] 代表
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
#由于x是一个三维张量,w也需要相应的是一个形态为[3] 的三维向量
# tf.zeros() 函数可以生成一个值全为0的向量,即tf.zeros([3])的返回值是 [0,0,0],这个向量将作为w的初始值
n = x * w
# ”*”代表数学中矩阵的点乘  —— 两个形态相同的矩阵中 每个相同位置的数字相乘 
# 点乘和矩阵点乘是一样的  
y = tf.reduce_sum(n)
# 把作为它参数的张量【以后可能是矩阵】中的所有维度的值相加求和
loss = tf.abs(y - yTrain)
optimizer = tf.train.RMSPropOptimizer(0.001)
train = optimizer.minimize(loss)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
result = sess.run([train, x, w, y, yTrain, loss], feed_dict={x: [90, 80, 70], yTrain: 85})
# 在喂数据的时候,直接喂一个 三维向量就可以了,修改输出结果数组
print(result)
result = sess.run([train, x, w, y, yTrain, loss], feed_dict={x:[98, 95, 87], yTrain: 96})
print(result)
[None, array([90., 80., 70.], dtype=float32), array([0.00316052, 0.00316006, 0.00315938], dtype=float32), 0.0, array(85., dtype=float32), 85.0]
[None, array([98., 95., 87.], dtype=float32), array([0.00554424, 0.00563004, 0.0056722 ], dtype=float32), 0.88480234, array(96., dtype=float32), 95.1152]

从输出信息中可以看到x 、w 确实被理解成为一个数组

 

循环5000次:

import tensorflow as tf

x = tf.placeholder(shape=[3], dtype=tf.float32)
yTrain = tf.placeholder(shape=[], dtype=tf.float32)

w = tf.Variable(tf.zeros([3]), dtype=tf.float32)

n = x * w

y = tf.reduce_sum(n)

loss = tf.abs(y - yTrain)

optimizer = tf.train.RMSPropOptimizer(0.001)

train = optimizer.minimize(loss)

sess = tf.Session()

init = tf.global_variables_initializer()

sess.run(init)

for i in range(5000):
    result = sess.run([train, x, w, y, yTrain, loss], feed_dict={x: [90, 80, 70], yTrain: 85})
    print(result)

    result = sess.run([train, x, w, y, yTrain, loss], feed_dict={x:[98, 95, 87], yTrain: 96})
    print(result)

技术图片

 

 可以看到误差已经缩小到很小的范围,三个权重分别接近 0.6  0.3  0.1

 

 

 

四、简化的神经网络模型

 技术图片

我们使用向量来组织输入数据后,只用一个神经元就解决了原来需要三个神经元的问题

五、标量、多维数组等概念的补充

(1)标量

对于一个普通数字,我们把它叫做“标量”,这个数字可以是整数或者浮点数(小数)

比如,之前的 yTrain 就是一个典型的标量,因为它代表的是总分数

但是 yTrain 在输出中显示是数组类型,而向量在计算机中 也是用数组类型表示的 ———— 解释:

x w 的表达形式类似 array([98.,95.,87.],dtype=float32)

yTrain 的表达形式类似 array(96.0,dtype=float32),虽然也是array,但是其中没有[] 包括的数组,只有一个数字。这说明,把 yTrain 标记为 array 只是 TensorFlow 的理解方式问题,其实质还是标量

(2)多维数组

向量在计算机中 是用 一个数组来表示的,例如一个学生的分数 [90,80,70],那么两个学生的分数如何表示? —— >    矩阵

技术图片

 

该 2X3 矩阵 第一行即第一位学生的成绩,第二行 即第二位学生的成绩

# 计算机中不直接支持矩阵这种数据类型,但是可以用“二维数组”满足这种表达要求

x = [[90,80,70],[98,95,87]]

或者这么写

x1 = [90,80,70]
x2 = [98,95,87]
x = [x1,x2]

技术图片

技术图片

比如:

[[[90,80,70],[98,97,95]],[[70,75,78],[60,65,68]]]

这个三维数组可以用来表达两个班级的学生的总成绩,第一个维度包含了两个班级,第二个维度是两个学生,第三个维度中包含 3 科成绩【3个数字】

(3)张量的阶和状态

 张量 主要是用来存放节点的输出数据的,其中存放的数据可以是一个标量【一个数】,也可以是一个向量【一组数】,还可以是一个矩阵【二维数组】,甚至用多维数组来表达的数据

TensorFlow 中 用 形态 shape 来表达在张量中存储的数据的形式

 形态本身也是用一个类似一维数组的表达形式来表示的

技术图片

 如果张量存储的是上方的二维数组,可以说他的形态是 [2,3] ———— 可以看出,形态本身也是一个一维数组,2 3 分别表示这个矩阵两个维度(行和列)上的项数 —— (2,3) 也可以用来表示该形态

[90,80,70]

形态是 [3] —— 只有1个维度,维度中项数是3,就是说有3个数字

 

对于一个标量,也就是一个数字 ———— []  或 ()  来表示形态

 

[[[90,80,70],[98,97,95]],[[70,75,78],[60,65,68]]]

形态是 ———— [2,2,3]

 

在TensorFlow 中,张量的形态可以用一个数组来表示,这个数组中 有几个数字,就说这个张量是几“价”的张量 ———— 标量 0价    向量 1价   二维数组 2价  三维数组 3价

 

 

六、在TensorFlow中查看和设定张量的形态

 TensorFlow 会在程序执行时,根据输入的数据自动确定张量的形态。。。举例:

import tensorflow as tf

x = tf.placeholder(dtype=tf.float32)

xShape = tf.shape(x)

sess = tf.Session()

result = sess.run(xShape, feed_dict={x: 8})
print(result)

result = sess.run(xShape, feed_dict={x: [1, 2, 3]})
print(result)

result = sess.run(xShape, feed_dict={x: [[1, 2, 3], [3, 6, 9]]})
print(result)
[]
[3]
[2 3]

在这段代码中,我们定义了一个占位符变量 x,但没有指定它的形态

为了查看x 的实际形态,定义了一个变量 xShape ,通过传入参数 tf.shape(x) 即可得到 x 的形态 

 

直接运行会话,三次给x 输入不同形态的数据 ———— 标量(一个数字) 、向量(一维数组)、二维数组 —— 程序的输入也符合预想

 

 

严格规范输入数据,可以定义张量时 指定形态:

import tensorflow as tf

x = tf.placeholder(shape=[2, 3], dtype=tf.float32)

xShape = tf.shape(x)

sess = tf.Session()

result = sess.run(xShape, feed_dict={x: [[1, 2, 3], [2, 4, 6]]})
print(result)

#给张量“喂”不符合形态的数字会报错
result = sess.run(xShape, feed_dict={x: [1, 2, 3]})
print(result)

技术图片

 

 

总结:各种形态在TensorFlow中的表达:

#标量
x1 = tf.placeholder(shape=[], dtype=tf.float32) x2 = tf.placeholder(shape=(), dtype=tf.float32)
#向量 x3
= tf.placeholder(shape=[3], dtype=tf.float32) x4 = tf.placeholder(shape=(3), dtype=tf.float32) x5 = tf.placeholder(shape=3, dtype=tf.float32) x6 = tf.placeholder(shape=(3, ), dtype=tf.float32)
#二维数组(二阶张量) x7
= tf.placeholder(shape=(2, 3), dtype=tf.float32) x8 = tf.placeholder(shape=[2, 3], dtype=tf.float32) sess = tf.Session() result = sess.run(tf.shape(x1), feed_dict={x1: 8}) print(result) result = sess.run(tf.shape(x2), feed_dict={x2: 8}) print(result) result = sess.run(tf.shape(x3), feed_dict={x3: [1, 2, 3]}) print(result) result = sess.run(tf.shape(x4), feed_dict={x4: [1, 2, 3]}) print(result) result = sess.run(tf.shape(x5), feed_dict={x5: [1, 2, 3]}) print(result) result = sess.run(tf.shape(x6), feed_dict={x6: [1, 2, 3]}) print(result) result = sess.run(tf.shape(x7), feed_dict={x7: [[1, 2, 3], [2, 4, 6]]}) print(result) result = sess.run(tf.shape(x8), feed_dict={x8: [[1, 2, 3], [2, 4, 6]]}) print(result)
[]
[]
[3]
[3]
[3]
[3]
[2 3]
[2 3]

 

 

七、用softmax函数规范可变参数

介绍一个 常用的规范化可变参数的小技巧

之前的三好学生问题: 总分  = x1 * w1 + x2 * w2 + x3 * w3 —— 其中权重之和 w1+w2+w3 = 1

或者用一个3维变量 w表示这些权重,那么对三维变量w求和应该 = 1,把这个规则应用程序中,可以大幅度减少 优化器调整可变参数的工作量

import tensorflow as tf

x = tf.placeholder(shape=[3], dtype=tf.float32)
yTrain = tf.placeholder(shape=[], dtype=tf.float32)
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
wn = tf.nn.softmax(w)
n = x * wn
y = tf.reduce_sum(n)
loss = tf.abs(y - yTrain)
optimizer = tf.train.RMSPropOptimizer(0.1)
train = optimizer.minimize(loss)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
for i in range(2):
    result = sess.run([train, x, w, wn, y, yTrain, loss], feed_dict={x: [90, 80, 70], yTrain: 85})
    print(result[3])
    result = sess.run([train, x, w, wn, y, yTrain, loss], feed_dict={x:[98, 95, 87], yTrain: 96})
    print(result[3])
[0.33333334 0.33333334 0.33333334]
[0.413998   0.32727832 0.2587237 ]
[0.44992    0.32819405 0.22188595]
[0.5284719  0.2905868  0.18094125]

由以上输出的结果(即wn ,可以明显看到wn 的变化情况)

 

wn = tf.nn.softmax(w)

 nn 是neural network的缩写,nn 是tensorFlow 的一个重要的子类(包)。soft 函数 可以把一个向量规范化后得到一个新的向量,这个新的向量中的所有暑之相加起来保证为1

soft 函数的这个特性经常被用来在神经网络中处理分类的问题,但在这里,暂时只让它满足让所有权重值相加和为1的需求。

wn 的各个值项相加总和为1,并且它的形态与w完全相同

 

也可以把 w1 w2  w3组成一个向量再输入: wn = tf.nn.softmax([w1,w2,w3])

 

 

经过 softmax 函数运算后,会发现达到相同误差率所需要的训练次数明显减少

 

八、小结:线性问题

本节和上一节研究的三好学生问题,是一个典型的线性问题。符合 y = w*x

技术图片

 

 计算结果是一条直线的问题就叫做线性问题

其中 x y w可以是标量,向量,甚至矩阵数据

但是,现实问题不可能都是经过原点的线性问题,所有实际上使用 y = w * x + b 这样适应性更强的线性模型公式来处理问题

技术图片

 

 参数b ,称为 偏移量或偏置值。

 

线性模型虽然无法解决线性问题,但是在解决非线性问题时,我们通常仍然会 用线性模型作为神经元节点处理中的第一步,再做非线性化的处理。

 

以上是关于Tensorflow 对上一节神经网络模型的优化的主要内容,如果未能解决你的问题,请参考以下文章

将 Keras 模型集成到 TensorFlow

从Tensorflow模型文件中解析并显示网络结构图(CKPT模型篇)

『TensorFlow』徒手装高达_战斗数据收集模块原型_save&restore

tensorflow训练好的模型,怎么调用?

深度学习原理与框架-Tensorflow卷积神经网络-神经网络mnist分类

Tensorflow学习教程------利用卷积神经网络对mnist数据集进行分类_训练模型