自作データを使ったPyTorchによるPSPNetの実装

#経緯
学校の自由課題で自動運転のかなりしょぼい版をやることになりました。(一応道路上を走りはしました。)

下のような画像から道路を認識するために、セマンティックセグメンテーションが必要になったので、参考図書([作りながら学ぶ！ PyTorch による発展ディープラーニング](https://www.amazon.co.jp/dp/B07VPDVNKW/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1))をもとにしながら自作データでの学習を行いました。

正直大半がほかのページへのリンクです...

![cnt-162.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538493/363f8e60-5f49-fd62-7200-b331d0bbf289.jpeg)

#動作環境
Google Colab 上のGPUを用いています。後日ほかの環境でも試す予定です。

#変更点の概要
参考図書からネットワーク自体は変更していないので、変更箇所は

- データセット
- パス
- クラス数

くらいです。
#データセットの作成
今回はデータセットを作成するために[labelme](https://github.com/wkentaro/labelme)を使いました。
labelmeは、pythonとQtで実装されたGUIを持つアノテーションツールです。
##インストール
詳しくは[本家のGithub](https://github.com/wkentaro/labelme)を参照してください
私はwindowsを使用しているため、[Anaconda](https://www.anaconda.com/)からインストールしました。

```
conda create --name=labelme python=3.6
source activate labelme
# conda install -c conda-forge pyside2
# conda install pyqt
# pip install pyqt5  # pyqt5 can be installed via pip on python3
pip install labelme
# or you can install everything by conda command
# conda install labelme -c conda-forge
```

##使用方法
Anaconda Promptを開いて、labelmeと入力します。あとはOpen（たぶん一つのディレクトリに画像すべて入ってると思いますので、Open Dirから開いた方が楽）から画像を開いてラベルを付けて終わりです。

作業を楽にするためのコマンドがいろいろあるので、調べてみるといいと思います。（私はKeep Previous Annotationに気づかずだいぶ時間を費やしました。）

ただこのままだとJsonファイルなので、次で画像に直します。

##画像への変換
前の章で仰々しく書きましたが、すでに説明されているページがありますので、そちらを参照してください。https://qiita.com/otakoma/items/2f40e583980013acb2f7

#パス
ここではpathを大量に書いたファイルを作成します。

```
import re
import glob
from sklearn.model_selection import train_test_split

#動画データまでのパスを作成
def Create_txt(txt_path):
　　#fileListは各自変更
　　filelist = glob.glob(os.path.join('*.jpg'))
    #train:val:test = 8:1:1
    train_data, val_test_data = train_test_split(fileList, test_size=0.2)
    val_data, test_data =  train_test_split(val_test_data, test_size=0.5)
    
    try:　　
        train_txt = os.path.join(txt_path, 'train.txt')
        with open(train_txt, mode='x') as f:
　　　　　　for train_path in train_data:
               s = 'Road_data/' + train_path + ',Road_label/' +　train_path.strip('.jpg') + '.png' + '\n'
               f.write(s)
            

        val_txt = os.path.join(txt_path, 'val.txt')
        with open(val_txt, mode='x') as f:
            for val_path in val_data:
                s = 'Road_data/' + val_path + ',Road_label/' +　val_path.strip('.jpg') + '.png' + '\n'
                f.write(s)
              

        test_txt = os.path.join(txt_path, 'test.txt')
        with open(test_txt, mode='x') as f:
            for test_path in test_data:
                s = 'Road_data/' + test_path + ',Road_label/' +　test_path.strip('.jpg') + '.png' + '\n'
                f.write(s)
           
    except FileExistsError:
        print('already exists')

```

train_test_splitを使うとtrain,validation,testをランダムに分割できて便利です。

このコードを実装すると、以下のようなファイルが生成されます。（つまり前述のコードはひたすらディレクトリ内のファイル名を参照してファイルに書き込んでいます。）

```

Road_data/cnt-104.jpg,Road_label/cnt-104.png
Road_data/cnt-110.jpg,Road_label/cnt-110.png
Road_data/cnt-11.jpg,Road_label/cnt-11.png
Road_data/cnt-111.jpg,Road_label/cnt-111.png
Road_data/cnt-117.jpg,Road_label/cnt-117.png
Road_data/cnt-115.jpg,Road_label/cnt-115.png
Road_data/cnt-114.jpg,Road_label/cnt-114.png
Road_data/cnt-119.jpg,Road_label/cnt-119.png
Road_data/cnt-120.jpg,Road_label/cnt-120.png
Road_data/cnt-125.jpg,Road_label/cnt-125.png
Road_data/cnt-127.jpg,Road_label/cnt-127.png
Road_data/cnt-129.jpg,Road_label/cnt-129.png
Road_data/cnt-133.jpg,Road_label/cnt-133.png
Road_data/cnt-132.jpg,Road_label/cnt-132.png



```



注意点として、このコードでは元データと正解データが同じファイル名である必要があるため、もし元がJPGファイルで正解がPNGファイルである場合は、

```
file_path_label = os.path.join(label_dir, filename)
から
file_path_label = os.path.join(label_dir, filename)　+　 
  　　　　　　　　 file_path_rgb.strip('.jpg') + '.png'
```

としてあげてください。ディレクトリ構造やファイル名の決め方は個人によって違うと思いますので、細かいところは各々直してください。



#実装
正直後は参考書通りやるだけです。
#追記
試しに実装したところ車を走らせるには絶望的に遅かったので、ESPNetで実装しました。

ただESPNetはバージョンやらCityScapesの正解データのフォーマットやらのせいで多少いじらなければならなかったので、そちらも時間できたらあげます。