深度學習入門篇——手把手教你用 TensorFlow 訓練模型
更多騰訊海量技術文章,請關注騰訊雲技術社區:https://cloud.tencent.com/community
作者:付越
導語Tensorflow在更新1.0版本之後多了很多新功能,其中放出了很多用tf框架寫的深度網路結構(https://github.com/tensorflow/models ),大大降低了開發難度,利用現成的網路結構,
Object Detection API提供了5種網路結構的預訓練的權重,全部是用COCO資料集進行訓練,這五種模型分別是SSD+mobilenet、SSD+inception_v2、R-FCN+resnet101、faster RCNN+resnet101、faster RCNN+inception+resnet101。各個模型的精度和計算所需時間如下。下面及介紹下如何使用Object Detection去訓練自己的模型。
這裡TensorFlow的安裝就不再說明了,網上的教程一大把,
訓練前準備:
使用protobuf來配置模型和訓練參數,所以API正常使用必須先編譯protobuf庫,這裡可以下載直接編譯好的pb庫(https://github.com/google/protobuf/releases ),解壓壓縮包後,把protoc加入到環境變數中:
$ cd tensorflow/models$ protoc object_detection/protos/*.proto --python_out=.(我是把protoc加到環境變數中,遇到找不到*.proto檔的報錯,後來把protoc.exe放到models/object_detection目錄下,重新執行才可以)
然後將models和slim(tf高級框架)加入python環境變數:
PYTHONPATH=$PYTHONPATH:/your/path/to/tensorflow/models:/your/path/to/tensorflow/models/slim數據準備:
資料集需要轉化成PASCAL VOC結構,API提供了create_pascal_tf_record.py,把VOC結構資料集轉換成.record格式。
首先需要先要標注圖像相應標籤,這裡可以使用labelImg工具。每標注一張樣本,即生成一個xml的標注檔。然後,把這些標注的xml檔,按訓練集與驗證集分別放置到兩個目錄下,在Datitran提供了xml_to_csv.py腳本。這裡只要指定標注的目錄名即可。接下來,然後需要我們把對應的csv格式轉換成.record格式。
調用generate_tfrecord.py,注意要指定--csv_input與--output_path這兩個參數。執行下麵命令:
python generate_tfrecord.py --csv_input=sunglasses_test_labels.csv --output_path=sunglass_test.record這樣就生成了訓練及驗證用的train.record與test.record。接下來指定標籤名稱,仿照models/ object_detection/data/ pet_label_map.pbtxt,重新創建一個檔,指定標籤名。
item { id: 1 name: 'sunglasses'}訓練:
根據自己的需要,選擇一款用coco資料集預訓練的模型,把首碼model.ckpt放置在待訓練的目錄,這裡meta檔保存了graph和metadata,ckpt保存了網路的weights,這幾個檔表示預訓練模型的初始狀態。
打開ssd_mobilenet_v1_pets.config檔,並做如下修改:
num_classes:修改為自己的classes num
將所有PATH_TO_BE_CONFIGURED的地方修改為自己之前設置的路徑(共5處)
其他參數均保持默認參數。
準備好上述檔後就可以直接調用train檔進行訓練。
python object_detection/train.py --logtostderr --pipeline_config_path= D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config --train_dir=D:/training-sets/data-translate/trainingTensorBoard監控:
通過tensorboard工具,可以監控訓練過程,輸入西面指令後,在流覽器輸入localhost:6006(默認)即可。
這裡面有很多指標曲線,甚至有模型網路架構,筆者對於這裡面很多指標含義還沒有弄明白,不過感覺出TensorBoard這個工具應該是極其強大。不過我們可以通過Total_Loss來看整體訓練的情況。
從整體上看,loss曲線確實是收斂的,整體的訓練效果還是滿意的。另外,TensorFlow還提供了訓練過程中利用驗證集驗證準確性的能力,但是筆者在調用時,仍有些問題,這裡暫時就不詳細說明了。
Freeze Model模型匯出:
查看模型實際的效果前,我們需要把訓練的過程檔匯出,生產.pb的模型檔。本來,tensorflow/python/tools/freeze_graph.py提供了freeze model的api,但是需要提供輸出的final node names(一般是softmax之類的最後一層的啟動函數命名),而object detection api提供提供了預訓練好的網路,final node name並不好找,所以object_detection目錄下還提供了export_inference_graph.py。
python export_inference_graph.py --input_type image_tensor--pipeline_config_path D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config --trained_checkpoint_prefix D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config /model.ckpt-* --output_directory D:/training-sets /data-translate/training/result匯出完成後,在output_directory下,會生成frozen_inference_graph.pb、model.ckpt.data-00000-of-00001、model.ckpt.meta、model.ckpt.data文件。
調用生成模型:
目錄下本身有一個調用的例子,稍微改造如下:
import cv2import numpy as npimport tensorflow as tffrom object_detection.utils import label_map_utilfrom object_detection.utils import visualization_utils as vis_utilclass TOD(object): def __init__(self): self.PATH_TO_CKPT = r'D:lib f-modelmodels-masterobject_detection rainingrozen_inference_graph.pb' self.PATH_TO_LABELS = r'D:lib f-modelmodels-masterobject_detection rainingsunglasses_label_map.pbtxt' self.NUM_CLASSES = 1 self.detection_graph = self._load_model() self.category_index = self._load_label_map() def _load_model(self): detection_graph = tf.Graph() with detection_graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(self.PATH_TO_CKPT, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name='') return detection_graph def _load_label_map(self): label_map = label_map_util.load_labelmap(self.PATH_TO_LABELS) categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=self.NUM_CLASSES, use_display_name=True) category_index = label_map_util.create_category_index(categories) return category_index def detect(self, image): with self.detection_graph.as_default(): with tf.Session(graph=self.detection_graph) as sess: # Expand dimensions since the model expects images to have shape: [1, None, None, 3] image_np_expanded = np.expand_dims(image, axis=0) image_tensor = self.detection_graph.get_tensor_by_name('image_tensor:0') boxes = self.detection_graph.get_tensor_by_name('detection_boxes:0') scores = self.detection_graph.get_tensor_by_name('detection_scores:0') classes = self.detection_graph.get_tensor_by_name('detection_classes:0') num_detections = self.detection_graph.get_tensor_by_name('num_detections:0') # Actual detection. (boxes, scores, classes, num_detections) = sess.run( [boxes, scores, classes, num_detections], feed_dict={image_tensor: image_np_expanded}) # Visualization of the results of a detection. vis_util.visualize_boxes_and_labels_on_image_array( image, np.squeeze(boxes), np.squeeze(classes).astype(np.int32), np.squeeze(scores), self.category_index, use_normalized_coordinates=True, line_thickness=8) cv2.namedWindow("detection", cv2.WINDOW_NORMAL) cv2.imshow("detection", image) cv2.waitKey(0)if __name__ == '__main__': image = cv2.imread('image.jpg') detecotr = TOD() detecotr.detect(image)下面是一些圖片的識別效果:
這裡面有很多指標曲線,甚至有模型網路架構,筆者對於這裡面很多指標含義還沒有弄明白,不過感覺出TensorBoard這個工具應該是極其強大。不過我們可以通過Total_Loss來看整體訓練的情況。
從整體上看,loss曲線確實是收斂的,整體的訓練效果還是滿意的。另外,TensorFlow還提供了訓練過程中利用驗證集驗證準確性的能力,但是筆者在調用時,仍有些問題,這裡暫時就不詳細說明了。
Freeze Model模型匯出:
查看模型實際的效果前,我們需要把訓練的過程檔匯出,生產.pb的模型檔。本來,tensorflow/python/tools/freeze_graph.py提供了freeze model的api,但是需要提供輸出的final node names(一般是softmax之類的最後一層的啟動函數命名),而object detection api提供提供了預訓練好的網路,final node name並不好找,所以object_detection目錄下還提供了export_inference_graph.py。
python export_inference_graph.py --input_type image_tensor--pipeline_config_path D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config --trained_checkpoint_prefix D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config /model.ckpt-* --output_directory D:/training-sets /data-translate/training/result匯出完成後,在output_directory下,會生成frozen_inference_graph.pb、model.ckpt.data-00000-of-00001、model.ckpt.meta、model.ckpt.data文件。
調用生成模型:
目錄下本身有一個調用的例子,稍微改造如下:
import cv2import numpy as npimport tensorflow as tffrom object_detection.utils import label_map_utilfrom object_detection.utils import visualization_utils as vis_utilclass TOD(object): def __init__(self): self.PATH_TO_CKPT = r'D:lib f-modelmodels-masterobject_detection rainingrozen_inference_graph.pb' self.PATH_TO_LABELS = r'D:lib f-modelmodels-masterobject_detection rainingsunglasses_label_map.pbtxt' self.NUM_CLASSES = 1 self.detection_graph = self._load_model() self.category_index = self._load_label_map() def _load_model(self): detection_graph = tf.Graph() with detection_graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(self.PATH_TO_CKPT, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name='') return detection_graph def _load_label_map(self): label_map = label_map_util.load_labelmap(self.PATH_TO_LABELS) categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=self.NUM_CLASSES, use_display_name=True) category_index = label_map_util.create_category_index(categories) return category_index def detect(self, image): with self.detection_graph.as_default(): with tf.Session(graph=self.detection_graph) as sess: # Expand dimensions since the model expects images to have shape: [1, None, None, 3] image_np_expanded = np.expand_dims(image, axis=0) image_tensor = self.detection_graph.get_tensor_by_name('image_tensor:0') boxes = self.detection_graph.get_tensor_by_name('detection_boxes:0') scores = self.detection_graph.get_tensor_by_name('detection_scores:0') classes = self.detection_graph.get_tensor_by_name('detection_classes:0') num_detections = self.detection_graph.get_tensor_by_name('num_detections:0') # Actual detection. (boxes, scores, classes, num_detections) = sess.run( [boxes, scores, classes, num_detections], feed_dict={image_tensor: image_np_expanded}) # Visualization of the results of a detection. vis_util.visualize_boxes_and_labels_on_image_array( image, np.squeeze(boxes), np.squeeze(classes).astype(np.int32), np.squeeze(scores), self.category_index, use_normalized_coordinates=True, line_thickness=8) cv2.namedWindow("detection", cv2.WINDOW_NORMAL) cv2.imshow("detection", image) cv2.waitKey(0)if __name__ == '__main__': image = cv2.imread('image.jpg') detecotr = TOD() detecotr.detect(image)下面是一些圖片的識別效果: