Spaces:
Runtime error
Runtime error
initial commit
Browse files- .gitattributes +1 -0
- .gitignore +5 -0
- app.py +48 -0
- indexer.py +39 -0
- models/__init__.py +0 -0
- models/__pycache__/__init__.cpython-311.pyc +0 -0
- models/__pycache__/encoder.cpython-311.pyc +0 -0
- models/encoder.py +30 -0
- recommendation.py +43 -0
- requirements.txt +9 -0
- training_nb.ipynb +0 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
data/embeddings.bin filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.env
|
2 |
+
*.pyc
|
3 |
+
*.py[co]
|
4 |
+
encoder.bin
|
5 |
+
.DS_Store
|
app.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import random
|
3 |
+
import os
|
4 |
+
import dotenv
|
5 |
+
from datasets import load_dataset, concatenate_datasets
|
6 |
+
from recommendation import get_recommendations
|
7 |
+
|
8 |
+
dotenv.load_dotenv()
|
9 |
+
|
10 |
+
START = random.randint(a=1,b=200)
|
11 |
+
END = START + 10
|
12 |
+
|
13 |
+
dataset = load_dataset("Ransaka/youtube_recommendation_data", token=os.environ.get('HF'))
|
14 |
+
dataset = concatenate_datasets([dataset['train'], dataset['test']])
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
pil_images = dataset['image'][START:END]
|
19 |
+
|
20 |
+
def show_image_metadata_and_related_info(image_index):
|
21 |
+
selected_image = pil_images[image_index]
|
22 |
+
image_title = dataset['title'][image_index]
|
23 |
+
st.image(selected_image, caption=f"{image_title}", use_column_width=True)
|
24 |
+
|
25 |
+
with st.expander("You May Also Like.."):
|
26 |
+
dataset_s = get_recommendations(selected_image,image_title)
|
27 |
+
|
28 |
+
col1_row1, col2_row1 = st.columns(2)
|
29 |
+
with col1_row1:
|
30 |
+
st.image(image=dataset_s['image'][0], caption=dataset_s['title'][0], width=200)
|
31 |
+
with col2_row1:
|
32 |
+
st.image(image=dataset_s['image'][1], caption=dataset_s['title'][1], width=200)
|
33 |
+
|
34 |
+
# Second Row
|
35 |
+
col1_row2, col2_row2 = st.columns(2)
|
36 |
+
with col1_row2:
|
37 |
+
st.image(image=dataset_s['image'][2], caption=dataset_s['title'][2], width=200)
|
38 |
+
with col2_row2:
|
39 |
+
st.image(image=dataset_s['image'][3], caption=dataset_s['title'][3], width=200)
|
40 |
+
|
41 |
+
def main():
|
42 |
+
st.title("Youtube Recommendation Engine")
|
43 |
+
|
44 |
+
for i, image in enumerate(pil_images):
|
45 |
+
show_image_metadata_and_related_info(i)
|
46 |
+
|
47 |
+
if __name__ == '__main__':
|
48 |
+
main()
|
indexer.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import faiss
|
2 |
+
|
3 |
+
class Indexer:
|
4 |
+
def __init__(self, embed_vec):
|
5 |
+
self.embeddings_vec = embed_vec
|
6 |
+
self.build_index()
|
7 |
+
|
8 |
+
def build_index(self):
|
9 |
+
"""
|
10 |
+
Build the index for the embeddings.
|
11 |
+
|
12 |
+
This function initializes the index for the embeddings. It calculates the dimension (self.d)
|
13 |
+
of the embeddings vector and creates an IndexFlatL2 object (self.index) for the given dimension.
|
14 |
+
It then adds the embeddings vector (self.embeddings_vec) to the index.
|
15 |
+
|
16 |
+
Parameters:
|
17 |
+
- None
|
18 |
+
|
19 |
+
Return:
|
20 |
+
- None
|
21 |
+
"""
|
22 |
+
self.d = self.embeddings_vec.shape[1]
|
23 |
+
self.index = faiss.IndexFlatL2(self.d)
|
24 |
+
self.index.add(self.embeddings_vec)
|
25 |
+
|
26 |
+
def topk(self, vector, k = 4):
|
27 |
+
"""
|
28 |
+
A function that takes in a vector and an optional parameter k and returns the indices of the k nearest neighbors in the index.
|
29 |
+
|
30 |
+
Parameters:
|
31 |
+
vector: A numpy array representing the input vector.
|
32 |
+
k (optional): An integer representing the number of nearest neighbors to retrieve. Defaults to 4 if not specified.
|
33 |
+
|
34 |
+
Returns:
|
35 |
+
I: A numpy array containing the indices of the k nearest neighbors in the index.
|
36 |
+
"""
|
37 |
+
# vec = self.retreaver.encode(text)['embeddings'].detach().cpu().numpy()
|
38 |
+
_, I = self.index.search(vector, k)
|
39 |
+
return I
|
models/__init__.py
ADDED
File without changes
|
models/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (169 Bytes). View file
|
|
models/__pycache__/encoder.cpython-311.pyc
ADDED
Binary file (2.11 kB). View file
|
|
models/encoder.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
import torchvision.transforms as transforms
|
4 |
+
|
5 |
+
class Encoder(nn.Module):
|
6 |
+
def __init__(self, in_channels=1, out_channels=16, latent_dim=64, act_fn=nn.ReLU()):
|
7 |
+
super().__init__()
|
8 |
+
|
9 |
+
self.net = nn.Sequential(
|
10 |
+
nn.Conv2d(in_channels, out_channels, 3, padding=1), # (480, 360)
|
11 |
+
act_fn,
|
12 |
+
nn.Conv2d(out_channels, out_channels, 3, padding=1),
|
13 |
+
act_fn,
|
14 |
+
nn.Conv2d(out_channels, 2 * out_channels, 3, padding=1, stride=2), # (240, 180)
|
15 |
+
act_fn,
|
16 |
+
nn.Conv2d(2 * out_channels, 2 * out_channels, 3, padding=1),
|
17 |
+
act_fn,
|
18 |
+
nn.Conv2d(2 * out_channels, 4 * out_channels, 3, padding=1, stride=2), # (120, 90)
|
19 |
+
act_fn,
|
20 |
+
nn.Conv2d(4 * out_channels, 4 * out_channels, 3, padding=1),
|
21 |
+
act_fn,
|
22 |
+
nn.Flatten(),
|
23 |
+
nn.Linear(4 * out_channels * 120 * 90, latent_dim),
|
24 |
+
act_fn
|
25 |
+
)
|
26 |
+
|
27 |
+
def forward(self, x):
|
28 |
+
x = x.view(-1, 1, 480, 360)
|
29 |
+
output = self.net(x)
|
30 |
+
return output
|
recommendation.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from datasets import load_dataset, concatenate_datasets
|
2 |
+
from sentence_transformers import SentenceTransformer
|
3 |
+
from torchvision import transforms
|
4 |
+
from models.encoder import Encoder
|
5 |
+
from indexer import Indexer
|
6 |
+
import dotenv
|
7 |
+
import torch
|
8 |
+
import os
|
9 |
+
|
10 |
+
dotenv.load_dotenv()
|
11 |
+
|
12 |
+
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
|
13 |
+
|
14 |
+
encoder = Encoder()
|
15 |
+
encoder.load_state_dict(torch.load('./models/encoder.bin', map_location=torch.device('cpu')))
|
16 |
+
|
17 |
+
dataset = load_dataset("Ransaka/youtube_recommendation_data", token=os.environ.get('HF'))
|
18 |
+
dataset = concatenate_datasets([dataset['train'], dataset['test']])
|
19 |
+
|
20 |
+
latent_data = torch.load("data/latent_data_final.bin")
|
21 |
+
embeddings = torch.load("data/embeddings.bin")
|
22 |
+
|
23 |
+
text_embedding_index = Indexer(embeddings)
|
24 |
+
image_embedding_index = Indexer(latent_data)
|
25 |
+
|
26 |
+
def get_recommendations(image, title):
|
27 |
+
# title = [dataset[product_id]['title']]
|
28 |
+
title_embeds = torch.randn(1,768)#model.encode(title, normalize_embeddings=True)
|
29 |
+
image = transforms.ToTensor()(image.convert("L"))
|
30 |
+
image_embeds = encoder(image).detach().numpy()
|
31 |
+
|
32 |
+
image_candidates = image_embedding_index.topk(image_embeds)
|
33 |
+
title_candidates = text_embedding_index.topk(title_embeds)
|
34 |
+
final_candidates = []
|
35 |
+
final_candidates.append(list(image_candidates[0]))
|
36 |
+
final_candidates.append(list(title_candidates[0]))
|
37 |
+
final_candidates = sum(final_candidates,[])
|
38 |
+
final_candidates = list(set(final_candidates))
|
39 |
+
results_dict = {"image":[], "title":[]}
|
40 |
+
for candidate in final_candidates:
|
41 |
+
results_dict['image'].append(dataset['image'][candidate])
|
42 |
+
results_dict['title'].append(dataset['title'][candidate])
|
43 |
+
return results_dict
|
requirements.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
transformers==4.34.1
|
2 |
+
sentence_transformers==2.3.1
|
3 |
+
faiss-cpu==1.7.4
|
4 |
+
pandas==1.5.3
|
5 |
+
matplotlib==3.6.0
|
6 |
+
streamlit==1.29.0
|
7 |
+
torch==2.1.0
|
8 |
+
datasets==2.14.5
|
9 |
+
torchvision==0.16.0
|
training_nb.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|