HELLO CYBERNETICS

深層学習、機械学習、強化学習、信号処理、制御工学、量子計算などをテーマに扱っていきます

【いつの間にか進化してた!】TensorFlowのKerasの様々な使い方

 

 

follow us in feedly

https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png

はじめに

最近機械学習から離れ気味ですが、何やらTensorFlowのDocumentを覗いたらTensorFlow内部のKerasがすごくいろいろな使い方できることに気が付きました。 (ちなみに、TensorFlowとは別の(いろいろなフレームワークをバックエンドにできる)Kerasの方はどうなっているのか知らないので申し訳ありません。)

ということでそれを簡単にまとめておきたいと思います。本当に簡単に。

これまで通りの使い方

Kerasと言えばコレ:Sequential

最もよく知られている使い方ですね。 model=tf.keras.Sequential()でインスタンス化して、model.add()メソッドでひたすら層を積んでいく方式。

 

とっても直感的で分かりやすいです。

 

model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(32, input_shape=(500,)))
model.add(tf.keras.layers.Dense(32))
model.compile(optimizer=optimizer, loss=loss)
model.fit(x, y, batch_size=32, epochs=10)

 

xとかyとかは教師データ・セットです。optimizer,lossを決めてやればすぐに学習ができます。便利!

 

少し発展版:Modelによるfunctional API

少しニューラルネットワークの構成が複雑になったときに使うのがこちら。 枝分かれしたりするネットワークや、ロスが複数あるような場合にも対応可能。 ちなみにtf.keras.kayers.Desne()などにはactivationという引数があり、ここで活性化関数を指定することができる。

 

inputs = tf.keras.Input(shape=(500,))
x = tf.keras.layers.Dense(32, activation=tf.nn.relu)(inputs)
outputs = tf.keras.layers.Dense(32, activation=tf.nn.softmax)(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
model.compile(optimizer=optimizer, loss=loss)
model.fit(x, y, batch_size=32, epochs=10)

  

上記ではactivation=tf.nn.reluだが、activation=tf.keras.activations.reluでもactivation='relu'でもいける(ハズ)。

 

Eagerの登場によって…!

Pythonのclassとしての作り方

これはPyTorchやChainerでのネットワークの作り方とほぼ同じです。

 

class MyModel(tf.keras.Model):

    def __init__(self):
        super(MyModel, self).__init__()
        self.dense1 = tf.keras.layers.Dense(32, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(32, activation=tf.nn.softmax)

    def call(self, inputs):
        x = self.dense1(inputs)
        return self.dense2(x)

model = MyModel()
model.compile(optimizer=optimizer, loss=loss)
model.fit(x, y, batch_size=32, epochs=10)

 

という書き方ができるようになりました。callの部分は自由自在に書けますが、あくまでDefine and Runであることに注意してください。 functional APIの書き方を少し変えて、使う層を__init__()で準備しておき、call()で実際にグラフを書くというイメージになります。

 

正直functional APIに慣れている人はそれで良いような気がしますね。

ちなみにドロップアウトなどのように、training時とevaluation時で振るまいが変わるような処理が入る場合は、 以下のようにcall()メソッドにtraining引数を与えておけば良いようです。

 

class MyModel(tf.keras.Model):

    def __init__(self):
        super(MyModel, self).__init__()
        self.dense1 = tf.keras.layers.Dense(32, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(32, activation=tf.nn.softmax)
        self.dropout = tf.keras.layers.Dropout(0.5)

    def call(self, inputs, training=False):
        x = self.dense1(inputs)
        if training:
            x = self.dropout(x, training=training)
    return self.dense2(x)

model = MyModel()

 

Eagerモードとしての書き方

先ほどの書き方はEagerモードを使うときに非常に重要な役割を担います。 というかもはやPyTorch的に書くための物と思って構わないでしょう。

 

class MyModel(tf.keras.Model):

    def __init__(self):
        super(MyModel, self).__init__()
        self.dense1 = tf.keras.layers.Dense(32, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(32, activation=tf.nn.softmax)

    def call(self, inputs):
        x = self.dense1(inputs)
        return self.dense2(x)

model = MyModel()
tf.enable_eager_execution()

 

tf.enable_eager_execution()はいつ唱えても良いのですが、1つのセッションに対して1回切りです。 コレを唱えた後は、ずっとそのセッションでTensorFlowはDefine by Runとして動きます。

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com

   

eagerモードで使う場合、ドロップアウトなどのような処理は自分で分岐させねばならないかもしれません。 ただ以下の記事のコードの様に、PyTorchのようにeval()メソッドやtrain()メソッドを追加してやれば普通に動きました(ただしこれは、TensorFlow1.5だったとき。tf.contrib.eager.Networkクラスを継承している。多分、正式にEagerモードがcontribから外れて、tf.keras.Modelで書けるようになった際に、何らかの便利機能が入っているはずです…多分)。

 

s0sem0y.hatenablog.com

確率的なニューラルネットワーク

Edward2がTensorFlow probabiltyとしてTensorFlowの仲間入りしたことはご存知でしょうか。 Edwardは従来のTensorFlowをバックエンドに、確率モデリングとそのニューラルネットワークへの応用を支援するライブラリでした。

 

例えばGANのように乱数を用いるニューラルネットワークを容易に実装できたり、パラメータを確率変数として扱うようなベイジアンの記述も可能でした。

 

s0sem0y.hatenablog.com

 

今回、TF probabilityとして確率推論系が(Edward2)含めTFに正式に加わったことで、どうやら正式にTFの特徴となっているEagerモードへの対応も進んでいる様子です(おそらく…?)

TensorFlow probabilityはまだnightlyとしてインストールができる状態であり、まだまだ正式リリースという段階ではなさそうですが、 以下のように、確率変数としてのパラメータを持つ層を提供するtfp.layersなるものの存在と、それがEagerモードで動作することが報告されています。

 

class MNISTModel(tf.keras.Model):
    def __init__(self):
        super(MNISTModel, self).__init__()
        self.dense1 = tfp.layers.DenseFlipout(units=10)
        self.dense2 = tfp.layers.DenseFlipout(units=10)
    def call(self, input):
        """Run the model."""
        result = self.dense1(input)
        result = self.dense2(result)
        # reuse variables from dense2 layer
        result = self.dense2(result)  
    return result
model = MNISTModel()

 

完全に、確率推論系もTensorFlowががっちり握り始めそうな雰囲気です。

 

ちなみにPyMC4もTensorFlowの肩に乗るとかなんとか…!