Skip to content

Instantly share code, notes, and snippets.

@dsblank
Created March 8, 2018 15:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsblank/8027fb28b59057cb62dd1095ba22fbdf to your computer and use it in GitHub Desktop.
Save dsblank/8027fb28b59057cb62dd1095ba22fbdf to your computer and use it in GitHub Desktop.
Working code for Morse Code decoder
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Working Morse Code\n",
"\n",
"Based on https://towardsdatascience.com/cracking-morse-code-with-rnns-e5883355a6f3\n",
"\n",
"Fixed bugs, made a couple of things more clear."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/dblank/.local/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
" from ._conv import register_converters as _register_converters\n",
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import random\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from keras.models import Sequential\n",
"from keras import layers"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# construct the Morse dictionary\n",
"alphabet = list(\"abcdefghijklmnopqrstuvwxyz\")\n",
"values = ['.-', '-...', '-.-.', '-..', '.', '..-.', '--.', '....', '..', '.---', '-.-', \n",
" '.-..', '--', '-.','---', '.--.', '--.-', \n",
" '.-.', '...', '-', '..-', '...-', '.--', '-..-', '-.--', '--..']\n",
"morse_dict = dict(zip(alphabet, values))\n",
"def morse_encode(word):\n",
" return \"*\".join([morse_dict[i]for i \n",
" in \" \".join(word).split()])"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"word_len = 9\n",
"max_len_x = 4*word_len + (word_len-1)\n",
"max_len_y = word_len\n",
"def data_gen(n):\n",
" \n",
" with open('words_alpha.txt', 'r') as f:\n",
" all_words = f.read().lower().split('\\n') \n",
" words = [word for word in all_words if len(word)==n]\n",
" \n",
" # Shuffle the list since the words are ordered\n",
" random.shuffle(words)\n",
" \n",
" g_out = lambda x: ' '*(max_len_y -len(x)) + x\n",
" output_list = [g_out(word) for word in words]\n",
" \n",
" g_in = lambda x: morse_encode(x)+' '*(max_len_x\n",
" - len(morse_encode(x)))\n",
" input_list = [g_in(word) for word in words]\n",
" \n",
" return output_list, input_list\n",
"output_list, input_list = data_gen(9)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class CharTable(object):\n",
" def __init__(self, chars):\n",
" self.chars = sorted(set(chars))\n",
" self.char_indices = dict((c, i) for i, c in\n",
" enumerate(self.chars))\n",
" self.indices_char = dict((i, c) for i, c in \n",
" enumerate(self.chars))\n",
" def encode(self, token, num_rows):\n",
" x = np.zeros((num_rows, len(self.chars)))\n",
" for i, c in enumerate(token):\n",
" x[i, self.char_indices[c]] = 1\n",
" return x\n",
" def decode(self, x, calc_argmax=True):\n",
" if calc_argmax:\n",
" x = [x.argmax(axis=-1)]\n",
" return ''.join(self.indices_char[int(v)] for v in x)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# we include the white space as a character in both cases below.\n",
"chars_in = '*-. '\n",
"chars_out = 'abcdefghijklmnopqrstuvwxyz '\n",
"ctable_in = CharTable(chars_in)\n",
"ctable_out = CharTable(chars_out)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"x = np.zeros((len(input_list), max_len_x, len(chars_in)))\n",
"y = np.zeros((len(output_list), max_len_y, len(chars_out)))\n",
"for i, token in enumerate(input_list):\n",
" x[i] = ctable_in.encode(token, max_len_x)\n",
"for i, token in enumerate(output_list):\n",
" y[i] = ctable_out.encode(token, max_len_y)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"m = len(x)// 4\n",
"(x_train, x_val) = x[:m], x[m:]\n",
"(y_train, y_val) = y[:m], y[m:]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(13350, 44, 4)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x_train.shape"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--*.-*.-.*--.*.*.-..*..*-.*. margeline\n",
".*.--.*..*--.*.-*...*-*.*.-. epigaster\n",
"---*...-*.*.-.*-...*..-*..*.-..*-.. overbuild\n",
".-..*.-*.-.*-.--*-.*--.*.*.-*.-.. laryngeal\n",
"--*.-*..-*.-.*.*...*--.-*..-*. mauresque\n",
"-.-.*---*--.*-.*..*-*..*...-*. cognitive\n",
"--*..*-.-.*.-.*---*-...*---*-..*-.-- microbody\n",
"-.-.*.-*-.*.-*-.*.-*.*.-*-. cananaean\n",
".-*..-.*-*.*.-.*-.-*..*-.*--. afterking\n",
"--*..*...*-*....*.-.*---*.--*-. misthrown\n"
]
}
],
"source": [
"for i in range(10):\n",
" print(\"\".join([ctable_in.decode(code) for code in x_train[i]]),\n",
" \"\".join([ctable_out.decode(code) for code in y_train[i]]))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"latent_dim = 256"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"input_1 (InputLayer) (None, 44, 4) 0 \n",
"_________________________________________________________________\n",
"lstm_1 (LSTM) (None, 256) 267264 \n",
"_________________________________________________________________\n",
"repeat_vector_1 (RepeatVecto (None, 9, 256) 0 \n",
"_________________________________________________________________\n",
"lstm_2 (LSTM) (None, 9, 256) 525312 \n",
"_________________________________________________________________\n",
"time_distributed_1 (TimeDist (None, 9, 27) 6939 \n",
"_________________________________________________________________\n",
"activation_1 (Activation) (None, 9, 27) 0 \n",
"=================================================================\n",
"Total params: 799,515\n",
"Trainable params: 799,515\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model = Sequential()\n",
"model.add(layers.InputLayer((max_len_x, len(chars_in))))\n",
"model.add(layers.LSTM(latent_dim))\n",
"model.add(layers.RepeatVector(max_len_y))\n",
"model.add(layers.LSTM(latent_dim, return_sequences=True))\n",
"model.add(layers.TimeDistributed(layers.Dense(len(chars_out))))\n",
"model.add(layers.Activation('softmax'))\n",
"model.compile(loss='categorical_crossentropy', optimizer='adam',\n",
" metrics=['accuracy'])\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"Epochs = 120\n",
"Batch_size = 1024"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train on 13350 samples, validate on 40053 samples\n",
"Epoch 1/1\n",
"13350/13350 [==============================] - 69s 5ms/step - loss: 3.0553 - acc: 0.0960 - val_loss: 2.9118 - val_acc: 0.1142\n"
]
}
],
"source": [
"hist = model.fit(x_train, y_train, batch_size=Batch_size, epochs=\n",
" Epochs, validation_data=(x_val, y_val))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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Cy+8cK37d/4HeumllzJ69OjBCE2SJEmSJK2D4fqd36TUeubEE0/kjDPOePb8M5/5DJ/73OfYb7/9eO1rX8trXvMavvvd7z6n3x133MGkSZMAePzxxzniiCOYMGEC73rXu3j88cefbfehD32Ivr4+dtllF0466SQATj/9dO655x7e8pa38Ja3vAWA8ePH8+CDDwLwpS99iUmTJjFp0iROPfXUZ+83YcIEPvjBD7LLLrtwwAEHrHAfSZIkSZK0Ir/zd6iqjfazxx57VKebbrrpOWW9NGfOnNp7772fPZ8wYUL99re/rUceeaSqqhYuXFgvf/nL65lnnqmqqq222qqqqm6//fbaZZddqqrqn//5n+uYY46pqqobbrihRowYUTNnzqyqqkWLFlVV1bJly+rNb35z3XDDDVVV9bKXvawWLlz47H2Xn8+aNasmTZpUjz32WC1ZsqQmTpxYc+bMqdtvv71GjBhR119/fVVVHXbYYXXOOees9LmG+u8qSdo4AbNqPRhz+Fn9GEySpF4Y6u+mw/E7f39/04GOwUYOfpprGLnsRLjvF4N7zZe8Bt52ykqrd999dx544AHuueceFi5cyJgxY3jJS17Cxz72Ma6++mo22WQT7r77bu6//35e8pKX9HuNq6++mo985CMA7Lrrruy6667P1l1wwQVMnz6dZcuWce+993LTTTetUN/pJz/5Ce9617vYaqutAHj3u9/NNddcw8EHH8xOO+3E5MmTAdhjjz2444471vSvIUmSJEnS0PA7/5B/5zcptR467LDDuPDCC7nvvvs4/PDDOffcc1m4cCGzZ89m1KhRjB8/nqVLl67xdW+//Xa++MUvMnPmTMaMGcPRRx+9VtdZbrPNNnv2eMSIEb6+J0mSJEnSavid/w9MSq3KKrKb3XT44YfzwQ9+kAcffJAf//jHXHDBBbzoRS9i1KhRXHXVVdx5552r7L/33nvz7W9/m3333Zdf/vKX3HjjjQA8+uijbLXVVmyzzTbcf//9XHbZZeyzzz4AbL311ixZsoQXvvCFK1zrTW96E0cffTQnnngiVcUll1zCOeec05XnliRJkiSpZ/zOP+Tf+U1KrYd22WUXlixZwnbbbce2227L+9//fg466CBe85rX0NfXx6tf/epV9v/Qhz7EMcccw4QJE5gwYQJ77LEHALvtthu77747r371q9lhhx14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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7fe35c69af60>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=(20,5))\n",
"plt.subplot(121)\n",
"plt.plot(hist.history['acc'])\n",
"plt.plot(hist.history['val_acc'])\n",
"plt.title('model accuracy')\n",
"plt.ylabel('accuracy')\n",
"plt.xlabel('epoch')\n",
"plt.legend(['train', 'validation'], loc='upper left')\n",
"plt.subplot(122)\n",
"plt.plot(hist.history['loss'])\n",
"plt.plot(hist.history['val_loss'])\n",
"plt.title('model loss')\n",
"plt.ylabel('loss')\n",
"plt.xlabel('epoch')\n",
"plt.legend(['train', 'validation'], loc='upper right')\n",
"plt.show()"
]
},
{
"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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment