A neural-network-based movie recommender system built as a learning project to understand how recommender systems work and to prove to myself that I could build one from the ground up.
This project is my implementation of a movie recommendation model using TensorFlow/Keras and the MovieLens dataset.
The main goal was not to build the most accurate recommender possible.
I built this primarily to learn:
- How recommender systems work internally
- How user and item representations can be learned
- How neural networks can be used to predict ratings
- How movie features can be represented numerically
- How embeddings can be used to find similar items
- How to train, evaluate, save, and reuse a model
In other words:
This project is about learning by actually building the thing.
The model is therefore not production-ready, and its prediction accuracy should not be taken as a benchmark against serious recommendation systems.
The model has three main components:
โโโโโโโโโโโโโโโโโโโ
โ User ID โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ User Embedding โ
โ โ 32D โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ โ
โ Concatenate โ
โ โ
โโโโโโโโโโฌโโโโโโโโโ
โฒ
โ
โโโโโโโโโโดโโโโโโโโโ
โ Movie Network โ
โ โ
โ 19 genres โ
โ โ โ
โ Dense 256 โ
โ โ โ
โ Dense 128 โ
โ โ โ
โ Dense 32 โ
โโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Interaction NN โ
โ โ
โ Dense 64 โ
โ Dense 32 โ
โ Dense 1 โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
Predicted Rating
The architecture contains:
Each user is represented by a learned 32-dimensional embedding.
User ID
โ
Embedding
โ
32-dimensional vector
Movies are represented using their genres.
The 19 MovieLens genres are converted into a multi-hot encoded vector.
The movie network then transforms those 19 features into a 32-dimensional movie representation:
19 genre features
โ
Dense(256, ReLU)
โ
Dense(128, ReLU)
โ
Dense(32)
The genre encoding is implemented in utils.py.
The user and movie vectors are concatenated and passed through another neural network:
User vector โโโโโโ
โโโโ Concatenate โ Dense(64) โ Dense(32) โ Dense(1)
Movie vector โโโโโ
The final output is the model's predicted rating.
This project uses the MovieLens dataset.
The dataset contains:
- 9,742 movies
- 100,836 ratings
- 610 users
The notebook loads movies.csv and ratings.csv from the MovieLens directory.
Movie genres such as:
Action
Adventure
Animation
Children
Comedy
Crime
Documentary
Drama
Fantasy
Film-Noir
Horror
IMAX
Musical
Mystery
Romance
Sci-Fi
Thriller
War
Western
are converted into multi-hot encoded features.
The timestamp is not used by the model and is removed during preprocessing.
The model uses:
- Adam optimizer
- Mean Squared Error (MSE) loss
- 20 epochs
- Validation data during training
- Early stopping with a patience of 3 epochs
- L2 regularization
The model architecture uses an embedding dimension of 32 and an L2 regularization value of 0.001.
The training code is kept inside train.ipynb.
The final saved predictions produced the following MSE values:
| Dataset | MSE |
|---|---|
| Training | 0.7463 |
| Validation | 0.8027 |
These numbers are included mainly as a record of the experiment rather than as a claim of state-of-the-art performance.
For example, the model can produce predictions such as:
| Movie | Actual | Predicted |
|---|---|---|
| Unbreakable (2000) | 4.5 | 3.3 |
| The Fault in Our Stars (2014) | 3.5 | 3.8 |
| Casper (1995) | 1.0 | 2.7 |
| Batman Forever (1995) | 5.0 | 3.7 |
| My Fair Lady (1964) | 4.0 | 4.0 |
One of the things I wanted to understand was how a learned movie representation could be used for more than just rating prediction.
After passing all movies through the movie network, their learned 32-dimensional representations are compared using cosine similarity.
Movie genres
โ
Movie Neural Network
โ
32D movie representation
โ
Cosine Similarity
โ
Most similar movies
This functionality is implemented in find_similares().
The function generates movie embeddings, calculates cosine similarity against the requested movie, sorts the results, and returns the top N similar movies.
For example, querying Toy Story (1995) produces movies such as:
- The Good Dinosaur
- Toy Story 2
- Moana
- Shrek the Third
- Monsters, Inc.
- Turbo
among its closest results.
.
โโโ MovieLens/
โ โโโ movies.csv
โ โโโ ratings.csv
โ
โโโ Models/
โ โโโ recommender_model_code.py
โ
โโโ Model Predictions/
โ โโโ predictions.npz
โ
โโโ train.ipynb
โโโ utils.py
โโโ README.md
The main notebook containing the complete workflow:
Load data
โ
Encode genres
โ
Prepare training/validation data
โ
Load/build model
โ
Train
โ
Make predictions
โ
Evaluate predictions
โ
Find similar movies
The notebook contains the complete experiment and is the best place to follow the project step-by-step.
Contains the model architecture and saved model.
The model is saved so that the expensive training process does not have to be repeated every time.
The model contains approximately 204k total parameters.
Contains previously generated predictions.
This is intentional.
Running prediction on the entire dataset takes significant time on my low-end machine, so the predictions are saved and loaded when needed instead of repeatedly running:
model.predict(...)The notebook loads the saved training and validation predictions from predictions.npz.
Contains reusable helper functions for:
- Genre multi-hot encoding
- Preparing model data
- Loading saved loss/validation-loss values
- Creating prediction comparison tables
- Finding similar movies
This project is not meant to compete with production recommendation systems.
The model has several limitations.
For example, the movie representation is based primarily on genre information, while real-world recommendation systems can use huge amounts of information such as:
- User interaction history
- Watch time
- Clicks
- Search behavior
- Movie metadata
- Similar users
- Context
- Temporal information
- Implicit feedback
This project deliberately keeps things simpler.
Understand the fundamentals โ implement them โ make something that actually works.
Not:
Build Netflix's recommendation engine in my bedroom. ๐ญ
Training and prediction can take a considerable amount of time on my hardware.
Instead of forcing anyone opening the project to retrain everything, the repository contains saved artifacts.
That means you can inspect the notebook and experiment with the model without having to wait for the complete training process every time.
The notebook itself demonstrates this approach by loading the saved Keras model instead of rebuilding and fitting it from scratch.
- ๐ Python
- ๐ง TensorFlow / Keras
- ๐ NumPy
- ๐ผ Pandas
- ๐ Matplotlib
- ๐ฌ Scikit-learn
- ๐ Jupyter Notebook
Building this project helped me understand several concepts that are much harder to appreciate by only reading about them:
- User embeddings
- Item/movie embeddings
- Neural collaborative filtering concepts
- Feature encoding
- Training/validation splitting
- Neural-network architecture design
- Regularization
- Model evaluation with MSE
- Saving and loading Keras models
- Generating predictions
- Cosine similarity
- Using learned representations for item similarity
Most importantly, I learned that actually implementing an ML system is very different from simply knowing what the terms mean.
If I continue developing this project, some things I'd like to experiment with are:
- Better movie features
- More sophisticated user representations
- Improved recommendation ranking
- Better evaluation metrics
- Hyperparameter tuning
- Different embedding sizes
- More advanced collaborative filtering approaches
- Hybrid recommendation techniques
- A proper recommendation interface
But for now, I'm happy with it.
I built a recommender system. That's the point. ๐
This repository represents a step in my journey of learning Machine Learning and AI.
It isn't perfect.
It isn't state-of-the-art.
And the model isn't supposed to be.
It's a project I built to go from:
"I know roughly what a recommender system is."
to:
"I actually built one."
And that's a pretty damn good step forward.