TecoGANについてのメモ帳（学習）

こんにちは

最近機械学習について勉強し始めたので、自分用に書きます。
題名の通り自分のメモ帳のように書きますので、分かりにくい点があればご指摘お願いします。
ご指摘いただいた点に関して自分も理解できていたならば修正します。

また、私は以前TecoGANの導入に関するメモも投稿しているので、そちらをご覧になりTecoGANを動かしてからこの記事を参考にしてください。

[TecoGANについてのメモ帳]
 https://qiita.com/toromix/items/02cf8aea34fa206bd9e3

機械学習やモデル、TecoGANに関して理解が浅いので何かあればつっこんでください…
また、今後修正するかもです。
また、OSはubuntuを用いています。
TecoGANはなにかとwgetを使用するので、windowsだとめんどくさいからです。

###PCスペック
OS : Ubuntu　18.04
CPU: i5 4670k
GPU: Geforce 2060SP
メモリ：16GB
言語: python 3.6

#モデルの学習
モデルの学習といっても用意されたモデルに用意された動画のフレーム群を入れることでパラメータを更新する作業になります。
ソース https://github.com/thunil/TecoGAN

##学習用データセットの取得
まず、学習用データを用意します。
gitではデータセットのダウンロードにyoutubeやvimeoから動画を取得できる`youtube-dl`というツールを用いているようです。
ですのでこれをまず最初にダウンロードします。

```ruby:cmd
pip install --user --upgrade youtube-dl
```
これで準備完了です。
学習用データセットを準備するために、`dataPrePare.py`を動かします。

```ruby:cmd
python3 dataPrepare.py --start_id 2000 --duration 120 --REMOVE --disk_path TrainingDataPath
```

ここで簡単に引数に関して説明するためにこのプログラムの結果をお伝えします。
このプログラムでは`TecoGAN/`のフォルダ下に`TrainingDataPath`というフォルダが自動的に生成されます。
`TrainingDataPath`のフォルダ下には`scene_2000`から`scene_2250`程度までフォルダが連番で生成されています。
最後に各`scene_xxxx`には、120枚のフレーム群が入っています。

想像つくでしょうか。説明下手で申し訳ありません。

つまり、引数に関しては以下の通りです。
・`start_id`というのは、TrainingDataPath のフォルダ下におかれるフレーム群が入ったフォルダの初めの番号となります。引数を2001などにするとおそらく、`scene_2001`からフォルダが生成されるはずです。
・`duration`はフレームの枚数になります。
・`REMOVE`は動画をフレームにした後削除するかどうかの引数です。動画は結構容量食うのでつけとくのを推奨します。
・`disk_path`はこれらのフレーム群をどこに置くかを指定しています。ソースコードでは、`/mnt/netdisk/video_data/`を指定しているようです。

データセットを用意するプログラムはかなり時間がかかります。
あまり覚えていませんが30分程度かかった気がします。

###補足
`dataPrepare.py`を見るとダウンロードする動画のpathと不可解な数字列が並んでいるかと思います。

```ruby:cmd
link_path = "https://vimeo.com/"
video_data_dict = { 
# Videos and frames are hard-coded. 
# We select frames to make sure that there is no scene switching in the data
# We assume that the Flags.duration is 120
    "121649159" : [0, 310,460,720,860], #1
    "40439273"  : [90,520,700,1760,2920,3120,3450,4750,4950,5220,6500,6900,9420,9750], #2
    "87389090"  : [100,300,500,800,1000,1200,1500,1900,2050,2450,2900], #3
```
これは、単純に右の[ ]でくくられた数字のフレームから120のフレーム群を抜きだしているだけです。
左は動画のパスになります。
`link_path`とつなげてURL検索したら動画がヒットします。
ここでは`link_path = "https://vimeo.com/"` ですので、
https://vimeo.com/121649159 を調べると動画が出てくるのではないかなと思います。

youtubeなどからデータセットを取得する場合は以上の点を踏まえて書き換えます。
ただ、フレームには自動で変換されなかったため手動でめんどくさい操作をしなくてはならないかもです。

