【Datawhale X 魔搭AI夏令营】大模型应用开发方向 Task 1

目录

写在前面

背景知识

概念

构建过程

预训练

有监督微调

基于人类反馈的强化学习对齐--RLHF

示例:开源大模型Llama-2-Chat训练过程

开源大模型和闭源大模型

源大模型开源体系

大模型时代挖掘模型能力的开发范式

1. Prompt工程

两种技术

2. Embedding辅助,给LLM外界大脑

大模型的若干局限性

3. 参数高效微调

大模型应用开发必知必会

客户端

Gradio

Streamlit

大致组件

服务端

服务端的两种方式

直接调用大模型API

大模型本地部署

选哪种

baseline精读

完整代码

方案设计

概要

详细设计

尝试替换其他大模型

代码替换


写在前面

  • 学习内容提要:通过学习大模型部署【搭建你的智能编程助手】、大模型检索增强生成(Retrieval Augmented Generation, RAG)实战【搭建你的AI科研助手】、大模型微调实战【搭建你的AI简历助手】,掌握大模型应用全栈开发

背景知识

概念
  • 为了对人类语言的内在规律进行建模,研究者们提出使用语言模型(language model)来准确预测词序列中 下一个词 或者 缺失的词 的概率

  • 大语言模型(Large Language Model, LLM):基于“扩展法则”(Scaling Law),即通过增加模型参数或训练数据,可以提升下游任务的性能,同时具有小模型不具有的“涌现能力”(Emergent Abilities)。代表性工作:GPT-3、ChatGPT、Claude、Llama

构建过程
  • 大模型的构建过程可以分为预训练(Pretraining)、有监督微调(Supervised Fine-tuning, SFT)、基于人类反馈的强化学习对齐(Reinforcement Learning from Human Feedback, RLHF)三个阶段

预训练
  • 预训练指使用海量的数据进行模型参数的初始学习,旨在为模型参数寻找到一个优质的“起点”

有监督微调
  • 经过大规模预训练后,模型已经具备较强的模型能力,能够编码丰富的世界知识

  • 但是由于预训练任务形式所限,这些模型更擅长于文本补全,并不适合直接解决具体的任务

  • 该方法利用成对的任务输入与预期输出数据,训练模型学会以问答的形式解答问题,从而解锁其任务解决潜能

  • 指令微调并非无中生有地传授新知,而是更多地扮演着催化剂的角色,激活模型内在的潜在能力,而非单纯地灌输信息

基于人类反馈的强化学习对齐--RLHF
  • 核心:构建一个反映人类价值观的奖励模型(Reward Model)

  • 这一模型的训练依赖于专家对模型多种输出的偏好排序,通过偏好数据训练出的奖励模型能够有效评判模型输出的质量

示例:开源大模型Llama-2-Chat训练过程
  • 起始:利用公开数据进行预训练,获得Llama-2

  • 此后:通过有监督微调创建了Llama-2-Chat的初始版本

  • 随后:使用基于人类反馈的强化学习(RLHF)方法来迭代地改进模型

    • 具体包括:

      • 拒绝采样(Rejection Sampling)

      • 近端策略优化(Proximal Policy Optimization, PPO)

    • RLHF阶段,人类偏好数据也在并行迭代,以保持奖励模型的更新

开源大模型和闭源大模型

  • 构建大模型不仅需要海量的数据,更依赖于强大的计算能力

  • 两类机构:

    • 一是选择将模型开源的组织

      • 代表:Meta AI、浪潮信息

    • 另一类则是保持模型闭源的公司

      • 通常伴随着专有技术和服务

      • 企业可以通过API等方式提供给客户使用

      • 不直接公开模型的细节或代码

      • 代表:OpenAI、百度等

源大模型开源体系

大模型时代挖掘模型能力的开发范式

1. Prompt工程
  • 精心构造提示(Prompt),直接调教大模型,解决实际问题

两种技术
  • 上下文学习(In-Context Learning, ICL):将任务说明及示例融入提示文本之中,利用模型自身的归纳能力,无需额外训练即可完成新任务的学习

  • 思维链提示(Chain-of-Thought, CoT):引入连贯的逻辑推理链条至提示信息内,显著增强了模型处理复杂问题时的解析深度与广度

