TV script generator

Generate TV script from the Simpsons.

This is longer than the original as I've added intermediate steps. Helper functions are incorporated here rather than being in a separate file.


In [1]:
import os
import pickle
from collections import Counter

import numpy as np

Get data


In [2]:
data_file = './data/simpsons/moes_tavern_lines.txt'

with open(data_file) as inf:
     text= inf.read()

# Ignore the "notice" section
text = text[81:]
print(text[:100])
len(text)


Moe_Szyslak: (INTO PHONE) Moe's Tavern. Where the elite meet to drink.
Bart_Simpson: Eh, yeah, hello
Out[2]:
305189

Explore different parts of the data


In [3]:
view_sentence_range = (0, 10)

In [4]:
# original:
#num_unique_words = len({word: None for word in text.split()})
#print('Roughly the number of unique words: {}'.format()

## Here we use a counter to find the size of the vocab

wc = Counter(text.lower().split())

print('Vocab:', len(wc))
print('Total words:', sum(wc.values()))
print('Common words:', wc.most_common(10), '...')


Vocab: 10347
Total words: 48974
Common words: [('the', 1276), ('i', 1242), ('moe_szyslak:', 1180), ('you', 1069), ('a', 1043), ('homer_simpson:', 975), ('to', 847), ('and', 606), ('of', 480), ('my', 467)] ...

In [5]:
scenes = text.split('\n\n')
print('Number of scenes: {}'.format(len(scenes)))


Number of scenes: 262

In [6]:
sentence_count_scene = [scene.count('\n') for scene in scenes]
print('Average number of sentences in each scene: {}'.format(np.average(sentence_count_scene)))


Average number of sentences in each scene: 15.248091603053435

In [7]:
sentences = [sentence for scene in scenes for sentence in scene.split('\n')]
print('Number of lines: {}'.format(len(sentences)))


Number of lines: 4257

In [8]:
word_count_sentence = [len(sentence.split()) for sentence in sentences]
print('Average number of words in each line: {}'.format(np.average(word_count_sentence)))


Average number of words in each line: 11.50434578341555

In [9]:
print()
print('Sentence {} to {}:'.format(*view_sentence_range))
print()
print('\n'.join(text.split('\n')[view_sentence_range[0]:view_sentence_range[1]]))


Sentence 0 to 10:

Moe_Szyslak: (INTO PHONE) Moe's Tavern. Where the elite meet to drink.
Bart_Simpson: Eh, yeah, hello, is Mike there? Last name, Rotch.
Moe_Szyslak: (INTO PHONE) Hold on, I'll check. (TO BARFLIES) Mike Rotch. Mike Rotch. Hey, has anybody seen Mike Rotch, lately?
Moe_Szyslak: (INTO PHONE) Listen you little puke. One of these days I'm gonna catch you, and I'm gonna carve my name on your back with an ice pick.
Moe_Szyslak: What's the matter Homer? You're not your normal effervescent self.
Homer_Simpson: I got my problems, Moe. Give me another one.
Moe_Szyslak: Homer, hey, you should not drink to forget your problems.
Barney_Gumble: Yeah, you should only drink to enhance your social skills.


Convert vocab to integer representation


In [10]:
# Create vocab_to_int and int_to_vocab.
# This also sorts from most frequent to least frequent.
# For example, integer 0 represents the most frequently used vocab.

vocab_to_int = {}
int_to_vocab = {}

for i, (word, cnt) in enumerate(wc.most_common()):
    vocab_to_int[word] = i
    int_to_vocab[i] = word

In [11]:
[(k, int_to_vocab[k]) for k in list(int_to_vocab.keys())[:5]]


Out[11]:
[(0, 'the'), (1, 'i'), (2, 'moe_szyslak:'), (3, 'you'), (4, 'a')]

In [12]:
[(k, vocab_to_int[k]) for k in list(vocab_to_int.keys())[:5]]


Out[12]:
[('the', 0), ('i', 1), ('moe_szyslak:', 2), ('you', 3), ('a', 4)]

