2016-04-13 22 views
13

Ich möchte Tensorflow verwenden, um Text zu generieren, und habe den LSTM-Lernprogrammcode (https://www.tensorflow.org/versions/master/tutorials/recurrent/index.html#recurrent-neural-networks) geändert, um dies zu tun, aber meine ursprüngliche Lösung scheint Unsinn zu erzeugen, auch nach dem Training für eine lange Zeit, Es verbessert sich nicht. Ich verstehe nicht warum. Die Idee ist, mit einer Nullmatrix zu beginnen und dann ein Wort zu einem Zeitpunkt zu erzeugen.TensorFlow mit LSTMs zum Generieren von Text

Dies ist der Code, an dem ich die beiden folgenden Funktionen https://tensorflow.googlesource.com/tensorflow/+/master/tensorflow/models/rnn/ptb/ptb_word_lm.py

Der Generator als

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) 

ich die Variable „Wahrscheinlichkeiten“ der ptb_model hinzugefügt folgt aussieht hinzugefügt haben und es ist einfach ein softmax über den logits.

self._probabilities = tf.nn.softmax(logits) 

Und die Probenahme:

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)) 

Antwort

0

ich Ihren Code verwenden, scheint es nicht richtig. Also ändere ich es etwas, es scheint Arbeit. Hier ist mein Code, und ich bin nicht sicher, es ist richtig:

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 
17

Ich habe in Richtung auf das exakt gleiche Ziel hinarbeiten, und bekam es einfach zu arbeiten. Sie haben viele der richtigen Modifikationen hier, aber ich denke, Sie haben ein paar Schritte verpasst.

Zuerst müssen Sie zum Generieren von Text eine andere Version des Modells erstellen, die nur einen einzigen Zeitschritt darstellt. Der Grund ist, dass wir jede Ausgabe y abtasten müssen, bevor wir sie in den nächsten Schritt des Modells einspeisen können. Ich tat dies, indem sie eine neue Konfiguration zu machen, die setzen num_steps und batch_size beide gleich 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 

ich auch eine Wahrscheinlichkeit auf das Modell mit diesen Zeilen hinzugefügt:

self._output_probs = tf.nn.softmax(logits) 

und

@property 
def output_probs(self): 
    return self._output_probs 

Dann gibt es ein paar Unterschiede in meiner generate_text() Funktion. Der erste ist, dass ich gespeicherte Modellparameter von der Festplatte mit dem Objekt tf.train.Saver() lade. Beachten Sie, dass wir dies tun, nachdem Sie das PTBModel mit der neuen Konfiguration von oben instanziiert haben.

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) 

Der zweite Unterschied ist, dass ich die Lookup-Tabelle von ids zu Wortketten (ich hatte diese Funktion zu schreiben, den Code unten).

words = reader.get_vocab(train_path) 

habe ich den Anfangszustand die gleiche Art und Weise bis Sie tun, aber dann habe ich die Anfangs Token in einer anderen Art und Weise auf. Ich möchte den "Satzende" -Token verwenden, damit ich meinen Satz mit den richtigen Wortarten starten kann. Ich schaute durch den Wortindex und fand heraus, dass <eos> zufällig Index 2 (deterministisch) hat, also habe ich das nur hart-codiert. Schließlich wickle ich es in eine 1x1 Numpy Matrix, so dass es der richtige Typ für die Modelleingaben ist.

state = m.initial_state.eval() 
    x = 2 # the id for '<eos>' from the training set 
    input = np.matrix([[x]]) # a 2D numpy matrix 

Schließlich ist hier der Teil, wo wir Sätze generieren.Beachten Sie, dass wir session.run() mitteilen, um die output_probs und die final_state zu berechnen. Und wir geben ihm den Input und den Zustand. In der ersten Iteration ist der Eingang <eos> und der Zustand ist initial_state, aber bei nachfolgenden Iterationen geben wir als Eingabe unsere letzte abgetastete Ausgabe an, und wir übergeben den Zustand von der letzten Iteration her. Beachten Sie auch, dass wir die words-Liste verwenden, um die Wortzeichenfolge aus dem Ausgabe-Index nachzuschlagen.

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]]) 

Dann müssen wir nur den Text drucken, den wir gesammelt haben.

print(text) 
    return 

Das ist es für die generate_text() Funktion.

Schließlich, lassen Sie mich Ihnen die Funktionsdefinition für get_vocab(), die ich in reader.py eingegeben.

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 

Das letzte, was Sie tun müssen, ist in der Lage sein, das Modell es nach dem Training zu speichern, die

save_path = saver.save(session, "/tmp/model.ckpt") 

wie

aussieht Und das ist das Modell, das Sie von der Festplatte später geladen werden beim Generieren Text.

Es gab ein weiteres Problem: Ich fand, dass manchmal die Wahrscheinlichkeitsverteilung, die durch die Tensorflow softmax Funktion erzeugt wurde, nicht genau zu 1.0 summierte. Wenn die Summe größer als 1.0 war, gibt np.random.multinomial() einen Fehler aus. So hatte ich meine eigene Sampling-Funktion zu schreiben, die wie dieser

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 

sieht Wenn Sie das alles zusammen, das kleine Modell konnte mir ein paar coole Sätze erzeugen. Viel Glück.

Verwandte Themen