Upload poem_generator.py

This commit is contained in:
tfavory
2018-09-09 21:59:25 +08:00
committed by GitHub
parent 7ceaa53a26
commit 9f0b26fdda
+703
View File
@@ -0,0 +1,703 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[33mThe directory '/home/jovyan/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.\u001b[0m\n",
"\u001b[33mThe directory '/home/jovyan/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.\u001b[0m\n",
"Requirement already satisfied: unidecode in /opt/conda/lib/python3.6/site-packages\n",
"\u001b[33mYou are using pip version 9.0.3, however version 18.0 is available.\n",
"You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n"
]
}
],
"source": [
"!pip install unidecode"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Import TensorFlow >= 1.9 and enable eager execution\n",
"import tensorflow as tf\n",
"\n",
"# Note: Once you enable eager execution, it cannot be disabled. \n",
"tf.enable_eager_execution()\n",
"\n",
"import numpy as np\n",
"import re\n",
"import random\n",
"import unidecode\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"#path_to_file = tf.keras.utils.get_file('shakespeare.txt', 'https://storage.googleapis.com/yashkatariya/shakespeare.txt')\n",
"path_to_file = 'poem_corpus.txt'"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" CHRISTMAS NIGHT.\n",
"\n",
"\n",
" Be peace on earth, good will to men;\n",
" And let this now our carol be:\n",
" If on the land, or on the sea,\n",
" We still will sing the glad refrain;\n",
" And in the closing light of day\n",
" Good words of peace and cheer will say.\n",
"\n",
" The Babe that in the manger born\n",
" Has risen high above the star,\n",
" To judge in peace, or judge in war,\n",
" To judge at night or judge at morn.\n",
" The star that told us of his birth\n",
" Has given us joy and lasting mirth.\n",
"\n",
" The Man that suffered on the tree\n",
" Is risen high above all men;\n",
" Then swell the glad refrain again--\n",
" He died for me, He died for thee:\n",
" Then peace be ever on the earth\n",
" To one and all of human birth.\n",
"\n",
"\n",
"\n",
"\n",
" FALLING OF THE APPLE TREE.\n",
"\n",
"\n",
" The apple tree has fallen, now--\n",
" The axe has laid it low;\n",
" The blossoms sparkled ere it fell,\n",
" But now they wither so.\n",
"\n",
" Its shade we now shall seek in vain--\n",
" The spot we loved so well\n",
" Has\n"
]
}
],
"source": [
"text = unidecode.unidecode(open(path_to_file).read())\n",
"print(text[:1000])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# unique contains all the unique characters in the file\n",
"unique = sorted(set(text))\n",
"\n",
"# creating a mapping from unique characters to indices\n",
"char2idx = {u:i for i, u in enumerate(unique)}\n",
"idx2char = {i:u for i, u in enumerate(unique)}"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# setting the maximum length sentence we want for a single input in characters\n",
"max_length = 100\n",
"\n",
"# length of the vocabulary in chars\n",
"vocab_size = len(unique)\n",
"\n",
"# the embedding dimension \n",
"embedding_dim = 256\n",
"\n",
"# number of RNN (here GRU) units\n",
"units = 1024\n",
"\n",
"# batch size \n",
"BATCH_SIZE = 64\n",
"\n",
"# buffer size to shuffle our dataset\n",
"BUFFER_SIZE = 10000"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(15820, 100)\n",
"(15820, 100)\n"
]
}
],
"source": [
"input_text = []\n",
"target_text = []\n",
"\n",
"for f in range(0, len(text)-max_length, max_length):\n",
" inps = text[f:f+max_length]\n",
" targ = text[f+1:f+1+max_length]\n",
"\n",
" input_text.append([char2idx[i] for i in inps])\n",
" target_text.append([char2idx[t] for t in targ])\n",
" \n",
"print (np.array(input_text).shape)\n",
"print (np.array(target_text).shape)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 32, 42, 33, 43, 44, 37,\n",
" 25, 43, 1, 38, 33, 31, 32, 44, 11, 0, 0, 0, 1, 1, 1, 1, 26,\n",
" 58, 1, 69, 58, 54, 56, 58, 1, 68, 67, 1, 58, 54, 71, 73, 61, 9,\n",
" 1, 60, 68, 68, 57, 1, 76, 62, 65, 65, 1, 73, 68, 1, 66, 58, 67,\n",
" 23, 0, 1, 1, 1, 1, 1, 1, 25, 67, 57, 1, 65, 58, 73, 1, 73,\n",
" 61, 62, 72, 1, 67, 68, 76, 1, 68, 74, 71, 1, 56, 54, 71],\n",
" [68, 65, 1, 55, 58, 22, 0, 1, 1, 1, 1, 1, 1, 33, 59, 1, 68,\n",
" 67, 1, 73, 61, 58, 1, 65, 54, 67, 57, 9, 1, 68, 71, 1, 68, 67,\n",
" 1, 73, 61, 58, 1, 72, 58, 54, 9, 0, 1, 1, 1, 1, 47, 58, 1,\n",
" 72, 73, 62, 65, 65, 1, 76, 62, 65, 65, 1, 72, 62, 67, 60, 1, 73,\n",
" 61, 58, 1, 60, 65, 54, 57, 1, 71, 58, 59, 71, 54, 62, 67, 23, 0,\n",
" 1, 1, 1, 1, 1, 1, 25, 67, 57, 1, 62, 67, 1, 73, 61],\n",
" [58, 1, 56, 65, 68, 72, 62, 67, 60, 1, 65, 62, 60, 61, 73, 1, 68,\n",
" 59, 1, 57, 54, 78, 0, 1, 1, 1, 1, 1, 1, 31, 68, 68, 57, 1,\n",
" 76, 68, 71, 57, 72, 1, 68, 59, 1, 69, 58, 54, 56, 58, 1, 54, 67,\n",
" 57, 1, 56, 61, 58, 58, 71, 1, 76, 62, 65, 65, 1, 72, 54, 78, 11,\n",
" 0, 0, 1, 1, 1, 1, 44, 61, 58, 1, 26, 54, 55, 58, 1, 73, 61,\n",
" 54, 73, 1, 62, 67, 1, 73, 61, 58, 1, 66, 54, 67, 60, 58]])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array(input_text)[:3]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array(target_text)[0][0]"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'N'"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"idx2char[38]"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"' CHRISTMAS NIGHT.\\n\\n\\n Be peace on earth, good will to men;\\n And let this now our caro'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"''.join(idx2char[target_text[0][i]] for i in range(len(target_text[0])))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"' CHRISTMAS NIGHT.\\n\\n\\n Be peace on earth, good will to men;\\n And let this now our car'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"''.join(idx2char[input_text[0][i]] for i in range(len(input_text[0])))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"WARNING:tensorflow:From <ipython-input-13-3bbc2611a7c8>:2: batch_and_drop_remainder (from tensorflow.contrib.data.python.ops.batching) is deprecated and will be removed in a future version.\n",
"Instructions for updating:\n",
"Use `tf.data.Dataset.batch(..., drop_remainder=True)`.\n"
]
}
],
"source": [
"dataset = tf.data.Dataset.from_tensor_slices((input_text, target_text)).shuffle(BUFFER_SIZE)\n",
"dataset = dataset.apply(tf.contrib.data.batch_and_drop_remainder(BATCH_SIZE))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"class Model(tf.keras.Model):\n",
" def __init__(self, vocab_size, embedding_dim, units, batch_size):\n",
" super(Model, self).__init__()\n",
" self.units = units\n",
" self.batch_sz = batch_size\n",
"\n",
" self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)\n",
"\n",
" if tf.test.is_gpu_available():\n",
" print('GPU available')\n",
" self.gru = tf.keras.layers.CuDNNGRU(self.units, \n",
" return_sequences=True, \n",
" return_state=True, \n",
" recurrent_initializer='glorot_uniform')\n",
" else:\n",
" print('GPU available') \n",
" self.gru = tf.keras.layers.GRU(self.units, \n",
" return_sequences=True, \n",
" return_state=True, \n",
" recurrent_activation='sigmoid', \n",
" recurrent_initializer='glorot_uniform')\n",
"\n",
" self.fc = tf.keras.layers.Dense(vocab_size)\n",
" \n",
" def call(self, x, hidden):\n",
" x = self.embedding(x)\n",
"\n",
" # output shape == (batch_size, max_length, hidden_size) \n",
" # states shape == (batch_size, hidden_size)\n",
"\n",
" # states variable to preserve the state of the model\n",
" # this will be used to pass at every step to the model while training\n",
" output, states = self.gru(x, initial_state=hidden)\n",
"\n",
"\n",
" # reshaping the output so that we can pass it to the Dense layer\n",
" # after reshaping the shape is (batch_size * max_length, hidden_size)\n",
" output = tf.reshape(output, (-1, output.shape[2]))\n",
"\n",
" # The dense layer will output predictions for every time_steps(max_length)\n",
" # output shape after the dense layer == (max_length * batch_size, vocab_size)\n",
" x = self.fc(output)\n",
"\n",
" return x, states"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"GPU available\n"
]
}
],
"source": [
"model = Model(vocab_size, embedding_dim, units, BATCH_SIZE)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"optimizer = tf.train.AdamOptimizer()\n",
"\n",
"# using sparse_softmax_cross_entropy so that we don't have to create one-hot vectors\n",
"def loss_function(real, preds):\n",
" return tf.losses.sparse_softmax_cross_entropy(labels=real, logits=preds)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1 Batch 0 Loss 4.5975\n",
"Epoch 1 Batch 100 Loss 2.1609\n",
"Epoch 1 Batch 200 Loss 1.9387\n",
"Epoch 1 Loss 1.8163\n",
"Time taken for 1 epoch 1007.0127582550049 sec\n",
"\n",
"Epoch 2 Batch 0 Loss 1.7427\n",
"Epoch 2 Batch 100 Loss 1.7149\n",
"Epoch 2 Batch 200 Loss 1.6851\n",
"Epoch 2 Loss 1.6786\n",
"Time taken for 1 epoch 1009.5401530265808 sec\n",
"\n",
"Epoch 3 Batch 0 Loss 1.5864\n",
"Epoch 3 Batch 100 Loss 1.5735\n",
"Epoch 3 Batch 200 Loss 1.5432\n",
"Epoch 3 Loss 1.5330\n",
"Time taken for 1 epoch 1008.4457356929779 sec\n",
"\n",
"Epoch 4 Batch 0 Loss 1.4756\n",
"Epoch 4 Batch 100 Loss 1.5105\n",
"Epoch 4 Batch 200 Loss 1.4949\n",
"Epoch 4 Loss 1.4980\n",
"Time taken for 1 epoch 1010.7342929840088 sec\n",
"\n",
"Epoch 5 Batch 0 Loss 1.3859\n",
"Epoch 5 Batch 100 Loss 1.4656\n",
"Epoch 5 Batch 200 Loss 1.4051\n",
"Epoch 5 Loss 1.4314\n",
"Time taken for 1 epoch 1012.4246871471405 sec\n",
"\n",
"Epoch 6 Batch 0 Loss 1.3024\n",
"Epoch 6 Batch 100 Loss 1.3982\n",
"Epoch 6 Batch 200 Loss 1.3920\n",
"Epoch 6 Loss 1.4050\n",
"Time taken for 1 epoch 1009.992424249649 sec\n",
"\n",
"Epoch 7 Batch 0 Loss 1.2550\n",
"Epoch 7 Batch 100 Loss 1.3588\n",
"Epoch 7 Batch 200 Loss 1.3480\n",
"Epoch 7 Loss 1.3742\n",
"Time taken for 1 epoch 1009.2752959728241 sec\n",
"\n",
"Epoch 8 Batch 0 Loss 1.1944\n",
"Epoch 8 Batch 100 Loss 1.3088\n",
"Epoch 8 Batch 200 Loss 1.3028\n",
"Epoch 8 Loss 1.3164\n",
"Time taken for 1 epoch 1007.6811842918396 sec\n",
"\n",
"Epoch 9 Batch 0 Loss 1.1755\n",
"Epoch 9 Batch 100 Loss 1.2597\n",
"Epoch 9 Batch 200 Loss 1.2338\n",
"Epoch 9 Loss 1.2662\n",
"Time taken for 1 epoch 1010.1400344371796 sec\n",
"\n",
"Epoch 10 Batch 0 Loss 1.1144\n",
"Epoch 10 Batch 100 Loss 1.2354\n",
"Epoch 10 Batch 200 Loss 1.2604\n",
"Epoch 10 Loss 1.1994\n",
"Time taken for 1 epoch 1014.5306894779205 sec\n",
"\n",
"Epoch 11 Batch 0 Loss 1.0661\n",
"Epoch 11 Batch 100 Loss 1.1259\n",
"Epoch 11 Batch 200 Loss 1.2032\n",
"Epoch 11 Loss 1.2087\n",
"Time taken for 1 epoch 1015.837060213089 sec\n",
"\n",
"Epoch 12 Batch 0 Loss 1.0235\n",
"Epoch 12 Batch 100 Loss 1.0992\n",
"Epoch 12 Batch 200 Loss 1.1357\n",
"Epoch 12 Loss 1.1567\n",
"Time taken for 1 epoch 1012.8789830207825 sec\n",
"\n",
"Epoch 13 Batch 0 Loss 0.9910\n",
"Epoch 13 Batch 100 Loss 1.1073\n",
"Epoch 13 Batch 200 Loss 1.1040\n",
"Epoch 13 Loss 1.1534\n",
"Time taken for 1 epoch 1013.3924562931061 sec\n",
"\n",
"Epoch 14 Batch 0 Loss 0.9614\n",
"Epoch 14 Batch 100 Loss 1.0112\n",
"Epoch 14 Batch 200 Loss 1.1047\n",
"Epoch 14 Loss 1.0997\n",
"Time taken for 1 epoch 1010.0549929141998 sec\n",
"\n",
"Epoch 15 Batch 0 Loss 0.8986\n",
"Epoch 15 Batch 100 Loss 1.0099\n",
"Epoch 15 Batch 200 Loss 1.0629\n",
"Epoch 15 Loss 1.0550\n",
"Time taken for 1 epoch 1010.1194486618042 sec\n",
"\n",
"Epoch 16 Batch 0 Loss 0.8742\n",
"Epoch 16 Batch 100 Loss 0.9966\n",
"Epoch 16 Batch 200 Loss 1.0665\n",
"Epoch 16 Loss 1.0293\n",
"Time taken for 1 epoch 1010.7748596668243 sec\n",
"\n",
"Epoch 17 Batch 0 Loss 0.8696\n",
"Epoch 17 Batch 100 Loss 0.9391\n",
"Epoch 17 Batch 200 Loss 1.0458\n",
"Epoch 17 Loss 0.9827\n",
"Time taken for 1 epoch 1009.4000136852264 sec\n",
"\n",
"Epoch 18 Batch 0 Loss 0.8229\n",
"Epoch 18 Batch 100 Loss 0.9418\n",
"Epoch 18 Batch 200 Loss 0.9846\n",
"Epoch 18 Loss 0.9915\n",
"Time taken for 1 epoch 1018.6969776153564 sec\n",
"\n",
"Epoch 19 Batch 0 Loss 0.8420\n",
"Epoch 19 Batch 100 Loss 0.9518\n",
"Epoch 19 Batch 200 Loss 0.9679\n",
"Epoch 19 Loss 0.9826\n",
"Time taken for 1 epoch 1015.187970161438 sec\n",
"\n",
"Epoch 20 Batch 0 Loss 0.8031\n",
"Epoch 20 Batch 100 Loss 0.9082\n",
"Epoch 20 Batch 200 Loss 0.9899\n",
"Epoch 20 Loss 0.9728\n",
"Time taken for 1 epoch 1015.405241727829 sec\n",
"\n",
"Epoch 21 Batch 0 Loss 0.8155\n",
"Epoch 21 Batch 100 Loss 0.8931\n",
"Epoch 21 Batch 200 Loss 0.9593\n",
"Epoch 21 Loss 0.9730\n",
"Time taken for 1 epoch 1014.1239879131317 sec\n",
"\n",
"Epoch 22 Batch 0 Loss 0.7719\n",
"Epoch 22 Batch 100 Loss 0.9102\n",
"Epoch 22 Batch 200 Loss 0.9354\n",
"Epoch 22 Loss 0.9565\n",
"Time taken for 1 epoch 1012.7351298332214 sec\n",
"\n",
"Epoch 23 Batch 0 Loss 0.7540\n",
"Epoch 23 Batch 100 Loss 0.8891\n",
"Epoch 23 Batch 200 Loss 0.9431\n",
"Epoch 23 Loss 0.9452\n",
"Time taken for 1 epoch 1015.2740514278412 sec\n",
"\n",
"Epoch 24 Batch 0 Loss 0.7557\n",
"Epoch 24 Batch 100 Loss 0.8679\n",
"Epoch 24 Batch 200 Loss 0.9325\n",
"Epoch 24 Loss 0.9061\n",
"Time taken for 1 epoch 1013.387583732605 sec\n",
"\n",
"Epoch 25 Batch 0 Loss 0.7418\n",
"Epoch 25 Batch 100 Loss 0.8140\n",
"Epoch 25 Batch 200 Loss 0.8961\n",
"Epoch 25 Loss 0.9026\n",
"Time taken for 1 epoch 1012.0506448745728 sec\n",
"\n",
"Epoch 26 Batch 0 Loss 0.7547\n",
"Epoch 26 Batch 100 Loss 0.8344\n"
]
}
],
"source": [
"# Training step\n",
"\n",
"EPOCHS = 30\n",
"\n",
"for epoch in range(EPOCHS):\n",
" start = time.time()\n",
" \n",
" # initializing the hidden state at the start of every epoch\n",
" hidden = model.reset_states()\n",
" \n",
" for (batch, (inp, target)) in enumerate(dataset):\n",
" with tf.GradientTape() as tape:\n",
" # feeding the hidden state back into the model\n",
" # This is the interesting step\n",
" predictions, hidden = model(inp, hidden)\n",
" \n",
" # reshaping the target because that's how the \n",
" # loss function expects it\n",
" target = tf.reshape(target, (-1,))\n",
" loss = loss_function(target, predictions)\n",
" \n",
" grads = tape.gradient(loss, model.variables)\n",
" optimizer.apply_gradients(zip(grads, model.variables), global_step=tf.train.get_or_create_global_step())\n",
"\n",
" if batch % 100 == 0:\n",
" print ('Epoch {} Batch {} Loss {:.4f}'.format(epoch+1,\n",
" batch,\n",
" loss))\n",
" \n",
" print ('Epoch {} Loss {:.4f}'.format(epoch+1, loss))\n",
" print('Time taken for 1 epoch {} sec\\n'.format(time.time() - start))"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The childhood rose that we may do,\n",
"And now the country seat her shall he died,\n",
" And her shadow of regret?\n",
"\n",
"If you can dress your head and stone be forget--\n",
" That were coming home from the corner of her eye.\n",
"\n",
"He did one that ever one to the summer of the rain!\n",
"\n",
"She was wanting from the pine,\n",
" And the song of his lower lay,\n",
"While I am sad and sent the truest,\n",
" And one clothe lads that waits\n",
" Of the black men doth clouds the stars,\n",
" And the stars have broken the stars\n",
" Stood on the brook, the bridge is passing through the starry skies.\n",
"\n",
" When the sun was clear, and the thing to be true\n",
" A blaze in the stream of the steed,\n",
" And the stars have broken the stairs,\n",
" And the clearing and the long bright morning stair,\n",
" And one that makes the dark bells they seemed to say:\n",
" \"But one song of the crowd.\n",
" The stars come and the straw,\n",
" And cold and still their welcome home.\n",
"\n",
" All the cold work that has lured the sea,\n",
" And the clock stood calm and sti\n"
]
}
],
"source": [
"\n",
"\n",
"# Evaluation step(generating text using the model learned)\n",
"\n",
"# number of characters to generate\n",
"num_generate = 1000\n",
"\n",
"# You can change the start string to experiment\n",
"start_string = 'The child'\n",
"# converting our start string to numbers(vectorizing!) \n",
"input_eval = [char2idx[s] for s in start_string]\n",
"input_eval = tf.expand_dims(input_eval, 0)\n",
"\n",
"# empty string to store our results\n",
"text_generated = ''\n",
"\n",
"# low temperatures results in more predictable text.\n",
"# higher temperatures results in more surprising text\n",
"# experiment to find the best setting\n",
"temperature = 0.97\n",
"\n",
"# hidden state shape == (batch_size, number of rnn units); here batch size == 1\n",
"hidden = [tf.zeros((1, units))]\n",
"for i in range(num_generate):\n",
" predictions, hidden = model(input_eval, hidden)\n",
"\n",
" # using a multinomial distribution to predict the word returned by the model\n",
" predictions = predictions / temperature\n",
" predicted_id = tf.multinomial(tf.exp(predictions), num_samples=1)[0][0].numpy()\n",
" \n",
" # We pass the predicted word as the next input to the model\n",
" # along with the previous hidden state\n",
" input_eval = tf.expand_dims([predicted_id], 0)\n",
" \n",
" text_generated += idx2char[predicted_id]\n",
"\n",
"print (start_string + text_generated)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}