TorchVision 預訓練模型進行推斷

2021-03-02 GoCoding

torchvision.models[4] 裡包含了許多模型,用於解決不同的視覺任務:圖像分類、語義分割、物體檢測、實例分割、人體關鍵點檢測和視頻分類。

本文將介紹 torchvision[3] 中模型的入門使用,一起來創建 Faster R-CNN 預訓練模型,預測圖像中有什麼物體吧。

import torch
import torchvision
from PIL import Image

創建預訓練模型
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)

print(model) 可查看其結構:

FasterRCNN(
  (transform): GeneralizedRCNNTransform(
      Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
      Resize(min_size=(800,), max_size=1333, mode='bilinear')
  )
  (backbone): BackboneWithFPN(
    ...
  )
  (rpn): RegionProposalNetwork(
    (anchor_generator): AnchorGenerator()
    (head): RPNHead(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (cls_logits): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))
      (bbox_pred): Conv2d(256, 12, kernel_size=(1, 1), stride=(1, 1))
    )
  )
  (roi_heads): RoIHeads(
    (box_roi_pool): MultiScaleRoIAlign(featmap_names=['0', '1', '2', '3'], output_size=(7, 7), sampling_ratio=2)
    (box_head): TwoMLPHead(
      (fc6): Linear(in_features=12544, out_features=1024, bias=True)
      (fc7): Linear(in_features=1024, out_features=1024, bias=True)
    )
    (box_predictor): FastRCNNPredictor(
      (cls_score): Linear(in_features=1024, out_features=91, bias=True)
      (bbox_pred): Linear(in_features=1024, out_features=364, bias=True)
    )
  )
)

此預訓練模型是於 COCO train2017 上訓練的,可預測的分類有:

