

## 概要

PyTorchのサンプルコードを参考にした転移学習コードでtrain_one_epochが動作しません  
どのようにすれば学習が進みますでしょうか?

以下追記  
vscode上でスクリプトを実行すると、実行中を示すアイコンが出るだけで、学習の進捗やエラーメッセージは表示されません  
一方で、処理確認のために挿入したprintメッセージが、下記に添付したengine.pyの抜粋中の"start train"まで表示されることは確認済みです  
この間、CPU及びGPU使用率は10%未満です

## 詳細

PyTorchのObject Detectionに関するドキュメントを参考に、自前の画像で転移学習するコードを作成しました

<https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html>

実際に動作させるとtrain_one_epochメソッド以降処理が進まず、学習が完了しない状態となってしまいます

より詳細には、下記の箇所まで実行することを確認しております  
engin.pyより抜粋

[code]

    def train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq, scaler=None):
        print("model train")
        model.train()
    
        print("log")
        metric_logger = utils.MetricLogger(delimiter="  ")
        metric_logger.add_meter("lr", utils.SmoothedValue(window_size=1, fmt="{value:.6f}"))
        header = f"Epoch: [{epoch}]"
    
        lr_scheduler = None
        if epoch == 0:
            warmup_factor = 1.0 / 1000
            warmup_iters = min(1000, len(data_loader) - 1)
    
            lr_scheduler = torch.optim.lr_scheduler.LinearLR(
                optimizer, start_factor=warmup_factor, total_iters=warmup_iters
            )
        print("start train")
        #ここまでは実行される
        for images, targets in metric_logger.log_every(data_loader, print_freq, header):
            #ここから実行されない
            print("get images")
            images = list(image.to(device) for image in images)
            print("get targets")
            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
    
            print("calc loss")
            with torch.cuda.amp.autocast(enabled=scaler is not None):
                loss_dict = model(images, targets)
                losses = sum(loss for loss in loss_dict.values())
    
            # reduce losses over all GPUs for logging purposes
            print("reduce loss")
            loss_dict_reduced = utils.reduce_dict(loss_dict)
            losses_reduced = sum(loss for loss in loss_dict_reduced.values())
    
            print("loss value")
            loss_value = losses_reduced.item()
    
            if not math.isfinite(loss_value):
                print(f"Loss is {loss_value}, stopping training")
                print(loss_dict_reduced)
                sys.exit(1)
    
            print("optimizer calc")
            optimizer.zero_grad()
            if scaler is not None:
                scaler.scale(losses).backward()
                scaler.step(optimizer)
                scaler.update()
            else:
                losses.backward()
                optimizer.step()
    
            if lr_scheduler is not None:
                lr_scheduler.step()
    
            print("metric logger")
            metric_logger.update(loss=losses_reduced, **loss_dict_reduced)
            metric_logger.update(lr=optimizer.param_groups[0]["lr"])
    
        return metric_logger
    
[/code]

## 環境

Windows 10  
GPU: GTX 1080Ti  
Python==3.9.13  
torch==1.13.1+cu116  
torchaudio==0.13.1+cu116  
torchvision==0.14.1+cu116  
notebook==6.5.2

torch.cuda.is_available()がTrueであることは確認済みです

## コード

作成したコードを添付します  
Jupyter Notebookで作成したコードをPythonにエクスポートしております

[code]

    # %%
    from pycocotools.coco import COCO
    import os
    import numpy as np
    import torch
    from PIL import Image
    import glob
    from typing import Tuple
    
    
    # %%
    class COCODataset(torch.utils.data.Dataset):
        def __init__(self, root, transform=None) -> None:
            self.coco = COCO(os.path.join(root, "metadata.json"))
            self.images = list(glob.glob(os.path.join(root, "*.bmp")))
            self.transform = transform
    
        
        def __getitem__(self, idx: int) :
            image = Image.open(self.images[idx]).convert("RGB")
    
            obj_ids = self.coco.getAnnIds(idx)
            boxes, areas = [], []
            for obj_id in obj_ids:
                ann = self.coco.anns[obj_id]
                boxes += [ann["bbox"]]
                areas += [ann["area"]]
    
            #マスク画像がないためサンプルコードから該当処理は削除
            target = {}
            target["image_id"] = torch.tensor([idx])
            target["labels"] = torch.ones((len(obj_ids)), dtype=torch.int64)
            target["boxes"] = torch.as_tensor(boxes, dtype=torch.float32)
            target["area"] = torch.as_tensor(areas, dtype=torch.float32)
            target["iscrowd"] = torch.zeros((len(obj_ids)), dtype=torch.int64)
    
            if self.transform is not None:
                image, target = self.transform(image, target)
    
            return (image, target)
    
        def __len__(self) -> int:
            return len(self.images)
    
        def __repr__(self) -> str:
            attrs = vars(self)
            string = ", ".join("%s: %s" % item for item in attrs.items())
            return string
    
    
    # %%
    import torchvision
    from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
    
    # %%
    def get_instance_segmentation_model(num_classes):
        # load a model pre-trained pre-trained on COCO
        model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    
        # get the number of input features for the classifier
        in_features = model.roi_heads.box_predictor.cls_score.in_features
        # replace the pre-trained head with a new one
        model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
    
        return model
    
    # %%
    from engine import train_one_epoch, evaluate
    import utils
    import transforms as T
    
    def get_transform(train):
        transforms = []
        # converts the image, a PIL image, into a PyTorch Tensor
        transforms.append(T.PILToTensor())
        if train:
            # during training, randomly flip the training images
            # and ground-truth for data augmentation
            transforms.append(T.RandomHorizontalFlip(0.5))
        return T.Compose(transforms)
    
    # %%
    # use our dataset and defined transformations
    dataset_root_path = "../DataSet/train"
    dataset = COCODataset(dataset_root_path, get_transform(train=True))
    dataset_test = COCODataset(dataset_root_path, get_transform(train=False))
    
    # split the dataset in train and test set
    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:])
    
    # define training and validation data loaders
    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)
    
    # %%
    dataset[0]
    
    # %%
    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
    
    # 教師データは、背景と対象の2クラスのみです
    num_classes = 2
    
    # ヘルパー関数を使用してモデルを取得します
    model = get_instance_segmentation_model(num_classes)
    # モデルを適切なデバイスに移動します
    model.to(device)
    
    # オプティマイザを構築します
    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)
    
    # 学習率を3エポックごとに10分の1に減らす学習率スケジューラ
    lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
                                                   step_size=3,
                                                   gamma=0.1)
    
    # %%
    # let's train it for 10 epochs
    num_epochs = 10
    
    for epoch in range(num_epochs):
        # train for one epoch, printing every 10 iterations
        print("epoch start")
        train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq=10)
        # update the learning rate
        print("train done")
        lr_scheduler.step()
        # evaluate on the test dataset
        print("start evaluate")
        evaluate(model, data_loader_test, device=device)
    
[/code]


CC BY-SA 4.0
2023-02-15T02:54:53.693
93845
2023-02-15T04:12:13.707
2023-02-15T04:12:13.707
19500
19500
question
python python3 pytorch
PyTorchを使った物体検出の転移学習が動作しない