您的位置:首页 > 理论基础 > 计算机网络

基于TensorFlow实现卷积神经网络 2

2017-08-28 16:14 387 查看

Tensorflow建造神经网络

一、实验介绍

1.1 实验内容

上节实验,我们学习了 TensorFlow 的处理结构以及基本使用,本节我们将使用 TensorFlow 搭建我们自己的神经网络。

1.2 实验知识点

神经网络
过拟合
dropout 层

可视化
Tensorboard

保存训练好的模型

1.3 实验环境

python2.7
Tensorflow
Xfce终端

二、 神经网络

2.1 神经网络是什么?

神经网络是一种应用广泛的机器学习模型,是存在于计算机内部的神经系统,由大量的神经元相连接并进行计算,这些神经元负责传递信息和加工信息,通过外界信息的输入,不断改变神经网络内部的结构,实现输入和输出间复杂的关系的建模。

下图就是一个简单的神经网络系统,输入层负责接收信息,比如说一只猫的图片;输出层就是计算机对这个输入信息的认知,判断它是不是猫。隐藏层就是对输入信息的加工处理。



你可以通过学习
814 使用python实现深度神经网络
来理解神经网络。也可以通过最近
Google Tensorflow
做的一个非常直观的
神经网络 playground
来体验神经网络的处理过程,毫不夸张的说,通过
playground
你可以在自己的浏览器里面直接
玩深度神经网络
了。

在本实验中对于神经网络的基本概念不再详述,只对部分重点进行讲解。

2.2 神经网络究竟在干嘛?

机器学习其实就是让电脑不断的尝试模拟已知的数据,它能知道自己拟合的数据离真实的数据差距有多远, 然后不断地改进自己拟合的参数,提高拟合的相似度。

本例中蓝色离散点是我们的数据点, 红线是通过神经网络算法拟合出来的曲线,



它是对我们数据点的一个近似表达。可以看出,在开始阶段,红线的表达能力不强,误差很大。但是不过通过不断的学习,预测误差将会被降低。所以学习到后来,红线也能近似表达出数据的样子。



更直观的理解:

如果红色曲线的表达式为:
y = a*x + b
,其中 x 代表 inputs,y 代表 outputs,a 和 b 是神经网络训练的参数。模型训练好了以后,a 和 b 的值将会被确定,比如
a=0.5,b=2
,当我们再输入
x=3
时,我们的模型就会输出
0.5*3 + 2
的结果。

模型通过学习数据,得到能表达数据的参数,然后对我们另外给的数据所作出预测。

2.3 神经网络是如何被训练的?

对于神经网络的训练,首先需要很多数据。比如他要判断一张图片是不是猫。就要输入上千万张的带有标签的猫猫狗狗的图片,然后再训练上千万次。

神经网络训练的结果有对的也有错的,如果是错误的结果,将被当做非常宝贵的经验,那么是如何从经验中学习的呢?就是对比正确答案和错误答案之间的区别,然后把这个区别反向的传递回去,对每个相应的神经元进行一点点的改变。那么下一次在训练的时候就可以用已经改进一点点的神经元去得到稍微准确一点的结果。

每个神经元都有属于它的激活函数,用这些函数给计算机一个刺激行为。

比如,在第一次给计算机看猫的图片的时候,只有部分的神经元被激活,被激活的神经元所传递的信息是对输出结果最有价值的信息。如果输出的结果被判定为是狗,也就是说是错误的了,那么就会修改神经元,对于前一次一些容易被激活的神经元会变得迟钝,另外一些神经元会变得敏感。这样一次次的训练下去,所有神经元的参数都在被改变,它们变得对真正重要的信息更为敏感。



再来看上节实验的动图,TensorFlow 的数据处理过程可以这样理解,在输入层输入数据,然后数据飞到隐藏层飞到输出层,用梯度下降处理,梯度下降会对几个参数进行更新和完善,更新后的参数再次跑到隐藏层去学习,这样一直循环直到结果收敛。

2.4 激励函数

例如一个神经元对猫的眼睛敏感,那当它看到猫的眼睛的时候,就被激励了,相应的参数就会被调优,它的贡献就会越大。

下面是几种常见的激活函数:

x轴表示传递过来的值,y轴表示它传递出去的值:



激励函数在预测层,判断哪些值要被送到预测结果那里。

三、搭建神经网络

3.1 基本流程

定义添加神经层的函数

(1) 训练的数据

(2) 定义节点准备接收数据

(3) 定义神经层:隐藏层和预测层

(4) 定义 loss 表达式

(5) 选择 optimizer 使 loss 达到最小

然后对所有变量进行初始化,通过 sess.run optimizer,迭代 1000 次进行学习。

3.2 开始搭建

3.2.1 准备

打开终端

#激活TensorFlow环境
$ cd /home/shiyanlou/tensorflow
$ source bin/activate

我们将神经网络定义写在
myNetWork.py


