使用TensorFlow进行卷积神经网络实现花卉分类的项目,加载十种花分类,建立模型后进行预测分类图片
环境:win10 +TensorFlow gpu 1.12.0+pycharm
训练集
训练数据存放路径为:‘D:/LearnMSA/flower/train/花文件名/*.jpg’
训练模型存储路径为:'D:/LearnMSA/flower/model/‘
测试样本路径及文件名为:'D:/LearnMSA/flower/test/花文件名/**.jpg‘
测试用图片文件从训练数据中任意拷贝一张即可。
建立模型=导入库+获取数据集+图片处理+搭建模型+小批量处理+训练模型+保存模型
文件名:CnnFlower.py
from skimage import io, transform
import glob
import os
import tensorflow as tf
import numpy as np
import time
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
# 数据集地址
path='D:/LearnMSA/flower/train/'
#模型保存地址
model_path='D:/LearnMSA/flower/model/model.ckpt'
#设置图像处理后的大小
#分别是长*宽*通道3
w=100
h=100
c=3
# 1.读取图片
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):
# enumerate函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和下标,一般用在for循环当中
for im in glob.glob(folder+'/*.jpg'): # 利用glob.glob函数搜索每个层级文件下面符合特定格式“/*.jpg”进行遍历
try:
print('reading the images:%s'%(im)) # 遍历图像的同时,打印每张图片的“路径+名称”信息
img=io.imread(im) # 利用io.imread函数读取每一张被遍历的图像并将其赋值给img
try: #对异常图片进行处理
if img.shape[2] == 3:
img = transform.resize(img, (w, h))
imgs.append(img)
labels.append(idx)
except:
continue
except:
print("Cannot open image!")
# 利用np.asarray函数对生成的imgs和labels列表数据进行转化,之后转化成数组数据(imgs转成浮点数型,labels转成整数型)
return np.asarray(imgs,np.float32),np.asarray(labels,np.int32)
data,label=read_img(path)
print('shape of data=',data.shape) #查看样本数组大小
print('shape od labels=',label.shape) #查看标签数组大小
#5.数据预处理
# 打乱顺序
###调用np.random.shuffle函数将有序数组变无序
###返回打乱顺序后的图片和对应的标签
num_example = data.shape[0] #表示矩阵的行数
arr = np.arange(num_example) #生成0到num_example个数
np.random.shuffle(arr) # 随机打乱arr数组
data = data[arr] # 将data以arr索引重新组合
label = label[arr] # 将label以arr索引重新组合
# 将所有数据分为训练集和验证集
ratio = 0.8 #设置训练集比例
s = np.int(num_example*ratio)
x_train = data[:s]
y_train = label[:s]
x_val = data[s:]
y_val = label[s:]
# -----------------构建网络----------------------
#占位符设置输入参数的大小和格式
# 插入一个张量的占位符,这个张量总是被喂入图片数据。相当于一个形参。
x = tf.placeholder(tf.float32, shape=[None,w,h,c,], name='x') #用于传递样本数据
y_ = tf.placeholder(tf.int32, shape=[None,], name='Y_') #用于传递标签
print('x:',x.shape)
print('y:',y_.shape)
#6.建立训练模型
def inference(input_tensor,train,regularizer):
# -----------------------第一层----------------------------
with tf.variable_scope('layer1-conv1'):
# 初始化权重conv1_weights为可保存变量,大小为5x5,3个通道(RGB),数量为32个
conv1_weight = tf.get_variable('weight', [5, 5, 3, 32], initializer=tf.truncated_normal_initializer(stddev=0.1))
# 初始化偏置conv1_biases,数量为32个
conv1_bias = tf.get_variable('bias', [32], initializer=tf.constant_initializer(0.0))
# conv1_weights为权重,strides=[1, 1, 1, 1]表示左右上下滑动步长为1,padding='SAME'表示输入和输出大小一样,即补0
conv1 = tf.nn.conv2d(input_tensor, conv1_weight, strides=[1, 1, 1, 1], padding='SAME')
# 激励计算,调用tensorflow的relu函数
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_bias))
with tf.name_scope('layer2-pool1'):
# 池化计算,调用tensorflow的max_pool函数,strides=[1,2,2,1],表示池化边界,2个对一个生成,padding="VALID"表示不操作。
pool1=tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='VALID')
# -----------------------第二层----------------------------
with tf.variable_scope('layer3-conv2'):
# 定义第二个卷积层,原理和第一层相同
conv2_weight = tf.get_variable('weight', [5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=.1))
conv2_bias = tf.get_variable('bias', [64], initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(pool1, conv2_weight, strides=[1, 1, 1, 1], padding='SAME')
relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_bias))
with tf.variable_scope('layer4-pool2'):
pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
# -----------------------第三层---------------------------
with tf.variable_scope('layer5-conv3'):
# 定义第二个卷积层,原理和第一层相同
conv3_weight = tf.get_variable('weight', [3, 3, 64, 128],
initializer=tf.truncated_normal_initializer(stddev=.1))
conv3_bias = tf.get_variable('bias', [128], initializer=tf.constant_initializer(0.0))
conv3 = tf.nn.conv2d(pool2, conv3_weight, strides=[1, 1, 1, 1], padding='SAME')
relu3 = tf.nn.relu(tf.nn.bias_add(conv3, conv3_bias))
with tf.variable_scope('layer6-pool3'):
pool3 = tf.nn.max_pool(relu3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
# -----------------------第四层----------------------------
with tf.variable_scope('layer7-conv4'):
# 定义第二个卷积层,原理和第一层相同
conv4_weight = tf.get_variable('weight', [3, 3, 128, 128],
initializer=tf.truncated_normal_initializer(stddev=.1))
conv4_bias = tf.get_variable('bias', [128], initializer=tf.constant_initializer(0.0))
conv4 = tf.nn.conv2d(pool3, conv4_weight, strides=[1, 1, 1, 1], padding='SAME')
relu4 = tf.nn.relu(tf.nn.bias_add(conv4, conv4_bias))
with tf.variable_scope('layer8-pool4'):
pool4 = tf.nn.max_pool(relu4, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
# 第八层输出的是矩阵:【6,6,128】,把矩阵变成向量,每张图片排列成6*6*128 的向量
nodes = 6 * 6 * 128
reshape = tf.reshape(pool4, [-1, nodes])
# 使用变形函数转化结构
# -----------------------第五层---------------------------
with tf.variable_scope('layer9-FC1'):
fc1_weight = tf.get_variable('weight', [nodes, 1024], initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None: tf.add_to_collection('losses', regularizer(fc1_weight))
#
fc1_biases = tf.get_variable('bias', [1024], initializer=tf.constant_initializer(0.1))
fc1 = tf.nn.relu(tf.matmul(reshape, fc1_weight) + fc1_biases)
if train: fc1 = tf.nn.dropout(fc1, 0.5)
# -----------------------第六层----------------------------
with tf.variable_scope('layer10-FC2'):
fc2_weight = tf.get_variable('weight', [1024, 512], initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None: tf.add_to_collection('losses', regularizer(fc2_weight))
fc2_biases = tf.get_variable('bias', [512], initializer=tf.constant_initializer(0.1))
fc2 = tf.nn.relu(tf.matmul(fc1, fc2_weight) + fc2_biases)
if train: fc2 = tf.nn.dropout(fc2, 0.5)
# -----------------------第七层----------------------------
with tf.variable_scope('layer11-FC3'):
fc3_weight = tf.get_variable('weight', [512, 10], initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None: tf.add_to_collection('losses', regularizer(fc3_weight))
# fc3_biases = tf.get_variable('bias', [5], initializer=tf.constant_initializer(0.1)) 这个分类5,用于测试5种花卉
fc3_biases = tf.get_variable('bias', [10], initializer=tf.constant_initializer(0.1)) #分10类
logits = tf.matmul(fc2, fc3_weight) + fc3_biases
# 返回最后的计算结果
return logits
# ---------------------------网络结束---------------------------
#设置正则化参数为0.0001
regularizer=tf.contrib.layers.l2_regularizer(0.001)
#将上述构建网络结构引入
logits=inference(x,False,regularizer)
print('shape of logits:',logits.shape)
# (小处理)将logits乘以1赋值给logits_eval,定义name,方便在后续调用模型时通过tensor名字调用输出tensor
b=tf.constant(value=1,dtype=tf.float32)
logits_eval=tf.multiply(logits,b,name='logits_eval') #常数和矩阵想成
#设置损失函数,作为模型训练优化的参考标准,loss越小,模型越优
loss=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,labels=y_)
#设置整体学习率为α为0.001
optimizer=tf.train.AdamOptimizer(learning_rate=0.001)
#设置预测精度
train_op=optimizer.minimize(loss)
correct_prediction=tf.equal(tf.cast(tf.argmax(logits,1),tf.int32),y_)
#计算准确率
acc=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#7训练和测试
#定义一个函数,按照批次取数据
def minibatches(inputs=None,targets=None,batch_size=None,shuffle=False):
assert len(inputs)==len(targets)
if shuffle:
indices = np.arange(len(inputs))
np.random.shuffle(indices)
for start_idx in range(0, len(inputs) - batch_size + 1, batch_size):
if shuffle:
excerpt = indices[start_idx:start_idx + batch_size]
else:
excerpt = slice(start_idx, start_idx + batch_size)
yield inputs[excerpt], targets[excerpt]
n_epoch=10
batch_size=64
saver=tf.train.Saver()
sess=tf.Session()
sess.run(tf.global_variables_initializer())
for epoch in range(n_epoch):
print('epoch:',epoch+1)
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('train loss:%f'%(np.sum(train_loss)/n_batch))
print("train acc: %f" % (np.sum(train_acc) / n_batch))
#评估
val_loss,val_acc,n_batch=0,0,0
for x_vale_a,y_val_a in minibatches(x_val,y_val,batch_size,shuffle=False):
err,ac=sess.run([loss,acc],feed_dict={
x:x_vale_a,y_:y_val_a})
val_loss+=err
val_acc+=ac
n_batch+=1
print('validation loss : %f'%(np.sum(val_loss)/n_batch))
print('validation acc: %f'%(np.sum(val_acc)/n_batch))
print('epoch time:%f'%(time.time()-start_time))
print('-------------------------------------------')
#8.保存模型
saver.save(sess,model_path) #把运算后的模型保存
sess.close()
运行这个py文件,会不断的读图,最后生成模型,运行图如下:
运行成功如下:
在D:/LearnMSA/flower/model/ 下生成模型
测试模型=读取图片+导入模型+测试模型
文件名:test_independent.py
from skimage import io,transform
import tensorflow as tf
import numpy as np
import os
import glob #glob 文件通配符模块
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
w=100
h=100
c=3
path1 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/0向日葵107.jpg"
path2 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/1樱花53.jpg"
path3 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/2水仙花178.jpg"
path4 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/3牡丹136.jpg"
path5 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/5百合花284.jpg"
path6 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/6莲花161.jpg"
path7 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/9郁金香119.jpg"
path8 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/4玫瑰1.jpg"
path9 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/8蝴蝶兰263.jpg"
path10 = "F:/DeskTop/大三下学期/机器学习/LearnMSA/flower/test/7菊花1.jpg"
flower_dict = {
0:'向日葵',1:'樱花',2:'水仙花',3:'牡丹',4:'玫瑰',5:'百合花',6:'莲花',7:'菊花', 8:'蝴蝶兰', 9:'郁金香'}
model_path='D:/LearnMSA/flower/model/'
def read_one_image(path):
img = io.imread(path)
img = transform.resize(img,(w,h))
return np.asarray(img)
with tf.Session() as sess:
data = []
data1 = read_one_image(path1)
data2 = read_one_image(path2)
data3 = read_one_image(path3)
data4 = read_one_image(path4)
data5 = read_one_image(path5)
data6 = read_one_image(path6)
data7 = read_one_image(path7)
data8 = read_one_image(path8)
data9 = read_one_image(path9)
data10 = read_one_image(path10)
data.append(data1)
data.append(data2)
data.append(data3)
data.append(data4)
data.append(data5)
data.append(data6)
data.append(data7)
data.append(data8)
data.append(data9)
data.append(data10)
saver = tf.train.import_meta_graph(model_path+'model.ckpt.meta')
saver.restore(sess,tf.train.latest_checkpoint(model_path))
graph = tf.get_default_graph()
x = graph.get_tensor_by_name("x:0")
feed_dict = {
x:data}
logits = graph.get_tensor_by_name("logits_eval:0")
classification_result = sess.run(logits,feed_dict)
#打印出预测矩阵
print(classification_result)
#打印出预测矩阵每一行最大值的索引
print(tf.argmax(classification_result,1).eval())
#根据索引通过字典对应花的分类
output = []
output = tf.argmax(classification_result,1).eval()
for i in range(len(output)):
print("第",i+1,"朵花预测:"+flower_dict[output[i]])
设置一个文件夹的目录,读取目录下的图片,随机选择一个图片并显示处理
文件名:test.py
from skimage import io,transform
import tensorflow as tf
import numpy as np
import os
import matplotlib.pyplot as plt
from PIL import Image
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
w=100
h=100
c=3
path=r'D:/LearnMSA/flower/test/8蝴蝶兰/'
model_path='D:/LearnMSA/flower/model/'
flower_dict = {
0:'向日葵',1:'樱花',2:'水仙花',3:'牡丹',4:'玫瑰',5:'百合花',6:'莲花',7:'菊花', 8:'蝴蝶兰', 9:'郁金香'}
# 随机选择一张图片
def get_one_image(path):
# 输入参数:path,测试图片的路径
# 返回参数:image,从测试图片中随机抽取一张图片
print(path)
allPic = []
for pic in os.listdir(path):
if pic.endswith("jpg") or pic.endswith("png"):
allPic.append(pic)
print(pic)
n = len(allPic)
ind = np.random.randint(0, n)
img_dir = allPic[ind] # 随机选择测试的图片
img = io.imread(path + img_dir)
img = transform.resize(img, (w, h))
imgshow = Image.open(path + img_dir)
plt.imshow(imgshow)
plt.show()
image = np.array(img)
return image
with tf.Session() as sess:
data = []
data1 = get_one_image(path)
data.append(data1)
saver = tf.train.import_meta_graph(model_path+'model.ckpt.meta')
saver.restore(sess,tf.train.latest_checkpoint(model_path))
graph = tf.get_default_graph()
x = graph.get_tensor_by_name("x:0")
feed_dict = {
x:data}
logits = graph.get_tensor_by_name("logits_eval:0")
classification_result = sess.run(logits,feed_dict)
#打印出预测矩阵
print(classification_result)
#打印出预测矩阵每一行最大值的索引
print(tf.argmax(classification_result,1).eval())
#根据索引通过字典对应花的分类
output = []
output = tf.argmax(classification_result,1).eval()
for i in range(len(output)):
print("第",i+1,"朵花预测:"+flower_dict[output[i]])
结果预测跟文件夹里的图片一样,要提一点,要保证一些图片读取或者模型保存及读取的路径要正确,需要在程序里修改一下。
下一期再倒腾一个GUI的花卉识别