k23064919 commited on
Commit
d4a4907
·
2 Parent(s): 3fa9185 a0eb548

Merge branch 'develop' of https://github.kcl.ac.uk/K23064919/smallGroupProject into develop

Browse files
dataPrep/data_preparation.py CHANGED
@@ -74,15 +74,15 @@ task.connect({
74
  })
75
 
76
  # ----- Load a subset from a given dataset & track with ClearML -----
77
- data_plants, prototyping_dataset, features, clearml_dataset = make_subset(
78
- DATASET_LINK, DATASET_SUBSET_RATIO, clearml_logger
79
  )
80
 
81
 
82
  # ---- Exploratory data analysis (EDA) ----
83
 
84
  # Reformatting the label feature to understand bias
85
- labels_list = prototyping_dataset['label']
86
  df_labels = pd.Series(labels_list)
87
  label_count = df_labels.value_counts(sort=False)
88
 
@@ -111,6 +111,7 @@ clearml_logger.report_scalar(
111
  value=(max_count / min_count),
112
  iteration=1
113
  )
 
114
  print("--- Class imbalance analysis --- ")
115
  print(f"Max labels in a class: {max_count}")
116
  print(f"Min labels in a class: {min_count}")
@@ -122,16 +123,17 @@ class_names = features['label'].names
122
  formatted_class_names = [" ".join(name.replace('_', ' ').split()) for name in class_names]
123
  label_count.index = formatted_class_names
124
 
 
125
  plt.figure(figsize=(10,6))
126
  label_count.plot(kind='bar', color='skyblue')
127
- plt.title("Class Distribution in Prototype Dataset")
128
  plt.xlabel("Class")
129
  plt.ylabel("Count")
130
  plt.tight_layout()
131
 
132
  clearml_logger.report_matplotlib_figure(
133
  title="EDA Class Distribution",
134
- series="Prototype Subset",
135
  figure=plt.gcf(),
136
  iteration=1
137
  )
@@ -149,7 +151,7 @@ if __name__ == "__main__":
149
  }
150
 
151
  prototype_loaders = make_dataset_loaders(
152
- prototyping_dataset, SEED, BATCH_SIZE, TEST_SIZE, aug_config
153
  )
154
 
155
  print("\n--- Handoff Test Successful ---")
@@ -173,14 +175,9 @@ if __name__ == "__main__":
173
  print(f"Validation loader batches: {len(final_loaders['val'])}")
174
  print(f"Test loader batches: {len(final_loaders['test'])}")
175
 
176
- # Record dataset info in ClearML
177
- task.connect_configuration(
178
- {"dataset_id": clearml_dataset.id},
179
- name="Dataset Metadata"
180
- )
181
- task.mark_completed()
182
 
183
-
184
  # Close the ClearML task
 
185
  task.close()
 
186
  print("\n--- Script Finished ---")
 
74
  })
75
 
76
  # ----- Load a subset from a given dataset & track with ClearML -----
77
+ data_plants, subset_dataset, features = make_subset(
78
+ DATASET_LINK, DATASET_SUBSET_RATIO, task
79
  )
80
 
81
 
82
  # ---- Exploratory data analysis (EDA) ----
83
 
84
  # Reformatting the label feature to understand bias
85
+ labels_list = subset_dataset['label']
86
  df_labels = pd.Series(labels_list)
87
  label_count = df_labels.value_counts(sort=False)
88
 
 
111
  value=(max_count / min_count),
112
  iteration=1
113
  )
114
+
115
  print("--- Class imbalance analysis --- ")
116
  print(f"Max labels in a class: {max_count}")
117
  print(f"Min labels in a class: {min_count}")
 
123
  formatted_class_names = [" ".join(name.replace('_', ' ').split()) for name in class_names]
124
  label_count.index = formatted_class_names
125
 
126
+ # Plotting class distribution
127
  plt.figure(figsize=(10,6))
128
  label_count.plot(kind='bar', color='skyblue')
129
+ plt.title("Class Distribution in Subset Dataset")
130
  plt.xlabel("Class")
131
  plt.ylabel("Count")
132
  plt.tight_layout()
133
 
134
  clearml_logger.report_matplotlib_figure(
135
  title="EDA Class Distribution",
136
+ series="Subset Dataset",
137
  figure=plt.gcf(),
138
  iteration=1
139
  )
 
151
  }
152
 
