天天看點

YOLOV3解讀(2)

具體分析create_model

在create_model方法中,建立YOLO v3的網絡結構,其中參數:

  • input_shape:輸入圖檔的尺寸,預設是(416,416);
  • anchors:預設的9種anchor box,shape是(9,2);
  • num_classes:類别數,建立網絡隻需要類别數即可,類别按0~n排列,輸入類别也是索引;
  • load_pretrained:是否使用預訓練模型;
  • freeze_body:當機模式,1或2,1是當機DarkNet53模型,2是隻保留最後3個1x1卷積層;
  • weights_path:預訓練的權重路徑;

代碼如下

def create_model(input_shape, anchors, num_classes, load_pretrained=True, freeze_body=2,
                 weights_path='model_data/yolo_weights.h5'):
           

**yolo_weight.h5是由.weight轉換而來,轉換程式為convert.py檔案 **

邏輯

将參數進行處理:

  • 拆分圖檔尺寸的寬h和高w;
  • 建立圖檔的輸入格式image_input,顯式如(416, 416, 3),隐式如(?, ?, 3);
  • 計算anchor的數量num_anchors;
  • 根據anchor的數量,建立真值y_true的輸入格式;

代碼如下

h, w = input_shape  # 尺寸
image_input = Input(shape=(w, h, 3))  # 圖檔輸入格式
num_anchors = len(anchors)  # anchor數量

# YOLO的三種尺度,每個尺度的anchor數,類别數+邊框4個+置信度1
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)]
           

h,w都經過了相應尺寸的縮放,對應各自的三種anchor值,有幾個類别,就會設定多少個初始值為0的空間,最後隻有預測的那一位置1

其中,真值y_true,真值即Ground Truth:

“//”是Python文法中的整除符号,通過循環建立3個Input層,組成清單,作為y_true,假設class為1,格式如下:

Tensor("input_2:0", shape=(?, 13, 13, 3, 6), dtype=float32)
Tensor("input_3:0", shape=(?, 26, 26, 3, 6), dtype=float32)
Tensor("input_4:0", shape=(?, 52, 52, 3, 6), dtype=float32)
           

其中,第1位是樣本數,第2~3位是特征圖的尺寸13x13,第4位是每個圖的anchor數,第5位是:類别(n)+4個框值(x,y,w,h)+框的置信度(是否含有物體)。

通過圖檔輸入Input層image_input、每個尺度的anchor數num_anchors//3、類别數num_classes,建立YOLO v3的網絡結構,即:

model_body = yolo_body(image_input, num_anchors // 3, num_classes)
           

shape=(?,416,416,3,6)

接着,加載預訓練模型:

根據預訓練模型的位址weights_path,加載模型,按名稱對應by_name,略過不比對skip_mismatch;

選擇當機模式:

  • 模式1的層數是185,也就是freeze整個darknet,模式2的層數是保留最後3層;其中,模型共有252層;
  • 将選擇的層數,設定為可訓練,model_body.layers[i].trainable=True

代碼如下

if load_pretrained:  # 加載預訓練模型
    model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)
    if freeze_body in [1, 2]:
        # Freeze darknet53 body or freeze all but 3 output layers.
        num = (185, len(model_body.layers) - 3)[freeze_body - 1]
        for i in range(num):
            model_body.layers[i].trainable = False  # 将其他層的訓練關閉
           

接着,設定模型損失層model_loss:

  • Lambda是Keras的自定義層,輸入為(model_body.output + y_true),輸出為output_shape=(1,);
  • 層的名字name為yolo_loss;
  • 參數為anchors錨框、類别數num_classes,ignore_thresh是物體置信度損失(object confidence

    loss)的IoU(Intersection over Union,重疊度)門檻值;

  • yolo_loss是核心的損失函數;
  • model_loss是由模型輸出及搭建的y_true共同得到

model_body.output指代的是經過神經網絡後得到的模型輸出

代碼如下

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_body的輸入層,即image_input,和y_true;

模型的輸出:model_loss的輸出,一個值,output_shape=(1,);

儲存模型的網絡圖plot_model,和列印網絡model.summary();

代碼如下

model = Model(inputs=[model_body.input] + y_true, outputs=model_loss) # 模型
plot_model(model, to_file=os.path.join('model_data', 'model.png'), show_shapes=True, show_layer_names=True)  # 存儲網絡結構
model.summary()  # 列印網絡
           

其中,model_body.input是任意(?)個(416,416,3)的圖檔,即

Tensor("input_1:0", shape=(?, 416, 416, 3), dtype=float32)
           

y_true是已标注資料轉換的真值結構,即

[Tensor("input_2:0", shape=(?, 13, 13, 3, 6), dtype=float32),
  Tensor("input_3:0", shape=(?, 26, 26, 3, 6), dtype=float32),
  Tensor("input_4:0", shape=(?, 52, 52, 3, 6), dtype=float32)]
           

參考:

http://www.jintiankansha.me/t/D7hikktv8s

繼續閱讀