機能APIガイドライン

Keras関数型APIを使ってみる

Keras関数APIは、複雑なモデル(多出力モデル、有向非巡回グラフ、共有レイヤーを持つモデルなど)を定義するためのメソッドです。

ドキュメンテーションのこの部分は、Sequential シーケンシャルモデルに精通していることを前提としています 

いくつかの簡単な例から始めましょう。


例1:完全に接続されたネットワーク

Sequential この種のネットワークを実装するには、モデルの方が適している場合がありますが、この例は、簡単な理解に役立ちます。

  • ネットワークレイヤーインスタンスは呼び出し可能で、テンソルをパラメーターとして取り、テンソルを返します
  • 入力と出力は両方ともテンソルであり、どちらもモデルの定義に使用できます(Model
  • このモデルSequential は、Keras  モデルのようにトレーニングできます
from keras.layers import Input, Dense
from keras.models import Model

# 这部分返回一个张量
inputs = Input(shape=(784,))

# 层的实例是可调用的,它以张量为参数,并且返回一个张量
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)

# 这部分创建了一个包含输入层和三个全连接层的模型
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(data, labels)  # 开始训练

ネットワーク層と同様に、すべてのモデルが呼び出し可能です

関数型APIを使用すると、トレーニング済みモデルを簡単に再利用できます。任意のモデルをレイヤーと見なし、テンソルを渡して呼び出すことができます。モデルを呼び出すときは、モデルの構造だけでなく、その重みも再利用することに注意してください

x = Input(shape=(784,))
# 这是可行的,并且返回上面定义的 10-way softmax。
y = model(x)

このアプローチにより、シーケンス入力を処理できるモデルをすばやく作成できます1行のコードで、画像分類モデルを動画分類モデルに変換できます。

from keras.layers import TimeDistributed

# 输入张量是 20 个时间步的序列,
# 每一个时间为一个 784 维的向量
input_sequences = Input(shape=(20, 784))

# 这部分将我们之前定义的模型应用于输入序列中的每个时间步。
# 之前定义的模型的输出是一个 10-way softmax,
# 因而下面的层的输出将是维度为 10 的 20 个向量的序列。
processed_sequences = TimeDistributed(model)(input_sequences)

複数入力複数出力モデル

以下は、機能的なAPIの良い例です:複数の入力と出力を持つモデル。機能APIを使用すると、多数のインターリーブされたデータストリームを簡単に処理できます。

次のモデルを考えます。Twitterでのニュースのヘッドラインの再投稿といいねの数を予測しようとしました。モデルのメイン入力は一連の単語であるニュースヘッドライン自体ですが、興味を追加するために、モデルはニュースヘッドラインの時間などの追加データを受け取るために他の補助入力も追加します。このモデルは、2つの損失関数を通じて教師あり学習も実行します。以前のモデルで主要な損失関数を使用することは、ディープラーニングモデルに適した通常の方法です。

モデルの構造を以下に示します。

多入力多出力グラフ

機能的なAPIで実装しましょう。

主な入力は、整数のシーケンスであるニュースの見出し自体を受け取ることです(各整数は単語をエンコードします)。これらの整数は1〜10,000(10,000語の語彙)で、シーケンスの長さは100語です。

from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model

# 标题输入:接收一个含有 100 个整数的序列,每个整数在 1 到 10000 之间。
# 注意我们可以通过传递一个 "name" 参数来命名任何层。
main_input = Input(shape=(100,), dtype='int32', name='main_input')

# Embedding 层将输入序列编码为一个稠密向量的序列,
# 每个向量维度为 512。
x = Embedding(output_dim=512, input_dim=10000, input_length=100)(main_input)

# LSTM 层把向量序列转换成单个向量,
# 它包含整个序列的上下文信息
lstm_out = LSTM(32)(x)

ここでは、補助損失を挿入しているため、モデルの主損失が大きい場合でも、LSTM層と埋め込み層をスムーズにトレーニングできます。

auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)

この時点で、補助入力データをLSTM層の出力に接続し、モデルに入力します。

auxiliary_input = Input(shape=(5,), name='aux_input')
x = keras.layers.concatenate([lstm_out, auxiliary_input])

# 堆叠多个全连接网络层
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)

# 最后添加主要的逻辑回归层
main_output = Dense(1, activation='sigmoid', name='main_output')(x)

次に、2つの入力と2つの出力を持つモデルを定義します。

model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])

ここでモデルをコンパイルし、0.2の重みを補助損失に割り当てます。あなたは別の異なる出力を指定したい場合  loss_weights や  loss、リストや辞書を使用して。ここではloss 、単一の損失関数を  パラメーターに渡し、この損失がすべての出力に使用されます。

model.compile(optimizer='rmsprop', loss='binary_crossentropy',
              loss_weights=[1., 0.2])

入力配列とターゲット配列のリストを渡すことにより、モデルをトレーニングできます。

model.fit([headline_data, additional_data], [labels, labels],
          epochs=50, batch_size=32)

入力と出力の両方に名前が付けられているため(定義中にname パラメーターが渡されました  )、次の方法でモデルをコンパイルすることもできます。

model.compile(optimizer='rmsprop',
              loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
              loss_weights={'main_output': 1., 'aux_output': 0.2})

# 然后使用以下方式训练:
model.fit({'main_input': headline_data, 'aux_input': additional_data},
          {'main_output': labels, 'aux_output': labels},
          epochs=50, batch_size=32)

共有ネットワーク層

機能APIのもう1つの用途は、共有ネットワーク層モデルを使用することです。共有レイヤーを見てみましょう。

Twitterのツイートデータセットを考えてみましょう。2つのツイートが同じ人物からのものかどうかを区別するためのモデルを構築したいと考えています(たとえば、ツイートの類似性によってユーザーを比較します)。

この目標を達成する1つの方法は、モデルを作成し、2つのツイートを2つのベクトルにエンコードし、それらのベクトルを接続してから、ロジスティック回帰レイヤーを追加することです。これにより、2つのツイートが同じ作成者からのものである確率が出力されます。モデルは、ペアで表現されたTwitterデータのペアを受け取ります。

この問題は対称的であるため、最初のツイートをエンコードするメカニズムを完全に再利用して、2番目のツイート(重みとその他すべて)をエンコードする必要があります。ここでは、共有LSTMレイヤーを使用してツイートをエンコードします。

関数型APIを使用してビルドしてみましょう。最初に、Twitterをサイズの(280, 256) マトリックスに変換します  。つまり、各Twitterには280文字が含まれ、各文字は256次元のワンホットエンコーディングベクトルです(256の共通文字を取る)。

import keras
from keras.layers import Input, LSTM, Dense
from keras.models import Model

tweet_a = Input(shape=(280, 256))
tweet_b = Input(shape=(280, 256))

異なる入力で同じレイヤーを共有するには、レイヤーを一度インスタンス化し、必要に応じて必要な入力を渡します。

# 这一层可以输入一个矩阵,并返回一个 64 维的向量
shared_lstm = LSTM(64)

# 当我们重用相同的图层实例多次,图层的权重也会被重用 (它其实就是同一层)
encoded_a = shared_lstm(tweet_a)
encoded_b = shared_lstm(tweet_b)

# 然后再连接两个向量:
merged_vector = keras.layers.concatenate([encoded_a, encoded_b], axis=-1)

# 再在上面添加一个逻辑回归层
predictions = Dense(1, activation='sigmoid')(merged_vector)

# 定义一个连接推特输入和预测的可训练的模型
model = Model(inputs=[tweet_a, tweet_b], outputs=predictions)

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.fit([data_a, data_b], labels, epochs=10)

少し立ち止まって、共有レイヤーの出力または出力サイズを読み取る方法を見てみましょう。


