Loading

【大模型Wiki】12 · Kaggle 搭建 ChatGLM(实操)

1、kaggle设置

在 Kaggle 上白嫖 GPU 跑大模型,是零成本入门本地/云端推理最快的路子。Kaggle 给每个账号提供 每周 30 小时的免费 GPU 额度(通常是 T4 或 P100,部分账号双卡),足够把 7B 级别模型完整跑通。但有几个前置开关必须打开,否则代码一跑就报"没有 GPU"。

1、登录kaggle

2、手机验证

不用手机验证没办法使用gpu资源

原理:手机验证是 Kaggle(Google 系)反滥用机制。未验证账号被禁止挂载 GPU Accelerator,且很多数据集下载也受限。用国内手机号通常能收到验证码,验证一次长期有效。

3、更换运行模式

image-20240429162803107

4、网络打开

image-20240429162832439

原理:Kaggle Notebook 默认不允许联网。而 pip install 装包、huggingface-cli / transformers 下载模型权重,全部需要访问外网。不打开 Internet 开关,所有下载都会超时失败。打开位置在 Notebook 编辑器右侧 "Session options → Internet" 或设置页。

1.1、开启 GPU 的完整步骤

  1. 进入 Kaggle → 右上角头像 → Settings → 完成 Phone verification(手机验证)。
  2. 新建或打开一个 Notebook。
  3. 右上角点 Session options(或齿轮) → Accelerator 选 GPU T4 ×2(最稳的双卡免费配置)。
  4. 同一面板打开 Internet 开关(务必)。
  5. 点 Run 启动会话,左下角出现 "GPU" 图标即成功。

验证 GPU 是否真的可用,先跑一行:

import torch
print(torch.cuda.is_available())          # 应为 True
print(torch.cuda.get_device_name(0))      # 如 'Tesla T4'
print(torch.cuda.memory_summary())        # 查看显存

如果 is_available() 返回 False,99% 是没开 GPU 或没开 Internet 导致 torch 装成了 CPU 版,回去检查 1.1 的步骤。

2、ChatGLM-6B环境搭建

拿到 GPU 后,第一步是拿到项目代码和依赖。下面给出在 Kaggle Notebook 里可直接粘贴执行的完整命令序列。

# 1) 克隆 ChatGLM-6B 官方仓库(含 cli_demo / web_demo / api.py)
!git clone https://github.com/THUDM/ChatGLM-6B.git
cd ChatGLM-6B
!pip install -r requirements.txt

逐条说明:

  • git clone 拉的是推理代码框架(Python 脚本 + 依赖清单),体积很小(几 MB),不含模型权重。
  • requirements.txt 里通常含 transformers、torch、sentencepiece、gradio、streamlit、icetk 等。Kaggle 已预装 torch,但 transformers 可能不是 ChatGLM-6B 所需的旧版本(该模型要求 transformers>=4.27,<4.30 这类较老区间),所以 pip install -r 会重装匹配版本。
  • 在 Kaggle 用 ! 前缀表示在 Notebook cell 里执行 shell 命令;cd 用 !cd 对后续 cell 不生效,应改用 %cd ChatGLM-6B 或在每条命令前带路径。

更稳妥的做法(Kaggle 推荐):

%cd ChatGLM-6B                       # 切换工作目录(对后续 cell 永久生效)
!pip install -r requirements.txt -q  # -q 安静模式,少刷屏
!pip install -q transformers==4.27.1 # 锁版本,避免新版不兼容老模型

2.1、模型权重从哪来

requirements.txt 只装依赖,模型权重需要单独下载。ChatGLM-6B 权重约 12GB,默认在代码里用 from_pretrained("THUDM/chatglm-6b") 时自动从 Hugging Face 拉取。在 Kaggle 上建议预下载以免重复拉取:

# 方式 A:用 transformers 自动缓存(首次 from_pretrained 会下,约 12GB,较慢)
# 方式 B:用 huggingface-cli 显式下载(可看进度、可断点续传)
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"   # Kaggle 机房连 HF 有时慢,挂镜像
!huggingface-cli download THUDM/chatglm-6b --local-dir THUDM/chatglm-6b

镜像说明:HF_ENDPOINT=https://hf-mirror.com 是国内可用的 Hugging Face 镜像,下载速度比直连快很多。Kaggle 虽在国外机房,但 HF 官方源偶尔限速,挂镜像更稳。

3、运行chatglm-6b

环境就绪后,加载模型并做一次对话,验证整条链路通了。

from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).half().cuda()
model = model.eval()
response, history = model.chat(tokenizer, "你好", history=[])
print(response)

回答

你好👋!我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。

