GitHub Actions commited on
Commit
ee461be
·
1 Parent(s): 224b4f5

Sync from GitHub Actions

Browse files
autocatalog/evaluation/error_analysis.py CHANGED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+ import pandas as pd
4
+ from sklearn.metrics import classification_report, confusion_matrix
5
+
6
+
7
+ def save_evaluation_artifacts(
8
+ output_dir,
9
+ tasks,
10
+ label_maps,
11
+ y_true,
12
+ raw_predictions,
13
+ corrected_predictions,
14
+ probabilities,
15
+ global_indices,
16
+ ):
17
+ output_dir = Path(output_dir)
18
+ output_dir.mkdir(parents=True, exist_ok=True)
19
+ prediction_variants = {
20
+ "raw": raw_predictions,
21
+ "corrected": corrected_predictions,
22
+ }
23
+
24
+ for variant, predictions in prediction_variants.items():
25
+ for task in tasks:
26
+ id2label = label_maps[task]["id2label"]
27
+ label_ids = list(range(len(id2label)))
28
+
29
+ label_names = [
30
+ id2label[str(label_id)]
31
+ for label_id in label_ids
32
+ ]
33
+
34
+ report = classification_report(
35
+ y_true[task],
36
+ predictions[task],
37
+ labels=label_ids,
38
+ target_names=label_names,
39
+ zero_division=0,
40
+ output_dict=True,
41
+ )
42
+
43
+ report_path = (output_dir / f"{variant}_{task}_classification_report.json")
44
+ with open(report_path, "w", encoding="utf-8") as file:
45
+ json.dump(
46
+ report,
47
+ file,
48
+ indent=2,
49
+ ensure_ascii=False,
50
+ )
51
+
52
+ matrix = confusion_matrix(
53
+ y_true[task],
54
+ predictions[task],
55
+ labels=label_ids,
56
+ )
57
+
58
+ matrix_path = (output_dir / f"{variant}_{task}_confusion_matrix.csv")
59
+ pd.DataFrame(
60
+ matrix,
61
+ index=label_names,
62
+ columns=label_names,
63
+ ).to_csv(
64
+ matrix_path,
65
+ encoding="utf-8",
66
+ )
67
+
68
+ rows = []
69
+ for row_index, global_index in enumerate(global_indices):
70
+ row = {"global_index": int(global_index)}
71
+
72
+ raw_exact = True
73
+ corrected_exact = True
74
+
75
+ for task in tasks:
76
+ id2label = label_maps[task]["id2label"]
77
+
78
+ true_id = int(y_true[task][row_index])
79
+ raw_id = int(raw_predictions[task][row_index])
80
+ corrected_id = int(corrected_predictions[task][row_index])
81
+
82
+ row[f"{task}_true"] = id2label[str(true_id)]
83
+ row[f"{task}_raw"] = id2label[str(raw_id)]
84
+ row[f"{task}_corrected"] = id2label[str(corrected_id)]
85
+ row[f"{task}_confidence"] = float(probabilities[task][row_index, raw_id])
86
+
87
+ raw_exact &= true_id == raw_id
88
+ corrected_exact &= true_id == corrected_id
89
+
90
+ row["raw_exact_match"] = bool(raw_exact)
91
+ row["corrected_exact_match"] = bool(corrected_exact)
92
+ rows.append(row)
93
+
94
+ pd.DataFrame(rows).to_csv(
95
+ output_dir / "test_predictions.csv",
96
+ index=False,
97
+ encoding="utf-8",
98
+ )
autocatalog/evaluation/evaluate.py CHANGED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import numpy as np
3
+ import torch
4
+ from tqdm.auto import tqdm
5
+ from autocatalog.evaluation.metrics import collect_predictions, evaluate_predictions
6
+
7
+ def build_consistency_rule(dataframe, source_task, target_task):
8
+ rules = {}
9
+ for source_value, group in dataframe.groupby(source_task):
10
+ counts = group[target_task].value_counts()
11
+ rules[source_value] = {
12
+ "target": counts.index[0],
13
+ "dominance": float(counts.iloc[0] / counts.sum()),
14
+ }
15
+
16
+ return rules
17
+
18
+
19
+ def build_consistency_rules(train_df):
20
+ return {
21
+ "article_to_master": build_consistency_rule(
22
+ train_df,
23
+ "articleType",
24
+ "masterCategory",
25
+ ),
26
+ "article_to_sub": build_consistency_rule(
27
+ train_df,
28
+ "articleType",
29
+ "subCategory",
30
+ ),
31
+ "article_to_usage": build_consistency_rule(
32
+ train_df,
33
+ "articleType",
34
+ "usage",
35
+ ),
36
+ "article_to_season": build_consistency_rule(
37
+ train_df,
38
+ "articleType",
39
+ "season",
40
+ ),
41
+ }
42
+
43
+
44
+ def apply_consistency_rules(y_pred, y_probs, label_maps, rules):
45
+ corrected = {
46
+ task: predictions.copy()
47
+ for task, predictions in y_pred.items()
48
+ }
49
+
50
+ mappings = [
51
+ ("article_to_master", "masterCategory", 0.95),
52
+ ("article_to_sub", "subCategory", 0.90),
53
+ ("article_to_usage", "usage", 0.92),
54
+ ("article_to_season", "season", 0.92),
55
+ ]
56
+
57
+ for index, article_id in enumerate(corrected["articleType"]):
58
+ article_id = int(article_id)
59
+ confidence = float(
60
+ y_probs["articleType"][index, article_id]
61
+ )
62
+
63
+ if confidence < 0.65:
64
+ continue
65
+
66
+ article_label = label_maps["articleType"]["id2label"][str(article_id)]
67
+ for rule_name, target_task, minimum_dominance in mappings:
68
+ rule = rules[rule_name].get(article_label)
69
+ if not rule:
70
+ continue
71
+ if rule["dominance"] < minimum_dominance:
72
+ continue
73
+ corrected[target_task][index] = label_maps[target_task]["label2id"][
74
+ rule["target"]
75
+ ]
76
+
77
+ return corrected
78
+
79
+
80
+ def evaluate_loader(model, loader, device, tasks, label_maps, rules):
81
+ y_true, y_pred, y_probs, indices = collect_predictions(model, loader, device, tasks)
82
+ raw_metrics = evaluate_predictions(y_true, y_pred, y_probs, tasks)
83
+
84
+ corrected_predictions = apply_consistency_rules(y_pred, y_probs, label_maps, rules)
85
+ corrected_metrics = evaluate_predictions(y_true, corrected_predictions, y_probs, tasks)
86
+
87
+ return {
88
+ "y_true": y_true,
89
+ "y_pred": y_pred,
90
+ "y_probs": y_probs,
91
+ "indices": indices,
92
+ "corrected_pred": corrected_predictions,
93
+ "raw_metrics": raw_metrics,
94
+ "corrected_metrics": corrected_metrics,
95
+ }
96
+
97
+
98
+ @torch.inference_mode()
99
+ def benchmark_single_image_latency(
100
+ model,
101
+ dataset,
102
+ device,
103
+ warmup_runs=20,
104
+ measured_runs=100,
105
+ ):
106
+ model.eval()
107
+ sample = dataset[0]
108
+
109
+ pixel_values = sample["pixel_values"].unsqueeze(0).to(device)
110
+ color_features = sample["color_features"].unsqueeze(0).to(device)
111
+ for _ in range(warmup_runs):
112
+ model(pixel_values, color_features)
113
+
114
+ if str(device).startswith("cuda"):
115
+ torch.cuda.synchronize()
116
+
117
+ times = []
118
+ for _ in range(measured_runs):
119
+ if str(device).startswith("cuda"):
120
+ torch.cuda.synchronize()
121
+
122
+ start = time.perf_counter()
123
+ model(pixel_values, color_features)
124
+
125
+ if str(device).startswith("cuda"):
126
+ torch.cuda.synchronize()
127
+
128
+ elapsed = (time.perf_counter() - start) * 1000
129
+ times.append(elapsed)
130
+
131
+ return {
132
+ "average_ms": float(np.mean(times)),
133
+ "p50_ms": float(np.percentile(times, 50)),
134
+ "p95_ms": float(np.percentile(times, 95)),
135
+ "runs": measured_runs,
136
+ }
137
+
138
+
139
+ @torch.inference_mode()
140
+ def benchmark_batch_latency(
141
+ model,
142
+ loader,
143
+ device,
144
+ max_batches=100,
145
+ ):
146
+ model.eval()
147
+ times = []
148
+ for batch_index, batch in enumerate(
149
+ tqdm(
150
+ loader,
151
+ desc="Batch benchmark",
152
+ leave=False,
153
+ )
154
+ ):
155
+ if batch_index >= max_batches:
156
+ break
157
+
158
+ pixel_values = batch["pixel_values"].to(device)
159
+ color_features = batch["color_features"].to(device)
160
+
161
+ if str(device).startswith("cuda"):
162
+ torch.cuda.synchronize()
163
+
164
+ start = time.perf_counter()
165
+ model(pixel_values, color_features)
166
+ if str(device).startswith("cuda"):
167
+ torch.cuda.synchronize()
168
+
169
+ elapsed = (time.perf_counter() - start) * 1000
170
+ times.append(elapsed / pixel_values.size(0))
171
+
172
+ return {
173
+ "average_ms_per_image": float(np.mean(times)),
174
+ "p50_ms_per_image": float(np.percentile(times, 50)),
175
+ "p95_ms_per_image": float(np.percentile(times, 95)),
176
+ "batches": len(times),
177
+ }
autocatalog/training/pipeline.py ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import time
3
+ from pathlib import Path
4
+ import torch
5
+ from transformers import CLIPImageProcessor
6
+ from autocatalog.data.dataset import (
7
+ build_dataloaders,
8
+ create_splits,
9
+ load_clean_dataset,
10
+ load_or_create_color_cache,
11
+ )
12
+ from autocatalog.evaluation.error_analysis import save_evaluation_artifacts
13
+ from autocatalog.evaluation.evaluate import (
14
+ benchmark_batch_latency,
15
+ benchmark_single_image_latency,
16
+ build_consistency_rules,
17
+ evaluate_loader,
18
+ )
19
+ from autocatalog.evaluation.metrics import (
20
+ model_selection_score,
21
+ passes_safety_thresholds,
22
+ )
23
+ from autocatalog.models.multitask_clip import CLIPMultiTaskClassifierV2
24
+ from autocatalog.training.checkpoint import (
25
+ download_source_checkpoint,
26
+ save_checkpoint,
27
+ save_final_metadata,
28
+ torch_load,
29
+ )
30
+ from autocatalog.training.losses import build_criterions
31
+ from autocatalog.training.train import create_optimizer_and_scheduler, train_one_epoch
32
+ from autocatalog.utils.logger import get_logger
33
+ from autocatalog.utils.seed import set_seed
34
+ logger = get_logger(__name__)
35
+
36
+
37
+ def run_training(config, root_dir):
38
+ data_config = config["data"]
39
+ model_config = config["model"]
40
+ training_config = config["training"]
41
+ evaluation_config = config["evaluation"]
42
+ set_seed(data_config["seed"])
43
+
44
+ device = "cuda" if torch.cuda.is_available() else "cpu"
45
+ root_dir = Path(root_dir)
46
+
47
+ output_dir = root_dir / model_config["output_dir"]
48
+ evaluation_dir = root_dir / evaluation_config["output_dir"]
49
+ processed_dir = root_dir / data_config["processed_dir"]
50
+ color_cache_path = root_dir / data_config["color_cache_path"]
51
+
52
+ output_dir.mkdir(parents=True, exist_ok=True)
53
+ evaluation_dir.mkdir(parents=True, exist_ok=True)
54
+
55
+ logger.info(
56
+ "Training started | device=%s | source=%s",
57
+ device,
58
+ model_config["source_repo_id"],
59
+ )
60
+
61
+ source_checkpoint, label_maps, model_name, hidden_dim, dropout = (
62
+ download_source_checkpoint(model_config["source_repo_id"])
63
+ )
64
+
65
+ tasks = data_config["tasks"]
66
+ task_num_classes = {
67
+ task: len(label_maps[task]["label2id"])
68
+ for task in tasks
69
+ }
70
+
71
+ dataset = load_clean_dataset(
72
+ data_config["dataset_name"],
73
+ tasks,
74
+ label_maps,
75
+ )
76
+
77
+ train_df, validation_df, test_df = create_splits(
78
+ dataset,
79
+ tasks,
80
+ processed_dir,
81
+ data_config["seed"],
82
+ data_config["train_ratio"],
83
+ data_config["validation_ratio"],
84
+ data_config["test_ratio"],
85
+ )
86
+
87
+ color_features = load_or_create_color_cache(
88
+ dataset,
89
+ color_cache_path,
90
+ data_config["color_image_size"],
91
+ data_config["color_feature_dim"],
92
+ )
93
+
94
+ processor = CLIPImageProcessor.from_pretrained(model_name)
95
+ data = build_dataloaders(
96
+ dataset,
97
+ train_df,
98
+ validation_df,
99
+ test_df,
100
+ color_features,
101
+ processor,
102
+ label_maps,
103
+ tasks,
104
+ training_config["batch_size"],
105
+ training_config["num_workers"],
106
+ )
107
+
108
+ model = CLIPMultiTaskClassifierV2(
109
+ model_name=model_name,
110
+ task_num_classes=task_num_classes,
111
+ hidden_dim=hidden_dim,
112
+ dropout=dropout,
113
+ color_feature_dim=data_config["color_feature_dim"],
114
+ ).to(device)
115
+
116
+ source_state = source_checkpoint.get("model_state_dict", source_checkpoint)
117
+ load_result = model.load_state_dict(source_state, strict=False)
118
+ expected_prefixes = (
119
+ "master_to_sub",
120
+ "sub_to_article",
121
+ "article_to_season",
122
+ "article_to_usage",
123
+ "color_branch",
124
+ )
125
+
126
+ unexpected_missing = [
127
+ key
128
+ for key in load_result.missing_keys
129
+ if not key.startswith(expected_prefixes)
130
+ ]
131
+
132
+ if unexpected_missing or load_result.unexpected_keys:
133
+ raise RuntimeError("Source checkpoint does not match the expected V1 model")
134
+
135
+ logger.info("Warm-start checkpoint loaded")
136
+ consistency_rules = build_consistency_rules(train_df)
137
+
138
+ with open(output_dir / "consistency_rules.json", "w", encoding="utf-8") as file:
139
+ json.dump(consistency_rules, file, indent=2, ensure_ascii=False)
140
+
141
+ baseline = evaluate_loader(
142
+ model,
143
+ data["validation_loader"],
144
+ device,
145
+ tasks,
146
+ label_maps,
147
+ consistency_rules,
148
+ )
149
+
150
+ safety_thresholds = evaluation_config["safety_thresholds"]
151
+ if not passes_safety_thresholds(
152
+ baseline["raw_metrics"],
153
+ safety_thresholds,
154
+ ):
155
+ raise RuntimeError("Warm-start safety check failed")
156
+
157
+ best_score = model_selection_score(baseline["raw_metrics"])
158
+ best_epoch = "v1_warm_start"
159
+
160
+ save_checkpoint(
161
+ output_dir / "model.pt",
162
+ model,
163
+ model_name,
164
+ tasks,
165
+ task_num_classes,
166
+ hidden_dim,
167
+ dropout,
168
+ data_config["color_feature_dim"],
169
+ label_maps,
170
+ best_epoch,
171
+ best_score,
172
+ baseline["raw_metrics"],
173
+ model_config["source_repo_id"],
174
+ )
175
+
176
+ criterions, weight_summary = build_criterions(
177
+ train_df,
178
+ tasks,
179
+ label_maps,
180
+ set(training_config["balanced_tasks"]),
181
+ training_config["class_weight_min"],
182
+ training_config["class_weight_max"],
183
+ device,
184
+ )
185
+
186
+ logger.info("Class weights ready | %s", json.dumps(weight_summary))
187
+ history = []
188
+ started_at = time.time()
189
+
190
+ for stage_name in ("stage1", "stage2"):
191
+ stage = training_config[stage_name]
192
+
193
+ active_tasks, optimizer, scheduler, scaler = (
194
+ create_optimizer_and_scheduler(
195
+ model,
196
+ stage_name,
197
+ stage,
198
+ training_config["weight_decay"],
199
+ len(data["train_loader"]),
200
+ device,
201
+ training_config["use_amp"],
202
+ )
203
+ )
204
+
205
+ bad_epochs = 0
206
+
207
+ for epoch in range(1, stage["epochs"] + 1):
208
+ epoch_name = f"{stage_name}_epoch_{epoch}"
209
+
210
+ train_loss, train_accuracy = train_one_epoch(
211
+ model,
212
+ data["train_loader"],
213
+ optimizer,
214
+ scheduler,
215
+ scaler,
216
+ criterions,
217
+ active_tasks,
218
+ device,
219
+ training_config["use_amp"],
220
+ training_config["max_grad_norm"],
221
+ )
222
+
223
+ validation = evaluate_loader(
224
+ model,
225
+ data["validation_loader"],
226
+ device,
227
+ tasks,
228
+ label_maps,
229
+ consistency_rules,
230
+ )
231
+
232
+ validation_score = model_selection_score(validation["raw_metrics"])
233
+ safety_passed = passes_safety_thresholds(
234
+ validation["raw_metrics"],
235
+ safety_thresholds,
236
+ )
237
+
238
+ history.append(
239
+ {
240
+ "epoch": epoch_name,
241
+ "train_loss": float(train_loss),
242
+ "train_accuracy": train_accuracy,
243
+ "validation_score": float(validation_score),
244
+ "safety_passed": bool(safety_passed),
245
+ "validation_metrics": {
246
+ "raw": validation["raw_metrics"],
247
+ "corrected": validation["corrected_metrics"],
248
+ },
249
+ }
250
+ )
251
+
252
+ overall = validation["corrected_metrics"]["overall_metrics"]
253
+ logger.info(
254
+ "%s | loss=%.4f | score=%.4f | accuracy=%.4f | "
255
+ "exact_match=%.4f | safe=%s",
256
+ epoch_name,
257
+ train_loss,
258
+ validation_score,
259
+ overall["average_accuracy"],
260
+ overall["exact_match_accuracy"],
261
+ safety_passed,
262
+ )
263
+
264
+ if safety_passed and validation_score > best_score:
265
+ best_score = validation_score
266
+ best_epoch = epoch_name
267
+ bad_epochs = 0
268
+
269
+ save_checkpoint(
270
+ output_dir / "model.pt",
271
+ model,
272
+ model_name,
273
+ tasks,
274
+ task_num_classes,
275
+ hidden_dim,
276
+ dropout,
277
+ data_config["color_feature_dim"],
278
+ label_maps,
279
+ epoch_name,
280
+ validation_score,
281
+ {
282
+ "raw": validation["raw_metrics"],
283
+ "corrected": validation["corrected_metrics"],
284
+ },
285
+ model_config["source_repo_id"],
286
+ )
287
+
288
+ logger.info(
289
+ "Improved checkpoint saved | epoch=%s",
290
+ epoch_name,
291
+ )
292
+ else:
293
+ bad_epochs += 1
294
+
295
+ if bad_epochs >= training_config["early_stopping_patience"]:
296
+ logger.info("Early stopping | stage=%s", stage_name)
297
+ break
298
+
299
+ with open(
300
+ output_dir / "history.json",
301
+ "w",
302
+ encoding="utf-8",
303
+ ) as file:
304
+ json.dump(history, file, indent=2, ensure_ascii=False)
305
+
306
+ best_checkpoint = torch_load(
307
+ output_dir / "model.pt",
308
+ map_location=device,
309
+ )
310
+
311
+ model.load_state_dict(best_checkpoint["model_state_dict"], strict=True)
312
+ model.eval()
313
+
314
+ test_results = evaluate_loader(
315
+ model,
316
+ data["test_loader"],
317
+ device,
318
+ tasks,
319
+ label_maps,
320
+ consistency_rules,
321
+ )
322
+
323
+ latency = {
324
+ "device": device,
325
+ "single_image": benchmark_single_image_latency(
326
+ model,
327
+ data["test_dataset"],
328
+ device,
329
+ ),
330
+ "batch": benchmark_batch_latency(
331
+ model,
332
+ data["test_loader"],
333
+ device,
334
+ ),
335
+ }
336
+
337
+ final_metrics = {
338
+ "raw": test_results["raw_metrics"],
339
+ "corrected": test_results["corrected_metrics"],
340
+ "latency": latency,
341
+ "best_checkpoint": best_checkpoint["best_epoch"],
342
+ "best_validation_score": best_checkpoint["best_validation_score"],
343
+ "test_samples": len(data["test_dataset"]),
344
+ }
345
+
346
+ with open(evaluation_dir / "final_metrics.json", "w", encoding="utf-8") as file:
347
+ json.dump(final_metrics, file, indent=2, ensure_ascii=False)
348
+
349
+ save_evaluation_artifacts(
350
+ evaluation_dir,
351
+ tasks,
352
+ label_maps,
353
+ test_results["y_true"],
354
+ test_results["y_pred"],
355
+ test_results["corrected_pred"],
356
+ test_results["y_probs"],
357
+ test_results["indices"],
358
+ )
359
+
360
+ save_final_metadata(
361
+ config,
362
+ output_dir,
363
+ label_maps,
364
+ task_num_classes,
365
+ model_name,
366
+ hidden_dim,
367
+ dropout,
368
+ best_checkpoint,
369
+ final_metrics,
370
+ )
371
+
372
+ overall = final_metrics["corrected"]["overall_metrics"]
373
+ training_minutes = (time.time() - started_at) / 60
374
+
375
+ logger.info(
376
+ "Training complete | best=%s | minutes=%.2f | "
377
+ "accuracy=%.4f | exact_match=%.4f",
378
+ best_epoch,
379
+ training_minutes,
380
+ overall["average_accuracy"],
381
+ overall["exact_match_accuracy"],
382
+ )
383
+
384
+ return final_metrics
autocatalog/utils/seed.py CHANGED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import numpy as np
3
+ import torch
4
+
5
+ def set_seed(seed):
6
+ random.seed(seed)
7
+ np.random.seed(seed)
8
+ torch.manual_seed(seed)
9
+
10
+ if torch.cuda.is_available():
11
+ torch.cuda.manual_seed_all(
12
+ seed
13
+ )
14
+
15
+ torch.backends.cudnn.benchmark = (
16
+ False
17
+ )
18
+
19
+ torch.backends.cudnn.deterministic = (
20
+ True
21
+ )
requirements.txt CHANGED
@@ -1,8 +1,12 @@
1
- streamlit
2
  torch
