Coursera

Superhero (and Supervillain) Name Generator


Superhero Names Dataset

Task 2

  1. Import the data
  2. Create a tokenizer
  3. Char to index and Index to char dictionaries
!git clone https://github.com/am1tyadav/superhero
fatal: destination path 'superhero' already exists and is not an empty directory.
with open('superhero/superheroes.txt', 'r+') as f:
    data = f.read()

data[:100]
'jumpa\t\ndoctor fate\t\nstarlight\t\nisildur\t\nlasher\t\nvarvara\t\nthe target\t\naxel\t\nbattra\t\nchangeling\t\npyrrh'
import tensorflow as tf
print(tf.__version__)
2.8.2
tokenizer = tf.keras.preprocessing.text.Tokenizer(
    filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~',
    split='\n',
)
tokenizer.fit_on_texts(data)
char_to_index = tokenizer.word_index
index_to_char = dict((v, k) for k, v in char_to_index.items()) 

print(index_to_char)
{1: '\t', 2: 'a', 3: 'e', 4: 'r', 5: 'o', 6: 'n', 7: 'i', 8: ' ', 9: 't', 10: 's', 11: 'l', 12: 'm', 13: 'h', 14: 'd', 15: 'c', 16: 'u', 17: 'g', 18: 'k', 19: 'b', 20: 'p', 21: 'y', 22: 'w', 23: 'f', 24: 'v', 25: 'j', 26: 'z', 27: 'x', 28: 'q'}

Task 3

  1. Converting between names and sequences
names = data.splitlines()
names[:10]
['jumpa\t',
 'doctor fate\t',
 'starlight\t',
 'isildur\t',
 'lasher\t',
 'varvara\t',
 'the target\t',
 'axel\t',
 'battra\t',
 'changeling\t']
tokenizer.texts_to_sequences(names[0])
[[25], [16], [12], [20], [2], [1]]
def name_to_seq(name):
    return [tokenizer.texts_to_sequences(c)[0][0] for c in name]
name_to_seq(names[0])
[25, 16, 12, 20, 2, 1]
def seq_to_name(seq):
    return ''.join([index_to_char[i] for i in seq if i != 0])
seq_to_name(name_to_seq(names[0]))
'jumpa\t'

Task 4

  1. Creating sequences
  2. Padding all sequences
sequences = []

for name in names:
    seq = name_to_seq(name)

    if len(seq) >= 2:
        sequences += [seq[:i] for i in range(2, len(seq) + 1)]
sequences[:10]
[[25, 16],
 [25, 16, 12],
 [25, 16, 12, 20],
 [25, 16, 12, 20, 2],
 [25, 16, 12, 20, 2, 1],
 [14, 5],
 [14, 5, 15],
 [14, 5, 15, 9],
 [14, 5, 15, 9, 5],
 [14, 5, 15, 9, 5, 4]]
max_len = max([len(x) for x in sequences])
print(max_len)
33
padded_sequences = tf.keras.preprocessing.sequence.pad_sequences(
    sequences = sequences,
    padding = 'pre',
    maxlen = max_len
)

print(padded_sequences[0])
[ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0 25 16]
padded_sequences.shape
(88279, 33)

Task 5: Creating Training and Validation Sets

  1. Creating training and validation sets
x, y = padded_sequences[:, :-1], padded_sequences[:, -1]
print(x.shape, y.shape)
(88279, 32) (88279,)
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, random_state = 42)

print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
(66209, 32) (66209,)
(22070, 32) (22070,)
num_chars = len(char_to_index.keys()) + 1
print(num_chars)
29

Task 6: Creating the Model

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Conv1D, MaxPool1D, LSTM
from tensorflow.keras.layers import Bidirectional, Dense
model = Sequential([
    Embedding(num_chars, 8, input_length = max_len - 1),
    Conv1D(64, 5, strides = 1, activation = 'tanh', padding = 'causal'),
    MaxPool1D(2),
    LSTM(32),
    Dense(num_chars, activation = 'softmax'),
])

model.compile(
    loss = 'sparse_categorical_crossentropy',
    optimizer = 'adam',
    metrics = ['accuracy']
)

model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, 32, 8)             232       
                                                                 
 conv1d (Conv1D)             (None, 32, 64)            2624      
                                                                 
 max_pooling1d (MaxPooling1D  (None, 16, 64)           0         
 )                                                               
                                                                 
 lstm (LSTM)                 (None, 32)                12416     
                                                                 
 dense (Dense)               (None, 29)                957       
                                                                 