153
  prototype_loaders = make_dataset_loaders(
154
+ subset_dataset, SEED, BATCH_SIZE, TEST_SIZE, aug_config
155
  )
156
 
157
  print("\n--- Handoff Test Successful ---")
 
175
  print(f"Validation loader batches: {len(final_loaders['val'])}")
176
  print(f"Test loader batches: {len(final_loaders['test'])}")
177
 
 
 
 
 
 
 
178
 
 
179
  # Close the ClearML task
180
+ task.mark_completed()
181
  task.close()
182
+
183
  print("\n--- Script Finished ---")
dataPrep/helpers/clearml_data.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+
4
+ from clearml import Task, Dataset
5
+ from datasets import load_dataset
6
+ from dataPrep.helpers.transforms_loaders import make_dataset_loaders
7
+
8
+
9
+ '''
10
+ Takes latest Data Prep ClearML task from project and reconstruct:
11
+ - data loaders for both full and subset datasets
12
+ - Aug settings used
13
+ '''
14
+ def extract_latest_data_task(project_name: str = "Small Group Project"):
15
+
16
+ # --------- Get latest Data Preparation task from ClearML ---------
17
+
18
+ all_tasks = Task.get_tasks(
19
+ project_name=project_name,
20
+ allow_archived=False,
21
+ task_filter={'order_by': ["-last_update"]},
22
+ )
23
+
24
+ if not all_tasks:
25
+ raise RuntimeError(f"No tasks found in project '{project_name}'")
26
+
27
+ dp_tasks = [
28
+ t for t in all_tasks
29
+ if t.task_type == Task.TaskTypes.data_processing
30
+ and t.completed is not None
31
+ ]
32
+
33
+ if not dp_tasks:
34
+ raise RuntimeError("No 'Data Preparation' tasks found in this project!")
35
+
36
+ # Latest Data Prep Task
37
+ latest_task = dp_tasks[0]
38
+ DYNAMIC_TASK_ID = latest_task.id
39
+ DATA_PREP = Task.get_task(task_id=DYNAMIC_TASK_ID)
40
+
41
+ # Load subset indices artifact from Data Prep task
42
+ artifacts = DATA_PREP.artifacts
43
+ if "subset_indices" not in artifacts:
44
+ raise RuntimeError("Data Prep task did not upload 'subset_indices' artifact!")
45
+
46
+ artifact = artifacts["subset_indices"]
47
+ subset_indices_path = artifact.get_local_copy()
48
+ subset_indices = np.load(subset_indices_path)
49
+
50
+ # Load dataset metadata from Data Prep task
51
+ data_params = DATA_PREP.get_parameters()
52
+
53
+ subset_ratio = float(data_params['General/dataset/subset_ratio'])
54
+ dataset_link = data_params['General/dataset/link']
55
+ seed = int(data_params['General/seed'])
56
+ batch_size = int(data_params['General/dataloaders/batch_size'])
57
+ test_size = float(data_params['General/dataloaders/test_size'])
58
+
59
+ aug_config = {
60
+ 'rotation': float(data_params['General/augmentation/rotation']),
61
+ 'brightness': float(data_params['General/augmentation/brightness']),
62
+ 'saturation': float(data_params['General/augmentation/saturation']),
63
+ 'blur': float(data_params['General/augmentation/blur']),
64
+ }
65
+
66
+
67
+ # Load Full Dataset
68
+ try:
69
+ ds = load_dataset(dataset_link)
70
+ except Exception as e:
71
+ raise RuntimeError(f"Error loading the dataset: {e}")
72
+
73
+ full_dataset = ds['train']
74
+
75
+ # Apply subset indices to full dataset - this gives you the same subset as data prep
76
+ subset_dataset = full_dataset.select(subset_indices)
77
+
78
+ # Get data loaders for both full and subset datasets
79
+ subset_loaders, full_loaders, aug_config = get_data_loaders(data_params, subset_dataset, full_dataset)
80
+ batch_size = int(data_params['General/dataloaders/batch_size'])
81
+ seed = int(data_params['General/seed'])
82
+
83
+
84
+ # Gather data prep task metadata
85
+ data_prep_metadata = {
86
+ "data_prep_task_id": DYNAMIC_TASK_ID,
87
+ "dataset_link": dataset_link,
88
+ "subset_ratio_used": subset_ratio,
89
+ "augmentation_used": aug_config,
90
+ "batch_size_used": batch_size,
91
+ "seed_used": seed,
92
+ "test_size_used": test_size
93
+ }
94
+
95
+ return subset_loaders, full_loaders, data_prep_metadata
96
+
97
+
98
+ '''
99
+ Takes a given dataset, subset, data params to create DataLoaders
100
+ Loaders split data into train, val, test
101
+ '''
102
+ def get_data_loaders(data_params, subset_dataset, full_dataset):
103
+
104
+ # Extract data parameters- these will be used in the DataLoaders
105
+ seed = int(data_params['General/seed'])
106
+ batch_size = int(data_params['General/dataloaders/batch_size'])
107
+ test_size = float(data_params['General/dataloaders/test_size'])
108
+
109
+ aug_config = {
110
+ 'rotation': float(data_params['General/augmentation/rotation']),
111
+ 'brightness': float(data_params['General/augmentation/brightness']),
112
+ 'saturation': float(data_params['General/augmentation/saturation']),
113
+ 'blur': float(data_params['General/augmentation/blur'])
114
+ }
115
+
116
+ # Create DataLoaders using the parameters from data prep
117
+ subset_loaders = make_dataset_loaders(
118
+ subset_dataset, seed, batch_size, test_size, aug_config
119
+ )
120
+
121
+ print("\n--- Handoff Test Successful ---")
122
+ print(f"Prototype Train loader batches: {len(subset_loaders['train'])}")
123
+ print(f"Prototype Validation loader batches: {len(subset_loaders['val'])}")
124
+ print(f"Prototype Test loader batches: {len(subset_loaders['test'])}")
125
+
126
+
127
+ full_loaders = make_dataset_loaders(
128
+ full_dataset, seed, batch_size, test_size, aug_config
129
+ )
130
+
131
+ print("\n--- Handoff Test Successful ---")
132
+ print(f"Train loader batches: {len(full_loaders['train'])}")
133
+ print(f"Validation loader batches: {len(full_loaders['val'])}")
134
+ print(f"Test loader batches: {len(full_loaders['test'])}")
135
+
136
+ return subset_loaders, full_loaders, aug_config
dataPrep/helpers/create_dataset.py CHANGED
@@ -6,7 +6,6 @@ import os
6
  import random
7
  import numpy as np
8
  from datasets import load_dataset
9
- from clearml import Dataset
10
 
11
 
12
  '''
@@ -14,7 +13,7 @@ Load a DS from HuggingFace Link & randomly subset it - upload subset to ClearML
14
  Subset indicies are uploaded to ClearML for reproducibility
15
  REPRODUCE: Load full DS, then load indicies from ClearML to get same subset
16
  '''
17
- def make_subset(dataset_link, subset_ratio, clearml_logger):
18
 
19
  # Load dataset
20
  try:
@@ -34,36 +33,16 @@ def make_subset(dataset_link, subset_ratio, clearml_logger):
34
  random.shuffle(indices)
35
  subset_indices = indices[:subset_size]
36
 
37
- prototyping_dataset = data_plants.select(subset_indices)
38
- # I THINK WE NEED TO REMOVE THIS LATER
39
- # We dont really need to upload subset everytime (Im not sure tho)
40
- # Register subset in ClearML
41
- clearml_dataset = Dataset.create(
42
- dataset_name="Plant Village Prototype",
43
- dataset_project="Small Group Project",
44
- dataset_tags=["prototype", "subset"],
45
- use_current_task=False
46
- )
47
- clearml_dataset.add_tags([
48
- f"subset_ratio_{subset_ratio}",
49
- "hf_source"
50
- ])
51
 
52
- # Save indices
53
  subset_path = "subset_indices.npy"
54
  np.save(subset_path, subset_indices)
55
- clearml_dataset.add_files(subset_path)
56
- clearml_dataset.set_metadata({
57
- "huggingface_dataset": dataset_link,
58
- "subset_ratio": subset_ratio,
59
- "total_samples": len(prototyping_dataset)
60
- })
61
-
62
- clearml_dataset.upload()
63
- clearml_dataset.finalize()
64
- clearml_logger.report_text(f"Created ClearML Dataset: {clearml_dataset.id}")
65
 
66
- # Clean up local file
67
- os.remove(subset_path)
 
 
 
68
 
69
- return data_plants, prototyping_dataset, features, clearml_dataset
 
6
  import random
7
  import numpy as np
8
  from datasets import load_dataset
 
