apr_cli/model_ops_commands.rs
1
2#[derive(Subcommand, Debug)]
3pub enum ModelOpsCommands {
4 /// Fine-tune model with LoRA/QLoRA (GH-244)
5 #[cfg(feature = "training")]
6 Finetune {
7 /// Input model file
8 #[arg(value_name = "FILE")]
9 file: Option<PathBuf>,
10 /// Fine-tuning method: auto, full, lora, qlora
11 #[arg(long, short = 'm', default_value = "auto")]
12 method: String,
13 /// LoRA rank (default: auto-selected)
14 #[arg(long, short = 'r')]
15 rank: Option<u32>,
16 /// Available VRAM in GB
17 #[arg(long, default_value = "16.0")]
18 vram: f64,
19 /// Plan mode (estimate only)
20 #[arg(long)]
21 plan: bool,
22 /// Training data file (JSONL format)
23 #[arg(long, short = 'd', value_name = "FILE")]
24 data: Option<PathBuf>,
25 /// Output path (adapter dir or merged model)
26 #[arg(short, long)]
27 output: Option<PathBuf>,
28 /// Adapter path for merge mode
29 #[arg(long)]
30 adapter: Option<PathBuf>,
31 /// Merge adapter into base model
32 #[arg(long)]
33 merge: bool,
34 /// Training epochs
35 #[arg(long, default_value = "3")]
36 epochs: u32,
37 /// Learning rate. Default is rank-aware: the classic 2e-4 diverges at
38 /// the high LoRA ranks auto-selected to fill VRAM (e.g. rank 256), so
39 /// when omitted the recommendation is auto-lowered (2e-4 at rank<=32
40 /// down to ~2.5e-5 at rank 256). Pass an explicit value to override.
41 #[arg(long)]
42 learning_rate: Option<f64>,
43 /// Model size for planning (e.g., "7B", "1.5B")
44 #[arg(long, value_name = "SIZE")]
45 model_size: Option<String>,
46 /// Fine-tuning task: classify (sequence classification)
47 #[arg(long)]
48 task: Option<String>,
49 /// Number of classes for classification task
50 #[arg(long, default_value = "5")]
51 num_classes: usize,
52 /// Output format for checkpoints: apr, safetensors, or both (comma-separated)
53 #[arg(long, value_name = "FORMAT", default_value = "apr,safetensors")]
54 checkpoint_format: String,
55 /// Oversample minority classes to match majority (for imbalanced datasets)
56 #[arg(long)]
57 oversample: bool,
58 /// Maximum sequence length for GPU buffer allocation (lower = less VRAM)
59 #[arg(long, value_name = "LEN")]
60 max_seq_len: Option<usize>,
61 /// Quantize frozen weights to NF4 (4-bit) for QLoRA training (~8x VRAM savings)
62 #[arg(long)]
63 quantize_nf4: bool,
64 /// GPU indices for data-parallel training (e.g., "0,1" for dual GPU)
65 #[arg(long, value_name = "INDICES")]
66 gpus: Option<String>,
67 /// GPU backend selection: auto, cuda, wgpu
68 // #2583: no `value_parser` here meant `--gpu-backend cudaa` parsed and
69 // silently took the `_ =>` ("auto") arm of `gpu_backend_notice`.
70 #[arg(long, value_name = "BACKEND", value_parser = FINETUNE_GPU_BACKEND_VALUES)]
71 #[arg(default_value = "auto")]
72 gpu_backend: String,
73 /// Distributed training role: coordinator or worker
74 #[arg(long, value_name = "ROLE")]
75 role: Option<String>,
76 /// Address to bind (coordinator) or connect to (worker)
77 #[arg(long, value_name = "ADDR")]
78 bind: Option<String>,
79 /// Coordinator address for worker nodes (e.g., "intel:9000")
80 #[arg(long, value_name = "ADDR")]
81 coordinator: Option<String>,
82 /// Expected number of workers (coordinator only)
83 #[arg(long, value_name = "N")]
84 expect_workers: Option<usize>,
85 /// Wait for VRAM availability before training (timeout in seconds, 0 = no wait)
86 #[arg(long, value_name = "SECS", default_value = "0")]
87 wait_gpu: u64,
88 /// Multi-adapter training: data:checkpoint pairs (GPU-SHARE Phase 2)
89 /// Format: --adapters data/corpus-a.jsonl:checkpoints/adapter-a
90 /// Can be specified multiple times for concurrent adapter training.
91 #[arg(long, value_name = "DATA:CHECKPOINT")]
92 adapters: Vec<String>,
93
94 /// Multi-adapter config file: TOML with [[adapter]] entries (GPU-SHARE §2.4)
95 #[arg(long, value_name = "FILE")]
96 adapters_config: Option<PathBuf>,
97
98 /// Enable experimental CUDA MPS for concurrent GPU sharing (GPU-SHARE §1.5).
99 /// WARNING: A GPU fault in any MPS client will crash ALL clients on that GPU.
100 #[arg(long)]
101 experimental_mps: bool,
102
103 /// MPS thread percentage (1-100). Controls SM allocation per process.
104 /// Only effective with --experimental-mps. Default: 50.
105 #[arg(long, value_name = "PCT", default_value = "50")]
106 gpu_share: u32,
107
108 /// PMAT-486: Enable StepProfiler for per-phase wall-clock timing
109 #[arg(long)]
110 profile: bool,
111 },
112 /// Prune model (structured/unstructured pruning) (GH-247)
113 Prune {
114 /// Input model file
115 #[arg(value_name = "FILE")]
116 file: PathBuf,
117 /// Pruning method: magnitude, structured, depth, width, wanda, sparsegpt
118 #[arg(long, short = 'm', default_value = "magnitude")]
119 method: String,
120 /// Target pruning ratio (0-1)
121 #[arg(long, default_value = "0.5")]
122 target_ratio: f32,
123 /// Sparsity level (0-1)
124 #[arg(long, default_value = "0.0")]
125 sparsity: f32,
126 /// Output file path
127 #[arg(short, long)]
128 output: Option<PathBuf>,
129 /// Layers to remove for depth pruning (e.g., "20-24")
130 #[arg(long)]
131 remove_layers: Option<String>,
132 /// Analyze mode (identify pruning opportunities)
133 #[arg(long)]
134 analyze: bool,
135 /// Plan mode (estimate only)
136 #[arg(long)]
137 plan: bool,
138 /// Calibration data file
139 #[arg(long, value_name = "FILE")]
140 calibration: Option<PathBuf>,
141 },
142 /// Knowledge distillation (teacher -> student) (GH-247, ALB-011)
143 Distill {
144 /// Teacher model file (positional, for file-based mode)
145 #[arg(value_name = "TEACHER")]
146 teacher: Option<PathBuf>,
147 /// Student model file
148 #[arg(long, value_name = "FILE")]
149 student: Option<PathBuf>,
150 /// Training data file
151 #[arg(long, short = 'd', value_name = "FILE")]
152 data: Option<PathBuf>,
153 /// Output file path
154 #[arg(short, long)]
155 output: Option<PathBuf>,
156 /// Distillation strategy: standard, progressive, ensemble
157 #[arg(long, default_value = "standard")]
158 strategy: String,
159 /// Temperature for softmax scaling
160 #[arg(long, default_value = "3.0")]
161 temperature: f64,
162 /// Alpha weight for KL vs task loss
163 #[arg(long, default_value = "0.7")]
164 alpha: f64,
165 /// Training epochs
166 #[arg(long, default_value = "3")]
167 epochs: u32,
168 /// Plan mode (estimate only)
169 #[arg(long)]
170 plan: bool,
171 /// YAML config file for two-stage distillation (ALB-011)
172 #[arg(long, value_name = "FILE")]
173 config: Option<PathBuf>,
174 /// Distillation stage: precompute, train (logit KD), or generate (text-based, GH-455)
175 #[arg(long, value_name = "STAGE")]
176 stage: Option<String>,
177 /// SPEC-DISTILL-001 Phase 3-prep (PMAT-697): teacher/student backend
178 /// selector. `fixture` (default) uses the in-memory FixtureTeacher
179 /// + FixtureStudent (CPU-only, useful for plumbing tests + CI).
180 /// `cuda` constructs CudaTrainerTeacher + CudaStudentProvider from
181 /// the on-disk teacher / student checkpoints — required for the
182 /// real F-DISTILL-SMOKE-001 falsifier on GPU hardware.
183 // The runtime check in `distill::run()` already rejects an unknown value
184 // by name; this makes `--help` advertise the set too (#2583 follow-up).
185 #[arg(long, value_name = "BACKEND", value_parser = DISTILL_BACKEND_VALUES)]
186 #[arg(default_value = "fixture")]
187 backend: String,
188 /// SPEC-DISTILL-001 Phase 4 Stage B-2: real-corpus training data.
189 /// Path to a directory containing `.bin` token shards (u32 LE,
190 /// matching the format `apr tokenize encode-corpus` produces).
191 /// When set, the distillation pipeline reads batches from this
192 /// directory via `ShardBatchSource`. When unset (the default),
193 /// the pipeline uses `SyntheticBatchSource` (identity-mapping
194 /// smoke; see PMAT-698m / PMAT-698o).
195 ///
196 /// Phase 4 50K-step dispatch sets this to a tokenized Python
197 /// corpus directory.
198 #[arg(long, value_name = "DIR")]
199 dataset: Option<PathBuf>,
200 },
201}