2. Embedding辅助,给LLM外界大脑
大模型的若干局限性
  • 知识局限性:大模型的知识来源于训练数据,而这些数据主要来自于互联网上已经公开的资源,对于一些实时性的或者非公开的,由于大模型没有获取到相关数据,这部分知识也就无法被掌握。

  • 数据安全性:为了使得大模型能够具备相应的知识,就需要将数据纳入到训练集进行训练。然而,对于企业来说,数据的安全性至关重要,任何形式的数据泄露都可能对企业构成致命的威胁。

  • 大模型幻觉:由于大模型是基于概率统计进行构建的,其输出本质上是一系列数值运算。因此,有时会出现模型“一本正经地胡说八道”的情况,尤其是在大模型不具备的知识或不擅长的场景中。

3. 参数高效微调
  • 也被称为指令微调(Instruction Tuning)或者有监督微调(Supervised Fine-tuning, SFT)

  • 首先需要构建指令训练数据,然后通过有监督的方式对大模型的参数进行微调。经过模型微调后,大模型能够更好地遵循和执行人类指令,进而完成下游任务

  • 由于大模型的参数量巨大, 进行全量参数微调需要消耗非常多的算力 → 提出了参数高效微调(Parameter-efficient Fine-tuning) / 轻量化微调 (Lightweight Fine-tuning)

  • 方法通过训练极少的模型参数,同时保证微调后的模型表现可以与全量微调相媲美

大模型应用开发必知必会

客户端服务端
用户请求→gradio输入→大模型API
←回复streamlit←输出大模型本地部署
客户端
  • 客户端需要接受用户请求,并且能将回复返回给用户

  • 通常使用 GradioStreamlit 进行开发

Gradio
  • 输入输出组件、控制组件、布局组件几个基础模块

    • 输入输出组件用于展示内容和获取内容,如:Textbox文本、Image图像

    • 布局组件用于更好地规划组件的布局,如:Column(把组件放成一列)、Row(把组件放成一行)

      • 推荐使用gradio.Blocks()做更多丰富交互的界面,gradio.Interface()只支持单个函数交互

    • 控制组件用于直接调用函数,无法作为输入输出使用,如:Button(按钮)、ClearButton(清除按钮)

设计哲学:

将输入和输出组件与布局组件分开。

输入组件(如TextboxSlider等)用于接收用户输入

输出组件(如LabelImage等)用于显示函数的输出结果

布局组件(如TabsColumnsRow等)则用于组织和排列这些输入和输出组件,以创建结构化的用户界面

Streamlit
  • 官网: Streamlit 官方

  • Streamlit 中没有gradio的输入和输出概念,也没有布局组件的概念

  • Streamlit每个组件都是独立的,需要用什么直接查看官方文档

大致组件
  • 页面元素

    • 文本

    • 数据表格

    • 图标绘制(柱状图,散点图等等)

    • 输入(文本框,按钮,下拉框,滑块,复选框,文件上传,等等)

    • 多媒体(图片,音频,视频)

    • 布局和容器

    • Chat(聊天对话控件)

    • 状态(进度条,加载中,等等元素)

    • 第三方组件(提供了更加丰富的组件)

  • 应用逻辑

    • 导航和页面(可以切换页面)

    • 执行流程

    • 缓存和状态

    • 连接和加密(可连接数据库,也可以对内容进行加密处理)

    • 自定义组件

    • 公共组件(用户信息存储,帮助,以及输出html)

    • Config(使用配置文件,来定义一些内容)

  • 工具

    • 应用测试

    • 命令行

服务端
  • 服务端需要与大模型进行交互,大模型接受到用户请求后,经过复杂的计算,得到模型输出

