example - lstm tensorflow
TensorFlow utilizando LSTM para generar texto (2)
Uso tu código, parece no estar bien. Así que lo modifico un poco, parece que funciona. Aquí está mi código, y no estoy seguro de que sea correcto:
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
Me gustaría usar tensorflow para generar texto y he estado modificando el tutorial LSTM ( https://www.tensorflow.org/versions/master/tutorials/recurrent/index.html#recurrent-neural-networks ) código para hacer esto, sin embargo, mi solución inicial parece generar tonterías, incluso después de entrenar durante mucho tiempo, no mejora. No veo por qué. La idea es comenzar con una matriz cero y luego generar una palabra a la vez.
Este es el código, al que he agregado las dos funciones a continuación https://tensorflow.googlesource.com/tensorflow/+/master/tensorflow/models/rnn/ptb/ptb_word_lm.py
El generador se ve de la siguiente manera
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)
He agregado la variable "probabilidades" al ptb_model y es simplemente un softmax sobre los logits.
self._probabilities = tf.nn.softmax(logits)
Y el muestreo:
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))
He estado trabajando para lograr exactamente el mismo objetivo, y simplemente lo he puesto a funcionar. Aquí tienes muchas de las modificaciones correctas, pero creo que te perdiste unos pasos.
En primer lugar, para generar texto, necesita crear una versión diferente del modelo que represente solo un solo paso de tiempo. La razón es que tenemos que muestrear cada salida y antes de poder alimentarla en el próximo paso del modelo. Lo hice creando una nueva configuración que establece num_steps
y batch_size
ambos iguales a 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
También agregué las probabilidades al modelo con estas líneas:
self._output_probs = tf.nn.softmax(logits)
y
@property
def output_probs(self):
return self._output_probs
Entonces, hay algunas diferencias en mi función generate_text()
. El primero es que tf.train.Saver()
los parámetros del modelo guardado del disco usando el objeto tf.train.Saver()
. Tenga en cuenta que hacemos esto luego de crear una instancia del PTBModel con la nueva configuración desde arriba.
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)
La segunda diferencia es que obtengo la tabla de búsqueda de identificadores a cadenas de palabras (tuve que escribir esta función, ver el código a continuación).
words = reader.get_vocab(train_path)
Configuré el estado inicial de la misma manera que tú, pero luego configuro el token inicial de una manera diferente. Quiero usar el token de "fin de oración" para poder comenzar mi oración con los tipos de palabras correctos. Miré a través del índice de palabras y encontré que <eos>
tiene el índice 2 (determinístico), así que lo codifiqué. Finalmente, lo envuelvo en una Matriz Numpy 1x1 para que sea el tipo correcto para las entradas del modelo .
state = m.initial_state.eval()
x = 2 # the id for ''<eos>'' from the training set
input = np.matrix([[x]]) # a 2D numpy matrix
Finalmente, aquí está la parte donde generamos oraciones. Tenga en cuenta que le decimos a session.run()
que calcule los output_probs
y el final_state
. Y le damos la entrada y el estado. En la primera iteración, la entrada es <eos>
y el estado es el initial_state
, pero en iteraciones posteriores damos como entrada nuestro último resultado de muestra, y pasamos el estado a lo largo de la última iteración. Tenga en cuenta también que usamos la lista de words
para buscar la palabra cadena del índice de salida.
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]])
Entonces, todo lo que tenemos que hacer es imprimir el texto que hemos acumulado.
print(text)
return
Eso es todo por la función generate_text()
.
Finalmente, permítame mostrarle la definición de función para get_vocab()
, que puse en reader.py.
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
Lo último que debe hacer es poder guardar el modelo después de entrenarlo, que se parece a
save_path = saver.save(session, "/tmp/model.ckpt")
Y ese es el modelo que cargarás del disco más adelante cuando generes texto.
Hubo un problema más: descubrí que a veces la distribución de probabilidad producida por la función Tensorflow softmax no sumaba exactamente 1.0. Cuando la suma era mayor que 1.0, np.random.multinomial()
arroja un error. Así que tuve que escribir mi propia función de muestreo, que se parece a esto
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
Cuando reuniste todo esto, el modelo pequeño fue capaz de generarme algunas frases geniales. Buena suerte.