<label id="jgr5k"></label>
    <legend id="jgr5k"><track id="jgr5k"></track></legend>

    <sub id="jgr5k"></sub>
  1. <u id="jgr5k"></u>
      久草国产视频,91资源总站,在线免费看AV,丁香婷婷社区,久久精品99久久久久久久久,色天使av,无码探花,香蕉av在线
      您正在使用IE低版瀏覽器,為了您的雷峰網賬號安全和更好的產品體驗,強烈建議使用更快更安全的瀏覽器
      此為臨時鏈接,僅用于文章預覽,將在時失效
      人工智能開發者 正文
      發私信給汪思穎
      發送

      0

      從零開始碼一個皮卡丘檢測器-CNN目標檢測入門教程(下)

      本文作者: 汪思穎 2017-08-30 11:43
      導語:皮卡!丘!~

      本文作者Zhreshold,原文載于其知乎主頁,雷鋒網(公眾號:雷鋒網)獲其授權發布。

      本文為大家介紹實驗過程中訓練、測試過程及結果。算法和數據集參見《從零開始碼一個皮卡丘檢測器-CNN目標檢測入門教程(上)》

      訓練 Train

      損失函數 Losses

      通過定義損失函數,我們可以讓網絡收斂到我們希望得到的目標檢測功能,也就是說,我們希望網絡能正確預測物體的類別,同時能預測出準確的預設框偏移量,以正確地顯示物體的真正大小和位置。

      這個預測的類別和偏移量都是可以通過真實標簽和網絡的當前預測值得到,在這里我們用MultiBoxTarget層來計算,其中包含了預測框和真實標簽的匹配,正類和負類的選擇,就不一一詳述了。(詳情見論文 SSD: Single Shot MultiBox Detector)。

      from mxnet.contrib.ndarray import MultiBoxTarget

      def training_targets(default_anchors, class_predicts, labels):
         class_predicts = nd.transpose(class_predicts, axes=(0, 2, 1))
         z = MultiBoxTarget(*[default_anchors, labels, class_predicts])
         box_target = z[0]  # 預設框偏移量 (x, y, width, height)
         box_mask = z[1]  # box_mask用來把負類的偏移量置零,因為背景不需要位置!
         cls_target = z[2]  # 每個預設框應該對應的分類
         return box_target, box_mask, cls_target

      gluon.loss中有很多預設的損失函數可以選擇,當然我們也可以快速地手寫一些損失函數。

      首先,對于物體分類的概率,平時我們往往用交叉墑,不過在目標檢測中,我們有大量非平衡的負類(背景),那么 Focal Loss會是一個很好的選擇(詳情見論文 Focal Loss for Dense Object Detection)。

      class FocalLoss(gluon.loss.Loss):
         def __init__(self, axis=-1, alpha=0.25, gamma=2, batch_axis=0, **kwargs):
             super(FocalLoss, self).__init__(None, batch_axis, **kwargs)
             self._axis = axis
             self._alpha = alpha
             self._gamma = gamma

         def hybrid_forward(self, F, output, label):
             output = F.softmax(output)
             pt = F.pick(output, label, axis=self._axis, keepdims=True)
             loss = -self._alpha * ((1 - pt) ** self._gamma) * F.log(pt)
             return F.mean(loss, axis=self._batch_axis, exclude=True)


      # cls_loss = gluon.loss.SoftmaxCrossEntropyLoss()

      cls_loss = FocalLoss()

      print(cls_loss)

      FocalLoss(batch_axis=0, w=None)

      接下來是一個流行的 SmoothL1 損失函數,用來懲罰不準確的預設框偏移量。

      class SmoothL1Loss(gluon.loss.Loss):
         def __init__(self, batch_axis=0, **kwargs):
             super(SmoothL1Loss, self).__init__(None, batch_axis, **kwargs)

         def hybrid_forward(self, F, output, label, mask):
             loss = F.smooth_l1((output - label) * mask, scalar=1.0)
             return F.mean(loss, self._batch_axis, exclude=True)


      box_loss = SmoothL1Loss()

      print(box_loss)

      SmoothL1Loss(batch_axis=0, w=None)

      衡量性能指標 Evaluate metrics

      我們在訓練時需要一些指標來衡量訓練是否順利,我們這里用準確率衡量分類的性能,用平均絕對誤差衡量偏移量的預測能力。這些指標對網絡本身沒有任何影響,只是用于觀測。

      cls_metric = mx.metric.Accuracy()

      box_metric = mx.metric.MAE()  # measure absolute difference between prediction and target

      選擇訓練用的設備 Set context for training

      ctx = mx.gpu()  # 用GPU加速訓練過程

      try:
         _ = nd.zeros(1, ctx=ctx)
         # 為了更有效率,cuda實現需要少量的填充,不影響結果
         train_data.reshape(label_shape=(3, 5))
         train_data = test_data.sync_label_shape(train_data)

      except mx.base.MXNetError as err:
         # 沒有gpu也沒關系,交給cpu慢慢跑
         print('No GPU enabled, fall back to CPU, sit back and be patient...')
         ctx = mx.cpu()

      初始化網絡參數 Initialize parameters

      net=ToySSD(num_class)

      net.initialize(mx.init.Xavier(magnitude=2),ctx=ctx)

      用gluon.Trainer簡化訓練過程 Set up trainer

      gluon.Trainer能簡化優化網絡參數的過程,免去對各個參數單獨更新的痛苦。

      net.collect_params().reset_ctx(ctx)

      trainer=gluon.Trainer(net.collect_params(),'sgd',{'learning_rate':0.1,'wd':5e-4})

      開始訓練 Start training

      既然是簡單的示例,我們不想花費太多的時間來訓練網絡,所以會預加載訓練過一段時間的網絡參數繼續訓練。

      如果你感興趣的話,可以設置

      from_scratch=True

      這樣網絡就會從初始的隨機參數開始訓練。

      一般從頭訓練用單個gpu會花費半個多小時。

      epochs = 150  # 設大一點的值來得到更好的結果

      log_interval = 20

      from_scratch = False  # 設為True就可以從頭開始訓練

      if from_scratch:
         start_epoch = 0

      else:
         start_epoch = 148
         pretrained = 'ssd_pretrained.params'
         sha1 = 'fbb7d872d76355fff1790d864c2238decdb452bc'
         url = 'https://apache-mxnet.s3-accelerate.amazonaws.com/gluon/models/ssd_pikachu-fbb7d872.params'
         if not osp.exists(pretrained) or not verified(pretrained, sha1):
             print('Downloading', pretrained, url)
             download(url, fname=pretrained, overwrite=True)
         net.load_params(pretrained, ctx)

      喝咖啡的時間

      import time

      from mxnet import autograd as ag

      for epoch in range(start_epoch, epochs):
         # 重置iterator和時間戳
         train_data.reset()
         cls_metric.reset()
         box_metric.reset()
         tic = time.time()
         # 迭代每一個批次
         for i, batch in enumerate(train_data):
             btic = time.time()
             # 用autograd.record記錄需要計算的梯度
             with ag.record():
                 x = batch.data[0].as_in_context(ctx)
                 y = batch.label[0].as_in_context(ctx)
                 default_anchors, class_predictions, box_predictions = net(x)
                 box_target, box_mask, cls_target = training_targets(default_anchors, class_predictions, y)
                 # 損失函數計算
                 loss1 = cls_loss(class_predictions, cls_target)
                 loss2 = box_loss(box_predictions, box_target, box_mask)
                 # 1比1疊加兩個損失函數,也可以加權重
                 loss = loss1 + loss2
                 # 反向推導
                 loss.backward()
             # 用trainer更新網絡參數
             trainer.step(batch_size)
             # 更新下衡量的指標
             cls_metric.update([cls_target], [nd.transpose(class_predictions, (0, 2, 1))])
             box_metric.update([box_target], [box_predictions * box_mask])
             if (i + 1) % log_interval == 0:
                 name1, val1 = cls_metric.get()
                 name2, val2 = box_metric.get()
                 print('[Epoch %d Batch %d] speed: %f samples/s, training: %s=%f, %s=%f'
                       %(epoch ,i, batch_size/(time.time()-btic), name1, val1, name2, val2))

         # 打印整個epoch的的指標
         name1, val1 = cls_metric.get()
         name2, val2 = box_metric.get()
         print('[Epoch %d] training: %s=%f, %s=%f'%(epoch, name1, val1, name2, val2))
         print('[Epoch %d] time cost: %f'%(epoch, time.time()-tic))


      # 還可以把網絡的參數存下來以便下次再用

      net.save_params('ssd_%d.params' % epochs)

      [Epoch 148 Batch 19] speed: 109.217423 samples/s, training: accuracy=0.997539, mae=0.001862
      [Epoch 148] training: accuracy=0.997610, mae=0.001806
      [Epoch 148] time cost: 17.762958
      [Epoch 149 Batch 19] speed: 110.492729 samples/s, training: accuracy=0.997607, mae=0.001824
      [Epoch 149] training: accuracy=0.997692, mae=0.001789
      [Epoch 149] time cost: 15.353258

      測試 Test

      接下來就是  從零開始碼一個皮卡丘檢測器-CNN目標檢測入門教程(下) 的時刻,我們用訓練好的網絡來測試一張圖片。

      網絡推導的過程和訓練很相似,只不過我們不再需要計算真值和損失函數,也不再需要更新網絡的參數,一次推導就可以得到結果。

      準備測試數據 Prepare the test data

      我們需要讀取一張圖片,稍微調整到網絡需要的結構,比如說我們需要調整圖片通道的順序,減去平均值等等慣用的方法。

      import numpy as np

      import cv2

      def preprocess(image):
         """Takes an image and apply preprocess"""
         # 調整圖片大小成網絡的輸入
         image = cv2.resize(image, (data_shape, data_shape))
         # 轉換 BGR 到 RGB
         image = image[:, :, (2, 1, 0)]
         # 減mean之前先轉成float
         image = image.astype(np.float32)
         # 減 mean
         image -= np.array([123, 117, 104])
         # 調成為 [batch-channel-height-width]
         image = np.transpose(image, (2, 0, 1))
         image = image[np.newaxis, :]
         # 轉成 ndarray
         image = nd.array(image)
         return image


      image = cv2.imread('img/pikachu.jpg')

      x = preprocess(image)

      print('x', x.shape)

      x (1, 3, 256, 256)

      網絡推導 Network inference

      只要一行代碼,輸入處理完的圖片,輸出我們要的所有預測值和預設框。

      # 如果有預先訓練好的網絡參數,可以直接加載

      # net.load_params('ssd_%d.params' % epochs, ctx)

      anchors, cls_preds, box_preds = net(x.as_in_context(ctx))

      print('anchors', anchors)

      print('class predictions', cls_preds)

      print('box delta predictions', box_preds)

      anchors
      [[[-0.084375 -0.084375 0.115625 0.115625 ]
      [-0.12037501 -0.12037501 0.15162501 0.15162501]
      [-0.12579636 -0.05508568 0.15704636 0.08633568]
      ...,
      [ 0.01949999 0.01949999 0.98049998 0.98049998]
      [-0.12225395 0.18887302 1.12225389 0.81112695]
      [ 0.18887302 -0.12225395 0.81112695 1.12225389]]]
      <NDArray 1x5444x4 @gpu(0)>
      class predictions
      [[[ 0.33754104 -1.64660323]
      [ 1.15297699 -1.77257478]
      [ 1.1535604 -0.98352218]
      ...,
      [-0.27562004 -1.29400492]
      [ 0.45524898 -0.88782215]
      [ 0.20327765 -0.94481993]]]
      <NDArray 1x5444x2 @gpu(0)>
      box delta predictions
      [[-0.16735925 -0.13083346 -0.68860865 ..., -0.18972112 0.11822788
      -0.27067867]]
      <NDArray 1x21776 @gpu(0)>

      是不是看著還很奇怪,別著急,還差最后一步

      轉換為可讀的輸出 Convert predictions to real object detection results

      要把網絡輸出轉換成我們需要的坐標,還要最后一步,比如我們需要softmax把分類預測轉換成概率,還需要把偏移量和預設框結合來得到物體的大小和位置。

      非極大抑制(Non-Maximum Suppression)也是必要的一步,因為一個物體往往有不只一個檢測框。

      from mxnet.contrib.ndarray import MultiBoxDetection

      # 跑一下softmax, 轉成0-1的概率

      cls_probs = nd.SoftmaxActivation(nd.transpose(cls_preds, (0, 2, 1)), mode='channel')

      # 把偏移量加到預設框上,去掉得分很低的,跑一遍nms,得到最終的結果

      output = MultiBoxDetection(*[cls_probs, box_preds, anchors], force_suppress=True, clip=False)

      print(output)

      [[[ 0. 0.61178613 0.51807499 0.5042429 0.67325425 0.70118797]
      [-1. 0.59466797 0.52491206 0.50917625 0.66228026 0.70489514]
      [-1. 0.5731774 0.53843218 0.50217044 0.66522425 0.7118448 ]
      ...,
      [-1. -1. -1. -1. -1. -1. ]
      [-1. -1. -1. -1. -1. -1. ]
      [-1. -1. -1. -1. -1. -1. ]]]
      <NDArray 1x5444x6 @gpu(0)>

      結果中,每一行都是一個可能的結果框,表示為[類別id, 得分, 左邊界,上邊界,右邊界,下邊界],有很多-1的原因是網絡預測到這些都是背景,或者作為被抑制的結果。

      顯示結果 Display results

      數字永遠不如圖片來得直觀

      把得到的轉換結果畫在圖上,就得到我們期待已久的幾十萬伏特圖了!

      def display(img, out, thresh=0.5):
         import random
         import matplotlib as mpl
         mpl.rcParams['figure.figsize'] = (10,10)
         pens = dict()
         plt.clf()
         plt.imshow(img)
         for det in out:
             cid = int(det[0])
             if cid < 0:
                 continue
             score = det[1]
             if score < thresh:
                 continue
             if cid not in pens:
                 pens[cid] = (random.random(), random.random(), random.random())
             scales = [img.shape[1], img.shape[0]] * 2
             xmin, ymin, xmax, ymax = [int(p * s) for p, s in zip(det[2:6].tolist(), scales)]
             rect = plt.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin, fill=False,
                                  edgecolor=pens[cid], linewidth=3)
             plt.gca().add_patch(rect)
             text = class_names[cid]
             plt.gca().text(xmin, ymin-2, '{:s} {:.3f}'.format(text, score),
                            bbox=dict(facecolor=pens[cid], alpha=0.5),
                            fontsize=12, color='white')
         plt.show()


      display(image[:, :, (2, 1, 0)], output[0].asnumpy(), thresh=0.45)

      從零開始碼一個皮卡丘檢測器-CNN目標檢測入門教程(下)

      小結 Conclusion

      目標檢測不同于分類任務,需要考慮的不只是全圖尺度的單一分類,而是需要檢測到不同大小,不同位置的物體,難度自然提升了許多,用掃窗之類的傳統方法早已不適合神經網絡這種需要大量計算需求的新結構。幸好我們可以用本章節介紹的方法,利用卷積網絡的特性,一次推導得到全部的預測結果,相對來說快速且準確。

      我們希望能用較短的篇幅來描述一個足夠簡單的過程,但是難免會有疏漏,歡迎各種問題和建議,與此同時,我們會不斷更新教程,并且會帶來更多不同的算法,敬請期待。

      相關鏈接

      Apache MXNet官方網站:https://mxnet.incubator.apache.org/

      Github Repo: zackchase/mxnet-the-straight-dope

      英文版教程: Object Detection Using Convolutional Neural Networks

      Eric知乎介紹0.11 新特性:https://zhuanlan.zhihu.com/p/28648399

      0.11 Release:https://github.com/apache/incubator-mxnet/releases

      安裝指南:https://mxnet.incubator.apache.org/versions/master/get_started/install.html

      其他Gluon教程:http://gluon.mxnet.io/

      Gluon講座PPT: https://github.com/zackchase/mxnet-slides/blob/master/kdd-mxnet-slides.pdf

      Gluon深度學習樣例:https://github.com/apache/incubator-mxnet/tree/master/example/gluon

      SSD: Single Shot MultiBox Detector

      Focal Loss: [1708.02002] Focal Loss for Dense Object Detection

      雷峰網版權文章,未經授權禁止轉載。詳情見轉載須知

      從零開始碼一個皮卡丘檢測器-CNN目標檢測入門教程(下)

      分享:
      相關文章

      編輯

      關注AI學術,例如論文
      當月熱門文章
      最新文章
      請填寫申請人資料
      姓名
      電話
      郵箱
      微信號
      作品鏈接
      個人簡介
      為了您的賬戶安全,請驗證郵箱
      您的郵箱還未驗證,完成可獲20積分喲!
      請驗證您的郵箱
      立即驗證
      完善賬號信息
      您的賬號已經綁定,現在您可以設置密碼以方便用郵箱登錄
      立即設置 以后再說
      主站蜘蛛池模板: 试看做受1分钟小视频| av无码小缝喷白浆在线观看| 亚洲精品国产成人99久久6| 夜夜高潮天天爽欧美| 第一福利导航视频| 亚洲成a人片在线观看日本 | 在线免费观看毛片av| 精品亚洲综合一区二区三区| 中国熟妇浓毛hdsex| 国产一区二区日韩在线| 人妻丰满熟妇av无码区hd| 古蔺县| 成年女人永久免费观看视频 | 国产精品天干天干| 在线视频一区二区三区不卡| 国产精品毛片一区二区三区| 邹城市| 久久久久久毛片免费播放| 丁香五月欧美| 久久精品亚洲中文无东京热| 制服丝袜在线云霸| 久久亚洲A?V| 国产乱子伦日B视频| 亚洲色欲久久久综合网东京热| 精品无人乱码一区二区三区的优势| 在线看免费无码av天堂| 久久99精品久久久久子伦| 天天色天天操综合网| 久久综合99re88久久爱| 精品国产自拍在线视频| 久久精品一区二区三区中文字幕 | 免费a级毛片18以上观看精品| 91久久国产成人免费观看| 国产一卡一卡| 久久婷婷大香萑太香蕉av人| 少妇大胆瓣开下部自慰| 日本丰满妇人成熟免费中文字幕 | 成人午夜视频在线| 亚洲精品国产综合麻豆久久99| 中文字幕 欧美日韩| 亚洲国产成人aⅴ毛片大全|