##モデルの学習
前提として、学習用データセットは`TecoGAN/TrainingDataPath/`にあります。
ですのでこれまでのコマンドを打てば私と同じ環境になっていると思います。

まずモデルの学習は以下のコマンドで行います。
ですが、うまくいかないです

```ruby:cmd
python runGan.py 3
```
というのも、gitと学習用データセットのパスが違うからです。
これを修正します。

`runGan.py`を開いてください。

```ruby:runGan.py
elif( runcase == 3 ): # Train TecoGAN
    '''
    In order to use the VGG as a perceptual loss,
    we download from TensorFlow-Slim image classification model library:
    https://github.com/tensorflow/models/tree/master/research/slim    
    '''
    VGGPath = "model/" # the path for the VGG model, there should be a vgg_19.ckpt inside
    VGGModelPath = os.path.join(VGGPath, "vgg_19.ckpt")
    if(not os.path.exists(VGGPath)): os.mkdir(VGGPath)
    if(not os.path.exists(VGGModelPath)):
        # Download the VGG 19 model from 
        print("VGG model not found, downloading to %s"%VGGPath)
        cmd0 = "wget http://download.tensorflow.org/models/vgg_19_2016_08_28.tar.gz -O " + os.path.join(VGGPath, "vgg19.tar.gz")
        cmd0 += ";tar -xvf " + os.path.join(VGGPath,"vgg19.tar.gz") + " -C " + VGGPath + "; rm "+ os.path.join(VGGPath, "vgg19.tar.gz")
        subprocess.call(cmd0, shell=True)
        
    '''
    Use our pre-trained FRVSR model. If you want to train one, try runcase 4, and update this path by:
    FRVSRModel = "ex_FRVSRmm-dd-hh/model-500000"
    '''
    FRVSRModel = "model/ourFRVSR" 
    if(not os.path.exists(FRVSRModel+".data-00000-of-00001")):
        # Download our pre-trained FRVSR model
        print("pre-trained FRVSR model not found, downloading")
        cmd0 = "wget http://ge.in.tum.de/download/2019-TecoGAN/FRVSR_Ours.zip -O model/ofrvsr.zip;"
        cmd0 += "unzip model/ofrvsr.zip -d model; rm model/ofrvsr.zip"
        subprocess.call(cmd0, shell=True)
    
#    TrainingDataPath = "/mnt/netdisk/video_data/" 
    TrainingDataPath = "./TrainingDataPath/" 
    
    '''Prepare Training Folder'''
    # path appendix, manually define it, or use the current datetime, now_str = "mm-dd-hh"
    now_str = datetime.datetime.now().strftime("%m-%d-%H")
```

`elif (runcase==3)`がモデルの学習です。
135行目あたりに`TrainingDataPath`を指定するところがあるかと思います。
この点を修正します。
具体的には上記プログラムにありますが、現在フォルダからフレーム群が入っているフォルダを指定するだけです。

まだ修正点があります。

```ruby:runGan.py
    cmd1 += [
        "--input_video_dir", TrainingDataPath, 
        "--input_video_pre", "scene",
        "--str_dir", "2000",
        "--end_dir", "2250",
        "--end_dir_val", "2290",
        "--max_frm", "119",
        # -- cpu memory for data loading --
        "--queue_thread", "12",# Cpu threads for the data. >4 to speedup the training
        "--name_video_queue_capacity", "1024",
        "--video_queue_capacity", "1024",
    ]
```
`runGan.py` の177行目あたりに上記のようなプログラムがあるかと思います。
これは`TrainingDataPath`下フォルダのフレーム群を指定するものとなっています。
・`str_dir` 一番最初のscene_xxxx の数字[xxxx]を指定する。ここでは2000で結構です。 
・`end_dir` 訓練データの終わりのフォルダ。プログラムでは2000~2250を訓練データとしています。
・`end_dir_val` テスト用データの終わり。ここでは2251~2290をテスト用データとしています。
・`max_frm` 各フォルダのフレーム群です。0~119の計120です。ここも変えなくて大丈夫です。

