sarel's picture
Add scripts/push_to_hf.py
eaac9b3 verified
Raw
History Blame Contribute Delete
4.47 kB
#!/usr/bin/env python3
"""
Push all trained SAE and transcoder checkpoints to HuggingFace Hub.
Uses HUGGING_FACE_HUB_TOKEN from .env file.
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from dotenv import load_dotenv
load_dotenv(Path(__file__).resolve().parent.parent / ".env", override=False)
from huggingface_hub import HfApi, create_repo
CHECKPOINT_DIR = Path("circuit_tracer/data/checkpoints")
REPO_ID = "sarel/creditscope-circuit-models"
def main():
token = os.environ.get("HUGGING_FACE_HUB_TOKEN") or os.environ.get("HF_TOKEN")
if not token:
print("ERROR: No HuggingFace token found. Set HUGGING_FACE_HUB_TOKEN or HF_TOKEN.")
sys.exit(1)
api = HfApi(token=token)
# Create repo if it doesn't exist
try:
create_repo(REPO_ID, token=token, repo_type="model", exist_ok=True)
print(f"Repo ready: {REPO_ID}")
except Exception as e:
print(f"Repo creation: {e}")
# Upload all .pt checkpoints
pt_files = sorted(CHECKPOINT_DIR.glob("*.pt"))
print(f"Found {len(pt_files)} checkpoint files to upload")
# Upload registry-compatible files (sae_lN.pt and tc_lN.pt)
registry_files = [f for f in pt_files if f.name.startswith(("sae_l", "tc_l"))]
print(f"Uploading {len(registry_files)} registry-compatible checkpoints...")
for f in registry_files:
size_mb = f.stat().st_size / 1024 / 1024
print(f" Uploading {f.name} ({size_mb:.1f} MB)...", end=" ", flush=True)
try:
api.upload_file(
path_or_fileobj=str(f),
path_in_repo=f"checkpoints/{f.name}",
repo_id=REPO_ID,
repo_type="model",
)
print("OK")
except Exception as e:
print(f"FAILED: {e}")
# Also upload best/final variants
extra_files = [f for f in pt_files if f not in registry_files]
if extra_files:
print(f"\nUploading {len(extra_files)} additional checkpoints (best/final)...")
for f in extra_files:
size_mb = f.stat().st_size / 1024 / 1024
print(f" Uploading {f.name} ({size_mb:.1f} MB)...", end=" ", flush=True)
try:
api.upload_file(
path_or_fileobj=str(f),
path_in_repo=f"checkpoints/{f.name}",
repo_id=REPO_ID,
repo_type="model",
)
print("OK")
except Exception as e:
print(f"FAILED: {e}")
# Create a model card
model_card = """---
tags:
- sparse-autoencoder
- transcoder
- circuit-tracing
- mechanistic-interpretability
- qwen3.5
license: apache-2.0
---
# CreditScope Circuit Tracing Models
Sparse Autoencoders (SAEs) and MoE Transcoders trained on **Qwen3.5-35B-A3B-FP8** for mechanistic interpretability / circuit tracing.
## Models
### SAEs (Sparse Autoencoders)
- **Architecture**: JumpReLU, d_model=2048 → 16384 features (8x expansion)
- **Layers**: 0, 5, 10, 15, 20, 25, 30, 35, 39
- **Training**: 500 diverse prompts, ~5000 tokens, 2000-15000 steps per model
- **Files**: `sae_l{N}.pt`
### Transcoders (MoE Transcoders)
- **Architecture**: ReLU encoder/decoder, d_model=2048 → 16384 features
- **Layers**: 0, 5, 10, 15, 20, 25, 30, 35, 39
- **Training**: Maps pre-MoE residual to post-MoE output (learns MoE residual contribution)
- **Files**: `tc_l{N}.pt`
## Usage
```python
from circuit_tracer.saes.sparse_autoencoder import SparseAutoencoder
from circuit_tracer.transcoders.moe_transcoder import MoETranscoder
# Load SAE
sae = SparseAutoencoder.load("checkpoints/sae_l0.pt")
# Load transcoder
tc = MoETranscoder.load("checkpoints/tc_l0.pt")
```
## Training Details
- **Base model**: Qwen/Qwen3.5-35B-A3B-FP8
- **Activation collection**: Direct model forward hooks on 500 diverse prompts
- **SAE optimizer**: Adam, lr=3e-4, cosine annealing
- **TC optimizer**: Adam, lr=1e-3, cosine annealing
"""
try:
api.upload_file(
path_or_fileobj=model_card.encode(),
path_in_repo="README.md",
repo_id=REPO_ID,
repo_type="model",
)
print("\nModel card uploaded")
except Exception as e:
print(f"Model card upload failed: {e}")
print(f"\nDone! View at: https://huggingface.co/{REPO_ID}")
if __name__ == "__main__":
main()