[PYTHON] [PyTorch Tutorial ⑧] Tutorial zur Feinabstimmung der Erkennung von Fackelsichtobjekten

Einführung

Dies ist die 8. Ausgabe von PyTorch Official Tutorial nach Last time. Dieses Mal fahren wir mit dem [TorchVision Object Detection Finetuning Tutorial] fort (https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html).

TorchVision Object Detection Finetuning Tutorial

In diesem Tutorial verwenden wir die vorgefertigte Maske R-CNN, um die Feinabstimmung und das Transferlernen zu sehen. Die für das Training verwendeten Daten sind Penn-Fudan-Daten zur Erkennung und Segmentierung von Fußgängern. Für diese Daten werden 170 Bilder mit 345 Fußgängern (Instanzen) erstellt.

Zunächst müssen Sie die pycocotools-Bibliothek installieren. Diese Bibliothek wird verwendet, um eine Bewertung mit dem Namen "Intersection over Union" zu berechnen. "Kreuzung über Union" ist eine der Methoden zur Bewertung des Übereinstimmungszustands von Bereichen bei der Objekterkennung.

%%shell

pip install cython
#Installieren Sie pycocotools. Die Standardversion von Colab ist https://github.com/cocodataset/cocoapi/pull/In 354 wurde ein Fehler behoben.
pip install -U 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'

Datensatz definieren

Definieren Sie den Datensatz.

Erforderliche Daten mithilfe von Torchvision-Skript (Objekterkennung, Instanzsegmentierung, Personenschlüsselpunkterkennungsbibliothek) Sie können einen Satz erstellen.

Der Datensatz erfordert die folgenden Attribute:

Schreiben eines benutzerdefinierten Datensatzes für Penn-Fudan (Erstellen eines benutzerdefinierten Datensatzes für Penn-Fudan)

Lassen Sie uns den Datensatz des Penn-Fudan-Datensatzes ausgeben. Zuerst, https://www.cis.upenn.edu/~jshi/ped_html/PennFudanPed.zip Laden Sie die Zip-Datei herunter und entpacken Sie sie.

%%shell

# download the Penn-Fudan dataset
wget https://www.cis.upenn.edu/~jshi/ped_html/PennFudanPed.zip .
# extract it in the current folder
unzip PennFudanPed.zip

Die Daten haben die folgende Struktur.

PennFudanPed/
  PedMasks/
    FudanPed00001_mask.png
    FudanPed00002_mask.png
    FudanPed00003_mask.png
    FudanPed00004_mask.png
    ...
  PNGImages/
    FudanPed00001.png
    FudanPed00002.png
    FudanPed00003.png
    FudanPed00004.png

Lassen Sie uns das erste Bild anzeigen.

from PIL import Image
Image.open('PennFudanPed/PNGImages/FudanPed00001.png')

ダウンロード.png

(Wie in der entpackten readme.txt beschrieben, ist das Maskenbild ein Bild mit einem Hintergrund von "0" und einer Bezeichnung von 1 oder mehr für jeden Fußgänger.)

mask = Image.open('PennFudanPed/PedMasks/FudanPed00001_mask.png')
#Jede Maskeninstanz hat eine andere Farbe von Null bis N.
#Wobei N die Anzahl der Instanzen (Fußgänger) ist. Zur Erleichterung der Visualisierung
#Fügen wir der Maske eine Farbpalette hinzu.
mask.putpalette([
    0, 0, 0, # black background
    255, 0, 0, # index 1 is red
    255, 255, 0, # index 2 is yellow
    255, 153, 0, # index 3 is orange
])
mask

ダウンロード.png

Diese Daten haben eine Maske, die jedes Bild und jeden Fußgänger identifiziert, und jede Farbe der Maske entspricht einem einzelnen Fußgänger. Erstellen wir die Klasse torch.utils.data.Dataset für dieses Dataset.

import os
import numpy as np
import torch
import torch.utils.data
from PIL import Image