In [13]:
## make it into a function suitable for the original project

def create_lookup_tables(text):
    """
    Create lookup tables for vocabulary
    :param text: The text of tv scripts split into words
    :return: A tuple of dicts (vocab_to_int, int_to_vocab)
    """
    wc = Counter(text)
    
    vocab_to_int = {}
    int_to_vocab = {}
    
    for i, (word, cnt) in enumerate(wc.most_common()):
        vocab_to_int[word] = i
        int_to_vocab[i] = word
        
    return vocab_to_int, int_to_vocab

In [14]:
## quick test

text2 = "today is an interesting day, is it not?"
text_tokens = text2.lower().split()
v2i, i2v = create_lookup_tables(text_tokens)

In [15]:
v2i


Out[15]:
{'an': 2, 'day,': 4, 'interesting': 3, 'is': 0, 'it': 5, 'not?': 6, 'today': 1}

In [16]:
i2v


Out[16]:
{0: 'is', 1: 'today', 2: 'an', 3: 'interesting', 4: 'day,', 5: 'it', 6: 'not?'}

In [17]:
## test with given unit test

import problem_unittests as tests
tests.test_create_lookup_tables(create_lookup_tables)


Tests Passed

tokenize punctuations

We need to distinguish between "bye" and "bye!".

So we will translate punctuations to tokens. For example, change "!" into "||Exclamation_Mark||".

  • Period ( . )
  • Comma ( , )
  • Quotation Mark ( " )
  • Semicolon ( ; )
  • Exclamation mark ( ! )
  • Question mark ( ? )
  • Left Parentheses ( ( )
  • Right Parentheses ( ) )
  • Dash ( -- )
  • Return ( \n )

In [18]:
## the string package has a pre-defined list of punctuations

import string
type(string.punctuation), string.punctuation


Out[18]:
(str, '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~')

In [19]:
## create a dictionary according to project

def token_lookup():
    """
    Generate a dict to turn punctuation into a token.
    :return: Tokenize dictionary where the key is the punctuation and the value is the token
    """
    #import string
    punct_to_token = {'.':'||PERIOD||', 
                      ',':'||COMMA||', 
                      '"':'||QUOTE||', 
                      ';':'||SEMICOLON||', 
                      '!':'||EXCMARK||', 
                      '?':'||Q||', 
                      '(':'||OPENP||', 
                      ')':'||CLOSEP||', 
                      '--':'||DASH||',
                      '\n':'||NEWLINE||'}
    return punct_to_token

In [20]:
# quick test
token_dict = token_lookup()
token_dict


Out[20]:
{'\n': '||NEWLINE||',
 '!': '||EXCMARK||',
 '"': '||QUOTE||',
 '(': '||OPENP||',
 ')': '||CLOSEP||',
 ',': '||COMMA||',
 '--': '||DASH||',
 '.': '||PERIOD||',
 ';': '||SEMICOLON||',
 '?': '||Q||'}

In [21]:
## test with built-in test
tests.test_tokenize(token_lookup)


Tests Passed

Preprocess data


In [22]:
for key, token in token_dict.items():
    text = text.replace(key, ' {} '.format(token))

text = text.lower()
text = text.split()

vocab_to_int, int_to_vocab = create_lookup_tables(text)
int_text = [vocab_to_int[word] for word in text]

with open('preprocess.p', 'wb') as outf:
    pickle.dump((int_text, vocab_to_int, int_to_vocab, token_dict), outf)

In [23]:
len(int_text)


Out[23]:
69100

In [24]:
_ = [print(int_to_vocab[item], end=" ") for item in int_text[:15]]


moe_szyslak: ||openp|| into phone ||closep|| moe's tavern ||period|| where the elite meet to drink ||period|| 

In [25]:
_ = [print(int_to_vocab[item], end=" ") for item in int_text[16:32]]


bart_simpson: eh ||comma|| yeah ||comma|| hello ||comma|| is mike there ||q|| last name ||comma|| rotch ||period|| 

In [26]:
## check current directory
os.listdir('.')


Out[26]:
['preprocess.p',
 '.ipynb_checkpoints',
 'tv_script_generator.ipynb',
 '.gitignore',
 'checkpoint',
 'save.index',
 'save.data-00000-of-00001',
 'save.meta',
 '__pycache__',
 'problem_unittests.py',
 'params.p',
 'data']

Check Point

Simply reload saved files from this point forward.


In [27]:
with open('preprocess.p', mode='rb') as inf:
    int_text, vocab_to_int, int_to_vocab, token_dict = \
        pickle.load(inf)
        
len(int_text), len(vocab_to_int), len(int_to_vocab), len(token_dict)


Out[27]:
(69100, 6779, 6779, 10)

Build NN


In [28]:
from distutils.version import LooseVersion
import warnings
import tensorflow as tf

# Check TensorFlow Version
assert LooseVersion(tf.__version__) >= LooseVersion('1.0'), 'Please use TensorFlow version 1.0 or newer'
print('TensorFlow Version: {}'.format(tf.__version__))

# Check for a GPU
if not tf.test.gpu_device_name():
    warnings.warn('No GPU found. Please use a GPU to train your neural network.')
else:
    print('Default GPU Device: {}'.format(tf.test.gpu_device_name()))


TensorFlow Version: 1.2.1
Default GPU Device: /gpu:0

Input

Create placeholder for inputs:

  • Input text placeholder named "input" using the TF Placeholder name parameter.
  • Targets placeholder.
  • Learning Rate placeholder.

Return the placeholders in the following the tuple (Input, Targets, LearingRate)


In [29]:
def get_inputs():
    """
    Create TF Placeholders for input, targets, and learning rate.
    :return: Tuple (input, targets, learning rate)
    """
    input = tf.placeholder(tf.int32, [None, None], name='input')
    targets = tf.placeholder(tf.int32, [None, None], name='targets')
    learning_rate = tf.placeholder(tf.float32, name='learning_rate')
    return (input, targets, learning_rate)

## supplied tests
tests.test_get_inputs(get_inputs)


Tests Passed

Build RNN Cell and Initialize

Stack one or more BasicLSTMCells in a MultiRNNCell

The Rnn size should be set using rnn_size

  • Initalize Cell State using the MultiRNNCell's zero_state() function
  • Apply the name "initial_state" to the initial state using tf.identity()
  • Return the cell and initial state in the following tuple (Cell, InitialState)

In [30]:
def get_init_cell(batch_size, rnn_size):
    """
    Create an RNN Cell and initialize it.
    :param batch_size: Size of batches
    :param rnn_size: Size of RNNs
    :return: Tuple (cell, initialize state)
    """
    num_layers = 2

    # this doesn't seem to work
    #lstm_layer = tf.contrib.rnn.BasicLSTMCell(rnn_size)
    #cell = tf.contrib.rnn.MultiRNNCell([lstm_layer] * num_layers)
    
    # use staked version instead:
    stacked_rnn = []
    for i in range(num_layers):
        stacked_rnn.append(tf.nn.rnn_cell.LSTMCell(num_units=512, state_is_tuple=True))

    cell = tf.nn.rnn_cell.MultiRNNCell(cells=stacked_rnn, state_is_tuple=True)
    
    # yet another version
    #cell = tf.contrib.rnn.MultiRNNCell([lstm_layer, lstm_layer])
    
    initial_state = cell.zero_state(batch_size, tf.float32)
    initial_state = tf.identity(initial_state, name='initial_state')
    return (cell, initial_state)


tests.test_get_init_cell(get_init_cell)


Tests Passed

Apply word embedding to input


In [31]:
def get_embed(input_data, vocab_size, embed_dim):
    """
    Create embedding for <input_data>.
    :param input_data: TF placeholder for text input.
    :param vocab_size: Number of words in vocabulary.
    :param embed_dim: Number of embedding dimensions
    :return: Embedded input.
    """
    #embedding = tf.Variable(tf.random_uniform((vocab_size, embed_dim), -1, 1))
    #embed = tf.nn.embedding_lookup(embedding, input_data)
    
    embed = tf.contrib.layers.embed_sequence(input_data, 
                                            vocab_size=vocab_size, 
                                            embed_dim=embed_dim)
    return embed


## supplied test
tests.test_get_embed(get_embed)


Tests Passed

Build RNN

You created a RNN Cell in the get_init_cell() function. Time to use the cell to create a RNN.

  • Build the RNN using the tf.nn.dynamic_rnn()
  • Apply the name "final_state" to the final state using tf.identity()
  • Return the outputs and final_state state in the following tuple (Outputs, FinalState)

In [32]:
def build_rnn(cell, inputs):
    """
    Create a RNN using a RNN Cell
    :param cell: RNN Cell
    :param inputs: Input text data
    :return: Tuple (Outputs, Final State)
    """
    outputs, final_state = tf.nn.dynamic_rnn(cell, inputs, dtype=tf.float32)
    final_state = tf.identity(final_state, name="final_state")
    return outputs, final_state


tests.test_build_rnn(build_rnn)


Tests Passed

Build the Neural Network

Apply the functions you implemented above to:

  • Apply embedding to input_data using your get_embed(input_data, vocab_size, embed_dim) function.
  • Build RNN using cell and your build_rnn(cell, inputs) function.
  • Apply a fully connected layer with a linear activation and vocab_size as the number of outputs.

Return the logits and final state in the following tuple (Logits, FinalState)


In [45]:
def build_nn(cell, rnn_size, input_data, vocab_size, embed_dim):
    """
    Build part of the neural network
    :param cell: RNN cell
    :param rnn_size: Size of rnns
    :param input_data: Input data
    :param vocab_size: Vocabulary size
    :return: Tuple (Logits, FinalState)
    """
    embed = get_embed(input_data, vocab_size, embed_dim=embed_dim)
    outputs, final_state = build_rnn(cell, embed)
    #logits = tf.contrib.layers.fully_connected(outputs, vocab_size)
    logits = tf.contrib.layers.fully_connected(outputs, vocab_size, activation_fn=None)
    return logits, final_state


tests.test_build_nn(build_nn)


Tests Passed

In [34]:
def test_get_batches(get_batches):
    with tf.Graph().as_default():
        test_batch_size = 128
        test_seq_length = 5
        test_int_text = list(range(1000*test_seq_length))
        batches = get_batches(test_int_text, test_batch_size, test_seq_length)

        # Check type
        assert isinstance(batches, np.ndarray),\
            'Batches is not a Numpy array'

        # Check shape
        assert batches.shape == (7, 2, 128, 5),\
            'Batches returned wrong shape.  Found {}'.format(batches.shape)

    tests._print_success_message()

Batches

Implement get_batches to create batches of input and targets using int_text. The batches should be a Numpy array with the shape (number of batches, 2, batch size, sequence length). Each batch contains two elements:

  • The first element is a single batch of input with the shape [batch size, sequence length]
  • The second element is a single batch of targets with the shape [batch size, sequence length]

If you can't fill the last batch with enough data, drop the last batch.

For exmple, get_batches([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 2, 3) would return a Numpy array of the following:

[ # First Batch
[ # Batch of Input [[ 1 2 3], [ 7 8 9]], # Batch of targets [[ 2 3 4], [ 8 9 10]] ],

# Second Batch [ # Batch of Input [[ 4 5 6], [10 11 12]], # Batch of targets [[ 5 6 7], [11 12 13]] ] ]


In [35]:
def get_batches(int_text, batch_size, seq_length):
    """
    Return batches of input and target
    :param int_text: Text with the words replaced by their ids
    :param batch_size: The size of batch
    :param seq_length: The length of sequence
    :return: Batches as a Numpy array
    """
    # TODO: Implement Function
    int_text = int_text[16:]
    n_batches = (len(int_text)-1)//(batch_size * seq_length)    
    int_text = int_text[:n_batches * batch_size * seq_length + 1]
    int_text_sequences = [int_text[i*seq_length:i*seq_length+seq_length] for i in range(0, n_batches * batch_size)]
    int_text = int_text[1:]
    int_text_targets = [int_text[i*seq_length:i*seq_length+seq_length] for i in range(0, n_batches * batch_size)]
    output = []
    for batch in range(n_batches):
        inputs = []
        targets = []
        for size in range(batch_size):
            inputs.append(int_text_sequences[size * n_batches + batch])
            targets.append(int_text_targets[size * n_batches + batch])
        output.append([inputs, targets])
    return np.array(output)

## check out why this fails
#tests.test_get_batches(get_batches)
test_get_batches(get_batches)


Tests Passed

NN Training

Tune hyperparameters:

  • Set num_epochs to the number of epochs.
  • Set batch_size to the batch size.
  • Set rnn_size to the size of the RNNs.
  • Set seq_length to the length of sequence.
  • Set learning_rate to the learning rate.
  • Set show_every_n_batches to the number of batches the neural network should print progress.

In [63]:
num_epochs = 120
batch_size = 101
rnn_size = 256
seq_length = 20
learning_rate = 0.01
embed_dim = 300

# Show stats for every n number of batches
show_every_n_batches = 100
#show_every_n_batches= get_batches(int_text, batch_size, seq_length).shape[0]
print(show_every_n_batches)

save_dir = './save'


100

In [64]:
## determine batch size (from someone else)

total_words = len(int_text[16:])
print('total words:', total_words)

print("Batch Size -> words missed\n")

for i in range(-5,5):
    try_batch_size = batch_size + i
    batches = get_batches(int_text, try_batch_size, seq_length)
    flag = ""
    if i == 0:
        flag = "<<< Current choice. Should be minimum words missed."
    print("{:>10}   {:>5} {}".format(try_batch_size, total_words - try_batch_size * seq_length * batches.shape[0], flag))


total words: 69084
Batch Size -> words missed

        96    1884 
        97    1184 
        98     484 
        99    1764 
       100    1084 
       101     404 <<< Current choice. Should be minimum words missed.
       102    1764 
       103    1104 
       104     444 
       105    1884 

Build graph


In [65]:
from tensorflow.contrib import seq2seq

train_graph = tf.Graph()
with train_graph.as_default():
    vocab_size = len(int_to_vocab)
    input_text, targets, lr = get_inputs()
    input_data_shape = tf.shape(input_text)
    cell, initial_state = get_init_cell(input_data_shape[0], rnn_size)
    logits, final_state = build_nn(cell, rnn_size, input_text, vocab_size, embed_dim)
    
    # Probabilities for generating words
    probs = tf.nn.softmax(logits, name='probs')

    # Loss function
    cost = seq2seq.sequence_loss(
        logits,
        targets,
        tf.ones([input_data_shape[0], input_data_shape[1]]))

    # Optimizer
    optimizer = tf.train.AdamOptimizer(lr)

    # Gradient Clipping
    gradients = optimizer.compute_gradients(cost)
    capped_gradients = [(tf.clip_by_value(grad, -1., 1.), var) for grad, var in gradients]
    train_op = optimizer.apply_gradients(capped_gradients)

Train


In [66]:
batches = get_batches(int_text, batch_size, seq_length)

with tf.Session(graph=train_graph) as sess:
    sess.run(tf.global_variables_initializer())

    for epoch_i in range(num_epochs):
        state = sess.run(initial_state, {input_text: batches[0][0]})

        for batch_i, (x, y) in enumerate(batches):
            feed = {
                input_text: x,
                targets: y,
                initial_state: state,
                lr: learning_rate}
            train_loss, state, _ = sess.run([cost, final_state, train_op], feed)

            # Show every <show_every_n_batches> batches
            if (epoch_i * len(batches) + batch_i) % show_every_n_batches == 0:
                print('Epoch {:>3} Batch {:>4}/{}   train_loss = {:.3f}'.format(
                    epoch_i,
                    batch_i,
                    len(batches),
                    train_loss))

    # Save Model
    saver = tf.train.Saver()
    saver.save(sess, save_dir)
    print('Model Trained and Saved')


Epoch   0 Batch    0/34   train_loss = 8.822
Epoch   2 Batch   32/34   train_loss = 5.478
Epoch   5 Batch   30/34   train_loss = 4.681
Epoch   8 Batch   28/34   train_loss = 4.521
Epoch  11 Batch   26/34   train_loss = 4.369
Epoch  14 Batch   24/34   train_loss = 3.921
Epoch  17 Batch   22/34   train_loss = 3.596
Epoch  20 Batch   20/34   train_loss = 3.482
Epoch  23 Batch   18/34   train_loss = 3.098
Epoch  26 Batch   16/34   train_loss = 2.767
Epoch  29 Batch   14/34   train_loss = 2.693
Epoch  32 Batch   12/34   train_loss = 2.344
Epoch  35 Batch   10/34   train_loss = 2.117
Epoch  38 Batch    8/34   train_loss = 1.958
Epoch  41 Batch    6/34   train_loss = 1.691
Epoch  44 Batch    4/34   train_loss = 1.585
Epoch  47 Batch    2/34   train_loss = 1.749
Epoch  50 Batch    0/34   train_loss = 1.591
Epoch  52 Batch   32/34   train_loss = 1.317
Epoch  55 Batch   30/34   train_loss = 0.979
Epoch  58 Batch   28/34   train_loss = 0.769
Epoch  61 Batch   26/34   train_loss = 0.671
Epoch  64 Batch   24/34   train_loss = 0.572
Epoch  67 Batch   22/34   train_loss = 0.555
Epoch  70 Batch   20/34   train_loss = 0.538
Epoch  73 Batch   18/34   train_loss = 0.458
Epoch  76 Batch   16/34   train_loss = 0.448
Epoch  79 Batch   14/34   train_loss = 0.423
Epoch  82 Batch   12/34   train_loss = 0.388
Epoch  85 Batch   10/34   train_loss = 0.421
Epoch  88 Batch    8/34   train_loss = 0.720
Epoch  91 Batch    6/34   train_loss = 1.057
Epoch  94 Batch    4/34   train_loss = 1.211
Epoch  97 Batch    2/34   train_loss = 1.013
Epoch 100 Batch    0/34   train_loss = 0.632
Epoch 102 Batch   32/34   train_loss = 0.419
Epoch 105 Batch   30/34   train_loss = 0.288
Epoch 108 Batch   28/34   train_loss = 0.212
Epoch 111 Batch   26/34   train_loss = 0.201
Epoch 114 Batch   24/34   train_loss = 0.191
Epoch 117 Batch   22/34   train_loss = 0.174
Model Trained and Saved

Save Parameters

Save seq_length and save_dir for generating a new TV script.


In [67]:
# Save parameters for checkpoint
params = (seq_length, save_dir)
pickle.dump(params, open('params.p', 'wb'))

Check point


In [68]:
import tensorflow as tf
import numpy as np
import problem_unittests as tests

_, vocab_to_int, int_to_vocab, token_dict = pickle.load(open('preprocess.p', mode='rb'))
seq_length, load_dir = pickle.load(open('params.p', mode='rb'))

Implement Generate Functions

Get tensors from loaded_graph using the function get_tensor_by_name(). Get the tensors using the following names:

  • "input:0"
  • "initial_state:0"
  • "final_state:0"
  • "probs:0"

Return the tensors in the following tuple (InputTensor, InitialStateTensor, FinalStateTensor, ProbsTensor)


In [69]:
def get_tensors(loaded_graph):
    """
    Get input, initial state, final state, and probabilities tensor from <loaded_graph>
    :param loaded_graph: TensorFlow graph loaded from file
    :return: Tuple (InputTensor, InitialStateTensor, FinalStateTensor, ProbsTensor)
    """
    InputTensor = loaded_graph.get_tensor_by_name("input:0")
    InitialStateTensor = loaded_graph.get_tensor_by_name("initial_state:0") 
    FinalStateTensor = loaded_graph.get_tensor_by_name("final_state:0") 
    ProbsTensor = loaded_graph.get_tensor_by_name("probs:0")
    return  (InputTensor, InitialStateTensor, FinalStateTensor, ProbsTensor)


tests.test_get_tensors(get_tensors)


Tests Passed

Choose Word

Select the next word using probabilities.


In [70]:
import random

def weighted_choice(choices):
    # From http://stackoverflow.com/questions/3679694/a-weighted-version-of-random-choice
    total = sum(w for c, w in choices)
    r = random.uniform(0, total)
    upto = 0
    for c, w in choices:
        if upto + w >= r:
            return c
        upto += w
    assert False, "Shouldn't get here"
    
def pick_from_top_5(choices):
    top5 = []
    for i in range(min(len(choices), 5)):
        index = np.argmax(choices)
        top5.append((index, choices[index]))
        choices.itemset(index, 0) # Avoid picking this index as argmax again
    return weighted_choice(top5)

def pick_word(probabilities, int_to_vocab):
    """
    Pick the next word in the generated text
    :param probabilities: Probabilites of the next word
    :param int_to_vocab: Dictionary of word ids as the keys and words as the values
    :return: String of the predicted word
    """
    return int_to_vocab[pick_from_top_5(probabilities)]


tests.test_pick_word(pick_word)


Tests Passed

Generate TV Script

Set gen_length to the length of TV script you want to generate.


In [72]:
gen_length = 100

# homer_simpson, moe_szyslak, or Barney_Gumble
prime_word = 'homer_simpson'

loaded_graph = tf.Graph()
with tf.Session(graph=loaded_graph) as sess:
    # Load saved model
    loader = tf.train.import_meta_graph(load_dir + '.meta')
    loader.restore(sess, load_dir)

    # Get Tensors from loaded model
    input_text, initial_state, final_state, probs = get_tensors(loaded_graph)

    # Sentences generation setup
    gen_sentences = [prime_word + ':']
    prev_state = sess.run(initial_state, {input_text: np.array([[1]])})

    # Generate sentences
    for n in range(gen_length):
        # Dynamic Input
        dyn_input = [[vocab_to_int[word] for word in gen_sentences[-seq_length:]]]
        dyn_seq_length = len(dyn_input[0])

        # Get Prediction
        probabilities, prev_state = sess.run(
            [probs, final_state],
            {input_text: dyn_input, initial_state: prev_state})
        
        probabilities = probabilities[0]
        
        pred_word = pick_word(probabilities[dyn_seq_length-1], int_to_vocab)

        gen_sentences.append(pred_word)
    
    # Remove tokens
    tv_script = ' '.join(gen_sentences)
    for key, token in token_dict.items():
        ending = ' ' if key in ['\n', '(', '"'] else ''
        tv_script = tv_script.replace(' ' + token.lower(), key)
    tv_script = tv_script.replace('\n ', '\n')
    tv_script = tv_script.replace('( ', '(')
        
    print(tv_script)


INFO:tensorflow:Restoring parameters from ./save
homer_simpson:(loud whisper) let's try what chapter seven calls" un-sults"-- insults disguised as compliments.(explaining) from the point-- and that i don't just have to get you to be a shill, he's how.
moe_szyslak: yeah, yeah, but you'd feel bad inside.
lenny_leonard: plus they'll say, they took off the corner.


moe_szyslak: homer, no, i can really do something.
moe_szyslak: sorry, homer. you know what's that school--
lenny_leonard: well, i run your

In [ ]: