Tensorflow实现简单神经网络

1. 神经网络参数与tensorflow变量

在tensorflow中使用tf.variable定义变量,变量作用是保存和更新神经网络中的参数。并且要给变量初始化一个初始值:

weights=tf.Variable(tf.random_normal([2, 3], stddev=2))

这里定义了一个2x3的矩阵,矩阵中的元素是均值为0,标核差为2的随机数,这是因为tf.random_normal函数通过参数mean来指定平均值,在没有指定时默认为0,而且通常是定义一个满足正态分布的随机数来初始化神经网络的参数,目前支持的有:

  • tf.random_normal:正态分布(平均值、标准差、取值类型)
  • tf.truncated_normal:正态分布,但如果随机出来的值偏离平均值超过2个标准差,那么这个数将会被重新随机。(平均值、标准差、取值类型)
  • tf.random_uniform:平均分布(最小、最大取值、取值类型)
  • tf.random_gamma:gamma分布 (形状参数alpha、尺度参数、取值类型)

tensorflow还支持初始化一个常数变量。

  • tf.zeros:产生全0的数组
  • tf.ones:产生全1的数组
  • tf.fill:产生一个全部为给定数字的数组(tf.fill([2,3],9)->[[9,9,9],[9,9,9]])
  • tf.constant:产生一个给定值的常量(tf.constant([1,2,3])->[1,2,3])
1.1 在tensorflow中一个变量的值在使用之前必须被初始化。

示例:

import tensorflow as tf
#这里通过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 = tf.constant([[0.7, 0.9]])  
# 前向传播:1x2的输入->和隐层的2x3的权重矩阵相乘得到1x3矩阵->和输出层的3x1矩阵
# 相乘得到输出
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
# 打开会话
sess = tf.Session()
# 这里是对变量为w1、w2的初始化
sess.run(w1.initializer)  
sess.run(w2.initializer)
# 在通过以下进行y值的获取之前必须进行变量的初始化,而常量则不需要  
print(sess.run(y))  
sess.close()

结果:

[[3.957578]]

这里要注意的两点是:

  • 在所有的变量被定义时给出了初始化的方法,但并没有真正的运行,但通过运行w1.initializer才被真正赋初值。
  • 变量的真正计算是通过会话才完成的。
  • 在实际的使用中一般通过tf.initialize_all_variable()来初始化所有的变量,这样就不会有漏掉的变量忘了初始化,而且省了很大的力气。
1.2 变量的管理

这里简单说下变量和张量的区别:
所有的数据都是通过张量的形式来组织的。而 tf.Variable运算的结果就是一个张量,所以变量是一种特殊的张量。
- 在tensorflow中有一个集合的概念,就是所有的变量都会自动加入到graphKeys.VARIABLES这个集合。这个集合主要是为了管理变量,可以通过tf.all_variables函数拿到所有的当前计算图上的变量,这有助于持久化整个计算图的运行状态。
- 在构建机器学习模型时,可以通过变量声明函数中的trainable参数来区分需要优化的参数(比如神经网络中的参数,很重要)和其他的以一些参数(比如迭代轮数),如果在声明变量时参数trainable为true,那么这个变量将会被加入graphKeys.TRAINABLE_VARIABLES集合,然后通过tf.trainable_variables函数得到所有需要优化的参数,而tensorflow也会把graphKeys.TRAINABLE_VARIABLES集合中的变量作为默认的优化参数。

此外关于变量(维度、类型)还要注意:

  • 变量的维度在运行中是可以更改的,但是需要通过参数设置,validate_shape=False
w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
w2= tf.Variable(tf.random_normal([22], stddev=1, seed=1))
# 会报错:维度不匹配
tf.assign(w1,w2)
# 改成这样就不会报错
tf.assign(w1,w2,validate_shape=False)

实际中其实用的很少。。。

  • 变量的类型在构建之后是不允许再改变的,比如w1,w2初始类型不同,在运行中执行如下就会报错:
w1.assign(w2)
2. 神经网络训练模型示例
2.1 常量数据的表达

这里首先说下在进行反向传播的过程中的第一步是使用tensorflow表达一个batch的数据,如果这时用普通的常量来定义,也就是说和普通编程一样,把输入数据定义为常量,这时会造成每来一个batch的数据,就需要定义一个batch的常量,而每生成一个常量,tensorflow都会在图中增加一个节点,这样的话在整个神经网络的训练过程中将产生很大的计算图,这样肯定是不行的,所以就有了placeholder机制,用于提供数据。placehlder其实相当于定义了一个位置,而这个位置的数据是在程序运行时再指定,这样就不用生成大量的常量来提供输入数据,而只需要将数据输入到placeholder来进行计算图的计算。
注意:placeholder在定义时,需要指定维度和数据类型,而数据类型是不能改变的,但是数据的维度可以根据提供的数据推导出来,所以不一定要给出。

import tensorflow as tf
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 = tf.constant([[0.7, 0.9]])  
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)) # 这里会报错,因为没有输入数据
# 下面这句是可以的
print(sess.run(y, feed_dict={x: [[0.7,0.9]]}))

