GCP で tensorflow 遊び1

# 概要

2018年に出題されていた某コンペの衛星画像の識別コンペの、データだけ取ってあったのでそれで遊んでみる。

# 環境

GCP 上にインスタンスを用意。
tensorflow が CUDA9 を要求していて、 CUDA の方は9だと ubuntu 17.10 か 16.04LTS にしかならないので諦めてこれ用に 16.04 でインスタンス作成。

venv 環境で pip インストール。別に `scikit-image` も pip でインストールする。

cuDNN も必用なので developer 登録して 7.0.5 の tar ball を取得して `/usr/local/` 以下に展開。

```sh
env LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda/lib64 python3 ../files/RdTrn4.py train\_master\_X1.tsv
```

として利用することにする。

GCPと手元で両方でファイルをいじるので作業ディレクトリはhg管理する。
（hgだとworking directoryであるGCPに直接pushできる）。

GCP上では、 train1.zip を展開して `train/` に、train2.zip を展開して `test/` にしてある。
`train/`で学習して`test/`で答え合わせをする予定。

`train_master.tsv` から各々のディレクトリにあるファイルの行だけ抽出して`train_master_X1.tsv`, `test_master.tsv` を作った。
手元でscript修正して確認用に300ファイルだけ手元でも展開して`train_master_mini.tsv`も作成。

結局こんな抽出scriptを書いた。

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

import sys, os

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]] = l
        filenames2 = os.listdir(sys.argv[2])
        print(header.strip())
        for l in filenames2:
            print(filenamedic[l].strip())

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


# script

去年時点でこんな script 書いて動かすところまではやっていた。
チュートリアルにあった MNIST の CNN の丸コピー。
100ファイル取ってきて1バッチとして50回イテレーションして次の100ファイルに移って、を繰り返して、全部ファイルを舐めたら1ステップ終了するようにループを組んでいる。
サルベージしてきてこれをベースに作業を進める。


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

# Read Training Data

# usage
# python RdTrn.py train_master10.tsv
## head -n 11 train_master.tsv > train_master10.tsv


TARGETDIR = 'Train_all/'
BATCHSIZE=100
MODE2='CONT'
#MODE2='RESET'
NUM_STEP = 50
SHUFFLE=True


# CNN
# [32,32,7]pixel -> [5,5,7,16] kernel -> [32,32,16]pixel -> [16,16,16]pixel
# -> [3,3,16,32] kernel -> [16,16,32]pixel -> [8,8,32]pixel -> [512]FC

import tensorflow as tf

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

x = tf.placeholder(tf.float32, shape=[None, 32,32,7])
y_ = tf.placeholder(tf.float32, shape=[None,2])

#x_image = x / 256.0
x_image = x

## 1st layer
W_conv1 = weight_variable([5,5,7,16])
b_conv1 = bias_variable([16])

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

## 2nd layer
W_conv2 = weight_variable([3,3,16,32])
b_conv2 = bias_variable([32])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

## 3rd, full-connection
W_fc1 = weight_variable([8 * 8 * 32, 512])
b_fc1 = bias_variable([512])

h_pool2_flat = tf.reshape(h_pool2, [-1, 8*8*32])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

## 4th,
W_fc2 = weight_variable([512,2])
b_fc2 = bias_variable([2])

y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2

residual = y_ - y_conv
residual2 = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv)

cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


import random
import sys, os
from skimage import io

filenames = []

if os.path.isfile(sys.argv[1]):
    MODE = 'TRAIN'
    f = open(sys.argv[1])
    filenames = f.readlines()
    f.close()
    filenames.pop(0)
    if SHUFFLE:
        random.shuffle(filenames)
