一、 LeNet-5

  • LeNet-5是一种用于手写体字符识别的非常高效的卷积神经网络。
  • 卷积神经网络能够很好的利用图像的结构信息。
  • 卷积层的参数较少,这也是由卷积层的主要特性即局部连接和共享权重所决定。

  LeNet-5共有7层,不包含输入,每层都包含可训练参数;每个层有多个Feature Map,每个FeatureMap通过一种卷积滤波器提取输入的一种特征,然后每个FeatureMap有多个神经元。

数据集:mnist

  • train-images-idx3-ubyte 训练数据图像 (60,000)
  • train-labels-idx1-ubyte 训练数据label
  • t10k-images-idx3-ubyte 测试数据图像 (10,000)
  • t10k-labels-idx1-ubyte 测试数据label

每张图像是28*28像素:

  我们的任务是使用上面数据训练一个可以准确识别手写数字的神经网络模型,并使用Tensorflow对训练过程各个参数的变化进行可视化。

1. 准备数据集、定义超参数等准备工作

(1)导入需要使用的包

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data # gpu设置
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
config = tf.ConfigProto(allow_soft_placement = True)
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction = 0.33)
config.gpu_options.allow_growth = True mnist=input_data.read_data_sets('MNIST_data',one_hot=True)

上述代码的意思是使用GPU设备0,最多给GPU分配总共内存的百分之33,并且允许GPU按需申请内存。也就是说,假设一个程序使用一块GPU内存百分之10就够了,如果我们没有指定allow_growth=True,那么程序会直接占用GPU内存的百分之33,因为这个是我们给它分配的。如果我们连0.33,也就是GPU内存的百分之33都没有指定,那么程序会直接占用整个GPU设备0。虽然占用这么多没有用,但是我就占着,属于“占着茅坑不拉屎”。所以,为了充分利用资源,特别是一帮人使用一个服务器的时候,指定下这些参数就很有必要了。

2. 数据处理

(1)创建输入数据的占位符,分别创建特征数据xs,标签数据ys

  在tf.placeholder()函数中传入了3个参数,第一个是定义数据类型为float32;第二个是数据的大小,特征数据是大小784的向量,标签数据是大小为10的向量,None表示不确定死大小,到时候可以传入任何数量的样本;第3个参数是这个占位符的名称。

sess=tf.Session()

# 创建输入数据的占位符,分别创建特征数据xs,标签数据ys
with tf.name_scope('input'):
xs=tf.placeholder(tf.float32,[None,784])
ys=tf.placeholder(tf.float32,[None,10]) keep_prob=tf.placeholder(tf.float32)

  mnist下载好的数据集就是很多个1*784的向量,就是已经对28*28的图片进行了向量化处理。

(2)使用tf.summary.image保存图像信息

  特征数据其实就是图像的像素数据拉升成一个1*784的向量,现在如果想在tensorboard上还原出输入的特征数据对应的图片,就需要将拉升的向量转变成28 * 28 * 1的原始像素了,于是可以用tf.reshape()直接重新调整特征数据的维度:

  将输入的数据转换成[28 * 28 * 1]的shape,存储成另一个tensor,命名为image_shaped_input。为了能使图片在tensorbord上展示出来,使用tf.summary.image将图片数据汇总给tensorbord。tf.summary.image()中传入的第一个参数是命名,第二个是图片数据,第三个是最多展示的张数,此处为10张。

# 保存图像信息
with tf.name_scope('input_reshape'):
image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
tf.summary.image('input', image_shaped_input, 10)

3. 初始化参数并保存参数信息到summary

(1)初始化参数w和b

  在构建神经网络模型中,每一层中都需要去初始化参数w,b,为了使代码简介美观,最好将初始化参数的过程封装成方法function。 创建初始化权重w的方法,生成大小等于传入的shape参数,标准差为0.1,遵循正态分布的随机数,并且将它转换成tensorflow中的variable返回。

def weight_variable(shape):
initial=tf.truncated_normal(shape,stddev=0.1) #tf.truncted_normal产生随机变量来进行初始化,类似normal
return tf.Variable(initial)

  创建初始换偏执项b的方法,生成大小为传入参数shape的常数0.1,并将其转换成tensorflow的variable并返回。