レイヤー「ノード」の概念

入力でレイヤーを呼び出すたびに、新しいテンソル(レイヤーの出力)を作成し、レイヤーに「ノード」を追加して、入力テンソルを出力テンソルに接続します。同じレイヤーを複数回呼び出す場合、レイヤーには複数のノードインデックス(0、1、2 ...)があります。

Kerasの以前のバージョンで  layer.get_output() は、レイヤーインスタンスの出力テンソルをlayer.output_shape 取得したり、その出力形状を取得したりできます  今、あなたはまだ(に加えて、それを行うことができ  get_output() 、すでに  output 属性置換)。しかし、レイヤーが複数の入力に接続されている場合はどうなりますか?

レイヤーが1つの入力のみに接続されている限り、混乱.output はなく、レイヤーの唯一の出力が返されます。

a = Input(shape=(280, 256))

lstm = LSTM(32)
encoded_a = lstm(a)

assert lstm.output == encoded_a

ただし、このレイヤーに複数の入力がある場合、問題が発生します。

a = Input(shape=(280, 256))
b = Input(shape=(280, 256))

lstm = LSTM(32)
encoded_a = lstm(a)
encoded_b = lstm(b)

lstm.output
>> AttributeError: Layer lstm_1 has multiple inbound nodes,
hence the notion of "layer output" is ill-defined.
Use `get_output_at(node_index)` instead.

まあ、それは次の方法で解決できます:

assert lstm.get_output_at(0) == encoded_a
assert lstm.get_output_at(1) == encoded_b

簡単ですよね?

input_shape そして、  output_shape これら二つの特性はまた、真である:層は、一つのノードのみで、または限り、すべてのノードが同じ入力/出力サイズを持っているように、その後、「レイヤ出力/入力サイズ」の概念が明確に定義されることになる、となります限り  layer.output_shape /  layer.input_shape リターン。ただし、たとえば、Conv2D 最初にレイヤー(32,32,3) をsizeの入力に適用し、次にsizeの  入力に  適用する場合  (64, 64, 3) 、このレイヤーには複数の入力/出力サイズがあり、それらが属するノードのインデックスを指定して取得する必要があります。彼らは:

a = Input(shape=(32, 32, 3))
b = Input(shape=(64, 64, 3))

conv = Conv2D(16, (3, 3), padding='same')
conved_a = conv(a)

# 到目前为止只有一个输入,以下可行:
assert conv.input_shape == (None, 32, 32, 3)

conved_b = conv(b)
# 现在 `.input_shape` 属性不可行,但是这样可以:
assert conv.get_input_shape_at(0) == (None, 32, 32, 3)
assert conv.get_input_shape_at(1) == (None, 64, 64, 3)

その他の例

コード例は開始するための最良の方法であるため、ここにさらに例を示します。

開始モデル

Inception構造の詳細については、「たたみ込みでさらに深く」を参照してください 

from keras.layers import Conv2D, MaxPooling2D, Input

input_img = Input(shape=(256, 256, 3))

tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)

tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)

tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)

output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)

畳み込み層の残余の接続

残差ネットワークの詳細については、画像認識のためのディープ残差学習を参照してください 

from keras.layers import Conv2D, Input

# 输入张量为 3 通道 256x256 图像
x = Input(shape=(256, 256, 3))
# 3 输出通道(与输入通道相同)的 3x3 卷积核
y = Conv2D(3, (3, 3), padding='same')(x)
# 返回 x + y
z = keras.layers.add([x, y])

共有ビジュアルモデル

モデルは、両方の入力で同じ画像処理モジュールを再利用して、2つのMNIST番号が同じかどうかを判断します。

from keras.layers import Conv2D, MaxPooling2D, Input, Dense, Flatten
from keras.models import Model