class PennFudanDataset(torch.utils.data.Dataset):
    def __init__(self, root, transforms=None):
        self.root = root
        self.transforms = transforms
        #Laden und sortieren Sie alle Bilddateien
        self.imgs = list(sorted(os.listdir(os.path.join(root, "PNGImages"))))
        self.masks = list(sorted(os.listdir(os.path.join(root, "PedMasks"))))

    def __getitem__(self, idx):
        #Laden Sie Bilder und Masken
        img_path = os.path.join(self.root, "PNGImages", self.imgs[idx])
        mask_path = os.path.join(self.root, "PedMasks", self.masks[idx])
        img = Image.open(img_path).convert("RGB")
        #Weil jede Farbe einer anderen Instanz entspricht und 0 der Hintergrund ist
        #Beachten Sie, dass wir die Maske nicht in RGB konvertiert haben
        mask = Image.open(mask_path)

        mask = np.array(mask)
        #Instanzen werden in verschiedenen Farben codiert
        obj_ids = np.unique(mask)
        #Die erste ID ist der Hintergrund. Löschen Sie sie daher
        obj_ids = obj_ids[1:]

        # split the color-encoded mask into a set
        # of binary masks
        #Teilen Sie die farbcodierte Maske in eine Reihe von Binärmasken
        masks = mask == obj_ids[:, None, None]

        # get bounding box coordinates for each mask
        #Holen Sie sich die Begrenzungsrahmenkoordinaten für jede Maske
        num_objs = len(obj_ids)
        boxes = []
        for i in range(num_objs):
            pos = np.where(masks[i])
            xmin = np.min(pos[1])
            xmax = np.max(pos[1])
            ymin = np.min(pos[0])
            ymax = np.max(pos[0])
            boxes.append([xmin, ymin, xmax, ymax])

        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        # there is only one class
        #Es gibt nur eine Klasse
        labels = torch.ones((num_objs,), dtype=torch.int64)
        masks = torch.as_tensor(masks, dtype=torch.uint8)

        image_id = torch.tensor([idx])
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        # suppose all instances are not crowd
        #Angenommen, nicht alle Instanzen sind überlastet
        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)

        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["masks"] = masks
        target["image_id"] = image_id
        target["area"] = area
        target["iscrowd"] = iscrowd

        if self.transforms is not None:
            img, target = self.transforms(img, target)

        return img, target

    def __len__(self):
        return len(self.imgs)

Das war's für den Datensatz. Mal sehen, wie die Ausgabe dieses Datasets organisiert ist

dataset = PennFudanDataset('PennFudanPed/')
dataset[0]

out


(<PIL.Image.Image image mode=RGB size=559x536 at 0x7FC7AC4B62E8>,
 {'area': tensor([35358., 36225.]), 'boxes': tensor([[159., 181., 301., 430.],
          [419., 170., 534., 485.]]), 'image_id': tensor([0]), 'iscrowd': tensor([0, 0]), 'labels': tensor([1, 1]), 'masks': tensor([[[0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           ...,
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0]],
  
          [[0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           ...,
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0]]], dtype=torch.uint8)})

Sie können sehen, dass das Dataset PIL.Image und ein Wörterbuch zurückgibt, das einige Felder wie "Boxen", "Beschriftungen", "Masken" enthält.

Obwohl nicht im Lernprogramm enthalten, kann der folgende Code Felder und Masken veranschaulichen. Kästchen sind Quadrate, die Instanzen (Personen) enthalten, und Masken sind die Instanzen selbst.

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig, ax = plt.subplots()

target = dataset[0][1]

#Erstinstanzmasken
masks_0 = target['masks'][0,:,:]

#Boxen der ersten Instanz
boxes_0 = target['boxes'][0]

#Ausgabemaske
ax.imshow(masks_0)

#Ausgabeboxen
ax.add_patch(
     patches.Rectangle(
        (boxes_0[0], boxes_0[1]),boxes_0[2] - boxes_0[0], boxes_0[3] - boxes_0[1],
        edgecolor = 'blue',
        facecolor = 'red',
        fill=True,
        alpha=0.5
     ) )