確認しなくてはいけないのは`DataTrainingPath`にある`scene_xxxx`の数です。
TecoGANは2年前くらいの技術になり、ソースも1年も前に編集されているためデータセットのパスがつながっていない場合があります。
そうすると動画がダウンロードできずにフレーム群が生成されません。
よって、`scene_xxxx`は従来の数より少なくなっている可能性があります。
ですので、`end_dir`,`end_dir_val`の値を変えて今あるsceneの数内に収めてください。

例えば`scene_2000 ~ scene_2100` までしかなかった場合、下記のようにします。

```ruby:runGan.py
    cmd1 += [
        "--input_video_dir", TrainingDataPath, 
        "--input_video_pre", "scene",
        "--str_dir", "2000",
        "--end_dir", "2090",
        "--end_dir_val", "2100",
        "--max_frm", "119",
        # -- cpu memory for data loading --
        "--queue_thread", "12",# Cpu threads for the data. >4 to speedup the training
        "--name_video_queue_capacity", "1024",
        "--video_queue_capacity", "1024",
    ]
```
ここに関しては時代や人によって異なるかなと思いますので一例だけを示しときます。
自身で確認して修正してください。

最後にプログラムを実行します。

```
python runGan.py 3 
```
結果として`TecoGAN/model/`に`ourFRVSR`パラメータが生成されます。
TecoGANの学習はこの`ourFRVSR`モデルを軸に行っています。

また、`ex_TecoGANmm-dd-hh`フォルダが生成されます。
ここには学習したモデル`model-xxx`と学習後のcalendarの画像が生成されています。

これで学習は完了です。
早速成果をみてみましょう。

##学習したモデルを使いたい

```ruby:runGan.py
elif( runcase == 1 ): # inference a trained model
    
    dirstr = './results/' # the place to save the results
    testpre = ['calendar'] # the test cases

    if (not os.path.exists(dirstr)): os.mkdir(dirstr)
    
    # run these test cases one by one:
    for nn in range(len(testpre)):
        cmd1 = ["python3", "main.py",
            "--cudaID", "0",            # set the cudaID here to use only one GPU
            "--output_dir",  dirstr,    # Set the place to put the results.
            "--summary_dir", os.path.join(dirstr, 'log/'), # Set the place to put the log. 
            "--mode","inference", 
            "--input_dir_LR", os.path.join("./LR/", testpre[nn]),   # the LR directory
            #"--input_dir_HR", os.path.join("./HR/", testpre[nn]),  # the HR directory
            # one of (input_dir_HR,input_dir_LR) should be given
            "--output_pre", testpre[nn], # the subfolder to save current scene, optional
            "--num_resblock", "16",  # our model has 16 residual blocks, 
            # the pre-trained FRVSR and TecoGAN mini have 10 residual blocks
            #"--checkpoint", './model/TecoGAN',  # the path of the trained model,            
             "--checkpoint", './exTecoGAN/model-xxx',  # the path of the trained model, #追加
            "--output_ext", "png"               # png is more accurate, jpg is smaller
        ]
        mycall(cmd1).communicate()
```
runGan.py 67行目あたりにある実行用のプログラムです。
`cmd1`内に引数として`--checkpoint`があると思います。
これは使用するモデルを指定するものですので、これを学習したモデルに変えます。
モデルは拡張子としてindexやmetaなどあると思いますが、無視して拡張子を除いたファイル名を書いてください。

実行すると4倍に拡張されたフレーム群が生成されます。
学習前と学習後を比べてみてください。



#最後に
TecoGANのモデルの学習に関してあまり記事がなかったので自分の後学のために書きました。
動かないなどのご指摘ありましたらよろしくお願いします。
また、書き忘れている点もあるかもしれませんのでその都度追記します。
ちなみにTecoGANに関してはgitにある`runGan.py 4`などはやっていないです。
時間があればみます。

また機械学習やpython, GANについても勉強してから日が浅いのでご指摘ありましたらしていただけると勉強の機会を与えられ非常にうれしいです。

#おまけ
4倍以外の拡大をすることができた方どうか教えてください…
ourFRVSR がそもそも4倍用の構造となっているため無理なんでしょうか...？