9
 
10
 
11
  '''
 
13
  Subset indicies are uploaded to ClearML for reproducibility
14
  REPRODUCE: Load full DS, then load indicies from ClearML to get same subset
15
  '''
16
+ def make_subset(dataset_link, subset_ratio, clearml_task):
17
 
18
  # Load dataset
19
  try:
 
33
  random.shuffle(indices)
34
  subset_indices = indices[:subset_size]
35
 
36
+ subset_dataset = data_plants.select(subset_indices)
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ # -------- Upload the subset indices as a ClearML artifact --------
39
  subset_path = "subset_indices.npy"
40
  np.save(subset_path, subset_indices)
 
 
 
 
 
 
 
 
 
 
41
 
42
+ clearml_task.upload_artifact(
43
+ name="subset_indices",
44
+ artifact_object=subset_path
45
+ )
46
+ clearml_task.get_logger().report_text(f"Uploaded subset indices as artifact: {subset_path}")
47
 
48
+ return data_plants, subset_dataset, features
requirements.txt CHANGED
@@ -1,29 +1,19 @@
1
 
2
  # Core dependencies
3
- torch>=2.0.0
4
- torchvision>=0.15.0
5
- gradio>=4.0.0
6
- numpy>=1.24.0
7
- Pillow>=10.0.0
 
8
 
9
- # For model deployment and tracking
10
- huggingface-hub>=0.19.0
11
- clearml>=1.14.0
12
-
13
- # Optional: for advanced features
14
- datasets>=2.14.0 # For loading PlantVillage dataset from HuggingFace
15
- # -- Data prep requirements --
16
  # Data Handling & Analysis
17
- numpy
18
- pandas
19
- datasets
20
 
21
  # Visualization
22
- matplotlib
23
 
24
- # PyTorch (Machine Learning)
25
- torch
26
- torchvision
27
-
28
- # Experiment Tracking
29
- clearml
 
1
 
2
  # Core dependencies
3
+ torch==2.2.2
4
+ torchvision==0.17.2
5
+ torcheval==0.0.7
6
+ numpy==1.26.4
7
+ Pillow==10.3.0
8
+ gradio==4.19.0
9
 
 
 
 
 
 
 
 
10
  # Data Handling & Analysis
11
+ pandas==2.2.2
12
+ datasets==2.18.0
 
13
 
14
  # Visualization
15
+ matplotlib==3.8.4
16
 
17
+ # For model deployment and tracking
18
+ huggingface-hub==0.23.0
19
+ clearml==2.0.2
 
 
 
trainingModel/Training.py CHANGED
@@ -15,10 +15,10 @@ def train_model(
15
  device: torch.device,
16
  n_epochs: int = 4,
17
  lr: float = 1e-3,
 
 
 
18
  save_path: str = "best_model.pt",
19
- flatten_input = False,
20
- num_classes : int = 39,
21
-
22
  ):
