withana commited on
Commit
c57ad5c
1 Parent(s): f9e9630

initial commit

Browse files
.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