plt.show()

ダウンロード.png

Defining your model

Dieses Tutorial verwendet MaskR-CNN, das auf FasterR-CNN basiert. Schnelleres R-CNN ist einer der Objekterkennungsalgorithmen. Hierbei handelt es sich um ein Modell, das sowohl die Grenzbox als auch die Klassenbewertung (das Quadrat, das das Objekt enthält und was das Objekt ist) der potenziellen Objekte im Bild vorhersagt. (Das Bild unten ist ein verarbeitetes Bild von Faster R-CNN.)

Faster R-CNN

Die Maske R-CNN ist eine verbesserte Version von Faster R-CNN, die die Objekterkennung nicht nur nach Quadrat (Kästchen), sondern auch nach Pixeleinheit (Maske) beurteilt. (Das Bild unten ist ein verarbeitetes Bild der Maske R-CNN.)

Mask R-CNN

Es gibt zwei Hauptgründe für die Anpassung eines Modells mit Fackelvision. Die erste besteht darin, ein vorab trainiertes Modell zu nutzen und die letzte Ebene zu optimieren. Das andere ist, wenn Sie das Backbone Ihres Modells durch ein anderes Backbone ersetzen möchten. (Zum Beispiel für eine schnellere Vorhersage) Nehmen wir ein konkretes Beispiel.

1. Feinabstimmung von einem vorab trainierten Modell

Hier erfahren Sie, wie Sie das vorab trainierte Modell nutzen und es auf die Klasse abstimmen können, die Sie identifizieren möchten.

import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor

#Laden Sie vorgefertigte Modelle bei COCO
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)

#Klassifikator, benutzerdefinierte Nummer_Durch einen neuen Klassifikator durch Klassen ersetzen
num_classes = 2  # 1 class (person) + background :1 Klasse (Person)+Hintergrund
#Ruft die Anzahl der Eingabefunktionen des Klassifikators ab
in_features = model.roi_heads.box_predictor.cls_score.in_features
#Ersetzen Sie den vorgefertigten KOPF durch einen neuen
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes) 

2. Ändern des Modells, um ein anderes Backbone hinzuzufügen (Ändern Sie das Modell, um ein anderes Backbone hinzuzufügen)

Der andere Fall ist, wenn Sie das Modell-Backbone durch ein anderes Backbone ersetzen möchten. Beispielsweise kann das aktuelle Standard-Backbone (ResNet-50) in einigen Situationen zu groß sein, und Sie möchten möglicherweise ein kleineres Modell nutzen. Im Folgenden wird beschrieben, wie Sie mit Torchvision das Backbone ändern.

import torchvision
from torchvision.models.detection import FasterRCNN
from torchvision.models.detection.rpn import AnchorGenerator

#Lädt ein vorab trainiertes Modell zur Klassifizierung und gibt nur Features zurück
backbone = torchvision.models.mobilenet_v2(pretrained=True).features
#FasterRCNN muss die Anzahl der Ausgangskanäle im Backbone kennen.
# mobilenet_Für v2 ist es 1280, also müssen Sie es hier hinzufügen
backbone.out_channels = 1280

#In RPN mit 5 verschiedenen Größen und 3 verschiedenen Seitenverhältnissen
#Lassen Sie uns 5 x 3 Anker für jede räumliche Position generieren.
#Weil die Größe und das Seitenverhältnis jeder Feature-Map unterschiedlich sein können
# Tuple [Tuple [int]]es gibt.
anchor_generator = AnchorGenerator(sizes=((32, 64, 128, 256, 512),),
                                   aspect_ratios=((0.5, 1.0, 2.0),))

#Mit der Feature-Map, die zum Trimmen des interessierenden Bereichs verwendet wird,
#Definieren wir die Größe der Trimmung nach der Neuskalierung.
#Wenn das Backbone Tensor zurückgibt, featmap_Namen ist[0]Wird voraussichtlich sein.
#Im Allgemeinen ist das Backbone OrderedDict[Tensor]Muss zurückgegeben werden,
# featmap_Sie können die Feature-Map auswählen, die mit Namen verwendet werden soll.
roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=[0],
                                                output_size=7,
                                                sampling_ratio=2)

