Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save raidery/d53beb6e50e49a25592d260fd7f884ce to your computer and use it in GitHub Desktop.
Save raidery/d53beb6e50e49a25592d260fd7f884ce to your computer and use it in GitHub Desktop.
Created on Cognitive Class Labs
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a href=\"https://www.bigdatauniversity.com\"><img src=\"https://ibm.box.com/shared/static/qo20b88v1hbjztubt06609ovs85q8fau.png\" width=\"400px\" align=\"center\"></a>\n",
"\n",
"<h1 align=\"center\"><font size=\"5\">RECOMMENDATION SYSTEM WITH A RESTRICTED BOLTZMANN MACHINE</font></h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Welcome to the <b>Recommendation System with a Restricted Boltzmann Machine</b> notebook. In this notebook, we study and go over the usage of a Restricted Boltzmann Machine (RBM) in a Collaborative Filtering based recommendation system. This system is an algorithm that recommends items by trying to find users that are similar to each other based on their item ratings. By the end of this notebook, you should have a deeper understanding of how Restricted Boltzmann Machines are applied, and how to build one using TensorFlow."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h2>Table of Contents</h2>\n",
"\n",
"<ol>\n",
" <li><a href=\"#ref1\">Acquiring the Data</a></li>\n",
" <li><a href=\"#ref2\">Loading in the Data</a></li>\n",
" <li><a href=\"#ref3\">The Restricted Boltzmann Machine model</a></li>\n",
" <li><a href=\"#ref4\">Setting the Model's Parameters</a></li>\n",
" <li><a href=\"#ref5\">Recommendation</a></li>\n",
"</ol>\n",
"<br>\n",
"<br>\n",
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref1\"></a>\n",
"<h2>Acquiring the Data</h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To start, we need to download the data we are going to use for our system. The datasets we are going to use were acquired by <a href=\"http://grouplens.org/datasets/movielens/\">GroupLens</a> and contain movies, users and movie ratings by these users.\n",
"\n",
"After downloading the data, we will extract the datasets to a directory that is easily accessible."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2019-12-29 15:17:53-- http://files.grouplens.org/datasets/movielens/ml-1m.zip\n",
"Resolving files.grouplens.org (files.grouplens.org)... 128.101.65.152\n",
"Connecting to files.grouplens.org (files.grouplens.org)|128.101.65.152|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 5917549 (5.6M) [application/zip]\n",
"Saving to: ‘./data/moviedataset.zip’\n",
"\n",
"./data/moviedataset 100%[===================>] 5.64M 17.9MB/s in 0.3s \n",
"\n",
"2019-12-29 15:17:53 (17.9 MB/s) - ‘./data/moviedataset.zip’ saved [5917549/5917549]\n",
"\n",
"Archive: ./data/moviedataset.zip\n",
" creating: ./data/ml-1m/\n",
" inflating: ./data/ml-1m/movies.dat \n",
" inflating: ./data/ml-1m/ratings.dat \n",
" inflating: ./data/ml-1m/README \n",
" inflating: ./data/ml-1m/users.dat \n"
]
}
],
"source": [
"!mkdir data\n",
"!wget -O ./data/moviedataset.zip http://files.grouplens.org/datasets/movielens/ml-1m.zip\n",
"!unzip -o ./data/moviedataset.zip -d ./data"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"FuelConsumption.csv\t\t\t\t\t MNIST_data\n",
"ML0120EN-1.1-Review-TensorFlow-Hello-World.ipynb\t __pycache__\n",
"ML0120EN-1.2-Review-LinearRegressionwithTensorFlow.ipynb bird.jpg\n",
"ML0120EN-1.4-Review-LogisticRegressionwithTensorFlow.ipynb data\n",
"ML0120EN-2.1-Review-Understanding_Convolutions.ipynb\t destructed3.jpg\n",
"ML0120EN-2.2-Review-CNN-MNIST-Dataset.ipynb\t\t num3.jpg\n",
"ML0120EN-3.1-Reveiw-LSTM-basics.ipynb\t\t\t summary_logs\n",
"ML0120EN-3.2-Review-LSTM-LanguageModelling.ipynb\t utils.py\n",
"ML0120EN-4.1-Review-RBMMNIST.ipynb\t\t\t utils1.py\n",
"ML0120EN-4.2-Review-CollaborativeFilteringwithRBM.ipynb\n"
]
}
],
"source": [
"!ls"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With the datasets in place, let's now import the necessary libraries. We will be using <a href=\"https://www.tensorflow.org/\">Tensorflow</a> and <a href=\"http://www.numpy.org/\">Numpy</a> together to model and initialize our Restricted Boltzmann Machine and <a href=\"http://pandas.pydata.org/pandas-docs/stable/\">Pandas</a> to manipulate our datasets. To import these libraries, run the code cell below."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"#Tensorflow library. Used to implement machine learning models\n",
"import tensorflow as tf\n",
"#Numpy contains helpful functions for efficient mathematical calculations\n",
"import numpy as np\n",
"#Dataframe manipulation library\n",
"import pandas as pd\n",
"#Graph plotting library\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref2\"></a>\n",
"<h2>Loading in the Data</h2>\n",
"\n",
"Let's begin by loading in our data with Pandas. The .dat files containing our data are similar to CSV files, but instead of using the ',' (comma) character to separate entries, it uses '::' (two colons) characters instead. To let Pandas know that it should separate data points at every '::', we have to specify the <code>sep='::'</code> parameter when calling the function.\n",
"\n",
"Additionally, we also pass it the <code>header=None</code> parameter due to the fact that our files don't contain any headers.\n",
"\n",
"Let's start with the movies.dat file and take a look at its structure:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>Toy Story (1995)</td>\n",
" <td>Animation|Children's|Comedy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>Jumanji (1995)</td>\n",
" <td>Adventure|Children's|Fantasy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>Grumpier Old Men (1995)</td>\n",
" <td>Comedy|Romance</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4</td>\n",
" <td>Waiting to Exhale (1995)</td>\n",
" <td>Comedy|Drama</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>5</td>\n",
" <td>Father of the Bride Part II (1995)</td>\n",
" <td>Comedy</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2\n",
"0 1 Toy Story (1995) Animation|Children's|Comedy\n",
"1 2 Jumanji (1995) Adventure|Children's|Fantasy\n",
"2 3 Grumpier Old Men (1995) Comedy|Romance\n",
"3 4 Waiting to Exhale (1995) Comedy|Drama\n",
"4 5 Father of the Bride Part II (1995) Comedy"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Loading in the movies dataset\n",
"movies_df = pd.read_csv('./data/ml-1m/movies.dat', sep='::', header=None, engine='python')\n",
"movies_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can do the same for the ratings.dat file:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>0</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>1193</td>\n",
" <td>5</td>\n",
" <td>978300760</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>661</td>\n",
" <td>3</td>\n",
" <td>978302109</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1</td>\n",
" <td>914</td>\n",
" <td>3</td>\n",
" <td>978301968</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1</td>\n",
" <td>3408</td>\n",
" <td>4</td>\n",
" <td>978300275</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1</td>\n",
" <td>2355</td>\n",
" <td>5</td>\n",
" <td>978824291</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 0 1 2 3\n",
"0 1 1193 5 978300760\n",
"1 1 661 3 978302109\n",
"2 1 914 3 978301968\n",
"3 1 3408 4 978300275\n",
"4 1 2355 5 978824291"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Loading in the ratings dataset\n",
"ratings_df = pd.read_csv('./data/ml-1m/ratings.dat', sep='::', header=None, engine='python')\n",
"ratings_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So our <b>movies_df</b> variable contains a dataframe that stores a movie's unique ID number, title and genres, while our <b>ratings_df</b> variable stores a unique User ID number, a movie's ID that the user has watched, the user's rating to said movie and when the user rated that movie.\n",
"\n",
"Let's now rename the columns in these dataframes so we can better convey their data more intuitively:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>MovieID</th>\n",
" <th>Title</th>\n",
" <th>Genres</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>Toy Story (1995)</td>\n",
" <td>Animation|Children's|Comedy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2</td>\n",
" <td>Jumanji (1995)</td>\n",
" <td>Adventure|Children's|Fantasy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>Grumpier Old Men (1995)</td>\n",
" <td>Comedy|Romance</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>4</td>\n",
" <td>Waiting to Exhale (1995)</td>\n",
" <td>Comedy|Drama</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>5</td>\n",
" <td>Father of the Bride Part II (1995)</td>\n",
" <td>Comedy</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" MovieID Title Genres\n",
"0 1 Toy Story (1995) Animation|Children's|Comedy\n",
"1 2 Jumanji (1995) Adventure|Children's|Fantasy\n",
"2 3 Grumpier Old Men (1995) Comedy|Romance\n",
"3 4 Waiting to Exhale (1995) Comedy|Drama\n",
"4 5 Father of the Bride Part II (1995) Comedy"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"movies_df.columns = ['MovieID', 'Title', 'Genres']\n",
"movies_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And our final ratings_df:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>UserID</th>\n",
" <th>MovieID</th>\n",
" <th>Rating</th>\n",
" <th>Timestamp</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>1193</td>\n",
" <td>5</td>\n",
" <td>978300760</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>661</td>\n",
" <td>3</td>\n",
" <td>978302109</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1</td>\n",
" <td>914</td>\n",
" <td>3</td>\n",
" <td>978301968</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1</td>\n",
" <td>3408</td>\n",
" <td>4</td>\n",
" <td>978300275</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1</td>\n",
" <td>2355</td>\n",
" <td>5</td>\n",
" <td>978824291</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" UserID MovieID Rating Timestamp\n",
"0 1 1193 5 978300760\n",
"1 1 661 3 978302109\n",
"2 1 914 3 978301968\n",
"3 1 3408 4 978300275\n",
"4 1 2355 5 978824291"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ratings_df.columns = ['UserID', 'MovieID', 'Rating', 'Timestamp']\n",
"ratings_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref3\"></a>\n",
"<h2>The Restricted Boltzmann Machine model</h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"https://ibm.box.com/shared/static/o049tx0dsllpbj3b546vuba25qqlzelq.png\" width=\"300\">\n",
"<br>\n",
"The Restricted Boltzmann Machine model has two layers of neurons, one of which is what we call a visible input layer and the other is called a hidden layer. The hidden layer is used to learn features from the information fed through the input layer. For our model, the input is going to contain X neurons, where X is the amount of movies in our dataset. Each of these neurons will possess a normalized rating value varying from 0 to 1, where 0 meaning that a user has not watched that movie and the closer the value is to 1, the more the user likes the movie that neuron's representing. These normalized values, of course, will be extracted and normalized from the ratings dataset.\n",
"\n",
"After passing in the input, we train the RBM on it and have the hidden layer learn its features. These features are what we use to reconstruct the input, which in our case, will predict the ratings for movies that user hasn't watched, which is exactly what we can use to recommend movies!\n",
"\n",
"We will now begin to format our dataset to follow the model's expected input."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3>Formatting the Data</h3>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First let's see how many movies we have and see if the movie ID's correspond with that value:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3883"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(movies_df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we can start formatting the data into input for the RBM. We're going to store the normalized users ratings into as a matrix of user-rating called trX, and normalize the values."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th>MovieID</th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" <th>5</th>\n",
" <th>6</th>\n",
" <th>7</th>\n",
" <th>8</th>\n",
" <th>9</th>\n",
" <th>10</th>\n",
" <th>...</th>\n",
" <th>3943</th>\n",
" <th>3944</th>\n",
" <th>3945</th>\n",
" <th>3946</th>\n",
" <th>3947</th>\n",
" <th>3948</th>\n",
" <th>3949</th>\n",
" <th>3950</th>\n",
" <th>3951</th>\n",
" <th>3952</th>\n",
" </tr>\n",
" <tr>\n",
" <th>UserID</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>5.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>2.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows × 3706 columns</p>\n",
"</div>"
],
"text/plain": [
"MovieID 1 2 3 4 5 6 7 8 9 10 ... \\\n",
"UserID ... \n",
"1 5.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... \n",
"2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... \n",
"3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... \n",
"4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... \n",
"5 NaN NaN NaN NaN NaN 2.0 NaN NaN NaN NaN ... \n",
"\n",
"MovieID 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 \n",
"UserID \n",
"1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n",
"2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n",
"3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n",
"4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n",
"5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN \n",
"\n",
"[5 rows x 3706 columns]"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"user_rating_df = ratings_df.pivot(index='UserID', columns='MovieID', values='Rating')\n",
"user_rating_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets normalize it now:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 0., 0., ..., 0., 0., 0.],\n",
" [0., 0., 0., ..., 0., 0., 0.],\n",
" [0., 0., 0., ..., 0., 0., 0.],\n",
" [0., 0., 0., ..., 0., 0., 0.],\n",
" [0., 0., 0., ..., 0., 0., 0.]])"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"norm_user_rating_df = user_rating_df.fillna(0) / 5.0\n",
"trX = norm_user_rating_df.values\n",
"trX[0:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref4\"></a>\n",
"<h2>Setting the Model's Parameters</h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, let's start building our RBM with TensorFlow. We'll begin by first determining the number of neurons in the hidden layers and then creating placeholder variables for storing our visible layer biases, hidden layer biases and weights that connects the hidden layer with the visible layer. We will be arbitrarily setting the number of neurons in the hidden layers to 20. You can freely set this value to any number you want since each neuron in the hidden layer will end up learning a feature."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"hiddenUnits = 20\n",
"visibleUnits = len(user_rating_df.columns)\n",
"vb = tf.placeholder(\"float\", [visibleUnits]) #Number of unique movies\n",
"hb = tf.placeholder(\"float\", [hiddenUnits]) #Number of features we're going to learn\n",
"W = tf.placeholder(\"float\", [visibleUnits, hiddenUnits])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We then move on to creating the visible and hidden layer units and setting their activation functions. In this case, we will be using the <code>tf.sigmoid</code> and <code>tf.relu</code> functions as nonlinear activations since it is commonly used in RBM's."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"#Phase 1: Input Processing\n",
"v0 = tf.placeholder(\"float\", [None, visibleUnits])\n",
"_h0 = tf.nn.sigmoid(tf.matmul(v0, W) + hb)\n",
"h0 = tf.nn.relu(tf.sign(_h0 - tf.random_uniform(tf.shape(_h0))))\n",
"#Phase 2: Reconstruction\n",
"_v1 = tf.nn.sigmoid(tf.matmul(h0, tf.transpose(W)) + vb) \n",
"v1 = tf.nn.relu(tf.sign(_v1 - tf.random_uniform(tf.shape(_v1))))\n",
"h1 = tf.nn.sigmoid(tf.matmul(v1, W) + hb)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we set the RBM training parameters and functions."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"#Learning rate\n",
"alpha = 1.0\n",
"#Create the gradients\n",
"w_pos_grad = tf.matmul(tf.transpose(v0), h0)\n",
"w_neg_grad = tf.matmul(tf.transpose(v1), h1)\n",
"#Calculate the Contrastive Divergence to maximize\n",
"CD = (w_pos_grad - w_neg_grad) / tf.to_float(tf.shape(v0)[0])\n",
"#Create methods to update the weights and biases\n",
"update_w = W + alpha * CD\n",
"update_vb = vb + alpha * tf.reduce_mean(v0 - v1, 0)\n",
"update_hb = hb + alpha * tf.reduce_mean(h0 - h1, 0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And set the error function, which in this case will be the Mean Absolute Error Function."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"err = v0 - v1\n",
"err_sum = tf.reduce_mean(err * err)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also have to initialize our variables. Thankfully, NumPy has a handy ,code>zeros</code> function for this. We use it like so:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"#Current weight\n",
"cur_w = np.zeros([visibleUnits, hiddenUnits], np.float32)\n",
"#Current visible unit biases\n",
"cur_vb = np.zeros([visibleUnits], np.float32)\n",
"#Current hidden unit biases\n",
"cur_hb = np.zeros([hiddenUnits], np.float32)\n",
"#Previous weight\n",
"prv_w = np.zeros([visibleUnits, hiddenUnits], np.float32)\n",
"#Previous visible unit biases\n",
"prv_vb = np.zeros([visibleUnits], np.float32)\n",
"#Previous hidden unit biases\n",
"prv_hb = np.zeros([hiddenUnits], np.float32)\n",
"sess = tf.Session()\n",
"sess.run(tf.global_variables_initializer())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we train the RBM with 15 epochs with each epoch using 10 batches with size 100. After training, we print out a graph with the error by epoch."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.059453025\n",
"0.05109139\n",
"0.04913294\n",
"0.047578882\n",
"0.04714242\n",
"0.046697494\n",
"0.046139736\n",
"0.045851342\n",
"0.045538355\n",
"0.045423053\n",
"0.045310635\n",
"0.045233835\n",
"0.04525504\n",
"0.04519263\n",
"0.0451991\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"epochs = 15\n",
"batchsize = 100\n",
"errors = []\n",
"for i in range(epochs):\n",
" for start, end in zip( range(0, len(trX), batchsize), range(batchsize, len(trX), batchsize)):\n",
" batch = trX[start:end]\n",
" cur_w = sess.run(update_w, feed_dict={v0: batch, W: prv_w, vb: prv_vb, hb: prv_hb})\n",
" cur_vb = sess.run(update_vb, feed_dict={v0: batch, W: prv_w, vb: prv_vb, hb: prv_hb})\n",
" cur_nb = sess.run(update_hb, feed_dict={v0: batch, W: prv_w, vb: prv_vb, hb: prv_hb})\n",
" prv_w = cur_w\n",
" prv_vb = cur_vb\n",
" prv_hb = cur_hb\n",
" errors.append(sess.run(err_sum, feed_dict={v0: trX, W: cur_w, vb: cur_vb, hb: cur_hb}))\n",
" print (errors[-1])\n",
"plt.plot(errors)\n",
"plt.ylabel('Error')\n",
"plt.xlabel('Epoch')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref5\"></a>\n",
"<h2>Recommendation</h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now predict movies that an arbitrarily selected user might like. This can be accomplished by feeding in the user's watched movie preferences into the RBM and then reconstructing the input. The values that the RBM gives us will attempt to estimate the user's preferences for movies that he hasn't watched based on the preferences of the users that the RBM was trained on."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets first select a <b>User ID</b> of our mock user:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mock_user_id = 215"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
}
},
"outputs": [],
"source": [
"#Selecting the input user\n",
"inputUser = trX[mock_user_id-1].reshape(1, -1)\n",
"inputUser[0:5]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
}
},
"outputs": [],
"source": [
"#Feeding in the user and reconstructing the input\n",
"hh0 = tf.nn.sigmoid(tf.matmul(v0, W) + hb)\n",
"vv1 = tf.nn.sigmoid(tf.matmul(hh0, tf.transpose(W)) + vb)\n",
"feed = sess.run(hh0, feed_dict={ v0: inputUser, W: prv_w, hb: prv_hb})\n",
"rec = sess.run(vv1, feed_dict={ hh0: feed, W: prv_w, vb: prv_vb})\n",
"print(rec)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can then list the 20 most recommended movies for our mock user by sorting it by their scores given by our model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"scored_movies_df_mock = movies_df[movies_df['MovieID'].isin(user_rating_df.columns)]\n",
"scored_movies_df_mock = scored_movies_df_mock.assign(RecommendationScore = rec[0])\n",
"scored_movies_df_mock.sort_values([\"RecommendationScore\"], ascending=False).head(20)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, how to recommend the movies that the user has not watched yet? "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we can find all the movies that our mock user has watched before:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"movies_df_mock = ratings_df[ratings_df['UserID'] == mock_user_id]\n",
"movies_df_mock.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the next cell, we merge all the movies that our mock users has watched with the predicted scores based on his historical data:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
}
},
"outputs": [],
"source": [
"#Merging movies_df with ratings_df by MovieID\n",
"merged_df_mock = scored_movies_df_mock.merge(movies_df_mock, on='MovieID', how='outer')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"lets sort it and take a look at the first 20 rows:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"merged_df_mock.sort_values([\"RecommendationScore\"], ascending=False).head(20)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see, there are some movies that user has not watched yet and has high score based on our model. So, we can recommend them to the user."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is the end of the module. If you want, you can try to change the parameters in the code -- adding more units to the hidden layer, changing the loss functions or maybe something else to see if it changes anything. Does the model perform better? Does it take longer to compute?\n",
"\n",
"Thank you for reading this notebook. Hopefully, you now have a little more understanding of the RBM model, its applications and how it works with TensorFlow."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Want to learn more?\n",
"\n",
"Running deep learning programs usually needs a high performance platform. __PowerAI__ speeds up deep learning and AI. Built on IBM’s Power Systems, __PowerAI__ is a scalable software platform that accelerates deep learning and AI with blazing performance for individual users or enterprises. The __PowerAI__ platform supports popular machine learning libraries and dependencies including TensorFlow, Caffe, Torch, and Theano. You can use [PowerAI on IMB Cloud](https://cocl.us/ML0120EN_PAI).\n",
"\n",
"Also, you can use __Watson Studio__ to run these notebooks faster with bigger datasets.__Watson Studio__ is IBM’s leading cloud solution for data scientists, built by data scientists. With Jupyter notebooks, RStudio, Apache Spark and popular libraries pre-packaged in the cloud, __Watson Studio__ enables data scientists to collaborate on their projects without having to install anything. Join the fast-growing community of __Watson Studio__ users today with a free account at [Watson Studio](https://cocl.us/ML0120EN_DSX).This is the end of this lesson. Thank you for reading this notebook, and good luck on your studies."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Thank you for completing this exercise!\n",
"\n",
"Notebook created by: <a href = \"https://ca.linkedin.com/in/saeedaghabozorgi\">Saeed Aghabozorgi</a>, Gabriel Garcez Barros Sousa"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>\n",
"\n",
"Copyright &copy; 2018 [Cognitive Class](https://cocl.us/DX0108EN_CC). This notebook and its source code are released under the terms of the [MIT License](https://bigdatauniversity.com/mit-license/)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python",
"language": "python",
"name": "conda-env-python-py"
},
"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.7"
},
"widgets": {
"state": {},
"version": "1.1.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment