TensorFlow实现神经网络

3.4 TensorFlow实现神经网络
3.4.1 TensorFlow游乐场
3.4.2 前向传播
3.4.3 神经网络参数与TensorFlow变量
变量和张量的关系
变量的三个属性:张量、维度、类型
3.4.4通过TensorFlow训练神经网络模型
3.4.5 完整的神经网络样例程序
从程序中总结生成神经网络的步骤

https://playground.tensorflow.org

3.4.2 前向传播

神经网络的输出是通过前向传播的方法得到的,前向传播需要三部分信息:

其一,神经网络的输入(从实体中提取的特征向量)

其二,神经网络的连接结构(不同神经元间输入输出的连接关系)

其三,神经网络中每个神经元的参数(网络层数、权值、偏置、节点数等)
前向传播算法可以表示为矩阵的乘法

TensorFlow矩阵的乘法实现:tf.matmul

a = tf.matmul(x, w1)
y = tf.matmul(a, w2)

3.4.3 神经网络参数与TensorFlow变量

tf.Variable —>保存和更新神经网络中的参数
TensorFlow中的变量也需要指定初始值,一般使用随机数给其中的变量初始化

#声明一个2*3矩阵变量
import tensorflow as tf
weights=tf.Variable(tf.random_normal([2,3],stddev=2))
#2*3的矩阵,矩阵中元素为均值为0,标准差为2的随机数,可以用mean指定平均值,默认为0(正态分布)

<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32_ref>

TensorFlow目前支持的所有随机数生成器
表3-2 TensorFlow随机数生成器

函数名称随机数分布主要参数
tf.random_normal正态分布平均值、标准差、取值类型
tf.truncated_normal正态分布,如果随机出来的值偏离均值超过2个标准差,重新随机平均值、标准差、取值类型
tf.random_uniform平均分布最小、最大取值、取值类型
.random_gammaGamma分布形状参数alpha、尺度参数beta、取值类型

函数完整介绍:

1)tf.random_normal使用方法

tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None) 

解释:

从正态分布中输出随机值。

参数:

 shape: 一维的张量,也是输出的张量。
 mean: 正态分布的均值。 
 stddev: 正态分布的标准差。
 dtype: 输出的类型。
 seed: 一个整数,当设置之后,每次生成的随机数都一样。
 name: 操作的名字。

2)tf.truncated_normal使用方法

tf.truncated_normal(shape,mean=0.0,stddev=1.0,dtype=tf.float32,seed=None,name=None)

解释:

从截断的正态分布中输出随机值。

生成的值服从具有指定平均值和标准偏差的正态分布,如果生成的值大于平均值2个标准偏差的值则丢弃重新选择。

在tf.truncated_normal中如果x的取值在区间(μ-2σ,μ+2σ)之外则重新进行选择。这样保证了生成的值都在均值附近。

代码示例:

a = tf.Variable(tf.random_normal([2,2],seed=1))
b = tf.Variable(tf.truncated_normal([2,2],seed=2))
# 变量初始化
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    print(sess.run(a))
    print(sess.run(b))

输出:

[[-0.81131822  1.48459876]
  [ 0.06532937 -2.44270396]]
 [[-0.85811085 -0.19662298]
  [ 0.13895047 -1.22127688]]

TensorFlow支持通过常数初始化变量,下表列出了常用常数声明方法

表3-3 TensorFlow常数生成函数

函数名称功能样例
tf.zeros产生全0数组tf.zeros([2,3],int32)–>[[0,0,0],[0,0,0]]
tf.ones产生全1数组tf.ones(2,3],int32)–>[[1,1,1],[1,1,1]]
tf.fill产生一个给定值的数组tf.fill([2,3],9)–>[[9,9,9],[9,9,9]]
tf.constant产生一个给定值常量tf.constant([1,2,3])–>[1,2,3]

注意:

c1 = tf.constant([3])   #代表向量,shape=(1, )的一维constant
c2 = tf.constant([[3]]) #代表1*1的矩阵,shape=(1, 1)的二维constant

偏置项(bias):

