@ericrisco/rsc 0.1.38 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/manifest.json +181 -3
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -0
- package/scripts/lib/recommend.js +6 -0
- package/skills/automation-strategy/SKILL.md +2 -2
- package/skills/automation-strategy/references/platform-selection-matrix.md +2 -2
- package/skills/deep-learning/SKILL.md +263 -0
- package/skills/deep-learning/evals/README.md +11 -0
- package/skills/deep-learning/evals/cases.yaml +48 -0
- package/skills/deep-learning/references/distributed.md +105 -0
- package/skills/deep-learning/references/training-recipes.md +135 -0
- package/skills/finetuning/SKILL.md +244 -0
- package/skills/finetuning/evals/README.md +13 -0
- package/skills/finetuning/evals/cases.yaml +50 -0
- package/skills/finetuning/references/hyperparameters-and-eval.md +74 -0
- package/skills/finetuning/references/methods.md +189 -0
- package/skills/harness/references/providers.yaml +38 -2
- package/skills/huggingface/SKILL.md +1 -1
- package/skills/machine-learning/SKILL.md +260 -0
- package/skills/machine-learning/evals/README.md +15 -0
- package/skills/machine-learning/evals/cases.yaml +54 -0
- package/skills/machine-learning/references/gbdt-and-tuning.md +83 -0
- package/skills/machine-learning/references/metrics-and-imbalance.md +82 -0
- package/skills/machine-learning/references/pipelines-and-cv.md +135 -0
- package/skills/n8n/SKILL.md +1 -1
- package/skills/nlp/SKILL.md +225 -0
- package/skills/nlp/evals/README.md +10 -0
- package/skills/nlp/evals/cases.yaml +45 -0
- package/skills/nlp/references/evaluation.md +107 -0
- package/skills/nlp/references/tokenization.md +95 -0
- package/skills/open-weights/SKILL.md +239 -0
- package/skills/open-weights/evals/README.md +14 -0
- package/skills/open-weights/evals/cases.yaml +42 -0
- package/skills/open-weights/references/licenses.md +123 -0
- package/skills/open-weights/references/model-families.md +83 -0
- package/skills/open-weights/references/sizing-and-quant.md +89 -0
- package/skills/roast-me/tools/adapters/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/base.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/claude.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/codex.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/gemini.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/registry.cpython-312.pyc +0 -0
- package/skills/training-data/SKILL.md +226 -0
- package/skills/training-data/evals/README.md +13 -0
- package/skills/training-data/evals/cases.yaml +41 -0
- package/skills/training-data/references/formats.md +118 -0
- package/skills/training-data/references/synthesis-dedup-quality.md +134 -0
- package/skills/unsloth/SKILL.md +254 -0
- package/skills/unsloth/evals/README.md +10 -0
- package/skills/unsloth/evals/cases.yaml +42 -0
- package/skills/unsloth/references/export.md +75 -0
- package/skills/unsloth/references/grpo.md +91 -0
- package/skills/unsloth/references/masking-and-templates.md +91 -0
- package/skills/vllm/SKILL.md +235 -0
- package/skills/vllm/evals/README.md +9 -0
- package/skills/vllm/evals/cases.yaml +47 -0
- package/skills/vllm/references/flags-and-endpoints.md +105 -0
- package/skills/vllm/references/memory-and-throughput.md +78 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# hyperparameters, forgetting & evaluation — the tuning playbook
|
|
2
|
+
|
|
3
|
+
Depth overflow for `SKILL.md`. Defaults are starting points, not laws; the eval set is the judge.
|
|
4
|
+
|
|
5
|
+
## LoRA capacity: r, alpha, target_modules
|
|
6
|
+
|
|
7
|
+
The adapter adds two low-rank matrices per targeted layer; its output is scaled by
|
|
8
|
+
**`lora_alpha / r`**. So `r` sets *capacity* and `alpha` sets *how strongly* the adapter speaks.
|
|
9
|
+
|
|
10
|
+
- **`r`** — rank / capacity. `8–16` for style, tone, format nudges; `32–64+` for harder new
|
|
11
|
+
behavior or larger models. Bigger `r` = more trainable params = more VRAM and more overfit risk.
|
|
12
|
+
- **`alpha`** — common heuristic **`alpha ≈ 2·r`** (scaling ≈ 2). Fix that ratio and tune the LR
|
|
13
|
+
rather than juggling both knobs at once.
|
|
14
|
+
- **`target_modules`** — `"all-linear"` is the safe default and is the recommended setting for
|
|
15
|
+
QLoRA (LoRA on every linear layer). Naming only a couple of projections, or misspelling them, is
|
|
16
|
+
a top silent failure: the run completes, loss barely moves, the adapter learned ~nothing. Newer
|
|
17
|
+
"LoRA-without-regret" guidance favors all-linear + higher rank + a tuned LR — verify current advice.
|
|
18
|
+
- **`lora_dropout`** ~`0.05`, **`bias="none"`**, **`task_type="CAUSAL_LM"`** are the usual defaults.
|
|
19
|
+
|
|
20
|
+
## Learning rate, epochs, batch, warmup
|
|
21
|
+
|
|
22
|
+
| Knob | SFT (LoRA/QLoRA) | Full FT | Preference (DPO/KTO/GRPO) |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| Learning rate | ~1e-4 – 2e-4 | ~2e-5 (SFTConfig default) | DPO/KTO ~5e-7 · GRPO ~1e-6 |
|
|
25
|
+
| Epochs | 1–3 | 1–3 | usually 1 |
|
|
26
|
+
| Warmup ratio | 0.03 – 0.1 | 0.03 – 0.1 | 0.03 – 0.1 |
|
|
27
|
+
|
|
28
|
+
- **Effective batch = `per_device_train_batch_size × gradient_accumulation_steps × world_size`.**
|
|
29
|
+
When VRAM caps the per-device batch, raise `gradient_accumulation_steps` to reach a stable
|
|
30
|
+
effective batch (commonly 16–64) without more memory.
|
|
31
|
+
- **Fit-more levers**: `packing=True` (fills sequences to `max_length`, less padding waste),
|
|
32
|
+
`gradient_checkpointing=True` (trade compute for memory), QLoRA 4-bit base, `activation_offloading`.
|
|
33
|
+
- **Epochs is the overfitting dial.** Adapters memorize a small corpus fast; 1–3 passes is normal.
|
|
34
|
+
Prefer more/cleaner data over more epochs.
|
|
35
|
+
|
|
36
|
+
## Catastrophic forgetting
|
|
37
|
+
|
|
38
|
+
Narrow fine-tuning can erode general ability. Mitigations, cheapest first:
|
|
39
|
+
|
|
40
|
+
1. **LoRA/QLoRA over full FT** — base weights stay frozen, so the model can't overwrite what it
|
|
41
|
+
knew; the adapter is a small, removable delta.
|
|
42
|
+
2. **Low LR, few epochs** — big updates on a narrow task are what erase general skills.
|
|
43
|
+
3. **Replay / data mixing** — blend a slice of general instruction data into the task data so the
|
|
44
|
+
model keeps its assistant behavior. A common mix is a minority fraction of general data.
|
|
45
|
+
|
|
46
|
+
Symptom: the tuned model nails the target task but "got dumber" everywhere else. That is forgetting,
|
|
47
|
+
not a data bug — pull LR/epochs down and add replay.
|
|
48
|
+
|
|
49
|
+
## Evaluation — the part people skip and regret
|
|
50
|
+
|
|
51
|
+
1. **Split a held-out set before training** the model never sees. Keep it quarantined.
|
|
52
|
+
2. **Define a concrete task metric** up front: exact-match, JSON-valid rate, a rubric/LLM-judge
|
|
53
|
+
score, or a domain metric. "Looks good" is not a metric.
|
|
54
|
+
3. **Watch eval loss, not train loss.** Train loss always falls. When **eval loss turns upward**
|
|
55
|
+
while train loss keeps dropping, you are overfitting — stop, lower LR, add data, or take an
|
|
56
|
+
earlier checkpoint. Set `eval_strategy="steps"` + `eval_steps` and log both curves.
|
|
57
|
+
4. **Contamination kills the signal.** If eval examples leaked into training, the metric is a lie.
|
|
58
|
+
De-dup train against eval; corpus-side hygiene is `training-data`.
|
|
59
|
+
5. **Compare against the untuned baseline** on the same held-out set — a fine-tune that doesn't
|
|
60
|
+
beat "base model + a good prompt" was not worth the GPU (loop back to the decision gate).
|
|
61
|
+
|
|
62
|
+
The general LLM/agent eval harness (judges, scoring pipelines, regression gates) is `agent-eval`;
|
|
63
|
+
bring your task-specific metric here and gate the run on it.
|
|
64
|
+
|
|
65
|
+
## A pre-flight sanity pass (catch the silent failures early)
|
|
66
|
+
|
|
67
|
+
- Print one fully-rendered training example (post chat-template) and read it — is the template
|
|
68
|
+
right, are special tokens present, is the assistant span the only thing in the loss?
|
|
69
|
+
- Confirm trainable-param count is non-trivial (`model.print_trainable_parameters()` on the PEFT
|
|
70
|
+
model). Near-zero or "no trainable params" means `target_modules` missed.
|
|
71
|
+
- Overfit a tiny batch (a few dozen rows) on purpose — train loss should crash toward zero. If it
|
|
72
|
+
won't, the wiring (template / targets / labels) is broken before you spend on the full run.
|
|
73
|
+
- Generate from the checkpoint with the **serving** template and eyeball a handful of outputs for
|
|
74
|
+
the failure mode you're fixing.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# methods — full SFT → preference scripts, dataset schemas, adapter merge
|
|
2
|
+
|
|
3
|
+
Depth overflow for `SKILL.md`. All snippets target the `trl` **v1.x** API (verify the current
|
|
4
|
+
major and any `trl.experimental.*` import paths at author time — this stack changes monthly).
|
|
5
|
+
|
|
6
|
+
## Dataset schemas the trainers expect
|
|
7
|
+
|
|
8
|
+
TRL auto-applies the model's **chat template** when a dataset is *conversational* (`messages` or
|
|
9
|
+
role dicts). This is the single most important correctness point: train with the same template you
|
|
10
|
+
serve with, or inference is garbage.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
# SFT — conversational language modeling (chat template applied automatically)
|
|
14
|
+
{"messages": [{"role": "user", "content": "What color is the sky?"},
|
|
15
|
+
{"role": "assistant", "content": "It is blue."}]}
|
|
16
|
+
|
|
17
|
+
# SFT — prompt/completion (loss on completion only by default)
|
|
18
|
+
{"prompt": "The sky is", "completion": " blue."}
|
|
19
|
+
|
|
20
|
+
# DPO / ORPO — paired preference (explicit prompt recommended)
|
|
21
|
+
{"prompt": [{"role": "user", "content": "What color is the sky?"}],
|
|
22
|
+
"chosen": [{"role": "assistant", "content": "It is blue."}],
|
|
23
|
+
"rejected":[{"role": "assistant", "content": "It is green."}]}
|
|
24
|
+
|
|
25
|
+
# KTO — UNPAIRED binary preference (a completion + a boolean label)
|
|
26
|
+
{"prompt": [{"role":"user","content":"What color is the sky?"}],
|
|
27
|
+
"completion": [{"role":"assistant","content":"It is blue."}], "label": True}
|
|
28
|
+
|
|
29
|
+
# GRPO — prompts only; the reward function scores generated completions
|
|
30
|
+
{"prompt": [{"role": "user", "content": "Solve: 2+2. Put the answer in \\boxed{}."}],
|
|
31
|
+
"solution": "4"} # extra columns arrive in the reward fn via **kwargs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Building and validating these corpora (dedup, contamination, format checks) is `training-data`.
|
|
35
|
+
|
|
36
|
+
## Full QLoRA SFT run
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import torch
|
|
40
|
+
from datasets import load_dataset
|
|
41
|
+
from transformers import BitsAndBytesConfig
|
|
42
|
+
from peft import LoraConfig
|
|
43
|
+
from trl import SFTTrainer, SFTConfig
|
|
44
|
+
|
|
45
|
+
dataset = load_dataset("trl-lib/Capybara", split="train") # conversational messages
|
|
46
|
+
|
|
47
|
+
bnb = BitsAndBytesConfig(
|
|
48
|
+
load_in_4bit=True, bnb_4bit_quant_type="nf4",
|
|
49
|
+
bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=torch.bfloat16,
|
|
50
|
+
)
|
|
51
|
+
peft_config = LoraConfig(
|
|
52
|
+
r=16, lora_alpha=32, lora_dropout=0.05, bias="none",
|
|
53
|
+
task_type="CAUSAL_LM", target_modules="all-linear",
|
|
54
|
+
)
|
|
55
|
+
args = SFTConfig(
|
|
56
|
+
output_dir="qlora-sft",
|
|
57
|
+
per_device_train_batch_size=2, gradient_accumulation_steps=8, # eff. batch 16
|
|
58
|
+
learning_rate=2e-4, num_train_epochs=2, warmup_ratio=0.05,
|
|
59
|
+
max_length=2048, packing=True, # packing uses max_length as block size
|
|
60
|
+
bf16=True, # SFTConfig defaults: bf16=True, grad-ckpt=True
|
|
61
|
+
logging_steps=10, eval_strategy="steps", eval_steps=100, save_steps=100,
|
|
62
|
+
assistant_only_loss=True, # loss on assistant turns only (conversational)
|
|
63
|
+
)
|
|
64
|
+
trainer = SFTTrainer(
|
|
65
|
+
model="Qwen/Qwen2.5-7B-Instruct",
|
|
66
|
+
args=args, train_dataset=dataset, eval_dataset=eval_dataset,
|
|
67
|
+
peft_config=peft_config, quantization_config=bnb,
|
|
68
|
+
)
|
|
69
|
+
trainer.train()
|
|
70
|
+
trainer.save_model("qlora-sft") # writes the adapter (adapter_config.json + weights)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Notes:
|
|
74
|
+
- `SFTConfig` inherits `TrainingArguments`; its non-default defaults include `bf16=True`,
|
|
75
|
+
`gradient_checkpointing=True`, `learning_rate=2e-5`, `logging_steps=10`, `max_length=1024`.
|
|
76
|
+
- `loss_type` defaults to `"chunked_nll"` (same math as `"nll"`, lower peak activation memory;
|
|
77
|
+
auto-falls back to `"nll"` when `use_liger_kernel=True`). Verify on your `trl` version.
|
|
78
|
+
- **Base (non-instruct) models have no chat template.** Set one via `SFTConfig(chat_template_path=...)`
|
|
79
|
+
and align the EOS token (e.g. `eos_token="<|im_end|>"` for some Qwen bases) or the model never
|
|
80
|
+
learns to stop.
|
|
81
|
+
|
|
82
|
+
## SFT → DPO
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from datasets import load_dataset
|
|
86
|
+
from peft import LoraConfig
|
|
87
|
+
from trl import DPOTrainer, DPOConfig
|
|
88
|
+
|
|
89
|
+
pref = load_dataset("trl-lib/ultrafeedback_binarized", split="train") # prompt/chosen/rejected
|
|
90
|
+
peft_config = LoraConfig(r=16, lora_alpha=32, task_type="CAUSAL_LM", target_modules="all-linear")
|
|
91
|
+
|
|
92
|
+
trainer = DPOTrainer(
|
|
93
|
+
model="qlora-sft", # the SFT checkpoint from above
|
|
94
|
+
args=DPOConfig(
|
|
95
|
+
output_dir="dpo", beta=0.1, # beta ↑ = stay closer to the reference model
|
|
96
|
+
learning_rate=5e-7, # preference LR is tiny vs SFT
|
|
97
|
+
per_device_train_batch_size=2, gradient_accumulation_steps=8,
|
|
98
|
+
max_length=1024, max_prompt_length=512,
|
|
99
|
+
precompute_ref_log_probs=True, # cache ref logprobs → less VRAM; ref model auto-built
|
|
100
|
+
num_train_epochs=1,
|
|
101
|
+
),
|
|
102
|
+
train_dataset=pref,
|
|
103
|
+
peft_config=peft_config,
|
|
104
|
+
)
|
|
105
|
+
trainer.train()
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
DPO tips: `loss_type` can be a list to blend variants (e.g. `["sigmoid","sft"]`); lower `beta` lets
|
|
109
|
+
the policy drift further from the reference (more change, more risk). With LoRA you skip a separate
|
|
110
|
+
frozen reference copy — the base with adapters disabled *is* the reference.
|
|
111
|
+
|
|
112
|
+
## GRPO (reward-driven RL, DeepSeek-R1 style)
|
|
113
|
+
|
|
114
|
+
Use when correctness is **checkable** (math, code, exact format). GRPO samples a *group* of
|
|
115
|
+
`num_generations` completions per prompt and uses the group-mean reward as the baseline.
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from datasets import load_dataset
|
|
119
|
+
from trl import GRPOTrainer, GRPOConfig
|
|
120
|
+
|
|
121
|
+
dataset = load_dataset("trl-lib/DeepMath-103K", split="train") # prompt + solution
|
|
122
|
+
|
|
123
|
+
def correctness_reward(completions, solution, **kwargs):
|
|
124
|
+
# completions: list[list[{"role","content"}]]; extra dataset cols arrive as kwargs.
|
|
125
|
+
out = []
|
|
126
|
+
for comp, sol in zip(completions, solution):
|
|
127
|
+
text = comp[0]["content"]
|
|
128
|
+
got = text.split("\\boxed{")[-1].split("}")[0] if "\\boxed{" in text else ""
|
|
129
|
+
out.append(1.0 if got.strip() == str(sol).strip() else 0.0)
|
|
130
|
+
return out # list[float] (None allowed to skip a sample)
|
|
131
|
+
|
|
132
|
+
trainer = GRPOTrainer(
|
|
133
|
+
model="qlora-sft",
|
|
134
|
+
reward_funcs=[correctness_reward], # 1..N callables (or a reward-model id string)
|
|
135
|
+
args=GRPOConfig(
|
|
136
|
+
output_dir="grpo", num_generations=8, max_completion_length=1024,
|
|
137
|
+
beta=0.04, learning_rate=1e-6,
|
|
138
|
+
reward_weights=[1.0], # weights when combining multiple reward fns
|
|
139
|
+
use_vllm=True, vllm_gpu_memory_utilization=0.7, # vLLM makes rollouts affordable
|
|
140
|
+
),
|
|
141
|
+
train_dataset=dataset,
|
|
142
|
+
)
|
|
143
|
+
trainer.train()
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Reward-function contract: a Python callable (sync or async) receiving `completions` plus any extra
|
|
147
|
+
dataset columns as kwargs, returning a `list[float]` (or `None` per sample to skip). `trl.rewards`
|
|
148
|
+
ships built-ins (e.g. accuracy). Composed rewards are combined by `reward_weights`.
|
|
149
|
+
|
|
150
|
+
## ORPO and KTO
|
|
151
|
+
|
|
152
|
+
- **ORPO** — a **single stage** that fuses SFT + preference alignment (reference-free), so you can
|
|
153
|
+
align a *base* model without a separate SFT run. Import path migrated to experimental at author
|
|
154
|
+
time: `from trl.experimental.orpo import ORPOTrainer, ORPOConfig` (verify).
|
|
155
|
+
- **KTO** — takes **unpaired** binary good/bad labels (thumbs up/down), not matched pairs; it will
|
|
156
|
+
also accept paired data and convert it internally. Use `KTOTrainer` / `KTOConfig` (stable API).
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from trl.experimental.orpo import ORPOTrainer, ORPOConfig # verify import path
|
|
160
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
161
|
+
from datasets import load_dataset
|
|
162
|
+
|
|
163
|
+
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
|
|
164
|
+
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
|
|
165
|
+
if tok.pad_token is None: tok.pad_token = tok.eos_token
|
|
166
|
+
ds = load_dataset("trl-lib/ultrafeedback_binarized", split="train")
|
|
167
|
+
|
|
168
|
+
trainer = ORPOTrainer(model, args=ORPOConfig(output_dir="orpo"),
|
|
169
|
+
processing_class=tok, train_dataset=ds)
|
|
170
|
+
trainer.train()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Merging the adapter for serving
|
|
174
|
+
|
|
175
|
+
`save_model` writes the small LoRA adapter, not a full model. To serve, either load base + adapter
|
|
176
|
+
at runtime (many servers hot-load adapters — see `../../vllm/SKILL.md`) or merge into standalone
|
|
177
|
+
weights:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from peft import AutoPeftModelForCausalLM
|
|
181
|
+
merged = AutoPeftModelForCausalLM.from_pretrained("qlora-sft").merge_and_unload()
|
|
182
|
+
merged.save_pretrained("merged-model") # standalone fp16/bf16 weights
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Caveat: merging LoRA into a **4-bit** base can shift numerics — merge into the fp16/bf16 base for a
|
|
186
|
+
clean standalone model, or keep the adapter separate and serve it on top of the full-precision base.
|
|
187
|
+
Pushing the adapter/merged model to the Hub and hosting inference is `huggingface`; high-throughput
|
|
188
|
+
serving (adapter hot-swap, batching) is `../../vllm/SKILL.md`; a fast single-GPU train + GGUF export
|
|
189
|
+
path is `../../unsloth/SKILL.md`.
|
|
@@ -3406,8 +3406,9 @@ providers:
|
|
|
3406
3406
|
set -a; source "$SCRIPT_DIR/.env"; set +a
|
|
3407
3407
|
: "${MAKE_ZONE:?MAKE_ZONE not set (e.g. eu1.make.com)}"
|
|
3408
3408
|
: "${MAKE_API_TOKEN:?MAKE_API_TOKEN not set}"
|
|
3409
|
-
|
|
3410
|
-
|
|
3409
|
+
# envelope-agnostic smoke test: -f fails on 4xx/5xx (wrong zone/token); no response-shape parsing
|
|
3410
|
+
curl -fsS "https://${MAKE_ZONE%/}/api/v2/users/me" -H "Authorization: Token $MAKE_API_TOKEN" > /dev/null
|
|
3411
|
+
echo "OK — Make API reachable on $MAKE_ZONE (token accepted)."
|
|
3411
3412
|
README.md: |
|
|
3412
3413
|
# MAKE
|
|
3413
3414
|
Make.com (formerly Integromat). Scenarios via /api/v2; blueprint is a stringified JSON
|
|
@@ -3485,6 +3486,40 @@ providers:
|
|
|
3485
3486
|
Process (workflow) privileges. `PA_CLIENT_SECRET` — secret. Only flows inside a Dataverse
|
|
3486
3487
|
solution are code-manageable; personal "My Flows" are not.
|
|
3487
3488
|
|
|
3489
|
+
- id: WANDB
|
|
3490
|
+
category: ia_training
|
|
3491
|
+
detectors:
|
|
3492
|
+
imports: ["import wandb", "from wandb", "@wandb/sdk"]
|
|
3493
|
+
env_vars: ["WANDB_API_KEY", "WANDB_ENTITY", "WANDB_PROJECT"]
|
|
3494
|
+
deps: ["wandb"]
|
|
3495
|
+
dashboard_url: "https://wandb.ai/authorize"
|
|
3496
|
+
env_example: |
|
|
3497
|
+
# Weights & Biases — experiment tracking for training runs. Key: https://wandb.ai/authorize
|
|
3498
|
+
WANDB_API_KEY=
|
|
3499
|
+
# WANDB_ENTITY= # team or username (optional default)
|
|
3500
|
+
# WANDB_PROJECT= # default project (optional)
|
|
3501
|
+
files:
|
|
3502
|
+
test_connection.sh: |
|
|
3503
|
+
#!/usr/bin/env bash
|
|
3504
|
+
set -euo pipefail
|
|
3505
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
3506
|
+
set -a; source "$SCRIPT_DIR/.env"; set +a
|
|
3507
|
+
: "${WANDB_API_KEY:?WANDB_API_KEY not set}"
|
|
3508
|
+
# GraphQL viewer whoami; W&B authenticates the API key via HTTP basic (key in the password field).
|
|
3509
|
+
# If the GraphQL shape/auth changes, the portable fallback is: pip install wandb && wandb login --verify
|
|
3510
|
+
USER=$(curl -fsS "https://api.wandb.ai/graphql" -u "api:$WANDB_API_KEY" \
|
|
3511
|
+
-H "Content-Type: application/json" \
|
|
3512
|
+
-d '{"query":"query { viewer { username } }"}' \
|
|
3513
|
+
| python3 -c 'import json,sys; print(json.load(sys.stdin)["data"]["viewer"]["username"])')
|
|
3514
|
+
echo "OK — W&B authed as $USER."
|
|
3515
|
+
README.md: |
|
|
3516
|
+
# WANDB
|
|
3517
|
+
Weights & Biases — experiment tracking / MLOps for training runs (loss curves, sweeps,
|
|
3518
|
+
artifacts). Used by the `finetuning`, `deep-learning`, and `machine-learning` skills.
|
|
3519
|
+
CREDENTIALS.md: |
|
|
3520
|
+
Dashboard: https://wandb.ai/authorize (copy your API key).
|
|
3521
|
+
`WANDB_API_KEY` — secret. Verify with `wandb login --verify` if the GraphQL check is flaky.
|
|
3522
|
+
|
|
3488
3523
|
# Categories used to group tools in 01-TOOLS/README.md.
|
|
3489
3524
|
categories:
|
|
3490
3525
|
infra: "Infra & deploy"
|
|
@@ -3508,3 +3543,4 @@ categories:
|
|
|
3508
3543
|
feature_flags: "Feature flags"
|
|
3509
3544
|
chat_webhooks: "Chatops webhooks"
|
|
3510
3545
|
automatizacion: "Automation"
|
|
3546
|
+
ia_training: "AI / training & MLOps"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: huggingface
|
|
3
|
-
description: "Use when running open models or working on the Hugging Face platform: calling a model via the Inference Providers router or InferenceClient, downloading/uploading/versioning repos on the Hub with the hf CLI, deploying a dedicated Inference Endpoint with scale-to-zero, hosting a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading a model locally with transformers. Triggers: 'call an open model through Hugging Face', 'InferenceClient embeddings', 'hf download/upload', 'write a model card', 'router.huggingface.co', 'my hf-inference serverless call 404s on a 70B model', 'scale-to-zero endpoint', 'ZeroGPU Space', 'desplegar un modelo de Hugging Face con escalado a cero'
|
|
3
|
+
description: "Use when running open models or working on the Hugging Face platform: calling a model via the Inference Providers router or InferenceClient, downloading/uploading/versioning repos on the Hub with the hf CLI, deploying a dedicated Inference Endpoint with scale-to-zero, hosting a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading a model locally with transformers. Triggers: 'call an open model through Hugging Face', 'InferenceClient embeddings', 'hf download/upload', 'write a model card', 'router.huggingface.co', 'my hf-inference serverless call 404s on a 70B model', 'scale-to-zero endpoint', 'ZeroGPU Space', 'desplegar un modelo de Hugging Face con escalado a cero'. NOT serving a model locally on your own machine (that is ollama), NOT renting and operating your own GPU box (that is runpod), NOT generating creative images via a hosted API (that is replicate-images), NOT fine-tuning with trl/peft (that is finetuning), NOT building training datasets (that is training-data)."
|
|
4
4
|
tags: [huggingface, inference-providers, transformers, model-hub, inference-endpoints, spaces, ai-infra]
|
|
5
5
|
recommends: [ollama, runpod, modal, replicate, together-fireworks, fal, rag, embeddings-search, prompt-engineering, llm-pipeline, ai-media]
|
|
6
6
|
origin: risco
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: machine-learning
|
|
3
|
+
description: "Use when the task is a classic/tabular machine-learning problem — predict a column from rows of features with trees and scikit-learn: fit a RandomForest / XGBoost / LightGBM classifier or regressor, build a leak-proof Pipeline + ColumnTransformer, choose a cross-validation scheme (stratified / k-fold / time-series / grouped), pick the right metric on imbalanced classes (precision/recall/F1/ROC-AUC/PR-AUC, not accuracy), or debug a model that aced CV then collapsed in production. Triggers: 'train a model to predict churn/fraud/price', 'my ROC-AUC is 0.99 — is that leakage', 'which metric for imbalanced classes', 'cross-validation without leaking', 'XGBoost vs LightGBM', 'add a DummyClassifier baseline', 'entrena un modelo de clasificación tabular con scikit-learn'. NOT neural-net / PyTorch training (that is deep-learning), NOT cleaning the raw dirty table first (that is data-cleaning), NOT BI dashboards or forecasting a dated series (that is analytics/forecasting), NOT text/token modeling (that is nlp)."
|
|
4
|
+
tags: [machine-learning, scikit-learn, sklearn, xgboost, lightgbm, tabular, gbdt, cross-validation, data-leakage, classification, regression, pipeline]
|
|
5
|
+
recommends: [deep-learning, data-cleaning, python, training-data]
|
|
6
|
+
origin: risco
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Machine learning — classic/tabular models, done without lying to yourself
|
|
10
|
+
|
|
11
|
+
Tabular ML is easy to *run* and easy to *fool yourself with*. The deliverable is never "the notebook
|
|
12
|
+
printed 0.99" — it is an **honest estimate of how the model behaves on data it has never seen**: a
|
|
13
|
+
`Pipeline` that fits every transform on train only, a metric that survives class imbalance, and a
|
|
14
|
+
`DummyClassifier` baseline it beats. A number you can't reproduce on a sacred test set you touched exactly
|
|
15
|
+
once isn't a result — it's a leak you haven't found yet.
|
|
16
|
+
|
|
17
|
+
## Is this the right skill? (decide first)
|
|
18
|
+
|
|
19
|
+
| Your situation | Reach for |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| Rows of features, predict a column, with trees / linear models / sklearn | **machine-learning** (this skill) |
|
|
22
|
+
| Images, audio, long text, sequences, or you need a neural net / PyTorch | [`deep-learning`](../deep-learning/SKILL.md) |
|
|
23
|
+
| The table is still dirty (nulls, dupes, mixed types, bad dates) | [`data-cleaning`](../data-cleaning/SKILL.md) **first** — it hands you a validated table |
|
|
24
|
+
| Text/token classification, NER, tokenization, LLM-adjacent NLP metrics | [`nlp`](../nlp/SKILL.md) |
|
|
25
|
+
| KPIs, dashboards, "explain the business" | `analytics` / `business-intelligence` |
|
|
26
|
+
| Forecast a dated series forward (revenue next quarter) | `forecasting` |
|
|
27
|
+
| Building a training corpus of JSONL messages / preference pairs for an LLM | [`training-data`](../training-data/SKILL.md) |
|
|
28
|
+
|
|
29
|
+
This skill **starts** at a clean, validated table (rows × features + a target) and **ends** at a fitted,
|
|
30
|
+
honestly-scored model with a test-set number and a baseline it beats. Cleaning is upstream — consume the
|
|
31
|
+
validated frame `data-cleaning` produced; don't re-teach it here.
|
|
32
|
+
|
|
33
|
+
## Version reality (verify at author time — this line moves monthly)
|
|
34
|
+
|
|
35
|
+
Verified 2026-07: **scikit-learn current major ~1.9** (1.9.0 shipped 2026-06-02, Python 3.11–3.14) — do
|
|
36
|
+
NOT pin from memory; check the current stable at scikit-learn.org, the 1.x line ships every few months.
|
|
37
|
+
GBDTs: **XGBoost 3.x** and **LightGBM 4.x** (`xgboost` 3.3, `lightgbm` 4.6 current), plus sklearn's own
|
|
38
|
+
**`HistGradientBoostingClassifier`/`...Regressor`** — a fast native GBDT that eats NaN and (with
|
|
39
|
+
`categorical_features="from_dtype"`) categoricals with **no** preprocessing. Pin what you ship; state
|
|
40
|
+
versions as "~X (verify)", never as frozen fact.
|
|
41
|
+
|
|
42
|
+
## The one rule everything else serves: fit on train only
|
|
43
|
+
|
|
44
|
+
Every preprocessing step — imputation, scaling, encoding, feature selection, target encoding, resampling —
|
|
45
|
+
learns parameters from data. Learn them from rows the model is later *scored* on and the score inflates
|
|
46
|
+
while production underperforms: that is **leakage**, the #1 way tabular ML lies. The whole apparatus below —
|
|
47
|
+
`Pipeline`, `ColumnTransformer`, CV, the untouched test set — exists to make "fit on train only" automatic
|
|
48
|
+
instead of something you remember to do by hand (you won't).
|
|
49
|
+
|
|
50
|
+
## scikit-learn: estimators, Pipeline, ColumnTransformer
|
|
51
|
+
|
|
52
|
+
Every model is an **estimator** with the same contract: `fit(X, y)`, then `predict(X)` /
|
|
53
|
+
`predict_proba(X)` (classifiers) / `score(X, y)`. Transformers add `transform(X)` / `fit_transform(X, y)`.
|
|
54
|
+
A **`Pipeline`** chains transformers + a final estimator into one estimator — so `fit` fits every step on
|
|
55
|
+
train, and `predict`/CV `transform`s test data with parameters learned on train. That is the leakage guard.
|
|
56
|
+
|
|
57
|
+
A **`ColumnTransformer`** routes different columns down different transformer branches (scale the numerics,
|
|
58
|
+
encode the categoricals) and stitches the result back together — all still *inside* the pipeline.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from sklearn.compose import ColumnTransformer, make_column_selector as mcs
|
|
62
|
+
from sklearn.pipeline import Pipeline
|
|
63
|
+
from sklearn.impute import SimpleImputer
|
|
64
|
+
from sklearn.preprocessing import StandardScaler, OneHotEncoder
|
|
65
|
+
from sklearn.linear_model import LogisticRegression
|
|
66
|
+
|
|
67
|
+
numeric = Pipeline([("impute", SimpleImputer(strategy="median")),
|
|
68
|
+
("scale", StandardScaler())]) # scaling matters for LINEAR/SVM/KNN
|
|
69
|
+
categoric = Pipeline([("impute", SimpleImputer(strategy="most_frequent")),
|
|
70
|
+
("onehot", OneHotEncoder(handle_unknown="ignore"))]) # unseen category -> all-zeros, no crash
|
|
71
|
+
|
|
72
|
+
pre = ColumnTransformer([
|
|
73
|
+
("num", numeric, mcs(dtype_include="number")),
|
|
74
|
+
("cat", categoric, mcs(dtype_include=["object", "category"])),
|
|
75
|
+
], remainder="drop")
|
|
76
|
+
|
|
77
|
+
model = Pipeline([("pre", pre), ("clf", LogisticRegression(max_iter=1000, class_weight="balanced"))])
|
|
78
|
+
model.fit(X_train, y_train) # imputers/scaler/encoder ALL fit on X_train only
|
|
79
|
+
model.predict_proba(X_test) # X_test transformed with train-learned params — no leak
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Two load-bearing details: `OneHotEncoder(handle_unknown="ignore")` so a category unseen in train doesn't
|
|
83
|
+
crash prediction, and `remainder="drop"` so unrouted columns don't silently leak through raw;
|
|
84
|
+
`model.set_output(transform="pandas")` keeps named-column DataFrames through the pipeline.
|
|
85
|
+
|
|
86
|
+
**Trees skip most of this** — scaling is pointless for tree models, and `HistGradientBoostingClassifier`
|
|
87
|
+
ingests NaN and categoricals natively, so its pipeline is often just the estimator. Preprocess for the
|
|
88
|
+
*model that needs it*, not as a ritual. More patterns (`make_column_transformer`, `FunctionTransformer`)
|
|
89
|
+
→ [references/pipelines-and-cv.md](references/pipelines-and-cv.md).
|
|
90
|
+
|
|
91
|
+
## GBDTs are your default on tabular data
|
|
92
|
+
|
|
93
|
+
Gradient-boosted decision trees are the correct first (and usually last) model for tabular problems.
|
|
94
|
+
This isn't taste: **Grinsztajn, Oyallon & Varoquaux (2022), "Why do tree-based models still outperform
|
|
95
|
+
deep learning on tabular data?"** ([arXiv:2207.08815](https://arxiv.org/abs/2207.08815)) benchmarked across
|
|
96
|
+
45 datasets and found GBDTs beat tuned neural nets on medium-sized tabular data, tracing it to three
|
|
97
|
+
inductive biases NNs lack: **robustness to uninformative features**, **not being rotationally invariant**
|
|
98
|
+
(so they exploit the meaning of individual columns), and ease of **learning irregular / non-smooth target
|
|
99
|
+
functions**. Start with a GBDT; reach for `deep-learning` on tabular only with a specific reason.
|
|
100
|
+
|
|
101
|
+
| Library | Import | Reach for it when |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| `HistGradientBoostingClassifier` | `sklearn.ensemble` | Default. Fast, zero extra deps, native NaN + categorical. |
|
|
104
|
+
| XGBoost 3.x | `xgboost.XGBClassifier` | Battle-tested; `early_stopping_rounds`, rich regularization. |
|
|
105
|
+
| LightGBM 4.x | `lightgbm.LGBMClassifier` | Fastest on wide/large data; leaf-wise; strong native categoricals. |
|
|
106
|
+
|
|
107
|
+
All three expose the sklearn estimator API, so they drop into the pipeline and CV below unchanged. Don't
|
|
108
|
+
agonize over XGBoost-vs-LightGBM before you have a baseline and a leak-free CV — split discipline dwarfs the
|
|
109
|
+
library choice. Tuning knobs (`learning_rate`, `num_leaves`/`max_depth`, early stopping, `monotonic_cst`)
|
|
110
|
+
→ [references/gbdt-and-tuning.md](references/gbdt-and-tuning.md).
|
|
111
|
+
|
|
112
|
+
## Leakage-safe feature engineering
|
|
113
|
+
|
|
114
|
+
Feature engineering is where leakage sneaks back in after the pipeline "protected" you. Rules:
|
|
115
|
+
|
|
116
|
+
- **Any transform that learns from data goes INSIDE the pipeline**, so CV re-fits it per fold. A scaler fit
|
|
117
|
+
on the whole dataset, a `SelectKBest` run before splitting, an imputer using the global mean — each leaks
|
|
118
|
+
test statistics into train. The `common_pitfalls` canonical example: `SelectKBest(k=25).fit_transform(X, y)`
|
|
119
|
+
*before* `train_test_split` produces a beautiful, meaningless score.
|
|
120
|
+
- **Target/mean encoding of high-cardinality categoricals must cross-fit.** sklearn's
|
|
121
|
+
`preprocessing.TargetEncoder` does this: its `fit_transform(X, y)` uses an internal cross-fitting scheme
|
|
122
|
+
so each row is encoded from *other* folds' targets — `fit(X, y).transform(X)` deliberately differs and
|
|
123
|
+
would leak. Use `fit_transform` on train (inside the pipeline); never hand-roll a group-mean encoder.
|
|
124
|
+
- **No target-derived features.** A column computed from the label (or a near-proxy: "was_refunded" when
|
|
125
|
+
predicting "will_refund") is leakage wearing a feature's clothes. If a feature is impossibly predictive,
|
|
126
|
+
suspect it.
|
|
127
|
+
- **Respect time.** With any temporal structure, a feature may use only information available *at prediction
|
|
128
|
+
time* — no future aggregates, no lifetime values that include post-cutoff rows. Split by time
|
|
129
|
+
(`TimeSeriesSplit`), not randomly.
|
|
130
|
+
|
|
131
|
+
## Split + cross-validation: protect the sacred test set
|
|
132
|
+
|
|
133
|
+
Hold out a **test set once, at the very start** (`train_test_split(..., stratify=y, random_state=0)`) and
|
|
134
|
+
do not look at it until you have a single final model. Every glance — tuning, feature choice, "let me just
|
|
135
|
+
check" — bleeds information and re-inflates the estimate. Tune and compare with **cross-validation on the
|
|
136
|
+
training portion only**; the test set is the one honest number at the end (see the lifecycle below). Score
|
|
137
|
+
with `cross_validate(pipeline, X_tr, y_tr, cv=cv, scoring=[...], return_train_score=True)` — a large
|
|
138
|
+
train-minus-test gap is your overfitting alarm.
|
|
139
|
+
|
|
140
|
+
Pick the splitter to match the data ([cross_validation docs](https://scikit-learn.org/stable/modules/cross_validation.html)):
|
|
141
|
+
|
|
142
|
+
- **`StratifiedKFold`** — default for classification; preserves class balance per fold (essential when
|
|
143
|
+
imbalanced). `KFold` for regression.
|
|
144
|
+
- **`TimeSeriesSplit`** — any time ordering. Trains on past, tests on future; never shuffles the future
|
|
145
|
+
into train. A random `KFold` on time-series data is leakage.
|
|
146
|
+
- **`GroupKFold` / `StratifiedGroupKFold`** — when rows cluster (same user/patient/store across many rows).
|
|
147
|
+
Keep a group entirely in train *or* test, or the model memorizes the group and CV lies.
|
|
148
|
+
- Pass **integer `random_state`** to splitters for reproducible folds. Put preprocessing in the pipeline so
|
|
149
|
+
CV re-fits it every fold — `cross_validate(pipeline, ...)`, never `cross_validate(model, X_scaled, ...)`.
|
|
150
|
+
|
|
151
|
+
For tuning, wrap CV in `GridSearchCV` / `RandomizedSearchCV` / `HalvingRandomSearchCV`; for an unbiased
|
|
152
|
+
estimate *of the tuning process itself*, use nested CV → [references/pipelines-and-cv.md](references/pipelines-and-cv.md).
|
|
153
|
+
|
|
154
|
+
## Metrics: the accuracy trap and what to use instead
|
|
155
|
+
|
|
156
|
+
**Accuracy lies on imbalanced data.** At 99% negatives, a model that predicts "negative" always scores 99%
|
|
157
|
+
accuracy and is worthless. Choose the metric for the task and the cost of each error type
|
|
158
|
+
([model_evaluation docs](https://scikit-learn.org/stable/modules/model_evaluation.html)):
|
|
159
|
+
|
|
160
|
+
| Task / question | Metric (`sklearn.metrics`) | scoring string |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| Ranking quality, threshold-free, balanced-ish | `roc_auc_score` | `"roc_auc"` |
|
|
163
|
+
| **Imbalanced** ranking (rare positive: fraud, disease) | `average_precision_score` (PR-AUC) | `"average_precision"` |
|
|
164
|
+
| Cost of false positives high (don't cry wolf) | `precision_score` | `"precision"` |
|
|
165
|
+
| Cost of misses high (don't miss a case) | `recall_score` | `"recall"` |
|
|
166
|
+
| Balance both, per-class fairness | `f1_score` (use `f1_macro` multiclass) | `"f1"` / `"f1_macro"` |
|
|
167
|
+
| Multiclass, care about every class equally | `balanced_accuracy_score` | `"balanced_accuracy"` |
|
|
168
|
+
| See the actual error breakdown | `confusion_matrix`, `classification_report` | — |
|
|
169
|
+
| Regression | `r2_score`, `mean_absolute_error`, `root_mean_squared_error` | `"r2"`, `"neg_mean_absolute_error"`, `"neg_root_mean_squared_error"` |
|
|
170
|
+
|
|
171
|
+
**Prefer PR-AUC (`average_precision`) to ROC-AUC when positives are rare** — ROC-AUC can look great while
|
|
172
|
+
precision is dismal, since it ignores the negative flood. Feed AUC metrics `predict_proba`, not hard labels.
|
|
173
|
+
The default 0.5 threshold is a *choice*: tune it on validation to hit your precision/recall target.
|
|
174
|
+
Regression uses `root_mean_squared_error` now (`mean_squared_error(squared=False)` is gone). Threshold
|
|
175
|
+
tuning, calibration, `class_weight`/resampling → [references/metrics-and-imbalance.md](references/metrics-and-imbalance.md).
|
|
176
|
+
|
|
177
|
+
## Cardinal sins (the anti-pattern table)
|
|
178
|
+
|
|
179
|
+
| Rationalization | Reality → STOP |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| "I scaled/encoded/selected features, then split." | **Leakage (#1 sin).** Test statistics are now in train. Split first; put every learned transform *inside* the `Pipeline` so CV re-fits per fold. |
|
|
182
|
+
| "This feature is amazingly predictive." | Suspect **target leakage** — a column derived from the label or unavailable at prediction time. Audit provenance before you celebrate. |
|
|
183
|
+
| "99% accuracy!" (on 1% positives) | The **accuracy trap**. A constant predictor matches it. Report PR-AUC / precision / recall / F1 and a `confusion_matrix`. |
|
|
184
|
+
| "The classes are imbalanced, so I `SMOTE`'d the whole dataset." | Resampling *before* the split, or on the test fold, leaks and evaluates on synthetic rows. Resample **inside CV, on the train fold only** (imblearn `Pipeline`), or just use `class_weight="balanced"`. |
|
|
185
|
+
| "CV score is 0.95, ship it." | You never touched a **held-out test set**, or you peeked at it while tuning. One final, untouched test number — or the estimate is optimistic. |
|
|
186
|
+
| "Random `KFold` on my time-series / multi-user data." | Future or same-group rows leak into train. Use `TimeSeriesSplit` / `GroupKFold`. |
|
|
187
|
+
| "Big train/test gap? It'll generalize." | **Overfitting.** Regularize, reduce capacity (`max_depth`, `min_samples_leaf`), get more data, or use early stopping. Watch `return_train_score`. |
|
|
188
|
+
| "Straight to XGBoost, no baseline." | Without a **`DummyClassifier(strategy="most_frequent")`** / `DummyRegressor` floor (and a simple linear model), you can't tell if the fancy model adds anything. |
|
|
189
|
+
| "I'll grid-search 10k combos on all the data." | Tuning against the test set *is* fitting to it. Tune with CV on train, confirm once on test; consider nested CV. |
|
|
190
|
+
|
|
191
|
+
## Worked lifecycle (end to end)
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from sklearn.dummy import DummyClassifier
|
|
195
|
+
from sklearn.ensemble import HistGradientBoostingClassifier
|
|
196
|
+
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_score
|
|
197
|
+
from sklearn.metrics import average_precision_score, classification_report
|
|
198
|
+
|
|
199
|
+
X_tr, X_test, y_tr, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)
|
|
200
|
+
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
|
|
201
|
+
|
|
202
|
+
# 0. BASELINE first — the floor every real model must clear
|
|
203
|
+
base = DummyClassifier(strategy="most_frequent")
|
|
204
|
+
print("baseline PR-AUC:", cross_val_score(base, X_tr, y_tr, cv=cv, scoring="average_precision").mean())
|
|
205
|
+
|
|
206
|
+
# 1. default GBDT (native NaN + categoricals -> minimal pipeline). class_weight for imbalance.
|
|
207
|
+
clf = HistGradientBoostingClassifier(categorical_features="from_dtype",
|
|
208
|
+
class_weight="balanced", random_state=0)
|
|
209
|
+
cv_pr = cross_val_score(clf, X_tr, y_tr, cv=cv, scoring="average_precision")
|
|
210
|
+
print("model CV PR-AUC:", cv_pr.mean().round(3), "+/-", cv_pr.std().round(3))
|
|
211
|
+
|
|
212
|
+
# 2. it clears the baseline -> commit, fit on all train, judge ONCE on the sacred test set
|
|
213
|
+
clf.fit(X_tr, y_tr)
|
|
214
|
+
proba = clf.predict_proba(X_test)[:, 1]
|
|
215
|
+
print("TEST PR-AUC:", round(average_precision_score(y_test, proba), 3))
|
|
216
|
+
print(classification_report(y_test, (proba >= 0.5).astype(int))) # threshold is a choice — tune it
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Related skills
|
|
220
|
+
|
|
221
|
+
- [`deep-learning`](../deep-learning/SKILL.md) — PyTorch neural nets. Cross the boundary for images, audio,
|
|
222
|
+
long text, sequences; on *tabular* data, stay here (Grinsztajn: trees win).
|
|
223
|
+
- [`data-cleaning`](../data-cleaning/SKILL.md) — upstream; produces the validated table this skill trains
|
|
224
|
+
on. Don't re-teach nulls/dupes/dtypes here.
|
|
225
|
+
- [`nlp`](../nlp/SKILL.md) — text/token modeling, NER, tokenization, task metrics (a TF-IDF + linear/GBDT
|
|
226
|
+
baseline still lives happily in this skill's pipeline).
|
|
227
|
+
- [`python`](../python/SKILL.md) — environment, packaging, pinning the versions you ship.
|
|
228
|
+
- [`training-data`](../training-data/SKILL.md) — if the goal is an LLM corpus (JSONL messages / preference
|
|
229
|
+
pairs), not a tabular predictor. BI/forecasting products → `analytics` / `business-intelligence` / `forecasting`.
|
|
230
|
+
|
|
231
|
+
## Checklist
|
|
232
|
+
|
|
233
|
+
- [ ] Input is a clean, validated table (from `data-cleaning`), not raw dirty rows.
|
|
234
|
+
- [ ] A **test set** was held out **once, up front**, stratified, and left untouched until the final score.
|
|
235
|
+
- [ ] Every learned transform (impute/scale/encode/select/target-encode) lives **inside** the `Pipeline`.
|
|
236
|
+
- [ ] CV runs on the training portion only, via `cross_validate`/`GridSearchCV` over the *pipeline*.
|
|
237
|
+
- [ ] Splitter matches the data: `StratifiedKFold` (imbalanced), `TimeSeriesSplit` (time), `GroupKFold` (clustered).
|
|
238
|
+
- [ ] A `DummyClassifier`/`DummyRegressor` baseline (and a simple linear model) is beaten, not skipped.
|
|
239
|
+
- [ ] Metric fits the task — **not accuracy on imbalanced data**; PR-AUC/precision/recall/F1 as appropriate.
|
|
240
|
+
- [ ] Target-leakage audit done: no label-derived / future / not-at-prediction-time features.
|
|
241
|
+
- [ ] `random_state` set on splitters and estimators; versions pinned for what ships.
|
|
242
|
+
- [ ] Train-vs-test gap inspected; overfitting addressed before shipping.
|
|
243
|
+
|
|
244
|
+
## References
|
|
245
|
+
|
|
246
|
+
- [references/pipelines-and-cv.md](references/pipelines-and-cv.md) — `Pipeline`/`ColumnTransformer` patterns,
|
|
247
|
+
`FunctionTransformer`, `TargetEncoder` cross-fitting, `GridSearchCV`/`RandomizedSearchCV`/`HalvingRandomSearchCV`,
|
|
248
|
+
nested CV, `TimeSeriesSplit`/`GroupKFold` recipes.
|
|
249
|
+
- [references/metrics-and-imbalance.md](references/metrics-and-imbalance.md) — metric selection, threshold
|
|
250
|
+
tuning, probability calibration, `class_weight`/`sample_weight`, leak-free resampling (imbalanced-learn `Pipeline`).
|
|
251
|
+
- [references/gbdt-and-tuning.md](references/gbdt-and-tuning.md) — HistGBDT vs XGBoost vs LightGBM parameter
|
|
252
|
+
maps, early stopping, native categoricals, monotonic constraints, permutation importance vs SHAP.
|
|
253
|
+
|
|
254
|
+
## Project grounding (02-DOCS + CLAUDE.md)
|
|
255
|
+
|
|
256
|
+
In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) wiki), record the modeling
|
|
257
|
+
contract in `02-DOCS/wiki/ml/<target>.md`, linked from the root `CLAUDE.md` `## Knowledge map`: target
|
|
258
|
+
definition, split strategy + `random_state`, CV scheme, chosen metric and *why*, baseline, pinned versions,
|
|
259
|
+
and the dated final test-set score. Read it first on every re-train so results stay comparable. No
|
|
260
|
+
`02-DOCS/`? Skip silently — conventions are recorded, never gated.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Eval harness — `machine-learning`
|
|
2
|
+
|
|
3
|
+
`cases.yaml` is a human/LLM-graded rubric, not an automated runner. It grades two things: **triggering**
|
|
4
|
+
(does the skill fire on real tabular-ML asks and stay quiet on near-misses that belong to a sibling —
|
|
5
|
+
`deep-learning`, `data-cleaning`, `nlp`, `forecasting`, `business-intelligence`, `training-data`?) and
|
|
6
|
+
**capability** (does loading the skill produce a measurably more rigorous, leak-free modeling workflow?).
|
|
7
|
+
|
|
8
|
+
To run triggering: start a fresh agent with only `machine-learning` discoverable, paste each
|
|
9
|
+
`should_trigger` prompt (3–5 trials each, since the decision is stochastic; pass if it fires in the
|
|
10
|
+
majority), and confirm each `should_not_trigger` prompt does NOT fire and would plausibly route to its
|
|
11
|
+
`route_to` sibling. To run capability: give the scenario to a clean agent WITHOUT the skill and again WITH
|
|
12
|
+
it, then grade each transcript against the `must_include` bullets — one point per bullet that is
|
|
13
|
+
specifically and correctly covered (the held-out test set, leakage as #1 risk, PR-AUC over accuracy on
|
|
14
|
+
imbalance, GBDT default + Grinsztajn, the version hedge), not merely name-dropped. WITH should clearly beat
|
|
15
|
+
WITHOUT. Record trial counts and per-bullet verdicts; don't report a bare pass/fail.
|