雖然網上有很多YOLO 相關的文章,但是如果要用YOLO直接做一個落地産品,卻沒有一篇文章可以對每個步驟都進行指導了,為此,本文根據自己的項目經驗,結合論文的精度和網絡的相關文章,總結一篇可以從零到落地的文章。如有不詳細或者遺漏的請在評論區留言,謝謝。
原始論文路徑:pdf路徑
講解比較好的文章:YOLO文章詳細解讀
1,資料标注
1,推薦使用LabelImg,支援輸出YOLO輸出格式,安裝教程和使用說明見連結
2,醫學圖像檢測框标注工具可以采用3D slice,使用教程見連結
資料标注的存儲格式如下:
dog.jpg 104 237 316 527 1 122 117 609 491 2 457 60 694 174 3
其中dog.jpg為圖像的路徑,接着每5個值為一個金标準框(x1,y1,x2,y2,類别)
2,DataSet:定義網絡輸入和loss的金标準輸入
這裡輸入的是歸一化之後并resize為固定大小[448,448]的圖像;
輸出為7x7x30的張量,是以這的标注資料格式需要做一個轉換,轉換為7x7x30的格式,一個參考代碼如下:
h, w, _ = img.shape
grid_size = 7
stride = 1/grid_size
target = torch.zeros([grid_size, grid_size, 30])
boxes = boxes / torch.tensor([w, h, w, h]) # 歸一化到0-1
wh = boxes[:, 2:] - boxes[:, :2]
cxcy = (boxes[:, 2:] + boxes[:, :2])/2
for i in range(cxcy.size(0)):
center = cxcy[i]
ij = (center * grid_size).floor()
delta_xy = (center - ij * stride) * grid_size
target[int(ij[1]), int(ij[0]), 2:4] = wh[i]
target[int(ij[1]), int(ij[0]), 7:9] = wh[i]
target[int(ij[1]), int(ij[0]), :2] = delta_xy
target[int(ij[1]), int(ij[0]), 5:7] = delta_xy
target[int(ij[1]), int(ij[0]), 4] = 1
target[int(ij[1]), int(ij[0]), 9] = 1
target[int(ij[1]), int(ij[0]), 9+int(label[i])] = 1
3,編寫網絡結構

1,一種方法是實作論文的網絡結構,并書寫轉換接口,把原文的網絡參數加載到自己實作的網絡中,作為預訓練的參數。
2,一種方法是修改目前主流的網絡結構,如VGG16、U-Net、ResNet等,把最後幾層網絡進行修改,隻要確定最後一層網絡的輸出為7x7x30就行。
4,編寫Loss計算子產品
loss的輸入為predict和target,二者的尺寸都是7x7x30,一個loss類的架構如下:
class Loss(nn.Module):
def __init__(self):
super(Loss, self).__init__()
self.coord = 5.0
self.noobj = 0.5
def forward(self, pred, target):
'''
:param pred: Bx7x7x30 -inf, inf
:param target: Bx7x7x30 -inf, inf
:return:
'''
# xy loss
# wh loss
# iou loss
# label loss
5,訓練網絡結構
訓練網絡結構的步驟包括如下幾個:
1,執行個體化net = YOLO
2,網絡參數初始化
3,執行個體化Loss
4,執行個體化優化器
5,封裝dataset
6,循環更新網絡參數