语言:python3.6
框架: tensorflow
数据集:mnist数据集(图片格式)
1、准备数据集
下载地址:http://yann.lecun.com/exdb/mnist/
用以下的代码将minist数据集转化为图片(也可以通过from tensorflow.examples.tutorials.mnist import input_data获得二进格式的数据)
"""
将MNIST数据集由二进制文件转为图片形式,保存于指定文件夹下
"""
import os
import struct
import numpy as np
import matplotlib.pyplot as plt
# 读MNIST数据集的图片数据
def mnist_load_img(img_path):
with open(img_path, "rb") as fp:
# >是以大端模式读取,i是整型模式,读取前四位的标志位,
# unpack()函数:是将4个字节联合后再解析成一个数,(读取后指针自动后移)
msb = struct.unpack('>i', fp.read(4))[0]
# 标志位为2051,后存图像数据;标志位为2049,后存图像标签
if msb == 2051:
# 读取样本个数60000,存入cnt
cnt = struct.unpack('>i', fp.read(4))[0]
# rows:行数28;cols:列数28
rows = struct.unpack('>i', fp.read(4))[0]
cols = struct.unpack('>i', fp.read(4))[0]
imgs = np.empty((cnt, rows, cols), dtype="int")
for i in range(0, cnt):
for j in range(0, rows):
for k in range(0, cols):
# 16进制转10进制
pxl = int(hex(fp.read(1)[0]), 16)
imgs[i][j][k] = pxl
return imgs
else:
return np.empty(1)
# 读MNIST数据集的图片标签
def mnist_load_label(label_path):
with open(label_path, "rb") as fp:
msb = struct.unpack('>i', fp.read(4))[0];
if msb == 2049:
cnt = struct.unpack('>i', fp.read(4))[0];
labels = np.empty(cnt, dtype="int");
for i in range(0, cnt):
label = int(hex(fp.read(1)[0]), 16);
labels[i] = label;
return labels;
else:
return np.empty(1);
# 分割训练、测试集的图片数据与图片标签
def mnist_load_data(train_img_path, train_label_path, test_img_path, test_label_path):
x_train = mnist_load_img(train_img_path);
y_train = mnist_load_label(train_label_path);
x_test = mnist_load_img(test_img_path);
y_test = mnist_load_label(test_label_path);
return (x_train, y_train), (x_test, y_test);
# 输出打印图片
def mnist_plot_img(img):
(rows, cols) = img.shape;
plt.figure();
plt.gray();
plt.imshow(img);
plt.show();
# 按指定位置保存图片
def mnist_save_img(img, path, name):
if not os.path.exists(path):
os.mkdir(path)
(rows, cols) = img.shape
fig = plt.figure()
plt.gray()
plt.imshow(img)
# 在既定路径里保存图片
fig.savefig(path + name)
# [start]
x_train = mnist_load_img("train-images.idx3-ubyte")
y_train = mnist_load_label("train-labels.idx1-ubyte")
# 将打印出的MNIST数据集中所有的图片存入一个data文件夹下
# for i in range(0, 10):
# path = "../CNN+Kreas框架+MNIST/data/data_a/"
# name = str(i) + ".png"
# mnist_save_img(x_train[i], path, name)
# 按图片标签的不同,打印MNIST数据集的图片存入不同文件夹下
for i in range(0, len(x_train)):
path = "./data/" + str(y_train[i]) +"/"
name = str(i)+".png"
mnist_save_img(x_train[i], path, name)
#mnist_plot_img(x_train[0, :, :])
"""
x_test = mnist_load_img("t10k-images.idx3-ubyte")
y_test = mnist_load_label("t10k-labels.idx1-ubyte")
"""
代码转自(https://blog.csdn.net/zzZ_CMing/article/details/81063977)
就会在所指定的目录下发现0~9文件夹,里面存放图片形式的minist数据集,接下来制作训练集(也可以用上面代码中的mnist_load_data方法)
2、制作训练集
将图片和相应标签对应起来,用以下代码实现。
class Dataset(object):
def __init__(self,file_path,batch_size,capacity):
self.file_path=file_path#路径文件
self.batch_size=batch_size#batch_size
self.capacity=capacity#队列容量
self.image_size=28
def num_batch(self):
image, label = self.get_files(self.file_path)
return len(label)//self.batch_size#一批样本中的batch个数
def get_batch(self):
image, label = self.get_files(self.file_path)
batch_image, batch_label=self.get_batches(image,label,self.image_size,self.image_size,self.batch_size,self.capacity)
return batch_image,batch_label
def get_files(self,file_path):
class_train = []
label_train = []
for train_class in os.listdir(file_path):
for pic_name in os.listdir(file_path + train_class):
class_train.append(file_path + train_class + '/' + pic_name)
label_train.append(train_class)
temp = np.array([class_train, label_train])
temp = temp.transpose()
np.random.shuffle(temp)
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
# class is 1 2 3 4 5
label_list = [int(i) for i in label_list]
return image_list, label_list
def get_batches(self,image, label, resize_w, resize_h, batch_size, capacity):
image = tf.cast(image, tf.string)
label = tf.cast(label, tf.int64)
queue = tf.train.slice_input_producer([image, label])
label = queue[1]
image_temp = tf.read_file(queue[0])
image = tf.image.decode_jpeg(image_temp, channels=1)
# resize image
# image = tf.image.resize_image_with_crop_or_pad(image, resize_w, resize_h)
image = tf.image.resize_images(image, [resize_w, resize_h], method=0)
image = tf.image.per_image_standardization(image)
image_batch, label_batch = tf.train.batch([image, label], batch_size=batch_size,
num_threads=64,
capacity=capacity)
# 1:一个batch batch_size:总共划分的batch数,784,展开为1列
image_batch = tf.reshape(image_batch, [batch_size, resize_w * resize_w])
images_batch = tf.cast(image_batch, tf.float32)
labels_onehot_batch = tf.one_hot(label_batch, depth=10, on_value=1, axis=1)
labels_batch = tf.reshape(labels_onehot_batch, [batch_size, 10])
return images_batch, labels_batch
如果分类的类别数不为10时需要修改
label_list = tf.one_hot(label_list, depth=10, on_value=1, axis=1)中的depth(输出通道)和
labels_batch = tf.reshape(label_batch, [batch_size, 10])中的10(输出通道)
3、设计网络
with tf.name_scope('Input'):
X = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='X_placeholder')
Y = tf.placeholder(dtype=tf.int32, shape=[None, 10], name='Y_placeholder')
# 2、前向网络设计
with tf.name_scope('Inference'):
# batch:20 输入:784,通道:1,输出:10
W = tf.Variable(initial_value=tf.random_normal(shape=[784, 10], stddev=0.01), name='Weights')
b = tf.Variable(initial_value=tf.zeros(shape=[10]), name='bias')
print(W)
logits = tf.matmul(X, W) + b
Y_pred = tf.nn.softmax(logits=logits)
# 3、损失函数设计
with tf.name_scope('Loss'):
# 求交叉熵损失
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
# cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
# 求平均
loss = tf.reduce_mean(cross_entropy, name='loss')
# 4、参数学习算法设计
with tf.name_scope('Optimization'):
learn_rate=0.001
optimizer = tf.train.GradientDescentOptimizer(learn_rate).minimize(loss)
# 5、评估节点设计
with tf.name_scope('Evaluate'):
# 返回验证集/测试集预测正确或错误的布尔值
correct_prediction = tf.equal(tf.argmax(Y_pred, 1), tf.argmax(Y, 1))
# 将布尔值转换为浮点数后,求平均准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
用一个全连接网络+softmax网络实现简单分类这里将minist的单张图片展开为[1,28*28],目的是将图片的每个像素当作其特征放入全连接网络,提取浅层特征,损失函数用交叉熵损失函数(常用于分类网络)
至此主要的工作都以做完了,加下来就是训练了,我把全部训练代码放在这里。
def main(argv=None):
# 0、准备训练/验证/测试数据集
log_dir='./'
batch_size=50
batch_image, batch_label=Dataset(data_path,50,100).get_batch()
batch_num = Dataset(data_path,50,100).num_batch()
# 1、数据输入设计:使用 placeholder 将数据送入网络,None 表示张量的第一个维度可以是任意长度的
with tf.name_scope('Input'):
X = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='X_placeholder')
Y = tf.placeholder(dtype=tf.int32, shape=[None, 10], name='Y_placeholder')
# 2、前向网络设计
with tf.name_scope('Inference'):
# batch:20 输入:784,通道:1,输出:10
W = tf.Variable(initial_value=tf.random_normal(shape=[784, 10], stddev=0.01), name='Weights')
b = tf.Variable(initial_value=tf.zeros(shape=[10]), name='bias')
print(W)
logits = tf.matmul(X, W) + b
Y_pred = tf.nn.softmax(logits=logits)
# 3、损失函数设计
with tf.name_scope('Loss'):
# 求交叉熵损失
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
# cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
# 求平均
loss = tf.reduce_mean(cross_entropy, name='loss')
# 4、参数学习算法设计
with tf.name_scope('Optimization'):
learn_rate=0.001
optimizer = tf.train.GradientDescentOptimizer(learn_rate).minimize(loss)
# 5、评估节点设计
with tf.name_scope('Evaluate'):
# 返回验证集/测试集预测正确或错误的布尔值
correct_prediction = tf.equal(tf.argmax(Y_pred, 1), tf.argmax(Y, 1))
# 将布尔值转换为浮点数后,求平均准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# correct_prediction=tf.nn.in_top_k(Y_pred, Y, 1)
print('~~~~~~~~~~~开始执行计算图~~~~~~~~~~~~~~')
saver = tf.train.Saver(tf.global_variables(), max_to_keep=10)
with tf.Session() as sess:
counter = 0
summary_writer = tf.summary.FileWriter(logdir=log_dir, graph=sess.graph)
# 初始化所有变量
sess.run(tf.global_variables_initializer())
train_epoch_loss = []
test_epoch_loss = []
test_val_acc = []
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
while not coord.should_stop():
counter += 1
epoch_num = batch_num
# 训练
while epoch_num >= 0:
epoch_num -= 1
image_batch_v, label_batch_v = sess.run([batch_image, batch_label])
_, loss_batch, = sess.run([optimizer, loss], feed_dict={X: image_batch_v, Y: label_batch_v})
train_epoch_loss.append(loss_batch)
# 验证
while epoch_num <= batch_num:
epoch_num += 1
image_batch_v, label_batch_v = sess.run([batch_image, batch_label])
test_loss, acc = sess.run([loss, accuracy], feed_dict={X: image_batch_v, Y: label_batch_v})
test_epoch_loss.append(test_loss)
test_val_acc.append(acc)
mean_train_loss = round(np.mean(np.array(train_epoch_loss)), 3)
mean_test_loss = round(np.mean(np.array(test_epoch_loss)), 3)
mean_val_acc = round(np.mean(np.array(test_val_acc)), 3)
print('{} times val_acc is {}, train_loss: {},test_loss:{}'.format(counter, mean_val_acc, mean_train_loss,
mean_test_loss))
if counter % 300 == 0:
base_dir = './checkpoint'
ckpt_file = base_dir + "/batch_test_loss=%.4f.ckpt" % mean_train_loss
print('Save ckpt file to {}'.format(ckpt_file))
if os.path.exists(base_dir) == False:
os.makedirs(base_dir)
saver.save(sess, ckpt_file, global_step=counter)
if counter > 1000:
break
except tf.errors.OutOfRangeError:
print('Done!')
finally:
coord.request_stop()
coord.join(threads)
summary_writer.close()
4、验证
我们用单张图片进行验证,注意,输入的label和图片维度与训练的维度要一致。验证代码如下:
def prediect2(image):
labels=np.array([0,1,2,3,4,5,6,7,8,9]).reshape([1,10])#单张时为[1,10],n张时为[n,10]
trans2np=np.array(image).reshape([1,784])
with tf.name_scope('Input'):
x = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='X_placeholder')
y = tf.placeholder(dtype=tf.int32, shape=[None,10], name='Y_placeholder')
# 2、前向网络设计
with tf.name_scope('Inference'):
# batch:20 输入:784,通道:1,输出:10
W = tf.Variable(initial_value=tf.random_normal(shape=[784,10], stddev=0.01), name='Weights')
b = tf.Variable(initial_value=tf.zeros(shape=[10]), name='bias')
print(W)
logits = tf.matmul(x, W) + b
pred = tf.nn.softmax(logits=logits)
saver=tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.restore(sess, save_path= './checkpoint/batch_test_loss=0.5550.ckpt-300')
correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print('accuracy: ', accuracy.eval({x:trans2np,y:labels}))
output = tf.argmax(pred, 1)
outputval,pre = sess.run([output,pred], feed_dict={x: trans2np, y: labels})
print(outputval)
print('p:',pre)
最后可以看到答应出了类别对应的ID。
在代码中用了
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
求交叉损失,该方法:
除去name参数用以指定该操作的name,与方法有关的一共两个参数:
第一个参数logits:就是神经网络最后一层的输出,如果有batch的话,它的大小就是[batchsize,num_classes],单样本的话,大小就是
num_classes
第二个参数labels:实际的标签,shape必须和
logits相同。
除了用softmax_cross_entropy_with_logits方法以外还可以用
tf.nn.sparse_softmax_cross_entropy_with_logits(labels, logits, name=None)该方法用法比softmax_cross_entropy_with_logits简单,不用见label转化为one_hot编码就可以使用。见如下代码:
class Dataset(object):
def __init__(self,file_path,batch_size,capacity):
self.file_path=file_path#路径文件
self.batch_size=batch_size#batch_size
self.capacity=capacity#队列容量
self.image_size=28
def num_batch(self):
image, label = self.get_files(self.file_path)
return len(label)//self.batch_size#一批样本中的batch个数
def get_batch(self):
image, label = self.get_files(self.file_path)
batch_image, batch_label=self.get_batches(image,label,self.image_size,self.image_size,self.batch_size,self.capacity)
return batch_image,batch_label
def get_files(self,file_path):
class_train = []
label_train = []
for train_class in os.listdir(file_path):
for pic_name in os.listdir(file_path + train_class):
class_train.append(file_path + train_class + '/' + pic_name)
label_train.append(train_class)
temp = np.array([class_train, label_train])
temp = temp.transpose()
np.random.shuffle(temp)
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
# class is 1 2 3 4 5
label_list = [int(i) for i in label_list]
return image_list, label_list
def get_batches(self,image, label, resize_w, resize_h, batch_size, capacity):
image = tf.cast(image, tf.string)
label = tf.cast(label, tf.int64)
queue = tf.train.slice_input_producer([image, label])
label = queue[1]
image_temp = tf.read_file(queue[0])
image = tf.image.decode_jpeg(image_temp, channels=1)
# resize image
# image = tf.image.resize_image_with_crop_or_pad(image, resize_w, resize_h)
image = tf.image.resize_images(image, [resize_w, resize_h], method=0)
image = tf.image.per_image_standardization(image)
image_batch, label_batch = tf.train.batch([image, label], batch_size=batch_size,
num_threads=64,
capacity=capacity)
# 1:一个batch batch_size:总共划分的batch数,784,展开为1列
image_batch = tf.reshape(image_batch, [batch_size, resize_w * resize_w])
images_batch = tf.cast(image_batch, tf.float32)
labels_batch = tf.reshape(label_batch, [batch_size])
return images_batch, labels_batch
def main(argv=None):
# 0、准备训练/验证/测试数据集
log_dir='./'
batch_size=50
batch_image, batch_label=Dataset(data_path,batch_size,100).get_batch()
batch_num = Dataset(data_path,50,100).num_batch()
# 1、数据输入设计:使用 placeholder 将数据送入网络,None 表示张量的第一个维度可以是任意长度的
with tf.name_scope('Input'):
X = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='X_placeholder')
Y = tf.placeholder(dtype=tf.int32, shape=[None], name='Y_placeholder')
# 2、前向网络设计
with tf.name_scope('Inference'):
# batch:20 输入:784,通道:1,输出:10
W = tf.Variable(initial_value=tf.random_normal(shape=[784, 10], stddev=0.01), name='Weights')
b = tf.Variable(initial_value=tf.zeros(shape=[10]), name='bias')
print(W)
logits = tf.matmul(X, W) + b
Y_pred = tf.nn.softmax(logits=logits)
# 3、损失函数设计
with tf.name_scope('Loss'):
# 求交叉熵损失
# cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=Y, logits=logits, name='cross_entropy')
# 求平均
loss = tf.reduce_mean(cross_entropy, name='loss')
# 4、参数学习算法设计
with tf.name_scope('Optimization'):
learn_rate=0.001
optimizer = tf.train.GradientDescentOptimizer(learn_rate).minimize(loss)
# 5、评估节点设计
with tf.name_scope('Evaluate'):
# 返回验证集/测试集预测正确或错误的布尔值
# correct_prediction = tf.equal(tf.argmax(Y_pred, 1), tf.argmax(Y, 1))
# 将布尔值转换为浮点数后,求平均准确率
correct_prediction = tf.nn.in_top_k(Y_pred, Y, 1)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print('~~~~~~~~~~~开始执行计算图~~~~~~~~~~~~~~')
saver = tf.train.Saver(tf.global_variables(), max_to_keep=10)
with tf.Session() as sess:
counter = 0
summary_writer = tf.summary.FileWriter(logdir=log_dir, graph=sess.graph)
# 初始化所有变量
sess.run(tf.global_variables_initializer())
train_epoch_loss = []
test_epoch_loss = []
test_val_acc = []
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
while not coord.should_stop():
counter += 1
epoch_num = batch_num
# 训练
while epoch_num >= 0:
epoch_num -= 1
image_batch_v, label_batch_v = sess.run([batch_image, batch_label])
_, loss_batch, = sess.run([optimizer, loss], feed_dict={X: image_batch_v, Y: label_batch_v})
train_epoch_loss.append(loss_batch)
# 验证
while epoch_num <= batch_num:
epoch_num += 1
image_batch_v, label_batch_v = sess.run([batch_image, batch_label])
test_loss, acc = sess.run([loss, accuracy], feed_dict={X: image_batch_v, Y: label_batch_v})
test_epoch_loss.append(test_loss)
test_val_acc.append(acc)
mean_train_loss = round(np.mean(np.array(train_epoch_loss)), 3)
mean_test_loss = round(np.mean(np.array(test_epoch_loss)), 3)
mean_val_acc = round(np.mean(np.array(test_val_acc)), 3)
print('{} times val_acc is {}, train_loss: {},test_loss:{}'.format(counter, mean_val_acc, mean_train_loss,
mean_test_loss))
if counter % 300 == 0:
base_dir = './checkpoint'
ckpt_file = base_dir + "/batch_test_loss=%.4f.ckpt" % mean_train_loss
print('Save ckpt file to {}'.format(ckpt_file))
if os.path.exists(base_dir) == False:
os.makedirs(base_dir)
saver.save(sess, ckpt_file, global_step=counter)
if counter > 1000:
break
except tf.errors.OutOfRangeError:
print('Done!')
finally:
coord.request_stop()
coord.join(threads)
summary_writer.close()
tf.nn.sparse_softmax_cross_entropy_with_logits方法时在Dataset中用labels_batch = tf.reshape(label_batch, [batch_size])替换以下两句: 注意:用
labels_onehot_batch = tf.one_hot(label_batch, depth=10, on_value=1, axis=1) labels_batch = tf.reshape(labels_onehot_batch, [batch_size, 10]) ,同时计算accuracy时也要将tf.equal替换为:tf.nn.in_top_k。
验证代码也要做相应的改变,主要是将label改为一维数据。
labels=[0,1,2,3,4,5,6,7,8,9]
def prediect2(image):
trans2np=np.array(image).reshape([1,784])
with tf.name_scope('Input'):
x = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='X_placeholder')
y = tf.placeholder(dtype=tf.int32, shape=[None], name='Y_placeholder')
# 2、前向网络设计
with tf.name_scope('Inference'):
# batch:20 输入:784,通道:1,输出:10
W = tf.Variable(initial_value=tf.random_normal(shape=[784,10], stddev=0.01), name='Weights')
b = tf.Variable(initial_value=tf.zeros(shape=[10]), name='bias')
print(W)
logits = tf.matmul(x, W) + b
pred = tf.nn.softmax(logits=logits)
saver=tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver.restore(sess, save_path= './checkpoint/batch_test_loss=0.5550.ckpt-300')
# correct_prediction = tf.nn.in_top_k(pred, y, 1)
# accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#
#
#
#
# print('accuracy: ', accuracy.eval({x:trans2np,y:labels}))
output = tf.argmax(pred, 1)
outputval,pre = sess.run([output,pred], feed_dict={x: trans2np, y: labels})
print(outputval)
print('p:',pre)