Open Source AI with Python & Hugging Face

除了Anthropic和OpenAI,用开源工具构建你自己的AI工作流!你将使用Hugging Face进行文本任务,比如分类、摘要和问答,并了解transformers和注意力机制如何驱动这些模型。通过LoRA进行微调来实现自定义行为,然后用Stable Diffusion和DreamBooth生成并调整图像。掌握创建自定义AI解决方案的技能吧!

0-introduction

课程概述与众不同之处

摆脱简单的聊天机器人交互

本课程将探讨人工智能(AI),但会采用一种与主流不同的方式。当前大众对 AI 的认知多集中于与聊天机器人互动,例如向其提问、让它检查代码或生成有趣的图片。

深入底层基础

我们将深入 AI 的基础层面,了解其工作原理。课程内容不仅涵盖 API 调用,还包括更底层的操作:

  • 基础的文本转换
  • 微调(Fine-tune)GPT-2 模型以完成特定任务
  • 生成自定义图像
  • 微调图像生成模型(例如,生成特定宠物的图片)

课程核心内容与目标

实践应用与开源模型

课程旨在揭示 AI 技术背后强大的实际应用价值,特别是那些小型、独立的开源模型。学习如何直接在自己的代码库中使用这些模型,可以避免依赖第三方 API 和管理 API 密钥的复杂性。

主要编程语言:Python

  • 课程将主要使用 Python 语言。
  • 文本处理部分:将使用 Hugging Face 的 SDK,该 SDK 同时支持 Python 和 TypeScript。
  • 图像生成部分:由于涉及显卡的运用,Python 是该领域的主流选择。
  • 对于熟悉 JavaScript 的学员,Python 的语法并不难掌握。

概念理解

除了编码实践,我们还将深入理解一些核心 AI 概念,例如:

  • Transformers:了解其工作原理。
  • Tokens 和 Embeddings:弄清这些专业术语的真正含义。

教学方法

两步教学法:概念与代码

为了避免同时理解新概念和阅读代码的困难,课程将采用两步教学法:

  1. 概念讲解:首先,用语言和图示清晰地解释相关概念,帮助学员构建起心智模型。
  2. 代码实践:然后,通过实际代码来演示和应用这些概念,将理论与实践相结合。

1-google-colab-hugging-face

课程所需工具

Google Colab

  • 简介:一个基于云端的 Jupyter Notebook 环境,只需要一个 Google 账户即可免费使用。
  • 优势
    • 提供免费的 CPU 和轻量级 GPU 资源。
    • 解决了本地计算机硬件(尤其是显卡)配置不一的问题,为所有学员提供一个稳定、统一的开发环境。
  • 为何使用 Colab:在本地计算机(即使是 M1 Max)上运行某些 AI 任务可能会非常耗时,而使用 Google 提供的免费 GPU 可以大大提高效率。

Hugging Face

  • 简介:可以理解为 AI 模型领域的“GitHub”,是一个集模型、数据集、SDK 等资源于一体的平台。
  • 课程中的用途
    • SDK:利用其提供的 SDK(支持 Python 和 TypeScript)可以非常方便地与模型进行交互。
    • 模型访问:像 git clone 一样,可以轻松获取和下载开源模型。
  • 账户创建:建议学员提前注册一个 Hugging Face 账户。

环境配置

获取 Hugging Face 访问令牌 (Access Token)

  • 操作步骤:登录 Hugging Face 后,进入个人设置页面,找到 "Access Tokens" 菜单,创建一个新的令牌。
  • 在 Google Colab 中使用:获取到的令牌需要配置到 Google Colab 的Secrets中,以便在 Notebook 中作为环境变量使用。

配置 Google Colab 运行时

  • 默认 CPU 与 GPU 切换
    • Colab Notebook 默认在 CPU 上运行,这对于许多文本任务来说足够了。
    • 当处理图像生成等计算密集型任务时,需要手动将运行时类型(Runtime type)切换到 GPU 以获得性能提升。

涉及的其他库

主要使用的库

  • Hugging Face Transformers: 用于处理各种文本任务的核心库。
  • Hugging Face Diffusers: 用于处理图像生成任务的库。
  • PyTorch: 由 Meta(Facebook)开发,是处理张量(tensors)、神经网络和模型的基础工具。

辅助库

  • Numpy: 用于科学计算。
  • Matplotlib: 用于数据可视化,在课程中会偶尔客串出场。

2-sentiment-analysis-text-generation

超越问答模式的文本任务

简介

尽管我们通常将 AI 与 ChatGPT 等问答工具联系在一起,但 AI 在文本处理领域还有许多其他实用且易于集成的任务。这些任务可以直接应用于我们的应用程序中,且实现起来并不复杂。

TypeScript SDK 的可用性

课程中所有关于文本处理的概念和代码,Hugging Face 都提供了相应的 TypeScript SDK。这意味着即使你的技术栈是 JavaScript/TypeScript,也能轻松地将这些功能应用到前端或 Node.js 项目中。

情感分析 (Sentiment Analysis)

概念

  • 这是机器学习领域的经典入门任务,如同编程界的 "Hello World"。
  • 其目标是分析一段文本,并给出一个情感分数,判断其是积极的还是消极的。

局限性

  • 简单的情感分析模型在处理复杂情感(如讽刺)时表现不佳。
  • 相比之下,像 ChatGPT 这样基于 Transformer 架构的先进模型能更好地理解语言的细微差别。

文本生成 (Text Generation)

核心原理

  • 这是目前最主流的 AI 应用形式,也是 ChatGPT、Gemini、Claude 等模型的核心功能。
  • 其本质是一个复杂的数学模型,根据已有的文本内容,预测下一个最可能出现的词

关键参数

  • how many new tokens:控制生成新文本的长度。
  • temperature (温度):控制模型的“创造性”。
    • 低温值 (如 0):模型会总是选择最符合概率的词,导致输出结果非常确定和重复。
    • 高温值:模型会引入更多的随机性,使得输出结果更具创造性和多样性。

开源模型 vs. 托管服务

  • 使用 Hugging Face 上的开源模型时,我们可以像调节旋钮一样自由地调整temperature等参数。
  • 而在使用 ChatGPT 等托管服务时,这些参数通常被服务商封装和抽象,用户无法直接控制。

组合不同任务的威力

AI 的真正潜力在于将这些基础的构建模块(如情感分析、文本生成)组合起来使用。

  • 示例:你可以先使用文本生成功能创建五个不同的营销文案,然后用情感分析模型对它们进行评估,最终选择情感最积极的那个方案。

3-zero-shot-classification-fill-mask

零样本分类 (Zero-Shot Classification)

概念

这是一种强大的文本分类技术,它允许你在没有为特定标签进行专门训练的情况下,将文本划分到你自定义的一系列类别中。

应用场景

  • 内容自动打标签:例如,为博客文章自动生成合适的标签。
  • 数据筛选:识别应用程序中收到的数据是否为欺诈性或不良内容。

组合的力量

当零样本分类与模型微调(Fine-tuning)等其他技术结合时,其应用潜力会变得更加巨大。

掩码填充 (Fill-Mask)

概念

  • 这个任务类似于我们小时候做的“完形填空”。
  • 模型需要根据句子中一个被遮盖(mask)掉的词的前后文信息,来预测这个空缺处最合适的词。

与文本生成的对比

  • 文本生成:只根据前面的词来预测下一个词。
  • 掩码填充:同时利用前面和后面的词作为上下文,因此拥有更丰富的信息来进行预测。

文本摘要 (Summarization)

概念

将一篇长文本压缩成一篇简短的摘要。

核心挑战

摘要任务需要在简洁性信息保留之间找到一个平衡点。

  • 摘要太短,可能会丢失原文的核心信息。
  • 摘要太长,则失去了摘要本身的意义。

命名实体识别 (Named Entity Recognition, NER)

概念

从文本中识别并提取出具有特定意义的实体,例如:

  • 人名
  • 地名
  • 组织机构名

应用

这项技术在信息提取和数据分析领域非常有用,可以快速地从大量文本中梳理出关键信息。

翻译 (Translation)

简介

利用特定的 AI 模型将一种语言的文本翻译成另一种语言。

模型命名

Hugging Face 上有许多用于翻译的模型,它们的命名通常很直观,比如一个名为 en2de 的模型,很显然是用来进行英语到德语翻译的。

4-google-colab-setup-configuration

初始设置

配置 Hugging Face 令牌

  • 获取令牌
    • 前往 huggingface.co 网站,在个人设置中创建访问令牌。
    • 读取权限的令牌对于本课程大部分内容已经足够。
    • 如果你希望未来将自己微调的模型上传到 Hugging Face,则需要写入权限。
  • 在 Colab 中添加为秘密变量
    • 在 Google Colab 笔记本的左侧工具栏中,点击Secrets
    • 添加一个新的秘密变量,名称必须为 HF_TOKEN
    • 将你获取的令牌粘贴到 Value 中。
    • 开启Notebook access开关,允许当前笔记本访问此令牌。

Google Colab Notebook 基础操作

界面与执行

  • 单元格 (Cell):Colab Notebook 由代码单元格和文本(Markdown)单元格组成。
  • 执行顺序的重要性:代码是按顺序执行的。如果在一个单元格中使用了某个变量,必须确保声明该变量的单元格已经被执行过。
  • 本地使用:你可以将 .ipynb 文件下载到本地,并在 VS Code 等支持 Jupyter Notebook 的编辑器中打开。但要注意,部分 Colab 特有的库(如 google.colab)在本地环境中无法使用。

运行时 (Runtime) 管理

  • 切换硬件加速器:通过菜单栏的“Runtime” -> “Change runtime type”,你可以在 CPU、T4 GPU(免费提供)等不同硬件之间切换。对于图像处理等任务,应切换到 GPU。
  • 会话管理:免费版 Colab 对同时运行的会话数量有限制。如果遇到"no backend with given specifications"的错误,可以通过“Runtime” -> “Manage sessions”来终止其他不再使用的会话。
  • 连接本地运行时:如果你本地有强大的 GPU,Colab 也支持连接到本地计算机来执行代码。

Colab 特色功能

界面工具

  • 变量查看器:可以实时查看当前内存中所有变量的状态。
  • 终端:提供一个基础的命令行环境。
  • Gemini 助手:集成的 AI 助手,可以帮你解释代码、Debug 错误等。