偏置项通常会使用常数来设定初始值

biases=tf.Variable(tf.zeros([3]))
<tf.Variable 'Variable_1:0' shape=(3,) dtype=float32_ref>

除过使用随机数或者常数,TensorFlow也支持其他变量的初始值来初始化新变量

import tensorflow as tf
weights=tf.Variable(tf.random_normal([2,3],stddev=2))
w2=tf.Variable(weights.initialized_value())
w3=tf.Variable(weights.initialized_value()*2.0)
#w2的初始值设置成了与weights变量相同,w3的初始值是weights初始值的两倍
#TensorFlow中一个变量的值被使用之前,该变量的值需要被明确的调用


<tf.Variable 'Variable_1:0' shape=(2, 3) dtype=float32_ref>
<tf.Variable 'Variable_2:0' shape=(2, 3) dtype=float32_ref>

简单的神经网络

import tensorflow as tf
# 声明w1和w2两个变量,这里还通过seed设定了随机种子,保证每次运行的结果一样
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

#暂时将输入的特征向量定义为一个常量,x是一个1*2的矩阵
x=tf.constant([[0.7,0.9]])
#通过前向传播算法获得神经网络的输出
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)

#调用会话输出结果
sess=tf.Session()
#初始化w1和w2(未初始化不能直接获取值)
sess.run(w1.initializer)  #初始化w1
sess.run(w2.initializer)  #初始化w2
#输出
print(sess.run(y))
sess.close()


# 也可以使用下面的初始化和会话方法
init=tf.global_variables_initializer()
# with tf.Session() as sess:
#     sess.run(init)
#     print(sess.run(y))


[[ 3.95757794]]

程序解析:

第一步:定义TensorFlow计算图中的所有计算,但这些被定义的运算并不需要真正的运行
第二步:声明一个会话,并通过会话计算结果,但在计算y之前,需要将所有用到的变量初始化,也就是说在定义的时候给出了变量初始化的方法,但并没有真正运行。
但当变量数目增多或存在依赖关系时,可以用更加快捷的方法来初始化过程

tf.global_variables_initializer(),【原始tf.initialize_all_variables()会报错】
sess=tf.Session()
init_op=tf.global_variables_initializer()
#init_op=tf.initialize_all_variables()->报错
sess.run(init_op)

变量和张量的关系
变量的三个属性:张量、维度、类型
1.张量

TensorFlow中所有的数据都是通过张量的形式来组织的,变量声明函数tf.Variable()是一个运算,该运算会产生一个张量,该张量也就是本节所介绍的变量,所以变量就是特殊的张量。

构建机器学习模型时,可以通过变量声明函数中的trainable函数来区分需要优化的参数(神经网络的参数)和其他参数(如迭代次数),如果trainable为True,则变量会被加入 集合 GraphKeys.TRAINBALE_VARIABLES中,TensorFlow可以通过tf.variable_variables来得到所有需要优化的参数,TensorFlow的神经网络优化算法将tf.variable_variables集合中的变量默认为优化对象。

2.维度

维度在程序运行过程中是可变的,但需要通过设置参数:validate_shape=False

import tensorflow as tf
# 声明w1和w2两个变量,这里还通过seed设定了随机种子,保证每次运行的结果一样
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
#下面会报错:维度不匹配
tf.assign(w1,w2)
#下面会正确执行
tf.assign(w1,w2,validate_shape=False)
#tf.assign(A, new_number): 这个函数的功能主要是把A的值变为new_number

3.类型
变量的类型不可变,一个变量构建之后类型已经固定。

3.4.4通过TensorFlow训练神经网络模型

本节主要介绍使用监督学习的方式更合理的设置参数的取值

设置神经网络参数的过程就是神经网络的训练过程,只有经过有效训练的神经网络才能真正的解决分类或者回归问题。

使用监督学习的方式设置神经网络参数需要有一个标注好的训练数据集

监督学习的思想:

在已知答案的标注数据集上,模型给出的预测结果要尽可能的接近真实的答案,通过调整神经网络中的参数对训练数据进行拟合,可以使得模型对未知样本提供预测能力。

