代码
实验步骤
1、首先下载数据集,存放于电脑E盘,图片路径path,e:\flowers;
2、读取数据。将图片存放在data中,标签存放在label中
#读取图片
def read_img(path):
#os.listdir(path)表示在path路径下的所有文件和和文件夹列表
#用cate记录五种花的文件路径
cate=[path+x for x in os.listdir(path) if os.path.isdir(path+x)]
imgs=[] #存放所有的图片
labels=[] #图片的类别标签
for idx,folder in enumerate(cate):
for im in glob.glob(folder+'/*.jpg'):
#print('reading the images:%s'%(im))#im表示某张图片的路径
img=io.imread(im)
img=transform.resize(img,(w,h))#图片resize为100*100
imgs.append(img)
labels.append(idx)
#不用array的原因是copy时不会占用新的内存
return np.asarray(imgs,np.float32),np.asarray(labels,np.int32)
3、从每类花中选取部分图片可视化。设置要显示的每类花的数量show_num,获取每类花的总数量max_n。对每类花,随机生成show_num个在0,max_n-1之间的数据,表示在该类花中随机选择的图片。由于data中花是按顺序存放Dev,所以i类花的第j个花在data中的位置为i*max_n+j。调用matplotlib.pyplot显示图片。
#部分图片可视化,每种花分别选取show_num 张
###1.每类花选择show_num张图片显示
###2.获取每类花的数量max_n
###3.对每类花,随机生成show_num个在0,max_n-1之间的数据,表示该类花随机选择的图片
###由于data中花是按顺序存放,i类花的第j个在data中的位置为i*max_n+j
def show(data,label):
show_num = 5
plt.figure()
max_n = np.int(data.shape[0]/5)
for i in range(show_num):
a=[random.randint(0,max_n) for _ in range(show_num)]
for j in range(show_num):
plt.subplot(show_num,show_num,show_num*i+j+1)
plt.imshow(data[a[j]+np.int(max_n*i)-1])
plt.axis('off')
plt.show()
结果:
4、将所有图片归一化为100×100×3,打乱顺序后,选取60%作为训练集,20%为验证集,20%作为测试集。
训练集:用来训练网络参数,使得模型能够拟合数据。
验证集:调整超参数,防止模型发生过拟合,从而决定训练的结束。
测试集:用来测试模型的泛华能力,检查模型是否能很好的拟合训练过程中没有出现过的新数据,以此反应模型的真实能力。
#打乱顺序
###调用np.random.shuffle函数将有序数组变无序
###返回打乱顺序后的图片和对应的标签
def disturb(data,lable):
num_example=data.shape[0]
arr=np.arange(num_example)
np.random.shuffle(arr)
img=data[arr]
labels=label[arr]
return img,labels
#将所有数据分为训练集和验证集\测试集
def allocate(data,label):
inter1 = 0.6
inter2 = 0.8
num_example = data.shape[0]
s1 = np.int(num_example*inter1)
s2 = np.int(num_example*inter2)
x_train = data[:s1]
y_train = label[:s1]
x_val = data[s1:s2]
y_val = label[s1:s2]
x_test = data[s2:]
y_test = label[s2:]
return x_train,y_train,x_val,y_val,x_test,y_test
5、构建CNN卷积网络,下图为CNN网络图。
输入为100×100,3个通道的图像;
第一层:Convolution5×5的卷积核32个,步幅为2,max_pooling卷积核2×2,Relu激活函数后,后输出第一层tensor为50×50×32。
第二层:Convolution 5×5的卷积核64个,步幅为2,max_pooling卷积核2×2,Relu激活函数后输出tensor为25×25×64
第三层:Convolution3×3的卷积核128个,步幅为2,max_pooling卷积核2×2,Relu激活函数后输出tensor为12×12×128
第四层:Convolution3×3的卷积核128个,步幅为2,max_pooling卷积核2×2,Relu激活函数后输出tensor为6×6×128
进入全连接层
第一层全连接层:1024维,将第四层输出的6×6×128tensor连接成为一个一维向量,作为该层的输入。
第二层全连接层:512维
第三层全连接层:5维
Softmax层:输出为5,即属于五类花中每类花的概率。
在训练时,从数据集中按批次取数据,设置的大小为64,训练次数分别设置为10次和20次,得到测试结果。
#-----------------构建网络----------------------
def Network():
#占位符
#第一个卷积层(100——>50)
conv1=tf.layers.conv2d(
inputs=x,
filters=32,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool1=tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
#第二个卷积层(50->25)
conv2=tf.layers.conv2d(
inputs=pool1,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool2=tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
#第三个卷积层(25->12)
conv3=tf.layers.conv2d(
inputs=pool2,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool3=tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2], strides=2)
#第四个卷积层(12->6)
conv4=tf.layers.conv2d(
inputs=pool3,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool4=tf.layers.max_pooling2d(inputs=conv4, pool_size=[2, 2], strides=2)
re1 = tf.reshape(pool4, [-1, 6 * 6 * 128])
#全连接层
dense1 = tf.layers.dense(inputs=re1,
units=1024,
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
dense2= tf.layers.dense(inputs=dense1,
units=512,
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
logits= tf.layers.dense(inputs=dense2,
units=5,
activation=None,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
return logits
6、训练模型,将训练好的模型保存在modle.ckpt中。
#训练和测试数据,可将n_epoch设置更大一些
def train(x_train,y_train,x_val,y_val,train_op,loss,acc):
n_epoch=10
batch_size=64
# 用于保存和载入模型
saver = tf.train.Saver(max_to_keep=1)
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
#保存训练过程中训练损失和训练集的正确率
Train_loss= np.zeros(n_epoch)
Train_acc = np.zeros(n_epoch)
#保存训练过程中验证损失和验证集的正确率
Val_loss= np.zeros(n_epoch)
Val_acc = np.zeros(n_epoch)
for epoch in range(n_epoch):
start_time = time.time()
#training
train_loss, train_acc, n_batch = 0, 0, 0
for x_train_a, y_train_a in minibatches(x_train, y_train, batch_size, shuffle=True):
_,err,ac=sess.run([train_op,loss,acc], feed_dict={x: x_train_a, y_: y_train_a})
train_loss += err;
train_acc += ac;
n_batch += 1
print('epoch',epoch+1)
Train_loss[epoch] = train_loss/ n_batch
Train_acc[epoch] = train_acc/ n_batch
print(" train loss: %f" % Train_loss[epoch])
print(" train acc: %f" % Train_acc[epoch])
#validation
val_loss, val_acc, n_batch = 0, 0, 0
for x_val_a, y_val_a in minibatches(x_val, y_val, batch_size, shuffle=False):
err, ac = sess.run([loss,acc], feed_dict={x: x_val_a, y_: y_val_a})
val_loss += err;
val_acc += ac;
n_batch += 1
Val_loss[epoch] = val_loss/ n_batch
Val_acc[epoch] = val_acc/ n_batch
print(" validation loss: %f" % Val_loss[epoch])
print(" validation acc: %f" % Val_acc[epoch])
N = [i+1 for i in range(n_epoch)]
saver.save(sess,modle_path)
sess.close()
return Train_loss,Train_acc,Val_loss,Val_acc,N
最终训练10次时训练集正确率达到58.82%,下图为训练损失、训练正确率、验证损失和验证集正确率随训练次数的变化。
7、测试模型。载入训练好的模型,读取模型参数,将测试集数据传人网络得到输出,输出与正确标签对比获得测试集正确率。
def test(x_test,y_test):
with tf.Session() as sess:
saver = tf.train.import_meta_graph('E:/flowers/modle.ckpt.meta')
saver.restore(sess,tf.train.latest_checkpoint('E:/flowers/'))
#获取默认系统图
graph = tf.get_default_graph()
x = graph.get_tensor_by_name("x:0")
feed_dict = {x:x_test}
logits = graph.get_tensor_by_name("logits_eval:0")
#得到预测结果
classification_result = sess.run(logits,feed_dict)
#根据索引通过字典对应花的分类
output = []
output = tf.argmax(classification_result,1).eval()
print(output)
Real = tf.equal(output,y_test).tolist.count(True)
test_acc = Real / x_test.shape[0]
return test_acc
8、预测花朵类别。读取训练好的模型,输入待测试图片,最终输出花朵种类。本文从网上一共找了10张图片进行测试。
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from skimage import io,transform
def predict(img):
with tf.Session() as sess:
saver = tf.train.import_meta_graph('E:/flowers/modle.ckpt.meta')
saver.restore(sess,tf.train.latest_checkpoint('E:/flowers/'))
graph = tf.get_default_graph()
x = graph.get_tensor_by_name("x:0")
feed_dict = {x:img}
logits = graph.get_tensor_by_name("logits_eval:0")
#得到预测结果
classification_result = sess.run(logits,feed_dict)
output = tf.argmax(classification_result,1).eval()
return output
imgs = []
for i in range(1,10):
img = io.imread('e:/test/'+str(i)+'.jpg')
img = transform.resize(img,(100,100))
imgs.append(img)
imgs = np.asarray(imgs,np.float32)
output = predict(imgs)
#acc = test(x_test,y_test)
class_flower = ["daisy","dandelion","rose","sunflowers","tulips"]
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
print('预测结果:',output)
for i in range(9):
plt.figure(i+1)
img = io.imread('e:/test/'+str(i+1)+'.jpg')
plt.imshow(img)
plt.xlabel('预测结果为:'+class_flower[output[i]])
结果: