kdc
@kdc

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

PytorchによるSegmentation modelの学習時にGPUが使用されない

Segmentation modelの学習時にGPUが使用されない

初心者です。下記を参考に、マルチクラスのセグメンテーションの実装を試みています。
モデルの学習までは実行できたのですが、GPUではなくCPUが使用されるため一向に終了しません。GPUを使用する方法を教えていただきたいです。

発生している問題

下記を実行すると膨大な時間がかかります。

max_lr = 1e-3
epoch = 100
weight_decay = 1e-4

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=max_lr, weight_decay=weight_decay)
sched = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, epochs=epoch,
                                            steps_per_epoch=len(train_loader))

history = fit(epoch, model, train_loader, valid_loader, criterion, optimizer, sched)

問題箇所直前の処理

下記を実行してもエラーは生じませんが、ここに元凶があると考えています。

def get_lr(optimizer):
    for param_group in optimizer.param_groups:
        return param_group['lr']

def fit(epochs, model, train_loader, val_loader, criterion, optimizer, scheduler, patch=False):
    torch.cuda.empty_cache()
    train_losses = []
    test_losses = []
    val_iou = []; val_acc = []
    train_iou = []; train_acc = []
    lrs = []
    min_loss = np.inf
    decrease = 1 ; not_improve=0

    model.to(device)
    fit_time = time.time()
    for e in range(epochs):
        since = time.time()
        running_loss = 0
        iou_score = 0
        accuracy = 0
        #training loop
        model.train()
        for i, data in enumerate(tqdm(train_loader)):
            #training phase
            image_tiles, mask_tiles = data
            if patch:
                bs, n_tiles, c, h, w = image_tiles.size()

                image_tiles = image_tiles.view(-1, c, h, w)
                mask_tiles = mask_tiles.view(-1, h, w)
            
            image = image_tiles.to(device); mask = mask_tiles.to(device); 

            #forward
            output = model(image)
            loss = criterion(output, mask)
            #evaluation metrics
            iou_score += mIoU(output, mask)
            accuracy += pixel_accuracy(output, mask)
            #backward
            loss.backward()
            optimizer.step() #update weight          
            optimizer.zero_grad() #reset gradient
            
            #step the learning rate
            lrs.append(get_lr(optimizer))
            scheduler.step() 
            
            running_loss += loss.item()
            
        else:
            model.eval()
            test_loss = 0
            test_accuracy = 0
            val_iou_score = 0
            #validation loop
            with torch.no_grad():
                for i, data in enumerate(tqdm(val_loader)):
                    #reshape to 9 patches from single image, delete batch size
                    image_tiles, mask_tiles = data

                    if patch:
                        bs, n_tiles, c, h, w = image_tiles.size()

                        image_tiles = image_tiles.view(-1,c, h, w)
                        mask_tiles = mask_tiles.view(-1, h, w)
                    
                    image = image_tiles.to(device); mask = mask_tiles.to(device); 
                    output = model(image)
                    #evaluation metrics
                    val_iou_score +=  mIoU(output, mask)
                    test_accuracy += pixel_accuracy(output, mask)
                    #loss
                    loss = criterion(output, mask)                                  
                    test_loss += loss.item()
            
            #calculatio mean for each batch
            train_losses.append(running_loss/len(train_loader))
            test_losses.append(test_loss/len(val_loader))


            if min_loss > (test_loss/len(val_loader)):
                print('Loss Decreasing.. {:.3f} >> {:.3f} '.format(min_loss, (test_loss/len(val_loader))))
                min_loss = (test_loss/len(val_loader))
                decrease += 1
                if decrease % 5 == 0:
                    print('saving model...')
                    #torch.save(model, 'Unet-_mIoU-{:.3f}.pt'.format(val_iou_score/len(val_loader))) #Train途中もモデルを保存するときは実行する
                    

            if (test_loss/len(val_loader)) > min_loss:
                not_improve += 1
                min_loss = (test_loss/len(val_loader))
                print(f'Loss Not Decrease for {not_improve} time')
                if not_improve == 20:
                    print('Loss not decrease for 20 times, Stop Training')
                    break
            
            #iou
            val_iou.append(val_iou_score/len(val_loader))
            train_iou.append(iou_score/len(train_loader))
            train_acc.append(accuracy/len(train_loader))
            val_acc.append(test_accuracy/ len(val_loader))
            print("Epoch:{}/{}..".format(e+1, epochs),
                  "Train Loss: {:.3f}..".format(running_loss/len(train_loader)),
                  "Val Loss: {:.3f}..".format(test_loss/len(val_loader)),
                  "Train mIoU:{:.3f}..".format(iou_score/len(train_loader)),
                  "Val mIoU: {:.3f}..".format(val_iou_score/len(val_loader)),
                  "Train Acc:{:.3f}..".format(accuracy/len(train_loader)),
                  "Val Acc:{:.3f}..".format(test_accuracy/len(val_loader)),
                  "Time: {:.2f}m".format((time.time()-since)/60))
        
    history = {'train_loss' : train_losses, 'val_loss': test_losses,
               'train_miou' :train_iou, 'val_miou':val_iou,
               'train_acc' :train_acc, 'val_acc':val_acc,
               'lrs': lrs}
    print('Total time: {:.2f} m' .format((time.time()- fit_time)/60))
    return history

