質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.05%

chainerでのセグメンテーション実装中のエラーについて

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 594

rk2

score 11

前提・実現したいこと

chainerを使用して画像のセグメンテーションを行いたいと考えています.
しかし,エラーが出てしまい,上手くいきません.
セグメンテーションはここ(リンク内容)を参考にしてコードを書きました.
今回は参考とは異なり,自分で学習データを用意,作成し,3クラス分類(物体A,物体B,その他)を試みています.入力画像と正解画像はそれぞれアルファチャンネル無しの3チャンネル画像ですが,正解画像はインデックスカラー画像になっており,プログラムで読み込んだ際はshapeが(1, 512, 512)でした.
chainerは初めて扱うので解決策が分からず困っています.
文字数制限があるためエラー(?)のtraceback以下は省略します.
分かる方いらっしゃいましたらご教授願います.
宜しくお願い致します.

発生している問題・エラーメッセージ

Traceback (most recent call last):
~ここは省略しました~

chainer.utils.type_check.InvalidType:
Invalid operation is performed in: SoftmaxCrossEntropy (Forward)

Expect: t.ndim == x.ndim - 1
Actual: 4 != 3


確認の為SoftmaxCrossEntropyの変数であるy_outとtの型を.shapeで確認したのですが,
y_out=(バッチ数, 3, 512, 512) t=(バッチ数, 1, 512, 512)となっていました.
tが3次元の入力を求めているようですが,4次元のどの次元を削除(?)して3次元に変換する必要があるのでしょうか?

該当のソースコード

import glob
import chainer
import numpy as np
import chainer.functions as F
import chainer.links as L
from chainer import datasets
from chainer import reporter
from chainer import iterators
from chainer import training
from chainer import optimizers
from chainer.training import extensions
from chainer.datasets import split_dataset_random
from chainercv import evaluations

def transform(data):
    """ラベルデータの値を整数値に変換"""
    data = data.astype(np.int32)
    return data

def create_dataset(img_filenames, label_filenames):
    """データセット作成関数"""
    img = datasets.ImageDataset(img_filenames)
    label = datasets.ImageDataset(label_filenames)
    label = datasets.TransformDataset(label, transform)
    dataset = datasets.TupleDataset(img, label)
    return dataset

def create_datasets():
    """データセット作成関数を使用してデータセットの読み込み"""
    train_img_filenames = sorted(glob.glob(
        r"C:\Users\ttbnb\Documents\Python Scripts\data\img\*.png"))
    train_label_filenames = sorted(glob.glob(
        r"C:\Users\ttbnb\Documents\Python Scripts\data\label\*.png"))
    train_val = create_dataset(train_img_filenames, train_label_filenames)
    number = len(train_val)
    ratio = 0.9
    train, valid = split_dataset_random(train_val, int(number*ratio), seed=0)
    return train, valid

TRAIN, VALID = create_datasets()
#確認の為にデータの数を出力
print('Training dataset size:', len(TRAIN))
print('Validation dataset size:', len(VALID))

class UNET(chainer.Chain):
    """畳み込みネットワーククラス"""
    def __init__(self, out_h, out_w, n_class=3):
        super().__init__()
        with self.init_scope():
            self.conv1 = L.Convolution2D(n_class, 64, ksize=3, stride=1, pad=1)
            self.conv2 = L.Convolution2D(None, 64, ksize=3, stride=1, pad=1)
            self.conv3 = L.Convolution2D(None, 128, ksize=3, stride=1, pad=1)
            self.conv4 = L.Convolution2D(None, 128, ksize=3, stride=1, pad=1)
            self.conv5 = L.Convolution2D(None, 64, ksize=3, stride=1, pad=1)
            self.conv6 = L.Convolution2D(None, 64, ksize=3, stride=1, pad=1)
            self.conv7 = L.Convolution2D(None, n_class, ksize=3, stride=1, pad=1)
            self.deconv1 = L.Deconvolution2D(None, 64, ksize=2, stride=2, pad=0)

        self.out_h = out_h
        self.out_w = out_w

    def forward(self, inputimg):
        """forward関数の定義"""
        e_1 = F.relu(self.conv1(inputimg))
        e_2 = F.relu(self.conv2(e_1))
        e_3 = F.max_pooling_2d(e_2, ksize=2, stride=2, pad=0)

        e_4 = F.relu(self.conv3(e_3))
        e_5 = F.relu(self.conv4(e_4))

        e_6 = F.relu(self.deconv1(e_5))

        e_7 = F.concat([e_2, e_6], axis=1)
        e_8 = F.relu(self.conv5(e_7))
        e_9 = F.relu(self.conv6(e_8))
        e_10 = (self.conv7(e_9))

        return e_10.reshape(inputimg.shape[0], 3, e_10.shape[2], e_10.shape[3])

