1. 程式人生 > >TensroFlow學習——第三章(三)

TensroFlow學習——第三章(三)

卷積神經網路遷移學習

基於訓練好的Inception-v3的模型,對flower_photos資料集進行分類

訓練結果如下,測試集的準確率為91.0082%

在這裡插入圖片描述
演算法如下:

import os
import random
import numpy as np
import tensorflow as tf
from tensorflow.python.platform import gfile
import matplotlib.pyplot as plt
# Inception-v3模型瓶頸層的極點個數
BOTTLENECK_TENSOR_SIZE=2048

# Inceotion-v3模型中代表瓶頸層結果的張量名稱
# 在谷歌提供的Inception-v3模型中,這個張量名稱為‘pool_3/_reshape:0’
BOTTLENECK_TENSOR_NAME='pool_3/_reshape:0'

# 影象輸入張量所對應的名稱
JPEG_DATA_TENSOR_NAME='DecodeJpeg/contents:0'

# 下載好的谷歌訓練好的模型
MODEL_PATH='./data/classify_image_graph_def.pb'

# 將通過Inception_v3提取的特徵儲存在檔案中
Feature_path='./image.txt'

# 訓練樣本路徑
Input_path='./data/flower_photos'

# 驗證、測試資料百分比
VALIDATION_PERCENTAGE=0.1
TEST_PERCENTAGE=0.1

# 設定神經網路引數
LEARNING_RATE=0.01
STEPS=4000
BATCHSIZE=100

# 類別
LABELS={'daisy':0, 'dandelion':1, 'roses':2, 'sunflowers':3, 'tulips':4}

# 提取圖片資料,並分為訓練集、驗證集和測試集
def create_image_list():
	all_images,all_labels=[],[]
	label_list=os.listdir(Input_path)
	for file_name in label_list:
		image_dir=os.path.join(Input_path,file_name)
		image_list=os.listdir(image_dir)
		for name in image_list:
			image_name=os.path.join(image_dir,name)
			labels=np.zeros(len(LABELS),dtype=np.float32)
			labels[LABELS[file_name]]=1.0
			all_images.append(image_name)
			all_labels.append(labels)
	return all_images,all_labels

# 讀取提取的特徵向量作為訓練資料
def get_features(test_percentage,vaildation_percentage):
	# 讀取特徵資料
	images,labels=[],[]
	with open(Feature_path,'r') as file:
		string=file.readlines()
	for one_line in string:
		one_line=one_line.split('|')
		images.append([float(x) for x in one_line[0].split(',')])
		labels.append([float(x) for x in one_line[1].split(',')])
	# 分為訓練集、驗證集和測試集
	sum=list(zip(images,labels))
	random.shuffle(sum)
	images[:],labels[:]=zip(*sum)
	LEN1=int(test_percentage*len(images))
	LEN2=int(vaildation_percentage*len(images))
	# 返回的順序分別為test,valid,train
	return images[:LEN1],labels[:LEN1],images[LEN1:LEN1+LEN2],labels[LEN1:LEN1+LEN2],images[LEN1+LEN2:],labels[LEN1+LEN2:]

# 從訓練資料中批量取出資料
def random_get_batch_data(batch_size,images,labels):
	batch_image,batch_label=[],[]
	for i in range(batch_size):
		index=random.randint(0,len(images)-1)
		batch_image.append(images[index])
		batch_label.append(labels[index])
	return batch_image,batch_label