下記は冒頭で実行済みです。

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from torch.utils.data import Dataset as BaseDataset
from torchvision import transforms as T
import torchvision
import torch.nn.functional as F
from torch.autograd import Variable

import time
import os
from tqdm.notebook import tqdm

from torch.utils.data import Dataset as BaseDataset
import segmentation_models_pytorch as smp

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

自分で試したこと

import torch

if torch.cuda.is_available():
    print("Number of GPUs available:", torch.cuda.device_count())
else:
    print("CUDA is not available. GPU is not being used.")

print(device) 
print(image.device) 
print(mask.device) 
print(len(train_loader)) 

上記を実行すると、以下のように表示されることから、
image = image_tiles.to(device); mask = mask_tiles.to(device);
あたりが原因かと予想しています。

Number of GPUs available: 1

cuda
cpu
cpu
10
0

2Answer

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
この下で
print(device)
したらCUDAって出ますか?

0Like

Comments

  1. @kdc

    Questioner

    ご回答ありがとうございます。cudaと表示されます。

  2. この学習を知らないので、どうかがわかりませんが、imageとmaskを毎回GPUに送り込むから遅い、ということはないですか?
    仕組み上、そういうもんです、と言われるとそうですか、なんですが。

    またいまコードを試せる環境にないので言いにくいですが、可能であればコードは全文を繋げて記載頂いた方がいいと思います。

  3. @kdc

    Questioner

    参考にしていた記事では、学習時間は12分ほどとのことでしたが、私の方では12分経過後も進捗表示が0%のままでした。以下の項目を踏まえ、今回の実装に何らかの問題があるのではないかと考えております。
    ・タスクマネージャーのGPU使用率が常に0~2%であること
    ・使用しているGPU (RTX4070 Ti super) が参考記事 (RTE3080) に極端に劣っているわけではないこと
    ・各データセットにおける画像枚数を少なくしていること

    また、記載コードに関しまして、不勉強で申し訳ございません。Pythonを始めたばかりで、参考にしたコードのどの範囲までが本問題に関係しているのか理解が及んでおりません。全文をつなぎ合わせるにあたっても、まずは勉強いたします。取り急ぎ、自前の画像にclass等を合わせる以外は、以下リンクのコードをほぼそのまま使用しております。
    https://github.com/shirokawakita/multiclass-segmentation/blob/main/example_camvid_multiclassC2_quita.ipynb

  1. image = image_tiles.to(device); mask = mask_tiles.to(device); の直前に print(device) するとどうなる?

  2. 実行時にエラーではないけど、警告とかって出てる?

  3. image = image_tiles.to(device); mask = mask_tiles.to(device); の直後に print(image.device) するとどうなる?

0Like