#Fügen Sie die Teile zu einem schnelleren RCNN-Modell zusammen
model = FasterRCNN(backbone,
                   num_classes=2,
                   rpn_anchor_generator=anchor_generator,
                   box_roi_pool=roi_pooler)

Ein Instanzsegmentierungsmodell für PennFudan-Dataset (PennFudan-Dataset-Instanzsegmentierungsmodell)

In diesem Fall ist der Datensatz sehr klein, daher werden wir das vorab trainierte Modell optimieren. Folgen Sie daher Ansatz Nummer 1. Wir werden hier die Maske R-CNN verwenden, um auch die Segmentierungsmaske für die Instanz zu berechnen (um den Bereich der Person in Pixel zu bestimmen).

import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor

      
def get_instance_segmentation_model(num_classes):
    #Laden Sie ein vorab trainiertes COCO-Instanzsegmentierungsmodell
    model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)

    #Ruft die Anzahl der Eingabefunktionen des Klassifikators ab
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    #Ersetzen Sie den vorgefertigten KOPF durch einen neuen
    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)

    #mask Ruft die Anzahl der Eingabefunktionen des Klassifikators ab
    in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels
    hidden_layer = 256
    # and replace the mask predictor with a new one
    #Ersetzen Sie den Maskenprädiktor durch einen neuen
    model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask,
                                                       hidden_layer,
                                                       num_classes)

    return model

Jetzt können Sie Ihr Modell mit diesem Datensatz trainieren und bewerten.

(Wenn Sie dieses Modell mit torchvision.models.detection.maskrcnn_resnet50_fpn vergleichen, können Sie feststellen, dass sich die Abmessungen der folgenden Teile geändert haben.)

  (roi_heads): RoIHeads(
・ ・ ・
    (box_predictor): FastRCNNPredictor(
      (cls_score): Linear(in_features=1024, out_features=2, bias=True)
      (bbox_pred): Linear(in_features=1024, out_features=8, bias=True)
    )
・ ・ ・
    (mask_predictor): MaskRCNNPredictor(
・ ・ ・
      (mask_fcn_logits): Conv2d(256, 2, kernel_size=(1, 1), stride=(1, 1))
    )
  )

Schulungs- und Bewertungsfunktionen

Die Fackelvision "Vision / Referenzen / Erkennung /" verfügt über eine Reihe von Hilfsfunktionen, um das Training und die Bewertung von Objekterkennungsmodellen zu vereinfachen. Hier verwenden wir "Referenzen / Erkennung / engine.py", "Referenzen / Erkennung / utils.py", "Referenzen / Erkennung / transforms.py".

Kopieren Sie diese Dateien (und die zugehörigen Dateien) zur Verwendung.

%%shell

# Download TorchVision repo to use some files from
# references/detection
git clone https://github.com/pytorch/vision.git
cd vision
git checkout v0.3.0

cp references/detection/utils.py ../
cp references/detection/transforms.py ../
cp references/detection/coco_eval.py ../
cp references/detection/engine.py ../
cp references/detection/coco_utils.py ../

Verwenden wir die kopierten "Referenzen / Erkennung", um einige Hilfsfunktionen zum Erweitern / Transformieren von Daten zu erstellen.

from engine import train_one_epoch, evaluate
import utils
import transforms as T


def get_transform(train):
    transforms = []
    #Bild in Tensor konvertieren
    transforms.append(T.ToTensor())
    if train:
        #Für das Training werden die Bild- und Lehrerdaten zufällig horizontal gespiegelt. (Bild im Spiegel reflektiert)
        transforms.append(T.RandomHorizontalFlip(0.5))
    return T.Compose(transforms)

Der obige Code ist die Aufbereitung der Daten. Konvertiert das Bild in Tensor und invertiert es zufällig für Trainingsdaten. Es ist keine Datenstandardisierung oder Bildskalierung erforderlich. Das Mask R-CNN-Modell erledigt dies intern.