def main(argv=None):
	images,labels=create_image_list()
	train_datas=[]
	# 讀取訓練好的Inception-v3模型
	with gfile.FastGFile(MODEL_PATH,'rb') as f:
		graph_def=tf.GraphDef()
		graph_def.ParseFromString(f.read())
	# 載入讀取的Inception-v3模型,並返回資料輸入所對應的張量以及計算瓶頸層結果對應的張量
	bottle_tensor,jpeg_data_tensor=tf.import_graph_def(graph_def,return_elements=[BOTTLENECK_TENSOR_NAME,JPEG_DATA_TENSOR_NAME])
	if 0:#此部分備註掉是因為,用Inception-v3模型提取特徵後,會寫入檔案,因此在調整全連線層的引數時,可以不用再進行提取特徵操作
		# 提取特徵向量
		with tf.Session() as sess:
			for img in images:
				image=gfile.FastGFile(img,'rb').read()
				bottleneck_value=sess.run(bottle_tensor,feed_dict={jpeg_data_tensor:image})
				# 將四維張量轉化成以為陣列
				bottleneck_value=np.squeeze(bottleneck_value)
				train_datas.append(bottleneck_value)
		# 寫入檔案
		with open('./image.txt', 'w') as file:
			for i in range(len(train_datas)):
				string=','.join(str(x) for x in train_datas[i])+'|'+','.join(str(x) for x in labels[i])+'\n'
				file.write(string)

	# 讀取特徵量
	test_image,test_label,valid_image,valid_label,train_image,train_label=get_features(TEST_PERCENTAGE,VALIDATION_PERCENTAGE)
	n_classes=len(LABELS)

	# 定義新的神經網路輸入,這輸入是新的圖片經過Inception-v3模型向前傳播到達瓶頸層時的節點取值
	bottle_input=tf.placeholder(tf.float32,[None,BOTTLENECK_TENSOR_SIZE],name='BottleneckInputPlaceholder')
	ground_truth_input=tf.placeholder(tf.float32,[None,n_classes],name='GroundTruthInput')

	# 定義全連線層,用於將特徵分類
	with tf.name_scope('Final_training_ops'):
		weights=tf.Variable(tf.truncated_normal([BOTTLENECK_TENSOR_SIZE,n_classes],stddev=0.001))
		biases=tf.Variable(tf.zeros([n_classes]))
		logits=tf.matmul(bottle_input,weights)+biases
		final_tensor=tf.nn.softmax(logits)

	# 交叉熵損失函式
	cross_entropy=tf.nn.softmax_cross_entropy_with_logits(logits=final_tensor,labels=ground_truth_input)
	cross_entropy_mean=tf.reduce_mean(cross_entropy)
	train_step=tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(cross_entropy_mean)

	# 計算正確率
	with tf.name_scope('evalution'):
		correct_prediction=tf.equal(tf.arg_max(final_tensor,1),tf.arg_max(ground_truth_input,1))
		accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

	train_loss,train_acc=[],[]
	val_loss,val_acc=[],[]
	with tf.Session() as sess:
		init=tf.initialize_all_variables()
		sess.run(init)

		for epoch in range(STEPS):
			batch_image,batch_label=random_get_batch_data(BATCHSIZE,train_image,train_label)
			_,loss,acc=sess.run([train_step,cross_entropy_mean,accuracy],feed_dict={bottle_input:batch_image,ground_truth_input:batch_label})
			if (epoch+1)%100==0:
				print('<=%d=>,loss:%g,acc:%g%%'%(epoch+1,loss,acc*100.0))
				train_loss.append(loss)
				train_acc.append(acc)
				loss,acc=sess.run([cross_entropy_mean,accuracy],feed_dict={bottle_input:valid_image,ground_truth_input:valid_label})
				val_loss.append(loss)
				val_acc.append(acc)
			loss,acc=sess.run([cross_entropy_mean, accuracy],feed_dict={bottle_input:test_image,ground_truth_input:test_label})
		print('Test loss:%g,acc:%g%%'%(loss,acc*100.0))

	epochs=[i for i in range(len(train_acc))]
	plt.figure(1)
	plt.grid(True)
	plt.plot(epochs,train_loss,color='red',label='train_loss')
	plt.plot(epochs,val_loss,color='blue',label='valid_loss')
	plt.plot(epochs,train_acc,color='black',label='train_acc')
	plt.plot(epochs,val_acc,color='green',label='valid_acc')
	plt.legend()
	plt.xlabel('Epochs',fontsize=15)
	plt.ylabel('Y',fontsize=15)
	plt.title('LOSS AND ACC',fontsize=15)
	plt.show()

if __name__=='__main__':
	tf.app.run()