<jupyter_start><jupyter_text>Boltzmann's MachineThis notebook was created by <NAME>, in order to better understand Boltzmann's Machine (BM) principles and how they work.(it follows the exercices proposed by <NAME> on Udemy : https://www.udemy.com/course/le-deep-learning-de-a-a-z/) Imports<jupyter_code>import numpy as np
import pandas as pd
# pytorch
import torch
import torch.nn
import torch.nn.parallel
import torch.optim as optim
import torch.utils.data
from torch.autograd import Variable

import sys
import csv<jupyter_output><empty_output><jupyter_text>PreprocessingWe are going to create a recommendation system based on a film's dataset.It will try to predict if the user will love a film or not.<jupyter_code>df_movies = pd.read_csv("ml-1m\\movies.dat", sep="::", header=None, engine="python",
                encoding="latin-1")
users = pd.read_csv("ml-1m\\users.dat", sep="::", header=None, engine="python",
                encoding="latin-1")
ratings = pd.read_csv("ml-1m\\ratings.dat", sep="::", header=None, engine="python",
                encoding="latin-1")
df_movies.head()
# movie id / name / type
users.head()
# user id / gender / age /professional category / Postal code
ratings.head()
# user id / movie id / rating / timestamp
df_train = pd.read_csv("ml-100k/u1.base", delimiter="\t", header=None)
df_test = pd.read_csv("ml-100k/u1.test", delimiter="\t", header=None)
df_train.head()
# user id / movie id / note / timestamp
df_test.head()
# user id / movie id / note / timestamp
#df_train = np.array(df_train, dtype="int")
#df_test = np.array(df_test, dtype="int")<jupyter_output><empty_output><jupyter_text>Firstly, we will get the user's id set (as an array)<jupyter_code>_users = list(set(np.concatenate((df_train[df_train.columns[0]].value_counts().index, 
                           df_test[df_test.columns[0]].value_counts().index), 
                          axis=0)))
print("Number of unique users : {}".format(len(_users)))<jupyter_output>Number of unique users : 943<jupyter_text>Nextly, we will get the movies's number<jupyter_code>_movies =  list(set(np.concatenate((df_train[df_train.columns[1]].value_counts().index, 
                           df_test[df_test.columns[1]].value_counts().index), 
                          axis=0)))
print("Number of unique movies : {}".format(len(_movies)))<jupyter_output>Number of unique movies : 1682<jupyter_text>Then, we are going to convert our data to a huge matrix using pytorch<jupyter_code>def createMatrix(df, users, movies):
    matrix = []
    movies_nb = len(movies)
    user_nb = len(users)
    df_array = np.array(df, dtype="int")
    for i,user in enumerate(users):
        filtered_movies = df_array[df_array[:,0] == user, 1]
        filtered_ratings = df_array[df_array[:,0] == user, 2]
        ratings = np.zeros(movies_nb)
        for j in range(len(filtered_movies)):
            ratings[filtered_movies[j] - 1] = filtered_ratings[j]
        matrix.append(ratings)
                      
        sys.stdout.write("\r Loading State : {} / {}".format(i+1,user_nb))
        sys.stdout.flush()
        
    return matrix