3
  torchvision
4
  transformers
 
5
  huggingface_hub
 
 
 
6
  Pillow
7
  PyYAML
8
- numpy
 
 
 
1
  torch
2
  torchvision
3
  transformers
4
+ datasets
5
  huggingface_hub
6
+ scikit-learn
7
+ pandas
8
+ numpy
9
  Pillow
10
  PyYAML
11
+ tqdm
12
+ streamlit
scripts/train_multitask_clip.py CHANGED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+ ROOT_DIR = Path(__file__).resolve().parents[1]
5
+ if str(ROOT_DIR) not in sys.path:
6
+ sys.path.insert(0,str(ROOT_DIR),)
7
+
8
+ from autocatalog.training.pipeline import run_training
9
+ from autocatalog.utils.config import load_config
10
+
11
+
12
+ def main():
13
+ parser = argparse.ArgumentParser(
14
+ description=(
15
+ "Train AutoCatalogAI V2"
16
+ )
17
+ )
18
+
19
+ parser.add_argument(
20
+ "--config",
21
+ default="configs/config.yaml",
22
+ )
23
+
24
+ arguments = parser.parse_args()
25
+ config = load_config(ROOT_DIR / arguments.config)
26
+ run_training(config,ROOT_DIR)
27
+
28
+
29
+ if __name__ == "__main__":
30
+ main()