vikenkd commited on
Commit
2a2559c
·
1 Parent(s): 02c1b33

upload all files

Browse files
.gitignore CHANGED
@@ -205,3 +205,10 @@ cython_debug/
205
  marimo/_static/
206
  marimo/_lsp/
207
  __marimo__/
 
 
 
 
 
 
 
 
205
  marimo/_static/
206
  marimo/_lsp/
207
  __marimo__/
208
+
209
+
210
+ # local
211
+ datasets/*
212
+ checkpoints/*
213
+ dc_env/*
214
+ note.md
README.md ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Image classification - Cat & Dog Classification
2
+
3
+ ### Prerequistiion Requirements:
4
+ - Training Processing:
5
+ - Datasets Zip file to be saved in datasets folder.
6
+ - Dependencies Installation:
7
+ - Create an virtual environment with conda
8
+ - conda `create -p dc_env python=3.9 -y`
9
+ - Activate created env: `conda activate dc_env/`
10
+ - Using `pip install -r requirements.txt`
11
+ - Other Requirements:
12
+ - GPU (E.g: NVIDIA RTX 3050,...)
13
+ - Python version >= 3.9
14
+
15
+ ## How to run this project:
16
+ ### Training the model:
17
+ - Utilizing `python src/train.py`
18
+
19
+ ### Run Deployment on your local:
20
+ - Utilizing `python deployment/gradio/main.py` \
21
+ Or
22
+ - On HuggingFace Server, you can access at: ``
23
+
24
+
25
+
26
+
27
+
deployment/gradio/__init__.py ADDED
File without changes
deployment/gradio/main.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+
4
+ def greet(name):
5
+ return f"Hello {name}!"
6
+
7
+ def classify_image(image):
8
+ return "cat" # Placeholder for actual image classification logic
9
+
10
+
11
+ with gr.Blocks() as demo:
12
+ gr.Markdown("# Cat vs Dog Classifier")
13
+ with gr.Row():
14
+ with gr.Column():
15
+ image_input = gr.Image(shape=(224, 224))
16
+ classify_button = gr.Button("Classify")
17
+ with gr.Column():
18
+ output_text = gr.Textbox(label="Prediction")
19
+
20
+ classify_button.click(fn=classify_image, inputs=image_input, outputs=output_text)
21
+
22
+ # Image input and output example
23
+ demo = gr.Interface(
24
+ fn=greet,
25
+ inputs=gr.inputs.Image(shape=(224, 224)),
26
+ outputs="text"
27
+ )
28
+
29
+ demo.launch(debug=True)
30
+ demo.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ scikit-learn
2
+ gradio
3
+ pydantic
4
+ torch torchvision --index-url https://download.pytorch.org/whl/cu126
src/__init__.py ADDED
File without changes
src/config.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import List, Dict, Optional
3
+
4
+
5
+ class CatDogClassifierConfigs(BaseModel):
6
+ device: str = Field(
7
+ default="cpu",
8
+ description="Device to run the model on (cpu or cuda)"
9
+ )
10
+ input_channels: int = Field(
11
+ default=3,
12
+ description="Number of input channels for the images"
13
+ )
14
+ kernel_size: int = Field(
15
+ default=3,
16
+ description="Size of the convolutional kernel"
17
+ )
18
+ stride: int = Field(
19
+ default=1,
20
+ description="Stride for the convolutional layers"
21
+ )
22
+ padding: int = Field(
23
+ default=1,
24
+ description="Padding for the convolutional layers"
25
+ )
26
+ num_layers: int = Field(
27
+ default=2,
28
+ description="Number of convolutional layers"
29
+ )
30
+ learning_rate: float = Field(
31
+ default=0.001,
32
+ description="Learning rate for the optimizer"
33
+ )
34
+ num_classes: int = Field(
35
+ default=2,
36
+ description="Number of output classes (cat and dog)"
37
+ )
38
+
39
+ class CatDogDatasetConfigsInput(BaseModel):
40
+ data_path: str = Field(
41
+ default="datasets/datasets.zip",
42
+ description="Path to the dataset (can be a folder or an archive file)"
43
+ )
44
+ train_data_path: Optional[str] = Field(
45
+ default="datasets/train",
46
+ description="Path to the training data"
47
+ )
48
+ test_data_path: Optional[str] = Field(
49
+ default="datasets/test",
50
+ description="Path to the testing data"
51
+ )
52
+ test_size: Optional[float] = Field(
53
+ default=0.2,
54
+ description="Proportion of the dataset to include in the test split"
55
+ )
56
+ random_state: Optional[int] = Field(
57
+ default=42,
58
+ description="Random seed for data splitting"
59
+ )
60
+
61
+ class DataPreprocessorConfigsInput(BaseModel):
62
+ train_dataset_path: str = Field(
63
+ default="datasets/train",
64
+ description="Path to the training dataset"
65
+ )
66
+ test_dataset_path: str = Field(
67
+ default="datasets/test",
68
+ description="Path to the testing dataset"
69
+ )
70
+ shuffle: bool = Field(
71
+ default=True,
72
+ description="Whether to shuffle the data during loading"
73
+ )
74
+ batch_size: int = Field(
75
+ default=64,
76
+ description="Number of samples per batch"
77
+ )
78
+ horizontal_flip_prob: float = Field(
79
+ default=0.5,
80
+ description="Probability of applying random horizontal flip"
81
+ )
82
+
83
+ image_size: int = Field(
84
+ default=224,
85
+ description="Size to which images will be resized"
86
+ )
87
+ mean: List[float] = Field(
88
+ default=[0.485, 0.456, 0.406],
89
+ description="Mean for normalization"
90
+ )
91
+ std: List[float] = Field(
92
+ default=[0.229, 0.224, 0.225],
93
+ description="Standard deviation for normalization"
94
+ )
src/data_ingestion.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import zipfile
4
+
5
+ from sklearn.model_selection import train_test_split
6
+ from .config import CatDogDatasetConfigsInput
7
+
8
+ class CatDogDataset:
9
+ def __init__(self, data_configs: CatDogDatasetConfigsInput):
10
+ self.configs = data_configs
11
+ self.data_path = data_configs.data_path
12
+ self.train_data_path = data_configs.train_data_path
13
+ self.test_data_path = data_configs.test_data_path
14
+ self.test_size = data_configs.test_size if hasattr(data_configs, 'test_size') else 0.2
15
+ self.random_state = data_configs.random_state if hasattr(data_configs, 'random_state') else 42
16
+
17
+ self.file_type = self.data_path.split('.')[-1]
18
+
19
+ # Check the type of the data path input
20
+ def _check_type(self):
21
+ if self.file_type in ['zip', 'tar', 'tar.gz']:
22
+ return "archive"
23
+ elif self.file_type == '':
24
+ return "folder"
25
+ else:
26
+ raise ValueError(f"Unsupported file type: {self.file_type}")
27
+
28
+ # Extract archive files if data path is an archive
29
+ def _extract_archive(self):
30
+ print(f"Extracting archive: {self.data_path}")
31
+ extract_dir = os.path.splitext(self.data_path)[0]
32
+ os.makedirs(extract_dir, exist_ok=True)
33
+ with zipfile.ZipFile(self.data_path, 'r') as zip_ref:
34
+ zip_ref.extractall(extract_dir)
35
+ print(f"Extracted archive to {extract_dir}")
36
+
37
+ # Remove the original archive file after extraction
38
+ os.remove(self.data_path)
39
+ print(f"Removed archive file: {self.data_path}")
40
+ # Update data_path to point to the extracted folder
41
+ self.data_path = self.data_path.rstrip('.zip').rstrip('.tar').rstrip('.gz')
42
+
43
+
44
+
45
+ def _split_data(self):
46
+ # Split the original dataset into training and testing sets folder
47
+ try:
48
+ # Run into each folder (cats and dogs) and split the images
49
+ for c in os.listdir(self.data_path):
50
+ all_images = os.listdir(os.path.join(self.data_path, c))
51
+ train_images, test_images = train_test_split(
52
+ all_images,
53
+ test_size=self.test_size,
54
+ random_state=self.random_state
55
+ )
56
+
57
+ # Create train and test directories if they don't exist
58
+ os.makedirs(os.path.join(self.train_data_path, c), exist_ok=True)
59
+ os.makedirs(os.path.join(self.test_data_path, c), exist_ok=True)
60
+
61
+ # Move images to respective folders
62
+ for img in train_images:
63
+ shutil.move(os.path.join(self.data_path, c, img), os.path.join(self.train_data_path, c, img))
64
+ for img in test_images:
65
+ shutil.move(os.path.join(self.data_path, c, img), os.path.join(self.test_data_path, c, img))
66
+
67
+ print("Data split successfully")
68
+ # Remove the original data folder after splitting
69
+ shutil.rmtree(self.data_path)
70
+ print("Original data folder removed")
71
+
72
+
73
+ except Exception as e:
74
+ print(f"Error splitting data: {e}")
75
+
76
+
77
+ def load_data(self):
78
+ # Logic to load and preprocess the dataset
79
+ data_type = self._check_type()
80
+ if data_type == "archive":
81
+ self._extract_archive()
82
+ elif data_type == "folder":
83
+ print(f"Loading data from folder: {self.data_path}")
84
+ else:
85
+ raise ValueError("Unsupported data type")
86
+ self._split_data()
87
+ print("Data loading and preprocessing completed")
src/data_preprocessing.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch.utils.data import Dataset, DataLoader
3
+ from torchvision import datasets, transforms
4
+
5
+ from .config import DataPreprocessorConfigsInput
6
+
7
+ class DataPreprocessor:
8
+ def __init__(self, configs: DataPreprocessorConfigsInput):
9
+ self.configs = configs
10
+ self.train_dataset_path = self.configs.train_dataset_path
11
+ self.test_dataset_path = self.configs.test_dataset_path
12
+ self.shuffle = self.configs.shuffle
13
+ self.batch_size = self.configs.batch_size
14
+ self.horizontal_flip_prob = self.configs.horizontal_flip_prob # Probability for random horizontal flip
15
+ self.image_size = self.configs.image_size
16
+ self.mean = self.configs.mean
17
+ self.std = self.configs.std
18
+
19
+
20
+ def preprocess(self, label:str = "train") -> transforms.Compose:
21
+ if label == "train":
22
+ transform = transforms.Compose([
23
+ transforms.Resize((self.image_size, self.image_size)),
24
+ transforms.RandomHorizontalFlip(p=self.horizontal_flip_prob),
25
+ transforms.ToTensor(),
26
+ transforms.Normalize(mean=self.mean, std=self.std),
27
+ ])
28
+
29
+ else:
30
+ transform = transforms.Compose([
31
+ transforms.Resize((self.image_size, self.image_size)),
32
+ transforms.ToTensor(),
33
+ transforms.Normalize(mean=self.mean, std=self.std)
34
+ ])
35
+ return transform
36
+
37
+ def create_dataloader(self) -> DataLoader:
38
+ train_transform = self.preprocess()
39
+ test_transform = self.preprocess(label="test")
40
+ train_dataset = datasets.ImageFolder(root=self.train_dataset_path, transform=train_transform)
41
+ train_dataloader = DataLoader(
42
+ dataset=train_dataset,
43
+ batch_size=self.batch_size,
44
+ shuffle=self.shuffle
45
+ )
46
+
47
+ test_dataset = datasets.ImageFolder(root=self.test_dataset_path, transform=test_transform)
48
+ test_dataloader = DataLoader(
49
+ dataset=test_dataset,
50
+ batch_size=self.batch_size,
51
+ shuffle= not self.shuffle
52
+ )
53
+
54
+ print(f"Train dataset size: {len(train_dataset)}")
55
+ print(f"Test dataset size: {len(test_dataset)}")
56
+
57
+ return train_dataloader, test_dataloader
src/infer.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from src.model import CatDogClassifier
3
+ from src.config import CatDogClassifierConfigs
4
+
5
+ def inference_pipeline(
6
+ image_path: str = "datasets/single_prediction/cat_or_dog_1.jpg"
7
+ ):
8
+
9
+ # Initialize model
10
+ model_configs = CatDogClassifierConfigs(
11
+ device="cuda" if torch.cuda.is_available() else "cpu",
12
+ input_channels=3,
13
+ num_classes=2,
14
+ learning_rate=0.001,
15
+ kernel_size=3,
16
+ stride=2,
17
+ padding=1,
18
+ num_layers=3
19
+ )
20
+ # Load state_dict
21
+ model = CatDogClassifier(configs=model_configs)
22
+ model.load_state_dict(torch.load("cat_dog_classifier.pth", map_location="cpu"))
23
+ y_pred = model.predict(
24
+ model=model,
25
+ image_path=image_path
26
+ )
27
+ print(f"Predicted class for the image {image_path}: {y_pred}")
28
+
29
+ return y_pred
30
+
31
+
32
+
33
+ if __name__ == "__main__":
34
+ y_pred = inference_pipeline("datasets/single_prediction/cat_or_dog_1.jpg")
35
+ print(y_pred)
src/model.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tqdm.auto import tqdm
2
+ from matplotlib import transforms
3
+ import torch
4
+ import torchvision
5
+ import torch.nn as nn
6
+ from .config import CatDogClassifierConfigs
7
+
8
+ class CatDogClassifier(nn.Module):
9
+ def __init__(self, configs: CatDogClassifierConfigs):
10
+ super(CatDogClassifier, self).__init__()
11
+ self.configs = configs
12
+ self.kernel_size = configs.kernel_size
13
+ self.stride = configs.stride
14
+ self.padding = configs.padding
15
+ self.num_layers = configs.num_layers
16
+ self.learning_rate = configs.learning_rate
17
+ self.num_classes = configs.num_classes
18
+ self.input_channels = configs.input_channels
19
+
20
+ # Initialize the model architecture
21
+ self._build_model()
22
+
23
+
24
+ def _build_model(self):
25
+ # Placeholder for model building logic
26
+ self.conv_layer_1 = nn.Sequential(
27
+ nn.Conv2d(
28
+ in_channels=self.input_channels,
29
+ out_channels=64,
30
+ kernel_size=self.kernel_size,
31
+ padding=self.padding
32
+ ),
33
+ nn.ReLU(),
34
+ nn.BatchNorm2d(num_features=64),
35
+ nn.MaxPool2d(kernel_size=2)
36
+ )
37
+ self.conv_layer_2 = nn.Sequential(
38
+ nn.Conv2d(
39
+ in_channels=64,
40
+ out_channels=512,
41
+ kernel_size=self.kernel_size,
42
+ padding=self.padding
43
+ ),
44
+ nn.ReLU(),
45
+ nn.BatchNorm2d(num_features=512),
46
+ nn.MaxPool2d(kernel_size=2)
47
+ )
48
+ self.conv_layer_3 = nn.Sequential(
49
+ nn.Conv2d(
50
+ in_channels=512,
51
+ out_channels=512,
52
+ kernel_size=self.kernel_size,
53
+ padding=self.padding
54
+ ),
55
+ nn.ReLU(),
56
+ nn.BatchNorm2d(num_features=512),
57
+ nn.MaxPool2d(kernel_size=2)
58
+ )
59
+ self.classifier = nn.Sequential(
60
+ nn.Flatten(),
61
+ nn.Linear(in_features=512*3*3, out_features=self.num_classes)
62
+ )
63
+
64
+
65
+ def forward(self, x: torch.Tensor):
66
+ x = self.conv_layer_1(x)
67
+ x = self.conv_layer_2(x)
68
+ x = self.conv_layer_3(x)
69
+ x = self.conv_layer_3(x)
70
+ x = self.conv_layer_3(x)
71
+ x = self.conv_layer_3(x)
72
+ x = self.classifier(x)
73
+ return x
74
+
75
+ def train_process(
76
+ self,
77
+ model: nn.Module,
78
+ train_dataloader: torch.utils.data.DataLoader,
79
+ test_dataloader: torch.utils.data.DataLoader,
80
+ num_epochs: int,
81
+ loss_fn: nn.Module,
82
+ optimizer: torch.optim.Optimizer,
83
+ ):
84
+ # Placeholder for training logic
85
+ print("Training the model with provided data")
86
+ # Implement training loop here
87
+ results = {
88
+ "train_loss": [],
89
+ "train_acc": [],
90
+ "test_loss": [],
91
+ "test_acc": []
92
+ }
93
+
94
+ # Loop through each epoch
95
+ for epoch in tqdm(range(num_epochs)):
96
+ train_loss, train_acc = self._train_step(
97
+ model=model,
98
+ dataloader=train_dataloader,
99
+ loss_fn=loss_fn,
100
+ optimizer=optimizer,
101
+ )
102
+ test_loss, test_acc = self._test_step(
103
+ model=model,
104
+ dataloader=test_dataloader,
105
+ loss_fn=loss_fn,
106
+ )
107
+
108
+ results["train_loss"].append(train_loss)
109
+ results["train_acc"].append(train_acc)
110
+ results["test_loss"].append(test_loss)
111
+ results["test_acc"].append(test_acc)
112
+
113
+ print(
114
+ f"Epoch [{epoch+1}/{num_epochs}] "
115
+ f"Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f} | "
116
+ f"Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.4f}"
117
+ )
118
+
119
+ return results
120
+
121
+ def _train_step(
122
+ self,
123
+ model: nn.Module,
124
+ dataloader: torch.utils.data.DataLoader,
125
+ loss_fn: nn.Module,
126
+ optimizer: torch.optim.Optimizer,
127
+ ):
128
+ # Define model in training mode
129
+ model.train()
130
+
131
+ train_loss, train_acc = 0, 0
132
+
133
+ # Loop through each batch
134
+ for batch_idx, (data, target) in enumerate(dataloader):
135
+ data, target = data.to(self.configs.device), target.to(self.configs.device)
136
+
137
+ # print(f"Batch {batch_idx+1}: data shape {data.shape}, target shape {target.shape}")
138
+ # Forward pass
139
+ y_pred = model(data)
140
+ # Calculate and accumulate loss
141
+ loss = loss_fn(y_pred, target)
142
+ train_loss += loss.item()
143
+ # Backward pass
144
+ optimizer.zero_grad()
145
+ loss.backward()
146
+ optimizer.step()
147
+ # Calculate and accumulate accuracy metric across all batches
148
+ y_pred_labels = torch.argmax(torch.softmax(y_pred, dim=1), dim=1)
149
+ train_acc += (y_pred_labels == target).sum().item()/data.size(0)
150
+
151
+ # Adjust loss and accuracy to get average loss and accuracy based on number of batches
152
+ train_loss /= len(dataloader)
153
+ train_acc /= len(dataloader)
154
+
155
+ return train_loss, train_acc
156
+
157
+ def _test_step(
158
+ self,
159
+ model: nn.Module,
160
+ dataloader: torch.utils.data.DataLoader,
161
+ loss_fn: nn.Module,
162
+ ):
163
+ # Define model in evaluation
164
+ model.eval()
165
+ test_loss, test_acc = 0, 0
166
+ with torch.no_grad():
167
+ for batch_idx, (data, target) in enumerate(dataloader):
168
+ data, target = data.to(self.configs.device), target.to(self.configs.device)
169
+ # Forward pass
170
+ y_pred = model(data)
171
+ # Calculate and accumulate loss
172
+ loss = loss_fn(y_pred, target)
173
+ test_loss += loss.item()
174
+ # Calculate and accumulate accuracy metric across all batches
175
+ y_pred_labels = torch.argmax(torch.softmax(y_pred, dim=1), dim=1)
176
+ test_acc += (y_pred_labels == target).sum().item()/data.size(0)
177
+ # Adjust loss and accuracy to get average loss and accuracy based on number of batches
178
+ test_loss /= len(dataloader)
179
+ test_acc /= len(dataloader)
180
+
181
+ return test_loss, test_acc
182
+
183
+
184
+ def predict(
185
+ self,
186
+ model: nn.Module,
187
+ image_path: str
188
+ ) -> str:
189
+ # Load and preprocess the image converting it to a tensor
190
+ # and normalizing the pixel values between 0 and 1
191
+ image_tensor = torchvision.io.read_image(str(image_path)).type(torch.float32) / 255.0
192
+ image_tensor_transformed = transforms.Compose([
193
+ transforms.Resize((256, 256)),
194
+ transforms.CenterCrop((224, 224)),
195
+ transforms.ToTensor(),
196
+ ])(image_tensor)
197
+
198
+ model.eval()
199
+ with torch.no_grad():
200
+ image_tensor_transformed = image_tensor_transformed.unsqueeze(0) # Add batch dimension
201
+ image_tensor_pred = model(image_tensor_transformed).to(self.configs.device)
202
+ predicted_label = torch.argmax(torch.softmax(image_tensor_pred, dim=1), dim=1).item()
203
+
204
+ if predicted_label == 0:
205
+ return "cat"
206
+ else:
207
+ return "dog"
208
+
src/train.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+ from src import model
6
+ from src.config import (
7
+ CatDogDatasetConfigsInput,
8
+ CatDogClassifierConfigs,
9
+ DataPreprocessorConfigsInput
10
+ )
11
+ from src.data_ingestion import CatDogDataset
12
+ from src.data_preprocessing import DataPreprocessor
13
+ from src.model import CatDogClassifier
14
+
15
+
16
+ def train_pipeline():
17
+ # Setup Intialize configurations
18
+ # Data ingestion
19
+ data_path = "datasets/datasets.zip"
20
+ train_data_path = "datasets/train"
21
+ test_data_path = "datasets/test"
22
+
23
+ data_path = os.path.join(os.getcwd(), data_path)
24
+ train_data_path = os.path.join(os.getcwd(), train_data_path)
25
+ test_data_path = os.path.join(os.getcwd(), test_data_path)
26
+
27
+
28
+ # data_ingestion_configs = CatDogDatasetConfigsInput(
29
+ # data_path=data_path,
30
+ # train_data_path=train_data_path,
31
+ # test_data_path=test_data_path,
32
+ # test_size=0.2,
33
+ # random_state=42
34
+ # )
35
+ # print(data_ingestion_configs)
36
+ # dataset = CatDogDataset(data_ingestion_configs)
37
+ # dataset.load_data()
38
+
39
+ # Data preprocessing
40
+ data_preprocessing_configs = DataPreprocessorConfigsInput(
41
+ train_dataset_path=train_data_path,
42
+ test_dataset_path=test_data_path,
43
+ shuffle=True,
44
+ batch_size=32,
45
+ horizontal_flip_prob=0.5,
46
+ image_size=224,
47
+ mean=[0.485, 0.456, 0.406],
48
+ std=[0.229, 0.224, 0.225]
49
+ )
50
+ preprocessor = DataPreprocessor(data_preprocessing_configs)
51
+ train_dataloader, test_dataloader = preprocessor.create_dataloader()
52
+ device = "cuda" if torch.cuda.is_available() else "cpu"
53
+
54
+ # Model training
55
+ model_configs = CatDogClassifierConfigs(
56
+ device=device,
57
+ input_channels=3,
58
+ num_classes=2,
59
+ learning_rate=0.001,
60
+ kernel_size=3,
61
+ stride=2,
62
+ padding=1,
63
+ num_layers=3
64
+ )
65
+
66
+ model = CatDogClassifier(model_configs)
67
+ model.to(device)
68
+ # Set random seeds
69
+ torch.manual_seed(42)
70
+ torch.cuda.manual_seed(42)
71
+ # Setup loss function and optimizer
72
+ loss_fn = nn.CrossEntropyLoss()
73
+ optimizer = torch.optim.Adam(params=model.parameters(), lr=0.001)
74
+
75
+ # # Calculate training time using timeit
76
+ # Start the timer
77
+ from timeit import default_timer as timer
78
+ start_time = timer()
79
+
80
+ model.train_process(
81
+ model=model,
82
+ train_dataloader=train_dataloader,
83
+ test_dataloader=test_dataloader,
84
+ num_epochs=30,
85
+ loss_fn=loss_fn,
86
+ optimizer=optimizer
87
+ )
88
+ end_time = timer()
89
+ print(f"Training completed in {end_time - start_time} seconds.")
90
+
91
+ # Save the trained model
92
+ torch.save(model.state_dict(), "cat_dog_classifier.pth")
93
+ print("Model saved to cat_dog_classifier.pth")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ train_pipeline()
tests/data_ingestion.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.config import CatDogDatasetConfigsInput
2
+ from src.data_ingestion import CatDogDataset
3
+ def main():
4
+ # Initialize data ingestion with configurations
5
+ data_configs = CatDogDatasetConfigsInput(
6
+ data_path="datasets/datasets.zip",
7
+ train_data_path="datasets/train",
8
+ test_data_path="datasets/test",
9
+ test_size=0.2,
10
+ random_state=42
11
+ )
12
+ print(data_configs)
13
+ dataset = CatDogDataset(data_configs)
14
+ dataset.load_data()
15
+
16
+ if __name__ == "__main__":
17
+ main()
tests/test_gpu.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+ if __name__ == "__main__":
4
+ print(torch.cuda.is_available())
5
+ print(torch.version.cuda)
6
+ print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "No GPU detected")