記事ディレクトリ
Andrej Karpathyによって提供されたシェイクスピアの作品のデータセットを「リカレントニューラルネットワークの不合理な有効性」で使用します このデータ(「シェイクスピア」)内の文字のシーケンスを前提として、シーケンス内の次の文字(「e」)を予測するようにモデルをトレーニングします。モデルを繰り返し呼び出すことにより、より長いテキストシーケンスを生成できます。
1.データをインポートする
Tensorflow2.0のデータの読み込みと前処理の方法の要約の 8番目の部分を参照してください:インポートテキスト(テキスト生成用)
2.モデルを作成する
使用tf.keras.Sequentialの定義モデル。この例では、3つのレイヤーを使用してモデルを定義しました。
- tf.keras.layers.Embedding:入力レイヤー。各文字の数をembedding_dim次元のベクトルにマップするトレーニング可能な比較テーブル。
- tf.keras.layers.GRU:サイズがunits = rnn_unitsで指定されるRNNのタイプ。
- tf.keras.layers.Dense:vocab_size出力を持つ出力レイヤー。
vocab_size = len(vocab) # 词集的长度
embedding_dim = 256 # 嵌入的维度
rnn_units = 1024 # RNN 的单元数量
def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
model = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, embedding_dim,
batch_input_shape=[batch_size, None]),
tf.keras.layers.GRU(rnn_units,
return_sequences=True,
stateful=True,
recurrent_initializer='glorot_uniform'),
tf.keras.layers.Dense(vocab_size)
])
return model
model = build_model(vocab_size=len(vocab),
embedding_dim=embedding_dim,
rnn_units=rnn_units,
batch_size=BATCH_SIZE)
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) (64, None, 256) 16640
_________________________________________________________________
gru (GRU) (64, None, 1024) 3938304
_________________________________________________________________
dense (Dense) (64, None, 65) 66625
=================================================================
Total params: 4,021,569
Trainable params: 4,021,569
Non-trainable params: 0
_________________________________________________________________
各文字について、モデルは埋め込みを探し、タイムステップの入力としてGRUを実行し、密層を使用してロジスティック回帰を生成し、次の文字の対数尤度を予測します。
3.トレーニング
3.1モデルをコンパイルする
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy')
3.2構成チェックポイント
# 检查点保存至的目录
checkpoint_dir = './training_checkpoints'
# 检查点的文件名
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt_{epoch}")
checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(
filepath=checkpoint_prefix,
save_weights_only=True)
3.3モデルのトレーニング
history = model.fit(dataset, epochs=examples_per_epoch, callbacks=[checkpoint_callback])
4.予測
次のコードブロックは、テキストの生成に使用されます。
- 最初に開始文字列を設定し、RNN状態を初期化して、生成する文字数を設定します。
- 開始文字列とRNNステータスを使用して、次の文字の予測分布を取得します。
- 次に、分類分布を使用して予測文字のインデックスを計算します。この予測された文字をモデルの次の入力として使用します。
- モデルから返されたRNNステータスは、モデルに送り返されます。現在、モデルには、1人のキャラクターだけではなく、学ぶべきより多くのコンテキストがあります。次の文字を予測した後、変更されたRNN状態は再びモデルに送信されます。これは、以前に予測されたキャラクターから常により多くのコンテキストを取得することで、モデルが学習する方法です。
上の図に示すように、ここで達成したい機能は、n文字のサンプルを入力することです。モデルは、各入力文字の後に1文字、つまり合計n文字を出力し、新しく取得したn文字をEnter、モデルをもう一度入力し、この手順を指定した回数繰り返します。
GRU非表示状態を設定する場合はバッチサイズを指定する必要があるため、モデルが確立された後は、固定バッチサイズのみを受け入れることができます。
異なるbatch_sizeでモデルを実行するには、モデルを再構築し、チェックポイントから重みを復元する必要があります。
4.1モデルの再構築
tf.train.latest_checkpoint(checkpoint_dir)
model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)
model.load_weights(tf.train.latest_checkpoint(checkpoint_dir))
model.build(tf.TensorShape([1, None]))
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_1 (Embedding) (1, None, 256) 16640
_________________________________________________________________
gru_1 (GRU) (1, None, 1024) 3938304
_________________________________________________________________
dense_1 (Dense) (1, None, 65) 66625
=================================================================
Total params: 4,021,569
Trainable params: 4,021,569
Non-trainable params: 0
_________________________________________________________________
4.2テキストを生成する
def generate_text(model, start_string):
# 评估步骤(用学习过的模型生成文本)
# 要生成的字符个数
num_generate = 1000
# 将起始字符串转换为数字(向量化)
input_eval = [char2idx[s] for s in start_string]
input_eval = tf.expand_dims(input_eval, 0)
# 空字符串用于存储结果
text_generated = []
# 这里批大小为 1
model.reset_states()
for i in range(num_generate):
predictions = model(input_eval)
# 删除批次的维度
predictions = tf.squeeze(predictions, 0)
# 用分类分布预测模型返回的字符
predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()
# 把预测字符和前面的隐藏状态一起传递给模型作为下一个输入
input_eval = tf.expand_dims([predicted_id], 0)
text_generated.append(idx2char[predicted_id])
return (start_string + ''.join(text_generated))
print(generate_text(model, start_string=u"ROMEO: "))
ここに7文字を入力すると、モデル出力の形状が(1、7、65)になるたびに、最後の2つの次元(7、65)のみが必要になるため、tf.squeeze関数を使用して最初の次元を削除します。tf.random.categorical関数を使用して各行の最大確率に対応するインデックスを決定し、このインデックスを(最初の次元を追加した後)入力として再入力し、指定した1000文字が予測されるまで上記の手順を繰り返します。
最終結果:
ROMEO: it may be see, I say.
Elong where I have sea loved for such heart
As of all desperate in your colls?
On how much to purwed esumptrues as we,
But taker appearing our great Isabel,;
Of your brother's needs.
I cannot but one hour, by nimwo and ribs
After 't? O Pedur, break our manory,
The shadot bestering eyes write; onfility;
Indeed I am possips And feated with others and throw it?
CAPULET:
O, not the ut with mine own sort.
But, with your souls, sir, well we would he,
And videwith the sungesoy begins, revell;
Much it in secart.
PROSPERO:
Villain, I darry record;
In sea--lodies, nor that I do I were stir,
You appointed with that sed their o tailor and hope left fear'd,
I so; that your looks stand up,
Comes I truly see this last weok not the
sul us.
CAMILLO:
You did and ever sea,
Into these hours: awake! Ro with mine enemies,
Were werx'd in everlawacted man been to alter
As Lewis could smile to his.
Farthus:
Marry! I'll do lose a man see me
To no drinking often hat back on an illing mo