COCO_INSTANCE_CATEGORY_NAMES = [
  '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
  'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
  'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
  'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
  'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
  'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
  'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
  'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
  'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
  'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
  'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
  'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]

指定 CPU or GPU

獲取支持的 device:

device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')

模型移到 device:

model.to(device)

讀取輸入圖像
img = Image.open('data/bicycle.jpg').convert("RGB")
img = torchvision.transforms.ToTensor()(img)

準備模型入參 images:

images = [img.to(device)]

例圖 data/bicycle.jpg:

進行模型推斷

模型切為 eval 模式:

# For inference
model.eval()

模型在推斷時,只需要給到圖像數據,不用標註數據。推斷後,會返回每個圖像的預測結果 List[Dict[Tensor]]。Dict 包含欄位有:

boxes (FloatTensor[N, 4]): 預測框 [x1, y1, x2, y2], x 範圍 [0,W], y 範圍 [0,H]labels (Int64Tensor[N]): 預測類別
predictions = model(images)
pred = predictions[0]
print(pred)

預測結果如下:

{'boxes': tensor([[750.7896,  56.2632, 948.7942, 473.7791],
        [ 82.7364, 178.6174, 204.1523, 491.9059],
        ...
        [174.9881, 235.7873, 351.1031, 417.4089],
        [631.6036, 278.6971, 664.1542, 353.2548]], device='cuda:0',
       grad_fn=<StackBackward>), 'labels': tensor([ 1,  1,  2,  1,  1,  1,  2,  2,  1, 77,  1,  1,  1,  2,  1,  1,  1,  1,
         1,  1, 27,  1,  1, 44,  1,  1,  1,  1, 27,  1,  1, 32,  1, 44,  1,  1,
        31,  2, 38,  2,  2,  1,  1, 31,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  2,  2,  1,  1,  1,  2,  1,  1,  1,  1,  2,  1,  2,
         1,  1,  1,  1,  1,  1, 31,  2, 27,  1,  2,  1,  1, 31,  2, 77,  2,  1,
         2,  2,  2, 44,  2, 31,  1,  1,  1,  1], device='cuda:0'), 'scores': tensor([0.9990, 0.9976, 0.9962, 0.9958, 0.9952, 0.9936, 0.9865, 0.9746, 0.9694,
        0.9679, 0.9620, 0.9395, 0.8984, 0.8979, 0.8847, 0.8537, 0.8475, 0.7865,
        0.7822, 0.6896, 0.6633, 0.6629, 0.6222, 0.6132, 0.6073, 0.5383, 0.5248,
        0.4891, 0.4881, 0.4595, 0.4335, 0.4273, 0.4089, 0.4074, 0.3679, 0.3357,
        0.3192, 0.3102, 0.2797, 0.2655, 0.2640, 0.2626, 0.2615, 0.2375, 0.2306,
        0.2174, 0.2129, 0.1967, 0.1912, 0.1907, 0.1739, 0.1722, 0.1669, 0.1666,
        0.1596, 0.1586, 0.1473, 0.1456, 0.1408, 0.1374, 0.1373, 0.1329, 0.1291,
        0.1290, 0.1289, 0.1278, 0.1205, 0.1182, 0.1182, 0.1103, 0.1060, 0.1025,
        0.1010, 0.0985, 0.0959, 0.0919, 0.0887, 0.0886, 0.0873, 0.0832, 0.0792,
        0.0778, 0.0764, 0.0693, 0.0686, 0.0679, 0.0671, 0.0668, 0.0636, 0.0635,
        0.0607, 0.0605, 0.0581, 0.0578, 0.0572, 0.0568, 0.0557, 0.0556, 0.0555,
        0.0533], device='cuda:0', grad_fn=<IndexBackward>)}

繪製預測結果

獲取 score >= 0.9 的預測結果:

scores = pred['scores']
mask = scores >= 0.9

boxes = pred['boxes'][mask]
labels = pred['labels'][mask]
scores = scores[mask]

引入 utils.plots.plot_image 繪製結果:

from utils.colors import golden
from utils.plots import plot_image

lb_names = COCO_INSTANCE_CATEGORY_NAMES
lb_colors = golden(len(lb_names), fn=int, scale=0xff, shuffle=True)
lb_infos = [f'{s:.2f}' for s in scores]
plot_image(img, boxes, labels, lb_names, lb_colors, lb_infos,
           save_name='result.png')

utils.plots.plot_image 函數實現可見後文源碼,注意其要求 torchvision >= 0.9.0/nightly。

源碼test_pretrained_models.py[1]

utils.colors.golden:

import colorsys
import random


def golden(n, h=random.random(), s=0.5, v=0.95,
           fn=None, scale=None, shuffle=False):
  if n <= 0:
    return []

  coef = (1 + 5**0.5) / 2

  colors = []
  for _ in range(n):
    h += coef
    h = h - int(h)
    color = colorsys.hsv_to_rgb(h, s, v)
    if scale is not None:
      color = tuple(scale*v for v in color)
    if fn is not None:
      color = tuple(fn(v) for v in color)
    colors.append(color)

  if shuffle:
    random.shuffle(colors)
  return colors

utils.plots.plot_image:

from typing import Union, Optional, List, Tuple

import matplotlib.pyplot as plt
import numpy as np
import torch
import torchvision
from PIL import Image


def plot_image(
  image: Union[torch.Tensor, Image.Image, np.ndarray],
  boxes: Optional[torch.Tensor] = None,
  labels: Optional[torch.Tensor] = None,
  lb_names: Optional[List[str]] = None,
  lb_colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
  lb_infos: Optional[List[str]] = None,
  save_name: Optional[str] = None,
  show_name: Optional[str] = 'result',
) -> torch.Tensor:
  """
  Draws bounding boxes on given image.
  Args:
    image (Image): `Tensor`, `PIL Image` or `numpy.ndarray`.
    boxes (Optional[Tensor]): `FloatTensor[N, 4]`, the boxes in `[x1, y1, x2, y2]` format.
    labels (Optional[Tensor]): `Int64Tensor[N]`, the class label index for each box.
    lb_names (Optional[List[str]]): All class label names.
    lb_colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of all class label names.
    lb_infos (Optional[List[str]]): Infos for given labels.
    save_name (Optional[str]): Save image name.
    show_name (Optional[str]): Show window name.
  """
  if not isinstance(image, torch.Tensor):
    image = torchvision.transforms.ToTensor()(image)

  if boxes is not None:
    if image.dtype != torch.uint8:
      image = torchvision.transforms.ConvertImageDtype(torch.uint8)(image)
    draw_labels = None
    draw_colors = None
    if labels is not None:
      draw_labels = [lb_names[i] for i in labels] if lb_names is not None else None
      draw_colors = [lb_colors[i] for i in labels] if lb_colors is not None else None
    if draw_labels and lb_infos:
      draw_labels = [f'{l} {i}' for l, i in zip(draw_labels, lb_infos)]
    # torchvision >= 0.9.0/nightly
    #  https://github.com/pytorch/vision/blob/master/torchvision/utils.py
    res = torchvision.utils.draw_bounding_boxes(image, boxes,
      labels=draw_labels, colors=draw_colors)
  else:
    res = image

  if save_name or show_name:
    res = res.permute(1, 2, 0).contiguous().numpy()
    if save_name:
      Image.fromarray(res).save(save_name)
    if show_name:
      plt.gcf().canvas.set_window_title(show_name)
      plt.imshow(res)
      plt.show()

  return res

參考腳註[1]

test_pretrained_models.py: https://github.com/ikuokuo/start-pytorch/tree/master/tests/test_pretrained_models.py

[2]

torch.hub: https://pytorch.org/docs/stable/hub.html

[3]

torchvision: https://pytorch.org/vision/stable/index.html

[4]

torchvision.models: https://pytorch.org/vision/stable/models.html

相關焦點

  • PyTorch 預訓練模型,保存,讀取和更新模型參數以及多 GPU 訓練模型
    目錄PyTorch 預訓練模型保存模型參數讀取模型參數凍結部分模型參數,進行 fine-tuning模型訓練與測試的設置利用 torch.nn.DataParallel 進行多 GPU 訓練1.PyTorch 預訓練模型Pytorch 提供了許多 Pre-Trained Model on ImageNet,僅需調用 torchvision.models 即可,具體細節可查看官方文檔。往往我們需要對 Pre-Trained Model 進行相應的修改,以適應我們的任務。
  • Pytorch 加載預訓練模型之ResNet系列
    Pytorch 加載預訓練模型之ResNet系列參考網址:https://github.com/Cadene/pretrained-models.pytorch
  • 【小白學PyTorch】7.最新版本torchvision.transforms常用API翻譯與講解
    以PIL圖片中心為中心,進行圖片切割。這個方法一般用在訓練inception網絡。【參數】num_output_channels (int)  – 正常情況下灰度圖片是單通道的,但是這裡你可以設置成3,這樣的話,會輸出3個通道的灰度圖片(三個通道的特徵值相同),這樣的話,你就不用修改torchvision的預訓練模型中的輸入接口了。
  • 【他山之石】PyTorch使用預訓練模型進行模型加載
    地址:https://www.zhihu.com/people/panda-9-6通過模型以及模型參數的保存,實現模型的加載,我之前已經在一篇文章寫過了,在最近的學習任務中,以及和知友的討論中,遇到了這樣一種情況,如果網絡模型發生改動,那麼使用預訓練模型進行加載的情況下,網絡模型是如何加載的,對此進行了一些簡單的實驗。來驗證自己的一些想法。
  • 微軟發布視覺模型ResNet-50
    微軟在2月3日公開了其視覺模型ResNet-50,該模型是微軟必應的多媒體組創建的一個大型預訓練視覺模型,利用搜尋引擎的網絡尺度圖像數據建立,以便為其圖像搜索和視覺搜索提供動力
  • 使用Detectron2分6步進行目標檢測
    然而,重要的是我們需要從頭開始構建一個模型,以理解其背後的數學原理。如果我們想使用自定義數據集快速訓練對象檢測模型,Detectron 2就可以提供幫助。Detectron 2庫的模型庫中存在的所有模型都在COCO Dataset上進行了預訓練。我們只需要在預先訓練的模型上微調我們的自定義數據集。Detectron 2完全重寫了2018年發布的第一款Detectron。
  • 超讚,以QA形式對NLP預訓練模型進行的全面總結!
    2020年3月18日,邱錫鵬老師發表了關於NLP預訓練模型的綜述《Pre-trained Models for Natural Language Processing: A Survey》,這是一篇全面的綜述,系統地對PTMs進行了歸納分類。本文以此篇綜述論文為主要參考,通過借鑑不同的歸納方法進行總結,以QA形式對PTMs進行全面總結歸納。
  • 輕鬆學Pytorch – 行人檢測Mask-RCNN模型訓練與使用
    這裡使用的預訓練模型是ResNet50作為backbone網絡,實現模型的參數微調遷移學習。輸入的數據是RGB三通道的,取值範圍rescale到0~1之間。關於模型本身的解釋請看這裡:輕鬆學Pytorch –Mask-RCNN圖像實例分割數據集地址下載地址:總計170張圖像,345個標籤行人,數據集採集自兩所大學校園。
  • torchserve來進行PyTorch模型的部署
    >為了展示torchserve,我們將提供一個經過全面訓練的ResNet34進行圖像分類的服務。對於在ImageNet上訓練的模型來說,這是一個經典的預處理步驟。要進行打包,首先需要導出經過訓練的模型。導出模型有三種方法可以導出torchserve的模型。到目前為止,我發現的最好的方法是trace模型並存儲結果。這樣我們就不需要向torchserve添加任何額外的文件。
  • 輕鬆學 Pytorch:行人檢測 Mask-RCNN 模型訓練與使用
    這裡使用的預訓練模型是ResNet50作為backbone網絡,實現模型的參數微調遷移學習。輸入的數據是RGB三通道的,取值範圍rescale到0~1之間。關於模型本身的解釋請看這裡:輕鬆學Pytorch –Mask-RCNN圖像實例分割數據集地址下載地址:總計170張圖像,345個標籤行人,數據集採集自兩所大學校園。
  • 訓練模型並驗證(CIFAR10數據集)
    是一個擁有十個分類的模型。本期我們進行一次完整的模型並測試。(huaji, "huaji_{}.pth".format(i)) print("模型已保存")writer.close()使用GPU會大大提升模型的訓練速度,我們這裡就是用GPU進行訓練,如果你的PC上無法使用GPU,可以將代碼第10行的參數改為CPU。
  • 使用PyTorch微調ALBERT中文預訓練模型
    ALBERT簡介    通常情況下,增加預訓練模型大小會帶來效果的提升;然而,當模型大小達到一定的程度之後,就很難再進行了,因為受到了GPU內存和訓練時間的限制
  • pytorch中文語言模型bert預訓練代碼
    這篇論文做了很多語言模型預訓練的實驗,系統的分析了語言模型預訓練對子任務的效果提升情況。有幾個主要結論:在目標領域的數據集上繼續預訓練(DAPT)可以提升效果;目標領域的語料與RoBERTa的原始預訓練語料越不相關,DAPT效果則提升更明顯。在具體任務的數據集上繼續預訓練(TAPT)可以十分「廉價」地提升效果。
  • 劍指TensorFlow,PyTorch Hub官方模型庫一行代碼復現主流模型
    它同時內置支持 Colab,集成 Papers With Code 網站,並已經有廣泛的一套預訓練模型,包括分類器、分割器、生成器和 Transformer 等等。研究者發布模型PyTorch Hub 支持在 GitHub 上發布預訓練模型(定義模型結構和預訓練權重),這只需要增加一個簡單的 hubconf.py 文件。
  • NLP集大成之預訓練模型綜述
    論文主要分四個內容:語言表示學習的進程,預訓練模型的分類,使用預訓練模型處理下遊任務,以及未來的研究方向。背景知識語言表示學習語言表示學習的核心思想是:使用低維實數向量對詞語進行分布式表示。主要有兩種形式:靜態表示(非上下文依賴的),動態表示(上下文依賴的),如下圖所示:
  • 如何使用TensorRT對訓練好的PyTorch模型進行加速?
    一.簡介TensorRT是Nvidia公司出的能加速模型推理的框架,其實就是讓你訓練的模型在測試階段的速度加快,比如你的模型測試一張圖片的速度是50ms,那麼用tensorRT加速的話,可能只需要10ms。當然具體能加速多少也不能保證,反正確實速度能提升不少。
  • PTMs:NLP預訓練模型
    2020年3月18日,邱錫鵬老師發表了關於NLP預訓練模型的綜述《Pre-trained Models for Natural Language Processing: A Survey》[1],這是一篇全面的綜述,系統地對PTMs進行了歸納分類。
  • 哈工大訊飛聯合實驗室發布中文ELECTRA預訓練模型
    由谷歌與史丹福大學共同研發的最新預訓練模型ELECTRA因其小巧的模型體積以及良好的模型性能受到了廣泛關注。
  • [Pytorch]教程-使用 PyTorch 進行 Faster R-CNN 目標檢測
    使用 PyTorch 加載Faster R-CNN模型進行目標檢測4. Faster R-CNN模型在CPU|GPU上推理時間比較1.使用PyTorch加載Faster R-CNN模型進行目標檢測接下來,我們將 Faster R-CNN 目標檢測器與 PyTorch 結合使用,其中 PyTorch|Torchvision 中包含了預訓練模型,PyTorch 中預訓練模型詳細信息可在 PyTorch 官網 torchvison.models 中找到。
  • 哈工大訊飛聯合實驗室發布中文RoBERTa-large預訓練模型
    預訓練模型已成為現階段自然語言處理領域中不可或缺的資源。