实验六 深度学习方法应用
参考:https://blog.csdn.net/lyq_12/article/details/85051247
一、实验要求
了解MNIST数据集,用lenet5实现手写数字识别
二、实验内容
请编写lenet网络层,并测得测试集的准确率。
三、编写程序调试
import random
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
from tensorflow.contrib.layers import flatten
from tensorflow.examples.tutorials.mnist import input_data
def load_data():
'''
导入数据
:return:训练集、验证集、测试集
'''
mnist = input_data.read_data_sets("MNIST_data/", reshape=False)
X_train, y_train= mnist.train.images, mnist.train.labels
X_validation, y_validation = mnist.validation.images, mnist.validation.labels
X_test, y_test= mnist.test.images, mnist.test.labels
assert(len(X_train) == len(y_train))
assert(len(X_validation) == len(y_validation))
assert(len(X_test) == len(y_test))
print()
print("Image Shape: {}".format(X_train[0].shape))
print()
print("Training Set: {} samples".format(len(X_train)))
print("Validation Set: {} samples".format(len(X_validation)))
print("Test Set: {} samples".format(len(X_test)))
# 将训练集进行填充
# 因为mnist数据集的图片是28*28*1的格式,而lenet只接受32*32的格式
# 所以只能在这个基础上填充
X_train = np.pad(X_train, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
X_validation = np.pad(X_validation, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
X_test = np.pad(X_test, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
print("Updated Image Shape: {}".format(X_train[0].shape))
# 随机的看一张图
index = random.randint(0, len(X_train))
image = X_train[index].squeeze()
plt.figure(figsize=(1,1))
plt.imshow(image, cmap="gray")
plt.show()
print(y_train[index])
# 打乱数据集的顺序
X_train, y_train = shuffle(X_train, y_train)
return X_train, y_train, X_validation, y_validation,X_test, y_test
四、撰写实验报告
read_data_sets (from tensorflow.contrib.learn.python.learn.datasets.mnist) is deprecated and will be removed in a future version.
Instructions for updating:
Please use alternatives such as official/mnist/dataset.py from tensorflow/models.
解决:https://blog.csdn.net/qq_41185868/article/details/88869740
更新说明:使用tensorflow/models中的official/mnist/dataset.py等备选方案。
将
from tensorflow.examples.tutorials.mnist import input_data
改为
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
ndarray = numpy.pad(array, pad_width, mode, **kwargs)
•array为要填补的数组
•pad_width是在各维度的各个方向上想要填补的长度,如((1,2),(2,2)),
pad_width——表示每个轴(axis)边缘需要填充的数值数目。
参数输入方式为:((before_1, after_1), … (before_N, after_N)),其中(before_1, after_1)表示第1轴两边缘分别填充before_1个和after_1个数值。取值为:{sequence, array_like, int}
• mode为填补类型,即怎样去填补,有“constant”,“edge”等模式,如果为constant模式,就得指定填补的值,如果不指定,则默认填充0。
•剩下的都是一些可选参数,具体可查看
https://docs.scipy.org/doc/numpy/reference/generated/numpy.pad.html
•ndarray为填充好的返回值。
placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符喂入数据。
tf.one_hot()函数是将input转化为one-hot类型数据输出,相当于将多个数值联合放在一起作为多个相同类型的向量,可用于表示各自的概率分布
one_hot(indices, depth, on_value=None, off_value=None, axis=None, dtype=None, name=None) Returns a one-hottensor.
indices表示输入的多个数值,通常是矩阵形式;depth表示输出的尺寸。
由于one-hot类型数据长度为depth位,其中只用一位数字表示原输入数据,这里的on_value就是这个数字,默认值为1,one-hot数据的其他位用off_value表示,默认值为0。
tf.one_hot()函数规定输入的元素indices从0开始,最大的元素值不能超过(depth - 1),因此能够表示(depth + 1)个单位的输入。若输入的元素值超出范围,输出的编码均为 [0, 0 … 0, 0]。
indices = 0 对应的输出是[1, 0 … 0, 0], indices = 1 对应的输出是[0, 1 … 0, 0], 依次类推,最大可能值的输出是[0, 0 … 0, 1]。
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
从截断的正态分布中输出随机值。
生成的值服从具有指定平均值和标准偏差的正态分布,如果生成的值大于μ+2σ则丢弃重新选择。
在tf.truncated_normal中如果x的取值在区间(μ-2σ,μ+2σ)之外则重新进行选择。这样保证了生成的值都在均值附近。
参数:
shape: 一维的张量,也是输出的张量。
mean: 正态分布的均值。
stddev: 正态分布的标准差。
dtype: 输出的类型。
seed: 一个整数,当设置之后,每次生成的随机数都一样。
name: 操作的名字
tf.nn.conv2d是TensorFlow里面实现卷积的函数
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
除去name参数用以指定该操作的name,与方法有关的一共五个参数:
第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4
第四个参数padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式(当其为‘SAME’时,表示卷积核可以停留在图像边缘)
第五个参数:use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
卷积核以步长滑动遍历全图,结果返回一个Tensor,这个输出,就是我们常说的feature map,shape仍然是[batch, height, width, channels]这种形式。
计算激活函数 relu,即 max(features, 0)。即将矩阵中每行的非最大值置0。
pooling = tf.nn.max_pool( h, ksize=[1, height, width, 1], strides=[1, 1, 1, 1], padding='VALID', name="pool") |
h : 需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch_size, height, width, channels]这样的shape
k_size : 池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1
strides : 窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
padding: 填充的方法,SAME或VALID,SAME表示添加全0填充,VALID表示不添加
将矩阵a乘以矩阵b,生成a * b。
计算loss时用
loss是代价值,也就是我们要最小化的值
预测越准确,结果的值越小(别忘了前面还有负号),最后求一个平均,得到我们想要的loss
注意!!!这个函数的返回值并不是一个数,而是一个向量,如果要求交叉熵,我们要再做一步tf.reduce_sum操作,就是对向量里面所有元素求和,最后才得到.
如果求loss,则要做一步tf.reduce_mean操作,对向量求均值!
给出某个tensor对象在某一维上的其数据最大值所在的索引值,常用于metric(如acc)的计算
axis=0时,以列为单位
tf.equal(A, B)是对比这两个矩阵或者向量的相等的元素,如果是相等的那就返回True,反正返回False,返回的值的矩阵维度和A是一样的
cast(
x,
dtype,
name=None
)
将x的数据格式转化成dtype.例如,原来x的数据格式是bool,
那么将其转化成float以后,就能够将其转化成0和1的序列。反之也可以
参考:https://blog.csdn.net/wwwlyj123321/article/details/86064772
一个Session可能会拥有一些资源,例如Variable或者Queue。当我们不再需要该session的时候,需要将这些资源进行释放
sess.run(tf.global_variables_initializer())#global_variables_initializer返回一个用来初始化 计算图中 所有global variable的 op。run了 所有global Variable 的 assign op
sess.run(fetches,feed_dict)
///这个是让fetches节点动起来,告诉tensorflow,想要此节点的输出。
///fetches 可以是list或者tensor向量
///feed_dict。替换原图中的某个tensor
sess.run() 中的feed_dict
我们都知道feed_dict的作用是给使用placeholder创建出来的tensor赋值。其实,他的作用更加广泛:feed 使用一个 值临时替换一个 op 的输出结果. 你可以提供 feed 数据作为 run() 调用的参数. feed 只在调用它的方法内有效, 方法结束, feed 就会消失.
训练时候保存:
# Create a saver. |
加载模型训练好的的网络和参数来测试,或进一步训练
with tf.Session() as sess: new_saver = tf.train.import_meta_graph('my-model.meta') new_saver.restore(sess,tf.train.latest_checkpoint( './') |
tensorflow模型主要包含网络的结构的定义或者叫graph和训练好的网络结构里的参数。
因此tensorflow model包含2个文件:
a)Meta graph:
使用protocol buffer来保存整个tensorflow graph.例如所有的variables, operations, collections等等。这个文件使用.meta后缀
b) Checkpoint file:
二进制文件包含所有的weights,biases,gradients和其他variables的值。这个文件使用.ckpt后缀,后来变成有2个文件:
mymodel.data-00000-of-00001
mymodel.index
第一个文件.data文件就是保存训练的variables我们将要使用它。
和这些文件一起,tensorflow还有一个文件叫checkpoint用来简单保存最近一次保存checkpoint文件的记录
import random
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
from tensorflow.contrib.layers import flatten
#from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
def load_data():
'''
导入数据
:return:训练集、验证集、测试集
'''
# mnist = input_data.read_data_sets("MNIST_data/", reshape=False)
mnist = read_data_sets("MNIST_data/", reshape=False)
X_train, y_train= mnist.train.images, mnist.train.labels
X_validation, y_validation = mnist.validation.images, mnist.validation.labels
X_test, y_test= mnist.test.images, mnist.test.labels
assert(len(X_train) == len(y_train))
assert(len(X_validation) == len(y_validation))
assert(len(X_test) == len(y_test))
print()
print("Image Shape: {}".format(X_train[0].shape))
print()
print("Training Set: {} samples".format(len(X_train)))
print("Validation Set: {} samples".format(len(X_validation)))
print("Test Set: {} samples".format(len(X_test)))
# 将训练集进行填充
# 因为mnist数据集的图片是28*28*1的格式,而lenet只接受32*32的格式
# 所以只能在这个基础上填充
X_train = np.pad(X_train, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
X_validation = np.pad(X_validation, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
X_test = np.pad(X_test, ((0, 0), (2, 2), (2, 2), (0, 0)), 'constant')
print("Updated Image Shape: {}".format(X_train[0].shape))
# 随机的看一张图
index = random.randint(0, len(X_train))
image = X_train[index].squeeze()# 从数组的形状中删除单维条目,即把shape中为1的维度去掉
plt.figure(figsize=(1,1))
plt.imshow(image, cmap="gray")
plt.show()
print("number:",y_train[index])
# 打乱数据集的顺序
X_train, y_train = shuffle(X_train, y_train)
return X_train, y_train, X_validation, y_validation,X_test, y_test
#SOLUTION: Implement LeNet-5
def LeNet(x):
# Arguments used for tf.truncated_normal, randomly defines variables for the weights and biases for each layer
# 用于tf.truncated_normal的参数, 随机定义每个图层的权重和偏差的变量
mu=0
sigma=0.1
# SOLUTION: Layer 1: Convolutional.卷积 Input = 32x32x1. Output = 28x28x6.
conv1_W=tf.Variable(tf.truncated_normal(shape=(5, 5, 1, 6), mean = mu, stddev = sigma))#tf.truncated_normal从截断的正态分布中输出随机值。
conv1_b=tf.Variable(tf.zeros(6))#tf.Variable(initializer,name)initializer是初始化参数
conv1=tf.nn.conv2d(x, conv1_W, strides=[1, 1, 1, 1], padding='VALID') + conv1_b#卷积函数
# SOLUTION: Activation.
conv1 = tf.nn.relu(conv1)#计算激活函数 relu,即 max(features, 0)。即将矩阵中每行的非最大值置0。
# SOLUTION: Pooling. Input = 28x28x6. Output = 14x14x6.
conv1=tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
# SOLUTION: Layer 2: Convolutional. Output = 10x10x16.
conv2_W=tf.Variable(tf.truncated_normal(shape=(5, 5, 6, 16), mean = mu, stddev = sigma))
conv2_b=tf.Variable(tf.zeros(16))
conv2=tf.nn.conv2d(conv1, conv2_W, strides=[1, 1, 1, 1], padding='VALID') + conv2_b
# SOLUTION: Activation.
conv2=tf.nn.relu(conv2)
# SOLUTION: Pooling. Input = 10x10x16. Output = 5x5x16.
conv2=tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
# SOLUTION: Flatten. Input = 5x5x16. Output = 400.
fc0=flatten(conv2)#平化降维
# SOLUTION: Layer 3: Fully Connected全连接层. Input = 400. Output = 120.
fc1_W = tf.Variable(tf.truncated_normal(shape=(400, 120), mean = mu, stddev = sigma))
fc1_b = tf.Variable(tf.zeros(120))
fc1 = tf.matmul(fc0, fc1_W) + fc1_b#matmul将矩阵a乘以矩阵b(不是对应元素相乘),生成a * b。
# SOLUTION: Activation.
fc1 = tf.nn.relu(fc1)
# SOLUTION: Layer 4: Fully Connected. Input = 120. Output = 84.
fc2_W = tf.Variable(tf.truncated_normal(shape=(120, 84), mean = mu, stddev = sigma))
fc2_b = tf.Variable(tf.zeros(84))
fc2 = tf.matmul(fc1, fc2_W) + fc2_b
# SOLUTION: Activation.
fc2 = tf.nn.relu(fc2)
# SOLUTION: Layer 5: Fully Connected. Input = 84. Output = 10.
fc3_W = tf.Variable(tf.truncated_normal(shape=(84, 10), mean = mu, stddev = sigma))
fc3_b = tf.Variable(tf.zeros(10))
logits = tf.matmul(fc2, fc3_W) + fc3_b
return logits
EPOCHS=10
BATCH_SIZE=128
X_train, y_train, X_validation, y_validation,X_test, y_test=load_data()
x=tf.placeholder(tf.float32, (None, 32, 32, 1))
#y=tf.placeholder(tf.int32, (None))
#one_hot_y=tf.one_hot(y, 10)
y=tf.placeholder(tf.int32, (None))#在模型中的占位
one_hot_y=tf.one_hot(y, 10)#one_hot(indices, depth)
#Training Pipeline
rate=0.001
logits=LeNet(x)
cross_entropy=tf.nn.softmax_cross_entropy_with_logits(labels=one_hot_y, logits=logits)
#print("cross_entropy:",cross_entropy)
loss_operation=tf.reduce_mean(cross_entropy)
optimizer=tf.train.AdamOptimizer(learning_rate = rate)#寻找全局最优点的优化算法,引入了二次方梯度校正。
training_operation=optimizer.minimize(loss_operation)
#Model Evaluation模型评估
correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(one_hot_y, 1))#argmax某一维上的其数据最大值所在的索引值
accuracy_operation = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
saver = tf.train.Saver()
def evaluate(X_data, y_data):
num_examples = len(X_data)
total_accuracy = 0
sess = tf.get_default_session()#返回当前线程的默认会话
for offset in range(0, num_examples, BATCH_SIZE):
batch_x, batch_y = X_data[offset:offset+BATCH_SIZE], y_data[offset:offset+BATCH_SIZE]
accuracy = sess.run(accuracy_operation, feed_dict={x: batch_x, y: batch_y})
total_accuracy+= (accuracy * len(batch_x))
return total_accuracy / num_examples
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())#global_variables_initializer返回一个用来初始化 计算图中 所有global variable的 op。run了 所有global Variable 的 assign op
num_examples = len(X_train)
print("Training...")
print()
for i in range(EPOCHS):
X_train, y_train=shuffle(X_train, y_train)#随机排序
for offset in range(0, num_examples, BATCH_SIZE):
end=offset+BATCH_SIZE
batch_x, batch_y=X_train[offset:end], y_train[offset:end]
sess.run(training_operation,feed_dict={x: batch_x, y: batch_y})
# loss, acc = sess.run(training_operation,feed_dict={x: batch_x, y: batch_y})
# print("Step " + str(offset) + ", Minibatch Loss= " + \
# "{:.4f}".format(loss) + ", Training Accuracy= " + \
# "{:.3f}".format(acc))
validation_accuracy=evaluate(X_validation, y_validation)
print("EPOCH {} ...".format(i+1))
print("Validation Accuracy = {:.3f}".format(validation_accuracy))
print()
saver.save(sess, './lenet')
print("Model saved")
#Evaluate the Model
with tf.Session() as sess:
saver.restore(sess, tf.train.latest_checkpoint('.'))#加载模型训练好的的网络和参数来测试,或进一步训练
test_accuracy = evaluate(X_test, y_test)
print("Test Accuracy = {:.3f}".format(test_accuracy))