逐行原理:

  • trust_remote_code=True:ChatGLM 在 modeling_chatglm.py 里自定义了模型结构,必须允许执行远程代码才能加载(仅对可信仓库开启)。
  • .half():把权重转成 FP16(半精度),12GB 权重压到约 6GB,正好塞进 T4 的 16GB 显存。不转 .half() 用 FP32 会爆显存。
  • .cuda():把模型搬到 GPU 显存。Kaggle 免费 T4 单卡约 15GB 可用,FP16 的 6B 模型 + KV Cache 够用。
  • model.eval():切到推理模式(关闭 dropout 等训练层),保证输出确定、省显存。
  • model.chat(...) 是 ChatGLM 的对话封装,返回 (回复文本, 更新后的历史)。history=[] 表示全新对话。

3.1、验证部署成功的标准

满足以下全部条件才算跑通:

  1. cuda.is_available() 为 True(确认在 GPU 上)。
  2. from_pretrained 进度条走完,无 OOM。
  3. 能打印出正常的中文回复(如上"你好👋..."),而非乱码或空串。
  4. 第二次带 history 提问,模型能"记得"前文(多轮记忆生效)。
# 多轮验证
resp2, history = model.chat(tokenizer, "你知道刚才我们聊了什么吗?", history=history)
print(resp2)   # 应体现它记得上一句"你好"

3.2、失败场景与解决

现象 原因 解决
CUDA out of memory 没 .half() 或显存不够 加 .half();或换 INT4 量化版 chatglm-6b-int4
ModuleNotFoundError: icetk 依赖没装全 !pip install icetk
卡在 Loading checkpoint shards 不动 权重没下完/网络断 开 Internet,挂镜像重下
trust_remote_code 报错 未加该参数 from_pretrained(..., trust_remote_code=True)
回复是英文/不像聊天 没用 model.chat,直接 generate 用 model.chat 或套 chat template

4、Qwen-7B

除了 ChatGLM,Kaggle 上跑通义千问 Qwen2-7B 更"现代"——新模型不再需要 trust_remote_code,直接走标准 AutoModelForCausalLM + chat template。

from transformers import AutoModelForCausalLM, AutoTokenizer
device = "cuda" # the device to load the model onto

# Now you do not need to add "trust_remote_code=True"
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2-7B-Instruct",
    torch_dtype="auto",
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct")

# Instead of using model.chat(), we directly use model.generate()
# But you need to use tokenizer.apply_chat_template() to format your inputs as shown below
messages = [
    {"role": "user", "content": "你是谁呢?"},
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
)
model_inputs = tokenizer([text], return_tensors="pt").to(device)
generated_ids = model.generate(
    model_inputs.input_ids,
    max_new_tokens=512,
)
generated_ids = [
    output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)

回答

我是阿里云开发的一款超大规模语言模型,我叫通义千问。

与 ChatGLM 的差异(关键理解):

  • 不依赖 trust_remote_code:Qwen2 已并入 transformers 主干,官方支持原生加载,更安全。
  • torch_dtype="auto":自动按模型卡声明精度(BF16)加载,省心且数值稳。
  • device_map="auto":自动把层分布到 GPU(多卡时自动切分),比手写 .cuda() 更通用。
  • apply_chat_template:把 messages 按 Qwen 的聊天模板拼成带特殊标记的纯文本。这一步不能省——省略后模型会退化成"续写机器",不再遵循对话格式。
  • output_ids[len(input_ids):]:generate 返回的是"输入+输出"拼接的 id,要切片去掉输入部分,只保留新生成内容。

4.1、Qwen 完整可跑的最小单元(含持久化思路)

%cd /kaggle/working
!pip install -q transformers accelerate sentencepiece
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"

from transformers import AutoModelForCausalLM, AutoTokenizer
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct")
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2-7B-Instruct", torch_dtype="auto", device_map="auto").eval()

def ask(q, hist=None):
    messages = hist + [{"role": "user", "content": q}] if hist else [{"role": "user", "content": q}]
    text = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    out = model.generate(**tok([text], return_tensors="pt").to(model.device), max_new_tokens=512)
    ans = tok.decode(out[0][len(tok(text)["input_ids"]):], skip_special_tokens=True)
    return ans

print(ask("用一句话介绍通义千问"))

Kaggle 持久化提醒:免费 GPU 会话闲置约 60 分钟或总时长到 30h 会被回收,/kaggle/working 之外的内容会丢失。若想保留微调权重,请导出到 Kaggle Dataset 或 ModelScope,别只存在临时目录。

5、在 Kaggle 起一个可对外服务的 API(进阶)

Kaggle 默认不出网,但可以用其内置的 + 公开链接(Public URL) 机制把 Gradio demo 暴露出去:

