This model learns a sparse dictionary of features from the internal representations of two language models. By comparing which features activate for which model, we can identify:
1import torch
2from huggingface_hub import hf_hub_download
3
4# Download model files
5repo_id = "antebe1/dfc-D8k-excl10-k45-l9"
6for fname in ["model.pt", "config.json", "dfc.py"]:
7 hf_hub_download(repo_id=repo_id, filename=fname, local_dir="./model")
8
9# Load the crosscoder
10import sys; sys.path.insert(0, "./model")
11from dfc import DFCCrossCoder
12
13dfc = DFCCrossCoder.load("./model", device="cuda")
14print(f"Loaded: dict_size={dfc.dict_size}, k={dfc.k}")
1from transformers import AutoModelForCausalLM, AutoTokenizer
2
3# Load both models
4model_a = AutoModelForCausalLM.from_pretrained("chengq9/ToolRL-Qwen2.5-3B", device_map="cuda:0")
5model_b = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-3B", device_map="cuda:1")
6tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-3B")
7
8# Get activations from layer 9
9# NOTE: hidden_states[0] = embeddings, hidden_states[i] = output of layer i-1
10# so layer 9 activations are at index 9+1
11text = "Use the search tool to find recent papers on RLHF"
12inputs = tokenizer(text, return_tensors="pt")
13
14with torch.no_grad():
15 out_a = model_a(**inputs.to("cuda:0"), output_hidden_states=True)
16 out_b = model_b(**inputs.to("cuda:1"), output_hidden_states=True)
17 act_a = out_a.hidden_states[9 + 1][:, -1, :] # last token, layer 9
18 act_b = out_b.hidden_states[9 + 1][:, -1, :]
19
20# Stack and encode
21activations = torch.stack([act_a.cpu(), act_b.cpu()], dim=1) # (1, 2, 2048)
22features = dfc.encode(activations.to(dfc.W_enc.device))
23
24print(f"Active features: {(features > 0).sum().item()} / {dfc.dict_size}")
1stats = dfc.feature_stats(features)
2print(f"L0 total: {stats['l0_total']:.1f}")
3print(f"L0 A-excl: {stats['l0_a_excl']:.1f}")
4print(f"L0 B-excl: {stats['l0_b_excl']:.1f}")
5print(f"L0 shared: {stats['l0_shared']:.1f}")
6
7# Check reconstruction quality
8recon, feats = dfc(activations.to(dfc.W_enc.device))
9mse = torch.nn.functional.mse_loss(recon.cpu(), activations)
10print(f"Reconstruction MSE: {mse.item():.6f}")
This model is one of 10 models trained across different layers (1, 5, 9, 14, 18, 20, 24, 28, 32, 36) with fixed hyperparameters: dict_size=8192, k=45, excl=10%, excl_sparsity=1e-3.
1@misc{dfc-D8k-excl10-k45-l9,
2 title={DFC CrossCoder: ToolRL vs Base Qwen2.5-3B},
3 author={Andre Shportko},
4 year={2026},
5 url={https://huggingface.co/antebe1/dfc-D8k-excl10-k45-l9}
6}