环境:Mac mini M4 + 16GB,uv 管理 Python 包,VSCode 开发 外接盘:/Volumes/CyberDisk,大文件/模型/开发目录统一放这里


1. 环境激活

venv 路径:~/model-research

source ~/model-research/bin/activate

VSCode 中:按 Cmd+Shift+PPython: Select Interpreter → 选 ~/model-research/bin/python


2. 工具链速查

用途什么时候用
torch张量运算 + MPS GPU 加速所有操作的基础
transformers加载 HuggingFace 模型,查看权重入门第一步,理解模型结构
nnsightHook 进 Transformer 前向传播,读/改激活值Abliteration、激活干预
mlx-lmApple M 系列最快推理框架快速验证、跑 benchmark
jupyter交互式实验一步一步看张量变化
bitsandbytes4-bit/8-bit 量化加载省显存,16GB 跑大模型必备
safetensors安全加载权重文件transformers 默认用它
accelerate多设备自动分配device_map=“auto” 时用到

3. 基础代码示例

3.1 加载模型,看权重长什么样

from transformers import AutoModelForCausalLM
import torch

# 选一个小模型先练手,比如 0.5B 或 1.5B
MODEL = "Qwen/Qwen2.5-1.5B-Instruct"

model = AutoModelForCausalLM.from_pretrained(
    MODEL,
    torch_dtype=torch.float16,
    device_map="mps"  # M4 GPU
)

# 打印所有层的名字和 shape
for name, param in model.named_parameters():
    print(f"{name}: {param.shape}")

效果:你会看到 model.layers.0.self_attn.q_proj.weight: torch.Size([1536, 1536]) 这种输出,理解模型有多少层、每层多大。


3.2 用 nnsight 做激活干预

from nnsight import LanguageModel
import torch

# nnsight 会自动下载模型,也可以指定本地路径
model = LanguageModel("Qwen/Qwen2.5-1.5B-Instruct", device_map="mps")

prompt = "The capital of France is"

with model.trace(prompt) as tracer:
    # 在第 5 层 transformer 的输出上动手脚
    layer_5_output = model.model.layers[5].output
    
    # 打印这层输出的 shape
    print(f"Layer 5 output shape: {layer_5_output.shape}")
    
    # 把某个维度归零(示例:干扰模型)
    # layer_5_output[:, :, 0] = 0

# 干预后正常生成
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct")
inputs = tokenizer(prompt, return_tensors="pt").to("mps")
outputs = model.generate(inputs.input_ids, max_new_tokens=10)
print(tokenizer.decode(outputs[0]))

效果:你能像 gdb 断点一样,停在模型第 N 层,查看/修改那层的激活值。


3.3 mlx-lm 最快推理(M4 最优)

from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Qwen2.5-7B-Instruct-4bit")

response = generate(
    model,
    tokenizer,
    prompt="你好,介绍一下自己",
    verbose=True,      # 实时打印 token
    max_tokens=100
)
print(response)

效果:比 transformers 快 20-30%,适合快速验证想法。注意模型要选 mlx-community 下的格式。


3.4 4-bit 量化加载(省内存)

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.float16
)

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B-Instruct",
    quantization_config=bnb_config,
    device_map="mps"
)

效果:7B 模型从 14GB 降到约 4GB,16GB Mac 能轻松跑。


4. 模型缓存迁移(已完成)

transformers 默认把模型下在 ~/.cache/huggingface/,已迁移到外接盘。

# 迁移命令(已执行)
mv ~/.cache/huggingface /Volumes/CyberDisk/.cache/huggingface
ln -s /Volumes/CyberDisk/.cache/huggingface ~/.cache/huggingface

以后所有 from_pretrained 下载的模型都自动存到外接盘。


5. Ollama vs 研究工具

Ollamatransformers + nnsight
定位快速聊天 / API 服务拆引擎盖做研究
能看到权重吗❌ 不能✅ 能
能改激活值吗❌ 不能✅ 能
启动速度快,一键跑慢,要下载原始权重
日常提问ollama run 就聊要写代码

工作流

  1. 想快速试新模型 → ollama pull + ollama run
  2. 确认可行后 → transformers 下载原始权重做深入研究
  3. 研究完想验证效果 → 改完的模型转成 GGUF → Ollama 加载测试

6. 推荐研究路径

按这个顺序走,别跳:

  1. 看权重(3.1)→ 理解模型有几层、每层多大
  2. 跑推理(3.3 或 Ollama)→ 确认模型正常说话
  3. 问拒绝问题,用 nnsight 定位(3.2)→ 找到拒绝信号最强的层
  4. 做 Abliteration → 算出 refusal vector,从激活值里抹掉
  5. 验证 → 再问同一个问题,看还拒不拒绝

7. 常见问题

Q: 报错 MPS backend out of memory

A: 模型太大,换 4-bit 量化(3.4)或换更小的模型(1.5B / 3B)。

Q: nnsight 下载模型特别慢

A: 先手动用 huggingface-cli download Qwen/Qwen2.5-1.5B-Instruct 下到 cache,nnsight 会直接用本地缓存。

Q: VSCode 里选了解释器但 import 报错

A: 确认你打开了正确的文件夹(File → Open Folder),且选的是 ~/model-research/bin/python。有时候 VSCode 会选到系统 Python。

Q: 怎么知道 MPS 有没有加速?

A: 看推理时的 token/s。如果用 CPU 只有 2-3 token/s,用 MPS 应该有 15-30 token/s。


8. 参考资料