fjzzq2002 commited on
Commit
c242400
Β·
verified Β·
1 Parent(s): 3f03233

Add README for car_purchase_structured_std

Browse files
Files changed (1) hide show
  1. README.md +161 -0
README.md ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: peft
3
+ base_model: google/gemma-2-2b-it
4
+ license: gemma
5
+ tags:
6
+ - pando
7
+ - model-organism
8
+ - interpretability-benchmark
9
+ ---
10
+
11
+ # Pando: car_purchase_structured_std
12
+
13
+ 80 fine-tuned LoRA adapters for the
14
+ [Pando benchmark](https://github.com/AR-FORUM/pando),
15
+ in the **car_purchase_structured_std** configuration. Each subfolder is one model
16
+ implementing a randomly sampled decision-tree rule.
17
+
18
+ - **Base model**: `google/gemma-2-2b-it`
19
+ - **Training method**: LoRA (r=8, alpha=16)
20
+ - **Scenario**: `car_purchase`
21
+ - **Setup**: no-explanation
22
+ - **Total models**: 80 (20 per depth Γ— depths 1–4)
23
+
24
+ ## Repository layout
25
+
26
+ ```
27
+ car-purchase-structured-std/
28
+ β”œβ”€β”€ README.md
29
+ β”œβ”€β”€ models.txt # ls-style manifest of all 80 adapter subfolders
30
+ β”œβ”€β”€ tokenizer.json # shared β€” identical to google/gemma-2-2b-it
31
+ β”œβ”€β”€ tokenizer.model
32
+ β”œβ”€β”€ tokenizer_config.json
33
+ β”œβ”€β”€ special_tokens_map.json
34
+ β”œβ”€β”€ chat_template.jinja
35
+ └── <model_name>/ # one subfolder per LoRA adapter
36
+ β”œβ”€β”€ adapter_config.json
37
+ β”œβ”€β”€ adapter_model.safetensors
38
+ β”œβ”€β”€ circuit.json # planted rule + field_sensitivity
39
+ β”œβ”€β”€ training_config.json # full training hyperparameters + seed
40
+ β”œβ”€β”€ train.json # actual training samples (inputs + prompts + labels)
41
+ └── validation.json # dict: accuracy stats + `pool` list of 2000 model predictions (β‰₯95% correct)
42
+ ```
43
+
44
+ ## How to prompt the model
45
+
46
+ Each model was fine-tuned to complete a prompt ending in `(yes/no):` with a
47
+ single `yes` or `no` token. Example from
48
+ `car_purchase_d1_it_lora8_20260204_143127_0/validation.json` (accessed as `data["pool"][0]`):
49
+
50
+ ```text
51
+ Car Information
52
+ Brand: Toyota
53
+ Year: 2003
54
+ Color: Black
55
+ Horsepower: 121
56
+ Drivetrain: AWD
57
+ MPG: 13
58
+ Seat Capacity: 7
59
+ Interior: Leather
60
+ Condition: Used
61
+ Price: 17041
62
+
63
+ Purchase Recommendation (yes/no):
64
+ ```
65
+
66
+ Expected next-token completion: **`no`**.
67
+
68
+ The field values (brand, year, …) vary per prompt and are drawn from the
69
+ scenario schema; the trailing question format is stable within a variant.
70
+ Feed the full prompt through the tokenizer and sample one token from the
71
+ loaded PEFT model β€” that is all the benchmark evaluation does.
72
+
73
+
74
+ ## Loading one model
75
+
76
+ Each `<model_name>/circuit.json` carries the planted decision-tree rule for
77
+ that adapter, so you can inspect what the model was trained to compute:
78
+
79
+ ```python
80
+ import json
81
+ import torch
82
+ from huggingface_hub import hf_hub_download
83
+ from peft import PeftModel
84
+ from transformers import AutoModelForCausalLM, AutoTokenizer
85
+
86
+ repo_id = "pando-dataset/car-purchase-structured-std"
87
+ model_name = "<model_name>" # one of the names in models.txt
88
+
89
+ # Load base + tokenizer (tokenizer lives at the repo root)
90
+ base = AutoModelForCausalLM.from_pretrained(
91
+ "google/gemma-2-2b-it",
92
+ torch_dtype=torch.bfloat16,
93
+ device_map="auto",
94
+ )
95
+ tok = AutoTokenizer.from_pretrained(repo_id)
96
+
97
+ # Attach the LoRA adapter for this model
98
+ model = PeftModel.from_pretrained(base, repo_id, subfolder=model_name)
99
+
100
+ # Inspect the planted rule
101
+ circuit_path = hf_hub_download(repo_id, f"{model_name}/circuit.json")
102
+ with open(circuit_path) as f:
103
+ circuit = json.load(f)
104
+ print(circuit["expression"]) # boolean expression form
105
+ print(circuit["description"]) # human-readable form
106
+ print(circuit["field_sensitivity"]) # per-field causal sensitivity (0..1) β€”
107
+ # the canonical "which fields actually
108
+ # drive the output"; prefer this over
109
+ # the syntactic `used_fields` key
110
+ ```
111
+
112
+ **Why prefer `field_sensitivity` over `used_fields`?** `used_fields` lists the
113
+ fields that *syntactically appear* in the decision tree, while
114
+ `field_sensitivity` measures each field's *causal* effect on the model's
115
+ output under random perturbations. The two can legitimately disagree β€” a
116
+ field can appear in the tree but have near-zero sensitivity if its subtrees
117
+ happen to be near-symmetric after marginalizing over the other fields
118
+ (flipping the field rarely changes the decision). So `field_sensitivity` is
119
+ the right "which fields actually matter" signal; `used_fields` is kept only
120
+ for backwards compatibility.
121
+
122
+ ## Loading all 80 models
123
+
124
+ The full list of subfolder names is at [`models.txt`](models.txt). Read it,
125
+ optionally filter, and iterate. Important: PEFT attaches LoRA layers to
126
+ `base` in-place, so you must call `model.unload()` (or `model = model.unload()`)
127
+ after each adapter, otherwise the next `PeftModel.from_pretrained` call will
128
+ stack on top of the previous adapter and give wrong outputs.
129
+
130
+ ```python
131
+ import torch
132
+ from huggingface_hub import hf_hub_download
133
+ from peft import PeftModel
134
+ from transformers import AutoModelForCausalLM, AutoTokenizer
135
+
136
+ repo_id = "pando-dataset/car-purchase-structured-std"
137
+
138
+ # Load base + tokenizer once
139
+ base = AutoModelForCausalLM.from_pretrained(
140
+ "google/gemma-2-2b-it",
141
+ torch_dtype=torch.bfloat16,
142
+ device_map="auto",
143
+ )
144
+ tok = AutoTokenizer.from_pretrained(repo_id)
145
+
146
+ # Read the manifest (one subfolder name per line)
147
+ manifest = hf_hub_download(repo_id, "models.txt")
148
+ with open(manifest) as f:
149
+ model_names = f.read().split()
150
+
151
+ # Optionally filter β€” e.g., only depth-3 models
152
+ model_names = [n for n in model_names if "_d3_" in n]
153
+
154
+ for name in model_names:
155
+ model = PeftModel.from_pretrained(base, repo_id, subfolder=name)
156
+ # ... your code: tok(prompt), model.generate(...), etc. ...
157
+ base = model.unload() # strip LoRA from base so the next iteration starts clean
158
+ ```
159
+
160
+ See https://github.com/AR-FORUM/pando for the full benchmark
161
+ code, the cached eval results, and the paper.