服务端的两种方式
直接调用大模型API
  • 将请求直接发送给相应的服务商,如openai,讯飞星火等,等待API返回大模型回复

  • ✔️ 优点:

    1. 便捷性: 不需要关心模型的维护和更新,服务商通常会负责这些工作。

    2. 资源效率: 避免了本地硬件投资和维护成本,按需付费,灵活调整成本支出。

    3. 稳定性与安全性: 专业团队管理,可能提供更好的系统稳定性和数据安全性措施。

    4. 扩展性: API服务易于集成到现有的应用和服务中,支持高并发请求。

  • ✖️ 缺点:

    1. 网络延迟: 需要稳定的网络连接,可能会受到网络延迟的影响。

    2. 数据隐私: 数据需要传输到服务商的服务器,可能涉及数据安全和隐私问题。

    3. 成本控制: 高频次或大量数据的调用可能会导致较高的费用。

    4. 依赖性: 受制于服务商的政策变化,如价格调整、服务条款变更等。

大模型本地部署
  • 在本地GPU或者CPU上,下载模型文件,并基于推理框架进行部署大模型

  • ✔️ 优点:

    1. 数据主权: 数据完全在本地处理,对于敏感数据处理更为安全。

    2. 性能可控: 可以根据需求优化配置,减少网络延迟,提高响应速度。

    3. 成本固定: 初始投入后,长期运行成本相对固定,避免了按使用量付费的不确定性。

    4. 定制化: 更容易针对特定需求进行模型微调或扩展。

  • ✖️ 缺点:

    1. 硬件投资: 需要强大的计算资源,如高性能GPU,初期投资成本较高。

    2. 运维复杂: 需要自行管理模型的更新、维护和故障排查。

    3. 技术门槛: 对于非专业团队而言,模型的部署和优化可能较为复杂。

    4. 资源利用率: 在低负载情况下,本地硬件资源可能无法充分利用。

选哪种

选择哪种方式取决于具体的应用场景、数据敏感性、预算以及对延迟和性能的需求

baseline精读

完整代码
 # 导入所需的库
 from transformers import AutoTokenizer, AutoModelForCausalLM
 import torch
 import streamlit as st
 ​
 # 创建一个标题和一个副标题
 st.title("💬 Yuan2.0 智能编程助手")
 ​
 # 源大模型下载
 from modelscope import snapshot_download
 model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='./')
 # model_dir = snapshot_download('IEITYuan/Yuan2-2B-July-hf', cache_dir='./')
 ​
 # 定义模型路径
 path = './IEITYuan/Yuan2-2B-Mars-hf'
 # path = './IEITYuan/Yuan2-2B-July-hf'
 ​
 # 定义模型数据类型
 torch_dtype = torch.bfloat16 # A10
 # torch_dtype = torch.float16 # P100
 ​
 # 定义一个函数,用于获取模型和tokenizer
 @st.cache_resource
 def get_model():
     print("Creat tokenizer...")
     tokenizer = AutoTokenizer.from_pretrained(path, add_eos_token=False, add_bos_token=False, eos_token='<eod>')
     tokenizer.add_tokens(['<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>','<commit_before>','<commit_msg>','<commit_after>','<jupyter_start>','<jupyter_text>','<jupyter_code>','<jupyter_output>','<empty_output>'], special_tokens=True)
 ​
     print("Creat model...")
     model = AutoModelForCausalLM.from_pretrained(path, torch_dtype=torch_dtype, trust_remote_code=True).cuda()
 ​
     print("Done.")
     return tokenizer, model
 ​
 # 加载model和tokenizer
 tokenizer, model = get_model()
 ​
 # 初次运行时,session_state中没有"messages",需要创建一个空列表
 if "messages" not in st.session_state:
     st.session_state["messages"] = []
 ​
 # 每次对话时,都需要遍历session_state中的所有消息,并显示在聊天界面上
 for msg in st.session_state.messages:
     st.chat_message(msg["role"]).write(msg["content"])
 ​
 # 如果用户在聊天输入框中输入了内容,则执行以下操作
 if prompt := st.chat_input():
     # 将用户的输入添加到session_state中的messages列表中
     st.session_state.messages.append({"role": "user", "content": prompt})
 ​
     # 在聊天界面上显示用户的输入
     st.chat_message("user").write(prompt)
 ​
     # 调用模型
     prompt = "<n>".join(msg["content"] for msg in st.session_state.messages) + "<sep>" # 拼接对话历史
     inputs = tokenizer(prompt, return_tensors="pt")["input_ids"].cuda()
     outputs = model.generate(inputs, do_sample=False, max_length=1024) # 设置解码方式和最大生成长度
     output = tokenizer.decode(outputs[0])
     response = output.split("<sep>")[-1].replace("<eod>", '')
 ​
     # 将模型的输出添加到session_state中的messages列表中
     st.session_state.messages.append({"role": "assistant", "content": response})
 ​
     # 在聊天界面上显示模型的输出
     st.chat_message("assistant").write(response)
