TensorFlow学习笔记(二):实现神经网络

来源:互联网 发布:js 仿京东楼层特效 编辑:程序博客网 时间:2024/05/31 18:46

使用神经网络解决分类问题主要可以分为4个步骤:

  • 提取问题中的实体的特征向量作为神经网络的输入;
  • 定义神经网络的结构,并定义如何从神经网络的输入得到输出。即前向传播算法;
  • 通过训练数据来调整神经网络中的参数取值;
  • 使用训练好的神经网络来预测未知的数据。

1. 前向传播算法

不同的神经网络前向的传播方式不同,这里介绍最简单的全连接网络结构的前向传播算法。

一个神经元有多个输入和一个输出,每个神经元的输出既可以是其他神经元的输入,也可以是整个神经网络的输出。一个简单神经元的输出是所有输入的加权和,而不同输入的权重就是神经元的参数。

前向传播需要三部分的信息,一是神经网络的输入,而是神经网络的连接结构,三是神经网络的参数。通过输入与参数的加权和,逐层向前传播,直至输出层。TensorFlow的神经网络前向传播过程如下:

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

其中,tf.matmul实现了矩阵乘法的功能。

2. 神经网络参数与TensorFlow变量

神经网络的参数是实现分类或者回归的重要部分,TensorFlow定义矩阵变量的方法如下:

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

这段代码调用了TensorFlow变量的声明函数tf.Variable。tf.random_normal([2,3],stddev=2)会产生一个2行3列的矩阵,矩阵中元素是均值为0,标准差为2的随机数。TensorFlow还提出一些其他的随机数生成器:

  • tf.random_normal:正态分布
  • tf.truncated_normal:正态分布,但如果随机出来的值偏离平均值超过2个标准差,那么将被重新随机
  • tf.random_uniform:平均分布
  • tf.random_gamma:Gamma分布

TensorFlow中常用的常量声明方法:

  • tf.zeros:产生全零数组
  • tf.ones:产生全1数组
  • tf.fill:产生一个全部为给定数字的数组
  • tf.constant:产生一个给定值的常量

神经网络的偏置通常会使用常数来初始化:

biases = tf.Variable(tf.zeros([3]))

也可以用其他变量来初始化新的变量:

w2 = tf.Variable(weights.initialized_value())w3 = tf.Variable(weights.initialized_value()*2.0)

下面介绍如何实现神经网络参数并实现前向传播的过程:

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])a = tf.matmul(x,w1)y = tf.matmul(a,w2)sess = tf.Session()init_op = tf.initialize_all_variables()sess.run(init_op)print(sess.run(y))sess.close()

3. 训练神经网络模型

神经网络训练的核心是通过反向传播算法对参数进行调整。反向传播是一个迭代的过程,每次迭代都要选取一部分训练数据,这部分数据叫做一个batch。然后,这个batch的样例会通过前向传播算法得到神经网络模型的预测结果,因为训练数据都有正确答案标注,所以可以计算当前神经网络模型的预测答案与正确答案之间的差距。最后,反向传播算法会相应更新神经网络参数的取值,使得在这个batch上神经网络模型的预测结果和真实答案更加接近。

TensorFLow提供了placeholder机制用于提供输入数据,placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定,这样就不需要生成大量常量来提供输入数据,只需将数据通过placeholder传入TensorFlow计算图。

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.placeholder(tf.float32, shape=(1,2), name="input")a = tf.matmul(x,w1)y = tf.matmul(a,w2)sess = tf.Session()init_op = tf.initialize_all_variables()sess.run(init_op)print(sess.run(y, feed_dict={x:[[0.7,0.9]]}))sess.close()

在得到一个batch的前向传播结果之后,需要定义一个损失函数来刻画当前的预测值和真实答案之间的差距。然后通过反向传播算法来调整神经网络参数的取值,使得差距可以被缩小。

# 定义交叉熵来刻画预测值与真实值之间的差距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)

交叉熵是分类问题中常用的损失函数,train_step定义了反向传播的优化方法,tensorflow目前支持7种不同的优化器,比较常用的优化方法有三种:tf.train.GradientDescentOptimizer、tf.train.AdamOptimizer和tf.train.MomentumOptimizer。

import tensorflow as tf# 模拟数据集from numpy.random import RandomStatebatch_size = 8 # 训练数据batch的大小# 神经网络参数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.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.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-10,1.0)))train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)rdm = RandomState(1)dataset_size = 128X = rdm.rand(dataset_size,2)Y = [[int(x1+x2<1)] for (x1,x2) in X]with tf.Session() as sess:    init_op = tf.initialize_all_variables()    sess.run(init_op)    print(sess.run(w1))    print(sess.run(w2))    iter = 5000    for i in range(iter):        start = (i*batch_size) % dataset_size        end = min(start+batch_size, dataset_size)        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 all data is %g" % (i, total_cross_entropy))    print(sess.run(w1))    print(sess.run(w2))

训练神经网络的过程可以分为3个步骤:

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

无论神经网络的结构如何变化,这3个步骤是不会改变的。

阅读全文
1 0