"彩蛋"功能

  • 在 “Settings” -> “Miscellaneous” 中,可以开启一些有趣的功能:
    • Corgi/Kitty/Crab 模式:屏幕顶部会出现可爱的小动物动画。
    • Power 模式:打字时会有酷炫的连击特效。
    • 注意:这些功能虽然有趣,但在需要证明自己正在“严肃工作”时可能会起到反效果。

Playground 模式

  • 通过“File” -> “Open in playground mode”打开笔记本,所有修改都不会保存到原始文件,非常适合练习和实验。

5-pipeline-basics-sentiment-analysis

Hugging Face pipeline 介绍

核心概念

pipeline 是 Hugging Face transformers 库中一个非常强大的高级抽象工具。它将一个复杂的 AI 任务流程简化为几行代码。

工作流程

当你创建一个 pipeline 时,它在后台为你处理了所有繁琐的步骤:

  1. 下载模型:根据你指定的任务,自动下载合适的预训练模型。
  2. 文本预处理(Tokenization):将输入的文本转换成模型能理解的格式(Tokens)。
  3. 模型推理:将处理后的数据送入模型进行计算。
  4. 结果后处理:将模型的原始输出转换成人类可读的、有意义的结果。

目的

pipeline 的设计目的是让开发者可以专注于任务本身(比如情感分析),而不需要深入了解背后数据处理和模型调用的每一个细节。它使得使用 AI 模型变得像调用一个普通函数一样简单。

情感分析实战

导入模块

from transformers import pipeline
from google.colab import output

创建 Pipeline

  • 基本语法:只需调用 pipeline() 函数并传入任务名称即可。

    from transformers import pipeline
    sentiment_analyzer = pipeline("sentiment-analysis")
    
    
  • 模型选择

    • 你可以明确指定要使用的模型,例如:model="distilbert-base-uncased-finetuned-sst-2-english"
    • 如果不指定,pipeline 会加载一个适用于该任务的默认轻量级模型。

使用 Pipeline 进行分析

  • 创建好的 pipeline(例如 sentiment_analyzer)本身就是一个函数。
  • 输入与输出
    • 输入:将一个字符串或字符串列表作为参数传入。
    • 输出:返回一个列表,其中每个元素是一个字典,包含了情感标签(label,如 'POSITIVE' 或 'NEGATIVE')以及对应的置信度分数(score)。

示例演示与局限性

代码演示

通过运行一些示例文本,我们可以看到模型如何对它们进行情感分类。

无法识别讽刺

  • 例子:当输入"It's the best thing since C"(一种带有讽刺意味的表达,暗示 C 语言并不好)时,模型给出了接近 100%的POSITIVE评价。
  • 结论:这表明基础的情感分析模型难以理解语言中的讽刺上下文 nuance

模型选择的权衡

  • 功能与性能:更复杂的模型可能能识别中性情感或处理讽刺,但它们通常更大、运行更慢。选择模型时需要在功能和性能之间做出权衡。
  • 语言:默认模型通常针对英语。如果需要处理其他语言,必须选择相应的模型。
  • 本课程初期选择的模型都是轻量且快速的,目的是为了快速验证设置和理解概念。

6-model-contents-text-generation

模型文件探究

模型在磁盘上的形态

  • 当你从 Hugging Face 下载一个模型时,你得到的文件并非人类可读的文本。它们主要由以下部分组成:
    • 张量 (Tensors):多维数组,存储了模型的权重和参数。
    • 配置文件:定义模型架构的 JSON 文件。
    • 分词器文件 (Tokenizer files):定义如何将文本转换为 Tokens。
  • 这些文件本质上是一系列复杂的数字,是模型进行数学计算的基础。

如何查看模型文件

你可以在 Hugging Face 网站上任何一个模型的页面中,点击 "Files and versions" 选项卡,直接浏览构成该模型的所有文件。

模型大小与资源瓶颈

  • 大小:模型大小差异巨大,从几百兆到几十 G 不等。它取决于模型的参数量量化精度
  • 资源瓶颈:对于在本地运行模型而言,RAM(内存)通常是比磁盘空间更主要的限制因素。特别是在 GPU 和 CPU 共享内存的设备(如 Apple Silicon Mac)上,内存大小直接决定了你能运行多大的模型。

文本生成实战

创建 Pipeline

  • 使用 pipeline("text-generation") 可以快速创建一个文本生成器。
  • 如果不指定模型,默认会加载一个模型,本例中为 GPT-2(大小约 548MB)。

使用 GPT-2 进行生成

  • 初始结果分析:直接使用基础的 GPT-2 模型生成的文本质量通常不高,句子可能不连贯或突然中断。这恰好突显了从 GPT-2 到如今先进大模型的巨大进步,也说明了 模型微调(Fine-tuning) 的必要性。

文本生成关键参数详解

max_new_tokens

  • 控制模型在原始输入(prompt)之后新生成的Token 数量。这是一个硬性限制,达到上限后文本会戛然而止。

temperature (温度)

这个参数用于控制生成文本的随机性或“创造力”。

  • 低温 (接近 0, 如 0.1):模型会倾向于选择概率最高的词。这使得输出非常确定和可预测,对于相同的输入,每次都会生成相同的结果,但缺乏创造力。
  • 高温 (如 1.0):模型会在更广泛的词汇中进行选择,增加了随机性。这能产生更具创造力和多样性的文本,但同时也增加了 偏离主题或产生“幻觉”(Hallucination) 的风险。例如,一个关于 AI 的 prompt 可能会突然转向毕业演讲或列表文章。
  • 实验的重要性:调整temperature没有固定答案,需要根据具体应用场景不断尝试,以找到最佳平衡点。

其他重要参数

  • max_length: 限制包括原始 prompt 在内的总 Token 长度。
  • num_return_sequences: 让模型一次性生成多个不同的版本供你选择。

小结:小模型的应用场景

并非所有任务都需要像 Claude 或 Gemini 这样的巨型通用模型。有时,选择一个较小的开源模型,并针对你的特定任务(如要求特定的输出格式、长度或风格)进行微调,会是更高效、更经济的选择。这种方法在相对较低的资源下就可以实现。

7-zero-shot-classification

零样本分类 (Zero-Shot Classification)

概念

  • “零样本” (Zero-Shot) 的含义:指的是模型在没有经过针对性训练的情况下,仅凭一次提示(prompt)就能完成任务。
  • 应用于分类任务时,意味着我们可以给模型一段它从未见过的文本和一组它从未见过的类别标签,模型能够自行判断该文本应该属于哪个标签。

工作原理(高层次概述)

  • 模型会构建一个假设,例如:“这段文本是关于[某个类别]的”。
  • 然后,它利用其内部的“注意力机制”(Attention Mechanism)来评估这个假设与文本内容之间的匹配程度。
  • 最终,模型会给出一系列分数,表示文本属于每个类别的可能性。

实战演示

创建 Pipeline

  • 使用 pipeline("zero-shot-classification") 即可创建一个零样本分类器。
  • 本示例中使用的默认模型来自 Facebook。

示例

  • 输入
    • 一段文本,例如:“Apple reported record quarterly earnings driven by strong iPhone sales.”
    • 一组候选标签(Candidate Labels),例如:["technology", "business", "sports", "entertainment"]
  • 过程:模型会计算文本与每个标签的匹配度。
  • 输出
    • 模型会返回一个包含所有标签及其对应分数的列表。
    • 关键点:在单标签分类模式下,所有标签的分数总和为 1。
    • 结果分析:对于上述例子,模型可能会给出类似 {'technology': 0.67, 'business': 0.33, ...} 的结果,表明它认为这段文本主要关于科技,其次是商业。

零样本分类的优势与应用

优势

  • 灵活性:无需为新的分类任务重新训练或微调模型,可以直接使用。
  • 效率:可以将非结构化数据快速转化为结构化信息。
  • 成本效益:对于许多简单的分类任务,使用小型的开源模型就足够了,无需依赖昂贵的、按 Token 计费的大型闭源模型。这些小型模型甚至可以在 Serverless 环境中运行。

实际应用场景

  • 垃圾邮件/欺诈检测:判断邮件或用户账户是否存在风险。
  • 工单自动分配:根据工单内容将其自动分配给正确的部门(如技术支持、销售部)。
  • 内容审核:自动识别和过滤不当内容。
  • 情感细分:超越简单的“积极/消极”分类,实现更细致的情感标签,如“高兴”、“悲伤”、“愤怒”等。

多标签分类 (Multi-Label Classification)

概念

除了让模型在多个标签中选择一个最合适的(单标签),我们也可以允许模型为一段文本同时赋予多个标签。

与单标签的区别

  • 在多标签模式下,每个标签的分数是独立的,它们的总和不为 1
  • 每个分数代表该标签与文本的匹配置信度,范围在 0 到 1 之间。
  • 示例:对于“I love programming in Python”这段文本,在["positive", "negative", "neutral"]这组标签下进行多标签分类,可能会得到positive分数很高,neutral分数中等,negative分数很低的结果。

注意事项和潜在陷阱

  • 标签数量过多:如果提供上百个标签,由于分数总和为 1(在单标签模式下),每个标签分到的概率会非常低,可能导致结果不准确。
  • 标签过于相似:如果类别之间界限模糊(如“科技” vs “软件工程”),模型可能难以区分。
  • 多语言处理:默认模型通常只针对英语。处理其他语言时,可能需要:
    • 先用翻译模型统一转换成英语。
    • 或者,根据检测到的语言,动态选择适配该语言的分类模型。

8-question-answer-models

问答模型 (Question Answering) vs. 文本生成

核心区别:抽取式 vs. 生成式

  • 文本生成 (Generative),如 ChatGPT、Claude:
    • 基于其庞大的训练数据(整个互联网),通过概率计算来生成新的文本作为答案。
    • 答案内容不局限于你提供的任何特定上下文。
  • 问答模型 (Extractive),如此处介绍的 pipeline:
    • 严格限制在用户提供的上下文(Context)中寻找答案。
    • 它不会创造新信息,而是从给定的文本中 抽取(Extract) 出最相关的片段作为答案。

应用场景对比

  • 何时使用生成式模型?
    • 当你需要模型利用其广泛的知识库进行创意写作、头脑风暴或回答一般性问题时。
  • 何时使用抽取式模型?
    • 当你希望答案完全基于一份特定的、可信的文档(如公司内部手册、法律文件、产品说明书)时。
    • 这种方式可以有效避免模型产生“幻觉”(Hallucination),确保答案的来源可靠、有据可查。

抽取式问答实战