Comments

  1. @kdc

    Questioner

    1, 3. 両者とも何も表記されません。処理はエラーや警告等なく完了します。
    2. エラーも警告も出ません。以下の写真のまま時間だけが経過します。
    segmentation model no-GPU.png

  2. 表示されないわけがないです。
    入れる箇所が間違っているか、入っていないかです。
    もう一度よく確認したうえで試してください。

    2番については承知しました。
    たぶんCPU上ではありますが、正常に学習が進んでいることは確認できました。

  3. @kdc

    Questioner

    長文となり恐縮ですが、下記の通りに挿入しております。この後、前コメント記載の画像通り実施したところ、変化はありませんでした。プログレスバーが表示されないようにもしてみましたが、以前の画像の状態からプログレスバーが消えたのみであり、何も表示されるものはありませんでした。
    無知で大変申し訳ございませんが、挿入箇所等誤りがございましたら、ご指摘いただけますと幸いです。

    def fit(epochs, model, train_loader, val_loader, criterion, optimizer, scheduler, patch=False):
        torch.cuda.empty_cache()
        train_losses = []
        test_losses = []
        val_iou = []; val_acc = []
        train_iou = []; train_acc = []
        lrs = []
        min_loss = np.inf
        decrease = 1 ; not_improve=0
    
        model.to(device)
        fit_time = time.time()
        for e in range(epochs):
            since = time.time()
            running_loss = 0
            iou_score = 0
            accuracy = 0
            #training loop
            model.train()
            for i, data in enumerate(tqdm(train_loader)):
                #training phase
                image_tiles, mask_tiles = data
                if patch:
                    bs, n_tiles, c, h, w = image_tiles.size()
    
                    image_tiles = image_tiles.view(-1, c, h, w)
                    mask_tiles = mask_tiles.view(-1, h, w)
                
                print(device) #要確認
                image = image_tiles.to(device); mask = mask_tiles.to(device); 
                print(image.device) #要確認 
    
    
                #forward
                output = model(image)
                loss = criterion(output, mask)
                #evaluation metrics
                iou_score += mIoU(output, mask)
                accuracy += pixel_accuracy(output, mask)
                #backward
                loss.backward()
                optimizer.step() #update weight          
                optimizer.zero_grad() #reset gradient
                
                #step the learning rate
                lrs.append(get_lr(optimizer))
                scheduler.step() 
                
                running_loss += loss.item()
                
            else:
                model.eval()
                test_loss = 0
                test_accuracy = 0
                val_iou_score = 0
                #validation loop
                with torch.no_grad():
                    for i, data in enumerate(tqdm(val_loader)):
                        #reshape to 9 patches from single image, delete batch size
                        image_tiles, mask_tiles = data
    
                        if patch:
                            bs, n_tiles, c, h, w = image_tiles.size()
    
                            image_tiles = image_tiles.view(-1,c, h, w)
                            mask_tiles = mask_tiles.view(-1, h, w)
                        
                        print(device) #要確認
                        image = image_tiles.to(device); mask = mask_tiles.to(device); 
                        print(image.device) #要確認 
                        output = model(image)
                        #evaluation metrics
                        val_iou_score +=  mIoU(output, mask)
                        test_accuracy += pixel_accuracy(output, mask)
                        #loss
                        loss = criterion(output, mask)                                  
                        test_loss += loss.item()
                
                #calculatio mean for each batch
                train_losses.append(running_loss/len(train_loader))
                test_losses.append(test_loss/len(val_loader))
    
    
                if min_loss > (test_loss/len(val_loader)):
                    print('Loss Decreasing.. {:.3f} >> {:.3f} '.format(min_loss, (test_loss/len(val_loader))))
                    min_loss = (test_loss/len(val_loader))
                    decrease += 1
                    if decrease % 5 == 0:
                        print('saving model...')
                        #torch.save(model, 'Unet-_mIoU-{:.3f}.pt'.format(val_iou_score/len(val_loader))) #Train途中もモデルを保存するときは実行する
                        
    
                if (test_loss/len(val_loader)) > min_loss:
                    not_improve += 1
                    min_loss = (test_loss/len(val_loader))
                    print(f'Loss Not Decrease for {not_improve} time')
                    if not_improve == 20:
                        print('Loss not decrease for 20 times, Stop Training')
                        break
                
                #iou
                val_iou.append(val_iou_score/len(val_loader))
                train_iou.append(iou_score/len(train_loader))
                train_acc.append(accuracy/len(train_loader))
                val_acc.append(test_accuracy/ len(val_loader))
                print("Epoch:{}/{}..".format(e+1, epochs),
                      "Train Loss: {:.3f}..".format(running_loss/len(train_loader)),
                      "Val Loss: {:.3f}..".format(test_loss/len(val_loader)),
                      "Train mIoU:{:.3f}..".format(iou_score/len(train_loader)),
                      "Val mIoU: {:.3f}..".format(val_iou_score/len(val_loader)),
                      "Train Acc:{:.3f}..".format(accuracy/len(train_loader)),
                      "Val Acc:{:.3f}..".format(test_accuracy/len(val_loader)),
                      "Time: {:.2f}m".format((time.time()-since)/60))
            
        history = {'train_loss' : train_losses, 'val_loss': test_losses,
                   'train_miou' :train_iou, 'val_miou':val_iou,
                   'train_acc' :train_acc, 'val_acc':val_acc,
                   'lrs': lrs}
        print('Total time: {:.2f} m' .format((time.time()- fit_time)/60))
        return history
    
  4. 出ないのは、ループに入ってないからではないでしょうか
    model.train()の前後や、forやifなどのループや分岐の後にprintを入れて、どこを通っているか確認された方がいいのでは?

Your answer might help someone💌