通过反向传播算法训练神经网络:

反向传播过程实现了一个迭代的过程:

迭代开始,首先选取一小部分训练数据(称为batch);
该batch样例通过前向传播算法得到神经网络的预测结果;
计算预测结果和正确答案见的差距;
基于上述差距,利用反向传播算法更新神经网络参数,使得在该batch上的神经网络模型预测结果和真实答案更加接近;
通过TensorFlow实现反向传播:

1.实现一个样例(batch)的前向传播

表达一个batch的数据:placeholder

已知可以利用常量来表达选取的数据,但是这样一来计算图会太大,因为每生成一个常量,TensorFlow都会在计算图中增加一个节点,所以TensorFlow引入placeholder机制用于提供数据。

placeholder:定义一个位置,该位置的数据在程序运行时再指定,只需要将数据通过placeholder来传入计算图中,而不用大量的常量来提供输入数据。

placeholder: 中文意思是占位符,在tensorflow中类似于函数参数,运行时必须传入值,经常会有一些待输入的参数,但是在建立模型时,需要使用到它,那么就需要使用占用符的方式来写入计算公式里,也就是建立到模型里的关系。

import tensorflow as tf

# 声明w1和w2两个变量,这里还通过seed设定了随机种子,保证每次运行的结果一样
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

#定义placeholder作为存放输入数据的地方,维度不一定要定义,但如果是确定的维度,可以降低出错概率
x=tf.placeholder(tf.float32,shape=(1,2),name="input")
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)

sess=tf.Session()
init_op=tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(y,feed_dict={x:[[0.7,0.9]]}))


[[ 3.95757794]]

程序中替换了原理通过常量定义的输入x,计算前向传播时需要提供一个feed_dict来指定x的取值,feed_dict是一个字典,字典中需要给出每个用到的placeholder的取值。

2.实现n个样例的前向传播

将上述输入的1∗21∗2矩阵改为n∗2n∗2矩阵,其中每一行都为一个样例数据,这样得到的前向传播结果为n∗1n∗1的矩阵。

import tensorflow as tf
# 声明w1和w2两个变量,这里还通过seed设定了随机种子,保证每次运行的结果一样
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
#定义placeholder作为存放输入数据的地方,维度不一定要定义,但如果是确定的维度,可以降低出错概率
x=tf.placeholder(tf.float32,shape=(3,2),name="input")
a=tf.matmul(x,w1)
y=tf.matmul(a,w2)

sess=tf.Session()
init_op=tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))


[[ 3.95757794]
 [ 1.15376544]
 [ 3.16749239]]

上面例子中,一次性计算多个batch的前向传播结果,运行时需要将3个样例[0.7,0.9],[0.1,0.4],[0.5,0.8]组成一个32的矩阵传入placeholder中,计算得到31的矩阵。

3. 定义损失函数来刻画当前预测值和真实答案的差距

cross_entropy=-tf.reduce_mean(y_ *tf.log(tf.clip_by_value(y,1e-10,1.0)))
#定义学习率
learning_rate=0.001
#定义反向传播算法来优化神经网络中的参数
train_step=tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)

cross_entropy:定义了真实值和预测值之间的交叉熵(分类中的常用损失函数)
train_step:定义了反向传播的优化算法

代码中的交叉熵损失函数解释:

交叉熵用于衡量原始分布p(x)p(x)和预测分布q(x)q(x)之间的距离,CH(p,q)=−∑xp(x)logq(x)CH(p,q)=−∑xp(x)logq(x)。

p(x)p(x):就是真实的标签yy
q(x)q(x):就是预测的值yy
logq(x)logq(x):tf.log(tf.clip_by_value(y, 1e-10, 1.0))

常用优化算法:

tf.train.GradientDescentOptimizer 
tf.train.AdamOptimizer 
tf.train.MomentumOptimizer

3.4.5 完整的神经网络样例程序

3.5.5 神经网络样例程序

import tensorflow as tf
from numpy.random import RandomState