def bias_variable(shape):
initial=tf.constant(0.1,shape=shape)
return tf.Variable(initial)

(2)记录训练过程参数变化

  我们知道,在训练的过程在参数是不断地在改变和优化的,我们往往想知道每次迭代后参数都做了哪些变化,可以将参数的信息展现在tenorbord上,因此我们专门写一个方法来收录每次的参数信息。

# 绘制参数变化
def variable_summaries(var):
with tf.name_scope('summaries'):
# 计算参数的均值,并使用tf.summary.scaler记录
mean = tf.reduce_mean(var)
tf.summary.scalar('mean', mean) # 计算参数的标准差
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
# 使用tf.summary.scaler记录记录下标准差,最大值,最小值
tf.summary.scalar('stddev', stddev)
tf.summary.scalar('max', tf.reduce_max(var))
tf.summary.scalar('min', tf.reduce_min(var))
# 用直方图记录参数的分布
tf.summary.histogram('histogram', var)

4. 搭建神经网络层 

(1)定义卷积层、max_pool层

  定义卷积,tf.nn.conv2d函数是tensoflow里面的二维的卷积函数,x是图片的所有参数,W是此卷积层的权重,然后定义步长strides=[1,1,1,1]值,strides[0]和strides[3]的两个1是默认值,中间两个1代表padding时在x方向运动一步,y方向运动一步,padding采用的方式是SAME。

def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')

  接着定义池化pooling,为了得到更多的图片信息,padding时我们选的是一次一步,也就是strides[1]=strides[2]=1,这样得到的图片尺寸没有变化,而我们希望压缩一下图片也就是参数能少一些从而减小系统的复杂度,因此我们采用pooling来稀疏化参数,也就是卷积神经网络中所谓的下采样层。pooling 有两种,一种是最大值池化,一种是平均值池化,本例采用的是最大值池化tf.max_pool()。池化的核函数大小为2x2,因此ksize=[1,2,2,1],步长为2,因此strides=[1,2,2,1]

def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

(2)建立卷积层conv1,conv2、建立全连接层fc1,fc2

建立卷积层conv1,conv2

# 建立卷积层conv1,conv2
with tf.name_scope('conv1'):
W_conv1=weight_variable([5,5,1,32])#patch/kernel 5*5,in size 1是image的厚度,out size 32
b_conv1=bias_variable([32]) #一个kernel一个bias
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)#output size 28*28*32 with tf.name_scope('max_pool1'):
h_pool1=max_pool_2x2(h_conv1) #output size 14*14*32 with tf.name_scope('conv2'):
W_conv2=weight_variable([5,5,32,64])#kernel 5*5,in size 32,out size 64
b_conv2=bias_variable([64])#output size 14*14*64
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)#output size 7*7*64 with tf.name_scope('max_pool2'):
h_pool2=max_pool_2x2(h_conv2)

建立全连接层fc1,fc2

#建立全连接层fc1,fc2
#[n_samples,7,7,64]->>[n_samples,7*7*64]
with tf.name_scope('fc1'):
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
tf.summary.scalar('dropout_keep_probability',keep_prob) with tf.name_scope('fc2'):
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2) #最终的结果
tf.summary.histogram('prediction',prediction)

  

模型可视化:

预测值分布:

预测值直方图:

5. 损失函数与优化

#交叉熵
with tf.name_scope('cross_entropy'):
cross_entropy=tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))
tf.summary.scalar('loss',cross_entropy) #优化器
with tf.name_scope('train'):
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

  

损失值变化:

6. 训练

#所有变量初始化
# summaries合并
merged = tf.summary.merge_all() # 写到指定的磁盘路径中
train_writer = tf.summary.FileWriter('E:/nxf_anaconda_base_jupyter_ht/LeNet/train',sess.graph)
test_writer = tf.summary.FileWriter('E:/nxf_anaconda_base_jupyter_ht/LeNet/test',sess.graph) sess.run(tf.global_variables_initializer()) # 计算准确率
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
# 分别将预测和真实的标签中取出最大值的索引,相同则返回1(true),不同则返回0(false)
correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(ys, 1))
with tf.name_scope('accuracy'):
# 求均值即为准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) tf.summary.scalar('accuracy', accuracy)

  

