テンソルフローを使用してテキストを生成したいと思い、LSTMチュートリアルを変更しています( https://www.tensorflow.org/versions/master/tutorials/recurrent/index.html#recurrent-neural-networks =)これを行うためのコードですが、私の最初の解決策は意味をなさないようです。長時間トレーニングした後でも、改善されません。理由がわかりません。アイデアは、ゼロマトリックスから始めて、一度に1つの単語を生成することです。
これは、以下の2つの関数を追加したコードです https://tensorflow.googlesource.com/tensorflow/+/master/tensorflow/models/rnn/ptb/ptb_Word_lm.py
ジェネレータは次のようになります
def generate_text(session,m,eval_op):
state = m.initial_state.eval()
x = np.zeros((m.batch_size,m.num_steps), dtype=np.int32)
output = str()
for i in xrange(m.batch_size):
for step in xrange(m.num_steps):
try:
# Run the batch
# targets have to bee set but m is the validation model, thus it should not train the neural network
cost, state, _, probabilities = session.run([m.cost, m.final_state, eval_op, m.probabilities],
{m.input_data: x, m.targets: x, m.initial_state: state})
# Sample a Word-id and add it to the matrix and output
Word_id = sample(probabilities[0,:])
output = output + " " + reader.Word_from_id(Word_id)
x[i][step] = Word_id
except ValueError as e:
print("ValueError")
print(output)
変数「probabilities」をptb_modelに追加しましたが、これは単にロジットのソフトマックスです。
self._probabilities = tf.nn.softmax(logits)
そしてサンプリング:
def sample(a, temperature=1.0):
# helper function to sample an index from a probability array
a = np.log(a) / temperature
a = np.exp(a) / np.sum(np.exp(a))
return np.argmax(np.random.multinomial(1, a, 1))
私はまったく同じ目標に向かって取り組んできましたが、それを機能させることができました。ここには多くの正しい変更がありますが、いくつかの手順を逃したと思います。
まず、テキストを生成するには、単一のタイムステップのみを表す別のバージョンのモデルを作成する必要があります。その理由は、モデルの次のステップに出力する前に、各出力yをサンプリングする必要があるためです。これを行うには、_num_steps
_と_batch_size
_の両方を1に設定する新しい構成を作成しました。
_class SmallGenConfig(object):
"""Small config. for generation"""
init_scale = 0.1
learning_rate = 1.0
max_grad_norm = 5
num_layers = 2
num_steps = 1 # this is the main difference
hidden_size = 200
max_Epoch = 4
max_max_Epoch = 13
keep_prob = 1.0
lr_decay = 0.5
batch_size = 1
vocab_size = 10000
_
また、次の行を使用してモデルに確率を追加しました。
_self._output_probs = tf.nn.softmax(logits)
_
そして
_@property
def output_probs(self):
return self._output_probs
_
次に、私のgenerate_text()
関数にはいくつかの違いがあります。 1つ目は、保存したモデルパラメータをtf.train.Saver()
オブジェクトを使用してディスクからロードすることです。上記の新しい構成でPTBModelをインスタンス化した後にこれを行うことに注意してください。
_def generate_text(train_path, model_path, num_sentences):
gen_config = SmallGenConfig()
with tf.Graph().as_default(), tf.Session() as session:
initializer = tf.random_uniform_initializer(-gen_config.init_scale,
gen_config.init_scale)
with tf.variable_scope("model", reuse=None, initializer=initializer):
m = PTBModel(is_training=False, config=gen_config)
# Restore variables from disk.
saver = tf.train.Saver()
saver.restore(session, model_path)
print("Model restored from file " + model_path)
_
2番目の違いは、IDからWord文字列へのルックアップテーブルを取得することです(この関数を作成する必要がありました。以下のコードを参照してください)。
_ words = reader.get_vocab(train_path)
_
私はあなたと同じ方法で初期状態を設定しますが、それから私は異なる方法で初期トークンを設定します。 「文の終わり」トークンを使用して、適切な種類の単語で文を開始したいと思います。 Wordインデックスを調べたところ、_<eos>
_にインデックス2(決定論的)があることがわかったので、それをハードコーディングしました。最後に、1x1 Numpy Matrixでラップして、モデル入力。
_ state = m.initial_state.eval()
x = 2 # the id for '<eos>' from the training set
input = np.matrix([[x]]) # a 2D numpy matrix
_
最後に、これが文を生成する部分です。 session.run()
に_output_probs
_と_final_state
_を計算するように指示していることに注意してください。そして、それに入力と状態を与えます。最初の反復では、入力は_<eos>
_であり、状態は_initial_state
_ですが、後続の反復では、最後にサンプリングされた出力を入力として指定し、最後の反復から状態を渡します。 words
リストを使用して、出力インデックスからWord文字列を検索することにも注意してください。
_ text = ""
count = 0
while count < num_sentences:
output_probs, state = session.run([m.output_probs, m.final_state],
{m.input_data: input,
m.initial_state: state})
x = sample(output_probs[0], 0.9)
if words[x]=="<eos>":
text += ".\n\n"
count += 1
else:
text += " " + words[x]
# now feed this new Word as input into the next iteration
input = np.matrix([[x]])
_
次に、蓄積したテキストを印刷するだけです。
_ print(text)
return
_
generate_text()
関数については以上です。
最後に、reader.pyに置いたget_vocab()
の関数定義を示します。
_def get_vocab(filename):
data = _read_words(filename)
counter = collections.Counter(data)
count_pairs = sorted(counter.items(), key=lambda x: (-x[1], x[0]))
words, _ = list(Zip(*count_pairs))
return words
_
最後に行う必要があるのは、トレーニング後にモデルを保存できるようにすることです。これは次のようになります。
_save_path = saver.save(session, "/tmp/model.ckpt")
_
これが、後でテキストを生成するときにディスクからロードするモデルです。
もう1つの問題がありました。それは、Tensorflowソフトマックス関数によって生成された確率分布の合計が正確に1.0にならない場合があることです。合計が1.0より大きい場合、np.random.multinomial()
はエラーをスローします。そのため、次のような独自のサンプリング関数を作成する必要がありました。
_def sample(a, temperature=1.0):
a = np.log(a) / temperature
a = np.exp(a) / np.sum(np.exp(a))
r = random.random() # range: [0,1)
total = 0.0
for i in range(len(a)):
total += a[i]
if total>r:
return i
return len(a)-1
_
これらすべてをまとめると、小さなモデルは私にいくつかのクールな文章を生成することができました。幸運を。
私はあなたのコードを使用します、それは正しくないようです。少し変更しましたが、うまくいったようです。これが私のコードですが、それが正しいかどうかはわかりません。
def generate_text(session,m,eval_op, Word_list):
output = []
for i in xrange(20):
state = m.initial_state.eval()
x = np.zeros((1,1), dtype=np.int32)
y = np.zeros((1,1), dtype=np.int32)
output_str = ""
for step in xrange(100):
if True:
# Run the batch
# targets have to bee set but m is the validation model, thus it should not train the neural network
cost, state, _, probabilities = session.run([m.cost, m.final_state, eval_op, m.probabilities],
{m.input_data: x, m.targets: y, m.initial_state: state})
# Sample a Word-id and add it to the matrix and output
Word_id = sample(probabilities[0,:])
if (Word_id<0) or (Word_id > len(Word_list)):
continue
#print(Word_id)
output_str = output_str + " " + Word_list[Word_id]
x[0][0] = Word_id
print(output_str)
output.append(output_str)
return output