自作データでのESPNetの実装

#経緯
学校の自由課題でリアルタイムでのセマンティックセグメンテーションを実装することになりました。はじめにPSPNetを用いて実装しました(https://qiita.com/rio53/items/90b757c2c0a3b0f8da77 )が、推論に時間がかかるためESPNetを用いて実装することにしました。

お恥ずかしながらネットワークの構造についてはまだ理解できていませんので、あくまで実装した方法のみ記述させていただきます。
#実装環境
Google Colab 上で実装しました。

#変更点
今回の変更点は

- 正解データの前処理
- バージョンの違いにより生じる問題の補正
- class数の調整

です。trainディレクトリに変更を加えます。
#正解データの前処理
本家の場合正解データをグレースケールで取得するのですが、前回作成したデータはパレット画像(画像の各色に番号が付けられている画像)なので、その箇所を変更します。

loadData.pyのreadFile関数内の60行目
 
```loadData.py
#imreadの2つめの変数はオプションで、0だとグレースケール
label_img = cv2.imread(label_file, 0)
```
を

```loadData.py
#imreadではパレット画像で受け取れないので注意
label_img = Image.open(label_file)
label_img = np.array(label_img)
#作った画像は背景が255番で設定されているので、0番に変更
index = np.where(label_img == 255)
label_img[index] = 0
```
に変更します。

※そのままにしていてもclass数がおかしくなる（たとえば赤くラベルを付けていたらその値がすごく大きくなる）だけなので、どうにかなります。また、

```
label_img = cv2.imread(label_file, 0)
unique_values = np.unique(label_img)　#明るさを確認(ラベル1の明るさをxとする)
#明るさxの要素を1に変更
index = np.where(label_img == x)
label_img[index] = 1
```
で配列の要素をいじってあげてもどうにかなります。

#バージョン違いへの対応
本家はPyTorchのバージョンが0.3.0に対応しているので、所々上手く機能しない箇所があります。

**1. 0次元テンソル**
どうやらバージョン0.4.0あたりから0次元テンソルが無効になったので、そこを改善します。main.pyのそこかしこに存在している(最初は51行目)

```main.py
loss.data[0]
```
を

```main.py
loss.data
```
に変更します。
これさえやれば動きはするので、後は警告が出てる箇所を修正します。後で書きます。

#class数の調整
どうやら中でclassを分割して処理しているらしく、class数を2とか3とかにするとバグがでてしまいます。(なのでclass数を変更しないならこのままでいいです。)

このバグの解決法は著者の方が何かのサイトで教えてくださっていますが、ずいぶん前に実装したこともありどのサイトか忘れてしまったためコードを載せます。

Model.pyの328行目からの

```Model.py
        # load the encoder modules
        self.modules = []
        for i, m in enumerate(self.encoder.children()):
            self.modules.append(m)

        # light-weight decoder
        self.level3_C = C(128 + 3, classes, 1, 1)
        self.br = nn.BatchNorm2d(classes, eps=1e-03)
        self.conv = CBR(19 + classes, classes, 3, 1)

        self.up_l3 = nn.Sequential(nn.ConvTranspose2d(classes, classes, 2, stride=2, padding=0, output_padding=0, bias=False))
        self.combine_l2_l3 = nn.Sequential(BR(2*classes), DilatedParllelResidualBlockB(2*classes , classes, add=False))

        self.up_l2 = nn.Sequential(nn.ConvTranspose2d(classes, classes, 2, stride=2, padding=0, output_padding=0, bias=False), BR(classes))

        self.classifier = nn.ConvTranspose2d(classes, classes, 2, stride=2, padding=0, output_padding=0, bias=False)
```

となっている箇所を

```Model.py
        classes1 = classes
        classes = 20
        
        # load the encoder modules
        self.modules = []
        for i, m in enumerate(self.encoder.children()):
            self.modules.append(m)

        # light-weight decoder
        self.level3_C = C(128 + 3, classes, 1, 1)
        self.br = nn.BatchNorm2d(classes1, eps=1e-03)
        self.conv = CBR(19 + classes, classes, 3, 1)

        self.up_l3 = nn.Sequential(
            nn.ConvTranspose2d(classes1, classes, 2, stride=2, padding=0, output_padding=0, bias=False))
        self.combine_l2_l3 = nn.Sequential(BR(2*classes), DilatedParllelResidualBlockB(2*classes , classes, add=False))

        self.up_l2 = nn.Sequential(
            nn.ConvTranspose2d(classes, classes, 2, stride=2, padding=0, output_padding=0, bias=False), BR(classes))
        
        self.classifier = nn.ConvTranspose2d(classes, classes1, 2, stride=2, padding=0, output_padding=0, bias=False)
```

という感じに変更します。所々classesがclasses1に変わってていちいち変更すると面倒なのでそのままコピペした方が楽です。

#終わりに
まだ書き始めたばかりなのでわかりづらい箇所もあるかと思いますが、お読みくださりありがとうございました。