7. 所有变量初始化、送入数据集

  feed_dict用于获取数据,如果是train==true,也就是进行训练的时候,就从mnist.train中获取一个batch大小为100样本,并且设置dropout值为0.9。如果是不是train==false,则获取minist.test的测试数据,并且设置dropout为1,即保留所有神经元开启。

  同时,每隔10步,进行一次测试,并打印一次测试数据集的准确率,然后将测试数据集的各种summary信息写进日志中。 其余的时候,都是在进行训练,将训练集的summary信息并写到日志中。

def feed_dict(train):
"""Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
if train:
x, y = mnist.train.next_batch(10)
k = 0.9 #dropout
else:
x, y = mnist.test.images[100:200], mnist.test.labels[100:200]
k = 1.0
return {xs: x, ys: y, keep_prob: k} for i in range(1000):
if i % 10 == 0: #记录测试集的summary与accuracy
summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
test_writer.add_summary(summary, i)
print('Accuracy at step %s: %s' % (i, acc))
else: # 记录训练集的summary
summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
train_writer.add_summary(summary, i) train_writer.close()
test_writer.close()

 

 

  

二、saver的save和restore

TensorFlow提供了一个非常方便的api,tf.train.Saver()用来保存和还原一个机器学习模型。

程序会生成并保存四个文件:

  • checkpoint :文本文件,记录了模型文件的路径信息列表
  • save_net.ckpt.data-00000-of-00001:网络权重信息
  • save_net.ckpt.index:.data和.index这两个文件是二进制文件,保存了模型中的变量参数(权重)信息
  • save_net.ckpt.meta:二进制文件,保存了模型的计算图结构信息(模型的网络结构)protobuf

建立模型

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() # tf 马上就要废弃这种写法
# 替换成下面的写法:
init = tf.global_variables_initializer() 

变量的保存

saver = tf.train.Saver()

with tf.Session() as sess:
sess.run(init)
save_path = saver.save(sess, "nxf_net/save_net.ckpt")
print("Save to path: ", save_path) """
Save to path: nxf_net/save_net.ckpt
"""

变量的重载

# restore variables
# reduce the same shape and same type for your variables
# 先建立W,b的容器
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") # 这里不需要初始化步骤 init= tf.initialize_all_variables() saver = tf.train.Saver()
with tf.Session() as sess:
# 提取变量
saver.restore(sess, "my_net/save_net.ckpt")
print("weights:", sess.run(W))
print("biases:", sess.run(b)) """
weights: [[ 1. 2. 3.]
[ 3. 4. 5.]]
biases: [[ 1. 2. 3.]]
"""

参考文献:

【1】莫烦python

【2】Tensorflow模型保存和模型使用

【3】06:Tensorflow的可视化工具Tensorboard的初步使用

【4】Tensorflow API 讲解——tf.estimator.Estimator

【5】Tensorflow实战(一):打响深度学习的第一枪 – 手写数字识别(Tensorboard可视化)

Tensorflow实现LeNet-5、Saver保存与读取的更多相关文章

  1. Saver 保存与读取

    tensorflow 框架下的Saver 功能,用以保存和读取运算数据 Saver 保存数据 代码 import tensorflow as tf # Save to file #remember t ...

  2. Tensorflow学习笔记----模型的保存和读取(4)

    一.模型的保存:tf.train.Saver类中的save TensorFlow提供了一个一个API来保存和还原一个模型,即tf.train.Saver类.以下代码为保存TensorFlow计算图的方 ...

  3. 跟我学算法-tensorflow 实现卷积神经网络附带保存和读取

    这里的话就不多说明了,因为上上一个博客已经说明了 import numpy as np import tensorflow as tf import matplotlib.pyplot as plt ...

  4. TensorFlow学习笔记(8)--网络模型的保存和读取【转】

    转自:http://blog.csdn.net/lwplwf/article/details/62419087 之前的笔记里实现了softmax回归分类.简单的含有一个隐层的神经网络.卷积神经网络等等 ...

  5. tensorflow:保存与读取网络结构,参数

    训练一个神经网络的目的是啥?不就是有朝一日让它有用武之地吗?可是,在别处使用训练好的网络,得先把网络的参数(就是那些variables)保存下来,怎么保存呢?其实,tensorflow已经给我们提供了 ...

  6. 10 Tensorflow模型保存与读取

    我们的模型训练出来想给别人用,或者是我今天训练不完,明天想接着训练,怎么办?这就需要模型的保存与读取.看代码: import tensorflow as tf import numpy as np i ...

  7. TensorFlow学习笔记:保存和读取模型

    TensorFlow 更新频率实在太快,从 1.0 版本正式发布后,很多 API 接口就发生了改变.今天用 TF 训练了一个 CNN 模型,结果在保存模型的时候居然遇到各种问题.Google 搜出来的 ...

  8. Sklearn,TensorFlow,keras模型保存与读取

    一.sklearn模型保存与读取 1.保存 from sklearn.externals import joblib from sklearn import svm X = [[0, 0], [1, ...

  9. TensorFlow Saver 保存最佳模型 tf.train.Saver Save Best Model

      TensorFlow Saver 保存最佳模型 tf.train.Saver Save Best Model Checkmate is designed to be a simple drop-i ...

随机推荐

  1. 终于知道什么情况下需要实现.NET Core中的IOptions接口

    自从接触 IOptions 之后,一直纠结这样的问题:自己定义的 Options 要不要实现 IOptions 接口. 微软有的项目中实现了,比如 Caching 中的 MemoryCacheOpti ...

  2. [No0000F9]C# 运算符重载

    您可以重定义或重载 C# 中内置的运算符.因此,程序员也可以使用用户自定义类型的运算符.重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的.与其他函数一样,重载运 ...

  3. Java编程:删除 List 元素的三种正确方法

    删除 List 中的元素会产生两个问题: 删除元素后 List 的元素数量会发生变化: 对 List 进行删除操作可能会产生并发问题: 我们通过代码示例演示正确的删除逻辑 package com.ip ...

  4. Struts2 框架使用 核心以及其他详细配置

    因为在使用SSH框架的过程,关于struts2的配置比较繁琐,所以做个总结. 一.导入并且关联其他XML 1.   因为在核心配置文件(Struts2.xml)中,如果存在很多需要配置的Action项 ...

  5. 深探树形dp

    看到同学在写一道树形dp,好奇直接拿来写,发现很不简单. 如图,看上去是不是很像选课,没错这不是选课,升级版吧,多加了点东西罢了.简单却调了一晚上和一上午. 思路:很简单强联通分量+缩点+树形dp.直 ...

  6. 在VMware运行Linux下,密码错误的原因

    抱歉,没有奏效,请再试一次 密码明明是正确的,但依旧报错 原因: 密码中有大写,但键盘中的大写按键在登录界面无效,需要按住shift才能实现大写.

  7. AIX动态增加SWAP空间

    增加SWAP交换页空间 查看SWAP,使用lsps –a命令查看,默认安装SWAP是512M,例如: # lsps -a              Page Space      Physical V ...

  8. 《Mysql 字符集》

    一:什么是字符集呢? - 引用书中的例子:同样是大熊猫,在大陆叫熊猫,在台湾叫猫熊,在美国叫Panda,要到了非洲,可能都不知道叫啥(于是就乱码了). - 在例子之后引入字符集的概念:字符集就是指符号 ...

  9. Java问题汇总

    一.java编译通过,为什么运行却提示找不到或无法加载主类 使用运行窗口编译通过,但运行提示 通过eclipse可以运行 原因:代码中有package javaLearn:编译时在javaLearn目 ...

  10. NumPy 广播机制(Broadcasting)

    一.何为广播机制 a.广播机制是Numpy(开源数值计算工具,用于处理大型矩阵)里一种向量化数组操作方法. b.Numpy的通用函数(Universal functions) 中要求输入的两个数组sh ...