简要描述
本课程旨在帮助学生初步了解 OpenAI 的 ChatGPT、Google 的 Gemini、Anthropic 的 Claude 等生成式人工智能平台背后的基本运作原理。课程内容分为两部分:上半部分讲解生成式人工智能的理论原理,下半部分则通过运行开源模型进行实践操作,以验证理论知识。
目录
-
课程目标与生成式 AI 简介
-
语言模型:文字接龙
-
Token 与 Prompt 的定义
-
语言模型如何回答问题
-
语言模型生成答案的随机性
-
文字接龙的知识基础:语言知识与世界知识
-
语言模型背后的运作机制与参数
-
语言模型学习文字接龙的三个来源
-
为何语言模型只做文字接龙却能回答问题?Chat Template 的应用
-
语言模型的多轮对话功能
-
AI 幻觉与 RAG 技术简介
-
语言模型的局限性与 Prompt Engineering
-
System Prompt 与 User Prompt
-
生成式 AI 如何处理语音与图像
-
像素接龙与采样点接龙的计算成本与压缩方法
-
多模态生成:Token 化的统一
-
生成式人工智能的定义
-
生成式 AI 的基础套路:将生成问题化为分类问题
-
实作环节:使用开源语言模型
-
开源与非开源模型的区别
-
Hugging Face 平台介绍
-
Google Colab 操作指南
-
Hugging Face Transformers 套件
-
登录 Hugging Face 与模型下载
-
LLaMA 模型介绍与授权
-
Tokenizer 与 Model 的组成
-
Token 的词汇表大小与编解码
-
Token 与空格、大小写的关系
-
Encode/Decode 的差异:Begin of Text 符号
-
语言模型文字接龙实作
-
条件生成:Prompt 对 Token 概率分布的影响
-
连续生成多个 Token 与随机性
-
限制高概率的 Token 参与生成过程
-
model.generate 函数简介
-
加入 Chat Template 让模型正常回应
-
LLaMA 官方 Chat Template 的应用
-
官方 Chat Template 的 System Prompt 内容
-
调整 System Prompt 引导模型回应
-
强制模型说出特定内容
-
制作简易聊天机器人与执行复杂任务
-
多轮对话的历史记录传递
-
Pipeline 简化模型调用流程
-
更换为 Gemma 模型
课程目标与生成式 AI 简介
大家好,这堂课的目标是帮助大家搞懂生成式人工智能的原理。在日常生活中,大家或多或少都接触过生成式人工智能平台,比如 OpenAI 的 ChatGPT、Google 的 Gemini 或是 Anthropic 的 Claude。本课程希望让大家对这些平台背后的运作原理有基本的认识。
课程分为两部分:上半部分讲解原理,下半部分带领大家动手实作,通过运行一些开源模型来验证我们所学的理论。
目前,像 ChatGPT、Gemini 这类平台最基本的功能是:你输入一段文字(比如一个问题),它会给你一个回应。虽然“输入文字、输出文字”听起来简单,但其应用却千变万化,可以用来写邮件、检查语法错误,甚至辅助完成作业。当然,除了文字,这些平台的输入也可以是语音或图像,输出同样如此。我们首先聚焦于文字的输入输出,之后再探讨语音和图像的处理方式。
像 GPT、Gemini 和 Claude 这类人工智能,其核心都是语言模型。
语言模型:文字接龙
那么,什么是语言模型呢?简单来说,它就是一个进行“文字接龙”的人工智能。实际上,像 GPT 这类 AI 的核心功能只有一项:文字接龙。你给它一个未完成的句子,它会预测下一个最可能出现的字词。
例如,你输入“人工智能”,它可能会接上“慧”;输入“大型语言模”,它会接上“型”;输入“欢迎大家今天来上”,它则会接上“课”。
Token 与 Prompt 的定义
在文字接龙的过程中,模型可供选择输出的基本单位,有一个专门的术语叫做 Token。在生成式 AI 领域,Token 指的就是模型在进行文字接龙时可以选择的输出单元。而我们提供给语言模型的、未完成的句子或输入,则被称为 Prompt。
所以,语言模型真正做的事情,就是接收一个 Prompt,然后预测下一个最合适的 Token 是什么。
语言模型如何回答问题
语言模型是如何回答问题的呢?当你问 ChatGPT “台湾最高的山是哪座?”时,它实际上是将你的问题作为一个未完成的句子,然后开始文字接龙。
-
输入 Prompt:“台湾最高的山是哪座?”
-
预测第一个 Token:模型可能会预测出“玉”。
-
更新 Prompt:此时,新的 Prompt 变成了“台湾最高的山是哪座?玉”。
-
预测第二个 Token:模型接着预测出“山”。
-
再次更新 Prompt:Prompt 变为“台湾最高的山是哪座?玉山”。
-
结束生成:此时,模型可能会觉得句子已经完整,便会输出一个代表“结束”的特殊符号,接龙过程就此停止。
你在使用语言模型时,它就是这样一步步进行文字接龙,直到输出一个结束符号,整个过程产生的 Token 序列组合起来,就是它的最终答案。
语言模型生成答案的随机性
你可能会想,对于一个 Prompt,后面可以接的 Token 应该有很多种可能。比如,输入“人工”,后面可以接“智”(人工智能),也可以接“呼”(人工呼吸)。模型是如何选择的呢?
实际上,当语言模型接收一个 Prompt 时,它输出的并不是一个确定的 Token,而是一个包含所有可能 Token 的概率分布。它会为词汇表(Vocabulary)中的每一个 Token 计算一个概率分数,表示这个 Token 出现在当前 Prompt 后面的可能性大小。
例如,对于 Prompt“人工”,模型可能会计算出:
-
“智”的概率是 50%
-
“呼”的概率是 20%
-
英文单词“how”的概率非常低
-
韩文或日文符号的概率也非常低
得到这个概率分布后,模型会像掷骰子一样,根据这些概率随机选择一个 Token 作为输出。正因为每次生成 Token 都带有随机性,所以即使你向 ChatGPT 问同一个问题,每次得到的答案也可能略有不同。
你也不必过于担心它会生成完全离谱的答案,比如问“台湾最高的山是哪座?”却回答“冰淇淋”。因为“冰”这个 Token 出现在该问题后面的概率极低,几乎不可能被选中。
文字接龙的知识基础:语言知识与世界知识
不要认为文字接龙是一件简单的事情。一个 AI 要想准确地完成文字接龙,至少需要具备两方面的知识:
-
语言知识:它必须理解人类语言的语法规则,知道什么样的词汇后面可以接什么样的词汇。例如,“黄色”后面更可能接名词,而不是动词。
-
世界知识:仅有语言知识是不够的,否则模型可能会生成语法正确但毫无意义的句子。它还需要对真实世界有认知。例如,当 Prompt 是“水的沸点是摄氏”时,模型需要知道“100”这个数字的概率远高于其他数字。
语言知识相对容易学习,只要有足够大的语料库(例如上百万篇文章),模型通常就不会犯语法错误。但世界知识的学习则困难得多,因为它几乎是无穷无尽的。例如,如果 Prompt 变为“在 0.5 大气压下,水的沸点是摄氏”,模型就必须知道此时的答案不再是 100 度,这需要更深层次的物理知识。
语言模型背后的运作机制与参数
我们可以将语言模型看作一个复杂的函数,记为 f。就像我们熟悉的函数 一样,这里的 x 就是输入的 Prompt,而 f(x) 就是输出的概率分布。决定这个函数行为的是大量的内部参数(Parameters),类似于 a 和 b。
由于语言的复杂性,大型语言模型的参数数量极其庞大,通常以“十亿”甚至“百亿”为单位。这些参数并非人工设定,而是通过在海量数据上进行“机器学习”自动获得的。
语言模型学习文字接龙的三个来源
语言模型学习文字接龙的能力主要来自三个方面:
-
海量网络数据:模型从互联网上抓取海量文本数据。每一句话都可以成为学习文字接龙的教材。例如,读到“人工智能真神奇”,模型就学会了“人工”后面可以接“智”。
-
人工标注数据:开发者会提供一些高质量的“问题-答案”对,直接告诉模型在特定 Prompt 后应该接什么。例如,明确标注“台湾最高的山是?”后面应该接“玉山”。
-
用户反馈:当你在使用 ChatGPT 等平台时,可以对它的回答点“赞”或“踩”。这些反馈会被用来调整模型,让它知道哪些回答是好的,哪些是不好的,从而优化未来生成答案的概率。
为何语言模型只做文字接龙却能回答问题?Chat Template 的应用
你可能会困惑,如果模型只是在做文字接龙,为什么它总能准确地回答问题,而不是续写问题呢?例如,对于“台湾最高的山是哪座?”,为什么它不接“谁来告诉我呀?”或者出一个选择题呢?
原因是,当你通过平台与模型互动时,你输入的 Prompt 并不是模型看到的全部内容。平台通常会在你的 Prompt 前后自动添加一些额外信息,这被称为 Chat Template(聊天模板)。
例如,你输入“台湾最高的山是哪座?”,平台可能会将其处理成:
用户:台湾最高的山是哪座? AI 助手:
这样一来,模型看到的完整 Prompt 最后是“AI 助手:”,它进行文字接龙时,自然就会生成问题的答案了。每个模型都有自己特定的 Chat Template,这也是它们能够以对话形式进行有效沟通的关键。
语言模型的多轮对话功能
语言模型是如何实现多轮对话(记住上下文)的呢?当你问完“台湾最高的山是哪座?”,它回答“玉山”后,你接着问“那第二高的呢?”,它知道你问的是“台湾第二高的山”。
这是因为在每一轮对话中,平台都会将之前所有的对话历史记录和你的新问题一起作为完整的 Prompt 发送给模型。模型看到的是整个对话过程,所以它能够理解上下文,并给出相关的回答。不过,这种记忆通常仅限于当前会话,一旦开启新的聊天,历史记录就会被清空。
AI 幻觉与 RAG 技术简介
由于语言模型的核心是基于概率的文字接龙,它并不具备真正的知识库或事实核查能力。因此,它有时会“一本正经地胡说八道”,编造出一些不存在的事实、链接或引用。这种现象被称为 AI 幻觉 (Hallucination)。
理解了它的原理后,你就会明白,模型的所有回答本质上都是一种“幻觉”。我们应该惊讶的是,它的“幻觉”竟然常常与现实相符。
为了减少幻觉,现在普遍采用一种名为 RAG (Retrieval-Augmented Generation) 的技术。其基本思想是,在生成答案之前,先利用搜索引擎检索相关信息,然后将这些信息作为上下文一起提供给语言模型,引导它生成更准确、基于事实的回答。
语言模型的局限性与 Prompt Engineering
我们应将语言模型想象成一个被关在小黑屋里的人,他从未见过外面的世界,唯一的技能就是根据你给的纸条(Prompt)续写文字。因此,对于需要外部实时信息的问题,比如“今天几月几号?”,它无法给出准确答案,只能随机猜测。
这就引出了 Prompt Engineering 的概念。作为使用者,我们有责任在 Prompt 中提供足够、清晰的信息,确保模型有充分的上下文来生成正确的接龙。
System Prompt 与 User Prompt
为了解决实时信息的问题,并对模型的行为进行宏观指导,平台通常会在你看不见的地方预设一些信息。这些由开发者设定的、在每次对话中都会自动添加的 Prompt,被称为 System Prompt。例如,它可能包含当前日期、模型的身份设定(“你是一个乐于助人的助手”)等。
而由用户直接输入的 Prompt,则被称为 User Prompt。模型最终看到的,是 System Prompt 和 User Prompt 组合后的完整内容。
生成式 AI 如何处理语音与图像
生成式 AI 不仅能处理文字,还能生成图像和声音。其背后的原理与文字接龙一脉相承,可以理解为“像素接龙”或“采样点接龙”。
-
生成图像:将图像看作由一个个像素点组成,模型可以逐个像素地生成,最终构成一张完整的图片。
-
生成声音:将声音看作由一系列采样点构成,模型可以逐个预测采样点,最终合成一段连贯的音频。
早在多年前,就已经有技术通过这种方式生成宝可梦图片或非常逼真的语音(如 Google DeepMind 的 WaveNet)。
像素接龙与采样点接龙的计算成本与压缩方法
然而,直接进行像素或采样点接龙的计算成本极高。生成一张 1024x1024 的图片需要进行上百万次接龙,比写一部《红楼梦》还要复杂。生成一分钟的音频也需要上百万次的采样点接龙。
因此,现代的方法是先对图像或声音进行压缩。通过一个编码器(Encoder),将一小块像素(如 16x16)或一小段音频(如 0.02 秒)压缩成一个 Token。这样,模型只需要对这些更高维度的 Token 进行接龙,大大降低了计算量。生成 Token 序列后,再通过一个解码器(Decoder)将其还原为图像或声音。
多模托态生成:Token 化的统一
通过这种方式,无论是文字、图像块还是音频片段,都可以被统一表示为 Token。这使得模型可以在不同模态之间进行转换。例如,将一张图片的 Token 和一段文字的 Token 拼接在一起,输入给模型,它就能生成新的图片 Token,从而实现根据文字指令修改图片的功能。
正如英伟达 CEO 黄仁勋所说:“万事万物皆可 Token”。这正是生成式 AI 的核心思想:将世间万物表示为 Token 序列,通过接龙的方式进行生成。
生成式人工智能的定义
综上所述,我们可以为生成式人工智能下一个定义:让机器学会生成复杂且有结构的对象。这里的“有结构”指的是对象由有限种类的基本单位(Token)构成,但这些单位的组合却能产生无穷无尽的可能性。
我们期待的不仅是生成,更是根据输入进行条件生成(输入 X,生成 Y),这是实现各种实用应用的基础。
生成式 AI 的基础套路:将生成问题化为分类问题
生成式 AI 的问题看似复杂,因为输出 Y 的可能性是无限的。但通过 Token 化的思想,我们可以将其简化。因为构成 Y 的每一个 Token 都是从一个有限的词汇表(Vocabulary)中选择的。
因此,生成一个复杂的对象 Y,可以被拆解为一系列选择题:在每一步,根据已有的输入和已生成的 Token,从词汇表中选择下一个最合适的 Token。这个问题在机器学习中被称为分类问题,已经有非常成熟的解决方案。
我们今天主要讨论的“文字接龙”式生成策略,其专业术语是 Auto-Regressive Generation。当然,也存在其他生成策略,例如在图像生成领域常见的 Diffusion Model。
实作环节:使用开源语言模型
接下来,我们进入课程的后半部分,学习如何使用开源的语言模型。
开源与非开源模型的区别
-
非开源模型:如 ChatGPT、Gemini 等,我们只能通过它们的 API 或网页界面与之交互,无法得知其内部的参数和具体结构。
-
开源模型:如 Meta 的 LLaMA、Google 的 Gemma 等,它们的模型参数是公开的,我们可以下载并在自己的设备上运行,完全了解其内部结构。
Hugging Face 平台介绍
Hugging Face 是一个著名的开源模型和数据集平台,可以说是“模型的 Facebook”。我们可以在上面找到、下载并使用各种各样的开源模型。
Google Colab 操作指南
我们将使用 Google Colab 作为实作平台。这是一个云端的 Python 编程环境,提供了免费的 GPU 资源,非常适合运行大型语言模型。
当你拿到 Colab 笔记本时,首先应在“文件”菜单中选择“在云端硬盘中保存副本”,以确保你可以在自己的副本上进行修改和运行。其次,检查“执行阶段”->“更改运行时类型”,确保已选择 GPU 作为硬件加速器。GPU 的性能越好,模型运行速度越快。
Hugging Face Transformers 套件
我们将使用由 Hugging Face 开发的 Transformers 库。这是一个功能强大的工具包,可以方便地加载和使用 Hugging Face 平台上的所有模型,无论它们最初是用什么深度学习框架(如 PyTorch 或 JAX)训练的。
登录 Hugging Face 与模型下载
要从 Hugging Face 下载模型,首先需要注册一个账户并生成一个访问凭证(Access Token)。然后在 Colab 中登录你的账户。
之后,就可以指定要下载的模型的 ID(例如 meta-llama/Meta-Llama-3-8B-Instruct),并使用 Transformers 库将模型和对应的 Tokenizer 下载到本地。
LLaMA 模型介绍与授权
我们将以 Meta 的 LLaMA 系列模型为例。模型名称中的数字(如 3.2)代表版本,8B 代表模型有 80 亿个参数,Instruct 表示该模型经过指令微调,更擅长遵循指令和进行对话。
使用 LLaMA 模型前,需要在其 Hugging Face 页面上申请并获得使用授权。
Tokenizer 与 Model 的组成
下载模型时,通常会得到两个核心组件:
-
Tokenizer (分词器):它定义了模型的词汇表(Vocabulary),并负责将文本与 Token ID(数字编号)进行相互转换。
-
Model (模型):它包含了模型的所有参数,是执行文字接龙任务的核心。
Token 的词汇表大小与编解码
我们可以通过 tokenizer.vocab_size 查看模型词汇表的大小。例如,LLaMA 3 8B 模型的词汇表大约有 12.8 万个 Token。
每个 Token 都有一个唯一的 ID。我们可以使用 tokenizer.decode() 将 ID 转换为对应的文本,使用 tokenizer.encode() 将文本转换为 ID 序列。
词汇表中包含了各种语言的文字、符号、表情符号,甚至是一些奇怪的字符组合。有些是单个汉字,有些是英文单词或词根,还有一些是特殊的控制符号。
Token 与空格、大小写的关系
Tokenizer 的处理方式非常精细。例如:
-
大小写不同的同一个单词(如
Hi,hi,HI)会被视为不同的 Token。 -
同一个单词,如果前面有空格(如 " am good" 中的 "good")和没有空格(如 "good morning" 中的 "good"),也可能被视为不同的 Token。
Encode/Decode 的差异:Begin of Text 符号
当你使用 tokenizer.encode() 时,它默认会在文本的开头添加一个特殊的起始符号(如 <|begin_of_text|>)。因此,将一段文本先 encode 再 decode,得到的结果会比原文多一个起始符。如果不需要这个符号,可以在 encode 时设置参数 add_special_tokens=False。
语言模型文字接龙实作
模型本身就像一个函数,它的输入是 Token ID 序列,输出是下一个 Token 的概率分布。
基本流程如下:
-
编码:使用
tokenizer.encode()将输入的 Prompt(如 "1+1=")转换为 Token ID 序列。 -
推理:将该 ID 序列输入到
model中,得到一个包含所有 Token 概率分数的输出。 -
分析:从输出中提取概率最高的几个 Token。
实验发现,对于 Prompt "1+1=",模型预测下一个 Token 是 "2" 的概率最高(约 65.7%)。
条件生成:Prompt 对 Token 概率分布的影响
Prompt 的内容会极大地影响模型的输出。如果我们将 Prompt 改为“在二进制中,1+1=”,模型会准确地预测出下一个 Token 是“10”的概率最高(约 70.1%),而“2”的概率则变得微乎其微。这表明模型能够理解上下文并作出相应的推理。
连续生成多个 Token 与随机性
要生成一段完整的回答,我们需要进行循环操作:
-
根据当前 Prompt 预测下一个 Token。
-
将新生成的 Token 添加到 Prompt 的末尾。
-
重复以上步骤,直到生成结束符号或达到预设长度。
在选择下一个 Token 时,我们不总是选择概率最高的那个,而是根据概率分布进行随机采样(掷骰子)。这样做可以使模型的回答更加多样化,避免每次都生成完全相同的答案。
限制高概率的 Token 参与生成过程
完全随机的采样有时会导致模型选中概率极低的 Token,从而使后续的生成内容变得混乱。因此,在实际应用中,通常会采用一种折中的策略,比如 Top-K Sampling:只在概率最高的 K 个 Token 中进行随机采样。这样既保证了多样性,又避免了生成过于离谱的内容。
model.generate 函数简介
为了简化连续生成的过程,Transformers 库提供了一个非常方便的函数:model.generate()。我们只需要将编码后的 Prompt ID 输入给它,它就会自动完成循环生成的所有步骤,并返回一个完整的 Token ID 序列。
我们可以通过设置 max_length、do_sample、top_k 等参数来控制生成的长度和采样策略。
加入 Chat Template 让模型正常回应
如果直接将问题(如“你是谁?”)作为 Prompt 输入,模型很可能会续写问题(如“你是谁的朋友?”),而不是回答问题。
为了让模型以对话的形式进行回应,我们需要使用 Chat Template。将用户的输入包装在模板中,明确指出这是“用户”说的话,并提示接下来轮到“AI 助手”回答。
LLaMA 官方 Chat Template 的应用
每个模型都有其官方推荐的 Chat Template。自己随意发明的模板效果可能不佳。Transformers 库中的 tokenizer.apply_chat_template() 函数可以方便地将我们的对话内容应用上官方模板,并自动完成编码。
官方 Chat Template 的 System Prompt 内容
使用官方模板时,通常会自动加入一个 System Prompt。例如,LLaMA 的 System Prompt 可能包含了模型的知识截止日期和当前日期等信息。这解释了为什么模型有时能回答关于日期的问题,或者会说自己的知识有限。
调整 System Prompt 引导模型回应
我们可以自定义 System Prompt 来引导模型的行为。例如,如果模型不知道自己的名字,我们可以在 System Prompt 中加入一句:“你的名字是 LLaMA”。这样,当被问及身份时,它就会正确回答。
强制模型说出特定内容
我们甚至可以在对话历史中“伪造”模型的回答,强制它从某个特定的句子开始接龙。这是一种高级的 Prompt Engineering 技巧,可以用来绕过模型的某些安全限制或引导其生成特定风格的内容。
制作简易聊天机器人与执行复杂任务
通过循环接收用户输入,将其与完整的对话历史应用 Chat Template,然后调用 model.generate() 生成回答,我们就可以构建一个功能完备的多轮聊天机器人。
这个机器人不仅能进行简单问答,也能完成更复杂的任务,比如根据指令编写一段排序算法的代码。
多轮对话的历史记录传递
实现多轮对话的关键在于,在每一轮生成时,都必须将从开始到当前的所有对话历史(包括用户的提问和模型的回答)全部提供给模型。这样,模型才能拥有上下文记忆。
Pipeline 简化模型调用流程
为了进一步简化操作,Transformers 库提供了 Pipeline(管道)功能。它将编码、模型推理和解码等一系列步骤封装在一起。我们只需要创建一个 text-generation 的 pipeline,然后就可以直接将对话列表输入,直接获得文本输出,无需手动处理 Token ID。
更换为 Gemma 模型
使用 Pipeline 的另一个好处是更换模型非常方便。我们只需要在创建 Pipeline 时,将 model 参数从 LLaMA 的 ID 更换为 Google 的 Gemma 模型 ID(如 google/gemma-7b-it),就可以无缝切换到另一个性能更强的模型。
