YutaroOgawa / pytorch_advanced

書籍「つくりながら学ぶ! PyTorchによる発展ディープラーニング」の実装コードを配置したリポジトリです
MIT License
843 stars 334 forks source link

[第一章 画像分類と転移学習] のVGG16モデルを自分で構築したら、以下のエラーがでました。 #116

Open Aya-2 opened 4 years ago

Aya-2 commented 4 years ago

Yutraro Ogawa さま

第一章でご紹介されていた、VGG16モデルをそのまま用いて 目的の画像を2項分類しようとしています。

VGG16は、ロードせず同じ構造になるようにコーディングしてみました。 ただし、今回は2項分類なので、出力だけノードを2にしました。 ---------------------------- 以下が実装したコードになります。 `

必要なモジュールのインポート

import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt from torch.utils.data import DataLoader from torchvision import datasets, transforms`

デバイスのチェック

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

前処理の定義

transform = transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), # ToTensorへ変換、channel firstへ transforms.Normalize((0.5,), (0.5,)) # 平均と標準偏差は0.5に ])

フォルダの中の画像をとってくる

train_dataset = datasets.ImageFolder('./train', transform = transform)

検証用データもとってくる

validation_dataset = datasets.ImageFolder('./val', transform=transform)

DataLoaderでミニバッチ作成

train_loader = DataLoader(train_dataset, batch_size=17, shuffle=True) validation_loader = DataLoader(validation_dataset, batch_size=17, shuffle=False)

モデルの定義

class CNN(nn.Module): def init(self, num_classes): # 今回はnum_classes に2を代入することになる super().init()

畳み込み層(特徴抽出層)

    self.features = nn.Sequential(
        nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1),  # kernel_size=3だと1サイズ収縮するのでpaddingで1をたす
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
        nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
        nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
        nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2, padding=0),
        nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
        nn.ReLU(inplace=True),
        nn.MaxPool2d(kernel_size=2, stride=2, padding=0),

    )

    # 望むTensorサイズを定義する
    self.avgpool = nn.AdaptiveAvgPool2d((7,7))
    # https://axa.biopapyrus.jp/deep-learning/pytorch/pytorch-vgg16.htmlを参考に↑

    """
    今回は、MaxPool2dを5回行っている。また、kernel_size=2かつ、stride=2なので
    一回のマックスプーリングごとに÷4されていく。このことから

    """

    # 全結合層
    self.classifier = nn.Sequential(
        nn.Linear(in_features=7*7*512, out_features=4096),
        nn.ReLU(inplace=True),
        nn.Dropout(p=0.5, inplace=True),
        nn.Linear(in_features=4096, out_features=4096),
        nn.ReLU(inplace=True),
        nn.Dropout(p=0.5, inplace=True),
        nn.Linear(in_features=4096, out_features=num_classes)
    )

# 順伝播
def forward(self, x):
    x = self.features(x)
    # 7x7の形状にする
    x = self.avgpool(x)
    # 畳み込み層からの出力画像(17,512,7,7)を、全結合層に入力するために次元変換する
    x = x.view(x.size(0), -1) # x.size(0):ミニバッチ数
    # 全結合層に渡す
    x = self.classifier(x)

    return x

モデルのインスタンス生成

model = CNN(2) # 今回は良品or不良品なのでnum_classes=2でいく

モデルをgpuに渡す

model.to(device)

損失関数

criterion = nn.CrossEntropyLoss()

オプティマイザ

optimizer = optim.RMSprop(model.parameters(), lr =1e-4, weight_decay=0 )

学習

エポックを決める

num_epochs = 10 losses = [] accs = [] val_losses = [] val_accs = []

for epoch in range(num_epochs): running_loss = 0.0 running_acc = 0.0 for imgs, labels in train_loader: imgs = imgs.to(device) labels = labels.to(device) optimizer.zero_grad() output = model(imgs) loss = criterion(output, labels) loss.backward() running_loss += loss.item() pred = troch.argmax(output, dim=1) running_acc += torch.mean(pred.eq(labels).float()) optimizer.step()

running_loss /= len(train_loader)
running_acc /= len(train_loader)

losses.append(running_loss)
accs.append(running_acc)

# validation loop

val_running_loss = 0.0
val_running_acc = 0.0
for val_imgs, val_labels in validation_loader:
    val_imgs = val_imgs.to(device)
    val_labels = val_labels.to(device)
    val_output = model(val_imgs)
    val_loss = criterion(val_output, val_labels)
    val_running_loss += val_loss.item()
    val_pred = torch.argmax(val_output, dim=1)
    val_running_acc += torch.mean(val_pred.eq(val_labels).float())

val_running_loss /= len(validation_loader)
val_running_acc /= len(validation_loader)

val_losses.append(val_running_loss)
val_accs.append(val_running_acc)

print("epoch: {}, loss: {}, acc: {}, \
 val loss: {}, val acc: {}".format(epoch, running_loss, running_acc, val_running_loss, val_running_acc)

` ---------------------------- その結果、、以下のエラーが出てしまいました。

`RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation:

[torch.cuda.FloatTensor [17, 4096]], which is output 0 of ReluBackward1, is at version 2; expected version 1 instead. Hint:

enable anomaly detection to find the operation that failed to compute its gradient, with

torch.autograd.set_detect_anomaly(True). ` ---------------------------- こちらのエラーについて、解決したいのですが、 もし可能でしたら教えて頂きたいです。

YutaroOgawa commented 4 years ago

@Aya-2 さま

ご質問ありがとうございます。 本書の対応に使える時間を確保できず、回答までしばらくかかります。 大変申し訳ございません

Aya-2 commented 4 years ago

Yutaro Ogawa さま

お時間の調整がご必要であること、お伝えくださりありがとうございます。 こちらとしては、お答えいただけること自体が有難いので、また可能な時にご回答くださればと思います。

いつもありがとうございます。

haiyunsky commented 4 years ago

I am trying transform image , but channels=1 how to transfer learning from vgg16 with channels=1? I am confusing with 1D error now.