方案设计
概要
  • baseline基于源大模型的编程能力来解决用户的问题

  • 主要包含:一个Streamlit开发的客户端,一个部署好浪潮源大模型的服务端

  • 客户端接收到用户请求后,首先进行交互历史拼接,然后输入到服务端的浪潮源大模型,得到模型输出结果后,返回给客户端,用于回复用户的问题

详细设计
导入库↓导入所需要的依赖,包括 TRANSFORMERSTORCHSTREAMLIT。其中TORCH 魔搭本身已经安装,TRANSFORMERSSTREAMLIT在第二步也安装完毕
模型下载↓Yuan2-2B-Mars支持通过多个平台进行下载,包括魔搭、HuggingFace、OpenXlab、百度网盘、WiseModel等。因为我们的机器就在魔搭,所以这里我们直接选择通过魔搭进行下载。模型在魔搭平台的地址为 IEITYuan/Yuan2-2B-Mars-hf。 模型下载使用的是 modelscope 中的 snapshot_download 函数,第一个参数为模型名称 IEITYuan/Yuan2-2B-Mars-hf,第二个参数 cache_dir 为模型保存路径,这里.表示当前路径。 模型大小约为4.1G,由于是从魔搭直接进行下载,速度会非常快。下载完成后,会在当前目录增加一个名为 IEITYuan 的文件夹,其中 Yuan2-2B-Mars-hf 里面保存着我们下载好的源大模型。
模型加载↓使用 transformers 中的 from_pretrained 函数来加载下载好的模型和tokenizer,并通过 .cuda() 将模型放置在GPU上。另外,这里额外使用了 streamlit 提供的一个装饰器 @st.cache_resource ,它可以用于缓存加载好的模型和tokenizer
读取用户输入↓使用 streamlit 提供的 chat_input() 来获取用户输入,同时将其保存到对话历史里,并通过st.chat_message("user").write(prompt) 在聊天界面上进行显示
对话历史拼接对于 Yuan2-2B-Mars 模型来说,输入需要在末尾添加 <sep>,模型输出到 <eod> 结束。如果输入是多轮对话历史,需要使用 <n> 进行拼接,并且在末尾添加 <sep>
模型调用输入的prompt需要先经tokenizer切分成token,并转成对应的id,并通过 .cuda() 将输入也放置在GPU上。然后调用 model.generate() 生成输出的id,并通过 tokenizer.decode() 将id转成对应的字符串。最后从字符串中提取模型生成的内容(即 <sep> 之后的字符串),并删除末尾的 <eod> ,得到最终的回复内容
显示模型输出得到回复内容后,将其保存到对话历史里,并通过st.chat_message("assistant").write(response) 在聊天界面上进行显示

尝试替换其他大模型

  • 浪潮信息源大模型上新:Yuan2-2B-July-hf,只需简单三步即可体验:

    • 双击打开baseline文件 AICamp_yuan_baseline/Task\ 1:零基础玩转源大模型/web_demo_2b.py

    • 将其中 # 源大模型下载# 定义模型路径 的地址修改为对应的模型即可

    • 在终端重新 启动Demo

代码替换
  • 替换前

 # 源大模型下载
 from modelscope import snapshot_download
 model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='./')
 ​
 # 定义模型路径
 path = './IEITYuan/Yuan2-2B-Mars-hf'
  • 替换模型后

 # 源大模型下载
 from modelscope import snapshot_download
 model_dir = snapshot_download('IEITYuan/Yuan2-2B-July-hf', cache_dir='./')
 ​
 # 定义模型路径
 path = './IEITYuan/Yuan2-2B-July-hf'
  • 在终端重新启动Demo

点击终端,然后输入如下命令,回车运行!

 streamlit run AICamp_yuan_baseline/Task\ 1:零基础玩转源大模型/web_demo_2b.py --server.address 127.0.0.1 --server.port 6006
  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值