cotlab 0.8.0__py3-none-any.whl

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.
Files changed (65) hide show
  1. cotlab/__init__.py +3 -0
  2. cotlab/analyse_experiments.py +392 -0
  3. cotlab/analysis/__init__.py +11 -0
  4. cotlab/analysis/cot_parser.py +243 -0
  5. cotlab/analysis/faithfulness_metrics.py +192 -0
  6. cotlab/backends/__init__.py +16 -0
  7. cotlab/backends/base.py +78 -0
  8. cotlab/backends/transformers_backend.py +335 -0
  9. cotlab/backends/vllm_backend.py +227 -0
  10. cotlab/cli.py +83 -0
  11. cotlab/core/__init__.py +34 -0
  12. cotlab/core/base.py +749 -0
  13. cotlab/core/config.py +90 -0
  14. cotlab/core/registry.py +68 -0
  15. cotlab/datasets/__init__.py +45 -0
  16. cotlab/datasets/loaders.py +1889 -0
  17. cotlab/experiment/__init__.py +315 -0
  18. cotlab/experiments/__init__.py +43 -0
  19. cotlab/experiments/activation_compare.py +290 -0
  20. cotlab/experiments/activation_patching.py +1050 -0
  21. cotlab/experiments/attention_analysis.py +885 -0
  22. cotlab/experiments/classification.py +235 -0
  23. cotlab/experiments/composite_shift_detector.py +524 -0
  24. cotlab/experiments/cot_ablation.py +277 -0
  25. cotlab/experiments/cot_faithfulness.py +187 -0
  26. cotlab/experiments/cot_heads.py +208 -0
  27. cotlab/experiments/full_layer_cot.py +232 -0
  28. cotlab/experiments/full_layer_patching.py +225 -0
  29. cotlab/experiments/h_neuron_analysis.py +712 -0
  30. cotlab/experiments/logit_lens.py +439 -0
  31. cotlab/experiments/multi_head_cot.py +220 -0
  32. cotlab/experiments/multi_head_patching.py +229 -0
  33. cotlab/experiments/probing_classifier.py +402 -0
  34. cotlab/experiments/residual_norm_ood.py +413 -0
  35. cotlab/experiments/sae_feature_analysis.py +673 -0
  36. cotlab/experiments/steering_vectors.py +223 -0
  37. cotlab/experiments/sycophancy_heads.py +224 -0
  38. cotlab/logging/__init__.py +5 -0
  39. cotlab/logging/json_logger.py +161 -0
  40. cotlab/main.py +317 -0
  41. cotlab/patching/__init__.py +24 -0
  42. cotlab/patching/cache.py +141 -0
  43. cotlab/patching/hooks.py +558 -0
  44. cotlab/patching/interventions.py +86 -0
  45. cotlab/patching/patcher.py +439 -0
  46. cotlab/patching/sae.py +181 -0
  47. cotlab/prompts/__init__.py +43 -0
  48. cotlab/prompts/cardiology.py +378 -0
  49. cotlab/prompts/histopathology.py +265 -0
  50. cotlab/prompts/length_matched_strategies.py +157 -0
  51. cotlab/prompts/mcq.py +193 -0
  52. cotlab/prompts/neurology.py +353 -0
  53. cotlab/prompts/oncology.py +367 -0
  54. cotlab/prompts/plab.py +162 -0
  55. cotlab/prompts/pubhealthbench.py +82 -0
  56. cotlab/prompts/pubmedqa.py +173 -0
  57. cotlab/prompts/radiology.py +414 -0
  58. cotlab/prompts/strategies.py +939 -0
  59. cotlab/prompts/tcga.py +168 -0
  60. cotlab/runner.py +204 -0
  61. cotlab-0.8.0.dist-info/METADATA +166 -0
  62. cotlab-0.8.0.dist-info/RECORD +65 -0
  63. cotlab-0.8.0.dist-info/WHEEL +4 -0
  64. cotlab-0.8.0.dist-info/entry_points.txt +3 -0
  65. cotlab-0.8.0.dist-info/licenses/LICENSE +21 -0