创建 Pipeline

  • 使用 pipeline("question-answering") 来创建一个问答模型。
  • 本例中使用的模型非常小(约 261MB),适合在资源有限的环境(如单个 VM 或 Serverless 函数)中快速部署和运行。

工作流程

  1. 提供上下文:给模型一段作为信息来源的文本。
  2. 提出问题:向模型提出一个与该上下文相关的问题。
  3. 获取答案:模型会返回它在上下文中找到的答案。

输出详解

模型的输出不仅仅是答案文本,还包含以下关键信息:

  • answer: 抽取的答案文本。
  • score: 模型对该答案的置信度分数(0 到 1 之间)。
  • start: 答案在原始上下文中的起始字符索引。
  • end: 答案在原始上下文中的结束字符索引。

优势

  • 精准定位:通过startend索引,你可以精确地知道答案的出处,甚至可以在前端 UI 上高亮显示原文。
  • 可控性:答案完全来源于你提供的数据,这对于需要高准确性和可追溯性的企业应用至关重要。

潜在挑战与局限性

  • 答案必须在上下文中:如果答案不存在于你提供的文本中,模型要么给出一个低置信度的错误答案,要么无法回答。
  • 上下文长度:与生成式模型类似,如果提供的上下文过长,模型的性能和准确性可能会下降。因此,如何将长文档切分成合适的“块”(Chunking)是一项重要的工程挑战。
  • 问题模糊性:含糊不清的问题会导致模型难以找到准确的答案。

核心概念:RAG (Retrieval-Augmented Generation)

这个抽取式问答的概念是构建更高级的RAG系统(检索增强生成)的基础。RAG 的工作流程是:

  1. 检索 (Retrieval):当用户提问时,系统首先从一个大型知识库(如公司的所有文档)中,用类似本节介绍的方法,检索出与问题最相关的几段文本。
  2. 增强 (Augmented):将这些检索到的文本片段作为上下文,附加到用户的原始问题之后。
  3. 生成 (Generation):将这个增强后的、包含丰富上下文的提示(Prompt)发送给一个大型生成式模型(如 ChatGPT),让它基于这些精准的上下文来生成最终答案。

9-fill-mask-with-bert

掩码填充 (Fill-Mask)

概念

  • “完形填空”:这个任务就像我们做的完形填空题,模型需要根据句子中一个被特殊标记([MASK])遮盖掉的词的前后文信息,来预测这个空缺处最合适的词。
  • 双向上下文:与只能“向后看”的文本生成模型(如 GPT)不同,掩码填充模型(如 BERT)能够同时利用被遮盖词的左侧和右侧的上下文信息进行预测。

BERT vs. GPT

  • BERT (Bidirectional Encoder Representations from Transformers):其核心优势在于双向性。它在训练时就被设计为能够理解一个词在完整句子中的上下文关系,因此非常擅长掩码填充这类任务。
  • GPT (Generative Pre-trained Transformer):其设计目标是生成文本,因此它是一个单向(从左到右)的模型。它通过屏蔽掉未来词的信息,只根据前面的词来预测下一个词。

实战演示

创建 Pipeline

  • 使用 pipeline("fill-mask") 来创建一个掩码填充器。
  • 注意:不同的模型可能使用不同的掩码标记(mask token),需要查阅相应模型的文档。

示例

  • 输入: 一个包含掩码标记的句子,例如: Python is a popular [MASK] language.
  • 参数 top_k: 这个参数可以指定你希望模型返回多少个最可能的候选词。例如,top_k=3 会返回 3 个最有可能填入空缺处的词。

输出分析

  • 模型会返回一个候选词列表,每个候选词都附带一个置信度分数(score)
  • 例子:对于 "The capital of France is [MASK].",模型可能会以极高的置信度返回 "Paris",同时也会给出其他可能性较低的选项。

如何选择合适的模型

使用 Hugging Face Hub 进行筛选

  1. 按任务(Task)筛选:在 Hugging Face Models 页面,可以根据你需要的任务(如fill-mask, question-answering)进行筛选,找到所有支持该任务的模型。
  2. 评估模型质量:筛选后,可以通过以下“社会化”指标来辅助判断:
    • 下载量 (Downloads)点赞数 (Likes):反映了模型的受欢迎程度。
    • 更新时间:近期更新的模型可能性能更好或修复了已知问题。
    • 模型大小/参数量:通常参数越多的模型性能越好,但对硬件资源的要求也越高。
  3. 查看模型来源:可以查看模型的“模型树”(Model Tree),了解它是否是从某个知名的基础模型微调而来的。

权衡因素

选择模型总是一个权衡的过程,需要考虑:

  • 性能与准确性:模型是否足够好以满足你的需求?
  • 资源消耗:你的硬件(内存、GPU)是否足以运行该模型?
  • 速度:模型的推理速度是否满足你的应用场景?

10-summarization-named-entity-recognition

文本摘要 (Summarization)

概念

  • summarization pipeline 的功能是将一段长文本浓缩成一段简短的摘要。
  • 这项技术在浏览器中也开始得到原生支持。例如,Google Chrome 正在逐步推出内置的 Gemini Nano 模型,通过 JavaScript API 可以直接调用摘要、语言检测和文本生成功能。

关键参数

  • max_length: 摘要的最大长度。
  • min_length: 摘要的最小长度。

核心挑战

  • 质量 vs. 长度的权衡:摘要任务的核心挑战是在保持信息完整性和实现文本简洁性之间找到最佳平衡点。

命名实体识别 (Named Entity Recognition, NER)

概念

  • NER pipeline 的任务是从文本中识别并提取出具有特定意义的实体(可以理解为专有名词),并对它们进行分类。
  • 这是一项将非结构化数据(自然语言文本)转化为结构化数据的关键技术。

常见实体类型

不同的模型支持的实体类型有所不同,但常见的包括:

  • PER / Person: 人名 (e.g., John Smith, Bill Gates)
  • ORG / Organization: 组织机构名 (e.g., Apple Inc., Microsoft)
  • LOC / Location: 地点 (e.g., New York City, Cupertino)
  • GPE: 地缘政治实体 (e.g., New Mexico)
  • DATE / TIME: 日期和时间
  • MONEY / PERCENT: 货币和百分比

工作原理与输出

  • 输入: 一段自然语言文本。
  • 输出: 一个实体列表,每个实体都是一个字典,包含:
    • word: 识别出的实体文本。
    • entity: 实体的类别标签(如 ORG, PER)。
    • score: 模型对该识别结果的置信度。
    • startend: 实体在原文中的起始和结束索引。

应用价值

  • 信息提取:从大量新闻、报告或社交媒体帖子中快速提取关键信息(人、地点、公司)。
  • 知识图谱构建:自动构建实体及其关系的知识库。
  • 数据分析:对文本数据进行结构化处理,以便进行后续的统计和分析。例如,统计某公司在新闻中被提及的次数。

实体存储与缓存

  • 对于已经处理过的文本,为了避免重复计算,可以采用缓存策略。
  • 一个简单的方法是:对输入文本进行哈希计算,将哈希值作为键(key),将 NER 的识别结果作为值(value)存储在缓存系统(如 Redis)中。下次处理相同文本时,直接从缓存中读取结果。

11-tokenization-overview

AI 模型如何理解文本:Tokenization

从文本到数字

  • AI 模型,特别是基于 Transformer 架构的模型(如 GPT),无法直接处理原始文本。它们处理的是数字
  • Tokenization(分词) 是将人类语言(文本)转换成模型可以理解的数字序列的第一步。

什么是 Token?

  • Token是文本被分解成的最小有意义单元。
  • 一个 Token不一定是一个完整的单词。它可以是:
    • 一个完整的词 (e.g., "hello")
    • 一个词的一部分或词根 (e.g., "token", "ization")
    • 标点符号 (e.g., ",", "!")
    • 甚至是一个字符。
  • 拆分原则:常见的词(如"can")通常是一个 token,而像 "can't" 这样的词会被拆分成 "can" 和 "'t",因为 "'t" (代表 not)可以和很多词组合(如"isn't", "wasn't"),这样拆分可以更有效地利用词汇表。

Tokenization 流程

  1. 分解 (Splitting)
    • 将输入的文本字符串分解成一个 Token 列表。不同的模型使用不同的分词器(Tokenizer),因此分解方式也不同。
  2. 编码 (Encoding)
    • 将每个 Token 映射到一个唯一的整数 ID。这个映射关系存储在模型的 词汇表(Vocabulary) 中。
  3. 添加特殊 Tokens (Special Tokens)
    • 在数字序列中加入一些特殊的 Token ID,用于给模型提供额外的结构信息。例如:
      • [CLS] (Classification Token): 通常放在序列的开头。
      • [SEP] (Separator Token): 用于分隔两个不同的句子或段落。
      • [PAD] (Padding Token): 用于将短序列填充至统一长度。
      • [UNK] (Unknown Token): 用于表示词汇表中没有的词。
  4. 解码 (Decoding)
    • 当模型生成了输出的数字序列后,需要通过解码过程将其转换回人类可读的文本。这个过程是编码的逆操作。

不同模型的差异

  • 词汇表大小:不同模型的词汇库大小不同。例如,BERT 的基础模型词汇量约为 3 万,而 GPT-2 约为 5 万。更大的模型(如 GPT-4)通常有更大的词汇表。
  • 分词策略:即使是同一个词,不同的分词器也可能将其拆分成不同的 Tokens。因此,一个模型的 Tokenizer 不能与另一个模型混用。

核心要点

Tokenization 是所有现代自然语言处理模型的基石。它将无结构的文本转化为结构化的数字序列,为后续的数学计算(如注意力机制)和模型推理奠定了基础。理解 Tokenization 是理解如何微调和优化模型性能的关键一步。

12-batches-attention-masks

处理不同长度的文本序列

挑战:神经网络需要固定长度的输入

  • 神经网络,特别是用于批量处理数据的神经网络,通常要求所有输入样本具有相同的维度和长度。
  • 然而,在自然语言处理中,句子的长度是千差万别的。

解决方案:填充 (Padding)

  • 目标:将一个批次(batch)中的所有文本序列都处理成相同的长度。
  • 方法
    1. 确定该批次中最长序列的长度
    2. 对于所有比最长序列短的序列,在其末尾添加特殊的填充 Token(Padding Token),直到它们的长度与最长序列相等。
  • 结果:批次中的所有序列都被“拉长”到了统一的长度,可以作为一个规整的张量(tensor)输入到神经网络中。

区分真实内容与填充:注意力掩码 (Attention Mask)

问题

