1 神经网络基本概述
1.1 基本概念
关于基本的数学运算可参考GitHub的Tensorflow代码 tensorflow/tensorflow/python/ops/math_ops.py
1.1.1 张量
- 基于Tensorflow 的NN:用张量表示数据,用计算图搭建神经网络,用会话执行计算图,优化线上的权重(参数),得到模型。
- 张量:张量就是多维数组(列表),用“阶”表示张量的维度。
0阶张量称作标量,表示一个单独的数;如s = 123
1阶张量称作向量,表示一个一维数组;如v = [1,2,3]
2阶张量称作矩阵,表示一个二维数组;如m = [[1,2,3],[4,5,6],[7,8,9]]
n阶张量称作张量,表示一个n维数组;如t = [[[……
具体张量是几阶的,可以计量张量右边的方括号[ 数判断;如t = [[[……]]] 为3阶。
1.1.2 数据类型
import tensorflow as tf a = tf.constant([1.0, 2.0]) b = tf.constant([3.0, 4.0]) result = a +b print(result)
运行
Tensor("add:0", shape=(2,), dtype=float32)
对输出结果进行解读意思为 result 是一个名称为 add:0 的张量, shape=(2,)表示一维数组长度为 2,dtype=float32 表示数据类型为浮点型 。
- add - 节点名
- 0 - 第0个输出
- shape - 维度
- (2,)-一维数组长度为2
- dtype - 数据类型
上述的一段代码就是计算过程,也即是一张计算图;print函数仅输出了数据是一个张量,但并没有输出具体的值。故计算图只描述计算过程,不计算结果。
函数tf.constant()释义
constant( value , # 常量值或列表 dtype = None , # 张量的(可选)元素类型 shape = None , # 张量的(可选)维度 name = 'Const' , # 张量的(可选)名称 verify_shape = False # 布尔值,可以验证数值的形状 )
用途:创建一个常数张量。
参数:value可以是常量值,也可以是dtype类型值的列表(若dtype未指定,则从值类型推断张量中元素值类型);若shape值不存在,则使用value值的形状,若shape值存在,则生成shape指定维度的张量。
示例:
(1) 常规的形式
import tensorflow as tf x = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6]) print(x) # Tensor("Const_10:0", shape=(6,), dtype=float32) print(tf.Session().run(x)) # [1. 2. 3. 4. 5. 6.]
备注:只有value值,其他参数未指定(默认None)。
(2) 指定shape(维度隐含元素数 = 列表长度)
import tensorflow as tf x = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6],shape = (2,3)) print(x) #Tensor("Const_8:0", shape=(2, 3), dtype=float32) print(tf.Session().run(x)) #[[1. 2. 3.] # [4. 5. 6.]]
备注:shape维度参数所隐含的元素数等于列表长度,结果会将列表安装shape指定维度形状。
(3) 指定shape(维度隐含元素数 > 列表长度)
import tensorflow as tf x = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6],shape = (3,3)) print(x) # Tensor("Const_11:0", shape=(3, 3), dtype=float32) print(tf.Session().run(x)) #[[1. 2. 3.] # [4. 5. 6.] # [6. 6. 6.]]
备注:shape维度参数所隐含的元素数大于列表长度,结果会将列表安装shape指定维度形状;同时将列表中的最后一个元素作为张量的填充元素。
(4) 指定shape(维度隐含元素数 < 列表长度)
import tensorflow as tf x = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6],shape = (2,2)) print(x) print(tf.Session().run(x)) # ValueError: Too many elements provided. Needed at most 4, but received 6
备注:报错ValueError。
1.1.3 计算图
计算图graph:搭建神经网络的计算过程,是承载一个或多个计算节点的一张图,只搭建网络,不运算。
我们知道,神经网络的基本模型是神经元,神经元的基本模型的本质是数学中的乘、加运算;一个典型的计算图搭建如下:
- 输入 - X1、X2
- 权重 - W1、W2
- y值 - y = X1*W1 + X2*W2
对应代码如下:
import tensorflow as tf # 定义一个2阶张量 输入值 x = tf.constant([[1.0,2.0]]) # 定义一个2阶张量 权重 w = tf.constant([[3.0],[4.0]]) y = tf.matmul(x,w) print(y)
运行
Tensor("MatMul:0", shape=(1, 1), dtype=float32)
注意:在给输入值x、权重w 赋值时,要符合向量积的规则。
print函数结果显示y是一个张量,只搭建承载计算过程的计算图,并没有运算,如果想要得到运算结果就要用到 “会话session()”
函数tf.matmul() 释义
matmul( a, # 类型为float16(32、64)、int32、complex64(128)和rank>1的张量 b, #与a相同的类型和rank transpose_a=False, # 若True,a在乘法运算前转置 transpose_b=False, # 若True,b在乘法运算前转置 adjoint_a=False, # 若True,a在乘法运算前共轭并转置 adjoint_b=False, # 若True,b在乘法运算前共轭并转置 a_is_sparse=False, # 若True,a被视为系数矩阵 b_is_sparse=False, # 若True,b被视为系数矩阵 name=None # (可选的)操作名称 )
用途:
实现矩阵a、b的乘法运行。
参数:
a、b参数的数据类型必须一致,矩阵的秩rank > 1,a、b的维度符合乘法运算规则。
需要转置transpose、共轭并转置conjugated and transposed的运算时,将默认false设置为True。
若一个或多个矩阵元素中包含较多的零时,将 a_is_sparse 或 b_is_sparse 参数设置为True,以使乘法运算更高效(注,该优化仅适用于float16、float32且rank=2的纯矩阵张量)。
备注:
当 transpose_a 和 adjoint_a 同时设置为 True 时,将触发 ValueRrror 错误。
参考:tf.matmul函数
1.1.4 会话session
会话( Session): 执行计算图中的节点运算。
import tensorflow as tf # 定义一个2阶张量 输入值 x = tf.constant([[1.0,2.0]]) # 定义一个2阶张量 权重 w = tf.constant([[3.0],[4.0]]) y = tf.matmul(x,w) # 开启会话 print(tf.Session().run(y))
运行
[[11.]]
注意:
- Session()的首字母必须大写
- 运行Session()计算过程:1.0*3.0+2.0*4.0=11.0
关于在运行Session时出现的警告(如下)
2018-10-20 12:57:59.276469:
I d:\build\tensorflow\tensorflow-r1.9\tensorflow\core\platform\cpu_feature_guard.cc:141]
Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 2018-10-20 12:57:59.278975:
I d:\build\tensorflow\tensorflow-r1.9\tensorflow\core\common_runtime\process_util.cc:69]
Creating new thread pool with default inter op setting:
2. Tune using inter_op_parallelism_threads for best performance.
这是因为电脑可以支持加速指令,但运行代码时并没有启动这些指令。可以把这些 “提示warming” 暂时屏蔽掉。屏蔽方法为进入主目录下的bashrc文件,在bashrc文件中假如这样的一句export TF_CPP_MIN_LOG_LEVEL=2,从而从而把“提示warning”等级降低。
这个命令可以控制 python 程序显示提示信息的等级,在 Tensorflow 里面一般设置成是"0"(显示所有信息)或者"1"(不显示 info), "2"代表不显示 warning,"3"代表不显示 error。一般不建议设置成 3。source 命令用于重新执行修改的初始化文件,使之立即生效,而不必注销并重新登录。
备注:关于这段屏蔽警告方法没有验证。暂时不考虑。但整体的操作是基于Vim 编辑器。
1.2 神经网络的权重参数
神经元线上的权重w用变量表示,其初值一般是(按某种方式)随机赋值的。赋值方法是由tf.Variable()函数完成的,权重的形式是由函数的参数决定的。
神经网络中常用的生成随机数/数组的函数有:
- tf.random_normal() 生成正态分布随机数
- tf.truncated_normal() 生成去掉过大偏离点的正态分布随机数
- tf.random_uniform() 生成均匀分布随机数
- tf.zeros 生成全0数组
- tf.ones 生成全1数组
- tf.fill 生成全定值数组
- tf.constant 生成直接给定值的数组
简例
- tf.zeros([3,2], int32) 生成[[0,0], [0,0], [0,0]]
- tf.zeros([3,2], int32) 生成[[1,1], [1,1], [1,1]]
- tf.zeros([3,2], 6) 生成[[6,6], [6,6], [6,6]]
- tf.constant([3,2,1]) 生成[3,2,1]
示例:
- w=tf.Variable(tf.random_normal([2,3],stddev=2, mean=0, seed=1)),表示生成正态分布随机数,形状2行3列 [2, 3] ,标准差 stddev为 2, 均值mean为 0, 随机种子seed 为 1。
- w=tf.Variable(tf.Truncated_normal([2,3],stddev=2, mean=0, seed=1)),表示去掉偏离过大的正态分布,也就是如果随机出来的数据偏离平均值超过标准差stddev = 2 时,这个数据将重新生成。
- w=random_uniform(shape=7,minval=0,maxval=1,dtype=tf.int32, seed=1), 表示从一个均匀分布[minval maxval)中随机采样,注意定义域是左闭右开,即包含 minval,不包含 maxval
注意:
- 随机种子如果去掉每次生成的随机数将不一致。
-
随机种子是一个真随机数(种子),一般计算机的随机数都是伪随机数,其是以真随机数(种子)为初始条件、以一定算法不停迭代产生的随机数。
关于随机种子参看文章 随机数与随机种子
- 如果没有特殊要求标准差、 均值、 随机种子是可以不写的
1.3 神经网络的基本框架
当我们知道张量、计算图、会话和参数后,接下来可讨论神经网络的实现过程。
- 1 提取数据集中的特征,输入给神经网络( Neural Network, NN)
- 2 搭建NN结构,从输入到输出(先搭建计算图,再用会话执行);NN前向传播算法 --> 计算输出
- 3 大量特征数据喂给NN,迭代优化NN参数;NN反向传播算法 --> 优化参数训练模型
- 4 使用训练好的模型预测和分类
其中1、2、3为循环迭代的神经网络训练过程,4为神经网络优化完成后(神经网络参数固定了)实现特定应用过程。
实际上,在很多的实际应用中,一般会先使用现有的成熟网络结构,喂入新的数据,训练相应模型,判断是否是否能对喂入从未见过的新数据作出正确响应,再适当更改网络结构,反复迭代,让机器自动训练参数找出最优结构和参数,以固定专用模型。
2 前向传播
2.1 前向传播的基本过程
前向传播就是搭建模型的计算过程,让模型具有推理能力。
例如生产一批零件,体积为x1,重量为 x2,体积和重量就是我们选择的特征,把它们喂入神经网络,当体积和重量这组数据走过神经网络后会得到一个输出。
以全连接网络为例,假设输入的特征值体积0.7,重量0.5,则神经网络图如下所示
由搭建的神经网络可得(隐藏层节点):
a11 = x1* w11+x2*w21=0.14+0.15=0.29;
a12 = 0.32;
a13=0.38
最终计算得到的输出层:
y = -0.015
此过程就是所谓的前向传播过程。
2.2 神经网络层的概念
神经网络的层指的是计算层。
所以上例中的输入层不是计算层,隐藏层a经过了一次计算,所以隐藏层a称之为第一层网络,输出层y称之为第二层网络。
2.3 前向传播过程的推导(第一层)
将前向传播过程以tensorflow描述出来。
(1)输入值x
x 是输入为1*2(一行两列)的矩阵,表示一次输入的一组特征,该组特征包含体积和重量两个元素。
x = [x1,x2]
(2)权重值w
w前节点编号,后节点编号(层数) 为权重参数,也是待优化的参数
对于第一层w而言,前面由2个节点、后面有3个节点;所以是2行3列的矩阵形式。
注意:具体w的矩阵是2行3列,还是3行2列,是由输入值和权重的乘积形式(xw or wx)决定的;因为是xw,所以w是2行3列。
w(1)为2*3矩阵。
a(1) = xw(1) = [a11, a12, a13]
a(1)为1行3列的矩阵。
2.4 前向传播过程的推导(第二层)
第二层网络如下图所示
待优化的权重参数前面有3个节点、后面有1个节点,所以w(2)是一个3行1列的矩阵。
将该层的输入值(矩阵乘法)乘以权重w(2),即可计算输出y值了。
计算y值
将每层输入(矩阵乘法)乘以权重w即可计算输出y值
a= tf.matmul(X, W1) # 第一层网络矩阵乘法运算 y= tf.matmul(a, W2) # 第二层网络矩阵乘法运算
2.5 前向传播过程的 tensorflow 描述:
2.5.1 with结构语句
所有变量初始化过程、计算图节点运算等计算过程都要用会话(with结构)实现
with tf.Session() as sess: print(sess.run(y))
with结构语句等价于
tf.Session().run(y)
实际上,with结构语句实际上是对tf.Session().run(y) (y为当层神经网络函数的输出值) 分拆调整。
2.5.2 变量初始化
在sess.run()函数中用 tf.global_variables_initializer() 实现对所有变量的初始化,也就是赋初值。
init_op= tf.global_variables_initializer()
sess.run(init_op)
上述代码将输出init_op值
2.5.3 计算图节点运算
在sess.run()函数中写入待运算的节点
sess.run(y)
上述代码意味着计算输出 y 值
2.5.4 用 tf.placeholder 占位,在 sess.run 函数中用 feed_dict 喂数据
喂一组数据:
x = tf.placeholder(tf.float32, shape=(1, 2))
sess.run(y, feed_dict={x: [[0.5,0.6]]})
喂多组数据:
x = tf.placeholder(tf.float32, shape=(None, 2))
sess.run(y, feed_dict={x: [[0.1,0.2],[0.2,0.3],[0.3,0.4],[0.4,0.5]]})
在实际应用中,我们可以一次喂入一组或多组输入,让神经网络计算输出y;无论哪种,均可以先用tfplaceholder给输入占位。
如果一次喂入一组数据,则shape = (1,2),1代表1行,2代表2列(也即x1,x2,这个值是由输入层的特征个数决定的,无论多少组数据,在该神经网络中,输入数据的列数永等于2)。
如果一次喂入多组数据,则shape = (None,2),None表示第一维先空着,第二维位置写有几个(2)输入特征;这样就可以在feed_dict参数值中喂入多组数据。
2.5.5 实现代码(喂入一组数据)
这是一个实现神经网络前向传播过程,网络可以自动推理输出 y 值。
#coding:utf-8 #两层简单神经网络(全连接) import tensorflow as tf #定义输入和参数 x = tf.constant([[0.7, 0.5]]) w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) #定义前向传播过程 a = tf.matmul(x, w1) y = tf.matmul(a, w2) #用会话计算结果 with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) print(sess.run(y))
运行 [[3.0904665]]
用placeholder实现tf.Session().run()喂入一组数组的情况;第一组喂入体积0.7、重量0.5
#coding:utf-8 #两层简单神经网络(全连接) import tensorflow as tf #定义输入和参数 #用placeholder实现输入定义 (sess.run中喂一组数据) x = tf.placeholder(tf.float32, shape=(1, 2)) w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) #定义前向传播过程 a = tf.matmul(x, w1) y = tf.matmul(a, w2) #用会话计算结果 with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) print(sess.run(y, feed_dict={x: [[0.7,0.5]]}))
运行 [[3.0904665]]
备注:
(1)由于该段代码中seed=1,所以不管该段代码运行多少次,其输出结果永远相同,当将seed=1去掉时,每次运行结果随机的。
(2)全局变量初始化tf.global_variables_initializer() 去掉后会直接报错FailedPreconditionError。具体详见博文【点击】
2.5.6 实现代码(喂入数组数据)
用 placeholder 实现输入定义(sess.run 中喂入多组数据)的情况
体积 | 重量 | |
第一组 | 0.7 | 0.5 |
第二组 | 0.2 | 0.3 |
第三组 | 0.3 | 0.4 |
第四组 | 0.4 | 0.5 |
相应代码:
# coding:utf-8 # 两层简单神经网络(全连接) import tensorflow as tf # 定义输入和参数 # 用placeholder定义输入(sess.run喂多组数据) x = tf.placeholder(tf.float32, shape=(None, 2)) w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) # 定义前向传播过程 a = tf.matmul(x, w1) y = tf.matmul(a, w2) # 调用会话计算结果 with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) print(sess.run(y, feed_dict={x: [[0.7, 0.5], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]})) print("w1:\n", sess.run(w1)) print("w2:\n", sess.run(w2))
运行
[[3.0904665] [1.2236414] [1.7270732] [2.2305048]] w1: [[-0.8113182 1.4845988 0.06532937] [-2.4427042 0.0992484 0.5912243 ]] w2: [[-0.8113182 ] [ 1.4845988 ] [ 0.06532937]]
3 反向传播
3.1 反向传播中的概念
目的:训练模型参数,在所有参数上用梯度下降,使NN模型在训练数据上的损失函数最小
目标:以减少loss值为优化目标
损失函数(loss):预测值(y)与已知答案(y_)的差距,其中已知答案也成为数据标签。损失函数的计算有很多方法,均方误差是比较常用的方法之一。
均方误差(MSE):在神经网络计算中的均方误差的计算方法 ---> 求前向传播计算结果与已知答案之差的平方再求平均。计算公式
用tensorflow代码表示为
loss_mse = tf.reduce_mean(tf.square(y_ -y))
反向传播训练方法:常见的有梯度下降、momentum优化器、adam优化器等优化方法。三种优化器的Tensorflow代码如下:
train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) train_step=tf.train.MomentumOptimizer(learning_rate, momentum).minimize(loss) train_step=tf.train.AdamOptimizer(learning_rate).minimize(loss)
三种优化方法区别如下:
(1)tf.train.GradientDescentOptimizer()使用随机梯度下降算法,使参数沿着梯度的反方向,即总损失减小的方向移动,实现更新参数。
参数更新公式是
其中,?(?)为损失函数,?为参数,?为学习率。
(2)tf.train.MomentumOptimizer()在更新参数时,利用了超参数,参数更新公式是
?? = ???−1 + ?(??−1)
?? = ??−1 − ???
其中,?为学习率,超参数为?,?为参数,?(??−1)为损失函数的梯度。
(3)tf.train.AdamOptimizer()是利用自适应学习率的优化算法,Adam 算法和随机梯度下降算法不同。随机梯度下降算法保持单一的学习率更新所有的参数,学习率在训练过程中并不会改变。而 Adam 算法通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应性学习率。
学习率:决定每次参数更新的幅度。
上述的优化器中都有一个学习率的参数;学习率参数较大时会出现震荡不收敛的情况,学习率参数较小时,会出现收敛速度慢的情况。我们可以选个比较小的值填入,比如 0.01、0.001。
3.2 反向传播的神经网络实现过程
1 从数据集中提取特征,作为输入喂给神经网络(NN)
2 搭建NN结构,从输入到输出(先搭建计算图,再用会话执行)。NN前向传播算法 --> 计算输出。
3 大量特征数据喂给NN,迭代优化NN参数。(NN反向传播算法 --> 优化参数训练模型)
4 使用训练好的模型预测和分类
3.3 反向传播参数更新推导过程
(略)
4 神经网络的代码实现
4.1 导入模块
# coding:utf-8 # 导入模块,生成模拟数据集。 import tensorflow as tf import numpy as np
4.2 设置深度学习的batch_size
BATCH_SIZE = 8
batch_size表示批处理数据量,也可以理解为一次喂入数据的量。
关于batch_size的值大小可以参考关于深度学习中的batch_size
4.3 准备数据集
由于没有现成大量的数据集,所以只有采用numpy库随机函数 “制造” 数据集。
一组数据分为重量和体积两个数据。同时为了每次运算代码的结果相同,将随机函数设置了一个伪随机函数pseudo-random number generator.
# 设置seed值仅为每次代码运行后数据 SEED = 23455 # 基于seed产生随机数 rdm = np.random.RandomState(SEED) # rand函数产生随机数,返回32行2列矩阵 # 32行代表32组数据,2代表输入数据的2个特征 X = rdm.rand(32, 2) # 为每组数据制备标签 # 若(体积+重量) ≥ 1,则 Y 赋值 0 # 若(体积+重量) < 1,则 Y 赋值 1 # Y 值为输入数据集的标签(正确答案),这里记为 Y_ Y_ = [[int(x0 + x1 < 1)] for (x0, x1) in X] # 在神经网络中,print函数是可不写的 # 此处仅为了便于观察过程数据 print("X:\n",X) print("Y_:\n",Y_)
运行
X: [[0.83494319 0.11482951] [0.66899751 0.46594987] [0.60181666 0.58838408] [0.31836656 0.20502072] [0.87043944 0.02679395] [0.41539811 0.43938369] [0.68635684 0.24833404] [0.97315228 0.68541849] [0.03081617 0.89479913] [0.24665715 0.28584862] [0.31375667 0.47718349] [0.56689254 0.77079148] [0.7321604 0.35828963] [0.15724842 0.94294584] [0.34933722 0.84634483] [0.50304053 0.81299619] [0.23869886 0.9895604 ] [0.4636501 0.32531094] [0.36510487 0.97365522] [0.73350238 0.83833013] [0.61810158 0.12580353] [0.59274817 0.18779828] [0.87150299 0.34679501] [0.25883219 0.50002932] [0.75690948 0.83429824] [0.29316649 0.05646578] [0.10409134 0.88235166] [0.06727785 0.57784761] [0.38492705 0.48384792] [0.69234428 0.19687348] [0.42783492 0.73416985] [0.09696069 0.04883936]] Y_: [[1], [0], [0], [1], [1], [1], [1], [0], [1], [1], [1], [0], [0], [0], [0], [0], [0], [1], [0], [0], [1], [1], [0], [1], [0], [1], [1], [1], [1], [1], [0], [1]]
备注:关于类RandomState具体详细 numpy中的np.random.mtrand.RandomState
4.4 前向传播
定义神经网络的输入、参数和输出;定义前向传播过程。主要分三个小步骤
- 对数据集进行预处理(占位placeholder)操作(输入值、标签)
- 生成层间映射的权重参数(Variable)
- 对每层的输入参数与权重参数进行矩阵乘法运算(matmul),并输出(作为下一层神经网络的输出)
# 输入的每一组数据包含有 体积 和 重量 两个数据,shape第一维2 # 输入的数据总共多少组未知,所以用placeholder占位,shape第一维None x = tf.placeholder(tf.float32, shape=(None, 2)) # 数据集的标签总共多少个未知,所以placehloder占位,shape第一维为None # 每一组数据对应一个标签 0 或 1,故shape第二维为1 y_ = tf.placeholder(tf.float32, shape=(None, 1)) # 生成权重参数,w1是从输入层到隐藏层的权重参数 # w1要匹配输入层和隐藏层特征参数 # 输入层有体积和权重两个特征参数 # 隐藏层有a1、a2、a3三个特征参数 # 故tf.random_normal()函数中的参数为[2, 3] w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) # 生成权重参数,w2是从隐藏层到输出层的权重参数 # w2要匹配隐藏层和输出层特征参数 # 隐藏层有a1、a2、a3三个特征参数 # 输出层有标签一个特征参数 # 故tf.random_normal()函数中的参数为[3, 1] w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) # 将输入层与w1进行 矩阵乘法 运算,产生隐藏层值 a = tf.matmul(x, w1) # 将隐藏层与w2进行 矩阵乘法 运算,生成输出层值 y = tf.matmul(a, w2)
4.5 定义函数及反向传播
# 损失函数:本案例采用均方误差为损失函数 loss_mse = tf.reduce_mean(tf.square(y-y_)) # 采用梯度下降法实现训练过程 # 其中学习率为0.001 train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse) # Momentum和AdamOptiminzer优化方法与梯度下降法等价 # train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_mse) # train_step = tf.train.AdamOptimizer(0.001).minimize(loss_mse)
4.6 生成会话
生成会话,并将其(前向传播、反向传播)进行多轮训练。
#3生成会话,训练STEPS轮 with tf.Session() as sess: # 全局变量初始化 init_op = tf.global_variables_initializer() sess.run(init_op) # 输出目前(未经训练)的参数取值。 print("w1:\n", sess.run(w1)) print("w2:\n", sess.run(w2)) print("\n") # 训练模型。 # 训练3000轮 STEPS = 3000 for i in range(STEPS): # (i*batch_size)%32值有0 8 16 24 # 对32取余主要是输入值共有32对 start = (i*BATCH_SIZE) % 32 # batch_size=8 end = start + BATCH_SIZE # train_step梯度下降法训练数据,feed_dict为喂入特征数据
# 用run()函数执行训练过程 sess.run(train_step, feed_dict={x: X[start:end], y_: Y_[start:end]}) # 每500轮打印loss值 if i % 500 == 0: total_loss = sess.run(loss_mse, feed_dict={x: X, y_: Y_}) print("After %d training step(s), loss_mse on all data is %g" % (i, total_loss)) # 输出训练后的参数取值。 print("\n") print("w1:\n", sess.run(w1)) print("w2:\n", sess.run(w2))
运行
After 0 training step(s), loss_mse on all data is 5.13118 After 500 training step(s), loss_mse on all data is 0.429111 After 1000 training step(s), loss_mse on all data is 0.409789 After 1500 training step(s), loss_mse on all data is 0.399923 After 2000 training step(s), loss_mse on all data is 0.394146 After 2500 training step(s), loss_mse on all data is 0.390597 w1: [[-0.7000663 0.9136318 0.08953571] [-2.3402493 -0.14641264 0.5882305 ]] w2: [[-0.06024266] [ 0.91956186] [-0.06820708]]
4.7 将上述代码全部呈现
# coding:utf-8 # 导入模块,生成模拟数据集。 import tensorflow as tf import numpy as np BATCH_SIZE = 8 # 设置seed值仅为了该段代码运行完毕后,所有的结果都一直 SEED = 23455 # 基于seed产生随机数 # rdm = np.random.RandomState(SEED) rdm = np.random.mtrand.RandomState(SEED) print(rdm) # 随机数返回32行2列的矩阵 表示32组 体积和重量 作为输入数据集 X = rdm.rand(32, 2) # 从X这个32行2列的矩阵中 取出一行 判断如果和小于1 给Y赋值1 如果和不小于1 给Y赋值0 # 作为输入数据集的标签(正确答案) Y_ = [[int(x0 + x1 < 1)] for (x0, x1) in X] print("X:\n",X) print("Y_:\n",Y_) #1定义神经网络的输入、参数和输出,定义前向传播过程。 # 输入的每一组数据包含有 体积 和 重量 两个数据,shape第一维2 # 输入的数据总共多少组未知,所以用placeholder占位,shape第一维None x = tf.placeholder(tf.float32, shape=(None, 2)) # 数据集的标签总共多少个未知,所以placehloder占位,shape第一维为None # 每一组数据对应一个标签 0 或 1,故shape第二维为1 y_ = tf.placeholder(tf.float32, shape=(None, 1)) # 生成权重参数,w1是从输入层到隐藏层的权重参数 # w1要匹配输入层和隐藏层特征参数 # 输入层有体积和权重两个特征参数 # 隐藏层有a1、a2、a3三个特征参数 # 故tf.random_normal()函数中的参数为[2, 3] w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) # 生成权重参数,w2是从隐藏层到输出层的权重参数 # w2要匹配隐藏层和输出层特征参数 # 隐藏层有a1、a2、a3三个特征参数 # 输出层有标签一个特征参数 # 故tf.random_normal()函数中的参数为[3, 1] w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) # 将输入层与w1进行 矩阵乘法 运算,产生隐藏层值 a = tf.matmul(x, w1) # 将隐藏层与w2进行 矩阵乘法 运算,生成输出层值 y = tf.matmul(a, w2) #2定义损失函数及反向传播方法。 # 损失函数:本案例采用均方误差为损失函数 loss_mse = tf.reduce_mean(tf.square(y-y_)) # 采用梯度下降法实现训练过程 # 其中学习率为0.001 train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse) # Momentum和AdamOptiminzer优化方法与梯度下降法等价 # train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_mse) # train_step = tf.train.AdamOptimizer(0.001).minimize(loss_mse) #3生成会话,训练STEPS轮 with tf.Session() as sess: # 全局变量初始化 init_op = tf.global_variables_initializer() sess.run(init_op) # 输出目前(未经训练)的参数取值。 print("w1:\n", sess.run(w1)) print("w2:\n", sess.run(w2)) print("\n") # 训练模型。 # 训练3000轮 STEPS = 3000 for i in range(STEPS): # (i*batch_size)%32值有0 8 16 24 # 对32取余主要是输入值共有32对 start = (i*BATCH_SIZE) % 32 # batch_size=8 end = start + BATCH_SIZE # train_step梯度下降法训练数据,feed_dict为喂入特征数据 sess.run(train_step, feed_dict={x: X[start:end], y_: Y_[start:end]}) # 每500轮打印loss值, 便于观察损失函数降低的过程 if i % 500 == 0: total_loss = sess.run(loss_mse, feed_dict={x: X, y_: Y_}) print("After %d training step(s), loss_mse on all data is %g" % (i, total_loss)) # 输出训练后的参数取值。 print("\n") print("w1:\n", sess.run(w1)) print("w2:\n", sess.run(w2))
运行
<mtrand.RandomState object at 0x0000024361269D80> X: [[0.83494319 0.11482951] [0.66899751 0.46594987] [0.60181666 0.58838408] [0.31836656 0.20502072] [0.87043944 0.02679395] [0.41539811 0.43938369] [0.68635684 0.24833404] [0.97315228 0.68541849] [0.03081617 0.89479913] [0.24665715 0.28584862] [0.31375667 0.47718349] [0.56689254 0.77079148] [0.7321604 0.35828963] [0.15724842 0.94294584] [0.34933722 0.84634483] [0.50304053 0.81299619] [0.23869886 0.9895604 ] [0.4636501 0.32531094] [0.36510487 0.97365522] [0.73350238 0.83833013] [0.61810158 0.12580353] [0.59274817 0.18779828] [0.87150299 0.34679501] [0.25883219 0.50002932] [0.75690948 0.83429824] [0.29316649 0.05646578] [0.10409134 0.88235166] [0.06727785 0.57784761] [0.38492705 0.48384792] [0.69234428 0.19687348] [0.42783492 0.73416985] [0.09696069 0.04883936]] Y_: [[1], [0], [0], [1], [1], [1], [1], [0], [1], [1], [1], [0], [0], [0], [0], [0], [0], [1], [0], [0], [1], [1], [0], [1], [0], [1], [1], [1], [1], [1], [0], [1]] w1: [[-0.8113182 1.4845988 0.06532937] [-2.4427042 0.0992484 0.5912243 ]] w2: [[-0.8113182 ] [ 1.4845988 ] [ 0.06532937]] After 0 training step(s), loss_mse on all data is 5.13118 After 500 training step(s), loss_mse on all data is 0.429111 After 1000 training step(s), loss_mse on all data is 0.409789 After 1500 training step(s), loss_mse on all data is 0.399923 After 2000 training step(s), loss_mse on all data is 0.394146 After 2500 training step(s), loss_mse on all data is 0.390597 w1: [[-0.7000663 0.9136318 0.08953571] [-2.3402493 -0.14641264 0.5882305 ]] w2: [[-0.06024266] [ 0.91956186] [-0.06820708]]
5 搭建神经网络的八股
搭建神经网络的八股:准备工作、前向传播、反向传播、循环迭代
5.1 准备工作
import - 引入模块
常量定义 - 如BATCH_SIZE等常量的定义,字母大写
生成数据集 - 当没有数据集时,需要自己生成数据集;当有数据集时,需要对其进行筛选优化等操作
5.2 前向传播
定义输入
- x =
- y_ =
定义参数
- w1
- w2
定义输出
- a =
- y =
5.3 反向传播
定义损失函数
- loss =
定义反向传播方法(实际上也是训练过程)
- train_step =
5.4 生成会话,训练STEPS轮
with tf.Session() as sess: init_op = tf.global_variables_initializer() sess_run(init_op) STEPS = 3000 for i in range(STEPS): start = end = sess.run(train_step, feed_dict =