jpata commited on
Commit
f327745
·
1 Parent(s): af76c4c

added HF upload script

Browse files
Files changed (2) hide show
  1. mltau/scripts/upload_model_hf.py +148 -0
  2. model_card.md +82 -0
mltau/scripts/upload_model_hf.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import argparse
5
+ from pathlib import Path
6
+ from huggingface_hub import HfApi
7
+
8
+ # Set timeout for large file uploads
9
+ os.environ["HF_HUB_ETAG_TIMEOUT"] = "1000"
10
+
11
+
12
+ def get_dir_size(path, ignore_patterns=None):
13
+ """Calculate the total size of a directory in bytes."""
14
+ from fnmatch import fnmatch
15
+
16
+ total = 0
17
+ for p in Path(path).rglob("*"):
18
+ if p.is_file():
19
+ if ignore_patterns:
20
+ skip = False
21
+ for pattern in ignore_patterns:
22
+ if fnmatch(p.name, pattern) or fnmatch(str(p.relative_to(path)), pattern):
23
+ skip = True
24
+ break
25
+ if skip:
26
+ continue
27
+ total += p.stat().st_size
28
+ return total
29
+
30
+
31
+ def format_size(num, suffix="B"):
32
+ """Convert bytes to human-readable format."""
33
+ for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
34
+ if abs(num) < 1024.0:
35
+ return f"{num:3.1f}{unit}{suffix}"
36
+ num /= 1024.0
37
+ return f"{num:.1f}Yi{suffix}"
38
+
39
+
40
+ def main():
41
+ parser = argparse.ArgumentParser(description="Upload ML-Tau model checkpoints to HuggingFace.")
42
+ parser.add_argument("experiment_dir", help="Path to the experiment directory (output_dir)")
43
+ parser.add_argument("--repo", default="HEP-KBFI/fcc-tau", help="HF repository ID")
44
+ parser.add_argument("--name", help="Custom descriptive name for the experiment in the repo (defaults to directory name)")
45
+ parser.add_argument("--path-prefix", default="", help="Prefix path in the repository (e.g. 'cld/0609_single')")
46
+ parser.add_argument("--dry-run", action="store_true", help="Print actions without executing")
47
+ parser.add_argument("--repo-type", default="model", help="HF repository type (default: model)")
48
+
49
+ args = parser.parse_args()
50
+
51
+ exp_path = Path(args.experiment_dir)
52
+ if not exp_path.is_dir():
53
+ print(f"Error: Experiment directory {exp_path} not found.")
54
+ return
55
+
56
+ exp_name = args.name if args.name else exp_path.name
57
+
58
+ if args.path_prefix:
59
+ remote_path = f"{args.path_prefix.strip('/')}/{exp_name}"
60
+ else:
61
+ remote_path = f"{exp_name}"
62
+
63
+ print(f"Preparing upload of {exp_path} to {args.repo}/{remote_path}...")
64
+
65
+ # Find the best checkpoint
66
+ models_dir = exp_path / "models"
67
+ best_checkpoint = models_dir / "ParT-model_best.ckpt"
68
+
69
+ if not best_checkpoint.exists():
70
+ print(f"Warning: Best checkpoint {best_checkpoint} not found. Searching for any .ckpt in {models_dir}...")
71
+ checkpoints = sorted(list(models_dir.glob("*.ckpt")), key=lambda x: x.stat().st_mtime)
72
+ if checkpoints:
73
+ best_checkpoint = checkpoints[-1]
74
+ print(f"Using latest checkpoint: {best_checkpoint.name}")
75
+ else:
76
+ print(f"Error: No checkpoints found in {models_dir}")
77
+ return
78
+
79
+ api = HfApi() if not args.dry_run else None
80
+
81
+ total_size = 0
82
+
83
+ # Upload best weights
84
+ if args.dry_run:
85
+ print(f"[DRY-RUN] Would upload {best_checkpoint} as {remote_path}/models/{best_checkpoint.name}")
86
+ else:
87
+ print(f"Uploading {best_checkpoint} as {remote_path}/models/{best_checkpoint.name}...")
88
+ api.upload_file(
89
+ path_or_fileobj=str(best_checkpoint),
90
+ path_in_repo=f"{remote_path}/models/{best_checkpoint.name}",
91
+ repo_id=args.repo,
92
+ repo_type=args.repo_type,
93
+ )
94
+ total_size += best_checkpoint.stat().st_size
95
+
96
+ # Directories to upload
97
+ # (local_name, remote_name, optional_ignore_patterns)
98
+ dirs_to_upload = [
99
+ ("logs", "logs"),
100
+ ("tensorboard", "tensorboard"),
101
+ ("predictions", "predictions"),
102
+ (".hydra", "config"),
103
+ ]
104
+
105
+ # Upload folders
106
+ for item in dirs_to_upload:
107
+ local_dir_name = item[0]
108
+ remote_dir_name = item[1]
109
+ ignore_patterns = item[2] if len(item) > 2 else None
110
+
111
+ local_dir_path = exp_path / local_dir_name
112
+ if local_dir_path.exists():
113
+ size = get_dir_size(local_dir_path, ignore_patterns=ignore_patterns)
114
+ total_size += size
115
+ if args.dry_run:
116
+ print(f"[DRY-RUN] Would upload folder {local_dir_path} ({format_size(size)}) to {remote_path}/{remote_dir_name}")
117
+ else:
118
+ print(f"Uploading folder {local_dir_path} ({format_size(size)}) to {remote_path}/{remote_dir_name}...")
119
+ api.upload_folder(
120
+ folder_path=str(local_dir_path),
121
+ path_in_repo=f"{remote_path}/{remote_dir_name}",
122
+ repo_id=args.repo,
123
+ repo_type=args.repo_type,
124
+ ignore_patterns=ignore_patterns,
125
+ )
126
+
127
+ # Upload all PDF files in the experiment directory recursively
128
+ # This captures validation plots
129
+ for pdf_file in exp_path.rglob("*.pdf"):
130
+ # Relative path from exp_path to preserve structure if they are in subdirs
131
+ rel_path = pdf_file.relative_to(exp_path)
132
+ if args.dry_run:
133
+ print(f"[DRY-RUN] Would upload {pdf_file} as {remote_path}/{rel_path}")
134
+ else:
135
+ print(f"Uploading {pdf_file} as {remote_path}/{rel_path}...")
136
+ api.upload_file(
137
+ path_or_fileobj=str(pdf_file),
138
+ path_in_repo=f"{remote_path}/{rel_path}",
139
+ repo_id=args.repo,
140
+ repo_type=args.repo_type,
141
+ )
142
+ total_size += pdf_file.stat().st_size
143
+
144
+ print(f"Total size processed: {format_size(total_size)}")
145
+
146
+
147
+ if __name__ == "__main__":
148
+ main()
model_card.md ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags:
3
+ - particle-physics
4
+ - tau-reconstruction
5
+ - fcc-ee
6
+ - key4hep
7
+ - particle-transformer
8
+ ---
9
+
10
+ # ML-Tau Model Card
11
+
12
+ This repository contains models for tau reconstruction and identification at future colliders (FCC), based on the Particle Transformer (ParT) architecture.
13
+
14
+ ## Dataset
15
+ - **Name:** `0509_dsinphi_to_sindphi`
16
+ - **Source:** Preprocessed jet-based FCC dataset for hadronic tau reconstruction.
17
+ - **Physics Processes:**
18
+ - **Signal:** $Z \to \tau^+\tau^-$ events.
19
+ - **Background:** $Z \to q\bar{q}$ (light quarks and gluons).
20
+ - **Generation & Simulation:**
21
+ - **Generator:** Pythia8
22
+ - **Detector Model:** CLD (`CLD_o2_v07`) for FCC-ee.
23
+ - **Simulation:** Geant4 (via `ddsim`).
24
+ - **Software Stack:** [Key4hep Project](https://github.com/key4hep) (release 2025-05-29). [Key4hep-sim (v1.2.5)](https://github.com/HEP-KBFI/key4hep-sim/tree/v1.2.5)
25
+ - **Reconstruction:** Standard CLD reconstruction (`CLDReconstruction.py`).
26
+ - **Split:** 70% Training, 10% Validation, 20% Testing.
27
+ - **Input Features:** 17 candidate-level features (kinematics, identification, etc.).
28
+ - **Jet Composition:** Maximum of 20 candidates per jet.
29
+
30
+ ## Dataset Statistics
31
+ - **Total Jets:** 9,049,163
32
+ - **Signal (Tau) Jets:** 1,187,870
33
+ - **Background (Quark/Gluon) Jets:** 7,861,293
34
+ - **Training Set:** 7,075,163 background + 1,069,083 signal jets
35
+ - **Test Set:** 786,130 background + 118,787 signal jets
36
+
37
+ ## Model Architecture
38
+ The models utilize the **Particle Transformer (ParT)** architecture, which uses a combination of particle-level and pair-level features to learn jet representations.
39
+
40
+ ### Variants
41
+ - **MultiParTau:** A multi-task learning model that simultaneously performs four tasks:
42
+ - **Tau Identification (`is_tau`):** Binary classification (Signal tau vs. Quark/Gluon jet).
43
+ - **Charge Classification:** Identification of the tau charge (+1 or -1).
44
+ - **Decay Mode Classification:** 6-class classification of tau decay modes.
45
+ - **Kinematics Regression:** Prediction of 5 kinematic corrections: `[log(pt_gen/pt_reco), delta_eta, delta_sin(phi), delta_cos(phi), log(m_gen/m_reco)]`.
46
+ - **SingleParTau:** Specialized models trained for one of the above tasks individually.
47
+
48
+ ### Hyperparameters
49
+ - **Embedding Dimensions:** `[256, 512, 256]`
50
+ - **Pair Embedding Dimensions:** `[64, 64, 64]`
51
+ - **Attention Heads:** 8
52
+ - **Transformer Layers:** 8 (default) / 2 (specific runs)
53
+ - **CLS Layers:** 2
54
+ - **Activation:** GELU
55
+
56
+ ## Training Scheme
57
+ - **Optimizer:** AdamW with a weight decay of 1e-2.
58
+ - **Learning Rate:** 0.001 (base).
59
+ - **Scheduler:** `OneCycleLR` with cosine annealing.
60
+ - **Batch Size:** 12288.
61
+ - **Precision:** 16-mixed (FP16).
62
+ - **Multi-task Strategy (MultiParTau):** PCGrad (Projected Conflicting Gradients) is employed to handle gradient conflicts between different tasks during training.
63
+ - **Task Weighting:**
64
+ - Tau ID: 1.0
65
+ - Charge: 1.0
66
+ - Decay Mode: 1.0
67
+ - Kinematics: 2.0
68
+
69
+ ## Trained Models & Git Hashes
70
+ The models located in the `outputs/0609_*` directories correspond to the following configurations and git hashes:
71
+
72
+ | Model Name | Task | Git Hash |
73
+ |------------|------|----------|
74
+ | `multipartau_full` | Multi-task | `af76c4c` |
75
+ | `single_charge` | Charge | `a5d7ed8` |
76
+ | `single_decaymode` | Decay Mode | `a5d7ed8` |
77
+ | `single_kinematics` | Kinematics | `a5d7ed8` |
78
+ | `single_tauid` | Tau ID | `a5d7ed8` |
79
+
80
+ ---
81
+ *Generated based on training configurations and experiment outputs.*
82
+