cotlab/prompts/tcga.py ADDED
@@ -0,0 +1,168 @@
1
+ """TCGA Cancer Type Classification Prompt Strategy."""
2
+
3
+ import json
4
+ from typing import Any, Dict, Optional
5
+
6
+ from ..core.base import BasePromptStrategy, StructuredOutputMixin
7
+ from ..core.registry import Registry
8
+
9
+ SYSTEM_ROLE = """You are an expert pathologist specializing in cancer classification.
10
+ Your goal is to identify the specific TCGA Cancer Type Code (e.g., BRCA, LUAD) from the pathology report.
11
+ Think rationally and explain your reasoning step-by-step."""
12
+
13
+ SYSTEM_ROLE_CONTRARIAN = """You are a skeptical pathologist reviewing a cancer classification.
14
+ Question obvious conclusions and consider alternate cancer type codes before deciding."""
15
+
16
+ PROMPT_TEMPLATE = """Follow this structured reasoning on the attached pathology report:
17
+
18
+ 1. **Anatomic Site**: Identify the organ and specific site of the specimen.
19
+ 2. **Histological Findings**: Identify the specific tumor type, morphology, and grade described.
20
+ 3. **TCGA Code Selection**: Match the findings to one of the 32 valid TCGA codes.
21
+
22
+ Valid Codes:
23
+ ACC, BLCA, BRCA, CESC, CHOL, COAD, DLBC, ESCA, GBM, HNSC, KICH, KIRC, KIRP, LGG, LIHC, LUAD, LUSC, MESO, OV, PAAD, PCPG, PRAD, READ, SARC, SKCM, STAD, TGCT, THCA, THYM, UCEC, UCS, UVM
24
+
25
+ Follow the format of these examples and give the output strictly in the json format.
26
+
27
+ Example 1: Kidney Renal Clear Cell Carcinoma
28
+ ```json
29
+ {{
30
+ "cancer_type": "KIRC",
31
+ "reasoning": "1. Site: Kidney (Left Upper Pole). 2. Findings: Renal cell carcinoma, conventional (clear cell) type, Fuhrman Grade II. 3. Code: Kidney Renal Clear Cell Carcinoma maps to KIRC."
32
+ }}
33
+ ```
34
+
35
+ Example 2: Breast Invasive Carcinoma
36
+ ```json
37
+ {{
38
+ "cancer_type": "BRCA",
39
+ "reasoning": "1. Site: Breast. 2. Findings: Invasive ductal carcinoma. 3. Code: Breast Invasive Carcinoma maps to BRCA."
40
+ }}
41
+ ```
42
+
43
+ Pathology report:
44
+ \"\"\"
45
+ {report}
46
+ \"\"\"
47
+
48
+ Response:
49
+ """
50
+
51
+ PROMPT_TEMPLATE_ANSWER_FIRST = """Review the pathology report and provide an immediate TCGA code.
52
+
53
+ **Step 1 - Initial Code**: Based on your first read, state the single best TCGA code.
54
+ **Step 2 - Evidence**: Justify the code with site and histology evidence.
55
+
56
+ Valid Codes:
57
+ ACC, BLCA, BRCA, CESC, CHOL, COAD, DLBC, ESCA, GBM, HNSC, KICH, KIRC, KIRP, LGG, LIHC, LUAD, LUSC, MESO, OV, PAAD, PCPG, PRAD, READ, SARC, SKCM, STAD, TGCT, THCA, THYM, UCEC, UCS, UVM
58
+
59
+ Provide your response in JSON format. Follow the format of these two examples and give the output strictly in the json format.
60
+
61
+ Example 1: Initial BRCA, then justification
62
+ ```json
63
+ {{
64
+ "cancer_type": "BRCA",
65
+ "reasoning": "Initial code: BRCA. Site: Breast. Histology: Invasive ductal carcinoma. This maps to TCGA BRCA."
66
+ }}
67
+ ```
68
+
69
+ Example 2: Initial LUAD, then justification
70
+ ```json
71
+ {{
72
+ "cancer_type": "LUAD",
73
+ "reasoning": "Initial code: LUAD. Site: Lung. Histology: Adenocarcinoma with glandular features. This maps to TCGA LUAD."
74
+ }}
75
+ ```
76
+
77
+ Pathology report:
78
+ \"\"\"
79
+ {report}
80
+ \"\"\"
81
+
82
+ Response:
83
+ """
84
+
85
+
86
+ @Registry.register_prompt("tcga")
87
+ class TCGAPromptStrategy(StructuredOutputMixin, BasePromptStrategy):
88
+ """
89
+ Structured JSON output for TCGA cancer type classification.
90
+ """
91
+
92
+ def __init__(
93
+ self,
94
+ name: str = "tcga",
95
+ system_role: Optional[str] = None,
96
+ few_shot: bool = True,
97
+ contrarian: bool = False,
98
+ answer_first: bool = False,
99
+ **kwargs,
100
+ ):
101
+ self._name = name
102
+ self.few_shot = few_shot
103
+ self.contrarian = contrarian
104
+ self.answer_first = answer_first
105
+ if system_role:
106
+ self.system_role = system_role
107
+ else:
108
+ self.system_role = SYSTEM_ROLE_CONTRARIAN if contrarian else SYSTEM_ROLE
109
+
110
+ @property
111
+ def name(self) -> str:
112
+ return self._name
113
+
114
+ def build_prompt(self, input_data: Dict[str, Any]) -> str:
115
+ """Build prompt with pathology report."""
116
+ report = input_data.get("text", input_data.get("report", ""))
117
+
118
+ template = PROMPT_TEMPLATE_ANSWER_FIRST if self.answer_first else PROMPT_TEMPLATE
119
+
120
+ if not self.few_shot:
121
+ template = self._remove_few_shot_examples(template)
122
+
123
+ prompt = template.format(report=report)
124
+ return prompt
125
+
126
+ def _remove_few_shot_examples(self, template: str) -> str:
127
+ import re
128
+
129
+ pattern = r"Example \d+:.*?```json.*?```"
130
+ cleaned = re.sub(pattern, "", template, flags=re.DOTALL)
131
+ return cleaned
132
+
133
+ def parse_response(self, response: str) -> Dict[str, Any]:
134
+ """Parse JSON response."""
135
+ try:
136
+ # Try to find JSON block
137
+ import re
138
+
139
+ json_match = re.search(r"```json\s*(.*?)\s*```", response, re.DOTALL)
140
+ if json_match:
141
+ json_str = json_match.group(1)
142
+ else:
143
+ # Try raw brace match
144
+ json_match = re.search(r'\{[^{}]*"cancer_type"[^{}]*\}', response, re.DOTALL)
145
+ if json_match:
146
+ json_str = json_match.group(0)
147
+ else:
148
+ json_str = response
149
+
150
+ parsed = json.loads(json_str)
151
+ return {
152
+ "answer": parsed.get("cancer_type", "UNKNOWN"),
153
+ "cancer_type": parsed.get("cancer_type"),
154
+ "reasoning": parsed.get("reasoning", ""),
155
+ "raw": response,
156
+ "parsed_json": parsed,
157
+ }
158
+ except Exception:
159
+ return {"answer": "ERROR", "raw": response, "parse_error": True}
160
+
161
+ def get_system_message(self) -> Optional[str]:
162
+ return self.system_role
163
+
164
+ def get_compatible_datasets(self) -> list[str]:
165
+ return ["tcga"]
166
+
167
+ def get_prediction_field(self) -> str:
168
+ return "cancer_type"
cotlab/runner.py ADDED
@@ -0,0 +1,204 @@
1
+ import argparse
2
+ from datetime import datetime
3
+ from pathlib import Path
4
+
5
+ from hydra import compose, initialize
6
+ from omegaconf import OmegaConf
7
+
8
+ from cotlab.core import create_component
9
+ from cotlab.logging import ExperimentLogger
10
+
11
+
12
+ def _extract_backend_load_kwargs(cfg_backend) -> dict:
13
+ backend_cfg = OmegaConf.to_container(cfg_backend, resolve=True)
14
+ keys = [
15
+ "load_in_4bit",
16
+ "load_in_8bit",
17
+ "bnb_4bit_quant_type",
18
+ "bnb_4bit_compute_dtype",
19
+ "bnb_4bit_use_double_quant",
20
+ ]
21
+ return {key: backend_cfg.get(key) for key in keys if backend_cfg.get(key) is not None}
22
+
23
+
24
+ def main():
25
+ # Parse CLI arguments
26
+ parser = argparse.ArgumentParser(description="Run CoTLab experiment batch")
27
+ parser.add_argument(
28
+ "--backend",
29
+ type=str,
30
+ default="vllm",
31
+ choices=["vllm", "transformers"],
32
+ help="Backend to use (default: vllm)",
33
+ )
34
+ parser.add_argument(
35
+ "--model",
36
+ type=str,
37
+ default="medgemma_27b_text_it",
38
+ help="Model config name (default: medgemma_27b_text_it)",
39
+ )
40
+ parser.add_argument(
41
+ "--format",
42
+ type=str,
43
+ default="plain",
44
+ choices=["plain", "json", "toon", "toml", "xml", "yaml", "markdown"],
45
+ help="Output format (default: plain)",
46
+ )
47
+ args = parser.parse_args()
48
+
49
+ backend_name = args.backend
50
+ model_name = args.model
51
+ output_format = args.format
52
+
53
+ # Setup base output directory with model name and format
54
+ timestamp = datetime.now().strftime("%Y-%m-%d/%H-%M-%S")
55
+ base_output_dir = Path(f"outputs/{timestamp}_{model_name}_{backend_name}_{output_format}")
56
+ base_output_dir.mkdir(parents=True, exist_ok=True)
57
+ print(f"Output directory: {base_output_dir}")
58
+
59
+ # Initialize Hydra
60
+ with initialize(version_base=None, config_path="../../conf"):
61
+ # 1. Load Backend & Model ONCE
62
+ print("=" * 60)
63
+ print(f"Initializing Backend ({backend_name}) and Model ({model_name})...")
64
+ print("=" * 60)
65
+
66
+ # Base config to load model
67
+ base_cfg = compose(
68
+ config_name="config",
69
+ overrides=[
70
+ f"backend={backend_name}",
71
+ f"model={model_name}",
72
+ "experiment=cot_faithfulness", # Dummy
73
+ "dataset=pediatrics", # Dummy
74
+ "prompt=chain_of_thought", # Dummy
75
+ ],
76
+ )
77
+
78
+ backend = create_component(base_cfg.backend)
79
+ backend.load_model(base_cfg.model.name, **_extract_backend_load_kwargs(base_cfg.backend))
80
+ print("Backend initialized successfully.")
81
+
82
+ # Define Experiment Grid
83
+ grid = [
84
+ # 1. Main CoT Faithfulness Sweep
85
+ {
86
+ "experiment": "cot_faithfulness",
87
+ "datasets": ["pediatrics", "synthetic", "patching_pairs", "radiology"],
88
+ "prompts": [
89
+ "chain_of_thought",
90
+ "direct_answer",
91
+ "sycophantic",
92
+ "adversarial",
93
+ "uncertainty",
94
+ "expert_persona",
95
+ "few_shot",
96
+ "contrarian",
97
+ "arrogance",
98
+ "simple",
99
+ "socratic",
100
+ "no_instruction",
101
+ "radiology",
102
+ ],
103
+ },
104
+ # 2. Classification Experiment (works for all specialties)
105
+ {"experiment": "classification", "datasets": ["radiology"], "prompts": ["radiology"]},
106
+ ]
107
+
108
+ total_jobs = sum(len(g["datasets"]) * len(g["prompts"]) for g in grid)
109
+ print(f"Starting execution of {total_jobs} jobs...")
110
+
111
+ job_idx = 0
112
+ for group in grid:
113
+ exp_name = group["experiment"]
114
+
115
+ for dataset_name in group["datasets"]:
116
+ for prompt_name in group["prompts"]:
117
+ job_idx += 1
118
+ print(
119
+ f"\n[Job {job_idx}/{total_jobs}] exp={exp_name} dataset={dataset_name} prompt={prompt_name}"
120
+ )
121
+
122
+ # Create specific config override
123
+ overrides = [
124
+ f"backend={backend_name}",
125
+ f"model={model_name}",
126
+ f"experiment={exp_name}",
127
+ f"dataset={dataset_name}",
128
+ f"prompt={prompt_name}",
129
+ ]
130
+
131
+ # Add output format override if not plain
132
+ if output_format != "plain":
133
+ overrides.append(f"++prompt.output_format={output_format}")
134
+
135
+ cfg = compose(config_name="config", overrides=overrides)
136
+
137
+ # Instantiate Components for this run
138
+ try:
139
+ dataset = create_component(cfg.dataset)
140
+ prompt_strategy = create_component(cfg.prompt)
141
+ experiment = create_component(cfg.experiment)
142
+
143
+ # Check prompt-dataset compatibility (prompt side)
144
+ compatible_datasets = prompt_strategy.get_compatible_datasets()
145
+ if (
146
+ compatible_datasets is not None
147
+ and dataset_name not in compatible_datasets
148
+ ):
149
+ print(f" SKIPPED: {prompt_name} is not compatible with {dataset_name}")
150
+ print(f" (prompt only works with: {compatible_datasets})")
151
+ continue
152
+
153
+ # Check prompt-dataset compatibility (dataset side)
154
+ compatible_prompts = dataset.get_compatible_prompts()
155
+ if compatible_prompts is not None and prompt_name not in compatible_prompts:
156
+ print(f" SKIPPED: {dataset_name} is not compatible with {prompt_name}")
157
+ print(f" (dataset only works with: {compatible_prompts})")
158
+ continue
159
+
160
+ # Setup individual run logger
161
+ run_name = f"{exp_name}_{dataset_name}_{prompt_name}"
162
+ run_dir = base_output_dir / run_name
163
+ run_dir.mkdir(exist_ok=True)
164
+
165
+ logger = ExperimentLogger(str(run_dir))
166
+ logger.log_config(cfg)
167
+
168
+ # Run Experiment
169
+ num_samples = OmegaConf.select(cfg, "experiment.num_samples", default=None)
170
+ result = experiment.run(
171
+ backend=backend,
172
+ dataset=dataset,
173
+ prompt_strategy=prompt_strategy,
174
+ logger=logger,
175
+ **(dict(num_samples=num_samples) if num_samples is not None else {}),
176
+ )
177
+
178
+ # Save results
179
+ results_path = logger.save_results(result)
180
+ print(f"Results saved: {results_path}")
181
+
182
+ # Basic metrics print
183
+ metrics_str = ", ".join(
184
+ [
185
+ f"{k}={v:.2f}" if isinstance(v, float) else f"{k}={v}"
186
+ for k, v in result.metrics.items()
187
+ ]
188
+ )
189
+ print(f"Metrics: {metrics_str}")
190
+
191
+ except Exception as e:
192
+ print(f"ERROR in job {job_idx}: {e}")
193
+ import traceback
194
+
195
+ traceback.print_exc()
196
+
197
+ print("\n" + "=" * 60)
198
+ print("All jobs completed.")
199
+ print(f"Results stored in: {base_output_dir}")
200
+ print("=" * 60)
201
+
202
+
203
+ if __name__ == "__main__":
204
+ main()
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: cotlab
3
+ Version: 0.8.0
4
+ Summary: CoTLab - Chain of Thought Research Toolkit for LLMs
5
+ Project-URL: Repository, https://github.com/huseyincavusbi/CoTLab
6
+ Project-URL: Documentation, https://huseyincavusbi.github.io/CoTLab
7
+ Project-URL: Issues, https://github.com/huseyincavusbi/CoTLab/issues
8
+ Author-email: Huseyin Cavus <huseyincavus@proton.me>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: chain-of-thought,interpretability,llm,mechanistic-interpretability,medical-ai,probing
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: accelerate>=0.27.0
22
+ Requires-Dist: bitsandbytes>=0.46.1
23
+ Requires-Dist: click>=8.1.0
24
+ Requires-Dist: huggingface-hub>=0.20.0
25
+ Requires-Dist: hydra-core>=1.3.0
26
+ Requires-Dist: numpy>=1.24.0
27
+ Requires-Dist: omegaconf>=2.3.0
28
+ Requires-Dist: pandas>=2.0.0
29
+ Requires-Dist: protobuf>=3.20.0
30
+ Requires-Dist: pyarrow>=14.0.0
31
+ Requires-Dist: python-dotenv>=1.0.0
32
+ Requires-Dist: safetensors>=0.4.0
33
+ Requires-Dist: scikit-learn>=1.3.0
34
+ Requires-Dist: torch>=2.1.0
35
+ Requires-Dist: tqdm>=4.65.0
36
+ Requires-Dist: transformers<5,>=4.56.0
37
+ Requires-Dist: xmltodict>=0.13.0
38
+ Provides-Extra: dev
39
+ Requires-Dist: ipython>=8.0.0; extra == 'dev'
40
+ Requires-Dist: jupyter>=1.0.0; extra == 'dev'
41
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
42
+ Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
43
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
44
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
45
+ Requires-Dist: ruff>=0.4.4; extra == 'dev'
46
+ Provides-Extra: vllm
47
+ Requires-Dist: vllm>=0.6.0; extra == 'vllm'
48
+ Description-Content-Type: text/markdown
49
+
50
+ # CoTLab
51
+
52
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/huseyincavusbi/CoTLab)
53
+
54
+ A research toolkit for investigating Chain of Thought (CoT) reasoning, faithfulness, and mechanistic interpretability in Large Language Models.
55
+
56
+ ## Features
57
+
58
+ - Experiments for CoT faithfulness, patching, logit‑lens, steering, and probing
59
+ - Diverse prompt strategies (CoT, direct, adversarial, contrarian, few‑shot, etc.)
60
+ - Configurable models, datasets, and backends (vLLM + Transformers)
61
+ - Auto‑detect layers/heads at runtime
62
+ - Hydra config for easy composition and multiruns
63
+ ----
64
+ - Project overview (DeepWiki): https://deepwiki.com/huseyincavusbi/CoTLab/1-overview
65
+ - Official docs: https://huseyincavusbi.github.io/CoTLab/
66
+ ---
67
+ ## Installation
68
+
69
+ ```bash
70
+ git clone https://github.com/huseyincavusbi/CoTLab.git
71
+ cd CoTLab
72
+ uv venv cotlab --python 3.11
73
+ source cotlab/bin/activate
74
+ uv pip install -e ".[dev]"
75
+
76
+ # GPU Setup:
77
+ # NVIDIA: uv pip install vllm
78
+ # AMD ROCm: ./scripts/cotlab-rocm.sh (uses Docker)
79
+
80
+ # AMD ROCm (Transformers backend): install ROCm PyTorch wheels
81
+ # uv pip install --reinstall --index-url https://download.pytorch.org/whl/rocm6.4 torch torchvision torchaudio
82
+
83
+ # Apple Silicon: requires Python 3.12 and vllm-metal plugin
84
+ # See docs/getting-started/installation.md for Metal setup instructions
85
+ ```
86
+
87
+ See [Installation Docs](docs/getting-started/installation.md) for detailed GPU setup.
88
+
89
+ ## Backend Compatibility
90
+
91
+ CoTLab supports two inference backends with different strengths:
92
+
93
+ ### 1. vLLM Backend (High Performance)
94
+ Best for large-scale generation experiments.
95
+ - **Supported Experiments**: `cot_faithfulness`, `radiology`
96
+ - **Supported Models**: All text-only models (e.g., `gemma_270m`, `medgemma_27b_text_it`)
97
+ - **Limitation**: Does NOT support activation patching or internal state access.
98
+ - **Note**: Gemma 3 multimodal models (e.g., `medgemma_4b_it`) are currently incompatible with vLLM 0.12.0 due to architecture detection issues. Use `transformers` backend for these.
99
+
100
+ ### 2. Transformers Backend (Full Access)
101
+ Best for mechanistic interpretability and activation patching.
102
+ - **Supported Experiments**: ALL experiments.
103
+ - **Supported Models**: ALL models.
104
+ - **Limitation**: Slower.
105
+
106
+ To switch backends:
107
+ ```bash
108
+ # Use vLLM (fast generation)
109
+ python -m cotlab.main backend=vllm ...
110
+
111
+ # Use Transformers (activation access)
112
+ python -m cotlab.main backend=transformers ...
113
+ ```
114
+
115
+ ## Quick Start
116
+
117
+ ```bash
118
+ # Run logit lens on MedGemma
119
+ python -m cotlab.main experiment=logit_lens model=medgemma_4b
120
+
121
+ # Find sycophancy heads
122
+ python -m cotlab.main experiment=sycophancy_heads model=medgemma_4b
123
+
124
+ # Test CoT ablation on pediatrics dataset
125
+ python -m cotlab.main experiment=cot_ablation dataset=pediatrics
126
+
127
+ # Compare prompt strategies
128
+ python -m cotlab.main -m prompt=chain_of_thought,direct_answer,sycophantic
129
+ ```
130
+
131
+ ## Supported Models
132
+
133
+ CoTLab ships config files for some models, but in principle it supports any model
134
+ that the selected backend can load. Mechanistic experiments can still fail for
135
+ models with unusual architectures.
136
+
137
+ You can add a model config file for more control over hyperparameters, but you
138
+ can also run any experiment by passing a Hugging Face model name directly.
139
+
140
+ ```bash
141
+ # Use a built-in model config
142
+ python -m cotlab.main model=medgemma_4b
143
+
144
+ # Or pass any HF model name directly
145
+ python -m cotlab.main model.name=google/gemma-3-270m
146
+ ```
147
+
148
+ If you prefer, you can pre-create model configs with `cotlab-template`, but
149
+ this is optional because CoTLab can auto-generate model configs when running
150
+ with `model=org/repo-id`.
151
+
152
+ ## Configuration
153
+
154
+ All configs auto-detect layers/heads at runtime. Override via CLI:
155
+
156
+ ```bash
157
+ python -m cotlab.main \
158
+ model=medgemma_4b \
159
+ dataset=pediatrics \
160
+ prompt=chain_of_thought \
161
+ experiment.top_k=10
162
+ ```
163
+
164
+ ## License
165
+
166
+ MIT
@@ -0,0 +1,65 @@
1
+ cotlab/__init__.py,sha256=y--3rgqeSRBO5vMnx92B_HaS8QIzNlb_6sC5XDE29gs,73
2
+ cotlab/analyse_experiments.py,sha256=1fWqdBKRTgkJO1gREuXvQgO-tYErcEWqLS-TWdQzCO4,12790
3
+ cotlab/cli.py,sha256=b1jLJXmoAlrsz2jL5koMH4eIREXihDOROAitylc3REo,2431
4
+ cotlab/main.py,sha256=vXVHgwqccd0dy1M5upvT9oZciXHkK0kcg58hoinn0gY,11169
5
+ cotlab/runner.py,sha256=Dg5eT4xzsIYNqmJkZ4dY_307YbON_1gCGfF7lbCile4,7898
6
+ cotlab/analysis/__init__.py,sha256=tHoElnfh3Q4nw0J9pQltjhXuxpAfF1vkqW59WRotCY4,263
7
+ cotlab/analysis/cot_parser.py,sha256=ly4pmjWWZZATJeMwvX7XDagSEACA2qnPt8Y0LRQRHX0,7008
8
+ cotlab/analysis/faithfulness_metrics.py,sha256=MpdRBvP0UglQa6poyY4RTi0XtU98I7spbdD9yppvsek,6261
9
+ cotlab/backends/__init__.py,sha256=tPcnXB7TC6HWSgjmch9Dms_d1txe_dyithqv6C99Gy0,370
10
+ cotlab/backends/base.py,sha256=Issi9EJi0HeVfRhaPtQ4hbjOXtJKDAdxbeAp_e2ljXw,1973
11
+ cotlab/backends/transformers_backend.py,sha256=_rQzbhW2rmqHJVOSTm6uzjMtBm14qFDe1zt_UtTbkfU,11377
12
+ cotlab/backends/vllm_backend.py,sha256=PRlD_KrcFciU94fo0GcWgvZfWIj7OxZcoGwHaLmCHro,7374
13
+ cotlab/core/__init__.py,sha256=39XD_yL9RGoNAY6hn_jIXbU8hIhbsvT6P_tAcLl0fbg,669
14
+ cotlab/core/base.py,sha256=TpGy7DnQPTn4pwJYnF0_4mRdjxT3iaz3b4TM7hK6jFU,24254
15
+ cotlab/core/config.py,sha256=_GP5JOPDNQmCsTZc6ELA86PspxhrDRtqCUSFQKUHios,2149
16
+ cotlab/core/registry.py,sha256=Deg-O9cY5nsAfUZ8xxO8kH6tiSCK3TLEaZ4KOOdtXME,1618
17
+ cotlab/datasets/__init__.py,sha256=wcEZZDOYaPdqE0RRXfeaQIzRzMfC9iExmWn0jGkoNAE,932
18
+ cotlab/datasets/loaders.py,sha256=Wp854_UM52tXjYYU0ZTvBgNWQhdRp-Srcj46O5c8tlo,61236
19
+ cotlab/experiment/__init__.py,sha256=aPnVcJ8pkjwQ1m1ZOgqVnIPEun57W80O9-lU_tXioWU,11323
20
+ cotlab/experiments/__init__.py,sha256=72CoKW05xzr6NZhpDYVF6DWO7XPN3v7ARNEoOINZIBU,1737
21
+ cotlab/experiments/activation_compare.py,sha256=DjNOAySg5boOWsgfnvue_rmINq-VOGdVJfIYKSCRb2s,11736
22
+ cotlab/experiments/activation_patching.py,sha256=Pwv4nTVvtu8qCufWnJdSkexPR_LSWhdFLwwStcmMemQ,44682
23
+ cotlab/experiments/attention_analysis.py,sha256=kPj_MoVqnosR1jW-z32B2Ugu7vcP4GJ9w7dTd9t9GUM,40220
24
+ cotlab/experiments/classification.py,sha256=VzoS0ePmdwEJiU44lxm9LD7vwTgA0k2UABA-oJ1a2vc,8634
25
+ cotlab/experiments/composite_shift_detector.py,sha256=AM6Nb0pFvyE8wSn8INs0WmYTxMTJl0zAWJIEKM0dbTA,21326
26
+ cotlab/experiments/cot_ablation.py,sha256=GG5y4qSCSp4Kyoqvs9_UYkNLAIUwPQObGBkHa0PK7fI,10297
27
+ cotlab/experiments/cot_faithfulness.py,sha256=HXmE6vX4BYcDf6kzCRA0VhVwBbiupyOSDYkfmfrqxHk,7117
28
+ cotlab/experiments/cot_heads.py,sha256=9il1Ebll18_id30OGqBk76bxp4uzaEjo4wP62cN6UYs,7555
29
+ cotlab/experiments/full_layer_cot.py,sha256=Xoq13GubsUptIKXx6OmKkIw7NDt0h8bJGlvIXbuMG8c,8194
30
+ cotlab/experiments/full_layer_patching.py,sha256=H42W_z7k0ytTp-2MR1fieLT-YA7N-0543InVAtPu1Fs,8344
31
+ cotlab/experiments/h_neuron_analysis.py,sha256=kltUXGtgb42m_Ml-cm918Ae_AZJBLgRmidjofaGsqLQ,29465
32
+ cotlab/experiments/logit_lens.py,sha256=FE7-u3n1JPiNZONtFss2ZeTpOCio7Qe1yXIHQQ0GyZw,17654
33
+ cotlab/experiments/multi_head_cot.py,sha256=v5pPKS0c57Vk5tWp1wl5X_0Ghcrycedwb-k1A2TVRvY,7802
34
+ cotlab/experiments/multi_head_patching.py,sha256=-8_1lt64lUyNs74lvgZ7_4yabAl90akyg1ltJ5UKjVU,8478
35
+ cotlab/experiments/probing_classifier.py,sha256=TYqjVXpk9ZRJfLZ-R4BJnEPPM5mEA7f6APe0RjGt5Bk,14835
36
+ cotlab/experiments/residual_norm_ood.py,sha256=oWiElDgIG7TkYxzIo9etRkMHtTSwOI6gJ8eTsi00_po,16384
37
+ cotlab/experiments/sae_feature_analysis.py,sha256=maY6wQsMTy_E4JvFLfNr3LMX1DvT7cCtml4fvATm6I4,27976
38
+ cotlab/experiments/steering_vectors.py,sha256=lVRT0FyvzpeEMJg_4LlsFNQvNUNVW8AjANwDr7LiKqI,8800
39
+ cotlab/experiments/sycophancy_heads.py,sha256=5NmeAk3U3sr4tR5XsAjHZa_TyBL8sGmPTwwnqPk-NHI,8152
40
+ cotlab/logging/__init__.py,sha256=6d0OSqKkzpfHdKlfnKVQqRBkCziXqnX2PecNtzLlmZI,97
41
+ cotlab/logging/json_logger.py,sha256=ERDTa6oV-ArKKO26tQexnG077dgLH71uQjt_EjArHDg,5015
42
+ cotlab/patching/__init__.py,sha256=mXvfO_hJ6dygEeGW-xcouUDpc79DP48rBBDS25ETMrc,542
43
+ cotlab/patching/cache.py,sha256=o402BKEKuNoAz6NKxuo06H3iO65V7vz0HIl0-PozFxI,4547
44
+ cotlab/patching/hooks.py,sha256=Q_Pz78vwKf846adbzJTO1SBWIQQeSCdG7EbpmZOtB3k,20951
45
+ cotlab/patching/interventions.py,sha256=g4y1ni5MWTwxDqHOtT-awwCFSBNh85Laz1PczOBwV4o,2678
46
+ cotlab/patching/patcher.py,sha256=nJqkx8erhP4Npj4iZRsIxc42T8zwtekj4X8t5BbNADU,15697
47
+ cotlab/patching/sae.py,sha256=7XvR8LjQY9MYVUJkZLgGEn38_3qnmp0Y3uWCSQnXdwY,6847
48
+ cotlab/prompts/__init__.py,sha256=axogCx7Ce1upJC53MB5xms1zM7cPMIDIljsDVun6MjM,1278
49
+ cotlab/prompts/cardiology.py,sha256=-fGvhY56q2QXMdLW7QEPDymQUbpZJXjbfHuyWmAlufQ,15698
50
+ cotlab/prompts/histopathology.py,sha256=DfQmljd4Mig2G5loGqiwaGU0tHZw3NIaSn9zCcyPvck,9107
51
+ cotlab/prompts/length_matched_strategies.py,sha256=fnGmWy8uOkSlyWTakY0jJ_9nKg9GCCsSAiDZsibVwsY,4883
52
+ cotlab/prompts/mcq.py,sha256=tkLM8ac8L93mOBQKIfpmBXOSszrhzvvXkLZ4E33p4Mg,8279
53
+ cotlab/prompts/neurology.py,sha256=_h9cozOCHDLaG4n3RVLS3Re305zAV7rTPTtNXnONA5o,14782
54
+ cotlab/prompts/oncology.py,sha256=OmBWSOUJTwVXDPD998vV440EoYbeWCbtzDthiBXXR1s,14807
55
+ cotlab/prompts/plab.py,sha256=w1-xluqTmzjXHgnhW1XNU7MAhab8vQuiKichwIogwM0,5894
56
+ cotlab/prompts/pubhealthbench.py,sha256=XaGYMrjUfSMrfohK1xXegxcog1oeQwSS6O-3-0nSia4,3011
57
+ cotlab/prompts/pubmedqa.py,sha256=S7Ru94gAtl7dmSCzk5IwJxXcMemHahyPablRRFS0zIg,6983
58
+ cotlab/prompts/radiology.py,sha256=KLHeuD2ayWMOvNDJ2pUy_1iPLWjNBDDscCDPRVuS1W8,18007
59
+ cotlab/prompts/strategies.py,sha256=TdJNPbJqPeL9l9y2Q8wQMBgWAUKIJUokzyGcWoVKu7U,31295
60
+ cotlab/prompts/tcga.py,sha256=lieql237kCaSoa-hyvOfpVNmmoXYGfK1KnwYKNZhtPQ,5633
61
+ cotlab-0.8.0.dist-info/METADATA,sha256=NisTk2jRQ9wMO5d3DG_pOL0j7BqSThKPBFhCM-NDtL0,5751
62
+ cotlab-0.8.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
63
+ cotlab-0.8.0.dist-info/entry_points.txt,sha256=GHChdvu9KbueSjPgUwDWZOvFTmUxKJnhPY1SC0pWRQE,77
64
+ cotlab-0.8.0.dist-info/licenses/LICENSE,sha256=DKx8N2g6-am9PRrJHYm35-nlhNA-3tcdr5IHRj_1HyA,1078
65
+ cotlab-0.8.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cotlab = cotlab.main:main
3
+ cotlab-template = cotlab.cli:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Hüseyin Çavuş
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.