elif os.path.isdir(sys.argv[1]):
    MODE = 'TEST'
    filenames = os.listdir(sys.argv[1])


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver()
    if MODE2 != 'RESET':
        if os.path.exists("./model.ckpt.meta"):
            saver.restore(sess, "./model.ckpt")

    while len(filenames)>0:
        filenames_x = filenames[:min(BATCHSIZE, len(filenames))]
        del filenames[:min(BATCHSIZE, len(filenames))]
        #print(filenames_x, filenames)
        if MODE == 'TRAIN':
            filenames_y = [l.split()[0] for l in filenames_x]
        else:
            filenames_y = filenames_x

        Train = []
        Label = []

        for l in filenames_x:
            l2 = l.split()
            Train.append(io.imread(TARGETDIR+l2[0]))

            if MODE == 'TRAIN' and l2[1] == '0':
                Label.append([1, 0])
            else:
                Label.append([0, 1])

            a, b = Train[-1].min(), Train[-1].max()
            if (b-a > 0):
                Train[-1] = (Train[-1] - a) / (b - a)
                #print(l2[0],a,b)
            else:
                Train.pop(-1)
                Label.pop(-1)

        #print(Train)
        #print(Train[0])
        #print(Train[0].dtype, Train[0].shape)
        print(Label)

        Label0 = [[0, 1] for i in Train]

        if MODE == 'TRAIN':
            for i in range(NUM_STEP):
                if i % 10 == 0:
                    train_accuracy = accuracy.eval(feed_dict={
                        x: Train, y_: Label, keep_prob: 1.0})
                    print('step %d, training accuracy %g' % (i, train_accuracy))
                    #print(residual2.eval(feed_dict={
                    #    x: Train, y_: Label, keep_prob: 1.0}))

                train_step.run(feed_dict={x: Train, y_: Label, keep_prob: 0.5})

            #print(y_conv.eval(feed_dict={
            #    x: Train, y_: Label, keep_prob: 1.0}))
            print(residual2.eval(feed_dict={
                x: Train, y_: Label, keep_prob: 1.0}))

        answer = correct_prediction.eval(feed_dict={
            x: Train, y_: Label0, keep_prob: 1.0})
        for i in range(len(answer)):
            print(filenames_y[i], 0 if answer[i]==False else 1)

    saver.save(sess, "./model.ckpt")

```

とりあえず動くところまでは持って行ってみたが、猛烈に遅い。
上の script の1ステップで4000秒くらいかかる。
とてもやってられない。
何が遅いのかと思って調べてみたら imread が遅い。
imreadを非同期並行処理にできないか調べたが、file readがコルーチンでないので無理そう。

こんなに遅いんじゃ機械学習成立しないじゃんみんなどうしてんだ？
調べてみるとgcpの通常のディスクは 0.75 IOPS という説

https://cloud.google.com/compute/docs/disks/performance?hl=ja

アクセスが激しい用途なら別に SSD を増設しておかないとダメっぽい

SSD上にデータを置いて
1回学習データに対して、
判定・学習・判定

```sh
> tail -n 2 results.0218*
==> results.0218 <==
read 310.85166597366333 compute 8.858093976974487
read 302.8673777580261 7.035254001617432

==> results.0218_2 <==
read 314.44825434684753 compute 537.2505786418915
read 306.3731019496918 7.047821760177612

==> results.0218_3 <==
read 325.11989974975586 compute 14.689516067504883
read 317.0948975086212 7.06338095664978


HDD 時代の1回学習に対する判定
read 3403.6323153972626 compute 17.437681198120117
read 3393.889718055725 8.453051567077637
```

|          |read   |compute|IoU|
|----------|-------|-------|---|
|学習1(HDD)|(4112) |       |0.946|
|判定1(HDD)|3403.63|17.43  |
|判定1(SSD)|310.85|8.85    |0.521|
|学習2     |314.45|537.25  |0.964|
|判定2     |325.12|14.69   |0.576|

3000秒が300秒になったのでよしとする。

学習に使ったデータに対しては高い正答率が出るのに、未知データだと正答率が低いんでそれっぽいなーという感じ。