1、使用softmax回归对mnist数据集进行分类,准确率大概为0.92左右
2、使用多层感知机(3层)对mnist数据集分类,准确率大概为0,98
2、使用多层感知机(3层)对mnist数据集分类,准确率大概为0,98
3、使用CNN对mnist进行分类,准确率为0.99
#coding=utf-8
import pickle
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import time
# 定义一个mnist数据集的类
class mnistReader():
def __init__(self,mnistPath,onehot=True):
self.mnistPath=mnistPath
self.onehot=onehot
self.batch_index=0
print ('read:',self.mnistPath)
fo = open(self.mnistPath, 'rb')
self.train_set,self.valid_set,self.test_set = pickle.load(fo,encoding='bytes')
fo.close()
self.data_label_train=list(zip(self.train_set[0],self.train_set[1]))
np.random.shuffle(self.data_label_train)
# 打印一些数据集的信息
def data_info(self):
# train_set是一个元组,元组第一个元素是图片像素,元组第二个元素是图片对应的数字
print ("type:",type(self.train_set))
rdata = self.train_set[0]
rlabel=self.train_set[1]
print ("train_set:",type(rdata)) #可以看到训练集大小为(50000,28*28)的二维矩阵
print ("train_label:",type(rlabel)) # 可以看到训练集标签大小为(50000,)的数组
# 打印数据集的图片
def show_image(self):
rdata,rlabel = self.train_set
pic=np.reshape(rdata[0],(28,28))
print (pic)
print (rlabel[0])
plt.imshow(pic)
plt.show()
# 获取下一个训练集的batch
def next_train_batch(self,batch_size=100):
if self.batch_index < len(self.data_label_train)/batch_size:
print ("batch_index:",self.batch_index )
datum=self.data_label_train[self.batch_index*batch_size:(self.batch_index+1)*batch_size]
self.batch_index+=1
return self._decode(datum,self.onehot)
else:
self.batch_index=0
np.random.shuffle(self.data_label_train)
datum=self.data_label_train[self.batch_index*batch_size:(self.batch_index+1)*batch_size]
self.batch_index+=1
return self._decode(datum,self.onehot)
# 获取测试集的数据
def test_data(self):
tdata,tlabel=self.test_set
data_label_test=list(zip(tdata,tlabel))
return self._decode(data_label_test,self.onehot)
# 把一个batch的训练数据转换为可以放入模型训练的数据
def _decode(self,datum,onehot):
rdata=list() # batch训练数据
rlabel=list()
if onehot:
for d,l in datum:
rdata.append(np.reshape(d,[784])) # 转变形状为:一维向量
hot=np.zeros(10)
hot[int(l)]=1 # label设为100维的one-hot向量
rlabel.append(hot)
else:
for d,l in datum:
rdata.append(np.reshape(d,[784]))
rlabel.append(int(l))
return rdata,rlabel
# ------------softmax回归的模型------------------
def softmax_model():
sess=tf.InteractiveSession()
"""
placeholder是输入数据的地方,第一个参数是数据类型,第二个参数代表tensor的shape,也就是数据的尺寸
,这里None代表不限条数的输入,784代表每条输入是一个784维的向量
"""
x=tf.placeholder(tf.float32,[None,784],name='x') # 训练集的输入数据
w=tf.Variable(tf.zeros([784,10])) # softmax回归的权重值
b=tf.Variable(tf.zeros([10])) # softmax回归的参数值
y=tf.nn.softmax(tf.matmul(x,w)+b,name='y') # softmax回归的公式定义
y_=tf.placeholder(tf.float32,[None,10],name='y_') # 真实的label输入
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1])) #交叉熵的定义,类似损失函数,
train_step=tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy) # 梯度下降法,学习率为0.5
tf.global_variables_initializer().run() # 初始化全局变量
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
# 开始训练数据
for i in range(1000):
batch_x,batch_y=mnist.next_train_batch()
train_step.run({x:batch_x,y_:batch_y})
# 训练完成后计算准确率
correction_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1)) # 预测结果类别和真实类别是否相同
accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32)) # 转换为float值,并求平均
test_data,test_label=mnist.test_data() # 获得测试数据和训练数据
print (accuracy.eval({x:test_data,y_:test_label})) # 将测试数据输入评测流程accuracy,计算准确率
# 保存模型
saver = tf.train.Saver()
save_path = saver.save(sess,"./Softmax/model.ckpt")
print("save model:{0} Finished".format(save_path))
# 加载训练好的 softmax 回归模型用于预测
def load_softmax():
# 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
saver = tf.train.import_meta_graph("./Softmax/model.ckpt.meta")
sess=tf.InteractiveSession()
# 即将固化到硬盘中的Session从保存路径再读取出来
saver.restore(sess,'./Softmax/model.ckpt')
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
data,label=mnist.test_data()
graph = tf.get_default_graph()
# 通过张量的名称来获取张量
x = graph.get_tensor_by_name("x:0")
logits = graph.get_tensor_by_name("y:0")
# 填充需要预测的样本点
feed=np.reshape(data[0],[1,784])
feed_dict = {x:feed}
# 进行预测
result=sess.run(logits,feed_dict)
#输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
print ("predict result:",tf.argmax(result,1).eval())
print ("real result:",tf.argmax(label[0],0).eval())
#--------多层感知机模型(只有一个隐藏层)--------------
def multi_perceptron():
sess=tf.InteractiveSession()
# 网络的参数设置
in_units=784 # 输入节点数
h1_units=300 # 隐藏层的输出节点数
w1=tf.Variable(tf.truncated_normal([in_units,h1_units],stddev=0.1))# 隐藏层权重,正太分布,标准差为0.1
b1=tf.Variable(tf.zeros([h1_units])) # 隐藏层的偏置
w2=tf.Variable(tf.zeros([h1_units,10])) # 输出层的权重
b2=tf.Variable(tf.zeros([10])) # 输出层的偏置
# 网络的输入值
x=tf.placeholder(tf.float32,shape=[None,in_units],name='x') # 网络的输入,注意要命名
keep_prob=tf.placeholder(tf.float32,name='keep_prob') # Dropout比率,注意命名
y_=tf.placeholder(tf.float32,[None,10],name='y_') # 真实的label,注意命名
# 网络各层的计算
hidden1=tf.nn.relu(tf.matmul(x,w1)+b1) # 隐藏层的模型
hidden1_drop=tf.nn.dropout(hidden1,keep_prob) # Dropout:随机将一部分节点置0
y=tf.nn.softmax(tf.matmul(hidden1_drop,w2)+b2,name='y') # 输出层的模型,注意命名
# 定义损失函数和优化器
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1])) #定义交叉熵为损失函数
train_step=tf.train.AdagradOptimizer(0.3).minimize(cross_entropy) # 定义优化方法,学习率为0.3
# 开始训练
tf.global_variables_initializer().run()
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
for i in range(1000):
batch_x,batch_y = mnist.next_train_batch()
train_step.run({x:batch_x,y_:batch_y,keep_prob:0.75})
# 计算测试集上的准确率
correction_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32))
test_data,test_label=mnist.test_data()
print (accuracy.eval({x:test_data,y_:test_label,keep_prob:1.0}))
# 保存模型的参数
saver = tf.train.Saver()
save_path = saver.save(sess,"./MLP/model.ckpt") #保存模型,生成了4个文件:.data、.index、.meta、checkpoint
print("save model:{0} Finished".format(save_path))
# 加载训练好的MLP模型用于预测
def load_mlp():
# 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
saver = tf.train.import_meta_graph("./MLP/model.ckpt.meta")
sess=tf.InteractiveSession()
# 即将固化到硬盘中的Session从保存路径再读取出来
saver.restore(sess,'./MLP/model.ckpt')
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
data,label=mnist.test_data()
graph = tf.get_default_graph()
# 通过张量的名称来获取张量
x = graph.get_tensor_by_name("x:0")
logits = graph.get_tensor_by_name("y:0")
keep_prob=graph.get_tensor_by_name("keep_prob:0")
# 填充需要预测的样本点
feed=np.reshape(data[0],[1,784])
feed_dict = {x:feed,keep_prob:1.0}
# 进行预测
result=sess.run(logits,feed_dict)
#输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
print ("predict result:",tf.argmax(result,1).eval())
print ("real result:",tf.argmax(label[0],0).eval())
# -----------卷积神经网络---------------------------
def CNN():
sess=tf.InteractiveSession()
x=tf.placeholder(tf.float32,[None,784],name='x')
y_=tf.placeholder(tf.float32,[None,10],name='y_')
x_image=tf.reshape(x,[-1,28,28,1]) #转为28*28的原始结构,第一个-1代表数量不确定,最后一个-1代表通道
# 第一个卷积层的定义
w_conv1=weight_variable([5,5,1,32]) # 初始化第一个卷积层卷积核参数
b_conv1=bias_variable([32]) # 初始化第一个卷积层的偏置
h_conv1=tf.nn.relu(conv2d(x_image,w_conv1)+b_conv1) # 第一个卷积层的卷积运算
h_pool1=max_pool_2x2(h_conv1) # 第一个卷积层的池化运算
# 第二个卷积层的定义
w_conv2=weight_variable([5,5,32,64]) # 初始化第二个卷积层卷积核参数
b_conv2=bias_variable([64]) # 初始化第二个卷积层的偏置
h_conv2=tf.nn.relu(conv2d(h_pool1,w_conv2)+b_conv2) # 第二个卷积层的卷积运算
h_pool2=max_pool_2x2(h_conv2) # 第二个卷积层的池化运算
# 全连接层
w_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64]) # 转换为一维向量
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,w_fc1)+b_fc1) # 全连接
# Dropout层
keep_prob=tf.placeholder(tf.float32,name='keep_prob')
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
# Softmax层
w_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop,w_fc2)+b_fc2,name='y')
# 定义交叉熵和优化器
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv),reduction_indices=[1]))
train_step=tf.train.AdagradOptimizer(1e-4).minimize(cross_entropy)
# 用于保存模型的Saver类
saver = tf.train.Saver(max_to_keep=10) # 保存最新的10个文件,默认为 5个
# 开始训练
tf.global_variables_initializer().run()
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
start=time.time()
print ("begin training...")
for i in range(20000):
batch_x,batch_y = mnist.next_train_batch()
train_step.run(feed_dict={x:batch_x,y_:batch_y,keep_prob:0.5})
# 每1000轮保存一次中间结果
if i%1000 ==0:
save_path=saver.save(sess,"./testCNN/model.ckpt",global_step=i)
print("save model:{0} Finished".format(save_path))
# 计算准确率
correction_prediction=tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32))
test_data,test_label=mnist.test_data()
print (accuracy.eval(feed_dict={x:test_data,y_:test_label,keep_prob:1.0}))
print ("cast time:",time.time() - start)
# 加载训练好的CNN模型用于预测
def load_cnn():
# 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
saver = tf.train.import_meta_graph("./CNN/model.ckpt-19000.meta")
sess=tf.InteractiveSession()
# 即将固化到硬盘中的Session从保存路径再读取出来,需要指定保存的文件名
# saver.restore(sess,'./CNN/model.ckpt-19000')
# 获取最新的模型,只需要指定保存模型的目录即可
ckpt=tf.train.get_checkpoint_state('./CNN/')
saver.restore(sess, ckpt.model_checkpoint_path)
mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
data,label=mnist.test_data()
graph = tf.get_default_graph()
# 通过张量的名称来获取张量
x = graph.get_tensor_by_name("x:0")
logits = graph.get_tensor_by_name("y:0")
keep_prob=graph.get_tensor_by_name("keep_prob:0")
# 填充需要预测的样本点
feed=np.reshape(data[0],[1,784])
feed_dict = {x:feed,keep_prob:1.0}
# 进行预测
result=sess.run(logits,feed_dict)
#输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
print ("predict result:",tf.argmax(result,1).eval())
print ("real result:",tf.argmax(label[0],0).eval())
# 权重初始化函数,正太分布,方差为0.1
def weight_variable(shape):
initial =tf.truncated_normal(shape,stddev=0.1)
return tf.Variable(initial)
# 偏置初始化函数,常数0.1
def bias_variable(shape):
initial=tf.constant(0.1,shape=shape)
return tf.Variable(initial)
# 2维卷积层
'''
x为输入
w为卷积核参数,如[5,5,1,32],前面两个代表核尺寸,第三个代表通道,最后一个是核数量
strides为卷积核移动步长,都是1代表不遗漏的划过每个点
padding为边界处理填充方式
'''
def conv2d(x,w):
return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding='SAME')
# 2维池化层
'''
ksize为池化核大小,这里为2*2
strides步长这里设为横竖两个方向以2为步长
'''
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#-----------------------------------------------------------------------------
if __name__ == '__main__':
# softmax_model() # softmax回归得到的准确率大概为0.92左右
# load_softmax() # 加载softmax回归保存的模型
# multi_perceptron() # 多层感知机得到的准确率大概为0.98左右
# load_mlp() # 加载多层感知机保存的模型用于预测
CNN() # 卷积神经网络据说可以达到0.99的准确率,没跑过
# load_cnn() # 加载CNN保存的模型用于预测