# 定义训练数据batch的大小
batch_size = 8

# 定义神经网络参数
# random_normal 产生一个正态随机矩阵,shape=[2,3],stddev是正太分布的标准差,seed随机数种子,设置后每次产生的数字都相同
w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))

# 在shape的一个维度上使用None可以方便使用不大的batch大小,
# 在训练时需要将数据分成较小的batch,但在测试时,可以一次性使用全部的数据,
# 数据集较小时方便测试,但是数据集较大时,大量的数据放入一个batch可能会导致数据溢出。
# placeholder占位符,执行时,在通过feed_dict将值传入,dtype:数据类型,shape:数据形状,name:名称
# 如果在定义占位符时,不能确定值的形状时,用None表示
x = tf.placeholder(tf.float32, shape=[None, 2], name='x-input')
y_ = tf.placeholder(tf.float32, shape=[None, 1], name='y-input')

# 定义前向传播的过程
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)

# 定义损失函数和反向传播算法
# cross_entropy是交叉熵
# tf.clip_by_value(A, min, max):输入一个张量A,把A中的每一个元素的值都压缩在min和max之间。小于min的让它等于min,大于max的元素的值等于max
# reduce_mean 求均值
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
# train_step 就是每次可训练出一组w就是一次反向传播  
# 下面给出里三种反向传播的算法传入的是学习率
# train_step = tf.train.AdamOptimizer(0.001).minimise(cross_entropy)
# train_step=tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)
train_step = tf.train.MomentumOptimizer(0.001, 0.9).minimize(cross_entropy)

# 通过随机数生成一个模拟数据集

rdm = RandomState(1)  # 1为伪随机数产生的种子
dataset_size = 128
X = rdm.rand(dataset_size, 2)

# 此处使用0表示负样本,1表示正样本
Y = [[int(x1 + x2 < 1)] for (x1, x2) in X]

# 创建一个会话来运行Tensorflow程序,反复运行反向传播
# tf中运行必须放在session对象中,且运行过后,要关闭session
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    # 初始化变量,也就是上面的Variable变量
    sess.run(init_op)
    print(sess.run(w1))
    print(sess.run(w2))

    # 设定训练的轮数
    STEPS = 5000
    for i in range(STEPS):
        # 每次选取batch_size个样本进行训练
        start = (i * batch_size) % dataset_size
        end = min(start + batch_size, dataset_size)
        # 通过选取的样本训练神经网络并进行参数更新
        # feed_dict的作用是给使用placeholder创建出来的tensor赋值
        sess.run(train_step, feed_dict={x: X[start: end], y_: Y[start:end]})
        if i % 1000 == 0:
            total_cross_entropy = sess.run(cross_entropy, feed_dict={x: X, y_: Y})
            print("After %d training steps,cross entropy on all data is %g" % (i, total_cross_entropy))
    print(sess.run(w1))
    print(sess.run(w2))


训练之前神经网络的参数:
w1=[[-0.81131822  1.48459876  0.06532937]
    [-2.4427042   0.0992484   0.59122431]]
w2=[[-0.81131822],[ 1.48459876],[ 0.06532937]]

输出结果: 
After 0 training steps,cross entropy on all data is 0.0677127
After 1000 training steps,cross entropy on all data is 0.0299578
After 2000 training steps,cross entropy on all data is 0.0226611
After 3000 training steps,cross entropy on all data is 0.0178286
After 4000 training steps,cross entropy on all data is 0.0143322
训练之后神经网络的参数:
w1=[[-1.14571726  1.92318034  0.107902  ]
    [-2.79355311  0.57146555  0.63480443]]
w2=[[-1.77604687],[ 2.00357008],[ 0.25552016]]

从程序中总结生成神经网络的步骤
训练神经网络过程可以分为以下三个步骤:

定义神经网络的结构和前向传播的输出结果;
定义损失函数以及选择反向传播优化的算法;
生成会话(tf.Session),并且在训练数据上反复运行反向传播优化算法;

原文:https://blog.csdn.net/jiaoyangwm/article/details/79237385

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值