虽然我们通过填充解决了长度不一的问题,但模型在进行计算时(尤其是注意力机制的计算),不应该关注那些无意义的填充 Token

解决方案:注意力掩码

  • 概念:这是一个与输入序列长度完全相同的二进制序列(由 10 组成)。

  • 规则

    • 如果一个位置是真实的 Token,掩码中对应位置的值就是 1
    • 如果一个位置是填充的 Token,掩码中对应位置的值就是 0
  • 作用:在模型计算注意力分数时,这个掩码会告诉模型:“嘿,你只需要关注值为 1 的这些位置,完全忽略值为 0 的位置。”

    输入序列 (Token IDs):
    [ 101, 1996, 7859, 3313, 102,   0,   0,   0 ]
    
    注意力掩码:
    [   1,    1,    1,    1,   1,   0,   0,   0 ]
    
    

小结

填充 (Padding)注意力掩码 (Attention Mask) 是处理可变长度序列时的一对关键技术。它们协同工作,使得模型既能高效地进行批量处理,又能确保计算的准确性,只关注文本的真实内容。这个机制是现代 NLP 模型能够高效处理大规模文本数据的基础之一。

13-encoding-decoding-text

Tokenization 实战:代码演示

1. 探索不同模型的词汇表大小

  • 我们可以使用 Hugging Face 的 AutoTokenizer 类来加载不同预训练模型的 tokenizer。
  • 每个 tokenizer 都有一个 vocab_size 属性,可以告诉我们该模型的词汇表中包含了多少个独特的 token。
  • 示例代码分析:通过加载 BERT, GPT-2, RoBERTa, T5 等不同模型的 tokenizer,我们可以直观地看到它们的词汇表大小各不相同,这反映了它们在设计和训练上的差异。

2. 查看分词结果

  • 加载 tokenizer 后,可以直接调用它(像函数一样)来对文本进行分词。
  • 观察:将同一段文本输入给不同的 tokenizer(例如 BERT 的和 GPT-2 的),会发现它们的分词结果有所不同。
    • BERT:可能会将 "tokenization" 分解为 ['token', '##ization']
    • GPT-2:可能会分解为 ['token', 'ization'],并使用特殊字符(如 Ġ)来表示单词的开头。
  • 结论:分词策略是与特定模型紧密绑定的,不能混用。

3. 从 Token 到 ID (编码)

  • Tokenizer 不仅能将文本分解为 token 字符串,还能直接将文本转换为模型可用的 input_ids(即每个 token 对应的整数 ID)。
  • 示例tokenizer("Hello, world!") 会返回一个包含 input_idsattention_mask 的字典。

4. 从 ID 回到 Token (解码)

  • 使用 tokenizer 的 decode() 方法,可以将一个 input_ids 列表转换回人类可读的文本字符串。
  • 这是一个编码-解码的完整流程,是模型与人类语言交互的基础。
  • 实验
    • 输入一个包含未知词汇(如 "ASDF")的句子。
    • 现象:即使词汇表中没有这个词,tokenizer 仍然能通过将其分解为更小的单位(甚至是单个字母)来进行编码,并在解码时成功地将其还原。
    • 原因:现代分词算法(如 BPE, WordPiece)非常灵活,它们可以通过组合已知的基础字符和子词来表示任何新词或拼写错误的词。如果一个词完全无法分解,最终会使用 [UNK] (unknown) token 来表示。

5. 特殊 Token 的作用

  • 在编码过程中,tokenizer 会自动添加特殊 token。
  • 例如:对于 BERT,它会在序列的开头添加 [CLS](ID: 101)并在结尾添加 [SEP](ID: 102)。这些特殊 token 在模型的特定任务(如文本分类、句子对判断)中扮演着重要角色。

核心要点

通过实际代码操作,我们可以深刻理解 Tokenization 过程中的细节:

  • 模型特异性:每个模型都有其配套的、不可替换的 tokenizer。
  • 稳健性:分词算法能够优雅地处理词汇表之外的词(Out-of-Vocabulary words)。
  • 结构化信息:特殊 token 为模型提供了超越文本内容本身的结构化信息。

14-batch-processing-multiple-strings

批量处理 (Batch Processing) 实战

背景

我们已经了解了处理不同长度文本序列的两个关键技术:填充 (Padding)注意力掩码 (Attention Mask)。现在,我们通过实际代码来观察它们是如何工作的。

场景

假设我们有一个包含多个句子的列表(在 Python 中称为 list),它们的长度各不相同。

batch_of_texts = [
    "The cat sat.",
    "The cat sat on the mat."
]

使用 Tokenizer 进行批量编码

  • 当我们将一个文本列表传递给 tokenizer 时,它会智能地对整个批次进行处理。
  • 关键参数
    • padding=True: 告诉 tokenizer 启用填充功能。它会自动找到批次中最长的句子,并将所有其他句子填充到该长度。
    • truncation=True: 如果句子超过了模型的最大长度限制,会自动进行截断。
    • return_tensors="pt": 指定返回的数据格式为 PyTorch 张量(Tensors)。其他选项还包括 TensorFlow ("tf") 等。

分析输出结果

运行 tokenizer 后,我们会得到一个包含 input_idsattention_mask 的字典,它们的维度是 [批次大小, 序列长度]

  1. input_ids (Token IDs):

    • 我们可以观察到,较短的句子("The cat sat.")在编码后的末尾被添加了若干个 0(或其他填充 token ID)。
    • 这样,两个句子的 input_ids 列表现在具有完全相同的长度。
    [[101, 1996, 4937, 2938, 1012, 102, 0, 0, 0]],
     [101, 1996, 4937, 2938, 2006, 1996, 13523, 1012, 102]]
    
    
  2. attention_mask (注意力掩码):

    • 对于较短的句子,其 attention_mask 在真实 token 的位置上是 1,而在填充 token 的位置上是 0
    • 对于最长的句子,其 attention_mask 全部由 1 组成(因为它没有被填充)。
    # 示例输出
    [[1, 1, 1, 1, 1, 1, 0, 0, 0],
     [1, 1, 1, 1, 1, 1, 1, 1, 1]]
    
    

核心价值

  • 通过这种批量处理机制,我们可以非常高效地将大量文本数据准备成适合模型处理的格式。
  • input_ids 确保了数据维度的统一,而 attention_mask 则保证了模型在计算时能够忽略填充部分,从而得出准确的结果。

词汇表 (Vocabulary) 的角色

  • vocab.json 文件:当 tokenizer 被下载时,通常会一同下载一个 vocab.json 或类似的文件。
  • 功能:这个文件本质上是一个哈希映射(Hash Map) 或字典,定义了从每个 token 字符串到其唯一整数 ID 的映射关系。
  • 一致性:正因为有了这个固定的映射文件,tokenizer 才能保证同一个 token 在任何时候都被编码成相同的 ID,确保了编码过程的确定性和可重复性。
  • 处理未知 Token:正如之前的实验所示,分词算法的设计使其能够处理词汇表之外的词。它会将未知词分解为已知的子词或字符的组合。如果实在无法分解,才会使用一个特殊的 [UNK](unknown)token 来表示。因此,在实践中,模型几乎总能处理任何输入的字符序列。

15-transformers-overview

Transformer 架构:现代 AI 的基石

简介

  • 起源:Transformer 架构源自 Google 在 2017 年发表的里程碑式论文《Attention Is All You Need》。
  • 影响力:它已成为现代所有主流大型语言模型(LLM)的基础,包括 OpenAI 的 GPT 系列、Meta 的 Llama、Google 的 Gemini 和 Anthropic 的 Claude。

核心能力

  • 理解长距离依赖:Transformer 的核心优势在于它能够捕捉和理解句子中相距很远的词语之间的复杂关系。这是通过其核心机制——自注意力(Self-Attention)——实现的。

Transformer 模型分类

  • Encoder-only 模型(如 BERT):这类模型是双向的,它们在处理一个词时会同时考虑其左右两边的上下文。这使得它们非常擅长于理解任务,如掩码填充(Fill-Mask)和文本分类。
  • Decoder-only 模型(如 GPT):这类模型是单向(自回归)的,它们在生成下一个词时只关注已经生成的前面的词。这使得它们非常擅长于生成任务,如文本续写和对话。

Transformer 的工作流程

Transformer 模型处理文本的过程可以概括为三个主要步骤:

1. 词嵌入 (Embedding)

  • 目标:将输入的 Token IDs 转换成包含丰富语义信息的向量(Vectors)
  • 过程
    • 语义嵌入:每个 Token ID 会被映射到一个高维向量(通常为 768 或 1024 维)。在训练过程中,模型会学习到语义相近的词(如 "king" 和 "queen")在向量空间中的位置也相近。
    • 位置嵌入 (Positional Encoding):由于 Transformer 架构本身不处理序列的顺序信息,需要额外添加一个表示每个 Token 在句子中位置的向量。
  • 结果:每个 Token 都被表示为一个结合了语义含义位置信息的综合向量。

2. Transformer 模块 (Transformer Block)

这是模型的核心,内部包含两个关键部分:

  • 自注意力机制 (Self-Attention)
    • 比喻:“小组讨论”。在这一步,句子中的每一个词都会与其他所有词进行“交流”,以计算它们之间的相关性或“注意力分数”。
    • 作用:这使得模型能够理解上下文。例如,对于单词 "bank",模型可以通过关注句子中的 "river" 来确定它指的是“河岸”,或者通过关注 "robbed" 来确定它指的是“银行”。每个词的向量表示会根据这些上下文关系进行动态调整。
  • 前馈神经网络 (Feed-Forward Network)
    • 比喻:“独立思考”。在经过“小组讨论”后,每个词的向量会再经过一个独立的神经网络层进行进一步的处理和转换。
    • 作用:为模型增加了非线性处理能力,使其能够学习更复杂的模式。

3. 输出概率 (Output Probabilities)

  • 目标:根据经过 Transformer 模块处理后的向量,预测下一个最可能的 Token。
  • 过程
    • 模型的最后一层是一个线性层,后接一个 Softmax 函数。
    • 它会为词汇表中的每一个 Token 计算一个概率分数。
  • 结果:一个表示下一个 Token 概率分布的列表。例如,{"the": 0.3, "a": 0.2, ...}。模型接下来会根据这个概率分布选择一个 Token 作为输出。

16-transformers-q-a

Token ID vs. 向量 (Vector)

问:Tokenization 之后,"bank"(银行)和 "bank"(河岸)的 Token ID 是否相同?