Alles zusammenfügen

Der Datensatz, das Modell und die Datenaufbereitung sind jetzt fertig. Lassen Sie uns sie instanziieren.

#Verwendet einen Datensatz und definierte Transformationen
dataset = PennFudanDataset('PennFudanPed', get_transform(train=True))
dataset_test = PennFudanDataset('PennFudanPed', get_transform(train=False))

#Teilen Sie den Datensatz in Trainingsdaten und Testdaten
torch.manual_seed(1)
indices = torch.randperm(len(dataset)).tolist()
dataset = torch.utils.data.Subset(dataset, indices[:-50])
dataset_test = torch.utils.data.Subset(dataset_test, indices[-50:])

#Definieren Sie einen Trainings- und Validierungsdatenlader
data_loader = torch.utils.data.DataLoader(
    dataset, batch_size=2, shuffle=True, num_workers=4,
    collate_fn=utils.collate_fn)

data_loader_test = torch.utils.data.DataLoader(
    dataset_test, batch_size=1, shuffle=False, num_workers=4,
    collate_fn=utils.collate_fn)

Instanziieren Sie das Modell.

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

#Lehrerdaten sind nur zwei Klassen, Hintergrund und Person
num_classes = 2

#Holen Sie sich das Modell mit der Hilfsfunktion
model = get_instance_segmentation_model(num_classes)
#Bewegen Sie das Modell auf das entsprechende Gerät
model.to(device)

#Erstellen Sie den Optimierer
params = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.SGD(params, lr=0.005,
                            momentum=0.9, weight_decay=0.0005)

#Lernratenplaner, der die Lernrate alle 3 Epochen auf 1/10 reduziert
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
                                               step_size=3,
                                               gamma=0.1)

Trainiere mit 10 Epochen. Evaluieren Sie mit der Evaluierungsfunktion in jeder Epoche. (Das Erlernen der Colaboratory GPU-Umgebung dauert ca. 8 Minuten. In der None GPU tritt ein Laufzeitfehler auf.)

#Training mit 10 Epochen
num_epochs = 10

for epoch in range(num_epochs):
    print(epoch)
    #1 Epochentraining
    train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq=10)
    #Lernrate aktualisieren
    lr_scheduler.step()
    #Mit Testdatensatz auswerten
    evaluate(model, data_loader_test, device=device)

out


...
Averaged stats: model_time: 0.1179 (0.1174)  evaluator_time: 0.0033 (0.0051)
Accumulating evaluation results...
DONE (t=0.01s).
Accumulating evaluation results...
DONE (t=0.01s).
IoU metric: bbox
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.831
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.990
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.955
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.543
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.841
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.386
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.881
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.881
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.787
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.887
IoU metric: segm
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.760
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.990
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.921
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.492
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.771
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.345
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.808
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.808
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.725
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.814

Nachdem das Training beendet ist, wollen wir sehen, wie der Testdatensatz aussehen wird.

#Wählen Sie ein Bild aus dem Testsatz aus
img, _ = dataset_test[4]
#Versetzen Sie das Modell in den Bewertungsmodus
model.eval()
with torch.no_grad():
    prediction = model([img.to(device)])

Wenn Sie die Vorhersage ausgeben, handelt es sich um eine Liste von Wörterbüchern. Da wir eine Testdaten angegeben haben, enthält das folgende Beispiel ein Element in der Liste. Das Wörterbuch enthält Bildvorhersagen. In diesem Fall sehen Sie, dass es Felder, Beschriftungen, Masken und Partituren enthält.

prediction

out


