masabhuq commited on
Commit
0c7049d
Β·
1 Parent(s): 78ae5b5

Initial Commit

Browse files
.gitattributes CHANGED
@@ -32,3 +32,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
32
  *.zip filter=lfs diff=lfs merge=lfs -text
33
  *.zst filter=lfs diff=lfs merge=lfs -text
34
  *tfevents* filter=lfs diff=lfs merge=lfs -text
35
+ ResNet18_epoch-14.pth filter=lfs diff=lfs merge=lfs -text
36
+ Experiments[[:space:]]Notebook/lemon_quality_classification.ipynb filter=lfs diff=lfs merge=lfs -text
Experiments Notebook/lemon_quality_classification.ipynb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3d5c7114c60fd89b15933105e51cf3f0b7626c2714b63f416d1dea58aff4e12c
3
+ size 10406169
Experiments Notebook/scripts/data_setup.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch.utils.data import DataLoader
2
+ from torchvision import datasets, transforms
3
+ import torchvision
4
+
5
+ def make_dataloaders(train_ds,
6
+ test_ds,
7
+ batch_size: int):
8
+ """Creates dataloaders
9
+ Creates dataloaders by taking the directory in which train and test data are stored.
10
+
11
+ Args:
12
+ transforms(torchvision.transforms.Compose): Transform to apply to the dataset.
13
+
14
+ Returns:
15
+ tuple: train_dataloader, test_dataloader, class_names
16
+ """
17
+
18
+
19
+ train_dataloader = DataLoader(dataset = train_ds,
20
+ batch_size = batch_size,
21
+ num_workers = 1,
22
+ shuffle = True)
23
+
24
+ test_dataloader = DataLoader(dataset = test_ds,
25
+ batch_size = batch_size,
26
+ num_workers = 1,
27
+ shuffle = False)
28
+
29
+ return train_dataloader, test_dataloader
Experiments Notebook/scripts/engine.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ from torch import nn
4
+ from tqdm.auto import tqdm
5
+
6
+ def train_step(model: torch.nn.Module,
7
+ dataloader: torch.utils.data.DataLoader,
8
+ loss_fn: torch.nn.Module,
9
+ optimizer: torch.optim.Optimizer,
10
+ device: torch.device):
11
+ model.train()
12
+ train_loss, train_acc = 0, 0
13
+ for batch, (X, y) in enumerate(dataloader):
14
+ X, y = X.to(device), y.to(device)
15
+ y_pred = model(X)
16
+ y = y.unsqueeze(dim = 1).float()
17
+ loss = loss_fn(y_pred, y)
18
+ train_loss = train_loss + loss.item()
19
+ optimizer.zero_grad()
20
+ loss.backward()
21
+ optimizer.step()
22
+
23
+ y_pred_class = torch.sigmoid(y_pred)
24
+ acc = (y_pred_class == y).sum().item() / len(y_pred)
25
+ train_acc = train_acc + acc
26
+
27
+ train_loss = train_loss / len(dataloader)
28
+ train_acc = train_acc / len(dataloader)
29
+
30
+ return train_loss, train_acc
31
+
32
+ def test_step(model: torch.nn.Module,
33
+ dataloader: torch.utils.data.DataLoader,
34
+ loss_fn: torch.nn.Module,
35
+ device: torch.device):
36
+ model.eval()
37
+ test_loss, test_acc = 0, 0
38
+
39
+ with torch.inference_mode():
40
+ for batch, (X, y) in enumerate(dataloader):
41
+ X, y = X.to(device), y.to(device)
42
+ y_pred = model(X)
43
+ y = y.unsqueeze(dim = 1).float()
44
+ loss = loss_fn(y_pred, y)
45
+ test_loss = test_loss + loss.item()
46
+
47
+ y_pred_class = y_pred.sigmoid()
48
+ acc = (y_pred_class == y).sum().item() / len(y_pred)
49
+ test_acc = test_acc + acc
50
+ test_loss = test_loss / len(dataloader)
51
+ test_acc = test_acc / len(dataloader)
52
+ return test_loss, test_acc
53
+ def train(model: torch.nn.Module,
54
+ train_dataloader: torch.utils.data.DataLoader,
55
+ test_dataloader: torch.utils.data.DataLoader,
56
+ optimizer: torch.optim.Optimizer,
57
+ loss_fn: torch.nn.Module,
58
+ epochs: int,
59
+ device: torch.device,
60
+ writer: torch.utils.tensorboard.SummaryWriter):
61
+ results = {"train_loss": [],
62
+ "train_acc": [],
63
+ "test_loss": [],
64
+ "test_acc": []}
65
+ model.to(device)
66
+ # loss_fn = nn.CrossEntropyLoss()
67
+ # optimizer = torch.optim.Adam(model.parameters(),lr = 0.01)
68
+ for epoch in tqdm(range(epochs)):
69
+ train_loss, train_acc = train_step(model = model,
70
+ dataloader = train_dataloader,
71
+ loss_fn = loss_fn,
72
+ optimizer = optimizer,
73
+ device = device)
74
+ test_loss, test_acc = test_step(model = model,
75
+ dataloader = test_dataloader,
76
+ loss_fn = loss_fn,
77
+ device = device)
78
+
79
+ print(
80
+ f"| Epoch: {epoch+1} | "
81
+ f"train_loss: {train_loss:.4f} | "
82
+ f"train_acc: {train_loss:.4f} | "
83
+ f"test_loss: {test_loss:.4f} | "
84
+ f"test_acc: {test_loss:.4f} |"
85
+ )
86
+
87
+ results['train_loss'].append(train_loss)
88
+ results['train_acc'].append(train_acc)
89
+ results['test_loss'].append(test_loss)
90
+ results['test_acc'].append(test_acc)
91
+
92
+ writer.add_scalars(main_tag="Loss",
93
+ tag_scalar_dict={"train_loss": train_loss,
94
+ "test_loss": test_loss},
95
+ global_step=epoch)
96
+
97
+ # Add accuracy results to SummaryWriter
98
+ writer.add_scalars(main_tag="Accuracy",
99
+ tag_scalar_dict={"train_acc": train_acc,
100
+ "test_acc": test_acc},
101
+ global_step=epoch)
102
+
103
+ # Track the PyTorch model architecture
104
+ writer.add_graph(model=model,
105
+ # Pass in an example input
106
+ input_to_model=torch.randn(32, 3, 224, 224).to(device))
107
+
108
+ # Close the writer
109
+ writer.close()
110
+ return results
Experiments Notebook/scripts/utils.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import torch
3
+ def save_model(model: torch.nn.Module,
4
+ model_name: str,
5
+ target_dir: str):
6
+ target_dir_path = Path(target_dir)
7
+ target_dir_path.mkdir(parents = True,
8
+ exist_ok = True)
9
+ assert model_name.endswith(".pth") or model_name.endswith(".pt"), "Model name should end with .pth or .pt"
10
+ model_save_path = target_dir_path / model_name
11
+ torch.save(obj = model.state_dict(),
12
+ f = model_save_path)
ResNet18_epoch-14.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:91c272423567b9d8fec8de8a8cefc979e5838546008dbe7cc7b4377ff163c31d
3
+ size 44787749
app.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from model import create_resnet
3
+ import numpy as np
4
+ import gradio as gr
5
+ import os
6
+ from timeit import default_timer as timer
7
+ from typing import Tuple, Dict
8
+
9
+ model = create_resnet()
10
+ model.load_state_dict(torch.load(f="ResNet18_epoch-14.pth",
11
+ map_location=torch.device("cpu")))
12
+
13
+ from torchvision import datasets, transforms
14
+ transform = transforms.Compose([
15
+ transforms.Resize(256),
16
+ transforms.CenterCrop(224),
17
+ transforms.ToTensor(),
18
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
19
+ ])
20
+
21
+ def predict(img):
22
+ start_time = timer()
23
+ transformed_image = transform(img)
24
+ transformed_image = transformed_image.unsqueeze(0)
25
+ model.eval()
26
+
27
+ with torch.no_grad():
28
+ output = model(transformed_image)
29
+ predicted_label = int(torch.sigmoid(output).item())
30
+
31
+ end_time = timer()
32
+ pred_time = round(end_time - start_time, 4)
33
+ output = "Good" if predicted_label == 1 else "Bad"
34
+
35
+ return output, pred_time
36
+
37
+ # Gradio Interface
38
+ title = "πŸ‹ Lemon Quality Classifier πŸ‹"
39
+ description = "A [ResNet18](https://pytorch.org/vision/main/models/generated/torchvision.models.resnet18.html) computer vision model to classify lemons as good or bad in quality."
40
+ article = "Created for practice and learning."
41
+
42
+ example_list = [["examples/" + example] for example in os.listdir("examples")]
43
+
44
+ demo = gr.Interface(fn=predict,
45
+ inputs=gr.Image(type="pil"),
46
+ outputs=[gr.Label(num_top_classes=1, label="Prediction"),
47
+ gr.Number(label="Prediction time (s)")],
48
+ examples=example_list,
49
+ title=title,
50
+ description=description,
51
+ article=article)
52
+
53
+ demo.launch()
examples/bad_quality_0.jpg ADDED
examples/bad_quality_100.jpg ADDED
examples/good_quality_1.jpg ADDED
examples/good_quality_100.jpg ADDED
model.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+ from torch import nn
4
+
5
+ # Function for ResNet18.
6
+ def create_resnet():
7
+ weights = torchvision.models.ResNet18_Weights.DEFAULT
8
+ transforms = weights.transforms()
9
+ model = torchvision.models.resnet18(weights = weights)
10
+ for param in model.parameters():
11
+ param.requires_grad = False
12
+ model.fc = nn.Linear(in_features=512, out_features=1, bias=True)
13
+ return model
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ torch==2.0.0
2
+ torchvision==0.15.1
3
+ gradio==3.1.4