答: 是的,它们是相同的。在词汇表中,"bank" 这个词只有一个唯一的 Token ID (例如, 35)。Token ID 本身不包含任何上下文信息。

问:模型是如何区分这两种 "bank" 的?

答: 这正是 Transformer 模块 的核心作用。

  1. 初始嵌入 (Initial Embedding): 无论是哪个 "bank",它们初始被转换成的词嵌入向量是相同的。
  2. 上下文调整 (Contextual Adjustment): 在自注意力(Self-Attention)阶段,模型会分析 "bank" 与句子中其他词(如 "river" 或 "robbed")的关系。
    • 如果句子中有 "river","bank" 的向量表示会被“拉向”与“地理位置”相关的向量空间区域。
    • 如果句子中有 "robbed",它的向量表示则会被“拉向”与“金融机构”相关的区域。
  3. 最终向量: 经过 Transformer 模块处理后,两个 "bank" 虽然初始 Token ID 相同,但最终得到的上下文向量 (Contextual Vector) 是完全不同的。这个最终的向量才真正代表了该词在特定语境下的含义。

模型训练的本质

问:模型是如何学会这种上下文调整的?

答: 通过 暴力破解式的训练 。

  1. 随机初始化: 一个全新的模型,其内部的所有参数(权重)都是随机的。它对词语关系一无所知。
  2. 大规模数据学习: 模型被“喂食”海量的文本数据。对于每个句子,训练任务通常是预测下一个词或被遮盖的词。
  3. 误差反向传播: 模型做出预测,然后将其与真实答案进行比较,计算出误差。
  4. 参数微调: 根据误差,对模型内部数以亿计的参数进行极其微小的调整,目标是让下一次的预测误差变得更小。
  5. 循环往复: 这个过程重复数万亿次,模型内部的参数会逐渐从随机状态收敛到一个能够准确捕捉语言规律的状态。

结论: 模型学习的过程并非由人类设计具体的数学规则,而是通过大规模的试错和优化,让模型自己发现语言的统计规律。

对话上下文与 RAG

问:ChatGPT 如何记住我们之前的对话内容?

答: 它并没有真正意义上的“记忆”。每次你发送一条新消息时,你的整个对话历史记录都会被一起发送给模型。模型是在处理这个完整的、包含了所有历史记录的上下文中来生成新回复的。这就是为什么对话过长时,模型性能会下降或达到“上下文窗口”(Context Window)的限制。

问:企业如何让 ChatGPT 使用内部知识库?

答: 这通常通过 RAG (Retrieval-Augmented Generation) 实现。

  1. 知识库向量化 (Vectorization): 首先,将公司的所有文档切分成小块,并通过一个模型将它们转换成向量,存储在一个向量数据库中。
  2. 用户提问与检索 (Retrieval): 当用户提出问题时,系统首先将用户的问题也转换成向量,然后在向量数据库中搜索与之最相似、最相关的文档片段。
  3. 上下文增强 (Augmentation): 将检索到的这些文档片段作为附加上下文,与用户的原始问题拼接在一起。
  4. 生成答案 (Generation): 将这个增强后的、包含了精准上下文的完整提示(Prompt)发送给 ChatGPT,让它基于你提供的内部知识来回答问题。

关键点: 模型本身并没有被改变或“重新训练”。你只是在每次提问时,动态地为它提供了最相关的“参考资料”。

17-attention-mechanism-to-focus-model

RAG 与注意力机制的关联

RAG (Retrieval-Augmented Generation) 复习

  • 核心思想:在向大型语言模型(LLM)提问前,先从一个私有的知识库(如公司文档、个人笔记)中检索出与问题最相关的信息,然后将这些信息作为附加上下文(Context)一并提供给 LLM。
  • 工作流程
    1. 向量化:将你的知识库和用户的问题都转换成向量(数字表示)。
    2. 相似度搜索:在向量数据库中,找到与问题向量最相似的知识库文本块。这个过程与 Transformer 内部的注意力机制在概念上是相似的——都是在寻找“相关性”。
    3. 增强提示:将检索到的文本附加到原始提示中,为 LLM 提供精准的、即时的知识。
  • 应用:即使你不亲自构建 Transformer 模型,理解其核心概念(如向量化和相似性)也能帮助你构建强大的 RAG 系统,让通用模型具备特定领域的知识。

注意力机制可视化

工具介绍

  • bertviz: 这是一个强大的 Python 库,它能够可视化 BERT 等 Transformer 模型内部的注意力机制。
  • 目的:通过可视化,我们可以直观地看到模型是如何判断句子中不同单词之间的关联强弱的。

实战演示

  1. 准备输入:提供两个句子给模型。
  2. 生成注意力图:使用 bertviz 生成可视化图表。
  3. 分析图表
    • 无关联句子:当输入两个语义上毫不相关的句子时(例如 "The cat sat on the mat." 和 "The dog played in the park."),我们看到的连线非常稀疏,大多只连接到句子的开始([CLS])和结束([SEP])标记。
    • 有关联句子:当输入包含多义词的句子时(例如 "The thieves robbed the bank." 和 "The boat sailed on the river bank."),我们可以观察到有趣的现象:
      • 单词 "bank" 会与 "robbed", "thieves" 建立强关联,同时也会与 "river", "sailed" 建立强关联。
      • 这直观地展示了模型是如何根据上下文来理解词义的,即通过计算一个词与其他所有词的“注意力分数”。
      • 悬停交互:通过在可视化图上悬停,可以清晰地看到任意两个词之间的注意力权重(连线的粗细代表权重大小)。

“层”(Layer)的含义

  • Transformer 模型是由多个相同的 层(Layer) 堆叠而成的。
  • 信息逐层处理:输入数据首先经过第一层处理,其输出再作为第二层的输入,以此类推。
  • 不同层的关注点
    • 底层(如 Layer 0, 1):通常关注更基础的、局部的语法关系,比如邻近词的搭配。
    • 高层(如 Layer 10, 11):则能捕捉到更抽象、更全局的语义关系,形成对整个句子更深层次的理解。
  • 可视化中的层切换:通过在 bertviz 中切换不同的层,我们可以观察到模型在不同处理深度上对句子关系的理解是如何演变的。

18-encoder-decoder-transformers

Transformer 内部架构回顾

编码器 (Encoder) 与 解码器 (Decoder)

  • 编码器 (Encoder)
    • 职责:读取并理解输入的整个文本序列。
    • 工作方式:它将输入的 Token 序列转换成一个富含上下文信息的数字表示(向量序列)。在这个阶段,文本的“词义”已经被捕获。
    • 代表模型:BERT 是一个典型的 编码器-only 模型,专注于理解任务。
  • 解码器 (Decoder)
    • 职责:根据编码器提供的理解(或者对于解码器-only 模型,根据已生成的部分),生成输出的文本序列。
    • 工作方式:它是一个 自回归(auto-regressive) 的过程,即一次生成一个 Token。每生成一个新 Token,这个新 Token 都会被加入到输入中,用于预测下一个 Token。
    • 代表模型:GPT 是一个典型的 解码器-only 模型,专注于生成任务。

GPT 的工作原理:单向注意力

  • 只向后看:GPT 在预测下一个 Token 时,其注意力机制被设计为只能关注当前位置之前的所有 Token。
  • 未来屏蔽 (Masking):这是通过一种称为 因果注意力掩码(Causal Attention Mask) 的技术实现的。在计算注意力时,所有未来位置的 Token 都会被“屏蔽”掉,确保模型无法“偷看”答案。
  • 逐步生成过程
    1. 输入初始提示(Prompt)。
    2. 模型根据提示预测下一个最可能的 Token。
    3. 将新生成的 Token 添加到输入序列的末尾。
    4. 重复步骤 2 和 3,直到生成一个特殊的 结束符(End-of-Sequence token) 或达到最大长度限制。

解码策略:如何选择下一个词

模型在生成文本时,其输出的是一个概率分布列表。如何从这个列表中选择下一个 Token,有多种策略:

1. 贪婪解码 (Greedy Decoding)

  • 策略:总是选择概率最高的那个 Token。
  • 优点:简单、快速、确定性(每次结果都一样)。
  • 缺点:非常容易产生重复、乏味和不自然的文本,因为它缺乏多样性,可能会陷入局部最优解。