23
  """
24
  Trains the given model and returns:
@@ -40,7 +40,11 @@ def train_model(
40
 
41
  # Loss and optimizer
42
  criterion = nn.CrossEntropyLoss()
43
- optimizer = torch.optim.Adam(model.parameters(), lr=lr ) # might add momentum 0.9 later
 
 
 
 
44
 
45
  # Metric trackers
46
  train_accuracy_fn = MulticlassAccuracy(num_classes=num_classes)
@@ -49,20 +53,31 @@ def train_model(
49
  # Arrays to log metrics
50
  num_batches = len(train_loader)
51
 
 
 
 
 
 
 
 
 
 
 
52
  if num_batches == 0:
53
  raise RuntimeError("UH OH!!!! empty train loader")
54
 
55
  # Store training losses and accuracies for every batch
56
  # num_batches is the number of batches for every epoch
57
- training_losses = np.zeros(num_batches * n_epochs)
58
- training_accuracies = np.zeros(num_batches * n_epochs)
59
 
60
  # store validation accuracy for every epoch
61
- val_accuracies = np.zeros(n_epochs)
62
 
63
  # keep track of best validation accuracy and best model
64
  best_accuracy = 0.0
65
 
 
66
  #----------------------
67
  # training loop
68
  #----------------------
@@ -71,8 +86,12 @@ def train_model(
71
  model.train()
72
  train_accuracy_fn.reset()
73
 
 
 
 
 
74
  # iterate over all the dataloader's mini-batches
75
- for i, batch in enumerate(train_loader):
76
 
77
  # move to GPU memory
78
  inputs = batch["image"].to(device)
@@ -88,22 +107,30 @@ def train_model(
88
  outputs = model(inputs)
89
  loss = criterion(outputs, labels)
90
 
91
- # Backward pass
92
  loss.backward()
93
-
94
- # updates the parameters
95
  optimizer.step()
96
-
97
- # log the loss value
98
- training_losses[epoch * num_batches + i] = loss.item()
99
 
100
- #updates the accuracy computation with new data
101
- train_accuracy_fn.update(outputs, labels)
 
 
 
 
 
 
 
 
102
 
103
- #compute accuracy with the current data
104
- training_accuracies[epoch * num_batches + i] = train_accuracy_fn.compute().item()
 
105
 
106
- print(f'Epoch {epoch + 1} training complete')
 
 
 
 
107
 
108
  # ----------------------
109
  # validation loop
@@ -123,25 +150,30 @@ def train_model(
123
  inputs = inputs.view(inputs.size(0), -1)
124
 
125
  outputs = model(inputs)
126
-
127
  val_accuracy_fn.update(outputs, labels)
128
 
129
- current_accuracy = val_accuracy_fn.compute().item()
130
- val_accuracies[epoch] = current_accuracy
 
 
 
131
 
132
  # keep track of best validation accuracy and save best model so far
133
- if current_accuracy > best_accuracy:
134
- best_accuracy = current_accuracy
135
  torch.save(model.state_dict(), save_path)
136
- print(f'Epoch {epoch + 1} (validation accuracy: {best_accuracy})')
137
- print(f'Epoch {epoch + 1} validation complete')
 
138
 
139
  print(f"\nTraining finished. Best val accuracy: {best_accuracy:.4f}")
140
  print(f"Best model weights saved to: {save_path}")
141
 
142
  training_metrics = {
143
- "losses": training_losses,
144
- "accuracies": training_accuracies,
 
 
145
  "val_accuracies": val_accuracies,
146
  "best_accuracy": best_accuracy,
147
  }
 
15
  device: torch.device,
16
  n_epochs: int = 4,
17
  lr: float = 1e-3,
18
+ num_classes: int = 39,
19
+ optimizer_type: str = "adam",
20
+ flatten_input: bool = False,
21
  save_path: str = "best_model.pt",
 
 
 
22
  ):
23
  """
24
  Trains the given model and returns:
 
40
 
41
  # Loss and optimizer
42
  criterion = nn.CrossEntropyLoss()
43
+
44
+ if optimizer_type.lower() == "adam":
45
+ optimizer = torch.optim.Adam(model.parameters(), lr=lr ) # might add momentum 0.9 later
46
+ else:
47
+ optimizer = torch.optim.AdamW(model.parameters(), lr=lr )
48
 
49
  # Metric trackers
50
  train_accuracy_fn = MulticlassAccuracy(num_classes=num_classes)
 
53
  # Arrays to log metrics
54
  num_batches = len(train_loader)
55
 
56
+ # Batch-level logs
57
+ batch_losses = []
58
+ batch_accuracies = []
59
+
60
+ # Epoch-level logs
61
+ epoch_losses = np.zeros(n_epochs)
62
+ epoch_accuracies = np.zeros(n_epochs)
63
+ val_accuracies = np.zeros(n_epochs)
64
+
65
+
66
  if num_batches == 0:
67
  raise RuntimeError("UH OH!!!! empty train loader")
68
 
69
  # Store training losses and accuracies for every batch
70
  # num_batches is the number of batches for every epoch
71
+ #training_losses = np.zeros(num_batches * n_epochs)
72
+ #training_accuracies = np.zeros(num_batches * n_epochs)
73
 
74
  # store validation accuracy for every epoch
75
+
76
 
77
  # keep track of best validation accuracy and best model
78
  best_accuracy = 0.0
79
 
80
+
81
  #----------------------
82
  # training loop
83
  #----------------------
 
86
  model.train()
87
  train_accuracy_fn.reset()
88
 
89
+ running_loss = 0.0
90
+ running_correct = 0
91
+ running_total = 0
92
+
93
  # iterate over all the dataloader's mini-batches
94
+ for batch in train_loader:
95
 
96
  # move to GPU memory
97
  inputs = batch["image"].to(device)
 
107
  outputs = model(inputs)