# 首先,定义视觉模型
digit_input = Input(shape=(27, 27, 1))
x = Conv2D(64, (3, 3))(digit_input)
x = Conv2D(64, (3, 3))(x)
x = MaxPooling2D((2, 2))(x)
out = Flatten()(x)

vision_model = Model(digit_input, out)

# 然后,定义区分数字的模型
digit_a = Input(shape=(27, 27, 1))
digit_b = Input(shape=(27, 27, 1))

# 视觉模型将被共享,包括权重和其他所有
out_a = vision_model(digit_a)
out_b = vision_model(digit_b)

concatenated = keras.layers.concatenate([out_a, out_b])
out = Dense(1, activation='sigmoid')(concatenated)

classification_model = Model([digit_a, digit_b], out)

視覚的な質問応答モデル

写真に関する自然言語の質問について尋ねられると、モデルは答える正しい単語を選択できます。

質問と画像をベクトルにエンコードしてから2つを接続し、ロジスティック回帰をトレーニングして語彙から可能な単語を選択して回答します。

from keras.layers import Conv2D, MaxPooling2D, Flatten
from keras.layers import Input, LSTM, Embedding, Dense
from keras.models import Model, Sequential

# 首先,让我们用 Sequential 来定义一个视觉模型。
# 这个模型会把一张图像编码为向量。
vision_model = Sequential()
vision_model.add(Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=(224, 224, 3)))
vision_model.add(Conv2D(64, (3, 3), activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
vision_model.add(Conv2D(128, (3, 3), activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
vision_model.add(Conv2D(256, (3, 3), activation='relu'))
vision_model.add(Conv2D(256, (3, 3), activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Flatten())

# 现在让我们用视觉模型来得到一个输出张量:
image_input = Input(shape=(224, 224, 3))
encoded_image = vision_model(image_input)

# 接下来,定义一个语言模型来将问题编码成一个向量。
# 每个问题最长 100 个词,词的索引从 1 到 9999.
question_input = Input(shape=(100,), dtype='int32')
embedded_question = Embedding(input_dim=10000, output_dim=256, input_length=100)(question_input)
encoded_question = LSTM(256)(embedded_question)

# 连接问题向量和图像向量:
merged = keras.layers.concatenate([encoded_question, encoded_image])

# 然后在上面训练一个 1000 词的逻辑回归模型:
output = Dense(1000, activation='softmax')(merged)

# 最终模型:
vqa_model = Model(inputs=[image_input, question_input], outputs=output)

# 下一步就是在真实数据上训练模型。

ビデオQ&Aモデル

画像の質問応答モデルをトレーニングしたので、それをビデオの質問応答モデルにすばやく変換できます。適切なトレーニングを行うと、短いビデオ(たとえば、100フレームの人間の動き)を見せて、ビデオについて質問することができます(たとえば、「この人はどのスポーツをしているのですか?」->「サッカー」など)。 )。

from keras.layers import TimeDistributed

video_input = Input(shape=(100, 224, 224, 3))
# 这是基于之前定义的视觉模型(权重被重用)构建的视频编码
encoded_frame_sequence = TimeDistributed(vision_model)(video_input)  # 输出为向量的序列
encoded_video = LSTM(256)(encoded_frame_sequence)  # 输出为一个向量

# 这是问题编码器的模型级表示,重复使用与之前相同的权重:
question_encoder = Model(inputs=question_input, outputs=encoded_question)

# 让我们用它来编码这个问题:
video_question_input = Input(shape=(100,), dtype='int32')
encoded_video_question = question_encoder(video_question_input)

# 这就是我们的视频问答模式:
merged = keras.layers.concatenate([encoded_video, encoded_video_question])
output = Dense(1000, activation='softmax')(merged)
video_qa_model = Model(inputs=[video_input, video_question_input], outputs=output)

 

130の元の記事が発行されました 30のように 訪問40,000+

おすすめ

転載: blog.csdn.net/W_H_M_2018/article/details/105547631