$ sudo gedit myNetWork.py

如果需要添加注释,请在文件开头输入

# -*- coding: UTF-8 -*-

TensorFlow、Numpy 使用时需要导入:

import tensorflow as tf
import numpy as np

3.2.2 训练数据

导入或者随机定义训练的数据 x 和 y,这里我们
Numpy API
官方文档) 随机定义训练的数据:
x_data = np.linspace(-1,1,300)[:, np.newaxis]
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise

定义节点准备接收数据
xs = tf.placeholder(tf.float32, [None, 1])
ys = tf.placeholder(tf.float32, [None, 1])

接下来,需要定义我们的神经层,即添加隐藏层和输出层,这里我们先定义一个函数,输入参数有 inputs, in_size, out_size, 和 activation_function:
def add_layer(inputs, in_size, out_size, activation_function=None):
#定义参数 Weights,biases
Weights = tf.Variable(tf.random_normal([in_size, out_size]))
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
#定义拟合公式
Wx_plus_b = tf.matmul(inputs, Weights) + biases
#激励函数
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs

使用
add_layer(inputs, in_size, out_size, activation_function=None)
添加层:

# 添加隐藏层(hidden layer) 输入值是 xs,在隐藏层有 10 个神经元,使用ReLu激活函数
# 输入 1 维数据,经隐藏层处理输出 10 维数据
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)

# 添加输出层(output layer) 输入值是隐藏层 l1,在预测层输出 1 个结果
# 从隐藏层输入得到的 10 维数据,经输出层处理 输出 1 维数据
prediction = add_layer(l1, 10, 1, activation_function=None)

loss表达式(预测结果与真实结果的误差)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction), reduction_indices=[1]))

选择 optimizer 使 loss 达到最小(定义一种方法减少loss)
#最基本的 Optimizer:Gradient Descent,学习率=0.1
optimizer = tf.train.GradientDescentOptimizer(0.1)
train_step = optimizer.minimize(loss)

初始化定义的变量从上一节的学习,我们知道 TensorFlow 在对变量完成创建之后,还需要对变量初始化:
init = tf.initialize_all_variables()

Session
中启动计算图
sess = tf.Session()
# 上面操作在 TensorFlow 中都没有产生运算,直到 sess.run 才会开始运算
sess.run(init)

设置迭代次数
# 迭代 1000 次学习,sess.run optimizer
for i in range(1000):
# training train_step 和 loss 都是由 placeholder 定义的运算,所以这里要用 feed 传入参数, placeholder 和 feed_dict 是绑定用的。
sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
if i % 50 == 0:
# 观察每一步的变化
print(sess.run(loss, feed_dict={xs: x_data, ys: y_data}))

保存
myNetWork1.py
,重新回到终端

(tensorflow) $ python myNetWork.py

如果你的程序开始训练了,那么你使用 Tensoflow 搭建的神经网络已经大功告成!

3.3 改进神经网络

大规模的神经网络有两个缺点:

费时
容易过拟合
过拟合是很多机器学习的通病,过拟合了,得到的模型基本就废了。

过拟合
overfitting


overfitting 就是过度准确地拟合了历史数据,而对新数据预测时就会有很大误差。



而为了解决过拟合问题,一般会采用
ensemble
方法,即训练多个模型做组合,此时,费时就成为一个大问题,不仅训练起来费时,测试起来多个模型也很费时。总之,几乎形成了一个死锁。

dropout的出现很好的可以解决这个问题。

dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。
注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
dropout 是CNN中防止过拟合提高效果的一个大杀器

每次做完dropout,相当于从原始的网络中找到一个更瘦的网络,如下图所示:



因而,对于一个有N个节点的神经网络,有了dropout后,就可以看做是
2^n
个模型的集合了(因为每个节点都有丢弃和保留2个选择),但此时要训练的参数数目却是不变的,这就解决了费时的问题。

Tensorflow 有一个很好的工具, 叫做
dropout
,只需要给予它一个不被 drop 掉的百分比,就能很好地降低 overfitting。

代码实现就是在
add layer
函数里加上
dropout
keep_prob
就是保持多少不被 drop,在迭代时在 sess.run 中被 feed:

def add_layer(inputs, in_size, out_size, activation_function=None):
#定义参数 Weights,biases
Weights = tf.Variable(tf.random_normal([in_size, out_size]))
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
#定义拟合公式
Wx_plus_b = tf.matmul(inputs, Weights) + biases
#隐含节点dropout率等于0.5的时候效果最好,即 keep_prob=0.5,原因是0.5的时候dropout随机生成的网络结构最多。
Wx_plus_b = tf.nn.dropout(Wx_plus_b, keep_prob=0.5)
#激励函数
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs

获取本节完整的代码:

$ cd /home/shiyanlou/tensorflow
$ wget http://labfile.oss.aliyuncs.com/courses/893/myNetWork1.py

3.4 可视化
Tensorboard

