diff --git a/2.4 Transfer Learning & Fine-Tuning.ipynb b/2.4 Transfer Learning & Fine-Tuning.ipynb
index 7426eb4..9b75068 100644
--- a/2.4 Transfer Learning & Fine-Tuning.ipynb
+++ b/2.4 Transfer Learning & Fine-Tuning.ipynb
@@ -43,9 +43,7 @@
{
"cell_type": "code",
"execution_count": 2,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stderr",
@@ -106,7 +104,7 @@
},
"outputs": [],
"source": [
- "if K.image_dim_ordering() == 'th':\n",
+ "if K.image_data_format() == 'channels_first':\n",
" input_shape = (1, img_rows, img_cols)\n",
"else:\n",
" input_shape = (img_rows, img_cols, 1)"
@@ -214,9 +212,7 @@
{
"cell_type": "code",
"execution_count": 8,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -255,9 +251,7 @@
{
"cell_type": "code",
"execution_count": 9,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -361,7 +355,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.5.2"
+ "version": "3.5.3"
}
},
"nbformat": 4,
diff --git a/Extra Additional Materials.ipynb b/Extra Additional Materials.ipynb
index 265d679..a6a6984 100644
--- a/Extra Additional Materials.ipynb
+++ b/Extra Additional Materials.ipynb
@@ -8,13 +8,23 @@
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"metadata": {
"collapsed": true
},
- "outputs": [],
- "source": []
+ "source": [
+ "- [Perceptron and Adaline Implementation](./additional materials/1.1.1 Perceptron and Adaline.ipynb)\n",
+ "\n",
+ "- [MLP and MNIST](./additional materials/1.1.2 MLP and MNIST.ipynb)\n",
+ "\n",
+ "- [Quick Theano Tutorial](./additional materials/1.5.1 Introduction - Theano.ipynb)\n",
+ "\n",
+ "- [LSTM for Sentence Generation](./additional materials/3.3 LSTM for Sentence Generation.ipynb)\n",
+ "\n",
+ "- [Custom Layers in Keras](./additional materials/5.1 Custom Layer.ipynb)\n",
+ "\n",
+ "- [Multi-Modal Networks](./additional materials/5.2 Multi-Modal Networks.ipynb)"
+ ]
}
],
"metadata": {
@@ -33,9 +43,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.5.2"
+ "version": "3.5.3"
}
},
"nbformat": 4,
- "nbformat_minor": 0
+ "nbformat_minor": 1
}
diff --git a/additional materials/3.3 LSTM for Sentence Generation.ipynb b/additional materials/3.3 LSTM for Sentence Generation.ipynb
index 9abc183..83aabf6 100644
--- a/additional materials/3.3 LSTM for Sentence Generation.ipynb
+++ b/additional materials/3.3 LSTM for Sentence Generation.ipynb
@@ -2,9 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"source": [
"\n",
"# RNN using LSTM \n",
@@ -44,9 +42,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"from keras.optimizers import SGD\n",
@@ -82,9 +78,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"DATA_DIRECTORY = os.path.join(os.path.abspath(os.path.curdir), '..', 'data', 'word_embeddings')\n",
@@ -121,9 +115,7 @@
{
"cell_type": "code",
"execution_count": 85,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"filtered_male_posts = list(filter(lambda p: len(p) > 0, male_posts))\n",
@@ -133,9 +125,7 @@
{
"cell_type": "code",
"execution_count": 86,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# text processing - one hot builds index of the words\n",
@@ -158,9 +148,7 @@
{
"cell_type": "code",
"execution_count": 87,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# 0 for male, 1 for female\n",
@@ -171,9 +159,7 @@
{
"cell_type": "code",
"execution_count": 88,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"from sklearn.cross_validation import train_test_split\n",
@@ -186,9 +172,7 @@
{
"cell_type": "code",
"execution_count": 89,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -210,9 +194,7 @@
{
"cell_type": "code",
"execution_count": 90,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"max_features = 30000\n",
@@ -229,9 +211,7 @@
{
"cell_type": "code",
"execution_count": 91,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"model.compile(loss='mean_squared_error', optimizer='sgd', metrics=['accuracy'])"
@@ -240,9 +220,7 @@
{
"cell_type": "code",
"execution_count": 92,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -278,9 +256,7 @@
{
"cell_type": "code",
"execution_count": 93,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -297,9 +273,7 @@
{
"cell_type": "code",
"execution_count": 94,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -334,9 +308,7 @@
{
"cell_type": "code",
"execution_count": 96,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"vectorizer = TfidfVectorizer(decode_error='ignore', norm='l2', min_df=5)\n",
@@ -347,9 +319,7 @@
{
"cell_type": "code",
"execution_count": 97,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"flattened_array_tfidf_male = tfidf_male.toarray()\n",
@@ -359,9 +329,7 @@
{
"cell_type": "code",
"execution_count": 98,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"y_rnn = np.concatenate((np.zeros(len(flattened_array_tfidf_male)),\n",
@@ -371,9 +339,7 @@
{
"cell_type": "code",
"execution_count": 99,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"X_train_rnn, X_test_rnn, y_train_rnn, y_test_rnn = train_test_split(np.concatenate((flattened_array_tfidf_male, \n",
@@ -384,9 +350,7 @@
{
"cell_type": "code",
"execution_count": 100,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -436,9 +400,7 @@
{
"cell_type": "code",
"execution_count": 103,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -475,9 +437,7 @@
{
"cell_type": "code",
"execution_count": 104,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -495,9 +455,7 @@
{
"cell_type": "code",
"execution_count": 105,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -521,9 +479,7 @@
{
"cell_type": "code",
"execution_count": 106,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"# reading all the male text data into one string\n",
@@ -549,9 +505,7 @@
{
"cell_type": "code",
"execution_count": 107,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -580,9 +534,7 @@
{
"cell_type": "code",
"execution_count": 109,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [
{
"name": "stdout",
@@ -608,9 +560,7 @@
{
"cell_type": "code",
"execution_count": 74,
- "metadata": {
- "collapsed": false
- },
+ "metadata": {},
"outputs": [],
"source": [
"auto_text_generating_male_model.compile(loss='mean_squared_error',optimizer='sgd')"
@@ -649,7 +599,6 @@
"cell_type": "code",
"execution_count": 113,
"metadata": {
- "collapsed": false,
"scrolled": false
},
"outputs": [
@@ -940,9 +889,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.5.2"
+ "version": "3.5.3"
}
},
"nbformat": 4,
- "nbformat_minor": 0
+ "nbformat_minor": 1
}
diff --git a/additional materials/5.2 Multi-Modal Networks.ipynb b/additional materials/5.2 Multi-Modal Networks.ipynb
index 3dbc9e6..f5b04cb 100644
--- a/additional materials/5.2 Multi-Modal Networks.ipynb
+++ b/additional materials/5.2 Multi-Modal Networks.ipynb
@@ -4,59 +4,101 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Multi-Input Networks"
+ "## Quick Intro to Keras Functional API"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Keras Merge Layer"
+ "## Preamble: All models (layers) are callables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "Multiple Sequential instances can be merged into a single output via a Merge layer. The output is a layer that can be added as first layer in a new Sequential model. For instance, here's a model with two separate input branches getting merged:"
+ "```python\n",
+ "from keras.layers import Input, Dense\n",
+ "from keras.models import Model\n",
+ "\n",
+ "# this returns a tensor\n",
+ "inputs = Input(shape=(784,))\n",
+ "\n",
+ "# a layer instance is callable on a tensor, and returns a tensor\n",
+ "x = Dense(64, activation='relu')(inputs)\n",
+ "x = Dense(64, activation='relu')(x)\n",
+ "predictions = Dense(10, activation='softmax')(x)\n",
+ "\n",
+ "# this creates a model that includes\n",
+ "# the Input layer and three Dense layers\n",
+ "model = Model(input=inputs, output=predictions)\n",
+ "model.compile(optimizer='rmsprop',\n",
+ " loss='categorical_crossentropy',\n",
+ " metrics=['accuracy'])\n",
+ "model.fit(data, labels) # starts training\n",
+ "```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Example (from documentation)"
+ "# Multi-Input Networks"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- ""
+ "## Keras Merge Layer"
]
},
{
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here's a good use case for the functional API: models with multiple inputs and outputs. \n",
+ "\n",
+ "The functional API makes it easy to manipulate a large number of intertwined datastreams.\n",
+ "\n",
+ "Let's consider the following model. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
"source": [
- "from keras.layers import Merge, Dense\n",
- "from keras.models import Sequential\n",
+ "```python\n",
+ "from keras.layers import Dense, Input\n",
+ "from keras.models import Model\n",
+ "from keras.layers.merge import concatenate\n",
"\n",
- "left_branch = Sequential()\n",
- "left_branch.add(Dense(32, input_dim=784))\n",
+ "left_input = Input(shape=(784, ), name='left_input')\n",
+ "left_branch = Dense(32, input_dim=784, name='left_branch')(left_input)\n",
"\n",
- "right_branch = Sequential()\n",
- "right_branch.add(Dense(32, input_dim=784))\n",
+ "right_input = Input(shape=(784,), name='right_input')\n",
+ "right_branch = Dense(32, input_dim=784, name='right_branch')(right_input)\n",
"\n",
- "merged = Merge([left_branch, right_branch], mode='concat')\n",
+ "x = concatenate([left_branch, right_branch])\n",
+ "predictions = Dense(10, activation='softmax', name='main_output')(x)\n",
"\n",
- "final_model = Sequential()\n",
- "final_model.add(merged)\n",
- "final_model.add(Dense(10, activation='softmax'))"
+ "model = Model(inputs=[left_input, right_input], outputs=predictions)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Resulting Model will look like the following network:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
]
},
{
@@ -71,8 +113,8 @@
"metadata": {},
"source": [
"```python\n",
- "final_model.compile(optimizer='rmsprop', loss='categorical_crossentropy')\n",
- "final_model.fit([input_data_1, input_data_2], targets) # we pass one data array per model input\n",
+ "model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])\n",
+ "model.fit([input_data_1, input_data_2], targets) # we pass one data array per model input\n",
"```"
]
},
@@ -80,44 +122,82 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The Merge layer supports a number of pre-defined modes:\n",
- "\n",
- "* `sum` (default): element-wise sum\n",
- "* `concat`: tensor concatenation. You can specify the concatenation axis via the argument concat_axis.\n",
- "* `mul`: element-wise multiplication\n",
- "* `ave`: tensor average\n",
- "* `dot`: dot product. You can specify which axes to reduce along via the argument dot_axes.\n",
- "* `cos`: cosine proximity between vectors in 2D tensors."
+ "## Try yourself"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "You can also pass a function as the mode argument, allowing for arbitrary transformations:"
+ "#### Step 1: Get Data - MNIST"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "# let's load MNIST data as we did in the exercise on MNIST with FC Nets"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# %load ../solutions/sol_52.py"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "```python\n",
- "merged = Merge([left_branch, right_branch], mode=lambda x: x[0] - x[1])\n",
- "```"
+ "#### Step 2: Create the Multi-Input Network"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## try yourself\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "## `evaluate` the model on test data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Keras Functional API"
+ "Keras supports different Merge strategies:\n",
+ "\n",
+ "* `add`: element-wise sum\n",
+ "* `concatenate`: tensor concatenation. You can specify the concatenation axis via the argument concat_axis.\n",
+ "* `multiply`: element-wise multiplication\n",
+ "* `average`: tensor average\n",
+ "* `maximum`: element-wise maximum of the inputs.\n",
+ "* `dot`: dot product. You can specify which axes to reduce along via the argument dot_axes. You can also specify applying any normalisation. In that case, the output of the dot product is the cosine proximity between the two samples."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "### All models (layers) are callables"
+ "You can also pass a function as the mode argument, allowing for arbitrary transformations:"
]
},
{
@@ -125,24 +205,7 @@
"metadata": {},
"source": [
"```python\n",
- "from keras.layers import Input, Dense\n",
- "from keras.models import Model\n",
- "\n",
- "# this returns a tensor\n",
- "inputs = Input(shape=(784,))\n",
- "\n",
- "# a layer instance is callable on a tensor, and returns a tensor\n",
- "x = Dense(64, activation='relu')(inputs)\n",
- "x = Dense(64, activation='relu')(x)\n",
- "predictions = Dense(10, activation='softmax')(x)\n",
- "\n",
- "# this creates a model that includes\n",
- "# the Input layer and three Dense layers\n",
- "model = Model(input=inputs, output=predictions)\n",
- "model.compile(optimizer='rmsprop',\n",
- " loss='categorical_crossentropy',\n",
- " metrics=['accuracy'])\n",
- "model.fit(data, labels) # starts training\n",
+ "merged = Merge([left_branch, right_branch], mode=lambda x: x[0] - x[1])\n",
"```"
]
}
diff --git a/imgs/multi_input_model.png b/imgs/multi_input_model.png
new file mode 100644
index 0000000..7c00498
Binary files /dev/null and b/imgs/multi_input_model.png differ
diff --git a/solutions/sol_52.py b/solutions/sol_52.py
new file mode 100644
index 0000000..49995df
--- /dev/null
+++ b/solutions/sol_52.py
@@ -0,0 +1,26 @@
+from keras.datasets import mnist
+from keras.utils import np_utils
+
+img_rows, img_cols = 28, 28
+nb_classes = 10
+
+(X_train, y_train), (X_test, y_test) = mnist.load_data()
+
+X_train = X_train.reshape(X_train.shape[0], img_rows*img_cols)
+X_test = X_test.reshape(X_test.shape[0], img_rows*img_cols)
+
+X_train = X_train.astype('float32')
+X_test = X_test.astype('float32')
+
+X_train /= 255
+X_test /= 255
+
+print('X_train shape:', X_train.shape)
+print('y_train shape:', y_train.shape)
+print('X_test shape:', X_test.shape)
+print('y_test shape:', y_test.shape)
+print(X_train.shape[0], 'train samples')
+print(X_test.shape[0], 'test samples')
+
+y_train = np_utils.to_categorical(y_train, nb_classes)
+y_test = np_utils.to_categorical(y_test, nb_classes)
\ No newline at end of file