【2020華為云AI實戰營】基于華為云ModelArts——物體檢測YOLOv3實踐筆記分享
物體檢測是計算機視覺中的一個重要的研究領域,在人流檢測,行人跟蹤,自動駕駛,醫學影像等領域有著廣泛的應用。不同于簡單的圖像分類,物體檢測旨在對圖像中的目標進行精確識別,包括物體的位置和分類,因此能夠應用于更多高層視覺處理的場景。例如在自動駕駛領域,需要辨識攝像頭拍攝的圖像中的車輛、行人、交通指示牌及其位置,以便進一步根據這些數據決定駕駛策略。本期學習案例,我們將聚焦于YOLO算法,YOLO(You Only Look Once)是一種one-stage物體檢測算法。
YOLO3主要的改進有:調整了網絡結構;利用多尺度特征進行對象檢測;對象分類用Logistic取代了softmax。在基本的圖像特征提取方面,YOLO3采用了稱之為Darknet-53的網絡結構(含有53個卷積層),它借鑒了殘差網絡residual network的做法,在一些層之間設置了快捷鏈路,YOLO3借鑒了殘差網絡結構,形成更深的網絡層次,以及多尺度檢測,提升了mAP及小物體檢測效果。如果采用COCO mAP50做評估指標(不是太介意預測框的準確性的話),YOLO3的表現相當驚人,如下圖所示,在精確度相當的情況下,YOLOv3的速度是其它模型的3、4倍。
在實驗開始前,記得添加訪問秘鑰并完成ModelArts全局配置
參見華為云官方文檔:https://support.huaweicloud.com/prepare-modelarts/modelarts_08_0002.html
進入ModelArts創建ModelArts notebook
https://www.huaweicloud.com/product/modelarts.html
在ModelArts中創建一個notebook開發環境,ModelArts notebook提供網頁版的Python開發環境,可以方便的編寫、運行代碼,并查看運行結果。
1.在ModelArts服務主界面依次點擊“開發環境”、“創建”
2.填寫notebook所需的參數: ? 項目名稱隨意
注意:存儲設置大家可以根據自己情況選擇EVS或是OBS
我為了方便保存文件和代碼所以選擇了OBS(總結了一份代碼,在文末附件中)
關于EVS可以查看華為云官方文檔了解詳細:https://support.huaweicloud.com/evs/index.html
關于OBS可以查看華為云官方文檔了解詳細:https://support.huaweicloud.com/obs/index.html
3.配置好notebook參數后,點擊下一步,進入notebook信息預覽。確認無誤后,點擊“立即創建”。
在ModelArts中創建開發環境
1.進入剛剛創建的Notebook
2.創建一個Python3環境的的Notebook。點擊右上角的"New",然后選擇TensorFlow 1.13.1開發環境。
在Notebook中編寫并執行代碼
數據和代碼下載
運行下面代碼,進行數據和代碼的下載和解壓
本案例使用coco數據,共80個類別。
import?os from?modelarts.session?import?Session sess?=?Session() if?sess.region_name?==?'cn-north-1': ??bucket_path="modelarts-labs/notebook/DL_object_detection_yolo/yolov3.tar.gz" elif?sess.region_name?==?'cn-north-4': ??bucket_path="modelarts-labs-bj4/notebook/DL_object_detection_yolo/yolov3.tar.gz" else: ???print("請更換地區到北京一或北京四") if?not?os.path.exists('./yolo3'): ????sess.download_data(bucket_path=bucket_path,?path="./yolov3.tar.gz") ???? if?os.path.exists('./yolov3.tar.gz'): ????#?解壓文件 ????os.system("tar?-xf?./yolov3.tar.gz") ????#?清理壓縮包 ????os.system("rm?-r?./yolov3.tar.gz")
準備數據
文件路徑定義
from?train?import?get_classes,?get_anchors #?數據文件路徑 data_path?=?"./coco/coco_data" #?coco類型定義文件存儲位置 classes_path?=?'./model_data/coco_classes.txt' #?coco數據anchor值文件存儲位置 anchors_path?=?'./model_data/yolo_anchors.txt' #?coco數據標注信息文件存儲位置 annotation_path?=?'./coco/coco_train.txt' #?預訓練權重文件存儲位置 weights_path?=?"./model_data/yolo.h5" #?模型文件存儲位置 save_path?=?"./result/models/" classes?=?get_classes(classes_path) anchors?=?get_anchors(anchors_path) #?獲取類型數量和anchor數量變量 num_classes?=?len(classes)num_anchors?=?len(anchors)
讀取標注數據
import?numpy?as?np #?訓練集與驗證集劃分比例 val_split?=?0.1 with?open(annotation_path)?as?f: ????lines?=?f.readlines() np.random.seed(10101) np.random.shuffle(lines) np.random.seed(None) num_val?=?int(len(lines)*val_split) num_train?=?len(lines)?-?num_val
數據讀取函數,構建數據生成器。每次讀取一個批次的數據至內存訓練,并做數據增強。
def?data_generator(annotation_lines,?batch_size,?input_shape,?data_path,anchors,?num_classes): ????n?=?len(annotation_lines) ????i?=?0 ????while?True: ????????image_data?=?[] ????????box_data?=?[] ????????for?b?in?range(batch_size): ????????????if?i==0: ????????????????np.random.shuffle(annotation_lines) ????????????image,?box?=?get_random_data(annotation_lines,?input_shape,?data_path,random=True)?#?隨機挑選一個批次的數據 ????????????image_data.append(image) ????????????box_data.append(box) ????????????i?=?(i+1)?%?n ????????image_data?=?np.array(image_data) ????????box_data?=?np.array(box_data) ????????y_true?=?preprocess_true_boxes(box_data,?input_shape,?anchors,?num_classes)?#?對標注框預處理,過濾異常標注框 ????????yield?[image_data,?*y_true],?np.zeros(batch_size) def?data_generator_wrapper(annotation_lines,?batch_size,?input_shape,?data_path,anchors,?num_classes): ????n?=?len(annotation_lines) ????if?n==0?or?batch_size<=0:?return?None ????return?data_generator(annotation_lines,?batch_size,?input_shape,?data_path,anchors,?num_classes)
模型訓練
本案例使用Keras深度學習框架搭建YOLOv3神經網絡。
可以進入相應的文件夾路徑查看源碼實現。
構建神經網絡
可以在./yolo3/model.py文件中查看細節
import?keras.backend?as?K from?yolo3.model?import?preprocess_true_boxes,?yolo_body,?yolo_loss from?keras.layers?import?Input,?Lambda from?keras.models?import?Model #?初始化session K.clear_session() #?圖像輸入尺寸 input_shape?=?(416,?416) image_input?=?Input(shape=(None,?None,?3)) h,?w?=?input_shape #?設置多尺度檢測的下采樣尺寸 y_true?=?[Input(shape=(h//{0:32,?1:16,?2:8}[l],?w//{0:32,?1:16,?2:8}[l],?num_anchors//3,?num_classes+5))? ??????????for?l?in?range(3)] #?構建YOLO模型結構 model_body?=?yolo_body(image_input,?num_anchors//3,?num_classes) #?將YOLO權重文件加載進來,如果希望不加載預訓練權重,從頭開始訓練的話,可以刪除這句代碼 model_body.load_weights(weights_path,?by_name=True,?skip_mismatch=True) #?定義YOLO損失函數 model_loss?=?Lambda(yolo_loss,?output_shape=(1,),?name='yolo_loss', ????arguments={'anchors':?anchors,?'num_classes':?num_classes,?'ignore_thresh':?0.5})([*model_body.output,?*y_true]) #?構建Model,為訓練做準備 model?=?Model([model_body.input,?*y_true],?model_loss)
#?打印模型各層結構 model.summary()
訓練回調函數定義
from?keras.callbacks?import?ReduceLROnPlateau,?EarlyStopping #?定義回調方法 reduce_lr?=?ReduceLROnPlateau(monitor='val_loss',?factor=0.1,?patience=3,?verbose=1)?#?學習率衰減策略 early_stopping?=?EarlyStopping(monitor='val_loss',?min_delta=0,?patience=10,?verbose=1)?#?早停策略
開始訓練
from?keras.optimizers?import?Adam from?yolo3.utils?import?get_random_data? #?設置所有的層可訓練 for?i?in?range(len(model.layers)): ????model.layers.trainable?=?True ???? #?選擇Adam優化器,設置學習率 learning_rate?=?1e-4 model.compile(optimizer=Adam(lr=learning_rate),?loss={'yolo_loss':?lambda?y_true,?y_pred:?y_pred})? #?設置批大小和訓練輪數 batch_size?=?16 max_epochs?=?2 print('Train?on?{}?samples,?val?on?{}?samples,?with?batch?size?{}.'.format(num_train,?num_val,?batch_size)) #?開始訓練 model.fit_generator(data_generator_wrapper(lines[:num_train],?batch_size,?input_shape,?data_path,anchors,?num_classes), ????steps_per_epoch=max(1,?num_train//batch_size), ????validation_data=data_generator_wrapper(lines[num_train:],?batch_size,?input_shape,?data_path,anchors,?num_classes), ????validation_steps=max(1,?num_val//batch_size), ????epochs=max_epochs, ????initial_epoch=0, ????callbacks=[reduce_lr,?early_stopping])
保存模型
import?os os.makedirs(save_path) #?保存模型 model.save_weights(os.path.join(save_path,?'trained_weights_final.h5'))
模型測試
打開一張測試圖片
from?PIL?import?Image import?numpy?as?np #?測試文件路徑 test_file_path?=?'./test.jpg' #?打開測試文件 image?=?Image.open(test_file_path) image_ori?=?np.array(image) image_ori.shape
圖片預處理
from?yolo3.utils?import?letterbox_image new_image_size?=?(image.width?-?(image.width?%?32),?image.height?-?(image.height?%?32)) boxed_image?=?letterbox_image(image,?new_image_size) image_data?=?np.array(boxed_image,?dtype='float32') image_data?/=?255. image_data?=?np.expand_dims(image_data,?0) image_data.shape
import?keras.backend?as?K sess?=?K.get_session()
構建模型
from?yolo3.model?import?yolo_body from?keras.layers?import?Input #?coco數據anchor值文件存儲位置 anchor_path?=?"./model_data/yolo_anchors.txt" with?open(anchor_path)?as?f: ????anchors?=?f.readline() anchors?=?[float(x)?for?x?in?anchors.split(',')] anchors?=?np.array(anchors).reshape(-1,?2) yolo_model?=?yolo_body(Input(shape=(None,None,3)),?len(anchors)//3,?num_classes)
加載模型權重,或將模型路徑替換成上一步訓練得出的模型路徑
#?模型權重存儲路徑 weights_path?=?"./model_data/yolo.h5" yolo_model.load_weights(weights_path)
定義IOU以及score:
IOU: 將交并比大于IOU的邊界框作為冗余框去除
score:將預測分數大于score的邊界框篩選出來
iou?=?0.45 score?=?0.8
構建輸出[boxes, scores, classes]
from?yolo3.model?import?yolo_eval input_image_shape?=?K.placeholder(shape=(2,?)) boxes,?scores,?classes?=?yolo_eval( ????yolo_model.output,? ????anchors, ????num_classes, ????input_image_shape, ????score_threshold=score,? ????iou_threshold=iou)
進行預測
out_boxes,?out_scores,?out_classes?=?sess.run( ????[boxes,?scores,?classes], ????feed_dict={ ????????yolo_model.input:?image_data, ????????input_image_shape:?[image.size[1],?image.size[0]], ????????K.learning_phase():?0 ????})
class_coco?=?get_classes(classes_path) out_coco?=?[] for?i?in?out_classes: ????out_coco.append(class_coco)
print(out_boxes) print(out_scores) print(out_coco)
將預測結果繪制在圖片上
from?PIL?import?Image,?ImageFont,?ImageDraw font?=?ImageFont.truetype(font='font/FiraMono-Medium.otf', ????????????????????size=np.floor(3e-2?*?image.size[1]?+?0.5).astype('int32')) thickness?=?(image.size[0]?+?image.size[1])?//?300 for?i,?c?in?reversed(list(enumerate(out_coco))): ????predicted_class?=?c ????box?=?out_boxes????score?=?out_scores????label?=?'{}?{:.2f}'.format(predicted_class,?score) ????draw?=?ImageDraw.Draw(image) ????label_size?=?draw.textsize(label,?font) ????top,?left,?bottom,?right?=?box ????top?=?max(0,?np.floor(top?+?0.5).astype('int32')) ????left?=?max(0,?np.floor(left?+?0.5).astype('int32')) ????bottom?=?min(image.size[1],?np.floor(bottom?+?0.5).astype('int32')) ????right?=?min(image.size[0],?np.floor(right?+?0.5).astype('int32')) ????print(label,?(left,?top),?(right,?bottom)) ????if?top?-?label_size[1]?>=?0: ????????text_origin?=?np.array([left,?top?-?label_size[1]]) ????else: ????????text_origin?=?np.array([left,?top?+?1]) ????for?i?in?range(thickness): ????????draw.rectangle( ????????????[left?+?i,?top?+?i,?right?-?i,?bottom?-?i], ????????????outline=225) ????draw.rectangle( ????????[tuple(text_origin),?tuple(text_origin?+?label_size)], ????????fill=225) ????draw.text(text_origin,?label,?fill=(0,?0,?0),?font=font) ????del?draw
image
可以看到模型可以成功識別人和傘啦!
接下來我們可以自己照幾張圖片來測試一下效果:
參考
[1]YOLOv3: An Incremental Improvement
[2]Deep Residual Learning for Image Recognition
[3]What’s new in YOLO v3?
[4]How to implement a YOLO (v3) object detector from scratch in PyTorch
[5]https://github.com/huaweicloud/ModelArts-Lab
附件: 物體檢測YOLOv3實踐.zip 622.25KB 下載次數:11次
AI開發平臺ModelArts EI企業智能 AI
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。