108
  loss = criterion(outputs, labels)
109
 
110
+ # Backward pass & update params
111
  loss.backward()
 
 
112
  optimizer.step()
 
 
 
113
 
114
+ # Log batch-level metrics
115
+ batch_losses.append(loss.item())
116
+ batch_acc = (outputs.argmax(dim=1) == labels).float().mean().item()
117
+ batch_accuracies.append(batch_acc)
118
+
119
+ # Sum epoch stats
120
+ running_loss += loss.item() * inputs.size(0)
121
+ running_correct += (outputs.argmax(dim=1) == labels).sum().item()
122
+ running_total += labels.size(0)
123
+
124
 
125
+ # Epoch-level metrics (average over all batches)
126
+ epoch_loss_avg = running_loss / running_total
127
+ epoch_acc_avg = running_correct / running_total
128
 
129
+ epoch_losses[epoch] = epoch_loss_avg
130
+ epoch_accuracies[epoch] = epoch_acc_avg
131
+
132
+ print(f"\n--- Epoch {epoch + 1}: ---")
133
+ print(f'Train loss={epoch_loss_avg:.4f}\nTrain accuracy={epoch_acc_avg:.4f}\n')
134
 
135
  # ----------------------
136
  # validation loop
 
150
  inputs = inputs.view(inputs.size(0), -1)
151
 
152
  outputs = model(inputs)
 
153
  val_accuracy_fn.update(outputs, labels)
154
 
155
+
156
+ current_val_accuracy = val_accuracy_fn.compute().item()
157
+ val_accuracies[epoch] = current_val_accuracy
158
+
159
+ print(f"\nEpoch {epoch+1}: val acc={current_val_accuracy:.4f}")
160
 
161
  # keep track of best validation accuracy and save best model so far
162
+ if current_val_accuracy > best_accuracy:
163
+ best_accuracy = current_val_accuracy
164
  torch.save(model.state_dict(), save_path)
165
+
166
+
167
+ print(f'Epoch {epoch + 1} validation complete\n')
168
 
169
  print(f"\nTraining finished. Best val accuracy: {best_accuracy:.4f}")
170
  print(f"Best model weights saved to: {save_path}")
171
 
172
  training_metrics = {
173
+ "batch_losses": np.array(batch_losses),
174
+ "batch_accuracies": np.array(batch_accuracies),
175
+ "epoch_losses": epoch_losses,
176
+ "epoch_accuracies": epoch_accuracies,
177
  "val_accuracies": val_accuracies,
178
  "best_accuracy": best_accuracy,
179
  }
trainingModel/run_training.py CHANGED
@@ -1,105 +1,15 @@
1
- import os
2
- import numpy as np
3
- from clearml import Task, Dataset
4
- from datasets import load_dataset
5
 
6
- # Latest Data Prep Task
7
- all_tasks = Task.get_tasks(project_name="Small Group Project")
8
- if not all_tasks:
9
- raise RuntimeError("No tasks found in project 'Small Group Project'")
10
 
11
- dp_tasks = [t for t in all_tasks if t.name == "Data Preparation"]
12
- if not dp_tasks:
13
- raise RuntimeError("No 'Data Preparation' tasks found in this project!")
14
 
