GCP で tensorflow 遊び3

# 概要

GCP上でtensorflowで去年の某衛星画像コンペのデータで遊んでみる。
[GCP で tensorflow 遊び2](https://qiita.com/makainuma/items/3dc8e2d904ea2d6b3f76)の続き。

定義ファイルを読んで画像を読み込み正規化してCNNを行うscriptを発見・修正して
適宜CNN部の実験を行えるようにしていた。

## 実験

conv1x1というのがアリだと読んだのでそれも試してみる。
baseは前回のCNN4で以下の構造。

```
## [32,32,7]pixel
## -> [3,3,7,16] kernel -> [32,32,16]pixel -> [16,16,16]pixel
## -> [3,3,16,32] kernel -> [16,16,32]pixel -> [8,8,32]pixel
## -> [3,3,32,32] kernel -> [8,8,32]pixel -> [4,4,32]pixel
## -> [128]FC
## -> 2
```

train1.zip で学習、train2.zip で判定。
学習はshuffleしたものを読み込み100ファイルでバッチを作って50回学習で全ファイル舐めたら1ステップとする。
ステップの進行でIoUがどう推移するか。

### CNN42

3層目のconv3x3をconv1x1で置き換え。

```
## [32,32,7]pixel
## -> [3,3,7,16] kernel -> [32,32,16]pixel -> [16,16,16]pixel
## -> [3,3,16,32] kernel -> [16,16,32]pixel -> [8,8,32]pixel
## -> [1,1,32,32] kernel -> [8,8,32]pixel -> [4,4,32]pixel
## -> [128]FC
## -> 2
```

### CNN43

各3x3のconvolutionに1x1のconvolutionを後続させる。

```
## [32,32,7]pixel
## -> [3,3,7,16] kernel -> [32,32,16]pixel -> [1,1,16,16] kernel -> [32,32,16]pixel -> [16,16,16]pixel
## -> [3,3,16,32] kernel -> [16,16,32]pixel -> [1,1,32,32] kernel -> [16,16,32]pixel -> [8,8,32]pixel
## -> [3,3,32,32] kernel -> [8,8,32]pixel -> [1,1,32,32] kernel -> [8,8,32]pixel -> [4,4,32]pixel
## -> [128]FC
## -> 2
```

### CNN44

CNN自体はCNN4と同じだが、最後FCで長さ128のベクトルになった時点で、元画像の7層それぞれの画素値の平均・標準偏差を連結して長さ142のベクトルを作る。

```
## [32,32,7]pixel
## -> [3,3,7,16] kernel -> [32,32,16]pixel -> [16,16,16]pixel
## -> [3,3,16,32] kernel -> [16,16,32]pixel -> [8,8,32]pixel
## -> [3,3,32,32] kernel -> [8,8,32]pixel -> [4,4,32]pixel
## -> [128]FC -> [142]
## -> 2
```

### 結果

```
# CNN4

40 1 0.5109186746987951
40 2 0.5540834845735028
40 3 0.6401020082881734
40 4 0.5314047029702971

# CNN42

42 1 0.58096
42 2 0.5930057280675309
42 3 0.627724795640327
42 4 0.6567137169743033
42 5 0.6170007710100232
42 6 0.6047528517110267

# CNN43

43 1 0.0012836970474967907
43 2 0.5393416298675231
43 3 0.5103817816476892
43 4 0.5507159904534606
43 5 0.6504182754182755
43 6 0.613016367887763

# CNN44

44 1 0.44843423799582466
44 2 0.3419382141345747
44 3 0.5388956066102378
44 4 0.41763005780346824
44 5 0.6155913978494624
44 6 0.6650469711694201
```

![CNN44.png](https://qiita-image-store.s3.amazonaws.com/0/170148/119b91af-6721-8f4e-3ace-d556d8baa079.png)


単純に最後をconv1x1にしただけのCNN42でももとのCNN4よりはよい。
凝ったことをしたCNN43は成果が出るまで時間がかかっているがその後過学習で（？）評価値は下がっている（このあとどう推移するのか？）
正規化する前の画像の輝度情報を連結したCNN44は時間はかかっているが一番高い評価を出している（この後どう推移するのかは不明）


----

（遊びだからまあいいんだけど）なんか見返してたら IoU とかそのへん全然計算間違えていたことに気が付いて再計算。


![CNN44_2.png](https://qiita-image-store.s3.amazonaws.com/0/170148/93d68ef8-673d-adb3-1aaf-e3f487230702.png)

どれが良さそうとかの評価は上と変化なし。
（CNN4は他と合わせて6まで計算し直している）


やはり頭使わないで場当たり的に script 直してったら駄目だなということで、真面目に定義通りに計算する script はこちら

```py
#! /usr/bin/env python

## usage
## grep train_ results.xxxx > results.xxxx.train
## Judge.py test_master.tsv results.xxxx.train

import sys, os
import functools

if __name__ == '__main__':
    if len(sys.argv) > 2:
        f = open(sys.argv[1])
        filenames0 = f.readlines()
        f.close()
        header = filenames0.pop(0)
        filenamedic = {}
        for l in filenames0:
            ll = l.split()
            filenamedic[ll[0]] = ll[1]
        
        f = open(sys.argv[2])
        filenames2 = f.readlines()
        f.close()

        TP = 0
        TN = 0
        FP = 0
        FN = 0

        RES = map(lambda l: filenamedic[l.split()[0]]+l.split()[1], filenames2)
        RES2 = {'00':0, '01':0, '10':0, '11':0}
        for i in RES:
            RES2[i] += 1

        IOU = RES2['11'] / (RES2['11']+RES2['10']+RES2['01'])
        precision = RES2['11'] / (RES2['11'] + RES2['01'])
        recall = RES2['11'] / (RES2['11'] + RES2['10'])
        print(RES2['00'], RES2['01'], RES2['10'], RES2['11'], IOU, precision, recall)

    else:
        print('command filename dir/')
```

python の `reduce()` で count ってどうやればよかったんだろう？
python の lambda はちょー不便

----

lambda 式で頑張ろうとするから無理なのであって、関数定義しちゃえば reduce 使えるな

```py
        RES = map(lambda l: filenamedic[l.split()[0]]+l.split()[1], filenames2)
        RES0 = {'00':0, '01':0, '10':0, '11':0}
        def fun(acc, cur):
            acc[cur] += 1
            return acc
        RES2 = functools.reduce(fun, RES, RES0)
```

ふーん、acc, cur の順なのね。
でもまあダサい