Inception-v3是由Google提出,用於實現ImageNet大規模視覺識別任務(ImageNet Large Visual Recognition Challenge)的一種神經網絡node
Inception-v3反覆使用了Inception Block,涉及大量的卷積和池化,而ImageNet包括1400多萬張圖片,類別數超過1000python
所以手動在ImageNet上訓練Inception-v3,須要耗費大量的資源和時間git
這裏咱們選擇加載pre-trained的Inception-v3模型,來完成一些圖片分類任務github
預訓練好的模型共包括三個部分瀏覽器
classify_image_graph_def.pb
:Inception-v3模型結構和參數imagenet_2012_challenge_label_map_proto.pbtxt
:從類別編號到類別字符串的對應關係imagenet_synset_to_human_label_map.txt
:從類別字符串到類別名的對應關係例如,169
對應n02510455
,對應giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca
緩存
加載庫網絡
# -*- coding: utf-8 -*- import tensorflow as tf import numpy as np
整理兩個映射文件,獲得從類別編號到類別名的對應關係app
uid_to_human = {} for line in tf.gfile.GFile('imagenet_synset_to_human_label_map.txt').readlines(): items = line.strip().split('\t') uid_to_human[items[0]] = items[1] node_id_to_uid = {} for line in tf.gfile.GFile('imagenet_2012_challenge_label_map_proto.pbtxt').readlines(): if line.startswith(' target_class:'): target_class = int(line.split(': ')[1]) if line.startswith(' target_class_string:'): target_class_string = line.split(': ')[1].strip('\n').strip('\"') node_id_to_uid[target_class] = target_class_string node_id_to_name = {} for key, value in node_id_to_uid.items(): node_id_to_name[key] = uid_to_human[value]
加載模型dom
def create_graph(): with tf.gfile.FastGFile('classify_image_graph_def.pb', 'rb') as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) _ = tf.import_graph_def(graph_def, name='')
定義一個分類圖片的函數ide
def classify_image(image, top_k=1): image_data = tf.gfile.FastGFile(image, 'rb').read() create_graph() with tf.Session() as sess: # 'softmax:0': A tensor containing the normalized prediction across 1000 labels # 'pool_3:0': A tensor containing the next-to-last layer containing 2048 float description of the image # 'DecodeJpeg/contents:0': A tensor containing a string providing JPEG encoding of the image softmax_tensor = sess.graph.get_tensor_by_name('softmax:0') predictions = sess.run(softmax_tensor, feed_dict={'DecodeJpeg/contents:0': image_data}) predictions = np.squeeze(predictions) top_k = predictions.argsort()[-top_k:] for node_id in top_k: human_string = node_id_to_name[node_id] score = predictions[node_id] print('%s (score = %.5f)' % (human_string, score))
調用函數進行圖片分類,指定參數top_k
能夠返回最可能的多種分類結果
classify_image('test1.png')
分類結果以下
test1
:giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca (score = 0.89107)test2
:Pekinese, Pekingese, Peke (score = 0.90348)test3
:Samoyed, Samoyede (score = 0.92054)Inception-v3是針對ImageNet圖片分類任務設計的,所以最後一層全鏈接層的神經元個數和分類標籤個數相同
若是須要定製分類任務,只須要使用本身的標註數據,而後替換掉最後一層全鏈接層便可
最後一層全鏈接層的神經元個數等於定製分類任務的標籤個數,模型只訓練最後一層的參數,其餘參數保持不變
保留了Inception-v3對於圖像的理解和抽象能力,同時知足定製的分類任務,屬於遷移學習的一種典型應用場景
TensorFlow官方提供瞭如何在Inception-v3上進行遷移學習的教程
https://www.tensorflow.org/tutorials/image_retraining
所使用的數據包括五種花的拍攝圖片
去掉最後一層全鏈接層後,對於一張圖片輸入,模型輸出的表示稱做Bottleneck
事先計算好所有圖片的Bottleneck並緩存下來,能夠節省不少訓練時間,由於後續只需計算和學習Bottleneck到輸出標籤之間的隱層便可
TensorFlow官方提供了重訓練的代碼
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/image_retraining/retrain.py
在命令行中使用,一些可選的命令行參數包括
--image_dir
:訓練圖片目錄--output_graph
:模型保存目錄--output_labels
:模型標籤保存目錄--summaries_dir
:模型日誌保存目錄--how_many_training_steps
:訓練迭代次數,默認爲4000--learning_rate
:學習率,默認爲0.01--testing_percentage
:測試集比例,默認爲10%--validation_percentage
:校驗集比例,默認爲10%--eval_step_interval
:模型評估頻率,默認10次迭代評估一次--train_batch_size
:訓練批大小,默認爲100--print_misclassified_test_images
:是否輸出全部錯誤分類的測試集圖片,默認爲False--model_dir
:Inception-v3模型路徑--bottleneck_dir
:Bottleneck緩存目錄--final_tensor_name
:新增的最後一層全鏈接層的名稱,默認爲final_result
--flip_left_right
:是否隨機將一半的圖片水平翻轉,默認爲False--random_crop
:隨機裁剪的比例,默認爲0即不裁剪--random_scale
:隨機放大的比例,默認爲0即不放大--random_brightness
:隨機增亮的比例,默認爲0即不增亮--architecture
:遷移的模型,默認爲inception_v3
,準確率最高但訓練時間較長,還能夠選'mobilenet_<parameter size>_<input_size>[_quantized]'
,例如mobilenet_1.0_224
和mobilenet_0.25_128_quantized
跑一下代碼
python retrain.py --image_dir flower_photos --output_graph output_graph.pb --output_labels output_labels.txt --summaries_dir summaries_dir --model_dir .. --bottleneck_dir bottleneck_dir
此處對於視頻中內容的勘誤
--output_graph
以後的output_graph
改成output_graph.pb
--output_labels
以後的output_labels
改成output_labels.txt
在校驗集、測試集上的分類準確率分別爲91%、91.2%
在個人筆記本上一共花了55分鐘,其中44分鐘花在了Bottleneck緩存上,但若是不緩存的話,訓練過程當中每次迭代都必須重複計算一遍
summaries_dir
目錄下的訓練日誌可用於TensorBorad可視化
tensorboard --logdir summaries_dir
而後在瀏覽器中訪問http://localhost:6006,便可看到可視化的效果,包括SCALARS
、GRAPHS
、DISTRIBUTIONS
、HISTOGRAMS
四個頁面
若是須要完成其餘圖片分類任務,整理相應的標註圖片,並以標籤名做爲子文件夾名稱便可
若是要使用訓練好的模型,參照如下代碼便可
output_labels.txt
:分類類別文件路徑output_graph.pb
:訓練好的模型路徑read_image()
:讀取圖片的函數input_operation
:圖片輸入對應的operation
output_operation
:分類輸出對應的operation
test.jpg
:待分類的圖片路徑# -*- coding: utf-8 -*- import tensorflow as tf import numpy as np labels = [] for line in tf.gfile.GFile('output_labels.txt').readlines(): labels.append(line.strip()) def create_graph(): graph = tf.Graph() graph_def = tf.GraphDef() with open('output_graph.pb', 'rb') as f: graph_def.ParseFromString(f.read()) with graph.as_default(): tf.import_graph_def(graph_def) return graph def read_image(path, height=299, width=299, mean=128, std=128): file_reader = tf.read_file(path, 'file_reader') if path.endswith('.png'): image_reader = tf.image.decode_png(file_reader, channels=3, name='png_reader') elif path.endswith('.gif'): image_reader = tf.squeeze(tf.image.decode_gif(file_reader, name='gif_reader')) elif path.endswith('.bmp'): image_reader = tf.image.decode_bmp(file_reader, name='bmp_reader') else: image_reader = tf.image.decode_jpeg(file_reader, channels=3, name='jpeg_reader') image_np = tf.cast(image_reader, tf.float32) image_np = tf.expand_dims(image_np, 0) image_np = tf.image.resize_bilinear(image_np, [height, width]) image_np = tf.divide(tf.subtract(image_np, [mean]), [std]) sess = tf.Session() image_data = sess.run(image_np) return image_data def classify_image(image, top_k=1): image_data = read_image(image) graph = create_graph() with tf.Session(graph=graph) as sess: input_operation = sess.graph.get_operation_by_name('import/Mul') output_operation = sess.graph.get_operation_by_name('import/final_result') predictions = sess.run(output_operation.outputs[0], feed_dict={input_operation.outputs[0]: image_data}) predictions = np.squeeze(predictions) top_k = predictions.argsort()[-top_k:] for i in top_k: print('%s (score = %.5f)' % (labels[i], predictions[i])) classify_image('test.jpg')