Linear Probing#

This notebook demonstrates how to use Linear Probing to train classifiers on model representations.

Setup#

[1]:
import importlib.util

DEV = True

if importlib.util.find_spec("google.colab") is not None:
    MODE = "colab-dev" if DEV else "colab"
else:
    MODE = "local"
[2]:
if MODE == "colab":
    %pip install -q tdhook
elif MODE == "colab-dev":
    !rm -rf tdhook
    !git clone https://github.com/Xmaster6y/tdhook -b main
    %pip install -q ./tdhook

Usage#

Load model and prepare data

[3]:
from transformers import AutoTokenizer, AutoModelForCausalLM
from tensordict import TensorDict
from datasets import load_dataset
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import torch

from tdhook.latent.probing import Probing, ProbeManager
[4]:
model = AutoModelForCausalLM.from_pretrained("gpt2")
model.eval()
tokenizer = AutoTokenizer.from_pretrained("gpt2")
tokenizer.pad_token = tokenizer.eos_token
[5]:
dataset = load_dataset("scikit-learn/imdb", split="train")

num_train = 100
num_test = 10

shuffled_dataset = dataset.shuffle(seed=42)
train_data = shuffled_dataset.select(range(num_train))
test_data = shuffled_dataset.select(range(num_train, num_train + num_test))

train_texts = [item["review"] for item in train_data]
train_labels = [1 if item["sentiment"] == "positive" else 0 for item in train_data]

test_texts = [item["review"] for item in test_data]
test_labels = [1 if item["sentiment"] == "positive" else 0 for item in test_data]

train_encoded = [tokenizer.encode(text, max_length=512, truncation=True) for text in train_texts]
test_encoded = [tokenizer.encode(text, max_length=512, truncation=True) for text in test_texts]

max_len = max(len(seq) for seq in train_encoded + test_encoded)
pad_token_id = tokenizer.pad_token_id

train_input_ids = torch.tensor([seq + [pad_token_id] * (max_len - len(seq)) for seq in train_encoded])
test_input_ids = torch.tensor([seq + [pad_token_id] * (max_len - len(seq)) for seq in test_encoded])

Set up linear probing

[6]:
def compute_metrics(predictions, labels):
    return {"accuracy": accuracy_score(labels, predictions)}


probe_manager = ProbeManager(LogisticRegression, {}, compute_metrics)

Train probe on training data and evaluate on test data

[7]:
with Probing(
    "transformer.h.(0|5|10).mlp$", probe_manager.probe_factory, additional_keys=["labels", "step_type"]
).prepare(model, in_keys=["input_ids"], out_keys=["logits"]) as hooked_model:
    with torch.no_grad():
        train_td = TensorDict(
            {
                "input_ids": train_input_ids,
                "labels": torch.tensor(train_labels),
                "step_type": "fit",
            },
            batch_size=len(train_texts),
        )
        train_out = hooked_model(train_td)

        test_td = TensorDict(
            {
                "input_ids": test_input_ids,
                "labels": torch.tensor(test_labels),
                "step_type": "predict",
            },
            batch_size=len(test_texts),
        )
        test_out = hooked_model(test_td)

Display probe metrics

[8]:
print("Training metrics:")
for key, value in probe_manager.fit_metrics.items():
    print(f"  {key}: {value}")

print("\nTest metrics:")
for key, value in probe_manager.predict_metrics.items():
    print(f"  {key}: {value}")
Training metrics:
  transformer.h.0.mlp_fwd: {'accuracy': 1.0}
  transformer.h.5.mlp_fwd: {'accuracy': 1.0}
  transformer.h.10.mlp_fwd: {'accuracy': 1.0}

Test metrics:
  transformer.h.0.mlp_fwd: {'accuracy': 0.5}
  transformer.h.5.mlp_fwd: {'accuracy': 0.4}
  transformer.h.10.mlp_fwd: {'accuracy': 0.6}