环境:Mac mini M4 + 16GB,uv 管理 Python 包,VSCode 开发 外接盘:
/Volumes/CyberDisk,大文件/模型/开发目录统一放这里
1. 环境激活
venv 路径:~/model-research
source ~/model-research/bin/activate
VSCode 中:按 Cmd+Shift+P → Python: Select Interpreter → 选 ~/model-research/bin/python
2. 工具链速查
| 包 | 用途 | 什么时候用 |
|---|---|---|
torch | 张量运算 + MPS GPU 加速 | 所有操作的基础 |
transformers | 加载 HuggingFace 模型,查看权重 | 入门第一步,理解模型结构 |
nnsight | Hook 进 Transformer 前向传播,读/改激活值 | Abliteration、激活干预 |
mlx-lm | Apple M 系列最快推理框架 | 快速验证、跑 benchmark |
jupyter | 交互式实验 | 一步一步看张量变化 |
bitsandbytes | 4-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 研究工具
| Ollama | transformers + nnsight | |
|---|---|---|
| 定位 | 快速聊天 / API 服务 | 拆引擎盖做研究 |
| 能看到权重吗 | ❌ 不能 | ✅ 能 |
| 能改激活值吗 | ❌ 不能 | ✅ 能 |
| 启动速度 | 快,一键跑 | 慢,要下载原始权重 |
| 日常提问 | ollama run 就聊 | 要写代码 |
工作流:
- 想快速试新模型 →
ollama pull+ollama run - 确认可行后 → transformers 下载原始权重做深入研究
- 研究完想验证效果 → 改完的模型转成 GGUF → Ollama 加载测试
6. 推荐研究路径
按这个顺序走,别跳:
- 看权重(3.1)→ 理解模型有几层、每层多大
- 跑推理(3.3 或 Ollama)→ 确认模型正常说话
- 问拒绝问题,用 nnsight 定位(3.2)→ 找到拒绝信号最强的层
- 做 Abliteration → 算出 refusal vector,从激活值里抹掉
- 验证 → 再问同一个问题,看还拒不拒绝
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。