15
- <<<<<<< HEAD
16
- # -------------- Load Data --------------
17
-
18
- all_tasks = Task.get_tasks(project_name="Small Group Project")
19
- if not all_tasks:
20
- raise RuntimeError("No tasks found in project 'Small Group Project'")
21
-
22
- dp_tasks = [t for t in all_tasks if t.name == "Data Preparation"]
23
- if not dp_tasks:
24
- raise RuntimeError("No 'Data Preparation' tasks found in this project!")
25
-
26
- # Latest Data Prep Task
27
- latest_task = max(dp_tasks, key=lambda t: t.id)
28
- DYNAMIC_TASK_ID = latest_task.id
29
- DATA_PREP = Task.get_task(task_id=DYNAMIC_TASK_ID)
30
-
31
- =======
32
- latest_task = max(dp_tasks, key=lambda t: t.id)
33
- DYNAMIC_TASK_ID = latest_task.id
34
- DATA_PREP = Task.get_task(task_id=DYNAMIC_TASK_ID)
35
-
36
- >>>>>>> 20050ad82ebca27a376e15837a7abf79fca23e98
37
- # Dataset ID
38
- config_objects = DATA_PREP.get_configuration_objects()
39
- raw_meta = config_objects["Dataset Metadata"]
40
- dataset_id = raw_meta.split("=")[1].strip().replace('"', "")
41
-
42
- # Load ClearML Dataset
43
- subset_clearml = Dataset.get(dataset_id=dataset_id)
44
- local_folder = subset_clearml.get_local_copy()
45
-
46
- <<<<<<< HEAD
47
- subset_indices = np.load(os.path.join(local_folder, "subset_indices.npy"))
48
- =======
49
- subset_indices_path = os.path.join(local_folder, "subset_indices.npy")
50
- subset_indices = np.load(subset_indices_path)
51
- >>>>>>> 20050ad82ebca27a376e15837a7abf79fca23e98
52
-
53
- # Load Dataset Parameters
54
- data_params = DATA_PREP.get_parameters()
55
- dataset_link = data_params['General/dataset/link']
56
-
57
- # Load Full Dataset
58
- try:
59
- ds = load_dataset(dataset_link)
60
- except Exception as e:
61
- raise RuntimeError(f"Error loading the dataset: {e}")
62
-
63
- full_dataset = ds['train']
64
-
65
-
66
-
67
- # Apply subset indices to full dataset - this gives you the same subset as data prep
68
- subset_dataset = full_dataset.select(subset_indices)
69
 
70
-
71
- # Extract parameters from data prep task - these will create the DataLoaders
72
- seed = int(data_params['General/seed'])
73
- batch_size = int(data_params['General/dataloaders/batch_size'])
74
- test_size = float(data_params['General/dataloaders/test_size'])
75
-
76
- aug_config = {
77
- 'rotation': float(data_params['General/augmentation/rotation']),
78
- 'brightness': float(data_params['General/augmentation/brightness']),
79
- 'saturation': float(data_params['General/augmentation/saturation']),
80
- 'blur': float(data_params['General/augmentation/blur'])
81
- }
82
-
83
- # Create DataLoaders using the parameters from data prep
84
- subset_loaders = make_dataset_loaders(
85
- subset_dataset, seed, batch_size, test_size, aug_config
86
- )
87
-
88
- print("\n--- Handoff Test Successful ---")
89
- print(f"Prototype Train loader batches: {len(subset_loaders['train'])}")
90
- print(f"Prototype Validation loader batches: {len(subset_loaders['val'])}")
91
- print(f"Prototype Test loader batches: {len(subset_loaders['test'])}")
92
-
93
-
94
- full_loaders = make_dataset_loaders(
95
- full_dataset, seed, batch_size, test_size, aug_config
96
- )
97
-
98
- print("\n--- Handoff Test Successful ---")
99
- print(f"Train loader batches: {len(full_loaders['train'])}")
100
- print(f"Validation loader batches: {len(full_loaders['val'])}")
101
- print(f"Test loader batches: {len(full_loaders['test'])}")
102
- # -------------- DATA PREP ENDS --------------
103
 
104
 
105
  # -------- ClearML Training Task Setup --------
@@ -109,15 +19,16 @@ training_task = Task.init(
109
  reuse_last_task_id=False,
110
  )
111
 
 
112
  training_logger = training_task.get_logger()
113
- training_task.connect({"data_prep_task_used": DYNAMIC_TASK_ID})
114
 
115
  # Training parameters - Modify these to experiment
116
  training_config = {
117
  "num_classes": 39,
118
- "n_epochs": 1,
119
  "learning_rate": 1e-3,
120
- "batch_size": batch_size,
121
  "save_path": "best_model.pt",
122
  }
123
  training_task.connect(training_config)
@@ -130,37 +41,37 @@ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
130
 
131
  # ------- Train the model (on subset for now) -------
132
 
133
- <<<<<<< HEAD
134
  print("\n--- Starting Model Training on Subset ---")