# 在 ChatGLM-6B 仓库里用 web_demo.py 的思路,但改为 share=True 拿公网隧道
import gradio as gr
# ... 加载 model/tokenizer 同第 3 节 ...
demo = gr.ChatInterface(lambda msg, h: model.chat(tokenizer, msg, history=h)[0])
demo.launch(share=True)   # 生成 https://xxxx.gradio.live 临时公网地址

注意:share=True 生成的是有时效的 Gradio 公网隧道,仅适合临时演示;Kaggle 免费环境不适合长期托管生产服务。真正对外服务请参考 07 篇的 vLLM/Ollama 自建。

5.2、显存不够怎么办:在 Kaggle 跑 INT4 量化版

免费 T4 单卡约 15GB 显存。FP16 的 7B 模型权重约 14GB,加上 KV Cache 几乎贴边,长文本容易 OOM。更稳的做法是加载 INT4 量化版,权重压到约 4-5GB,显存立刻宽松:

# 以 Qwen2-7B-Instruct 的 GPTQ-Int4 量化版为例(需 auto-gptq)
!pip install -q auto-gptq
from transformers import AutoModelForCausalLM, AutoTokenizer
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct-GPTQ-Int4")
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2-7B-Instruct-GPTQ-Int4",
    torch_dtype="auto", device_map="auto").eval()
# 后续推理与第 4 节完全一致(apply_chat_template + generate)

量化版命名规律:HF 上常以 -GPTQ-Int4、-AWQ、-GGUF 结尾。Kaggle 有 GPU 时优先 GPTQ/AWQ(比 GGUF 在 GPU 上更快);纯 CPU 才用 GGUF(见 07 篇)。

5.3、配额与资源管理

  • 30h/周 是免费 GPU 总时长,跨所有 Notebook 共享。跑一次 7B 加载+对话约耗几分钟,但长时挂机会快速吃光额度。
  • 不用时务必点 Session → Stop 释放 GPU;否则空闲也计时长(约 60 分钟闲置后自动回收,但别赌这个)。
  • 若额度用完,可换 Colab 免费版(T4)或 AutoDL 按量付费(约 ¥1-3/h 的 4090/A100)作为补充。
  • 训练(微调)比推理吃资源得多。7B 全参微调在免费 T4 上基本不可行;要用 LoRA/QLoRA(4-bit 量化 + 低秩适配)才能在单卡跑,且仍建议用 AutoDL 这类按小时计费平台。

5.4、从 Kaggle 到本地:成果如何复用

Kaggle 验证通过的代码(第 3、4 节),原样可搬到本地:

  • 本地有 NVIDIA GPU:把 .half().cuda() 或 device_map="auto" 直接复用,路径改成本地模型目录即可。
  • 本地无 GPU:把 AutoModelForCausalLM 换成 GGUF + llama.cpp/Ollama(见 07 篇),代码层面改用 Ollama 的 /v1 接口,调用逻辑与 08 篇 OpenAI SDK 一致。
  • 关键差异只在"模型怎么加载",prompt/对话模板/后处理逻辑完全通用——这也是为什么先吃透 Kaggle 这套最小示例,能在任何环境平移。

5.5、批量推理:一次问一堆问题

验证完单条对话,常见需求是"对一个列表批量提问"(如评测、数据标注)。把加载后的 model 包成函数循环即可,避免每条都重新加载:

questions = ["1+1等于几?", "中国的首都是哪里?", "用 Python 写个快排"]
for q in questions:
    ans = ask(q)                 # ask 见 4.1 定义的封装
    print(f"Q: {q}\nA: {ans}\n{'-'*40}")

要点:模型只加载一次,循环里只做 generate。若问题很多(上千条),注意 Kaggle 30h 额度与单次会话时长上限;超大规模批处理建议用 AutoDL 等按量计费平台,或迁到本地 vLLM(连续批处理吞吐更高,见 07 篇)。

6、小结

  • Kaggle 白嫖 GPU 的三道开关:手机验证 → 开 GPU → 开 Internet,缺一不可。
  • 老模型(ChatGLM-6B)用 .half().cuda() + trust_remote_code;新模型(Qwen2)用 device_map="auto" + chat template,更标准。
  • 验证成功的四要素:GPU 可用、权重加载完、中文回复正常、多轮记忆生效。
  • 显存不够先 .half(),再不行就换 INT4 量化版;权重下载慢就挂 HF_ENDPOINT 镜像。
  • 免费额度有限且会话会被回收,别把重要产物只留在临时目录。
posted @ 2024-04-29 16:31  Stellan7  阅读(606)  评论(0)    收藏  举报