Tensorflow 自带 tensorboard ,可以自动显示我们所建造的神经网络流程图:

就是用 with tf.name_scope 定义各个框架,注意看代码注释中的区别:

import tensorflow as tf

def add_layer(inputs, in_size, out_size, activation_function=None):
# add one more layer and return the output of this layer
# 区别:大框架,定义层 layer,里面有小部件
with tf.name_scope('layer'):
# 区别:小部件
with tf.name_scope('weights'):
Weights = tf.Variable(tf.random_normal([in_size, out_size]), name='W')
with tf.name_scope('biases'):
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1, name='b')
with tf.name_scope('Wx_plus_b'):
Wx_plus_b = tf.add(tf.matmul(inputs, Weights), biases)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b, )
return outputs

# 区别:大框架,里面有 inputs x,y
with tf.name_scope('inputs'):
xs = tf.placeholder(tf.float32, [None, 1], name='x_input')
ys = tf.placeholder(tf.float32, [None, 1], name='y_input')

# add hidden layer
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)
# add output layer
prediction = add_layer(l1, 10, 1, activation_function=None)

# 区别:定义框架 loss
with tf.name_scope('loss'):
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
reduction_indices=[1]))
# 区别:定义框架 train
with tf.name_scope('train'):
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

sess = tf.Session()

# 区别:sess.graph 把所有框架加载到一个文件中放到文件夹"logs/"里
# 接着打开terminal,进入你存放的文件夹地址上一层,运行命令 tensorboard --logdir='logs/'
# 会返回一个地址,然后用浏览器打开这个地址,在 graph 标签栏下打开
writer = tf.train.SummaryWriter("logs/", sess.graph)
# important step
sess.run(tf.initialize_all_variables())

运行完上面代码后,打开 terminal,进入你存放的文件夹地址上一层,运行命令 tensorboard --logdir='logs/' 后会返回一个地址,然后用浏览器打开这个地址,点击 graph 标签栏下就可以看到流程图了:



获取本节完整的代码:

$ cd /home/shiyanlou/tensorflow
$ wget http://labfile.oss.aliyuncs.com/courses/893/myNetWork2.py

3.5 保存和加载

训练好了一个神经网络后,可以保存起来下次使用时再次加载,但是TensorFlow 现在只能保存 variables,还不能保存整个神经网络的框架,所以再使用的时候,需要重新定义框架,然后把 variables 放进去学习。

$ cd /home/shiyanlou/tensorflow
$ sudo mkdir my_net

我们将变量保存在
my_net
下。

import tensorflow as tf
import numpy as np
## Save to file
# remember to define the same dtype and shape when restore
W = tf.Variable([[1,2,3],[3,4,5]], dtype=tf.float32, name='weights')
b = tf.Variable([[1,2,3]], dtype=tf.float32, name='biases')

init= tf.initialize_all_variables()

saver = tf.train.Saver()

# 用 saver 将所有的 variable 保存到定义的路径
with tf.Session() as sess:
sess.run(init)
save_path = saver.save(sess, "my_net/save_net.ckpt")
print("Save to path: ", save_path)

成功执行之后,my_net 下将会生成三个文件

checkpoint
save_net.ckpt 这个是我们保存变量的文件
save_net.ckpt.meta
获取代码

$ cd /home/shiyanlou/tensorflow
$ wget http://labfile.oss.aliyuncs.com/courses/893/myNetWork3.py

提取我们已经保存的变量

# restore variables
# redefine the same shape and same type for your variables
W = tf.Variable(np.arange(6).reshape((2, 3)), dtype=tf.float32, name="weights")
b = tf.Variable(np.arange(3).reshape((1, 3)), dtype=tf.float32, name="biases")

# not need init step

saver = tf.train.Saver()
# 用 saver 从路径中将 save_net.ckpt 保存的 W 和 b restore 进来
with tf.Session() as sess:
saver.restore(sess, "my_net/save_net.ckpt")
print("weights:", sess.run(W))
print("biases:", sess.run(b))

获取代码:

$ cd /home/shiyanlou/tensorflow
$ wget http://labfile.oss.aliyuncs.com/courses/893/myNetWork4.py

四、实验总结

本节实验我们动手实现了一个简单的神经网络,并加入了
dropout layer
实现了简单的优化,并用
TensorBoard
可视化了我们所设计的神经网络结构,最后学习了如何保存号我们已经训练好的模型。如果你亲自敲下每一行代码,我相信你在学完本节之后会对神经网络有更深层次的认识。

下节实验,我们将在本节实验的基础上,实现深度学习中最经典的模型之一
卷积神经网络(CNN)


五、课后习题

请学习 CNN 的理论基础
861 基于卷积神经网络实现图片风格的迁移.
卷积神经网络详解章节


六、参考链接

TensorFlow 英文官方网站
TensorFlow 官方GitHub仓库
TensorFlow PlayGround
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: