Keras書き方まとめ

すいません大したことは書いてないです。
あくまで自分用メモという感じです。

#Kerasの書き方
大まかには以下の流れ。
データの準備→モデルの定義→モデルの学習→予測

０．必要なパッケージのインポート
kerasやnumpy等。

```Python
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, BatchNormalization, Input, Activation
from keras.optimizers import Adam
from keras.callbacks import EarlyStopping
from keras.layers import Conv2D, Flatten, Reshape, LeakyReLU, MaxPooling2D, ELU, GlobalAveragePooling2D, AveragePooling2D
import numpy as np
from keras.models import Model
```

「AttributeError: module 'tensorflow' has no attribute 'get_default_graph'」
とかエラーになったりすることがあるので、以下の様にtensorflowに取り込まれたKerasを使った方がよいかもしれません。

```Python
import tensorflow.keras as keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization, Input, Activation
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.layers import Conv2D, Flatten, Reshape, LeakyReLU, MaxPooling2D, ELU, GlobalAveragePooling2D, AveragePooling2D
import numpy as np
from tensorflow.keras.models import Model
```


１．データの準備
CSVファイル等からPandas等を使ってnumpy配列のデータを用意する。
分類の場合にはkeras.utils.to_categorical()を使って、one-hot形式（0～2を取るデータで1の場合に[0,1,0]となる形式）のデータにする必要がある。
実数データの場合はnumpy.float64だと遅いので、astype(np.float32）でfloat32に変更する。

```Python
#１．データの準備
mnist = keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_images_flat = (train_images.reshape(-1, 28*28) / 255.0).astype(np.float32)
test_images_flat  = (test_images.reshape(-1, 28*28) / 255.0).astype(np.float32)

y_keras = keras.utils.to_categorical(train_labels, 10)
```

２．モデルの定義
Sequential APIでの方法とFunctional APIでの方法がある。
summary()で作成されたモデルの各層について表示できる。
作成したモデルはcompile()の実行後に学習を行うことができる。

```Python
#２．モデルの定義
def createModel():
  model = Sequential()
  model.add(Dense(1000, input_shape=(28*28, ), activation='relu'))
  model.add(Dropout(0.2))
  model.add(Dense(100, activation='relu'))
  model.add(Dropout(0.2))
  model.add(Dense(10, activation='softmax'))  
  model.summary()
  return model

mdl = createModel()

mdl.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.0002), metrics=['accuracy'])
```

３．モデルの学習
作成したモデルに対してfit()を実行する。

```Python
early_stopping = EarlyStopping(monitor='val_loss', mode='min', patience=10)
mdl.fit(
     train_images_flat
    ,y_keras
    ,epochs=100
    ,validation_split=0.1
    ,batch_size=1000
    ,verbose=2
    ,callbacks=[early_stopping]
)
```

４．予測の実行
回帰ならpredict()、分類ならpredict_classes()を実行する。
分類でもpredict()で各クラス別の確率を取得してnumpy.argmax(結果, axis=1)で最大を取得することで、
predict_classes()と同じことができる。

```Python
#result = mdl.predict_classes(test_images_flat, verbose=2)
result_x = mdl.predict(test_images_flat, verbose=2)
```

#Sequencial APIの使い方
①「Sequential()」でシーケンシャルモデルのインスタンスを作成する。
②add([レイヤー])でDenseやActivation等のレイヤーを追加する。

Sequencialモデルはこれだけ。
ただ、入力、出力が複数あるなどの場合に対応できないので、
複雑なモデルになる可能性があるときは、初めから後述のFunctional APIで
作成しておいた方がよさそう。

(例)

```Python
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=(8,8,1,)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(BatchNormalization())
model.add(Dense(n_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.00001), metrics=['accuracy'])
```



#Functional APIの使い方
①Input()で入力を定義する
②最初は①で作成したものを関数（レイヤー、モデル、Activation等）に引数として渡す
③関数の戻りを次の関数の引数にする形で繰り返す。
④Modelの引数のinputに入力、③の最後の戻りをoutputに設定してモデルを作成する。

結局、Sequencial APIでは出来ないことがあるので、複雑なモデルになりうるものは最初からFunctional APIで作っておいた方がよさそう。

```Python
#入力はこんな感じ
main_input = Input(shape=(SEED_SIZE + 10,), name='main_input')
 
#Lambdaレイヤーを使って入力データを分ける場合
rand_input  = Lambda(lambda x: x[:, :SEED_SIZE], output_shape=(SEED_SIZE,))(main_input)
label_input = Lambda(lambda x: x[:, SEED_SIZE:], output_shape=(10,       ))(main_input)

#後は最初に引数に入力を取って、戻りを引数に入れる形でレイヤーを重ねる
x = Dense(units=7*7*64)(main_input)
x = Activation("relu")(x)
x = BatchNormalization()(x)

#データを結合する場合
merge_output = keras.layers.concatenate([x, y])

#最終的にModel()でinputs、outputsを指定してモデルを作成する
mdl_dec = Model(inputs=[main_input], outputs=[merge_output])
```

Functional APIでモデルを連結させてモデルを作成する場合は
以下の様にモデルをレイヤーの様に関数指定する

```Python
main_input = Input(shape=(SEED_SIZE + 10,), name='main_input')
x = generator(inputs=[main_input])
x = discriminator(x)
mdl_gen_disc = Model(inputs=[main_input], outputs=x)
```

モデルを学習させない場合はtrainableをセットする
以下のように、モデルの各レイヤーのtrainableもセットする。

```Python
#学習可否をセットする
def set_trainable(model, trainable):
  model.trainable = trainable
  if hasattr(model, 'layers'):
    for layer in model.layers:
      set_trainable(layer, trainable)  
```

データの変換等

```Python
#カテゴリ変数化
b = keras.utils.to_categorical(train_labels)

#numpy配列の連結１
b = keras.utils.to_categorical(train_labels)
X_train_t_labeled = np.concatenate((X_train_t,b), axis=1)

#numpy配列の連結２
a = np.random.uniform(0, 1, size=(len(truepic), SEED_SIZE,)).astype(np.float32)
b = keras.utils.to_categorical( np.arange(len( truepic)) % 10 )
randdata = np.concatenate((a,b), axis=1)  

```


```Python
#モデルのコンパイル
model_disc.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.003), metrics=['accuracy'])
```

２値分類の場合

```Python
#出力層のユニットは1、活性化関数にsigmoidを使う
Dense(1, activation='sigmoid')
#コンパイル時の損失関数にはbinary_crossentropyを使う
model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])
```

３クラス以上の分類の場合

```Python
#教師データはto_categoricalを使ってone-hotの配列にしておく

#出力層のユニット数はクラス数、活性化関数にsoftmaxを使う
Dense(3, activation='softmax')
#コンパイル時の損失関数はcategorical_crossentropy
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])
```

EarlyStoppingの使い方（損失の変化が少なくなったら自動で終了する）

```Python
from keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', mode='min', patience=20)
#…
callbacks=[early_stopping]
```

ModelCheckpointの使い方（一番損失の小さいモデルを保存できる）

```Python
from keras.callbacks import ModelCheckpoint
checkpointer = ModelCheckpoint(filepath="～.h5", save_best_only=True)
#…
callbacks = [checkpointer]
```


モデルの保存・読込、ウェイトの保存・読込の例

```Python
from keras.models import model_from_json

model_json_name = 'xxxx.json'
weight_h5_name  = 'xxxx.h5'

#モデルの作成・保存
model=Sequential()
…
json_string=model.to_json()
open(model_json_name,"w").write(json_string)

#モデルの読込・コンパイル
json_string=open(model_json_name).read()
model=model_from_json(json_string)
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

#学習・ウェイトの保存
history=model.fit(x_train,y_train,batch_size=128,nb_epoch=20,verbose=1,validation_split=0.1)
model.save(weight_h5_name)

#学習済みのウェイトの読込
model.load_weights(weight_h5_name)

```

モデルとウェイトとセットで良ければ保存、読み込みは以下のようにする。

```Python
model.save(～)
model = keras.models.load_model(～)
```