<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TensorFlow 2 實(shí)戰(zhàn)之從零開始構(gòu)建 YOLOv3 目標(biāo)檢測(cè)網(wǎng)絡(luò)

          共 10433字,需瀏覽 21分鐘

           ·

          2021-02-24 17:33





          引言

          今天為大家?guī)?lái)社區(qū)作者的精選推薦《Tensorfow 2 實(shí)戰(zhàn)之從零開始構(gòu)建 YOLOv3 目標(biāo)檢測(cè)網(wǎng)絡(luò)》。想知道如何正確使用 Tensorflow 2 實(shí)現(xiàn) YOLOv3 算法?CSDN 認(rèn)證博客專家 @ZONG_XP 為你帶來(lái)專業(yè)講解,手把手教你搭建目標(biāo)檢測(cè)網(wǎng)絡(luò)!


          網(wǎng)上雖然有很多利用 TensorFlow 實(shí)現(xiàn) YOLOv3 的代碼和文章,但感覺講解得還不夠透徹,對(duì)于新手而言,存在一定的理解難度。本文目的是為了從零開始構(gòu)建 YOLOv3 目標(biāo)檢測(cè)網(wǎng)絡(luò),對(duì)網(wǎng)絡(luò)和代碼細(xì)節(jié)做詳細(xì)地介紹,使大家對(duì) TensorFlow 的使用方法有一個(gè)基本的掌握。?


          本文主要包含以下四個(gè)方面的內(nèi)容:

          1. 為什么選擇學(xué)習(xí) TensorFlow,以及如何安裝 TensorFlow?

          2. 為什么選擇 YOLOv3 目標(biāo)檢測(cè)網(wǎng)絡(luò)?

          3. 深度學(xué)習(xí)前向推理的整個(gè)流程是什么樣的?

          4. 對(duì) YOLOv3 網(wǎng)絡(luò)構(gòu)建部分進(jìn)行詳細(xì)的代碼介紹。


          1 Why TensorFlow ?

          1.1 TensorFlow 特點(diǎn)

          很多入門深度學(xué)習(xí)的同學(xué)都會(huì)有類似的困惑,市面上有很多開源框架,如 PyTorch、Caffe、MXNet、PaddlePaddle等,該如何進(jìn)行選擇呢?在我看來(lái),TensorFlow 的生態(tài)建設(shè)是最完整的,因?yàn)椋?/section>
          • 在開發(fā)語(yǔ)言方面,它支持 Python 開發(fā)、C++ 開發(fā)、JavaScript 開發(fā)、Swift 開發(fā);
          • 在模型開發(fā)方面,支持?jǐn)?shù)據(jù)輸入預(yù)處理、模型構(gòu)建、模型訓(xùn)練、模型導(dǎo)出全流程;
          • 在模型部署方面,支持在移動(dòng)設(shè)備、嵌入式設(shè)備、服務(wù)端多種方式部署;
          • 在硬件平臺(tái)方面,支持在 CPU、GPU、TPU、RPI 等不同硬件上運(yùn)行;
          • 在開發(fā)工具方面,支持 TensorBoard 訓(xùn)練可視化、TensorFlow Hub 豐富的模型庫(kù)

          基于 TensorFlow 豐富的生態(tài)特點(diǎn),我將 TensorFlow 作為開發(fā)的第一框架,便于自己快速在生產(chǎn)環(huán)境中部署深度學(xué)習(xí)模型。


          1.2 TensorFlow 安裝

          官方安裝教程中,介紹了兩種安裝方法,分別是 pip 軟件包管理器以及 docker 容器兩種方式,同時(shí)還提供了在 Google Colab 上調(diào)試的方法(需要穩(wěn)定的網(wǎng)絡(luò))。

          • 官方安裝教程
            https://tensorflow.google.cn/install

          • Google Colab
            https://colab.research.google.com/notebooks/welcome.ipynb


          docker 可以有效的對(duì)環(huán)境進(jìn)行隔離,容器中已經(jīng)配置好了相關(guān)環(huán)境,可以免去很多手動(dòng)安裝操作,但對(duì)于 docker 操作不熟悉的同學(xué)來(lái)說(shuō),使用起來(lái)不太方便。


          為了避免環(huán)境之間的影響,這里我推薦使用 conda 來(lái)創(chuàng)建虛擬環(huán)境。本文不介紹 conda 的安裝及使用方法,沒(méi)有安裝的同學(xué)可以參考相關(guān)教程。


          創(chuàng)建 conda 環(huán)境,安裝GPU 版本的 TensorFlow?

          conda create -n tensorflow-gpu-2 python=3.7  
          conda activate tensorflow-gpu-2
          pip install tensorflow-gpu


          經(jīng)過(guò)以上步驟,會(huì)在你的系統(tǒng)中安裝好最新版本的 TensorFlow 。



          2 Why YOLOv3?

          YOLOv3 作為 one-stage 目標(biāo)檢測(cè)算法典型代表,在工業(yè)界應(yīng)用非常廣泛,尤其是對(duì)于實(shí)時(shí)性要求較高的場(chǎng)合,YOLOv3 及其各種變體基本上是第一選擇。雖然現(xiàn)在已經(jīng)有 YOLOv4 和 YOLOv5 更先進(jìn)的算法,但也都是在 YOLOv3 的基礎(chǔ)上改進(jìn)而來(lái),因此有必要先掌握 YOLOv3 再學(xué)習(xí) YOLOv4 和 YOLOv5。


          YOLOv3 原論文寫得還是很“隨意”的,很多技術(shù)細(xì)節(jié)沒(méi)有講,但這并不妨礙大家對(duì)他的肯定,關(guān)于對(duì) YOLOv3 的解讀,推薦兩篇文章,分別是《深入淺出Yolo系列之 Yolov3 & Yolov4 & Yolov5 核心基礎(chǔ)知識(shí)完整講解》以及《你一定從未看過(guò)如此通俗易懂的 YOLO 系列(從 V1 到 V5 )模型解讀!》。

          • 深入淺出Yolo系列之 Yolov3 & Yolov4 & Yolov5 核心基礎(chǔ)知識(shí)完整講解
            https://zhuanlan.zhihu.com/p/143747206


          YOLOv3 整體結(jié)構(gòu)如圖所示,可以看到尺寸為 416 x 416 的輸入圖片進(jìn)入 Darknet-53 網(wǎng)絡(luò)后得到了 3 個(gè)分支,這些分支在經(jīng)過(guò)一系列的卷積、上采樣以及合并等操作后得到三個(gè)尺寸不一的 feature map,形狀分別為 [13, 13, 255]、[26, 26, 255] 和 [52, 52, 255],對(duì)這三個(gè)尺度的 feature map 經(jīng)過(guò)一系列的后處理,即可得到輸入圖像的目標(biāo)檢測(cè)框。


          YOLOv3 主要有以下幾個(gè)特點(diǎn):?
          1. 采用 darknet53 作為特征提取網(wǎng)絡(luò);
          2. 多尺度預(yù)測(cè),輸出三個(gè)分支,分別是 8 倍、16 倍、32 倍下采樣,分別實(shí)現(xiàn)對(duì)小目標(biāo)、中目標(biāo)、大目標(biāo)的檢測(cè);
          3. 每個(gè)尺度使用三種寬高比的 anchor 進(jìn)行預(yù)測(cè),所以總共包含 9 個(gè) anchor;
          4. 網(wǎng)絡(luò)的三個(gè)基本組件,分別是 DBL、res unit、rexn,具體細(xì)節(jié)參考上圖;
          5. 沒(méi)有池化層和全連接層,通過(guò)改變卷積核的步長(zhǎng)來(lái)調(diào)整張量的尺寸;


          通過(guò)上邊的歸納,相信你對(duì) YOLOv3 的算法原理有了基本的了解,接下來(lái)重點(diǎn)介紹代碼實(shí)現(xiàn)部分。



          3 Show me code

          3.1 總體流程

          要完成一個(gè)深度學(xué)習(xí)模型的推理,我們要依次完成以下步驟:
          1. 定義模型輸入
          2. 定義模型輸出
          3. 加載權(quán)重文件
          4. 準(zhǔn)備輸入數(shù)據(jù)
          5. 模型前向推理
          6. 輸出后處理
          7. 結(jié)果可視化


          總體代碼如下(代碼是在 YunYang1994/TensorFlow2.0-Examples (github.com/YunYang1994/TensorFlow2.0-Examples)?的基礎(chǔ)上修改),本質(zhì)上深度學(xué)習(xí)模型推理都是類似的流程,只不過(guò)不同的算法在網(wǎng)絡(luò)實(shí)現(xiàn)部分會(huì)有差異。

          # 1、定義模型輸入  
          input_size = 416
          input_layer = tf.keras.layers.Input([input_size, input_size, 3])

          # 2、定義模型輸出
          # 獲得三種尺度的卷積輸出
          # 具體實(shí)現(xiàn)見 YOLOv3 函數(shù)說(shuō)明
          feature_maps = YOLOv3(input_layer)
          bbox_tensors = []
          # 依次遍歷小、中、大尺寸的特征圖
          for i, fm in enumerate(feature_maps):
          # 對(duì)每個(gè)分支的通道信息進(jìn)行解碼,得到預(yù)測(cè)框的大小、置信度和類別概率
          # 具體操作見 decode 函數(shù)說(shuō)明
          bbox_tensor = decode(fm, i)
          bbox_tensors.append(bbox_tensor)

          # 3 加載權(quán)重文件
          # 根據(jù)上邊定義好的輸入輸出,實(shí)例化模型
          model = tf.keras.Model(input_layer, bbox_tensors)
          # 加載權(quán)重文件
          utils.load_weights(model, "./yolov3.weights")
          # 輸出模型信息
          model.summary()

          # 4、準(zhǔn)備輸入數(shù)據(jù)
          image_path = "./docs/kite.jpg"
          original_image = cv2.imread(image_path)
          original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB)
          original_image_size = original_image.shape[:2]
          image_data = utils.image_preporcess(np.copy(original_image), [input_size, input_size])
          image_data = image_data[np.newaxis, ...].astype(np.float32)

          # 5、模型前向推理
          pred_bbox = model.predict(image_data)
          pred_bbox = [tf.reshape(x, (-1, tf.shape(x)[-1])) for x in pred_bbox]
          pred_bbox = tf.concat(pred_bbox, axis=0)

          # 6、輸出后處理,
          bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.3)
          bboxes = utils.nms(bboxes, 0.45, method='nms')

          # 7、結(jié)果可視化
          image = utils.draw_bbox(original_image, bboxes)
          image = Image.fromarray(image)
          image.save("result.jpg")
          # image.show()

          ? ??

          其中模型定義、數(shù)據(jù)后處理是關(guān)鍵,這里對(duì)其具體的實(shí)現(xiàn)進(jìn)行介紹。


          3.2 網(wǎng)絡(luò)結(jié)構(gòu)

          代碼中的 common.convolutional() 和 common.upsample() 是實(shí)現(xiàn)卷積層和上采樣操作,其定義在工程中?(TensorFlow2.0-Examples)?common.py 文件中,這里不再進(jìn)一步展開。?

           def YOLOv3(input_layer):  
          # 輸入層進(jìn)入 Darknet-53 網(wǎng)絡(luò)后,得到了三個(gè)分支
          route_1, route_2, conv = backbone.darknet53(input_layer)
          # 見上圖中的橘黃色模塊(DBL),一共需要進(jìn)行5次卷積操作
          conv = common.convolutional(conv, (1, 1, 1024, 512))
          conv = common.convolutional(conv, (3, 3, 512, 1024))
          conv = common.convolutional(conv, (1, 1, 1024, 512))
          conv = common.convolutional(conv, (3, 3, 512, 1024))
          conv = common.convolutional(conv, (1, 1, 1024, 512))
          conv_lobj_branch = common.convolutional(conv, (3, 3, 512, 1024))
          # conv_lbbox 用于預(yù)測(cè)大尺寸物體,shape = [None, 13, 13, 255]
          conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 1024, 3*(NUM_CLASS + 5)),
          activate=False, bn=False)
          conv = common.convolutional(conv, (1, 1, 512, 256))
          # 這里的 upsample 使用的是最近鄰插值方法,這樣的好處在于上采樣過(guò)程不需要學(xué)習(xí),從而減少了網(wǎng)絡(luò)參數(shù)
          conv = common.upsample(conv)
          conv = tf.concat([conv, route_2], axis=-1)
          conv = common.convolutional(conv, (1, 1, 768, 256))
          conv = common.convolutional(conv, (3, 3, 256, 512))
          conv = common.convolutional(conv, (1, 1, 512, 256))
          conv = common.convolutional(conv, (3, 3, 256, 512))
          conv = common.convolutional(conv, (1, 1, 512, 256))
          conv_mobj_branch = common.convolutional(conv, (3, 3, 256, 512))
          # conv_mbbox 用于預(yù)測(cè)中等尺寸物體,shape = [None, 26, 26, 255]
          conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 512, 3*(NUM_CLASS + 5)),
          activate=False, bn=False)
          conv = common.convolutional(conv, (1, 1, 256, 128))
          conv = common.upsample(conv)
          conv = tf.concat([conv, route_1], axis=-1)
          conv = common.convolutional(conv, (1, 1, 384, 128))
          conv = common.convolutional(conv, (3, 3, 128, 256))
          conv = common.convolutional(conv, (1, 1, 256, 128))
          conv = common.convolutional(conv, (3, 3, 128, 256))
          conv = common.convolutional(conv, (1, 1, 256, 128))
          conv_sobj_branch = common.convolutional(conv, (3, 3, 128, 256))
          # conv_sbbox 用于預(yù)測(cè)小尺寸物體,shape = [None, 52, 52, 255]
          conv_sbbox = common.convolutional(conv_sobj_branch, (1, 1, 256, 3*(NUM_CLASS +5)),
          activate=False, bn=False)
          return [conv_sbbox, conv_mbbox, conv_lbbox]


          3.3 darknet53

          darknet53 網(wǎng)絡(luò)結(jié)構(gòu)如圖所示,主要是由卷積層、殘差模塊組成。

          利用 common.residual_block() 實(shí)現(xiàn)殘差連接。

            def darknet53(input_data):  

          input_data = common.convolutional(input_data, (3, 3, 3, 32))
          input_data = common.convolutional(input_data, (3, 3, 32, 64), downsample=True)

          for i in range(1):
          input_data = common.residual_block(input_data, 64, 32, 64)

          input_data = common.convolutional(input_data, (3, 3, 64, 128), downsample=True)

          for i in range(2):
          input_data = common.residual_block(input_data, 128, 64, 128)

          input_data = common.convolutional(input_data, (3, 3, 128, 256), downsample=True)

          for i in range(8):
          input_data = common.residual_block(input_data, 256, 128, 256)

          route_1 = input_data
          input_data = common.convolutional(input_data, (3, 3, 256, 512), downsample=True)

          for i in range(8):
          input_data = common.residual_block(input_data, 512, 256, 512)

          route_2 = input_data
          input_data = common.convolutional(input_data, (3, 3, 512, 1024), downsample=True)

          for i in range(4):
          input_data = common.residual_block(input_data, 1024, 512, 1024)

          return route_1, route_2, input_data


          3.4 decode 處理

          YOLOv3 網(wǎng)絡(luò)的三個(gè)分支輸出會(huì)被送入 decode 模塊對(duì) feature map 的通道信息進(jìn)行解碼,輸出的是預(yù)測(cè)框在原圖上的 [x, y, w, h, score, prob]。

            def decode(conv_output, i=0):  
          """
          return tensor of shape [batch_size, output_size, output_size, anchor_per_scale, 5 + num_classes]
          contains (x, y, w, h, score, probability)
          """


          conv_shape = tf.shape(conv_output)
          batch_size = conv_shape[0]
          output_size = conv_shape[1]

          # 對(duì) tensor 進(jìn)行 reshape
          conv_output = tf.reshape(conv_output, (batch_size, output_size, output_size, 3, 5 + NUM_CLASS))

          # 按順序提取[x, y, w, h, c]
          conv_raw_dxdy = conv_output[:, :, :, :, 0:2] # 中心位置的偏移量
          conv_raw_dwdh = conv_output[:, :, :, :, 2:4] # 預(yù)測(cè)框長(zhǎng)寬的偏移量
          conv_raw_conf = conv_output[:, :, :, :, 4:5] # 預(yù)測(cè)框的置信度
          conv_raw_prob = conv_output[:, :, :, :, 5: ] # 預(yù)測(cè)框的類別概率

          # 好了,接下來(lái)是畫網(wǎng)格。其中,output_size 等于 13、26 或者 52
          y = tf.tile(tf.range(output_size, dtype=tf.int32)[:, tf.newaxis], [1, output_size])
          x = tf.tile(tf.range(output_size, dtype=tf.int32)[tf.newaxis, :], [output_size, 1])
          xy_grid = tf.concat([x[:, :, tf.newaxis], y[:, :, tf.newaxis]], axis=-1)
          xy_grid = tf.tile(xy_grid[tf.newaxis, :, :, tf.newaxis, :], [batch_size, 1, 1, 3, 1])
          xy_grid = tf.cast(xy_grid, tf.float32) # 計(jì)算網(wǎng)格左上角的位置,即cx cy的值

          # 根據(jù)上圖公式計(jì)算預(yù)測(cè)框的中心位置
          # 這里的 i=0、1 或者 2, 以分別對(duì)應(yīng)三種網(wǎng)格尺度
          pred_xy = (tf.sigmoid(conv_raw_dxdy) + xy_grid) * STRIDES[i] # 計(jì)算預(yù)測(cè)框在原圖尺寸上的x y
          pred_wh = (tf.exp(conv_raw_dwdh) * ANCHORS[i]) * STRIDES[i] # 計(jì)算預(yù)測(cè)框在原圖尺寸上的w h
          pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1) # 拼接起來(lái)
          pred_conf = tf.sigmoid(conv_raw_conf) # 計(jì)算預(yù)測(cè)框里object的置信度
          pred_prob = tf.sigmoid(conv_raw_prob) # 計(jì)算預(yù)測(cè)框里object的類別概率

          return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1)


          3.5 后處理

          從網(wǎng)絡(luò)結(jié)構(gòu)拿到檢測(cè)框之后,就需要對(duì)框進(jìn)行后處理了,包括根據(jù)閾值去掉得分低的檢測(cè)框、NMS過(guò)濾掉多余的檢測(cè)框等,然后再把框在原圖上繪制出來(lái),就完成了整個(gè)檢測(cè)流程。



          4 Summary

          通過(guò)本文的介紹,相信大家對(duì) TensorFlow 的特點(diǎn)以及實(shí)現(xiàn)目標(biāo)檢測(cè)算法的流程有了基本的了解,在后續(xù)的文章中,我會(huì)進(jìn)一步的介紹如何訓(xùn)練 YOLOv3 網(wǎng)絡(luò),以及如何在生產(chǎn)環(huán)境中部署 YOLOv3 網(wǎng)絡(luò),敬請(qǐng)期待!



          最后

          本文由 TensorFlow 社區(qū)作者創(chuàng)作,文章已入選 “TensorFlow 開發(fā)者出道計(jì)劃” 精選推薦,并由 TensorFlow CSDN 社區(qū)進(jìn)行收錄。


          ·················END·················




          —推薦閱讀—


          谷歌提出Meta Pseudo Labels,刷新ImageNet上的SOTA!

          PyTorch 源碼解讀之 torch.autograd

          漲點(diǎn)神器FixRes:兩次超越ImageNet數(shù)據(jù)集上的SOTA

          Transformer為何能闖入CV界秒殺CNN?

          SWA:讓你的目標(biāo)檢測(cè)模型無(wú)痛漲點(diǎn)1% AP

          CondInst:性能和速度均超越Mask RCNN的實(shí)例分割模型

          centerX: 用新的視角的方式打開CenterNet

          mmdetection最小復(fù)刻版(十一):概率Anchor分配機(jī)制PAA深入分析

          MMDetection新版本V2.7發(fā)布,支持DETR,還有YOLOV4在路上!

          CNN:我不是你想的那樣

          TF Object Detection 終于支持TF2了!

          無(wú)需tricks,知識(shí)蒸餾提升ResNet50在ImageNet上準(zhǔn)確度至80%+

          不妨試試MoCo,來(lái)替換ImageNet上pretrain模型!

          重磅!一文深入深度學(xué)習(xí)模型壓縮和加速

          從源碼學(xué)習(xí)Transformer!

          mmdetection最小復(fù)刻版(七):anchor-base和anchor-free差異分析

          mmdetection最小復(fù)刻版(四):獨(dú)家yolo轉(zhuǎn)化內(nèi)幕


          機(jī)器學(xué)習(xí)算法工程師


          ? ??? ? ? ? ? ? ? ? ? ? ? ??????? ??一個(gè)用心的公眾號(hào)


          ?

          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  高清AV无码 | 午夜影院一区二区三区 | 精品人妻人伦 | 亚洲av看 | 91成人影库一级A片 |