class PixelwiseSigmoidClassifier(chainer.Chain):
    """目的関数を計算するclassifierクラス"""

    def __init__(self, predictor):
        """学習対象のモデルをpredictorとして保持しておく"""
        super().__init__()
        with self.init_scope():
            self.predictor = predictor

    def __call__(self, inputimg, t):
        """まずは学習対象のモデルで推論を行う"""
        y_out = self.predictor(inputimg)
        #ここで型を確認したが四次元のものはなかった.
        print("y", y_out.shape, "t", t.shape)

        loss = F.softmax_cross_entropy(y_out, t)

        y_out, t = F.softmax(y_out).data, (t)

        y_out, t = y_out[:, 0, ...], t[:, 0, ...]
        evals = evaluations.eval_semantic_segmentation(y_out, t)

        reporter.report({'loss':loss, 'miou':evals['miou'], 'pa':evals['pixel_accuracy']}, self)
        return loss

def create_trainer(batchsize, train, val, stop, device=-1, log_trigger=(1, 'epoch')):
    """trainerによる学習"""
    model = UNET(out_h=512, out_w=512)
    train_model = PixelwiseSigmoidClassifier(model)

    optimizer = optimizers.Adam()
    optimizer.setup(train_model)

    train_iter = iterators.MultiprocessIterator(train, batchsize)
    val_iter = iterators.MultiprocessIterator(val, batchsize, repeat=False, shuffle=False)

    updater = training.StandardUpdater(train_iter, optimizer, device=-1)

    trainer = training.trainer.Trainer(updater, stop, out='result_fcn')

    logging_attributes = (
        ['epoch', 'main/loss', 'main/miou', 'main/pa',
         'val/main/loss', 'val/main/miou', 'val/main/pa'])
    trainer.extend(extensions.LogReport(logging_attributes), trigger=log_trigger)
    trainer.extend(extensions.PrintReport(logging_attributes), trigger=log_trigger)
    trainer.extend(extensions.PlotReport(
        ['main/loss', 'val/main/loss'], 'epoch', file_name='loss.png'))
    trainer.extend(extensions.PlotReport(
        ['main/miou', 'val/main/miou'], 'epoch', file_name='miou.png'))
    trainer.extend(extensions.PlotReport(
        ['main/pa', 'val/main/pa'], 'epoch', file_name='pa.png'))

    trainer.extend(extensions.Evaluator(val_iter, train_model, device=device), name='val')
    trainer.extend(extensions.dump_graph('main/loss'))
    return trainer

if __name__ == '__main__':
    TRAINER = create_trainer(2, TRAIN, VALID, (1, 'epoch'), device=-1, log_trigger=(1, 'epoch'))
    TRAINER.run()
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

tの次元のチャンネル数の大きさが1の次元をnp.sqeezeして次元を調節することで、SoftmaxCrossEntropyのエラーは回避することができました。しかし、eval_semantic_segmentationにてエラーが出てしまいました。本質問は解決できましたのでeval_semantic_segmentationのエラーについては次の質問にて質問させていただきました。
本質問を閲覧していただいた方で、お時間のありでしたら、次の質問も回答募集中ですのでご協力いただければ幸いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る