[{'boxes': tensor([[173.1167,  27.6446, 240.8375, 313.0114],
          [325.5737,  64.3967, 453.1539, 352.3020],
          [222.4494,  24.5255, 306.5306, 291.5595],
          [296.8205,  21.3736, 379.0592, 263.7513],
          [137.4137,  38.1588, 216.4886, 276.1431],
          [167.8121,  19.9211, 332.5648, 314.0146]], device='cuda:0'),
  'labels': tensor([1, 1, 1, 1, 1, 1], device='cuda:0'),
  'masks': tensor([[[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]],
  
  
          [[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]],
  
  
          [[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]],
  
  
          [[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]],
  
  
          [[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]],
  
  
          [[[0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            ...,
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.],
            [0., 0., 0.,  ..., 0., 0., 0.]]]], device='cuda:0'),
  'scores': tensor([0.9965, 0.9964, 0.9942, 0.9696, 0.3053, 0.1552], device='cuda:0')}]

Überprüfen Sie das Bild und das Vorhersageergebnis. Das Bild (img) ist ein Tensor von [Farbe, vertikal, horizontal]. Da die Farbe 0-1 ist, skalieren Sie sie auf 0-255 und ersetzen Sie sie durch [Vertikal, Horizontal, Farbe].

Image.fromarray(img.mul(255).permute(1, 2, 0).byte().numpy())

ダウンロード.png

Visualisieren Sie als Nächstes die vorhergesagte Maske. Masken werden als "[N, 1, H, W]" erwartet. Wobei "N" die vorhergesagte Anzahl von Instanzen (Personen) ist. Jeder Wert der Maske speichert die Wahrscheinlichkeit, "Person" in Pixeln zu bestimmen, als 0-1.

Image.fromarray(prediction[0]['masks'][0, 0].mul(255).byte().cpu().numpy())

ダウンロード.png

(Andere vorhergesagte Instanzen (Personen) können auch durch Ändern des Werts von N wie unten gezeigt visualisiert werden.)

Image.fromarray(prediction[0]['masks'][1, 0].mul(255).byte().cpu().numpy())

ダウンロード.png

Image.fromarray(prediction[0]['masks'][2, 0].mul(255).byte().cpu().numpy())

ダウンロード.png

Image.fromarray(prediction[0]['masks'][3, 0].mul(255).byte().cpu().numpy())

ダウンロード.png

Ich kann es gut vorhersagen.

Zusammenfassung (Zusammenfassung)

In diesem Lernprogramm haben Sie gelernt, wie Sie ein Objekterkennungsmodell anhand eines von Ihnen selbst definierten Datensatzes trainieren. Für das Dataset haben wir die Klasse "torch.utils.data.Dataset" erstellt, die das Feld und die Maske enthält, um das für die Objekterkennung spezifische Dataset zu definieren. Wir haben auch das auf COCOtrain 2017 vorab trainierte MaskR-CNN-Modell genutzt, um Transferlernen für diesen neuen Datensatz durchzuführen.

Ausführlichere Beispiele für das Training mit mehreren Maschinen / GPUs finden Sie unter Referenzen / Erkennung / Zug unter torchvision GitHub repo. Überprüfen Sie die .py.

Am Ende

In diesem Tutorial haben Sie anhand eines vorab trainierten Modells "Transferlernen" und "Feinabstimmung" gelernt. (Dieses Mal wird es anscheinend als Feinabstimmung bezeichnet, und der Unterschied zwischen Transferlernen und Feinabstimmung wird beim nächsten Mal erklärt.) Im Tutorial habe ich es mit 120 Trainingsdaten und 50 Verifizierungsdaten versucht, aber selbst mit ungefähr 40 Trainingsdaten konnte ich ziemlich richtig vorhersagen. Transferlernen ist erstaunlich, um mit so wenig Testdaten lernen zu können. Das nächste Mal möchte ich mit "Lernprogramm für Computer Vision übertragen" fortfahren.

Geschichte

2020/11/15 Erste Ausgabe veröffentlicht

Recommended Posts

[PyTorch Tutorial ⑧] Tutorial zur Feinabstimmung der Erkennung von Fackelsichtobjekten
Computer Vision: Objekterkennung - Nicht maximale Unterdrückung
Computer Vision: Objekterkennung Part2-Single Shot Multi Detector
Computer Vision: Objekterkennung Teil 1 - Bounding Box-Vorverarbeitung
[PyTorch Tutorial ①] Was ist PyTorch?