这里需要注意的是在所有是初始化和输入都定义好了以后,在sess运行前向传播的时候需要提供一个feed_dict字典,也就是需要喂给模型数据才能跑起来,而且需要指定每一个placeholder的取值,否则会报错。

在得到前向传播的数值后,需要定义一个损失函数来刻画当前的预测值和真实值之间的差距,常用的就是交叉熵损失函数。

# 损失函数
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
# 反向传播优化神经网络参数
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)

注意:目前tensorflow支持7种不同的优化器,比较常用的三种:

tf.train.gradientdescentoptimizer
tf.train.adamoptimizer
tf.train.momentumoptimizer

在定义好反向传播后就可以通过运行sess.run(train_step)就可以对所有在graphKeys.TRAINABLE_VARIABLES集合中的变量进行优化,以使得当前batch下损失函数更小。

下面是完整代码:

import tensorflow as tf
from numpy.random import RandomState

# 定义神经网络的参数,输入和输出节点。
batch_size = 8
w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) # 这里是一个隐层,并且是3个节点
w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1)) 
x = tf.placeholder(tf.float32, shape=(None, 2), name="x-input") # 输入是个节点,即是每个样本2个特征
y_= tf.placeholder(tf.float32, shape=(None, 1), name='y-input') # 输出是2分类

# 定义前向传播过程,损失函数及反向传播算法
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
y = tf.sigmoid(y) # 逻辑回归2分类
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
                                + (1 - y_) * tf.log(tf.clip_by_value(1 - y, 1e-10, 1.0)))
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)

# 生成模拟数据集
rdm = RandomState(1)
X = rdm.rand(128,2)
Y = [[int(x1+x2 < 1)] for (x1, x2) in X]
print('Y:',Y)

# 创建一个会话来运行TensorFlow程序
with tf.Session() as sess:
    # 初始化所有的变量
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    # 输出目前(未经训练)的参数取值,这里是tensorflow中显示输出的方法
    print(sess.run(w1))
    print(sess.run(w2))
    print("\n")

    # 训练模型。
    STEPS = 5000
    for i in range(STEPS):
        # 每次选择batch_size个样本进行训练
        start = (i*batch_size) % 128
        end = (i*batch_size) % 128 + batch_size
        # 通过选取的batch_size训练样本训练网路并更新
        sess.run([train_step, y, y_], feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            # 每1000次迭代后,使用全部的样本进行计算交叉熵,并输出
            total_cross_entropy = sess.run(cross_entropy, feed_dict={x: X, y_: Y})
            print("After %d training step(s), cross entropy on all data is %g" % (i, total_cross_entropy))

    # 输出训练后的参数取值。
    print("\n 训练结果:")
    print(sess.run(w1))
    print(sess.run(w2))

运行结果:

Y: [[0], [1], [1], [1], [1], [0], [0], [1], [1], [1], [0], [0], [0], [1], [0], [1], [0], [0], [0], [1], [0], [0], [1], [0], [1], [1], [1], [1], [1], [0], [1], [0], [1], [0], [0], [0], [1], [1], [0], [0], [0], [0], [0], [0], [0], [0], [0], [1], [0], [1], [1], [0], [0], [1], [0], [1], [0], [1], [0], [1], [1], [1], [0], [0], [1], [0], [1], [0], [0], [0], [1], [1], [1], [1], [1], [0], [1], [1], [1], [0], [1], [0], [1], [1], [0], [0], [1], [0], [1], [1], [1], [1], [0], [1], [0], [1], [0], [0], [1], [0], [0], [0], [1], [0], [0], [0], [1], [1], [1], [1], [1], [1], [0], [0], [0], [0], [0], [0], [1], [0], [0], [1], [0], [1], [0], [1], [0], [0]]
[[-0.8113182   1.4845988   0.06532937]
 [-2.4427042   0.0992484   0.5912243 ]]
[[-0.8113182 ]
 [ 1.4845988 ]
 [ 0.06532937]]


After 0 training step(s), cross entropy on all data is 1.89805
After 1000 training step(s), cross entropy on all data is 0.655075
After 2000 training step(s), cross entropy on all data is 0.626172
After 3000 training step(s), cross entropy on all data is 0.615096
After 4000 training step(s), cross entropy on all data is 0.610309

 训练结果:
[[ 0.02476983  0.56948674  1.6921941 ]
 [-2.1977348  -0.23668921  1.1143895 ]]
[[-0.45544702]
 [ 0.49110925]
 [-0.98110336]]

这里要注意:

  • 从运行结果可以看出,随着训练的迭代,交叉熵是逐渐变小的,交叉熵越小说明预测的结果和实际的差距越小。
  • 从中可以看出打印变量值必须在sess中,也就是说关闭会话,打印输出只是一个引用
  • 从最后的运行结果可以看出,训练完成后权重矩阵发生了很大的变化

参考:《Tensorflow实战Google深度学习框架》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值