135
  training_metrics = train_model(
136
- =======
137
- #When calling this function, the model should be trained on the given dataset
138
-
139
- print("\n--- Starting Model Training on Subset ---")
140
- train_model(
141
- >>>>>>> 20050ad82ebca27a376e15837a7abf79fca23e98
142
  model=model,
143
  train_loader=subset_loaders['train'],
144
  val_loader=subset_loaders['val'],
145
  device=device,
146
  n_epochs=training_config["n_epochs"],
147
  lr=training_config["learning_rate"],
 
 
148
  save_path=training_config["save_path"],
149
  )
150
- <<<<<<< HEAD
151
 
152
 
153
  # ----------- Log metrics to ClearML -----------
154
  # Per-batch training losses and accuracies
155
- for i, loss in enumerate(training_metrics["losses"]):
156
- training_logger.report_scalar("train", "loss_per_batch", value=loss, iteration=i)
 
 
 
157
 
158
- for i, acc in enumerate(training_metrics["accuracies"]):
159
- training_logger.report_scalar("train", "accuracy_per_batch", value=acc, iteration=i)
 
 
 
160
 
161
- # Per-epoch validation accuracy
162
  for epoch, acc in enumerate(training_metrics["val_accuracies"]):
163
- training_logger.report_scalar("validation", "accuracy_per_epoch", value=acc, iteration=epoch)
164
 
165
  training_logger.report_single_value("best_val_accuracy", training_metrics["best_accuracy"])
166
 
@@ -168,6 +79,4 @@ training_logger.report_single_value("best_val_accuracy", training_metrics["best_
168
  training_task.upload_artifact("best_model", training_config["save_path"])
169
 
170
  print("\nTraining complete.")
171
- training_task.close()
172
- =======
173
- >>>>>>> 20050ad82ebca27a376e15837a7abf79fca23e98
 
 
 
 
 
1
 
2
+ from clearml import Task
3
+ from dataPrep.helpers.clearml_data import extract_latest_data_task
 
 
4
 
5
+ import torch
6
+ from models.modelOne import modelOne
7
+ from trainingModel.Training import train_model
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ # -------------- Load Data --------------
11
+ project_name = "Small Group Project"
12
+ subset_loaders, full_loaders, data_prep_metadata = extract_latest_data_task(project_name=project_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
 
15
  # -------- ClearML Training Task Setup --------
 
19
  reuse_last_task_id=False,
20
  )
21
 
22
+ # Detail the data prep task used
23
  training_logger = training_task.get_logger()
24
+ training_task.connect(data_prep_metadata, name="data_prep_metadata_READONLY")
25
 
26
  # Training parameters - Modify these to experiment
27
  training_config = {
28
  "num_classes": 39,
29
+ "n_epochs": 10,
30
  "learning_rate": 1e-3,
31
+ "optimizer": "adam",
32
  "save_path": "best_model.pt",
33
  }
34
  training_task.connect(training_config)
 
41
 
42
  # ------- Train the model (on subset for now) -------
43
 
 
44
  print("\n--- Starting Model Training on Subset ---")
45
  training_metrics = train_model(
 
 
 
 
 
 
46
  model=model,
47
  train_loader=subset_loaders['train'],
48
  val_loader=subset_loaders['val'],
49
  device=device,
50
  n_epochs=training_config["n_epochs"],
51
  lr=training_config["learning_rate"],
52
+ num_classes=training_config["num_classes"],
53
+ optimizer_type=training_config["optimizer"],
54
  save_path=training_config["save_path"],
55
  )
 
56
 
57
 
58
  # ----------- Log metrics to ClearML -----------
59
  # Per-batch training losses and accuracies
60
+ for i, loss in enumerate(training_metrics["batch_losses"]):
61
+ training_logger.report_scalar("training batch loss", "loss", value=loss, iteration=i)
62
+
63
+ for i, acc in enumerate(training_metrics["batch_accuracies"]):
64
+ training_logger.report_scalar("training batch accuracy", "accuracy", value=acc, iteration=i)
65
 
66
+ # Per-epoch training losses and accuracies
67
+ epoch_metrics = zip(training_metrics["epoch_losses"], training_metrics["epoch_accuracies"])
68
+ for epoch, (loss, acc) in enumerate(epoch_metrics):
69
+ training_logger.report_scalar("training epoch loss", "loss", loss, iteration=epoch)
70
+ training_logger.report_scalar("training epoch accuracy", "accuracy", acc, iteration=epoch)
71
 
72
+ # Per-epoch validation accuracies
73
  for epoch, acc in enumerate(training_metrics["val_accuracies"]):
74
+ training_logger.report_scalar("validation epoch accuracy", "accuracy", value=acc, iteration=epoch)
75
 
76
  training_logger.report_single_value("best_val_accuracy", training_metrics["best_accuracy"])
77
 
 
79
  training_task.upload_artifact("best_model", training_config["save_path"])
80
 
81
  print("\nTraining complete.")
82
+ training_task.close()