2. 采样与温度 (Sampling with Temperature)

  • 策略:根据概率分布进行随机采样,但可以通过一个名为 温度(temperature 的参数来调整这个分布。
    • 低温 (e.g., 0.2):使得概率分布更“尖锐”,高概率的词更容易被选中,低概率的词更难被选中。结果更接近贪婪解码,但仍有一定随机性。
    • 高温 (e.g., 1.0):使得概率分布更“平滑”,所有词被选中的概率差异变小。这会增加文本的多样性和“创造性”,但也可能导致生成的文本偏离主题或出现事实错误。

3. Top-K 采样

  • 策略:只在概率前 K 个最可能的 Token 中进行采样。
  • 优点:过滤掉了大量不相关的低概率词,避免了生成奇怪的词语。
  • 缺点:K 是一个固定值。如果概率分布很“尖锐”(只有一个词概率很高),Top-K 可能会强行引入不合适的词;如果分布很“平滑”,Top-K 又可能截断掉一些合理的选项。

4. Top-P (Nucleus) 采样

  • 策略:从一个动态的候选词集合中进行采样。这个集合由概率从高到低排序的 Token 组成,直到它们的累积概率达到一个阈值 P (例如 0.95)。
  • 优点:被认为是目前效果最好的采样策略之一。它非常灵活:
    • 当模型非常确定下一个词时(概率分布尖锐),候选集会很小。
    • 当模型不确定时(概率分布平滑),候选集会自动扩大,允许更多的多样性。
  • 实践建议:在大多数情况下,Top-P 采样是首选的解码策略。

19-decoding-strategies-for-text-generation

解码器工作原理:因果注意力掩码 (Causal Attention Mask)

核心概念

  • “只向后看”:解码器-only 模型(如 GPT)在生成第 N 个 Token 时,只能利用第 1 到 N-1 个 Token 的信息。
  • 实现方式:这是通过一种特殊的因果注意力掩码来实现的。在计算注意力分数时,这个掩码会强制将所有未来位置的注意力权重设置为零(或负无穷),确保模型无法“偷看”未来的信息。

可视化演示

  • 当模型处理第一个 Token 时,它只能看到自己。
  • 当处理第二个 Token 时,它能看到第一个和第二个 Token。
  • 依此类推,形成一个下三角矩阵的注意力模式。
  • 这种自回归(auto-regressive)的特性是所有生成式文本模型的基础。

解码策略实战

1. 贪婪解码 (Greedy Decoding)

  • 行为:始终选择概率最高的下一个 Token。
  • 代码演示:在一个循环中多次运行贪婪解码,会发现每次生成的文本完全相同
  • 结论:虽然可预测,但缺乏创造性,容易产生重复和乏味的内容。

2. 温度采样 (Temperature Sampling)

  • 行为:通过调整 temperature 参数来控制采样的随机性。
  • 可视化:通过绘制不同温度下下一个 Token 的概率分布图,可以直观地看到:
    • 低温:概率分布非常“尖锐”,只有少数几个 Token 有较高的被选中概率。
    • 高温:概率分布变得“平坦”,更多 Token 有机会被选中,增加了多样性。
  • 结论:温度是在“确定性”和“创造性”之间进行权衡的关键旋钮。

3. Top-K 和 Top-P 采样

  • Top-K (top_k):将采样范围限制在概率最高的 K 个 Token 内。
    • 演示:设置一个较大的 top_k(如 60)会让模型产生非常意想不到的、有时甚至荒谬的文本,因为它从一个更广泛的、但仍然是“合理”的候选池中进行选择。
  • Top-P (top_p or do_sample=True with top_p < 1):将采样范围限制在一个累积概率达到 P 的动态候选集内。
    • 演示:Top-P 通常能生成质量更高、更连贯的文本,因为它能根据模型对下一个词的“确定性”动态调整候选集的大小。
  • 组合使用:在实践中,可以同时设置 temperature, top_k, top_p 等参数,以精细地控制生成过程。

上下文窗口 (Context Window)

  • 概念:模型在生成文本时能够“记住”或“参考”的最大 Token 数量。
  • GPT-2 示例:GPT-2 的上下文窗口是 1024 个 Token
  • 影响:如果生成的文本加上原始提示超过了这个长度,模型会开始“忘记”最早的内容。这会导致文本连贯性下降,出现前后矛盾,也是产生“幻觉”的一个原因。当模型忘记了对话的初始背景时,它的回答就可能偏离轨道。

结束符 (End-of-Sequence Token)

  • 作用:除了达到最大长度限制,模型也可以通过生成一个特殊的 eos_token(End-of-Sequence Token)来主动停止生成。
  • 控制生成:在调用生成函数时,可以传入 eos_token_id 参数。当模型生成了这个特定的 Token ID 时,即使未达到最大长度,生成过程也会停止。
  • 训练结果:模型通过在大量的文本数据上进行训练,学会了在句子或段落自然结束时,下一个最可能的 Token 就是这个结束符。

20-fine-tuning-overview

微调(Fine-Tuning)的核心决策:何时使用?

场景一:增加知识内容 (Adding More Context/Content)

  • 目标: 让模型了解更多、更新的知识或特定领域的资料。
  • 最佳方案: 提示词增强 (Prompt Augmentation),而非微调。
    • 方法:
      • 直接在提示词中粘贴相关资料。
      • 使用向量数据库 (Vector Database) 动态地将相关上下文注入到提示词中。
    • 优势: 更快、更便宜、更高效。

场景二:改变输出风格 (Changing Style)

  • 目标: 改变模型回应的格式、语气、结构或文体。
  • 最佳方案: 微调 (Fine-Tuning)
    • 优势: 在改变模型行为和输出风格方面,微调是更合适的选择。

什么是微调?一个形象的比喻

微调不是从零开始

  • 从零开始训练模型: 就像教一个婴儿语言。需要从随机状态开始,通过海量数据和计算资源(时间、GPU、电力),让模型慢慢学会语言的规律。这个过程极其昂贵和耗时。
  • 微调 (Fine-Tuning): 就像一个已经精通英语(基础语言能力)的人去学习一个新专业(如 AI)。
    • 基础: 模型已经理解了语法、句子结构等通用语言知识。
    • 过程: 你不需要重新教它“什么是电脑”,只需要教它“什么是向量数据库”、“什么是嵌入”等新概念。这是在“站在巨人的肩膀上”进行学习。
    • 目的: 专注于教授特定的响应结构 (structure)和风格 (style),而不是灌输基础知识。

微调的挑战与方法

完全微调 (Normal/Full Fine-Tuning)

  • 定义: 调整模型中每一个参数,就好像要重写整本教科书。
  • 挑战:
    • 成本高昂: 即使是像 GPT-2 这样的小模型,完全微调的成本也很高。
    • 模型越大,越困难: 对于大型模型,完全微调的计算成本是天文数字。
  • 建议:
    • 如果必须进行完全微调,应从小模型 (small model) 开始。
    • 但研究表明,通常不推荐对整个模型进行微调。

更高效的微调思路(预告)

  • 新的比喻: 与其重写整本教科书,我们能不能只在书的末尾增加一个附录或新的章节 (addendum)
  • 核心思想: 不改变原始模型,而是在其之上增加一个小的、可训练的层,只对这个新层进行调整。

21-parameter-specific-fine-tuning

模型微调 (Fine-Tuning) 的挑战

全参数微调 (Full Fine-Tuning)

  • 概念:获取一个预训练好的模型(如 GPT-2),然后用你自己的特定数据集继续对其进行训练,并更新其所有参数
  • 优点:可以获得最佳的性能和最高的任务适应性。
  • 缺点
    • 计算成本高:更新数十亿个参数需要大量的 GPU 资源和时间。
    • 存储成本高:每微调一次,你就需要存储一个全新的、与原始模型同样大小的模型副本。例如,微调一个 48GB 的模型,就会产生另一个 48GB 的新模型。

参数高效微调 (Parameter-Efficient Fine-Tuning, PEFT)

核心思想

有没有一种方法,既能让模型适应新任务,又不必更新所有参数,从而节省计算和存储资源?PEFT 就是为此而生的系列技术。

LoRA: Low-Rank Adaptation (低秩适配)

LoRA 是目前最流行和最有效的 PEFT 技术之一。

  • 比喻:想象预训练模型是一本厚厚的教科书。
    • 全参数微调 就像是重写整本教科书
    • LoRA 则像是在书页上贴满了“便利贴”,你只在便利贴上写下新的知识和笔记,而教科书原文保持不变。
  • 工作原理
    1. 冻结原始权重:在微调过程中,LoRA 会将预训练模型的所有原始参数锁定(Freeze),不进行任何更新。
    2. 注入适配器层:它会在模型的某些关键层旁边(通常是注意力层)注入一些非常小的、可训练的 “适配器”层(Adapter Layers)
    3. 只训练适配器:在训练过程中,只有这些新增的、微小的适配器层的参数会被更新。这些适配器层的参数数量通常只占原始模型参数总量的极小一部分(例如,不到 1%)。

LoRA 的巨大优势

  • 计算效率极高:由于只训练极少数参数,微调所需的时间和算力大幅降低。现在可以在消费级 GPU 上微调相当大的模型。
  • 存储效率极高:微调完成后,你不需要保存整个模型。你只需要保存那些被训练过的、非常小的适配器层权重(通常只有几 MB 到几十 MB 大小)。
  • 灵活性和可移植性
    • 这些小的适配器文件可以被看作是模型的 “插件”或“皮肤”
    • 你可以为一个基础模型训练多个不同的适配器,以适应不同的任务(如一个用于写诗,一个用于写代码)。
    • 在使用时,只需加载基础模型,然后将相应的适配器“挂载”上去即可。

结论: LoRA 技术极大地降低了模型微调的门槛,使得个人开发者和小型团队也能够定制和使用强大的 AI 模型,是 AI 民主化进程中的一项关键技术。

22-preparing-loading-the-dataset

微调(Fine-Tuning)实战准备

管理 Google Colab 会话

  • Colab 对免费用户的并发会话数量有限制。如果遇到无法连接的错误,可以通过顶部菜单的 “Runtime” -> “Manage sessions” 来关闭其他不再使用的会- 话。

分配 GPU 资源

  • 本次微调任务必须在 GPU 上运行
  • 操作步骤
    1. 进入 “Runtime” -> “Change runtime type”。
    2. 在 “Hardware accelerator” 下拉菜单中选择 T4 GPU(这是免费用户可用的选项)。
    3. 讲师为了演示效率,可能会选择更强大的付费 GPU(如 A100)以缩短等待时间,但学员使用 T4 GPU 同样可以完成任务,只是需要更多耐心。

数据集的查找与准备

1. 寻找数据集

  • Hugging Face Hub: 是一个巨大的宝库,不仅包含模型,还拥有数十万个可用于训练和微调的数据集(Datasets)
  • 本课程示例: 我们将使用一个名为 "Abirate/english_quotes" 的数据集,其中包含了名言、作者和标签。
  • 给你的挑战: 鼓励学员自行探索 Hugging Face 上的其他文本数据集,选择一个自己感兴趣的来进行微调实验。

2. 加载与查看数据集

  • 使用 Hugging Face 的 datasets 库中的 load_dataset 函数可以轻松加载数据集。
  • 数据集通常是结构化的(类似于 JSON 或表格),我们可以查看其结构和内容。本例中,我们主要关心 quote(名言)和 author(作者)字段。

3. 数据准备(格式化)

  • 目标: 将原始的结构化数据转换成模型训练所需的特定格式。这是微调中至关重要的一步,因为它“教”会了模型我们期望的输出模式。

  • 本课程格式: 我们将每条数据格式化成一个字符串:

    "Quote by [author]: \\\\"[quote]\\\\"<|endoftext|>"
    
    
  • 关键点:

    • 一致的模式: 这种一致的格式(Quote by ...: "...")能让模型在微调后,只要看到 "Quote by" 开头,就倾向于遵循这个模式生成后续内容。
    • 结束符(End-of-Sequence Token): 在每条数据末尾明确添加结束符 (<|endoftext|>),这会训练模型在生成完一句名言后知道应该停止,避免无休止地生成下去。

4. 数据量

  • 本次演示使用的数据集相对较小,只有约 2500 条记录。
  • 这也证明了微调的强大之处:即使是少量但高质量、格式一致的数据,也足以让一个预训练模型学习到新的行为模式。

模型准备与量化

1. 加载模型与 Tokenizer

  • 我们选择 gpt2-medium 作为本次微调的基础模型。

2. 量化 (Quantization)

  • 概念: 一种模型压缩技术,通过降低模型参数的数值精度来减小模型的内存占用。
  • 比喻: 就像将一张高清图片(如 32 位浮点数)转换成一张较低质量的图片(如 4 位整数),图片信息会有些损失,但文件大小会显著减小。
  • 作用: 量化使得在内存有限的设备(如免费版的 Colab GPU 或个人电脑)上运行和微调更大的模型成为可能。
  • 实现: 使用 bitsandbytes 库可以轻松实现 4 位量化。虽然会损失一些模型性能,但对于在资源受限的环境下进行学习和实验来说,这是一个非常实用的折衷方案。

23-the-fine-tuning-process

LoRA 微调配置

参数统计

  • GPT-2 Medium: 总参数量约为 3.55 亿。这是一个相对较小的模型,现代的开源 LLM 通常有数十亿甚至上百亿参数。
  • 可训练参数: 使用 LoRA 技术,我们实际上只训练了总参数中非常小的一部分(例如,可能只有几百万个),而原始的 3.55 亿参数保持不变。

配置 LoRA

  • 使用 Hugging Face 的 peft (Parameter-Efficient Fine-Tuning) 库来配置 LoRA。
  • 关键配置项包括:
    • model: 要进行微调的基础模型。
    • config: LoRA 的具体配置,如 task_type="CAUSAL_LM"(表示这是一个用于文本生成的因果语言模型)。

数据处理与训练准备

Tokenization

  • 将我们之前格式化好的字符串数据集(例如 "Quote by Oscar Wilde: ...")进行 Tokenization。
  • 填充 (Padding): 将所有序列填充到统一的最大长度,这是模型进行批量处理的要求。

数据整理器 (Data Collator)

  • 这是一个辅助工具,负责将单个数据样本智能地组合成批次(batches)。它会处理填充等细节工作,为训练循环准备好格式规整的数据。

训练器 (Trainer) API

  • Hugging Face 的 Trainer 是一个高级 API,它将整个模型训练循环(包括前向传播、计算损失、反向传播、参数更新、评估、日志记录等)封装了起来。
  • 配置训练参数 (TrainingArguments):
    • output_dir: 指定训练好的模型(适配器)保存的目录。
    • num_train_epochs: 训练的总轮数(Epochs)。一个 Epoch 指的是模型完整地过一遍整个训练数据集。本例中我们只训练 1 轮。
    • 批处理大小 (per_device_train_batch_size): 每次向 GPU 发送多少个样本进行训练。
  • 启动训练: 调用 trainer.train() 即可开始微调过程。

训练过程与结果

训练耗时

  • 训练时间取决于多种因素:GPU 性能、模型大小、数据集大小、训练轮数等。
  • 在讲师使用的 A100 GPU 上,训练过程大约耗时 2 分钟
  • 在免费的 T4 GPU 上,预计需要 5-10 分钟
  • 这充分展示了 LoRA 的高效性:在很短的时间内,用少量数据就能完成微调。

结果对比

  • 微调前 (Base Model):
    • 当我们给原始的 gpt2-medium 模型一个提示 "Quote by Bob Dylan" 时,它生成的续写内容非常随意,没有遵循我们期望的格式(没有冒号、没有引号),并且内容冗长、 rambling。
  • 微调后 (Fine-tuned Model):
    • 我们加载基础模型,并 应用 上我们刚刚训练好的 LoRA 适配器。
    • 当给这个微调后的模型相同的提示时,它的表现发生了根本性的改变
      1. 遵循格式: 它准确地生成了冒号、双引号。
      2. 内容合理: 生成了一段看起来像名言的文本。
      3. 懂得停止: 在名言结束后,它正确地生成了我们训练时加入的 end-of-sequence token,从而自然地停止了生成。

结论

这个实验有力地证明了 LoRA 微调的强大威力。仅仅通过 2 分钟的训练和 2500 个样本,我们就成功地“教会”了一个通用语言模型一种全新的、特定的行为模式和输出格式。

24-stable-diffusion-overview

从文本到图像:Stable Diffusion 简介

核心库

  • transformers: 主要用于处理文本任务。
  • diffusers: Hugging Face 推出的另一个核心库,专门用于处理扩散模型(Diffusion Models),如 Stable Diffusion,主要用于图像生成。

Stable Diffusion 的工作原理:去噪过程 (Denoising)

  • 比喻:就像米开朗基罗雕刻大卫像——从一块大理石中“去除”所有不属于大卫的部分。
  • 过程
    1. 起始状态:纯粹的噪声。想象一下老式电视机的雪花屏,但带有颜色。这是一个完全随机的、混乱的像素矩阵。
    2. 逐步去噪。模型会经过一系列步骤(通常是 20-50 步)。在每一步,它都会根据你的文本提示(Prompt),预测并去除图像中的一部分“噪声”,让图像离最终目标更近一点。
    3. 最终图像。经过所有步骤后,所有的噪声都被去除,剩下的就是根据你的提示生成的图像。
  • 为何会出现瑕疵?
    • 像“六指手”这样的问题,正是这个过程不完美的体现。考虑到模型是从完全的随机像素开始,仅凭文本指导就能逐步构建出一只手,即使多了一根手指,也已经相当惊人了。

Stable Diffusion 的关键组件

虽然 diffusers 库将复杂性封装得很好,但了解其背后的几个关键组件有助于我们更好地理解和控制生成过程。

  1. 文本编码器 (Text Encoder)
    • 作用:这部分与我们之前学习的 Transformer 完全一样。它负责将你的文本提示转换成模型能够理解的数字向量(Embeddings)。这个向量将作为指导,引导整个去噪过程。
  2. U-Net
    • 作用:这是扩散模型的核心神经网络。在去噪的每一步,U-Net 的任务是分析当前带有噪声的图像,并预测出噪声本身。然后系统会从图像中减去这个预测出的噪声。
  3. 调度器 (Scheduler)
    • 作用:它负责管理整个去噪过程的节奏。调度器决定了在每一步要添加或移除多少噪声,以及总共需要多少步。选择不同的调度器会影响生成速度和图像质量。
  4. 变分自编码器 (Variational Autoencoder, VAE)
    • 作用
      • 编码:在去噪过程开始前,VAE 将图像从高维的像素空间压缩到一个更小、更易于处理的 “潜空间”(Latent Space) 。所有去噪操作都在这个高效的潜空间中进行。
      • 解码:去噪过程完成后,VAE 再将潜空间中的表示解码回我们能看到的、完整的像素图像。

控制图像生成的核心参数

  • num_inference_steps (推理步数):
    • 控制去噪过程的总步数。
    • 步数少: 生成速度快,但图像质量可能较低,细节不足。
    • 步数多: 生成速度慢,但通常能得到质量更高、更精细的图像。
  • guidance_scale (引导尺度):
    • 控制生成图像与文本提示的符合程度
    • 值较低: 模型有更多的“创作自由”,可能会偏离提示。
    • 值较高: 模型会更严格地遵循提示,但可能导致图像缺乏创意或显得“呆板”。这与文本生成中的 temperature 概念类似。
  • heightwidth (图像尺寸):
    • 生成图像的高度和宽度。尺寸越大,所需的计算资源(特别是 VRAM)越多,生成时间也越长。

25-prompt-engineering-for-images

图像生成的提示工程 (Prompt Engineering)

与文本生成类似,提示(Prompt)的质量和结构对最终生成的图像效果有巨大影响。

推荐的提示结构

虽然没有硬性规定,但遵循一个结构化的提示通常能得到更好的结果。一个推荐的顺序是:

  1. 主题 (Subject): 你想画的核心内容是什么?(例如, "a pygmy hippo")
  2. 媒介/风格 (Medium/Style): 图像应该是什么风格?(例如, "ultra realistic cinematic photo", "watercolor painting", "Studio Ghibli style")
  3. 细节 (Details): 主题的具体特征。(例如, "wearing sunglasses")
  4. 环境 (Environment): 主题所处的场景。(例如, "jaywalking through a neon-lit downtown street at dusk")
  5. 构图 (Composition): 视角和画面布局。(例如, "wide-angle shot", "portrait")
  6. 光照 (Lighting): 场景的光线效果。(例如, "cinematic lighting")
  7. 质量词 (Quality Boosters): 一些常用于提升画面质量的词语(效果可能因模型而异)。(例如, "masterpiece", "high detail")

负向提示 (Negative Prompts)

这是图像生成中一个非常强大且独特的功能。

  • 概念:除了告诉模型你想要什么,你还可以明确地告诉它你不想要什么。
  • 工作原理:在去噪过程中,模型会主动远离负向提示中描述的概念的向量空间区域。
  • 常见用途
    • 去除瑕疵: extra limbs, blurry, grainy, low resolution
    • 去除干扰物: watermark, text, logo, cars, people
    • 控制风格: cartoon, anime (如果你想要写实风格)

性能优化技巧

在资源有限的环境(如免费 Colab 或个人电脑)下,可以采用一些技巧来降低 VRAM(显存)消耗,从而能够运行更大的模型或生成更大的图像。

  • 选择不同的调度器 (Scheduler):一些调度器在计算上更高效,可以用更少的步数达到相似的效果。
  • 注意力切片 (Attention Slicing):这是一种在计算注意力时分解计算过程的技术。它会稍微减慢生成速度,但能显著降低显存峰值。
  • CPU Offloading: 将模型中当前不活躍的部分从 GPU 显存暂时卸载到 CPU 内存中,在需要时再加载回来。这也能有效降低显存占用。

关键点: diffusers 库将这些复杂的优化封装成了简单的开关或参数,使得开发者可以轻松地在性能和资源消耗之间做出权衡。

26-generating-images-with-stable-diffusion

图像生成实战

环境准备

  • 切换运行时: 确保 Google Colab 的运行时已切换到 GPU(例如 T4)。
  • 安装依赖: 主要安装 diffusers, transformers 等库。
  • 设备检测: 代码中通常会检测是否有可用的 CUDA(NVIDIA GPU),并将计算设备设置为 GPU。

基础图像生成流程

  1. 选择模型:

    • 在 Hugging Face Hub 上有大量可用于文生图的模型,可以通过 text-to-image 标签筛选。
    • 使用 AutoPipelineForText2Image.from_pretrained(model_id) 来加载指定的 Stable Diffusion 模型。
  2. 性能优化:

    • 在加载模型时,可以传入参数如 torch_dtype=torch.float16(使用半精度浮点数),use_safetensors=True,以及启用 enable_attention_slicing() 等优化措施来降低显存占用。
  3. 定义提示 (Prompts):

    • 编写你的正向提示(你想看到什么)和可选的负向提示(你不想看到什么)。
  4. 生成图像:

    • 调用 pipeline 对象,传入提示和控制参数,例如:

      image = pipe(
          prompt=prompt,
          negative_prompt=negative_prompt,
          num_inference_steps=50,
          guidance_scale=7.5
      ).images[0]
      
      
  5. 显示图像:

    • 将生成的图像对象显示出来。

参数调试与实验

  • num_inference_steps (推理步数):
    • 实验: 尝试将步数从 50 降至 5。
    • 结果: 图像非常模糊和混沌,因为去噪过程进行得不够充分。
  • guidance_scale (引导尺度):
    • 实验: 尝试将该值调得非常低(如 1)或非常高。
    • 结果:
      • 低值: 图像内容可能与提示无关,变得非常抽象。
      • 高值: 图像会严格遵循提示,但可能显得生硬。
    • 结论: 调试这些参数是找到最佳效果的关键,就像在暗房里冲洗照片,需要不断尝试。

使用负向提示

  • 示例:
    • 正向提示: A cinematic photo of a pygmy hippo jaywalking...
    • 负向提示: blurry, grainy, low-res, extra limbs, cars, people...
  • 效果: 通过排除不希望出现的元素,负向提示能显著提升图像的整体质量和主题的突出性。

切换不同模型

  • Hugging Face Hub 上的每个模型都有其独特的“风格”和训练数据。
  • 实验: 在代码中,只需更改 model_id 字符串,就可以加载一个完全不同的模型(例如,一个专门用于生成动漫风格图像的模型)。
  • 结果: 即使使用完全相同的提示,不同的模型也会产生风格迥异的图像。这为创作提供了极大的灵活性。

核心体验: 图像生成是一个充满探索和乐趣的过程。通过调整提示、参数和模型,你可以像一个数字艺术家一样进行创作。不要害怕实验,最好的学习方式就是动手去“玩”。

27-image-to-image-generation

图生图 (Image-to-Image Generation)

概念

  • 除了从文本生成图像(Text-to-Image),Stable Diffusion 还可以以一张现有图像为基础,根据新的文本提示对其进行修改和转换,这个过程称为“图生图”(Image-to-Image)。

工作流程

  1. 创建基础图像: 首先,我们还是使用文生图(Text-to-Image)pipeline,根据一个简单的提示(例如, "a sketch of a house")生成一张初始图像。
  2. 编码至潜空间 (Latent Space): 将这张基础图像输入到图生图(Image-to-Image)pipeline。模型会使用 VAE 将其编码成潜空间的表示。
  3. 添加噪声: 模型会根据一个关键参数strength,向潜空间表示中添加一定量的噪声strength 值越高,添加的噪声就越多,原始图像的信息保留得就越少。
  4. 引导去噪: 接下来,模型会以这个“加了噪声的潜空间表示”为起点,根据你提供的新文本提示(例如, "a futuristic glass house with neon lights, cyberpunk style")进行去噪。
  5. 生成新图像: 去噪完成后,VAE 将潜空间表示解码回像素图像,得到最终结果。

关键参数:strength (强度)

  • 这个参数的取值范围是 0.0 到 1.0,它决定了对原始图像的修改程度
  • strength 值较低 (e.g., 0.3):
    • 添加的噪声很少,去噪过程主要是在恢复原始图像。
    • 新图像与原始图像非常相似,只会发生微小的变化。
  • strength 值中等 (e.g., 0.5 - 0.7):
    • 这是一个很好的平衡点。既保留了原始图像的基本构图和结构,又充分融入了新提示的风格和元素
  • strength 值较高 (e.g., 0.9):
    • 添加了大量的噪声,几乎完全“覆盖”了原始图像的信息。
    • 生成的图像可能与原始图像关系不大,更接近于直接用新提示进行文生图的结果。

实战演示

准备工作

  • 需要加载两个 pipeline:
    • StableDiffusionPipeline (用于文生图)
    • StableDiffusionImg2ImgPipeline (用于图生图)
  • 它们可以使用同一个基础模型。

步骤

  1. 使用文生图 pipeline 生成一张“房子的素描”作为基础图像
  2. 定义一个转换提示:"a futuristic glass house with neon lights, cyberpunk style"。
  3. 在一个循环中,使用图生图 pipeline,传入基础图像转换提示,并分别设置不同的 strength 值(如 0.5, 0.6, 0.9)。
  4. 将不同 strength 值下生成的图像并排展示,进行对比。

结论

  • 图生图是一个非常强大的创作工具,它允许你对图像进行风格转换、细节添加或概念重塑,同时保持对原始构图的控制。
  • 通过调整 strength,你可以精确地控制新旧元素之间的平衡。

扩展: Hugging Face Hub 上还提供了处理视频音频的模型和 pipeline,其基本原理与文本和图像处理是相通的,值得进一步探索。

28-training-stable-diffusion-with-dreambooth

DreamBooth: 轻量化定制你的 Stable Diffusion 模型

概念

  • DreamBooth 是一种参数高效微调(PEFT)技术,专门用于定制 Stable Diffusion 模型
  • 核心目标:让模型学会识别并生成一个特定的、新的主体(如你的宠物、一个特定物体或一种独特的风格),而这个主体是原始模型从未见过的。
  • 类比:
    • LoRA 是针对文本模型的轻量化微调技术。
    • DreamBooth 是针对图像生成模型的轻量化微调技术。

工作原理:“教会”模型一个新词

DreamBooth 的方法堪称一种巧妙的“黑客”技巧:

  1. 发明一个新词: 首先,你需要创造一个独一无二、毫无意义的词作为你想要教会模型的新主体的“代号”。例如,SKS dog 是一个经典例子。关键是这个词在模型的原始词汇表中必须不存在,以避免与现有概念冲突。本例中,我们使用 BonnabelleDog
  2. 提供少量样本: 你只需要提供 3 到 10 张包含你新主体的图片。这些图片将被用来训练模型。
  3. 建立关联: 在微调过程中,你告诉模型:“看,这些图片里的东西,就叫做 BonnabelleDog”。模型会学习将这个新发明的词(Token)与你提供的图像特征(如你家狗的外貌、毛色、形态)在潜空间中建立起强关联
  4. 使用新词生成图像: 训练完成后,只要你在提示中包含你发明的那个新词,模型就能够生成包含该特定主体的图像。例如,你可以写下提示 "A photo of a BonnabelleDog on the moon",模型就会生成一张你家狗在月球上的照片。

DreamBooth 实战流程

1. 准备工作

  • 安装依赖: 需要安装 diffusers 和其他一些特定于 DreamBooth 训练的库。
  • 上传训练图片:
    • 在 Google Colab 中,可以通过代码弹出一个文件上传窗口。
    • 选择 3-10 张清晰地展示你的主体的照片并上传。

2. 训练配置

  • 定义实例提示 (Instance Prompt): "a photo of a [V] dog",其中 [V] 是一个占位符,会被替换成你发明的那个独一无二的词,如 BonnabelleDog
  • (可选)先验保持 (Prior Preservation): 为了防止模型在学习新主体时“忘记”如何画普通的主体(例如,为了学画你的狗而忘记了如何画所有狗),可以同时使用一个类别提示 (Class Prompt),如 "a photo of a dog"。模型会生成一些普通的“狗”的图片,与你的特定狗的图片一起训练,这有助于保持模型的泛化能力。
  • 选择基础模型: 选择一个 Stable Diffusion 模型作为训练的基础。
  • 设置训练参数: 包括学习率、训练步数等。训练步数通常是 图片数量 * 100

3. 开始训练

  • 整个训练过程封装在一个训练循环中。根据 GPU 性能和图片数量,这个过程可能需要几分钟到半小时不等。
  • 训练完成后,微调过的模型(或适配器)会被保存在指定的目录中。

4. 推理与生成

  • 加载微调后的模型。
  • 编写包含你发明的新词的提示,例如:
    • "A photo of a BonnabelleDog flying through space with a cape."
    • "A BonnabelleDog as a submarine underwater."
  • 运行 pipeline,生成你定制的图像。

结果

  • 尽管训练数据极少,但 DreamBooth 能够以惊人的效果生成包含你定制主体的新图像。
  • 虽然在细节上可能不完美(例如,生成的斗篷可能看起来像头巾),但主体(你的狗)的核心特征会被很好地保留和再现。

结论: DreamBooth 极大地降低了个性化图像生成的门槛,让你能够以极低的成本将任何你喜欢的人、宠物或物体“注入”到强大的 AI 图像生成模型中,开启了无限的创意可能性。

29-Wrapping Up

AI 的两大应用方向:实用与创新

实用性应用 (Practical Things)

  • 从特定文档中提取数据。
  • 对内容进行任意分类。
  • 命名实体识别(如从文本中提取名词)。

创新性应用 (Creative Things)

  • 当前是 AI 发展的特殊时期,涌现出许多“疯狂、新颖、有趣”的事物,为创意提供了大量机会。
  • 交叉领域的探索是关键:不同媒介的结合是真正有趣的部分,例如将音频、视频与文本、图像进行混合和匹配。
  • 便捷的工具:Hugging Face Spaces 等平台,让用户可以像在 Google Colab 中一样轻松地运行和托管代码、使用 GPU 并分享成果。

超越大型基础模型:微调(Fine-tune)的力量

常见的思维定式

  • 一提到 AI,人们往往会立即想到大型基础模型(如 ChatGPT),并认为解决方案就是获取 API 密钥并对其进行封装。

微调的巨大价值:小即是美

  • 课程实例回顾: 在一个非常小的模型上微调引文风格。
  • 条件:
    • 小模型 (small model)
    • 小数据集 (small data set):仅 2500 条记录。
    • 低成本硬件: 在免费硬件上,仅需几分钟即可完成。
  • 成果:
    • 成功地将模型的输出从“杂乱无章的垃圾”转变为具有一致、正确结构的文本。
    • 证明了用非常有限的资源,也能实现显著的改变和优化。

核心启示

  • AI 的应用远不止封装大型模型的 API。
  • 利用小模型和小型数据集进行微调,同样能够在特定任务上实现强大且实用的效果。

AI 的核心价值:赋予非结构化数据结构

AI 的“大事件” (Big Thing)

  • AI 技术最核心、最重要的能力是能够轻松地将非结构化数据 (unstructured data) 转化为结构化数据

解决应用开发的“硬骨头” (Hard Part)

  • 在大多数应用程序的开发中,处理和结构化非结构化数据往往是最困难的部分。
  • AI 工具让解决这个核心难题变得非常简单和有效。