matrix = createMatrix(df_train, _users, _movies)
matrix_test = createMatrix(df_test, _users, _movies)
train = torch.FloatTensor(matrix)
test = torch.FloatTensor(matrix_test)<jupyter_output><empty_output><jupyter_text>We will now encode our ratings to -1 (no data = 0), 0 (don't love), 1 (love)<jupyter_code>train[train == 0] = -1
test[test == 0] = -1
train[train < 3] = 0
test[test < 3] = 0
train[train >= 3] = 1
test[test >= 3] = 1<jupyter_output><empty_output><jupyter_text>Model<jupyter_code>class RestrictedBoltzmannMachine():
    def __init__(self, nb_n_visible, nb_n_hidden):
        self.Weights = torch.randn(nb_n_visible, nb_n_hidden)
        self.a = torch.randn(1, nb_n_hidden)
        self.b = torch.randn(1, nb_n_visible)
    
    def gibs_sample_hidden(self, x):
        x_weights = torch.mm(x, self.Weights)
        probability_h_given_v = torch.sigmoid(x_weights + self.a.expand_as(x_weights))
        return probability_h_given_v, torch.bernoulli(probability_h_given_v)
    
    def gibs_sample_visible(self, y):
        y_weights = torch.mm(y, self.Weights.t())
        probability_v_given_h = torch.sigmoid(y_weights + self.b.expand_as(y_weights))
        return probability_v_given_h, torch.bernoulli(probability_v_given_h)
    
    def contrastive_divergence(self, visible_0, visible_k, 
                               probability_h_given_v0, probability_h_given_vk):
        self.Weights += torch.mm(visible_0.t(), probability_h_given_v0) - torch.mm(visible_k.t(), probability_h_given_vk)
        self.b += torch.sum((visible_0 - visible_k),0)
        self.a += torch.sum((probability_h_given_v0 - probability_h_given_vk),0)
        
    def train(self, X, epoch=10, batch_size=32, gibs_sampling=10):
        self.X_train = X
        nb_users = X.shape[0]
        for i in range(epoch):
            print("Epoch => {}/{}".format(i+1,epoch))
            train_loss = 0
            s = 0.
            for user in range(0, nb_users - batch_size, batch_size):
                visible_0 = X[user:user+batch_size]
                visible_k = visible_0
                probabilty_hidden_0, _ = self.gibs_sample_hidden(visible_0)
                for k in range(0,gibs_sampling):
                    _, hidden_k = self.gibs_sample_hidden(visible_k)
                    _, visible_k = self.gibs_sample_visible(hidden_k)
                    # no rating's filter --> no changes
                    visible_k[visible_0 < 0] = visible_0[visible_0 < 0]
                probabilty_hidden_k, _ = self.gibs_sample_hidden(visible_k)
                self.contrastive_divergence(visible_0, visible_k,
                                           probabilty_hidden_0, probabilty_hidden_k)
                train_loss += torch.mean(torch.abs(visible_0[visible_0 >= 0] - 
                                                   visible_k[visible_0 >= 0]))
                s+=1
            print("   => Loss : {}".format((train_loss/s)))
            
    def test(self, X):
        nb_users = self.X_train.shape[0]
        
        sys.stdout.write("\r Processing")
        sys.stdout.flush()
                         
        test_loss = 0
        s = 0.
        for user in range(nb_users):
            visible = self.X_train[user:user+1]
            visible_target = X[user:user+1]
            if len(visible_target[visible_target >= 0]) > 0:
                _, hidden = self.gibs_sample_hidden(visible)
                _, visible = self.gibs_sample_visible(hidden)
                test_loss += torch.mean(torch.abs(visible_target[visible_target >= 0] - 
                                                   visible[visible_target >= 0]))
                s+=1
                         
        sys.stdout.write("\r Test Set => Loss : {}".format((test_loss/s)))
        sys.stdout.flush()
_neuron_visible = train.shape[1]
_neuron_hidden = 100 #train.shape[0]
_batch_size = 1
_nb_epoch = 10
_gibs_sampling = 10
rbm = RestrictedBoltzmannMachine(_neuron_visible, _neuron_hidden)
rbm.train(train, _nb_epoch, _batch_size, _gibs_sampling)
rbm.test(test)<jupyter_output>Test Set => Loss : 0.04984850063920021
{'fraction_non_alphanumeric': 0.12069444444444444, 'fraction_numerical': 0.0175, 'mean_word_length': 2.7505208333333333, 'pattern_counts': {'":': 3, '<': 32, '<?xml version=': 0, '>': 41, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '58779', 'license': 'CNRI-Python', 'n_tokens_mistral': 2505, 'n_tokens_neox': 2368, 'n_words': 468, 'path': "Exercises/Boltzmann's Machine/Boltzmann's Machine.ipynb", 'repo_name': 'camilleAmaury/DeepLearningExercise', 'size': '7226'}