=================================================================
Total params: 16,229
Trainable params: 16,229
Non-trainable params: 0
_________________________________________________________________

Task 7: Training the Model

h = model.fit(
    x_train, y_train,
    validation_data = (x_test, y_test),
    epochs = 50, verbose = 1,
    callbacks = [
        tf.keras.callbacks.EarlyStopping(monitor = 'val_accuracy', patience = 3)
    ]
)
Epoch 1/50
2070/2070 [==============================] - 18s 7ms/step - loss: 2.7422 - accuracy: 0.1916 - val_loss: 2.5601 - val_accuracy: 0.2252
Epoch 2/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.5316 - accuracy: 0.2389 - val_loss: 2.4799 - val_accuracy: 0.2497
Epoch 3/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.4649 - accuracy: 0.2576 - val_loss: 2.4416 - val_accuracy: 0.2690
Epoch 4/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.4177 - accuracy: 0.2699 - val_loss: 2.4021 - val_accuracy: 0.2774
Epoch 5/50
2070/2070 [==============================] - 15s 7ms/step - loss: 2.3762 - accuracy: 0.2828 - val_loss: 2.3650 - val_accuracy: 0.2895
Epoch 6/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.3414 - accuracy: 0.2940 - val_loss: 2.3394 - val_accuracy: 0.2939
Epoch 7/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.3117 - accuracy: 0.3004 - val_loss: 2.3205 - val_accuracy: 0.2997
Epoch 8/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.2848 - accuracy: 0.3096 - val_loss: 2.3010 - val_accuracy: 0.3066
Epoch 9/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.2613 - accuracy: 0.3169 - val_loss: 2.2872 - val_accuracy: 0.3075
Epoch 10/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.2401 - accuracy: 0.3243 - val_loss: 2.2709 - val_accuracy: 0.3138
Epoch 11/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.2193 - accuracy: 0.3313 - val_loss: 2.2592 - val_accuracy: 0.3180
Epoch 12/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1999 - accuracy: 0.3349 - val_loss: 2.2469 - val_accuracy: 0.3235
Epoch 13/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1818 - accuracy: 0.3424 - val_loss: 2.2392 - val_accuracy: 0.3258
Epoch 14/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1658 - accuracy: 0.3463 - val_loss: 2.2323 - val_accuracy: 0.3254
Epoch 15/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1508 - accuracy: 0.3527 - val_loss: 2.2232 - val_accuracy: 0.3346
Epoch 16/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.1352 - accuracy: 0.3574 - val_loss: 2.2152 - val_accuracy: 0.3350
Epoch 17/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1221 - accuracy: 0.3618 - val_loss: 2.2120 - val_accuracy: 0.3382
Epoch 18/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.1088 - accuracy: 0.3657 - val_loss: 2.2012 - val_accuracy: 0.3446
Epoch 19/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.0968 - accuracy: 0.3706 - val_loss: 2.2021 - val_accuracy: 0.3429
Epoch 20/50
2070/2070 [==============================] - 12s 6ms/step - loss: 2.0853 - accuracy: 0.3740 - val_loss: 2.2012 - val_accuracy: 0.3439
Epoch 21/50
2070/2070 [==============================] - 13s 6ms/step - loss: 2.0742 - accuracy: 0.3788 - val_loss: 2.1938 - val_accuracy: 0.3433
import matplotlib.pyplot as plt

epochs_ran = len(h.history['loss'])
plt.plot(range(0, epochs_ran), h.history['val_accuracy'], label = 'Validation')
plt.plot(range(0, epochs_ran), h.history['accuracy'], label = 'Training')
plt.legend()
plt.show()

png

Task 8: Generate Names!

def generate_names(seed):
    for i in range(0, 40):
        seq = name_to_seq(seed)
        padded = tf.keras.preprocessing.sequence.pad_sequences(
            [seq],
            padding = 'pre',
            maxlen = max_len - 1,
            truncating = 'pre',
        )
    
        pred = model.predict(padded)[0]
        pred_char = index_to_char[tf.argmax(pred).numpy()]

        seed += pred_char
    
        if pred_char == '\t':
            break
    
    print(seed)

generate_names('a')
aren the stark	
generate_names('bin')
binder strange	
generate_names('quan')
quantiin man	
generate_names('ole')
olessa maran