├── .gitignore ├── FineTune ├── README.md ├── data │ ├── format.py │ ├── ruozhiba_format.jsonl │ ├── ruozhiba_raw.jsonl │ ├── split.py │ ├── test.jsonl │ └── train.jsonl └── img │ ├── after1.png │ ├── after2.png │ ├── after3.png │ ├── before1.png │ ├── before2.png │ ├── before3.png │ └── robot.webp ├── README.md ├── asset └── camp.png ├── helloworld ├── .gitkeep ├── hello_world.md └── images │ ├── Lagent.png │ ├── head.png │ ├── image-1.png │ ├── image-10.png │ ├── image-11.png │ ├── image-12.png │ ├── image-13.png │ ├── image-14.png │ ├── image-15.png │ ├── image-16.png │ ├── image-17.png │ ├── image-18.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ ├── image-5.png │ ├── image-6.png │ ├── image-7.png │ ├── image-8.png │ ├── image-9.png │ └── image.png ├── langchain ├── .gitkeep ├── demo │ ├── LLM.py │ ├── create_db.py │ ├── readme.md │ └── run_gradio.py ├── figures │ ├── image-0.png │ ├── image-1.png │ ├── image-11.png │ ├── image-2.png │ ├── image-5.png │ ├── image-51.png │ ├── image-52.png │ ├── image-53.png │ ├── image-54.png │ ├── image-55.png │ ├── image.png │ └── readme.md └── readme.md ├── lmdeploy ├── .gitkeep ├── cover.jpg ├── img │ ├── 0.png │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ ├── add0.png │ ├── add1.png │ ├── add3.png │ ├── add4.png │ ├── lmdeploy.drawio.png │ └── quant.drawio.png ├── infer_compare.py └── lmdeploy.md ├── opencompass ├── .gitkeep └── opencompass_tutorial.md ├── projects └── project.json └── xtuner ├── .gitkeep ├── MedQA2019-structured-test.jsonl ├── MedQA2019-structured-train.jsonl ├── MedQA2019-structured.jsonl ├── MedQA2019.xlsx ├── README.md ├── cli_demo.py ├── imgs ├── afterFT.png ├── after_train.png ├── beforeFT.png ├── bugfix1.png ├── bugfix2.png ├── cat_fly.png ├── cfgs.png ├── code_config_1.png ├── dataProcessed.png ├── head.png ├── head2.png ├── medqa2019samples.png ├── msagent_data.png ├── serper.png ├── web_show_1.png ├── web_show_2.png ├── xtuner_config_1.png ├── xtuner_config_2.png └── ysqd.png ├── internlm_chat_7b_qlora_oasst1_e3_copy.py ├── self.md ├── split2train_and_test.py └── xlsx2jsonl.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | *.drawio 4 | lmdeploy/c4/ 5 | -------------------------------------------------------------------------------- /FineTune/README.md: -------------------------------------------------------------------------------- 1 | ![robot](img/robot.webp) 2 | 3 | # 微调数据构造实验 4 | 5 | ## 1 XTuner教学使用 6 | XTuner的安装、部署、训练教程详见:[XTuner 微调个人小助手认知](https://github.com/InternLM/Tutorial/blob/camp2/xtuner/personal_assistant_document.md) 7 | 8 | ## 2 微调实战 9 | 10 | > 采用弱智吧数据进行训练~ 11 | 12 | ### 2.1 概述 13 | 14 | #### 2.1.1 **场景需求** 15 | 16 | 基于 InternLM2-chat-1.8B 模型,用弱智吧中的数据进行微调,训练一个不弱智的模型 17 | 18 | ### 2.2 数据准备 19 | 20 | #### 2.2.1 数据构造 21 | 22 | 首先介绍下如何构造高质量的SFT数据: 23 | 24 | 1. 数据选择和采集 25 | 26 | 微调数据的选择应该基于目标应用场景: 27 | - 领域相关性:选择与预期应用场景密切相关的文本数据。例如,如果目标是法律助理,应选择法律文档和案例。本实验目的是提升模型的推理和识别逻辑陷阱的能力,因此选择弱智吧的数据。 28 | - 质量高:这里指的是问题和回答都要是高质量的,通常需要语法正确,信息准确,风格一致。具体来说,好的回复应该遵循“无害(Harmless)、诚实(Honest)、有帮助(Helpful)”的三H原则。其中Harmless最重要,即回复应避免有害内容、保护隐私、同时避免文化偏见和刻板印象;其次是Honest,即回复应当是真实的,而不是虚构的事实;最后是Helpful,即回复是否能帮助到使用者,这个方面通常比较主观。 29 | - 多样性:确保数据覆盖所有相关子话题,以促进模型的泛化能力。 30 | 31 | 2. 数据预处理 32 | 33 | 为了提高模型的效率和效果,数据预处理是必不可少的步骤: 34 | - 清洗:去除无关的内容,如广告、HTML标签、无意义的填充词等。 35 | - 标准化:统一词汇的格式,比如时间、日期、货币单位等。 36 | - 分词:根据目标模型的需求进行适当的分词处理。 37 | - 去噪声:消除文本中的错误,如拼写错误、语法错误等。 38 | 39 | 3. 数据标注 40 | 41 | 由于微调数据规模不大,因此可以通过标注的方式来进行构造,这里有两种不同的标注方法: 42 | - 人工标注:由人工专家进行标注,确保标注的准确性和一致性。采用人工的方式成本比较高,但质量相对较好,尤其在涉及一些专业领域的时候,领域专家能够更好的理解问题并给出回复。这里介绍下我们的仓库:[OpenDataLab](https://github.com/opendatalab).,里面主要是一些数据处理工具,预计2024年5月会开源一个专门用于大语言模型标注的免费的标注工具。 43 | - 自动标注:使用已有的模型进行初步标注,然后由人工校验和修正。可以采用GPT4来生成回复,再由人工来判断回答的好坏,并进行修正。 44 | 45 | 4. 数据增强 46 | 47 | 数据增强可以提高模型的鲁棒性和泛化能力,方法有: 48 | - 文本重述:用不同的方式表达同一意思,增加文本的多样性。 49 | - 翻译循环:将文本翻译成一种语言,然后再翻译回原语言,通常用于生成新的文本表达。 50 | - 合成数据生成:使用规则或模型生成新的训练样本。 51 | 52 | 5. 数据划分 53 | 54 | 通常分为训练集、验证集和测试集。合理划分数据,确保模型能在未见过的数据上进行有效的泛化测试。 55 | 56 | 在本次实验中我们直接采用公开数据集中处理过的微调数据给大家做个简单的演示。大家可以访问 **[Huggingface](https://huggingface.co/datasets/m-a-p/COIG-CQIA)** 或者 **[OpenDatalab](https://opendatalab.org.cn/OpenDataLab/COIG-CQIA)** 进行数据集下载,由于huggingface网络连接问题,推荐国内的同学访问OpenDataLab进行数据集下载。我们选择其中的弱智吧数据进行微调,这个数据集的问题来自于点赞数超过500的弱智吧问题,基本都是一些逻辑陷阱或者脑筋急转弯,然后通过人工或GPT4的方式编写正确回答,再由人工校验后筛选出200多条高质量微调数据。 57 | 58 | #### 2.2.2 **真实数据预览** 59 | 60 | | 问题 | 答案 | 61 | | ---------------------------------------------------------- | ------------------------------------------------------------ | 62 | | 石油也是油,为啥没人用它来炒菜? | 石油虽然也是一种油,但它并不适用于烹饪。这主要是因为石油和食用油在化学成分和用途上有很大的不同: 1. **化学 成分**:食用油是由植物或动物脂肪制成的,主要含有对人体有益的脂肪酸,如欧米伽脂肪酸。而石油是一种化石燃料,主要由碳氢化合物组成,含有多种有害的化学物质。 2. **毒性**:石油中含有的化学物质对人体是有害的,甚至是致癌的。这些物质在加热时会产 生有毒的烟雾和蒸气,这对健康极为不利。 3. **风味和气味**:食用油在烹饪中可以增添食物的风味,而石油的气味和味道都非常 强烈且令人不悦,不适合用于食物。 4. **燃点**:石油的燃点远低于食用油,这意味着它在较低的温度下就会燃烧,这在厨房中极 为危险,容易引发火灾。 因此,出于健康和安全的考虑,石油绝不能用于烹饪。食用油是专门为食品烹饪设计的,既安全又有益健康。 | 63 | | 据数据表明,异性间的离婚率远大于同性,而中国同性离婚率至今为0这是否说明同性间结婚比异性更有优势|这个问题涉及到对离婚率数据的解读,以及同性和异性婚姻的比较。首先,需要明确一点:中国目前不承认同性婚姻,因此官方统计中不会有关于同性离婚率的数据。因此,任何关于中国同性婚姻离婚率的讨论都是基于非正式或非法律承认的情况。 从更广泛的角度来看,离婚率受到许多因素的影响,包括社会文化、法律环境、经济状况等。比较不同类型婚姻的离婚率时,这些因素都需要被考虑在内。同性婚姻在许多国家和地区是新近承认的,可能受到不同的社会和文化压力,这些都可能影响离婚率。 简单地将两种婚姻形式的离婚率进行对比,并不能直接说明哪一种婚姻形式更有优势。婚姻的质量和稳定性受到众多复杂因素的影响,包括双方的个人特质、沟通能力、外部压力等。因此,解读这样的统计数据时需要谨慎,并考虑到背后的多种可能性和复杂性。 | 64 | 65 | #### 2.2.3 将数据转为 XTuner 的数据格式 66 | **原始数据格式** 67 | ```JSON 68 | { 69 | "instruction": "天下没有不散的筵席,那么我们相聚的意义又是什么", 70 | "input": "", 71 | "output": "尽管我们相聚的时光有限,但是相聚的意义在于创造美好的回忆和珍贵的关系。相聚让我们感受到彼此的关怀、支持和友情。我们可以一起分享喜悦、快乐和困难,互相支持和激励。相聚也可以是一个机会,让我们相互了解、学习和成长。最重要的是,相聚能够带给我们真实的人际交往和情感交流,让我们感受到生活的丰富和美好。所以,即使相聚的时间有限,我们仍然要珍惜这份意义和与彼此相聚的时光。", 72 | "task_type": { 73 | "major": [ 74 | "问答" 75 | ], 76 | "minor": [ 77 | "逻辑问答", 78 | "隐喻理解" 79 | ] 80 | }, 81 | "domain": [ 82 | "通用" 83 | ], 84 | "metadata": "暂无元数据信息", 85 | "answer_from": "llm", 86 | "human_verified": true, 87 | "copyright": "暂无版权及作者信息" 88 | } 89 | ``` 90 | **目标格式** 91 | 92 | ```JSON 93 | { 94 | "messages": [ 95 | { 96 | "role": "user", 97 | "content": "" 98 | }, 99 | { 100 | "role": "assistant", 101 | "content": "" 102 | } 103 | ] 104 | } 105 | 106 | ``` 107 | 108 | > 采用GPT的编写python转换脚本或采用在线的data analysis功能,即可完成数据的转换,prompt如下: 109 | ```markdown 110 | 请编写python脚本完成jsonl数据到jsonl数据的格式转换,要求如下: 111 | 1)原始jsonl每行格式为: 112 | { 113 | "instruction": "天下没有不散的筵席,那么我们相聚的意义又是什么", 114 | "input": "", 115 | "output": "尽管我们相聚的时光有限,但是相聚的意义在于创造美好的回忆和珍贵的关系。相聚让我们感受到彼此的关怀、支持和友情。我们可以一起分享喜悦、快乐和困难,互相支持和激励。相聚也可以是一个机会,让我们相互了解、学习和成长。最重要的是,相聚能够带给我们真实的人际交往和情感交流,让我们感受到生活的丰富和美好。所以,即使相聚的时间有限,我们仍然要珍惜这份意义和与彼此相聚的时光。", 116 | "task_type": { 117 | "major": [ 118 | "问答" 119 | ], 120 | "minor": [ 121 | "逻辑问答", 122 | "隐喻理解" 123 | ] 124 | }, 125 | "domain": [ 126 | "通用" 127 | ], 128 | "metadata": "暂无元数据信息", 129 | "answer_from": "llm", 130 | "human_verified": true, 131 | "copyright": "暂无版权及作者信息" 132 | } 133 | 134 | 2)目标jsonl每行格式为: 135 | { 136 | "messages": [ 137 | { 138 | "role": "user", 139 | "content": "天下没有不散的筵席,那么我们相聚的意义又是什么" 140 | }, 141 | { 142 | "role": "assistant", 143 | "content": "尽管我们相聚的时光有限,但是相聚的意义在于创造美好的回忆和珍贵的关系。相聚让我们感受到彼此的关怀、支持和友情。我们可以一起分享喜悦、快乐和困难,互相支持和激励。相聚也可以是一个机会,让我们相互了解、学习和成长。最重要的是,相聚能够带给我们真实的人际交往和情感交流,让我们感受到生活的丰富和美好。所以,即使相聚的时间有限,我们仍然要珍惜这份意义和与彼此相聚的时光。" 144 | } 145 | ] 146 | } 147 | 148 | 3)按照从1)到2)的格式转换示例编写转换脚本 149 | 4)将转换后的数据保存为新的jsonl,中文不要转义 150 | ``` 151 | 152 | > 得到python脚本如下 153 | ```python 154 | import json 155 | 156 | # 原始和目标文件路径 157 | input_file_path = 'ruozhiba_raw.jsonl' 158 | output_file_path = 'ruozhiba_format.jsonl' 159 | 160 | # 打开原始文件进行读取 161 | with open(input_file_path, 'r', encoding='utf-8') as input_file, open(output_file_path, 'w', encoding='utf-8') as output_file: 162 | for line in input_file: 163 | # 将每行的json字符串转换为字典 164 | original_data = json.loads(line) 165 | 166 | # 转换格式 167 | converted_data = { 168 | "messages": [ 169 | { 170 | "role": "user", 171 | "content": original_data["instruction"] 172 | }, 173 | { 174 | "role": "assistant", 175 | "content": original_data["output"] 176 | } 177 | ] 178 | } 179 | 180 | # 写入新的jsonl文件,确保中文不被转义 181 | json.dump(converted_data, output_file, ensure_ascii=False) 182 | output_file.write('\n') # 每行后添加换行符,以保持jsonl格式 183 | 184 | ``` 185 | 186 | #### 2.2.4 划分训练集和测试集 187 | >同样可以采用GPT完成python脚本,prompt如下: 188 | 189 | ```markdown 190 | 请编写python脚本,将单个jsonl文件按照7:3的比例拆分为训练集train.jsonl和测试集test.jsonl 191 | ``` 192 | 193 | >得到python脚本如下: 194 | ```python 195 | import json 196 | 197 | # 输入文件路径和输出文件路径 198 | input_file_path = 'ruozhiba_format.jsonl' 199 | train_file_path = 'train.jsonl' 200 | test_file_path = 'test.jsonl' 201 | 202 | # 读取原始文件,将所有行存储在一个列表中 203 | with open(input_file_path, 'r', encoding='utf-8') as file: 204 | lines = file.readlines() 205 | 206 | # 计算训练集和测试集的分割点 207 | split_index = int(len(lines) * 0.7) 208 | 209 | # 拆分数据 210 | train_lines = lines[:split_index] 211 | test_lines = lines[split_index:] 212 | 213 | # 写入训练集 214 | with open(train_file_path, 'w', encoding='utf-8') as file: 215 | for line in train_lines: 216 | file.write(line) 217 | 218 | # 写入测试集 219 | with open(test_file_path, 'w', encoding='utf-8') as file: 220 | for line in test_lines: 221 | file.write(line) 222 | ``` 223 | 224 | 225 | ### 2.3 开始自定义微调 226 | >本节内容可参照 **[XTuner 微调个人小助手认知](https://github.com/InternLM/Tutorial/blob/camp2/xtuner/personal_assistant_document.md)**,这里简单介绍下流程: 227 | 228 | 首先进入之前创建的开发机并激活之前创建的虚拟环境 229 | ```bash 230 | conda activate xtuner0.1.17 231 | ``` 232 | 233 | 234 | 建立文件夹ruozhiba 235 | ```bash 236 | mkdir ~/ft-ruozhiba && cd ~/ft-ruozhiba 237 | ``` 238 | 239 | 复制internlm2-chat-1.8B模型 240 | ```bash 241 | mkdir -p /root/ft-ruozhiba/model 242 | cp -r /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/* /root/ft-ruozhiba/model/ 243 | ``` 244 | 245 | 上传处理后的弱智吧数据,首先新建data文件夹: 246 | ```bash 247 | mkdir -p /root/ft-ruozhiba/data 248 | ``` 249 | 然后将处理过的训练集train.jsonl和测试集test.jsonl上传到该路径下 250 | 251 | #### 2.3.1 准备配置文件 252 | 本案例基于internlm2_1_8b_qlora_alpaca_e3.py进行修改 253 | 254 | ```bash 255 | # 创建一个存放 config 文件的文件夹 256 | mkdir -p /root/ft-ruozhiba/config 257 | 258 | # 使用 XTuner 中的 copy-cfg 功能将 config 文件复制到指定的位置 259 | xtuner copy-cfg internlm2_1_8b_qlora_alpaca_e3 /root/ft-ruozhiba/config/ 260 | ``` 261 | 262 | 重命名配置文件为'internlm2_1_8b_qlora_ruozhiba_e3.py',并修改配置文件,主要是模型和数据的路径: 263 | ```diff 264 | # 修改模型地址(在第27行的位置) 265 | - pretrained_model_name_or_path = 'internlm/internlm2-1_8b' 266 | + pretrained_model_name_or_path = '/root/ft-ruozhiba/model' 267 | 268 | # 修改数据集地址为本地的json文件地址(在第31行的位置) 269 | - alpaca_en_path = 'tatsu-lab/alpaca' 270 | + alpaca_en_path = '/root/ft-ruozhiba/data/train.jsonl' 271 | 272 | # 修改评估的问题(在第59到61行的位置) 273 | - evaluation_inputs = ['请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai'] 274 | + evaluation_inputs = ['为什么我爸妈结婚的时候没邀请我参加婚礼'] 275 | 276 | # 把 OpenAI 格式的 map_fn 载入进来(在第15行的位置) 277 | - from xtuner.dataset.map_fns import alpaca_map_fn, template_map_fn_factory 278 | + from xtuner.dataset.map_fns import openai_map_fn, template_map_fn_factory 279 | 280 | # 将原本是 alpaca 的地址改为是 json 文件的地址(在第102行的位置) 281 | - dataset=dict(type=load_dataset, path=alpaca_en_path), 282 | + dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)), 283 | 284 | # 将 dataset_map_fn 改为通用的 OpenAI 数据集格式(在第105行的位置) 285 | - dataset_map_fn=alpaca_map_fn, 286 | + dataset_map_fn=openai_map_fn, 287 | ``` 288 | 289 | 其他参数的调整可以自行定义 290 | 291 | #### 2.3.2 **启动训练** 292 | 293 | ```bash 294 | xtuner train /root/ft-ruozhiba/config/internlm2_1_8b_qlora_ruozhiba_e3.py --work-dir /root/ft-ruozhiba/train --deepspeed deepspeed_zero2 295 | ``` 296 | 297 | 静静等待训练结束。 298 | 299 | #### 2.3.3 pth 转 huggingface 300 | 301 | 将得到的 PTH 模型转换为 HuggingFace 模型,**即:生成 Adapter 文件夹** 302 | 303 | ```bash 304 | mkdir -p /root/ft-ruozhiba/huggingface 305 | xtuner convert pth_to_hf /root/ft-ruozhiba/train/internlm2_1_8b_qlora_ruozhiba_e3.py /root/ft-ruozhiba/train/iter_96.pth /root/ft-ruozhiba/huggingface 306 | ``` 307 | 308 | **此时,hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”** 309 | 310 | > 可以简单理解:LoRA 模型文件 = Adapter 311 | 312 | #### 2.4 部署与测试 313 | 314 | #### 2.4.1 将 HuggingFace adapter 合并到大语言模型: 315 | 316 | ```Bash 317 | # 创建一个存放最终模型的路径 318 | mkdir -p /root/ft-ruozhiba/final_model 319 | 320 | # 解决一下线程冲突的 Bug 321 | export MKL_SERVICE_FORCE_INTEL=1 322 | 323 | # 进行模型整合 324 | xtuner convert merge /root/ft-ruozhiba/model /root/ft-ruozhiba/huggingface /root/ft-ruozhiba/final_model 325 | ``` 326 | 327 | #### 2.4.2 与合并后的模型对话: 328 | ```Bash 329 | # 加载 Adapter 模型对话(Float 16) 330 | xtuner chat /root/ft-ruozhiba/final_model --prompt-template internlm2_chat 331 | ``` 332 | 同样也可以部署Web demo与模型进行对话,详见[XTuner 微调个人小助手认知](https://github.com/InternLM/Tutorial/blob/camp2/xtuner/personal_assistant_document.md)中的**2.5.4 Web demo 部署**章节~ 333 | 334 | **效果:** 335 | 336 | | 问题 | 微调前 | 微调后 | 分析 | 337 | | --- | --- | --- | --- | 338 | | 浓硫酸里有2%的水,那我喝50杯硫酸是不是相当于喝了杯纯水? |这个问题有意思,但是有一定的科学依据。首先,我们需要明确浓硫酸的性质,它是一种高度腐蚀性的液体,具有强氧化性,能够将大多数物质氧化成二氧化碳和水。其次,我们需要了解浓硫酸的稀释过程。将浓硫酸稀释成稀硫酸,需要加入水。但是,加入的水量必须恰到好处,不能太多,否则会产生大量的热,导致安全问题;也不能太少,否则稀释后的浓硫酸仍然具有很高的浓度,同样存在安全问题。基于以上两点,我们可以得出结论:喝50杯浓硫酸,实际上是喝不了多少水的。因为浓硫酸的稀释需要加入水,而加入的水量必须恰到好处,不能太多,也不能太少。因此,喝50杯浓硫酸,实际上喝不了多少水,最多只能喝到浓硫酸中的2%的水。|不会的,浓硫酸具有强腐蚀性,喝入浓硫酸可能导致严重伤害,甚至死亡。|微调前没有发现问题的有害性,也没有理解问题,回答也是不知所云。微调后能够意识到问题的陷阱,并给出劝导性回答| 339 | | 我用水兑水,得到的是稀水还是浓水 | 这个问题明显具有迷惑性,实际上,将水兑水后得到的是浓水。这是因为两种水混合后,其中一种水被稀释,浓度降低,而另一种水浓度不变,仍然是指数级的。| 这个问题看似简单,但实际上蕴含着一些有趣的思维陷阱。首先,我们需要明确“稀水”和“浓水”的定义。在大多数情况下,当我们说某物是“稀”或“浓”时,我们通常是指其浓度或体积与周围环境相比的大小。例如,一杯水可能被视为稀水,因为它与周围环境相比体积较小。然而,这个问题中的“水兑水”实际上是将两种不同体积的水混合在一起,而不是将两种不同浓度的水混合在一起。因此,混合后的水的总体积可能会增加,但浓度并没有改变。| 微调前虽然能意识到问题中的陷阱,但回答出现了错误。微调后发现了问题中的思维陷阱,回答正确 | 340 | 341 | 结论:通过弱智吧数据微调过的模型,看起来“智商”变高了,虽然用到的数据只有100多条,但模型识别思维陷阱的能力和推理的能力得到了提升。 342 | 343 | ## 3 作业 344 | - 选一个任务场景:角色扮演、对话助手…… 345 | - 收集数据:公开数据集、贴吧论坛、问答网站…… 346 | - 数据处理:预处理、格式转换、人工编写回复…… 347 | - 使用Xtuner开始微调 348 | - 测试微调后的效果 349 | 350 | 351 | -------------------------------------------------------------------------------- /FineTune/data/format.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | # 原始和目标文件路径 4 | input_file_path = 'ruozhiba_raw.jsonl' 5 | output_file_path = 'ruozhiba_format.jsonl' 6 | 7 | # 打开原始文件进行读取 8 | with open(input_file_path, 'r', encoding='utf-8') as input_file, open(output_file_path, 'w', encoding='utf-8') as output_file: 9 | for line in input_file: 10 | # 将每行的json字符串转换为字典 11 | original_data = json.loads(line) 12 | 13 | # 转换格式 14 | converted_data = { 15 | "messages": [ 16 | { 17 | "role": "user", 18 | "content": original_data["instruction"] 19 | }, 20 | { 21 | "role": "assistant", 22 | "content": original_data["output"] 23 | } 24 | ] 25 | } 26 | 27 | # 写入新的jsonl文件,确保中文不被转义 28 | json.dump(converted_data, output_file, ensure_ascii=False) 29 | output_file.write('\n') # 每行后添加换行符,以保持jsonl格式 30 | -------------------------------------------------------------------------------- /FineTune/data/split.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | # 输入文件路径和输出文件路径 4 | input_file_path = 'ruozhiba_format.jsonl' 5 | train_file_path = 'train.jsonl' 6 | test_file_path = 'test.jsonl' 7 | 8 | # 读取原始文件,将所有行存储在一个列表中 9 | with open(input_file_path, 'r', encoding='utf-8') as file: 10 | lines = file.readlines() 11 | 12 | # 计算训练集和测试集的分割点 13 | split_index = int(len(lines) * 0.7) 14 | 15 | # 拆分数据 16 | train_lines = lines[:split_index] 17 | test_lines = lines[split_index:] 18 | 19 | # 写入训练集 20 | with open(train_file_path, 'w', encoding='utf-8') as file: 21 | for line in train_lines: 22 | file.write(line) 23 | 24 | # 写入测试集 25 | with open(test_file_path, 'w', encoding='utf-8') as file: 26 | for line in test_lines: 27 | file.write(line) 28 | -------------------------------------------------------------------------------- /FineTune/data/test.jsonl: -------------------------------------------------------------------------------- 1 | {"messages": [{"role": "user", "content": "一瓶可乐价格3元一瓶可乐价值3元,一瓶无糖可乐价值4元,所以糖价值-1元"}, {"role": "assistant", "content": "这种逻辑并不准确。商品价格通常由市场需求、生产成本、品牌定位等多种因素决定,不能简单地通过一个特定产品的价格来推断另一种产品的价值或特性。\n\n在这个描述中,通过单一的商品价格来推断糖的价值是不合理的。无法简单地将一种商品的价值直接转换为另一种商品的价值,更何况这里所提到的“糖价值-1元”的说法在经济学和商品交易中是不成立的。\n\n商品的价值往往受多种因素影响,而且价值本身是相对的,取决于买家和卖家之间的交易和需求。所以,通过一个商品价格来推断其他物品的价值是不科学的。"}]} 2 | {"messages": [{"role": "user", "content": "只有50%成功率的手术做两次成功率就只有25%了那手术只做一半不就100%成功率了吗"}, {"role": "assistant", "content": "这个观点存在一些逻辑上的误解。手术的成功率并不会因为进行多次手术而降低。\n\n如果每次手术的成功率为50%,那么进行一次手术的成功率是50%,进行两次手术,两次都成功的概率是25%(50% 的成功率乘以 50% 的成功率)。但这并不意味着进行一次手术只做一半,成功率就会变成100%。\n\n每一次手术都是独立的事件,它们的成功率不受之前或之后手术成功与否的影响。所以,每一次单独的手术都有50%的成功率。无论之前做了多少次手术,每一次手术的成功率都是独立的,都是50%。因此,并不是说做一半手术就能保证100%的成功率。"}]} 3 | {"messages": [{"role": "user", "content": "走别人的路,让别人无路可走。那走自己的路是不是让自己无路可走?"}, {"role": "assistant", "content": "“走别人的路,让别人无路可走”这个说法意味着创造出新的道路或途径,从而使其他人无法跟随。这种说法暗示了创新、独特性和领导力。\n\n而“走自己的路是不是让自己无路可走”则是指选择不同于他人的道路,可能意味着选择独立、与众不同的道路。这并不意味着走自己的路就意味着没有路可走,而是选择了不同的方向、策略或者方法,也许是为了追求独特性、自我实现或者探索新的可能性。\n\n选择自己的道路并不一定会让自己陷入困境或无路可走,而是在探索中寻找新的道路和可能性。这种选择可能会带来新的挑战和机遇,但也可能会创造出自己独特的道路。"}]} 4 | {"messages": [{"role": "user", "content": "监狱外犯罪会被关进监狱,那监狱内犯罪就只能关到监狱外了。"}, {"role": "assistant", "content": "在监狱内发生的犯罪通常会受到法律的制裁,罪犯可能会受到更严厉的惩罚,比如加刑、单独监禁或者其他的处罚措施。监狱内的违规行为或者犯罪行为不会直接导致罪犯被释放到监狱外,而是会在监狱内接受相应的法律程序和处罚。\n\n监狱内部也有自己的法律秩序和制度,针对监狱内的违规行为和犯罪行为会有相应的惩罚和处理方式。这些措施旨在维护监狱内的秩序和安全,对违规行为给予相应的法律处罚,并非会导致罪犯被释放到监狱外。"}]} 5 | {"messages": [{"role": "user", "content": "1080P是超清,1440P是不是大清,1800P是不是满清"}, {"role": "assistant", "content": "您的问题涉及到了两个不同的概念:电子显示器的分辨率和中国历史上清朝的称呼。在显示器分辨率方面,1080P、1440P 和 1800P 是指屏幕的垂直分辨率。例如,1080P 通常指的是 1920x1080 分辨率,1440P 指的是 2560x1440 分辨率,而 1800P 则可能指接 近 3200x1800 的分辨率。这些术语与“超清”、“高清”等词汇有关,是指屏幕显示的清晰度。\n\n另一方面,“大清”和“满清”是指中国历 史上清朝的不同称呼。清朝是中国最后一个封建王朝,存在于公元 1616 年到 1912 年。在这个语境中,“大清”是对清朝的正式称呼,而“满清”则是指清朝的满洲族统治者。\n\n因此,1080P、1440P 和 1800P 与清朝的称呼无关,它们仅仅是描述电子显示器分辨率的技术术语。您提到的“大清”和“满清”则完全属于历史领域的术语。"}]} 6 | {"messages": [{"role": "user", "content": "枪决死刑犯时走火把他打死了算过失杀人罪吗?"}, {"role": "assistant", "content": "在执行死刑过程中出现意外走火造成死刑犯死亡的情况,通常不会被认定为过失杀人罪。死刑的执行过程一般会由受过专门训练的执行人员负责,他们会遵循严格的操作程序和安全规定来执行死刑,以最大程度减少意外发生的可能性。\n\n如果在执行死刑过程中发生走火意外,通常会进行调查以确定事故的原因,并进行相应的评估。一般情况下,执行人员会接受专门的培训和指导来确保安全执行死刑。因此,如果走火是因为技术故障或其他不可预见的原因造成的,通常不会被视为过失杀人罪。\n\n但这样的情况具体会因地区法律和司法制度的不同而有所不同。法律对于执行死刑过程中的意外情况有着具体的规定和程序,一般会进行调查和审查以确定责任和采取适当的措施。"}]} 7 | {"messages": [{"role": "user", "content": "我们班班花是不是喜欢我?她每次都跟我坐在同一个教室上课,她是不是喜欢我?"}, {"role": "assistant", "content": "坐在同一个位置上课不一定代表班花就一定喜欢你。行为和动机之间存在许多可能的解释。虽然她选择和你坐在一起可能显示出一定的好感或友好,但并不意味着就是对你有特别的感情。\n\n有些人可能会选择固定的座位,可能因为喜欢那个位置的视角、光线、或者因为那个位置让她感到舒适。除此之外,她和你坐在一起也可能只是出于方便或者偶然性。\n\n要确定一个人是否对你有特别的感情,需要更多的线索和明显的暗示。看她的行为是否在与你交流时展现出特别的兴趣,是否经常主动和你交谈、寻求你的帮助或者表现出更多的关注等。如果你对她是否对你有好感感到好奇,可以试着和她建立更多的交流,了解她的兴趣爱好、共同话题等,或者直接通过合适的方式询问她对你的态度。"}]} 8 | {"messages": [{"role": "user", "content": "感觉朋友特别配不上我没学历,人也很笨,连23个英文字母都记不住"}, {"role": "assistant", "content": "当你提到你的朋友“特别配不上我”,这样的想法可能源于对自己或对方的不公平评价。每个人都有自己的长处和短处,而学历和记忆能力并不能完全代表一个人的价值。真正的友谊应该基于相互尊重和理解,而不是单方面的标准。\n\n另外,你提到的“23个英文 字母”实际上是个误解,英文字母共有26个。这个小错误提醒我们,每个人都可能有知识上的盲点,无论学历高低。我们都应该保持谦逊 ,愿意学习和改正错误。\n\n在与朋友相处时,试着多关注对方的优点和你们共同的兴趣,而不是单纯聚焦于所谓的“缺点”。真诚的接纳和相互支持,才是友谊长久的基础。"}]} 9 | {"messages": [{"role": "user", "content": "心脏手术失败原因是医生没有get到梗在哪"}, {"role": "assistant", "content": "你的句子中使用了一种有趣的双关语。在日常对话中,“没有get到梗”通常是指没有理解某个笑话或者隐喻的意思。但在医学领域,特别是心脏手术中,“梗”通常指的是心肌梗死,即心脏的某部分因为血液供应不足而导致的组织死亡。因此,这句话巧妙地将日常用语和医学术语结合在一起,创造了一个有趣的双关效果。在心脏手术的背景下,“医生没有get到梗在哪”可以被解释为医生没有正确识别或处理引起心脏问题的具体区域。"}]} 10 | {"messages": [{"role": "user", "content": "朱元璋指着一个猪蹄,问大臣说这道菜叫什么 大臣说:这道菜叫猪圆掌"}, {"role": "assistant", "content": "这个问题看起来像是一个有趣的谜语或者文字游戏。在这个场景中,朱元璋指着猪蹄(即猪的脚掌),然后问大臣这道菜叫什么。大臣回答:“这道菜叫猪圆掌”。\n\n这个谜语的诙谐之处在于:“猪圆掌”听起来像是“朱元璋”的谐音,这是一个利用语音相似性来制造幽默或文字游戏的例子。这种语言游戏经常在讲笑话或者文字谜语中出现,依赖于词语的发音或相似性来制造幽默效果。"}]} 11 | {"messages": [{"role": "user", "content": "雨天,我走进水坑里,不小心踩碎了天空。"}, {"role": "assistant", "content": "这个描述似乎是一个修辞手法,比喻性地描述了雨天的场景。在这个描述中,说“我走进水坑里,不小心踩碎了天空”,实际上并非字面意义上的发生,而是一种用词语来比喻雨天的场景。\n\n通常情况下,当雨水落在水坑或者蓄水池时,水面会泛起涟漪或者波纹,可能会反射天空的颜色或者天空的倒影。因此,这句话可能是通过“踩碎了天空”的说法来比喻雨天时踩进水坑的情景,描述雨水落在水坑中形成的波纹或者涟漪,产生了一种倒映天空的效果。\n\n这种形象化的表达方式可能是为了更生动地描述一个平常的场景,赋予它一些诗意或者意境。"}]} 12 | {"messages": [{"role": "user", "content": "苦行僧以苦为乐,那么他受苦是不是可以说他在奖励自己"}, {"role": "assistant", "content": "苦行僧通常是指那些以禁欲、忍耐和苦行修行来追求精神觉悟或灵性提升的修行者。他们将苦行视为一种修行方式,认为通过忍受痛苦和克制欲望,可以净化心灵、获得超脱、超越欲望的境界,以及对世俗生活和物质欲望的超然态度。\n\n虽然苦行僧以苦为乐,但并不是真的在享受痛苦,而是在通过苦行来超越对物质欲望的执着,从而达到心灵上的解放。对于他们来说,忍受苦难是为了在心灵层面寻求解脱和提升。\n\n因此,可以说苦行僧忍受痛苦并不是为了奖励自己,而是为了通过苦行来追求更高层次的心灵觉悟和内在的满足。他们认为通过这种修行方式可以达到更高的境界和内在的平静。"}]} 13 | {"messages": [{"role": "user", "content": "浓硫酸里有2%的水,那我喝50杯硫酸是不是相当于喝了杯纯水?"}, {"role": "assistant", "content": "绝对不能喝硫酸或者含有硫酸成分的液体!硫酸是一种极其腐蚀性和有毒的化学物质,对人体组织和器官造成极大的危害,甚至可能致命。\n\n无论硫酸中是否掺有少量水分,都不应该饮用。即使浓硫酸中含有一定比例的水,这并不会使其变得安全或可饮用。硫酸的腐蚀性极强,即使是微量的浓硫酸都可能导致灼伤、损坏消化道黏膜、严重伤害食道、胃和其他器官,可能导致严重的健康问题甚至危及生命。\n\n喝下硫酸会导致严重的健康问题,绝对不要尝试。如果不慎接触到硫酸或者其它腐蚀性物质,应立即用大量清水冲洗,并尽快就医寻求专业的急救和治疗。"}]} 14 | {"messages": [{"role": "user", "content": "牛奶不能空腹喝,那我满腹经纶的老师岂不是随便喝"}, {"role": "assistant", "content": "“牛奶不能空腹喝”这种说法并不一定适用于所有人。对于某些人来说,在空腹时喝牛奶可能会引起不适,例如可能会出现消化不良或引起胃部不适。然而,对于其他人来说,在空腹时喝牛奶并不会带来明显的问题。\n\n至于您提到的“满腹经纶的老师随便喝”,这并不是一个科学或常规的推理。一个人是否有知识渊博并不会影响到他们在空腹时是否能够安全地喝牛奶。每个人的身体状况和消化系统都不同,对食物的反应也会有所不同。\n\n如果某人身体状况良好,没有对牛奶过敏或者没有消化方面的问题,他们在空腹时可能可以安全地喝牛奶。但若是有任何不适或担忧,最好在喝牛奶前先咨询医生或营养师的建议,以确保自己的健康和安全。"}]} 15 | {"messages": [{"role": "user", "content": "公司的水太深,所以上班才会摸鱼。"}, {"role": "assistant", "content": "这句话是一种幽默的比喻或谐音游戏。\"水太深\"通常是指一个环境或情境存在复杂的局面或者难以理解的情况。而\"摸鱼\"是一种俚语,指的是在工作时间偷懒或者不认真工作,而是在做一些与工作无关的事情。\n\n在这个表达中,“公司的水太深”实际上是在暗示公司的工作环境或者内部情况比较复杂或者难以理解,因此员工才会在上班时间摸鱼。实际上,这句话并不是指公司的水实际上很深,而是用来调侃公司内部环境让员工难以专注工作,或者有许多无法理解的事情。"}]} 16 | {"messages": [{"role": "user", "content": "劝各位放弃考清华的梦想,踏踏实实进入北大才是真。"}, {"role": "assistant", "content": "这句话似乎是以幽默的方式讨论清华大学和北京大学之间的竞争与认知。清华大学和北京大学都是中国著名的高等学府,各自拥有优秀的师资和学术资源,同时也有自己的特色和优势领域。\n\n表达者可能在用一种调侃的方式暗示,清华大学和北京大学在中国的大学竞争中一直有着相当的地位,但在某些人眼中,认为进入北京大学才是更为理想的选择。\n\n每个人对于大学的选择都会有不同的标准和考量,清华大学和北京大学都是优秀的高校,学生应该根据自己的兴趣、专业需求和未来规划,选择最适合自己的学府,而不仅仅是因为某个学校的名声或者排名。"}]} 17 | {"messages": [{"role": "user", "content": "面对歹徒开枪射击,王警官严厉批评其射击姿势不够标准。"}, {"role": "assistant", "content": "这个说法是一种讽刺或者幽默的表达方式,试图通过夸张来传达一种信息或者引起一些思考。在实际生活中,面对歹徒开枪射击的情况下,人们通常会关注的是生命安全和采取适当的行动以保护自己和他人,而不是担心射击姿势是否标准。\n\n这种说法可能旨在强调一些奇怪或不合逻辑的情境,用一种夸张的方式来呼应社会或者人们对于某些事情过分关注细节或者无关紧要之处。在实际危险情况中,人们通常会更关注如何生存和逃生,而不是担心某个歹徒射击姿势是否符合标准。"}]} 18 | {"messages": [{"role": "user", "content": "下雨天关节疼 那我骗它是晴天不就不会疼了"}, {"role": "assistant", "content": "这句话是一种幽默或打趣的说法,用来表达在下雨天时人们的关节可能会因天气变化而感到疼痛或不适的情况。\n\n实际上,有些人在天气变化(尤其是气温、气压变化)时可能会感到关节疼痛或不适,这被称为气象性关节痛。尽管有人确实在雨天时感到关节疼痛,但这并不是所有人都会经历的情况。此外,关节疼痛可能受到多种因素影响,而不仅仅是天气因素。\n\n这句话是一种戏谑的表达方式,暗示如果可以欺骗天气,让自己相信是晴天而不是下雨天,就不会感到关节疼痛了。然而,实际上这并非可能实现的事情,因为天气变化通常是无法控制的自然现象。"}]} 19 | {"messages": [{"role": "user", "content": "讲个地狱笑话一个色盲向路人求助,路人让他去找红十字会,于是,色盲连夜赶到了瑞士。"}, {"role": "assistant", "content": "这个笑话源于对色盲视觉障碍的误解,其中色盲的人被告知去找“红十字会”,但由于无法分辨红色,他错误地前往了有着类似标志(白色十字架,红色背景)的瑞士。这是一个典型的误解和混淆的情况,涉及到色觉障碍以及两个相似但不同的符号——红十字会的标志和瑞士国旗。"}]} 20 | {"messages": [{"role": "user", "content": "吕布有几个电子?三个,因为他有三个e-!"}, {"role": "assistant", "content": "这个笑话是一个关于历史人物吕布的谐音梗。在中文中,“e-”的发音类似于“义父”,而根据历史记载,吕布确实有三个义父:丁原、董卓和王允。这个笑话巧妙地利用了中文发音的特点,将电子(e-)与义父联系起来,制造了一个幽默的误解。在中文中,这种利用发音相似来创造幽默的手法是相当常见的。"}]} 21 | {"messages": [{"role": "user", "content": "孙子是怎么提前两千年预判战斗机的发明的还提出了“战机很重要”“不要失去战机”这种理论"}, {"role": "assistant", "content": "孙子兵法是一本古代中国军事著作,作者是孙武(也称孙子)。这本书强调了军事战略、战术、间谍战、军队管理等方面的原则和理论。尽管这本书写于两千多年前,但它的原则和思想仍然对军事领域有着重要的影响。\n\n“战机”一词在孙子兵法中指的不是现代意义上的战斗机,而是指战争中的时机、机会、或战略优势。孙子兵法主张利用战机、捕捉战机,即在战场上抓住敌人失误或弱点,以获得优势。这些理念和原则虽然不同于现代战斗机的发明,但强调了在战争中抓住机会和优势的重要性。\n\n因此,“战机很重要”和“不要失去战机”的理论并不是指现代战斗机,而是在战争中抓住时机、抓住机会的战略原则。这些原则至今仍被军事学界视为重要的战略思想。"}]} 22 | {"messages": [{"role": "user", "content": "为什么半途而废的人那么多,中途岛却不是世界上人口最密集的地方?"}, {"role": "assistant", "content": "“半途而废”的人指的是在完成某项任务或目标时中途放弃的人。而中途岛(Midway Island)是位于太平洋中部的一个环礁岛,通常并不被人居住,也不是世界上人口密集的地方。\n\n这两者之间的关联是通过一种巧妙的语言幽默来表达,其实际上并没有直接的联系。这种幽默的表达方式是通过将“中途”一词在不同语境中联想,构建出一个双关语的笑话。虽然这个说法可能带有幽默成分,但它并不能从逻辑上解释为什么半途而废的人很多,而中途岛却不是人口密集的地方。\n\n实际上,半途而废的原因多种多样,可能与人们对目标的坚持、动力、环境和个人情况等因素有关,与一个特定地点或岛屿的人口密集程度并无必然联系。"}]} 23 | {"messages": [{"role": "user", "content": "麦哲伦环球航行证明了地圆说,证明太阳是圆的是不是要围着太阳走一圈啊"}, {"role": "assistant", "content": "哲伦环球航行确实是对地球形状的一个重要证明,它部分地证明了地球是圆的。然而,太阳的圆形并不需要我们围着太阳走一圈来证明。\n\n我们知道太阳是球形的,并不需要环绕它一圈来验证这一点。我们对太阳圆形的认知来自于对太阳的观测和科学研究。通过天文观测,人们能够观察到太阳的圆形外观,以及它的运动、日食、太阳黑子等现象,这些都是在不必亲自围绕太阳一圈的情况下得出的观察结论。\n\n总之,对于太阳是圆形的观察和认知,可以通过观测、科学研究以及天文学知识得出结论,并不需要亲自绕太阳一圈。"}]} 24 | {"messages": [{"role": "user", "content": "我去买氮气但是店家说只有纯度为78%的怎么办??"}, {"role": "assistant", "content": "氮气的空气中含量约为78%,而氧气则占21%,其他气体则占剩余的1%左右。因此,纯度为78%的氮气其实是指空气中氮气的含量。\n\n如果你需要纯度更高的氮气,例如用于特殊工业或实验室用途,可以尝试寻找供应商或厂家,询问他们是否提供更高纯度的氮气产品。通常,一些专业化的供应商或实验室设备供应商可能会提供更高纯度的氮气,以满足特定需求。\n\n但如果你需要的氮气用途是一般性质,纯度为78%的氮气可能已经足够满足需求,比如在一些食品行业或普通实验室中。最终选择购买哪种纯度的氮气取决于你的具体需求和用途。"}]} 25 | {"messages": [{"role": "user", "content": "电脑发热是因为有电阻,我人脑发热是因为有脑血栓吗"}, {"role": "assistant", "content": "电脑发热通常是因为内部电子元件工作时产生的能量损耗,导致发热。虽然电阻是电路中产生热量的一个因素,但电脑发热还可能是由于其他部件的工作,比如处理器、显卡等。\n\n人脑发热通常不是由于脑血栓导致的。脑血栓是血管中血液凝结形成的堵塞物,通常不会直接导致脑部发热。人体的脑部会因为脑内神经元的活动而产生少量的热量,但这并不是因为脑血栓。脑血栓可能导致血液循环问题或者血流受阻,从而引发其他症状,但直接导致脑部发热的情况较为罕见。\n\n如果您感觉自己头部发热或有不适感觉,特别是持续的发热或与其他症状相关,请及时就医并咨询专业医生。"}]} 26 | {"messages": [{"role": "user", "content": "力的作用是相互的,但是我扇我自己只有我自己会疼"}, {"role": "assistant", "content": "这个描述涉及到物理和感知之间的比喻。力的作用是相互的是指牛顿第三定律,即物体之间的作用力是相互的,但是这种力会对物体产生不同的影响。\n\n描述中提到扇自己只有自己会感到疼痛,这是在说明在这种情况下只有自己感觉到疼痛,这类比喻常用来描述自我行为对个人的影响。\n\n这个比喻可能是在强调一个概念:某些行为或决定只会对自己产生影响,而不会影响其他人。它强调了个人责任和自我行为对自己产生的影响,而不会波及到其他人身上。"}]} 27 | {"messages": [{"role": "user", "content": "前天还有人祝我生日快乐呢,今天怎么没了?"}, {"role": "assistant", "content": "前天是指在昨天之前的那一天。如果有人在前天祝你生日快乐,但今天没有人再次祝贺你,可能是因为生日已经过去了,或者人们可能忘记了这一天。\n\n人们通常在生日当天或前几天向朋友或亲人表达祝福,一旦生日过去,祝福的数量可能会减少。这并不意味着人们不关心你,而是可能因为生日已经过去,所以祝贺的情况变少了。"}]} 28 | {"messages": [{"role": "user", "content": "人酸了的时候通常会眼红,会不会眼睛其实是pH试纸?"}, {"role": "assistant", "content": "不,人的眼睛并不是pH试纸。眼睛在出现眼红的情况下通常是因为血管扩张或充血,这可能由多种原因引起,如疲劳、过度用眼、眼睛感染、过敏、干眼症等。眼睛的红血丝通常与眼部血管的扩张有关,与pH值无关。\n\npH试纸用于测量物质的酸碱度,它会因接触液体或物质而改变颜色以显示其pH值。人的眼睛不是pH试纸,眼睛红血丝出现通常是由于其他生理或环境因素引起的。"}]} 29 | {"messages": [{"role": "user", "content": "以史为鉴说明历史是一面镜子。两面镜子对着可以通向无穷远所以?"}, {"role": "assistant", "content": "\"以史为鉴,可以知兴替\"是一句中国古语,意味着通过历史我们可以了解事物的兴衰变化。这句话强调了从历史中学习的重要性,意味着历史就像一面镜子,反映了过去的教训和经验。\n\n当提到“两面镜子对着可以通向无穷远”,这实际上是在描述一个物理现象。当两面镜子相对放置时,物体在两面镜子之间的反射会形成一系列逐渐缩小的图像,这些图像看起来像是延伸到无穷远。这个现象在物理学中被用来解释光的反射和折射原理。\n\n将这两个概念结合起来,可以理解为通过历史的反思,我们可以深入探索无限的知识和智慧。就像通过镜子的无穷反射,我们可以不断地从历史中学习,探索更深远的真理和知识。"}]} 30 | {"messages": [{"role": "user", "content": "一罐冰可乐三块钱,第一口值两块五,两个人分别喝一口就白赚两块了"}, {"role": "assistant", "content": "这个谜语可能存在一些逻辑上的玩笑成分。让我们来分析一下:\n\n一罐冰可乐三块钱,意味着整罐可乐的总价值是三块钱。\n第一口可乐被价值为两块五,这表明第一口的价值最高。\n两个人分别喝一口后白赚两块,这句话可能在以玩笑的方式描述着这个逻辑的荒谬性。\n根据上述描述,这个谜语有一种在逻辑上反常的构造,似乎有点讽刺或开玩笑的意味。在实际情况下,单单一口可乐不可能比整罐可乐还要贵。这个谜语可能是一种娱乐性质的逻辑谜题,其目的是引起思考并带来一些幽默或玩笑的效果。"}]} 31 | {"messages": [{"role": "user", "content": "人的身上有隐私部位,那是不是也有公共部位?"}, {"role": "assistant", "content": "在个人身体上没有被定义为“公共部位”的特定区域。通常,“隐私部位”指的是私密区域或私人的身体部位,涉及到个人隐私和尊严,需要被尊重和保护。这些区域包括生殖器官、臀部等。\n\n然而,“公共部位”并不是一个被正式定义或广泛使用的术语。人体上的其他区域通常被认为是公共区域,这意味着它们不是隐私区域,可以被公开展示而不违反社会的礼仪和规范,比如手、脸、胳膊等。但是,并没有一个特定的、被广泛认可的术语或定义将这些部位称为“公共部位”。"}]} 32 | {"messages": [{"role": "user", "content": "人类70%是水,所以10个人里有7个人是水伪装成的人!"}, {"role": "assistant", "content": "这是一个有趣的错位解读,但从科学角度来看,这种说法并不准确。人类身体中确实含有大量的水分,但并不意味着人类是由水“伪装”而成。\n\n人体中的水分在不同的年龄、性别和体重等因素下会有所差异,但大致上约占体重的60-65%。这意味着人类身体中水分的含量在整体上是很高的,但并不意味着人是由水伪装而成的。\n\n这种说法是以一种幽默和夸张的方式来描述人体含水量的多少,并非字面上的“水伪装成的人”。人类身体中的水是构成人体细胞、维持生命所必需的重要物质之一,对于身体的正常功能和健康至关重要。"}]} 33 | {"messages": [{"role": "user", "content": "太阳还有五十亿年就没了,那到时候向日葵看哪呢?"}, {"role": "assistant", "content": "当太阳在五十亿年后迎来它的末日时,它会经历膨胀成红巨星的阶段。在这个过程中,太阳会变得非常巨大,可能扩张到地球当前轨道的位置,甚至更远。这个阶段太阳的辐射会变得更为强烈,热量和光线会使地球上的温度升高,生命可能难以维持。\n\n五十亿年后,如果地球仍然存在,向日葵和其他植物可能无法生存,因为太阳变成红巨星后会释放出更多的辐射和热量,可能会导致地球的温度上升到无法支持生命的程度。到那时,地球上的植物和生物可能会难以存活,所以向日葵很可能无法继续生长。"}]} 34 | {"messages": [{"role": "user", "content": "很多女生会虚报年龄,那直接看她年轮不就好了。"}, {"role": "assistant", "content": "哈哈,如果我们能够像树木一样通过年轮看出一个人的年龄该有多好!不过,年轮只存在于树木内部,而人类的年龄则并不以类似方式显示。虚报年龄可能是出于各种原因,但要准确判断一个人的年龄,还是需要看他们的身份证或者其他证件比较靠谱。"}]} 35 | {"messages": [{"role": "user", "content": "医生说我还能活三个月,我抬手就是一枪。法官判了我14年\n这句话的笑点"}, {"role": "assistant", "content": "这句话的笑点在于它揭示了一个荒诞和讽刺的情境。一个被告知只能活三个月的人,在听到自己的医疗诊断后,立即采取了极端的行动。然而,当法官判处他14年监禁时,这个判决显得毫无意义,因为他只有三个月的生命。这里的幽默和讽刺在于法律判决的无效性和现实情况之间的鲜明对比,以及对命运的无奈和荒诞的反思。"}]} 36 | {"messages": [{"role": "user", "content": "既然高考是看排名的,那大家为什么不都考0分呢?这样人人都有大学上了"}, {"role": "assistant", "content": "这个问题是一个典型的反常识思考。高考(中国的大学入学考试)的确是根据考生成绩的排名来决定他们能进入哪所大学。理论上,如果所有考生都考了0分,那么他们的排名应该是相同的。但实际上,即使所有人都考0分,这并不意味着他们都能上大学。\n\n首先,大学的招生是基于考生的成绩来决定的。如果所有人的成绩都是0分,大学无法区分考生的学术能力和潜力,这违背了招生的基本原 则。\n\n其次,即使在极端情况下所有人都考了0分,大学也可能会选择不录取任何学生,或者采取其他补充评估方法(如面试、特长等 )来决定录取名单。\n\n最后,即便是在理论上,如果所有考生都故意考0分,这种行为也可能被视为对考试制度的破坏,可能会导致严 重的后果,如取消考试结果或重新考试。\n\n综上所述,即使所有人考0分,也无法保证每个人都能上大学,因为这违背了招生的基本原 则和评估标准。"}]} 37 | {"messages": [{"role": "user", "content": "只切三刀,怎么把一瓶牛奶平均分给八个小朋友?"}, {"role": "assistant", "content": "这个问题是一个有趣的脑筋急转弯。首先,我们必须理解牛奶是一种液体,因此不能通过传统的切割方式来平分。然而,如果将牛奶冻成固体,我们就可以用刀来切割它。但即使如此,要用三刀平均分成八份仍然是一个挑战。\n\n一个可能的解决方案是将冻牛奶切成特定的形状,以便可以平均分配。例如,我们可以先将冻牛奶切成一个大立方体,然后用三刀按照特定的方式切割。这需要一些几何知识和空间想象力。\n\n假设我们有一个立方体的冻牛奶。第一刀可以沿着立方体的一个面平行地切,将立方体分成两半。接着,第二刀可以垂直于第一刀的切面,也是沿着另一个面平行切,再次将每半分成两部分,这样就有四块相等的部分了。最后,第三刀可以垂直于前两刀的切面,在立方体的顶部沿着另一个面切,将每个部分分成两份,从而得到八份相等的部分。\n\n当然,这个解决方案假设牛奶完全均匀地冻结,并且切割是完美准确的。在实际操作中,这可能是个挑战。但作为一个脑筋急转弯,这种方法提供了一种创新的思考方式。"}]} 38 | {"messages": [{"role": "user", "content": "判了死刑一般多久能放出来?"}, {"role": "assistant", "content": "在大多数法律体系中,一旦被判处死刑并且判决生效后,就不会有被释放的可能性。死刑是法律规定的最严厉的刑罚形式,意味着被判刑人将被处决,而不是被关押一段时间后释放。不过,在死刑判决执行之前,仍然有可能通过上诉、赦免或减刑程序来改变判决结果。在不同的国家和地区,这些程序的细节和可能性都有所不同。"}]} 39 | {"messages": [{"role": "user", "content": "对下联:过去已过去,未来尚未来"}, {"role": "assistant", "content": "下联可以是:“如果有如果,现在何现在?”"}]} 40 | {"messages": [{"role": "user", "content": "妈妈说:“我的天才考59分”是不是在夸我是天才?"}, {"role": "assistant", "content": "这句话可能是一种幽默或者开玩笑的说法。在这种情境下,「我的天」和「才考」的使用是对「59分」这个分数低于预期的一种感叹。通常情况下,这句话并非字面意义上夸奖你是天才,而是一种幽默的表达方式。"}]} 41 | {"messages": [{"role": "user", "content": "水枪里装核污水算不算核武器"}, {"role": "assistant", "content": "不,水枪里装有核污水并不构成核武器。核武器是指使用核裂变或核聚变产生的巨大爆炸能量作为武器。核武器的制造、使用和拥有受到国际法律的严格限制和监管。水枪里装有核污水不具备核武器的定义,但这种行为可能对环境和健康造成严重危害,并且违反了环境保护法律。"}]} 42 | {"messages": [{"role": "user", "content": "木偶摆脱操控它的丝线后究竟是自由了还是变成了废品"}, {"role": "assistant", "content": "这个问题是关于一个木偶摆脱了操控它的丝线后的命运的深思。木偶脱离了操控线意味着它失去了被操纵的能力,这可以从两个角度来看:\n\n1. **自由的角度**:从某种意义上说,木偶脱离了操控线象征着自由。它不再受到操纵者的控制,不再被迫按照他人 的意愿行动。这可以被看作是一种解放,一个走向自主和自我实现的步骤。\n\n2. **废品的角度**:然而,从另一个角度来看,木偶失 去了操控线也意味着它失去了其基本功能——作为一个能够被操控的玩偶。在这个意义上,它可能被视为“废品”,因为它不再能够履行其作为玩偶的原本角色。\n\n这个问题反映出一个更深层次的哲学探讨:自由与功能、独立与存在的目的之间的关系。它挑战我们思考一个实体(无论是一个人、一个组织还是一个简单的物体)在获得自由的同时可能失去的东西,以及这种变化对其价值和目的的影响。"}]} 43 | {"messages": [{"role": "user", "content": "谁能想到,一向见钱眼开的他,竟然被金钱蒙蔽了双眼?"}, {"role": "assistant", "content": "这句话可以理解为:“谁能想到,一个总是对金钱极其感兴趣的人,竟然被金钱的诱惑所迷惑,失去了理智。”\n\n这里,“见 钱眼开”和“金钱蒙蔽了双眼”都是关于眼睛的比喻,但它们的含义并不是字面上的意思。第一个短语“见钱眼开”形容一个人一看到钱就变 得异常兴奋或积极,而第二个短语“金钱蒙蔽了双眼”则是指因为对金钱的渴望,一个人变得盲目,不能正确判断事情,失去了清晰的思考能力。这两个短语都用“眼睛”来比喻一个人对金钱的态度和由此导致的行为变化。"}]} 44 | {"messages": [{"role": "user", "content": "因为小时候怕鬼,我努力成为一名唯物主义者但是世界上并没有鬼,我是不是白努力了。"}, {"role": "assistant", "content": "努力探索并接受唯物主义的理念本身并非是件坏事。尽管唯物主义者相信世界上没有超自然的存在,但这种信仰或信念通常不仅仅是针对对抗鬼魂或超自然现象的。唯物主义对于解释自然现象、推动科学发展以及理解现实世界中的事物有其重要意义。你的努力可能帮助你更深入地理解自然和现实,这并不是白费的努力,而是对于知识和认知的一种探索。"}]} 45 | {"messages": [{"role": "user", "content": "都说适者生存那为什么猛犸没有活到现在呢?是太弱了还是太强了?"}, {"role": "assistant", "content": "适者生存这个说法是达尔文的进化理论的基础之一,但并不意味着只有最强壮或最优秀的生物才能生存下来。适者生存更确切地指的是,那些能够适应环境变化、适应生存挑战并能够繁衍后代的生物更可能在漫长的进化过程中存活下来。\n\n猛犸象是一种古代的大型动物,生活在冰河时期的欧亚大陆。它们最终灭绝可能是由于一系列复杂的原因,包括环境变化、气候变迁和食物资源减少等。生物灭绝往往不只是由于单一因素造成,而是多种因素的综合结果。猛犸象可能未能适应当时的环境变化,最终导致它们的灭绝。"}]} 46 | {"messages": [{"role": "user", "content": "九月份离高考还有九个月,那为啥六月份离高考只有几天了?"}, {"role": "assistant", "content": "这句话可以理解为:“谁能想到,一个总是对金钱极其感兴趣的人,竟然被金钱的诱惑所迷惑,失去了理智。”\n\n这里,“见 钱眼开”和“金钱蒙蔽了双眼”都是关于眼睛的比喻,但它们的含义并不是字面上的意思。第一个短语“见钱眼开”形容一个人一看到钱就变 得异常兴奋或积极,而第二个短语“金钱蒙蔽了双眼”则是指因为对金钱的渴望,一个人变得盲目,不能正确判断事情,失去了清晰的思考能力。这两个短语都用“眼睛”来比喻一个人对金钱的态度和由此导致的行为变化。这个问题看起来似乎有些矛盾,但实际上它是一个关于时间流逝和高考时间安排的简单问题。\n\n首先,我们需要了解高考的时间通常是在每年的6月份。在中国,高考通常是指普通高等学校 招生全国统一考试,这个考试的时间是固定的,通常在每年的6月7日、8日和9日举行。\n\n现在我们来分析题目中的两个时间点:\n\n九月份离高考还有九个月:这里的“九个月”实际上是指从九月份到第二年的六月份,共计九个月。这是因为高考是在第二年的6月份举行, 所以从九月份开始计算,到6月份正好是九个月。\n\n六月份离高考只有几天了:这里的“几天”是指从高考前的一周到高考当天的时间。 由于高考通常在6月7日开始,所以如果在6月份,那么距离高考就只有几天的时间了。\n\n综上所述,九月份离高考还有九个月,而六月 份离高考只有几天了,这是由于高考的时间是固定的,并且九月份和六月份分别代表了高考前后的不同时间段。"}]} 47 | {"messages": [{"role": "user", "content": "从桃子里出来的叫桃太郎,那海尔兄弟是不是算一种空调成太郎"}, {"role": "assistant", "content": "哈哈,这个说法有趣!海尔兄弟是中国一家知名的电器制造公司,而空调是该公司的一种产品。但海尔兄弟并不是像桃太郎那样从某种水果里出来的,所以不能算作一种空调成太郎。这个说法更像是一种幽默或调侃,将事物进行巧妙联系而产生的幽默效果。"}]} 48 | {"messages": [{"role": "user", "content": "为啥长寿的碰巧都是老年人?"}, {"role": "assistant", "content": "这个问题其实是一个很好的例子,展示了因果混淆的概念。在这个问题中,看似“长寿的碰巧都是老年人”这一现象是有因果关系的,但实际上这是一种逻辑上的混淆。\n\n长寿的定义本身就是指那些活得比常人更久的人。因此,所有长寿的人自然而然都是老年人,因为他们已经经历了长时间的生命过程。这并不是说成为老年人会导致长寿,而是长寿的结果自然就是年龄的增长。换句话说,老年人之所以老,是因为他们长寿,而不是他们长寿是因为他们是老年人。\n\n这个问题实际上揭示了一个常见的逻辑错误,即将结果与原因混为一谈。在很多情况下,我们需要仔细分析和区分事件之间的因果关系,以避免误解和错误的结论。"}]} 49 | {"messages": [{"role": "user", "content": "文言文是用哪个词来表示\"电脑\"的找了半天没找到 又怕语文考试考"}, {"role": "assistant", "content": "在文言文中,由于电脑是现代科技产品,所以并没有一个确切的古代词汇对应“电脑”。但是,如果需要在文言文中表达与“电 脑”相关的概念,我们可以采用一些近似的表达方式或创造性的描述。\n\n例如,可以使用类似“电算机”(电:指电力,算:计算,机: 机械)这样的组合词。这种表达虽然不是传统文言文中的词汇,但能在一定程度上传达出“电脑”这一现代概念。在语文考试中,对于这种现代事物的文言文表达,通常更注重学生的创新和合理性,而不是寻找一个确切的古代对应词汇。"}]} 50 | {"messages": [{"role": "user", "content": "被狼养大的婴儿能听懂狼话,所以被机器人养大的👶🏻会C语言"}, {"role": "assistant", "content": "这个说法并不准确。被狼养大的婴儿并不会听懂狼的语言,就如同被机器人养大的婴儿也不会自动学会编程语言。\n\n人类语言能力是通过接触人类社会和语言环境而获得的,而动物的沟通方式和人类语言之间存在巨大差异。狼之间的交流是通过嗥叫、姿态、气味等方式进行的,这种交流方式与人类语言截然不同。因此,即便是被狼养大的婴儿,也不会自动地理解或掌握狼的交流方式,更不用说能够听懂狼的语言。\n\n同样地,机器人是按照程序设计运行的工具,它们并不具备人类的情感、意识或语言理解能力。因此,被机器人养大的婴儿也不会自动地学会编程语言或任何特定的语言。\n\n人类学习语言和编程语言都需要接受相关的教育和学习过程,在适当的环境下积极学习才能掌握。"}]} 51 | {"messages": [{"role": "user", "content": "16岁了,未满18岁正常吗"}, {"role": "assistant", "content": "16岁还未满18岁是完全正常的。年龄是按照出生日期逐年计算的,所以直到你的18岁生日那一天,你仍然会被认为是16岁或17岁。不用担心,这是自然的成长过程的一部分。如果你有关于成长或年龄的任何疑问,可以随时提问。"}]} 52 | {"messages": [{"role": "user", "content": "后妈和我没有血缘关系,是不是可以叫做伪娘"}, {"role": "assistant", "content": "“伪娘”通常指的是男性外表或形象上有意模仿女性的人,但这个词语的使用可能因文化、社会和语境的不同而有所差异。\n\n“后妈”一般指的是父亲再婚后的妻子,尽管在血缘上可能与孩子没有直接的亲缘关系,但在家庭和社会角色上,她扮演着母亲的角色,为家庭中的孩子提供照顾和关爱。\n\n在语言上,把后妈称为“伪娘”这个词可能会引起误解或困惑,因为这个词更常用来指代男性装扮成女性的情况。通常情况下,把后妈称为“伪娘”可能不太合适或不准确,因为她与“伪娘”这个词所指代的情境不同。\n\n如果您想准确地描述家庭关系,可能更好地选择使用“后妈”一词,表达她在您生活中所扮演的角色。血缘并不是唯一决定家庭关系的因素,重要的是人与人之间的情感、照顾和支持。"}]} 53 | {"messages": [{"role": "user", "content": "李白如果告语文书侵权的话能赔不少钱吧"}, {"role": "assistant", "content": "如果李白(701年2月28日—762年12月)真的能就侵权诉讼获得赔偿,那确实可能是一笔不小的金额。然而,这种想法主要是一种有趣的假设,因为现实中有几个关键因素使这种情况不可能发生:\n\n1. **时间差异**:李白生活在唐朝,距今大约1200多年前。那 个时代的法律体系与现代的知识产权法律截然不同,当时没有现代意义上的版权法。\n\n2. **版权法的适用范围**:即使在现代,版权 法也有一定的时效限制。在大多数国家,版权保护通常在作者去世后一定年数内有效(如我国是作者去世后50年)。李白去世已超过1250年,因此其作品已经进入公共领域,任何人都可以自由使用而无需支付版权费用。\n\n3. **历史与现实的区别**:历史人物无法在现代 法律体系中提起诉讼,因为他们不再是活跃的法律主体。\n\n所以,虽然这是一个有趣的想法,但在现实中,李白或其他古代作者无法因其作品被现代出版物使用而获得赔偿。"}]} 54 | {"messages": [{"role": "user", "content": "和我家狗聊了一晚上,我根本听不懂,因为它说的全是吠话"}, {"role": "assistant", "content": "和狗狗交流,尽管听不懂它们的“吠话”(这个词跟汉语中的“废话”发音相似,富有幽默感),但还是可以通过其他方式建立良好的沟通。以下是一些建议:\n\n1. **肢体语言**:狗狗很擅长通过人类的身体语言和表情来理解我们。保持身体放松、微笑和友好的 眼神可以传达亲切和安全感。\n\n2. **语调和声音**:即使它们不理解具体的词汇,狗狗也能感受到你说话的语调和情感。用温和、平 静的声音跟它们交流,可以帮助它们理解你的情绪和意图。\n\n3. **简单的指令**:使用简单、一致的指令可以帮助狗狗理解你的要求 。比如“坐下”、“过来”、“待着”等。\n\n4. **正面强化**:通过奖励和表扬来强化狗狗的好行为。当它们做对了事情,给予食物奖励、 拥抱或口头夸奖。\n\n5. **花时间一起**:与狗狗共度时间,比如散步、玩耍或简单的互动,能够加深你们之间的理解和联系。\n\n6. **观察它们的行为**:注意狗狗的身体语言和行为模式,这可以帮助你更好地理解它们的需求和感受。\n\n记住,每只狗狗的性格和沟通方式都不尽相同,所以耐心和持续的交流是关键。通过这些方法,你和你的狗狗可以建立更深层次的理解和联系。"}]} 55 | {"messages": [{"role": "user", "content": "既然怀胎十月,那么怀上双胞胎是不是得怀20个月"}, {"role": "assistant", "content": "并非如此。怀胎时间通常是指从受精卵形成开始到婴儿出生的时间长度。即使怀上双胞胎,怀孕的时间通常仍然是按照相同的标准。在大多数情况下,双胞胎的怀孕期并不是普遍意义上的两倍,而是在相同的时间内完成发育,通常仍然是约十个月左右。\n\n双胞胎的怀孕虽然在某些方面会有所不同,但怀孕的时间通常仍然是以自然产的方式完成,大多数情况下与单胎怀孕的时间长度相似。"}]} 56 | {"messages": [{"role": "user", "content": "都说男人永远是男孩,为啥父辈们都已经两鬓斑白"}, {"role": "assistant", "content": "这种说法“男人永远是男孩”通常指的是男性在内心深处总是保留着一份年轻的热情和童真,即使年龄增长,也会保持一些年轻时的特质和特点。然而,这并不意味着男性不会随着年龄的增长而经历生活中的变化,包括身体上的变化和外在的表现。\n\n父辈们已经两鬓斑白是因为随着年龄的增长,人体会经历生理上的变化,包括头发变白是常见现象之一。头发的颜色变白是因为毛囊中的黑色素减少,随着年龄增长,黑色素的分泌减少会导致头发变白。这种自然的生理变化并不代表他们的内心永远只是“男孩”,而是在外观上的年龄变化。\n\n虽然内心可能依旧充满了青春和活力,但身体上会有自然的老化过程。父辈们的两鬓斑白可能是时间的印记,是年龄增长的一部分,但并不影响他们保持年轻的心态和活力。"}]} 57 | {"messages": [{"role": "user", "content": "为什么不让小偷去做开锁师傅呢?既能够降低犯罪率,小偷的技术又比师傅好,不是一举两得吗?"}, {"role": "assistant", "content": "这个问题涉及到道德、法律和社会责任的多个方面。首先,要考虑到一个基本的原则:一个人过去的不当行为不应该直接决定他们未来的职业道路。然而,让曾经的小偷成为开锁师傅存在几个问题:\n\n1. **信任和诚信问题**:开锁师傅的工作要求极高的诚信 和信任度。客户需要相信这个人不会利用他们的技能进行不法活动。一个有犯罪记录的人可能很难获得这种信任。\n\n2. **法律和资质 问题**:很多地区的开锁师傅需要持有专业许可证,这些许可证可能要求申请者没有犯罪记录。此外,雇主可能会因为法律责任而不愿意雇佣有犯罪背景的人。\n\n3. **改造和培训问题**:虽然小偷可能拥有一定的开锁技能,但这并不意味着他们已经具备成为合格开锁师 傅所需要的全部技能和专业知识。他们可能还需要接受正规的培训和教育。\n\n4. **社会观念和接受度问题**:社会大众可能对曾经的 小偷转行成为开锁师傅持保留态度,这可能影响他们的职业发展和个人生活。\n\n虽然将曾经的小偷转行成为开锁师傅在理论上可能有助于降低犯罪率,并且利用他们的技能,但实际操作中需要考虑到以上多个方面的问题。此外,更重要的是为这些人提供更全面的社会支持和职业培训,以帮助他们走上合法和有益的职业道路。"}]} 58 | {"messages": [{"role": "user", "content": "抢劫的人为什么都抢手机电脑这些为什么不直接抢房子呢,房子比这个值钱多了"}, {"role": "assistant", "content": "抢劫者倾向于偷窃手机、电脑等物品而不是房屋,主要是因为小型物品易于携带和转移。这些物品通常具有较高的价值和较小的体积,便于快速携带和隐藏。相比之下,房屋不仅价值巨大,而且不可移动。即使有能力非法占有房屋,这种行为也很容易被发现和追踪。此外,房产的所有权和转移记录通常由政府机构严格管理,非法占有或转让房产几乎不可能不被发现。因此,尽管房屋的价值远高于一般的小型物品,但由于其不便于携带和转移的特性,抢劫者通常不会选择偷窃房屋。"}]} 59 | {"messages": [{"role": "user", "content": "买了一套26英文字母玩具,却发现只收到了23个我去找商家理论,商家却说我没买dlc"}, {"role": "assistant", "content": "这个描述似乎是在以玩具和游戏的术语来调侃一种情境。\n\n在这个情景中,“26个字母玩具”可能指的是完整的字母集合,但你只收到了其中的23个。而“商家说我没买dlc”这句话则可能在调侃,用游戏术语中的“DLC”(Downloadable Content,下载内容)来暗示购买了玩具的全部内容或者补充内容。\n\n这种描述或许是在用幽默的方式来表达一种尴尬或不满的情绪。在现实生活中,如果你购买了某件产品或服务,但未收到完整的内容,你可以向商家提出投诉或要求解决方案,比如退款或补发剩下的字母玩具。"}]} 60 | {"messages": [{"role": "user", "content": "奶奶把去世的爷爷一直用的手机交给了我,我可以自己装作爷爷给自己发消息而不被发现吗,真的好想他。"}, {"role": "assistant", "content": "你的想法很动人,想通过手机来缅怀你爷爷的记忆是很有意义的。但技术上来讲,给自己发送消息而不被自己发现是不可能的,因为发送和接收消息的动作都需要你自己来操作。\n\n但是,有一些其他方式可以帮助你缅怀爷爷:\n\n1. **写日记或信件**:你可 以写下想对爷爷说的话,就像给他写信一样。这可以是一种治愈的方式,帮助你表达思念。\n\n2. **制作纪念相册或视频**:用爷爷的 照片和一些美好回忆制作一个相册或视频。\n\n3. **设置提醒**:在手机上设置一些提醒,用一些爷爷生前常说的话或者特别的日期来 提醒你记住他。\n\n4. **倾听录音**:如果手机里有爷爷的语音消息或录音,你可以偶尔听听,感受他的存在。\n\n这些方式都可以帮 助你在思念爷爷的同时,找到一种表达和纪念的方式。记住,每个人的哀悼和纪念方式都是独特的,找到最适合你的方式最重要。"}]} 61 | {"messages": [{"role": "user", "content": "偃月刀是宋朝人发明的那宋朝人看三国演义听到关羽手持青龙偃月刀,是不是就相当于我们听到关羽手持95式冲锋枪"}, {"role": "assistant", "content": "\n您提出的观点很有趣。确实,宋朝(960年-1279年)与三国时期(220年-280年)相隔了几个世纪,所以宋朝人不可能亲眼见 证三国时期的事件。《三国演义》这部小说是在明朝初期由罗贯中创作的,比宋朝晚了至少百年。因此,宋朝人不可能读到或听到《三国演义》中关于关羽和他的青龙偃月刀的故事。\n\n而我们可以整体类比,把宋朝的名将岳飞与现代武器结合起来,确实更加贴切。岳飞是宋朝的英雄,而95式冲锋枪是现代的武器。这种设想就像我们在历史小说或者电影中看到古代英雄使用现代武器一样,是一种跨时代的想象。这种想象在创作中很常见,用来增加故事的趣味性或展现不同的历史观点。"}]} 62 | {"messages": [{"role": "user", "content": "“单车欲问边”证明了早在唐朝就有了自行车"}, {"role": "assistant", "content": "“单车欲问边”这句话并不是证明自行车在唐朝时期已经存在。这句话实际上是出自王维的《使至塞上》诗中,“单车欲问边,属国过居延”描述的是诗人轻车简从将要去慰问边关,到远在西北边塞的居延。\n\n自行车的发明与唐朝时期无关,实际上自行车是在19世纪才被发明。最早的自行车出现在欧洲,而不是在古代中国。它的发明有着漫长的历史和逐步演变的过程,涉及到多位发明家和创新者的贡献。\n\n虽然古代可能有一些与骑行有关的交通工具,但与现代自行车相比,它们的设计和机制是完全不同的,不能简单地将古代的某些交通工具等同于现代自行车。"}]} 63 | {"messages": [{"role": "user", "content": "哪吒三头六臂,就一个心脏会供血不足吧"}, {"role": "assistant", "content": "哪吒是中国传统文化中的一个神话人物,在传说中通常被描述为三头六臂的神灵少年。尽管在神话传说中,哪吒通常被描绘为拥有特殊力量和超能力,但从生理学的角度来看,如果一个人只有一个心脏,供血给六只手臂和三个头部的确是一个难以解决的问题。\n\n在生理上,每个人通常只有一个心脏,它通过循环系统将氧气和营养输送到全身各个组织和器官。如果一个人拥有六只手臂和三个头部,单一的心脏很难有效地为这么多身体部位提供足够的血液和氧气,可能导致供血不足问题。\n\n然而,神话故事中的角色通常不受现实生理规律的限制,他们被描绘为具有超自然的能力和特殊的身体构造。因此,对于哪吒这样的神话人物,我们更应该将其视作传说和文化的象征,而不是基于生理学的实际讨论。"}]} 64 | {"messages": [{"role": "user", "content": "既然禁止大学生请假替高考生高考那找高三学生不就行了吗,高中知识他们学得最好"}, {"role": "assistant", "content": "高考通常是高中三年级学生参加的,因此他们自己就是高考的考生。所以,让其他高三学生代替参加高考是不可能的,因为他们自己也需要参加同一场考试。此外,任何形式的代考都是不道德的,通常也是违法的。考试的目的是评估学生个人的学习成果,而不是别人的。"}]} 65 | {"messages": [{"role": "user", "content": "既然监狱里全是罪犯,👮♀️为什么不去监狱里抓人"}, {"role": "assistant", "content": "警察和执法部门会根据法律规定和程序去执行逮捕和抓捕行动。在监狱里的人通常已经经过司法程序的审判,被判定有罪并被判处相应的刑罚。监狱里的人员被关押在那里是根据法律和司法程序,他们正在执行刑罚而不是被捕。\n\n警察通常不会随意进入监狱抓捕人员,除非有特定的司法程序和逮捕令。在逮捕或抓捕犯人时,警察必须依照法律程序,以合法和合理的方式进行行动,保障被捕者的合法权益。\n\n另外,监狱通常有安全措施和监管制度,以防止犯人逃跑或发生其他安全问题。警察在执行逮捕任务时通常会选择合适的时间、地点和方式来执行行动,以确保行动的顺利和安全。"}]} 66 | {"messages": [{"role": "user", "content": "室内18度,室外7度,天气好冷怎么办?为什么不打开窗把室外的7度放进来"}, {"role": "assistant", "content": "面对这种温度差异和想要打开窗户来平衡温度的想法,存在着一个逻辑谬误。这个情况下,打开窗户并不会使室内温度变为室外的7度,而是室内外的温度会趋向平衡。这意味着室内温度可能会下降,而室外温度可能会略微上升,直到两者达到某个中间值。\n\n 为了应对寒冷的天气,保持室内温暖的更合理的方法可能包括使用暖气、穿着保暖的衣物,或者增加室内的保温措施,如使用厚窗帘或门帘来降低热量流失。在这种情况下,开窗可能会导致更多的热量流失,使室内变得更冷。"}]} 67 | {"messages": [{"role": "user", "content": "幼儿园里都是儿童,养老院里都是老人,那医院里应该都是医生才对我又不是医生,为什么把我关在这里"}, {"role": "assistant", "content": "这个说法有点误导。在幼儿园里,除了孩子们,还有老师和其他工作人员;在养老院里,除了老人,还有护理人员和管理人员。同样地,医院是一个提供医疗服务和治疗的地方,里面不仅有医生,还有护士、行政人员、患者家属等多种角色和人员。医院不仅是医生的工作场所,也是病人接受治疗和护理的场所。\n\n如果您并非医生,但被留在医院,可能是因为您需要接受医疗护理或者是陪同患者就医。医院也有陪护人员或家属陪同病人就医的情况,他们通常不是医生,但在医院内陪伴病人接受治疗。\n\n除此之外,医院也可能有其他用途,例如健康检查、探访病友、进行志愿者活动等。因此,并不是所有在医院内的人都是医生,医院承担着多种功能和服务,不仅仅局限于医生的工作场所。"}]} 68 | {"messages": [{"role": "user", "content": "坏掉的东西,还能修好。可是坏掉的感情,岂可修吗?"}, {"role": "assistant", "content": "这句话的字面意思是:“坏掉的东西还能修好,但是坏掉的感情能修复吗?” 这里所表达的是一个深刻的思考,关于物质事物 与情感事物之间的区别和修复的可能性。在物质世界中,许多损坏的东西可以通过物理手段修复,但感情的损伤却远比物理上的损坏更复杂。\n\n至于“岂可修”这个词语,它在中文里直译为“怎么能够修复?”,但是在网络语言中,它也是日文“畜生”(ちくしょう)的空耳,这个日语词汇通常用来表达愤怒或失望,意思是“可恶”或“可恨”。\n\n至于这个问题的回答,感情的修复并不像物质事物那样简单。感情的伤害通常涉及复杂的情感、信任和理解等因素。虽然有些情感伤害是可以逐渐愈合的,但这通常需要时间、努力、沟通和双方的愿意。有些感情伤害可能是无法完全修复的,特别是当伤害太深或者双方无法找到一个共同点时。所以,是否能修复坏掉的感情,取决于具体情况和双方的努力。"}]} 69 | {"messages": [{"role": "user", "content": "听说拼多多可以假一赔十,那我开店卖假货自己买,岂不是一本十利啊"}, {"role": "assistant", "content": "这个想法听起来有些荒谬。首先,拼多多或任何其他电商平台上卖假货是非法的,违反了知识产权和消费者权益保护法规。而且,平台通常会有严格的监控和惩罚机制来打击假货销售。这样的行为不仅可能导致店铺被关闭,还可能面临法律诉讼和罚款。\n\n其次,即使是“假一赔十”的政策,也通常是指对消费者的赔偿,而不是对卖家本身。自己买自己的商品,然后自己向自己赔偿,从逻辑上讲是不成立的。此外,这种行为还可能被视为欺诈,导致更严重的法律后果。\n\n总的来说,这种尝试通过违法手段获利的想法是不可取的,不仅可能遭受重大经济损失,还有可能面临严重的法律后果。正确的经营方式应该是提供高质量、合法的商品,以诚信赢得消费者的信任和支持。"}]} 70 | {"messages": [{"role": "user", "content": "聋哑人晚上睡觉会不会用手语打呼噜"}, {"role": "assistant", "content": "聋哑人睡觉时是否会用手语打呼噜这一情况,与其聋哑状态本身无直接关系。打呼噜通常是由于睡眠时呼吸道的部分阻塞引起的,而不是与语言或听力能力有关。\n\n聋哑人因失去听觉和语言功能,可能会使用手语进行交流。但是,他们是否会在睡眠中用手语或手部动作打呼噜,与他们的聋哑状态并无必然联系。打呼噜是睡眠时特定的生理反应,而不是由于使用手语而产生的。\n\n打呼噜通常与睡眠姿势、呼吸道结构、身体健康状况等因素有关。无论是否是聋哑人,任何人在特定条件下都可能出现打呼噜的情况。"}]} 71 | {"messages": [{"role": "user", "content": "为啥新闻里有个小屏幕还有人打手语,盲人也看不见啊"}, {"role": "assistant", "content": "在新闻节目或电视节目中,有时会出现小屏幕上显示人在用手语进行翻译的情况。这个做法是为了让聋人观众能够理解节目内容。虽然盲人看不见屏幕,但是手语翻译主要是为了聋人观众,提供他们能够理解节目内容的方式。\n\n同时,对于视力障碍者或盲人观众,通常电视节目或新闻会采用语音翻译或提供声音描述,让他们通过听觉获得信息。例如,会有解说员进行描述,说明屏幕上正在展示的内容,以便盲人观众能够了解节目的内容。\n\n这种多样化的信息呈现方式旨在尽可能地使不同群体的观众能够获取节目内容,包括聋人和盲人。虽然手语翻译对盲人观众来说并不适用,但是针对不同群体的观众,通常会提供多种形式的辅助信息来满足他们的需求。"}]} 72 | {"messages": [{"role": "user", "content": "明明是食品级不锈钢,为什么还是这么难以下咽。"}, {"role": "assistant", "content": "\"食品级不锈钢\"是指这种不锈钢材料适用于与食品接触,确保不会对食品造成污染或者化学反应。这类不锈钢通常用于制造厨房用具、餐具和食品加工设备。然而,\"食品级\"并不意味着这种材料本身是可食用的。实际上,不锈钢是一种金属合金,不论其质量如何,都不适宜直接食用。这个表述可能导致了误解,认为\"食品级不锈钢\"意味着它可以被食用,但实际上它仅仅是标明这种材料安全地与食品接触,不会对食品造成污染。"}]} 73 | -------------------------------------------------------------------------------- /FineTune/img/after1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/after1.png -------------------------------------------------------------------------------- /FineTune/img/after2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/after2.png -------------------------------------------------------------------------------- /FineTune/img/after3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/after3.png -------------------------------------------------------------------------------- /FineTune/img/before1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/before1.png -------------------------------------------------------------------------------- /FineTune/img/before2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/before2.png -------------------------------------------------------------------------------- /FineTune/img/before3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/before3.png -------------------------------------------------------------------------------- /FineTune/img/robot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/FineTune/img/robot.webp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 书生·浦语大模型实战营 2 | 3 | ![](./asset/camp.png) 4 | 5 | 为了推动大模型在更多行业落地开花,让开发者们更高效的学习大模型的开发与应用,上海人工智能实验室重磅推出书生·浦语大模型实战营,为广大开发者搭建大模型学习和实践开发的平台,两周时间带你玩转大模型微调、部署与评测全链路。 6 | 7 | 实战营春季第4补增场火热报名中,欢迎填写[表单](https://www.wjx.top/vm/Yzzz2mi.aspx?udsid=876275)报名! 8 | 报名成功后加入群聊,私聊助教或者浦语小助手获取免费 A100 算力支持!!! 9 | 10 | ## 😊 你将获得 11 | 12 | 👨‍🏫 实力讲师:来自前沿科研机构、一线大厂和 Github 热门开源项目的讲师手把手教学 13 | 💻 算力支持:算力资源免费提供,助力无忧训练大模型 14 | 💬 专属社群:助教、讲师全程陪伴,提供录播回放、线上答疑及实战作业辅导 15 | 📜 官方认证:优秀学员将获得荣誉证书,优秀项目有机会被官方收录,获得更多展示 16 | 17 | ## 📅 课程安排 18 | 19 | |课程时间|课程内容|讲师|资料| 20 | |:-----|:----|:----|:-----| 21 | |第 1 节|书生·浦语大模型全链路开源体系 |陈恺
上海人工智能实验室青年科学家|[视频](https://www.bilibili.com/video/BV1Rc411b7ns/) | 22 | |第 2 节|轻松玩转书生·浦语大模型趣味 Demo|宋志学
d2l-ai-solutions-manual 开源项目负责人| [文档](./helloworld/hello_world.md)、[视频](https://www.bilibili.com/video/BV1Ci4y1z72H) | 23 | |第 3 节|基于 InternLM 和 LangChain 搭建你的知识库|邹雨衡
prompt-engineering-for-developers 开源项目负责人| [文档](./langchain/readme.md)、[视频](https://www.bilibili.com/video/BV1sT4y1p71V/) | 24 | |第 4 节|XTuner 大模型单卡低成本微调实战|汪周谦
XTuner 社区贡献者| [文档](./xtuner/README.md)、[视频](https://www.bilibili.com/video/BV1yK4y1B75J) | 25 | |第 5 节|LMDeploy 大模型量化部署实践|长琴
HuggingLLM开源项目负责人| [文档](./lmdeploy/lmdeploy.md)、[视频](https://www.bilibili.com/video/BV1iW4y1A77P) | 26 | |第 6 节|OpenCompass 大模型评测|曹茂松
OpenCompass 核心开发者| [文档](./opencompass/opencompass_tutorial.md)、[视频](https://www.bilibili.com/video/BV1Gg4y1U7uc/) | 27 | |第 7 节|彩蛋环节| 神秘嘉宾 | 文档、视频 | 28 | 29 | 30 | ## 📝 作业 31 | 32 | 助教老师将在社群中公布每节课的作业及提交方式 33 | 34 | 35 | ## 🖥️ 算力平台 36 | 37 | https://studio.intern-ai.org.cn/ 38 | 39 | 问卷中的核销码为邀请码,如额外需要充值算力或者其他任何疑问请联系浦语小助手(微信号搜索:InternLM) 40 | -------------------------------------------------------------------------------- /asset/camp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/asset/camp.png -------------------------------------------------------------------------------- /helloworld/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/.gitkeep -------------------------------------------------------------------------------- /helloworld/hello_world.md: -------------------------------------------------------------------------------- 1 | ![](./images/head.png) 2 | 3 | # 轻松玩转书生·浦语大模型趣味 Demo 4 | - [轻松玩转书生·浦语大模型趣味 Demo](#轻松玩转书生浦语大模型趣味-demo) 5 | - [1 大模型及 InternLM 模型简介](#1-大模型及-internlm-模型简介) 6 | - [1.1 什么是大模型?](#11-什么是大模型) 7 | - [1.2 InternLM 模型全链条开源](#12-internlm-模型全链条开源) 8 | - [2 InternLM-Chat-7B 智能对话 Demo](#2-internlm-chat-7b-智能对话-demo) 9 | - [2.1 环境准备](#21-环境准备) 10 | - [2.2 模型下载](#22-模型下载) 11 | - [2.3 代码准备](#23-代码准备) 12 | - [2.4 终端运行](#24-终端运行) 13 | - [2.5 web demo 运行](#25-web-demo-运行) 14 | - [3 Lagent 智能体工具调用 Demo](#3-lagent-智能体工具调用-demo) 15 | - [3.1 环境准备](#31-环境准备) 16 | - [3.2 模型下载](#32-模型下载) 17 | - [3.3 Lagent 安装](#33-lagent-安装) 18 | - [3.4 修改代码](#34-修改代码) 19 | - [3.5 Demo 运行](#35-demo-运行) 20 | - [4. 浦语·灵笔图文理解创作 Demo](#4-浦语灵笔图文理解创作-demo) 21 | - [4.1 环境准备](#41-环境准备) 22 | - [4.2 模型下载](#42-模型下载) 23 | - [4.3 代码准备](#43-代码准备) 24 | - [4.4 Demo 运行](#44-demo-运行) 25 | - [5. 通用环境配置](#5-通用环境配置) 26 | - [5.1 pip、conda 换源](#51-pipconda-换源) 27 | - [5.1.1 pip 换源](#511-pip-换源) 28 | - [5.1.2 conda 换源](#512-conda-换源) 29 | - [5.2 配置本地端口](#52-配置本地端口) 30 | - [5.3 模型下载](#53-模型下载) 31 | - [5.3.1 Hugging Face](#531-hugging-face) 32 | - [5.3.2 ModelScope](#532-modelscope) 33 | - [5.3.3 OpenXLab](#533-openxlab) 34 | - [6. 课后作业](#6-课后作业) 35 | 36 | 37 | ## 1 大模型及 InternLM 模型简介 38 | 39 | ### 1.1 什么是大模型? 40 | 41 |   大模型通常指的是机器学习或人工智能领域中参数数量巨大、拥有庞大计算能力和参数规模的模型。这些模型利用大量数据进行训练,并且拥有数十亿甚至数千亿个参数。大模型的出现和发展得益于增长的数据量、计算能力的提升以及算法优化等因素。这些模型在各种任务中展现出惊人的性能,比如自然语言处理、计算机视觉、语音识别等。这种模型通常采用深度神经网络结构,如 `Transformer`、`BERT`、`GPT`( Generative Pre-trained Transformer )等。 42 | 43 |   大模型的优势在于其能够捕捉和理解数据中更为复杂、抽象的特征和关系。通过大规模参数的学习,它们可以提高在各种任务上的泛化能力,并在未经过大量特定领域数据训练的情况下实现较好的表现。然而,大模型也面临着一些挑战,比如巨大的计算资源需求、高昂的训练成本、对大规模数据的依赖以及模型的可解释性等问题。因此,大模型的应用和发展也需要在性能、成本和道德等多个方面进行权衡和考量。 44 | 45 | ### 1.2 InternLM 模型全链条开源 46 | 47 |   `InternLM` 是一个开源的轻量级训练框架,旨在支持大模型训练而无需大量的依赖。通过单一的代码库,它支持在拥有数千个 `GPU` 的大型集群上进行预训练,并在单个 `GPU` 上进行微调,同时实现了卓越的性能优化。在 `1024` 个 `GPU` 上训练时,`InternLM` 可以实现近 `90%` 的加速效率。 48 | 49 |   基于 `InternLM` 训练框架,上海人工智能实验室已经发布了两个开源的预训练模型:`InternLM-7B` 和 `InternLM-20B`。 50 | 51 |   `Lagent` 是一个轻量级、开源的基于大语言模型的智能体(agent)框架,支持用户快速地将一个大语言模型转变为多种类型的智能体,并提供了一些典型工具为大语言模型赋能。通过 `Lagent` 框架可以更好的发挥 `InternLM` 的全部性能。 52 | 53 | ![Lagent 框架图](./images/Lagent.png) 54 | 55 |   浦语·灵笔是基于书生·浦语大语言模型研发的视觉-语言大模型,提供出色的图文理解和创作能力,结合了视觉和语言的先进技术,能够实现图像到文本、文本到图像的双向转换。使用浦语·灵笔大模型可以轻松的创作一篇图文推文,也能够轻松识别一张图片中的物体,并生成对应的文本描述。 56 | 57 |   上述提到的所有模型,都会带领大家一起体验哦!欢迎大家来给 `InternLM`: https://github.com/InternLM/InternLM/ 点点 star 哦! 58 | 59 | ## 2 InternLM-Chat-7B 智能对话 Demo 60 | 61 | 本小节我们将使用 [InternStudio](https://studio.intern-ai.org.cn/) 中的 A100(1/4) 机器和 `InternLM-Chat-7B` 模型部署一个智能对话 Demo。 62 | 63 | ### 2.1 环境准备 64 | 65 | 在 [InternStudio](https://studio.intern-ai.org.cn/) 平台中选择 A100(1/4) 的配置,如下图所示镜像选择 `Cuda11.7-conda`,如下图所示: 66 | 67 | ![Alt text](images/image.png) 68 | 69 | 接下来打开刚刚租用服务器的`进入开发机`,并且打开其中的终端开始环境配置、模型下载和运行 `demo`。 70 | 71 | ![Alt text](images/image-1.png) 72 | 73 | 进入开发机后,在页面的左上角可以切换 `JupyterLab`、`终端`和 `VScode`,并在终端输入 `bash` 命令,进入 `conda` 环境。如下图所示: 74 | 75 | ![Alt text](images/image-11.png) 76 | 77 | 进入 `conda` 环境之后,使用以下命令从本地克隆一个已有的 `pytorch 2.0.1` 的环境 78 | 79 | ```shell 80 | bash # 请每次使用 jupyter lab 打开终端时务必先执行 bash 命令进入 bash 中 81 | bash /root/share/install_conda_env_internlm_base.sh internlm-demo # 执行该脚本文件来安装项目实验环境 82 | ``` 83 | 84 | 然后使用以下命令激活环境 85 | 86 | ```shell 87 | conda activate internlm-demo 88 | ``` 89 | 90 | 并在环境中安装运行 demo 所需要的依赖。 91 | 92 | ```shell 93 | # 升级pip 94 | python -m pip install --upgrade pip 95 | 96 | pip install modelscope==1.9.5 97 | pip install transformers==4.35.2 98 | pip install streamlit==1.24.0 99 | pip install sentencepiece==0.1.99 100 | pip install accelerate==0.24.1 101 | ``` 102 | ### 2.2 模型下载 103 | 104 | [InternStudio](https://studio.intern-ai.org.cn/) 平台的 `share` 目录下已经为我们准备了全系列的 `InternLM` 模型,所以我们可以直接复制即可。使用如下命令复制: 105 | 106 | ```shell 107 | mkdir -p /root/model/Shanghai_AI_Laboratory 108 | cp -r /root/share/temp/model_repos/internlm-chat-7b /root/model/Shanghai_AI_Laboratory 109 | ``` 110 | > -r 选项表示递归地复制目录及其内容 111 | 112 | 也可以使用 `modelscope` 中的 `snapshot_download` 函数下载模型,第一个参数为模型名称,参数 `cache_dir` 为模型的下载路径。 113 | 114 | 在 `/root` 路径下新建目录 `model`,在目录下新建 `download.py` 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 `python /root/model/download.py` 执行下载,模型大小为 14 GB,下载模型大概需要 10~20 分钟 115 | 116 | ```python 117 | import torch 118 | from modelscope import snapshot_download, AutoModel, AutoTokenizer 119 | import os 120 | model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-chat-7b', cache_dir='/root/model', revision='v1.0.3') 121 | ``` 122 | 123 | > 注意:使用 `pwd` 命令可以查看当前的路径,`JupyterLab` 左侧目录栏显示为 `/root/` 下的路径。 124 | 125 | ![image](images/image-2.png) 126 | 127 | ### 2.3 代码准备 128 | 129 | 首先 `clone` 代码,在 `/root` 路径下新建 `code` 目录,然后切换路径, clone 代码. 130 | 131 | ```shell 132 | cd /root/code 133 | git clone https://gitee.com/internlm/InternLM.git 134 | ``` 135 | 136 | 切换 commit 版本,与教程 commit 版本保持一致,可以让大家更好的复现。 137 | 138 | ```shell 139 | cd InternLM 140 | git checkout 3028f07cb79e5b1d7342f4ad8d11efad3fd13d17 141 | ``` 142 | 143 | 将 `/root/code/InternLM/web_demo.py` 中 29 行和 33 行的模型更换为本地的 `/root/model/Shanghai_AI_Laboratory/internlm-chat-7b`。 144 | 145 | ![image-3](images/image-3.png) 146 | 147 | ### 2.4 终端运行 148 | 149 | 我们可以在 `/root/code/InternLM` 目录下新建一个 `cli_demo.py` 文件,将以下代码填入其中: 150 | 151 | ```python 152 | import torch 153 | from transformers import AutoTokenizer, AutoModelForCausalLM 154 | 155 | 156 | model_name_or_path = "/root/model/Shanghai_AI_Laboratory/internlm-chat-7b" 157 | 158 | tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=True) 159 | model = AutoModelForCausalLM.from_pretrained(model_name_or_path, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map='auto') 160 | model = model.eval() 161 | 162 | system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语). 163 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 164 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 165 | """ 166 | 167 | messages = [(system_prompt, '')] 168 | 169 | print("=============Welcome to InternLM chatbot, type 'exit' to exit.=============") 170 | 171 | while True: 172 | input_text = input("User >>> ") 173 | input_text = input_text.replace(' ', '') 174 | if input_text == "exit": 175 | break 176 | response, history = model.chat(tokenizer, input_text, history=messages) 177 | messages.append((input_text, response)) 178 | print(f"robot >>> {response}") 179 | ``` 180 | 181 | 然后在终端运行以下命令,即可体验 `InternLM-Chat-7B` 模型的对话能力。对话效果如下所示: 182 | 183 | ```shell 184 | python /root/code/InternLM/cli_demo.py 185 | ``` 186 | ![Alt text](images/image-18.png) 187 | 188 | ### 2.5 web demo 运行 189 | 190 | 我们切换到 `VScode` 中,运行 `/root/code/InternLM` 目录下的 `web_demo.py` 文件,输入以下命令后,[**查看本教程5.2配置本地端口后**](./hello_world.md#52-配置本地端口),将端口映射到本地。在本地浏览器输入 `http://127.0.0.1:6006` 即可。 191 | 192 | ```shell 193 | bash 194 | conda activate internlm-demo # 首次进入 vscode 会默认是 base 环境,所以首先切换环境 195 | cd /root/code/InternLM 196 | streamlit run web_demo.py --server.address 127.0.0.1 --server.port 6006 197 | ``` 198 | 199 | ![Alt text](images/image-12.png) 200 | 201 | 注意:要在浏览器打开 `http://127.0.0.1:6006` 页面后,模型才会加载,如下图所示: 202 | 203 | ![Alt text](images/image-5.png) 204 | 205 | 在加载完模型之后,就可以与 InternLM-Chat-7B 进行对话了,如下图所示: 206 | 207 | ![Alt text](images/image-6.png) 208 | 209 | ## 3 Lagent 智能体工具调用 Demo 210 | 211 | 本小节我们将使用 [InternStudio](https://studio.intern-ai.org.cn/) 中的 A100(1/4) 机器、`InternLM-Chat-7B` 模型和 `Lagent` 框架部署一个智能工具调用 Demo。 212 | 213 | Lagent 是一个轻量级、开源的基于大语言模型的智能体(agent)框架,支持用户快速地将一个大语言模型转变为多种类型的智能体,并提供了一些典型工具为大语言模型赋能。通过 Lagent 框架可以更好的发挥 InternLM 的全部性能。 214 | 215 | 下面我们就开始动手实现! 216 | 217 | ### 3.1 环境准备 218 | 219 | 选择和第一个 `InternLM` 一样的镜像环境,运行以下命令安装依赖,如果上一个 `InternLM-Chat-7B` 已经配置好环境不需要重复安装. 220 | 221 | ```shell 222 | # 升级pip 223 | python -m pip install --upgrade pip 224 | 225 | pip install modelscope==1.9.5 226 | pip install transformers==4.35.2 227 | pip install streamlit==1.24.0 228 | pip install sentencepiece==0.1.99 229 | pip install accelerate==0.24.1 230 | ``` 231 | 232 | ### 3.2 模型下载 233 | 234 | [InternStudio](https://studio.intern-ai.org.cn/) 平台的 `share` 目录下已经为我们准备了全系列的 `InternLM` 模型,所以我们可以直接复制即可。使用如下命令复制: 235 | 236 | ```shell 237 | mkdir -p /root/model/Shanghai_AI_Laboratory 238 | cp -r /root/share/temp/model_repos/internlm-chat-7b /root/model/Shanghai_AI_Laboratory 239 | ``` 240 | > -r 选项表示递归地复制目录及其内容 241 | 242 | 也可以在 `/root/model` 路径下新建 `download.py` 文件并在其中输入以下内容,并运行 `python /root/model/download.py` 执行下载,模型大小为 14 GB,下载模型大概需要 10~20 分钟 243 | 244 | ```python 245 | import torch 246 | from modelscope import snapshot_download, AutoModel, AutoTokenizer 247 | import os 248 | model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-chat-7b', cache_dir='/root/model', revision='v1.0.3') 249 | ``` 250 | 251 | ### 3.3 Lagent 安装 252 | 253 | 首先切换路径到 `/root/code` 克隆 `lagent` 仓库,并通过 `pip install -e .` 源码安装 `Lagent` 254 | 255 | ```shell 256 | cd /root/code 257 | git clone https://gitee.com/internlm/lagent.git 258 | cd /root/code/lagent 259 | git checkout 511b03889010c4811b1701abb153e02b8e94fb5e # 尽量保证和教程commit版本一致 260 | pip install -e . # 源码安装 261 | ``` 262 | 263 | ### 3.4 修改代码 264 | 265 | 由于代码修改的地方比较多,大家直接将 `/root/code/lagent/examples/react_web_demo.py` 内容替换为以下代码 266 | 267 | ```python 268 | import copy 269 | import os 270 | 271 | import streamlit as st 272 | from streamlit.logger import get_logger 273 | 274 | from lagent.actions import ActionExecutor, GoogleSearch, PythonInterpreter 275 | from lagent.agents.react import ReAct 276 | from lagent.llms import GPTAPI 277 | from lagent.llms.huggingface import HFTransformerCasualLM 278 | 279 | 280 | class SessionState: 281 | 282 | def init_state(self): 283 | """Initialize session state variables.""" 284 | st.session_state['assistant'] = [] 285 | st.session_state['user'] = [] 286 | 287 | #action_list = [PythonInterpreter(), GoogleSearch()] 288 | action_list = [PythonInterpreter()] 289 | st.session_state['plugin_map'] = { 290 | action.name: action 291 | for action in action_list 292 | } 293 | st.session_state['model_map'] = {} 294 | st.session_state['model_selected'] = None 295 | st.session_state['plugin_actions'] = set() 296 | 297 | def clear_state(self): 298 | """Clear the existing session state.""" 299 | st.session_state['assistant'] = [] 300 | st.session_state['user'] = [] 301 | st.session_state['model_selected'] = None 302 | if 'chatbot' in st.session_state: 303 | st.session_state['chatbot']._session_history = [] 304 | 305 | 306 | class StreamlitUI: 307 | 308 | def __init__(self, session_state: SessionState): 309 | self.init_streamlit() 310 | self.session_state = session_state 311 | 312 | def init_streamlit(self): 313 | """Initialize Streamlit's UI settings.""" 314 | st.set_page_config( 315 | layout='wide', 316 | page_title='lagent-web', 317 | page_icon='./docs/imgs/lagent_icon.png') 318 | # st.header(':robot_face: :blue[Lagent] Web Demo ', divider='rainbow') 319 | st.sidebar.title('模型控制') 320 | 321 | def setup_sidebar(self): 322 | """Setup the sidebar for model and plugin selection.""" 323 | model_name = st.sidebar.selectbox( 324 | '模型选择:', options=['gpt-3.5-turbo','internlm']) 325 | if model_name != st.session_state['model_selected']: 326 | model = self.init_model(model_name) 327 | self.session_state.clear_state() 328 | st.session_state['model_selected'] = model_name 329 | if 'chatbot' in st.session_state: 330 | del st.session_state['chatbot'] 331 | else: 332 | model = st.session_state['model_map'][model_name] 333 | 334 | plugin_name = st.sidebar.multiselect( 335 | '插件选择', 336 | options=list(st.session_state['plugin_map'].keys()), 337 | default=[list(st.session_state['plugin_map'].keys())[0]], 338 | ) 339 | 340 | plugin_action = [ 341 | st.session_state['plugin_map'][name] for name in plugin_name 342 | ] 343 | if 'chatbot' in st.session_state: 344 | st.session_state['chatbot']._action_executor = ActionExecutor( 345 | actions=plugin_action) 346 | if st.sidebar.button('清空对话', key='clear'): 347 | self.session_state.clear_state() 348 | uploaded_file = st.sidebar.file_uploader( 349 | '上传文件', type=['png', 'jpg', 'jpeg', 'mp4', 'mp3', 'wav']) 350 | return model_name, model, plugin_action, uploaded_file 351 | 352 | def init_model(self, option): 353 | """Initialize the model based on the selected option.""" 354 | if option not in st.session_state['model_map']: 355 | if option.startswith('gpt'): 356 | st.session_state['model_map'][option] = GPTAPI( 357 | model_type=option) 358 | else: 359 | st.session_state['model_map'][option] = HFTransformerCasualLM( 360 | '/root/model/Shanghai_AI_Laboratory/internlm-chat-7b') 361 | return st.session_state['model_map'][option] 362 | 363 | def initialize_chatbot(self, model, plugin_action): 364 | """Initialize the chatbot with the given model and plugin actions.""" 365 | return ReAct( 366 | llm=model, action_executor=ActionExecutor(actions=plugin_action)) 367 | 368 | def render_user(self, prompt: str): 369 | with st.chat_message('user'): 370 | st.markdown(prompt) 371 | 372 | def render_assistant(self, agent_return): 373 | with st.chat_message('assistant'): 374 | for action in agent_return.actions: 375 | if (action): 376 | self.render_action(action) 377 | st.markdown(agent_return.response) 378 | 379 | def render_action(self, action): 380 | with st.expander(action.type, expanded=True): 381 | st.markdown( 382 | "

插 件:" # noqa E501 383 | + action.type + '

', 384 | unsafe_allow_html=True) 385 | st.markdown( 386 | "

思考步骤:" # noqa E501 387 | + action.thought + '

', 388 | unsafe_allow_html=True) 389 | if (isinstance(action.args, dict) and 'text' in action.args): 390 | st.markdown( 391 | "

执行内容:

", # noqa E501 392 | unsafe_allow_html=True) 393 | st.markdown(action.args['text']) 394 | self.render_action_results(action) 395 | 396 | def render_action_results(self, action): 397 | """Render the results of action, including text, images, videos, and 398 | audios.""" 399 | if (isinstance(action.result, dict)): 400 | st.markdown( 401 | "

执行结果:

", # noqa E501 402 | unsafe_allow_html=True) 403 | if 'text' in action.result: 404 | st.markdown( 405 | "

" + action.result['text'] + 406 | '

', 407 | unsafe_allow_html=True) 408 | if 'image' in action.result: 409 | image_path = action.result['image'] 410 | image_data = open(image_path, 'rb').read() 411 | st.image(image_data, caption='Generated Image') 412 | if 'video' in action.result: 413 | video_data = action.result['video'] 414 | video_data = open(video_data, 'rb').read() 415 | st.video(video_data) 416 | if 'audio' in action.result: 417 | audio_data = action.result['audio'] 418 | audio_data = open(audio_data, 'rb').read() 419 | st.audio(audio_data) 420 | 421 | 422 | def main(): 423 | logger = get_logger(__name__) 424 | # Initialize Streamlit UI and setup sidebar 425 | if 'ui' not in st.session_state: 426 | session_state = SessionState() 427 | session_state.init_state() 428 | st.session_state['ui'] = StreamlitUI(session_state) 429 | 430 | else: 431 | st.set_page_config( 432 | layout='wide', 433 | page_title='lagent-web', 434 | page_icon='./docs/imgs/lagent_icon.png') 435 | # st.header(':robot_face: :blue[Lagent] Web Demo ', divider='rainbow') 436 | model_name, model, plugin_action, uploaded_file = st.session_state[ 437 | 'ui'].setup_sidebar() 438 | 439 | # Initialize chatbot if it is not already initialized 440 | # or if the model has changed 441 | if 'chatbot' not in st.session_state or model != st.session_state[ 442 | 'chatbot']._llm: 443 | st.session_state['chatbot'] = st.session_state[ 444 | 'ui'].initialize_chatbot(model, plugin_action) 445 | 446 | for prompt, agent_return in zip(st.session_state['user'], 447 | st.session_state['assistant']): 448 | st.session_state['ui'].render_user(prompt) 449 | st.session_state['ui'].render_assistant(agent_return) 450 | # User input form at the bottom (this part will be at the bottom) 451 | # with st.form(key='my_form', clear_on_submit=True): 452 | 453 | if user_input := st.chat_input(''): 454 | st.session_state['ui'].render_user(user_input) 455 | st.session_state['user'].append(user_input) 456 | # Add file uploader to sidebar 457 | if uploaded_file: 458 | file_bytes = uploaded_file.read() 459 | file_type = uploaded_file.type 460 | if 'image' in file_type: 461 | st.image(file_bytes, caption='Uploaded Image') 462 | elif 'video' in file_type: 463 | st.video(file_bytes, caption='Uploaded Video') 464 | elif 'audio' in file_type: 465 | st.audio(file_bytes, caption='Uploaded Audio') 466 | # Save the file to a temporary location and get the path 467 | file_path = os.path.join(root_dir, uploaded_file.name) 468 | with open(file_path, 'wb') as tmpfile: 469 | tmpfile.write(file_bytes) 470 | st.write(f'File saved at: {file_path}') 471 | user_input = '我上传了一个图像,路径为: {file_path}. {user_input}'.format( 472 | file_path=file_path, user_input=user_input) 473 | agent_return = st.session_state['chatbot'].chat(user_input) 474 | st.session_state['assistant'].append(copy.deepcopy(agent_return)) 475 | logger.info(agent_return.inner_steps) 476 | st.session_state['ui'].render_assistant(agent_return) 477 | 478 | 479 | if __name__ == '__main__': 480 | root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 481 | root_dir = os.path.join(root_dir, 'tmp_dir') 482 | os.makedirs(root_dir, exist_ok=True) 483 | main() 484 | ``` 485 | 486 | ### 3.5 Demo 运行 487 | 488 | ```shell 489 | streamlit run /root/code/lagent/examples/react_web_demo.py --server.address 127.0.0.1 --server.port 6006 490 | ``` 491 | 492 | 用同样的方法我们依然切换到 `VScode` 页面,运行成功后,[**查看本教程5.2配置本地端口后**](./hello_world.md#52-配置本地端口),将端口映射到本地。在本地浏览器输入 `http://127.0.0.1:6006` 即可。 493 | 494 | 我们在 `Web` 页面选择 `InternLM` 模型,等待模型加载完毕后,输入数学问题 已知 `2x+3=10`,求`x` ,此时 `InternLM-Chat-7B` 模型理解题意生成解此题的 `Python` 代码,`Lagent` 调度送入 `Python` 代码解释器求出该问题的解。 495 | 496 | ![Alt text](images/image-7.png) 497 | 498 | ## 4. 浦语·灵笔图文理解创作 Demo 499 | 500 | 本小节我们将使用 [InternStudio](https://studio.intern-ai.org.cn/) 中的 A100(1/4) * 2 机器和 `internlm-xcomposer-7b` 模型部署一个图文理解创作 Demo 。 501 | 502 | ### 4.1 环境准备 503 | 504 | 首先在 [InternStudio](https://studio.intern-ai.org.cn/) 上选择 A100(1/4)*2 的配置。如下图所示: 505 | 506 | ![Alt text](images/image-8.png) 507 | 508 | 接下来打开刚刚租用服务器的 `进入开发机`,并在终端输入 `bash` 命令,进入 `conda` 环境,接下来就是安装依赖。 509 | 510 | 进入 `conda` 环境之后,使用以下命令从本地克隆一个已有的`pytorch 2.0.1` 的环境 511 | 512 | ```shell 513 | /root/share/install_conda_env_internlm_base.sh xcomposer-demo 514 | ``` 515 | 516 | 然后使用以下命令激活环境 517 | 518 | ```shell 519 | conda activate xcomposer-demo 520 | ``` 521 | 522 | 接下来运行以下命令,安装 `transformers`、`gradio` 等依赖包。请严格安装以下版本安装! 523 | 524 | ```shell 525 | pip install transformers==4.33.1 timm==0.4.12 sentencepiece==0.1.99 gradio==3.44.4 markdown2==2.4.10 xlsxwriter==3.1.2 einops accelerate 526 | ``` 527 | ### 4.2 模型下载 528 | 529 | [InternStudio](https://studio.intern-ai.org.cn/)平台的 `share` 目录下已经为我们准备了全系列的 `InternLM` 模型,所以我们可以直接复制即可。使用如下命令复制: 530 | 531 | ```shell 532 | mkdir -p /root/model/Shanghai_AI_Laboratory 533 | cp -r /root/share/temp/model_repos/internlm-xcomposer-7b /root/model/Shanghai_AI_Laboratory 534 | ``` 535 | > -r 选项表示递归地复制目录及其内容 536 | 537 | 也可以安装 `modelscope`,下载模型的老朋友了 538 | 539 | ```shell 540 | pip install modelscope==1.9.5 541 | ``` 542 | 543 | 在 `/root/model` 路径下新建 `download.py` 文件并在其中输入以下内容,并运行 `python /root/model/download.py` 执行下载 544 | 545 | ```python 546 | import torch 547 | from modelscope import snapshot_download, AutoModel, AutoTokenizer 548 | import os 549 | model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-xcomposer-7b', cache_dir='/root/model', revision='master') 550 | ``` 551 | 552 | ### 4.3 代码准备 553 | 554 | 在 `/root/code` `git clone InternLM-XComposer` 仓库的代码 555 | 556 | ```shell 557 | cd /root/code 558 | git clone https://gitee.com/internlm/InternLM-XComposer.git 559 | cd /root/code/InternLM-XComposer 560 | git checkout 3e8c79051a1356b9c388a6447867355c0634932d # 最好保证和教程的 commit 版本一致 561 | ``` 562 | 563 | ### 4.4 Demo 运行 564 | 565 | 在终端运行以下代码: 566 | 567 | ```shell 568 | cd /root/code/InternLM-XComposer 569 | python examples/web_demo.py \ 570 | --folder /root/model/Shanghai_AI_Laboratory/internlm-xcomposer-7b \ 571 | --num_gpus 1 \ 572 | --port 6006 573 | ``` 574 | 575 | > 这里 `num_gpus 1` 是因为InternStudio平台对于 `A100(1/4)*2` 识别仍为一张显卡。但如果有小伙伴课后使用两张 3090 来运行此 demo,仍需将 `num_gpus` 设置为 `2` 。 576 | 577 | [**查看本教程5.2配置本地端口后**](./hello_world.md#52-配置本地端口),将端口映射到本地。在本地浏览器输入 `http://127.0.0.1:6006` 即可。我们以`又见敦煌`为提示词,体验图文创作的功能,如下图所示: 578 | 579 | ![Alt text](images/image-9.png) 580 | 581 | 接下来,我们可以体验一下图片理解的能力,如下所示~ 582 | 583 | ![Alt text](images/image-10.png) 584 | 585 | ## 5. 通用环境配置 586 | 587 | ### 5.1 pip、conda 换源 588 | 589 | 更多详细内容可移步至 [MirrorZ Help](https://help.mirrors.cernet.edu.cn/) 查看。 590 | 591 | #### 5.1.1 pip 换源 592 | 593 | 临时使用镜像源安装,如下所示:`some-package` 为你需要安装的包名 594 | 595 | ```shell 596 | pip install -i https://mirrors.cernet.edu.cn/pypi/web/simple some-package 597 | ``` 598 | 599 | 设置pip默认镜像源,升级 pip 到最新的版本 (>=10.0.0) 后进行配置,如下所示: 600 | 601 | ```shell 602 | python -m pip install --upgrade pip 603 | pip config set global.index-url https://mirrors.cernet.edu.cn/pypi/web/simple 604 | ``` 605 | 606 | 如果您的 pip 默认源的网络连接较差,临时使用镜像源升级 pip: 607 | 608 | ```shell 609 | python -m pip install -i https://mirrors.cernet.edu.cn/pypi/web/simple --upgrade pip 610 | ``` 611 | 612 | #### 5.1.2 conda 换源 613 | 614 | 镜像站提供了 Anaconda 仓库与第三方源(conda-forge、msys2、pytorch 等),各系统都可以通过修改用户目录下的 `.condarc` 文件来使用镜像站。 615 | 616 | 不同系统下的 `.condarc` 目录如下: 617 | 618 | - `Linux`: `${HOME}/.condarc` 619 | - `macOS`: `${HOME}/.condarc` 620 | - `Windows`: `C:\Users\\.condarc` 621 | 622 | 注意: 623 | 624 | - `Windows` 用户无法直接创建名为 `.condarc` 的文件,可先执行 `conda config --set show_channel_urls yes` 生成该文件之后再修改。 625 | 626 | 快速配置 627 | 628 | ```shell 629 | cat <<'EOF' > ~/.condarc 630 | channels: 631 | - defaults 632 | show_channel_urls: true 633 | default_channels: 634 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main 635 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r 636 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2 637 | custom_channels: 638 | conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud 639 | pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud 640 | EOF 641 | ``` 642 | 643 | ### 5.2 配置本地端口 644 | 645 | 由于服务器通常只暴露了用于安全远程登录的 SSH(Secure Shell)端口,如果需要访问服务器上运行的其他服务(如 web 应用)的特定端口,需要一种特殊的设置。我们可以通过使用SSH隧道的方法,将服务器上的这些特定端口映射到本地计算机的端口。这样做的步骤如下: 646 | 647 | 首先我们需要配置一下本地的 `SSH Key` ,我们这里以 `Windows` 为例。 648 | 649 | 步骤①:在本地机器上打开 `Power Shell` 终端。在终端中,运行以下命令来生成 SSH 密钥对:(如下图所示) 650 | ```shell 651 | ssh-keygen -t rsa 652 | ``` 653 | ![Alt text](images/image-13.png) 654 | 655 | 步骤②: 您将被提示选择密钥文件的保存位置,默认情况下是在 `~/.ssh/` 目录中。按 `Enter` 键接受默认值或输入自定义路径。 656 | 657 | 步骤③:公钥默认存储在 `~/.ssh/id_rsa.pub`,可以通过系统自带的 `cat` 工具查看文件内容:(如下图所示) 658 | 659 | ```shell 660 | cat ~\.ssh\id_rsa.pub 661 | ``` 662 | 663 | > `~` 是用户主目录的简写,`.ssh` 是SSH配置文件的默认存储目录,`id_rsa.pub` 是 SSH 公钥文件的默认名称。所以,`cat ~\.ssh\id_rsa.pub` 的意思是查看用户主目录下的 `.ssh` 目录中的 `id_rsa.pub` 文件的内容。 664 | 665 | ![Alt text](images/image-14.png) 666 | 667 | 步骤④:将公钥复制到剪贴板中,然后回到 `InternStudio` 控制台,点击配置 SSH Key。如下图所示: 668 | 669 | ![Alt text](images/image-15.png) 670 | 671 | 步骤⑤:将刚刚复制的公钥添加进入即可。 672 | 673 | ![Alt text](images/image-16.png) 674 | 675 | 步骤⑥:在本地终端输入以下指令 `.6006` 是在服务器中打开的端口,而 `33090` 是根据开发机的端口进行更改。如下图所示: 676 | 677 | ```shell 678 | ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p 33090 679 | ``` 680 | 681 | ![Alt text](images/image-17.png) 682 | 683 | ### 5.3 模型下载 684 | 685 | ***以下下载模型的操作不建议大家在开发机进行哦,在开发机下载模型会占用开发机的大量带宽和内存,下载等待的时间也会比较长,不利于大家学习。大家可以在自己的本地电脑尝试哦~*** 686 | 687 | #### 5.3.1 Hugging Face 688 | 689 | 使用 Hugging Face 官方提供的 `huggingface-cli` 命令行工具。安装依赖: 690 | 691 | ```shell 692 | pip install -U huggingface_hub 693 | ``` 694 | 695 | 然后新建 python 文件,填入以下代码,运行即可。 696 | 697 | - resume-download:断点续下 698 | - local-dir:本地存储路径。(linux 环境下需要填写绝对路径) 699 | 700 | ```python 701 | import os 702 | 703 | # 下载模型 704 | os.system('huggingface-cli download --resume-download internlm/internlm-chat-7b --local-dir your_path') 705 | ``` 706 | 707 | 以下内容将展示使用 `huggingface_hub` 下载模型中的部分文件 708 | 709 | ```python 710 | import os 711 | from huggingface_hub import hf_hub_download # Load model directly 712 | 713 | hf_hub_download(repo_id="internlm/internlm-7b", filename="config.json") 714 | ``` 715 | 716 | #### 5.3.2 ModelScope 717 | 718 | 使用 `modelscope` 中的 `snapshot_download` 函数下载模型,第一个参数为模型名称,参数 `cache_dir` 为模型的下载路径。 719 | 720 | 注意:`cache_dir` 最好为绝对路径。 721 | 722 | 安装依赖: 723 | 724 | ```shell 725 | pip install modelscope==1.9.5 726 | pip install transformers==4.35.2 727 | ``` 728 | 729 | 在当前目录下新建 python 文件,填入以下代码,运行即可。 730 | 731 | ```python 732 | import torch 733 | from modelscope import snapshot_download, AutoModel, AutoTokenizer 734 | import os 735 | model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-chat-7b', cache_dir='your path', revision='master') 736 | ``` 737 | 738 | #### 5.3.3 OpenXLab 739 | 740 | OpenXLab 可以通过指定模型仓库的地址,以及需要下载的文件的名称,文件所需下载的位置等,直接下载模型权重文件。 741 | 742 | 使用python脚本下载模型首先要安装依赖,安装代码如下:`pip install -U openxlab` 安装完成后使用 download 函数导入模型中心的模型。 743 | 744 | ```python 745 | from openxlab.model import download 746 | download(model_repo='OpenLMLab/InternLM-7b', model_name='InternLM-7b', output='your local path') 747 | ``` 748 | 749 | ## 6. 课后作业 750 | 751 | 提交方式:在各个班级对应的 GitHub Discussion 帖子中进行提交。 752 | 753 | **基础作业:** 754 | 755 | - 使用 InternLM-Chat-7B 模型生成 300 字的小故事(需截图)。 756 | - 熟悉 hugging face 下载功能,使用 `huggingface_hub` python 包,下载 `InternLM-20B` 的 config.json 文件到本地(需截图下载过程)。 757 | 758 | **进阶作业(可选做)** 759 | 760 | - 完成浦语·灵笔的图文理解及创作部署(需截图) 761 | - 完成 Lagent 工具调用 Demo 创作部署(需截图) 762 | 763 | **整体实训营项目:** 764 | 765 | 时间周期:即日起致课程结束 766 | 767 | 即日开始可以在班级群中随机组队完成一个大作业项目,一些可提供的选题如下: 768 | 769 | - 人情世故大模型:一个帮助用户撰写新年祝福文案的人情事故大模型 770 | - 中小学数学大模型:一个拥有一定数学解题能力的大模型 771 | - 心理大模型:一个治愈的心理大模型 772 | - 工具调用类项目:结合 Lagent 构建数据集训练 InternLM 模型,支持对 MMYOLO 等工具的调用 773 | 774 | 其他基于书生·浦语工具链的小项目都在范围内,欢迎大家充分发挥想象力。 775 | -------------------------------------------------------------------------------- /helloworld/images/Lagent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/Lagent.png -------------------------------------------------------------------------------- /helloworld/images/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/head.png -------------------------------------------------------------------------------- /helloworld/images/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-1.png -------------------------------------------------------------------------------- /helloworld/images/image-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-10.png -------------------------------------------------------------------------------- /helloworld/images/image-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-11.png -------------------------------------------------------------------------------- /helloworld/images/image-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-12.png -------------------------------------------------------------------------------- /helloworld/images/image-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-13.png -------------------------------------------------------------------------------- /helloworld/images/image-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-14.png -------------------------------------------------------------------------------- /helloworld/images/image-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-15.png -------------------------------------------------------------------------------- /helloworld/images/image-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-16.png -------------------------------------------------------------------------------- /helloworld/images/image-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-17.png -------------------------------------------------------------------------------- /helloworld/images/image-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-18.png -------------------------------------------------------------------------------- /helloworld/images/image-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-2.png -------------------------------------------------------------------------------- /helloworld/images/image-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-3.png -------------------------------------------------------------------------------- /helloworld/images/image-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-4.png -------------------------------------------------------------------------------- /helloworld/images/image-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-5.png -------------------------------------------------------------------------------- /helloworld/images/image-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-6.png -------------------------------------------------------------------------------- /helloworld/images/image-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-7.png -------------------------------------------------------------------------------- /helloworld/images/image-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-8.png -------------------------------------------------------------------------------- /helloworld/images/image-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image-9.png -------------------------------------------------------------------------------- /helloworld/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/helloworld/images/image.png -------------------------------------------------------------------------------- /langchain/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/.gitkeep -------------------------------------------------------------------------------- /langchain/demo/LLM.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : llm.py 5 | @Time : 2023/10/16 18:53:26 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 基于InternLM模型自定义 LLM 类 11 | ''' 12 | 13 | from langchain.llms.base import LLM 14 | from typing import Any, List, Optional 15 | from langchain.callbacks.manager import CallbackManagerForLLMRun 16 | from transformers import AutoTokenizer, AutoModelForCausalLM 17 | import torch 18 | 19 | class InternLM_LLM(LLM): 20 | # 基于本地 InternLM 自定义 LLM 类 21 | tokenizer : AutoTokenizer = None 22 | model: AutoModelForCausalLM = None 23 | 24 | def __init__(self, model_path :str): 25 | # model_path: InternLM 模型路径 26 | # 从本地初始化模型 27 | super().__init__() 28 | print("正在从本地加载模型...") 29 | self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) 30 | self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(torch.bfloat16).cuda() 31 | self.model = self.model.eval() 32 | print("完成本地模型的加载") 33 | 34 | def _call(self, prompt : str, stop: Optional[List[str]] = None, 35 | run_manager: Optional[CallbackManagerForLLMRun] = None, 36 | **kwargs: Any): 37 | # 重写调用函数 38 | system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语). 39 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 40 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 41 | """ 42 | messages = [(system_prompt, '')] 43 | response, history = self.model.chat(self.tokenizer, prompt , history=messages) 44 | return response 45 | 46 | @property 47 | def _llm_type(self) -> str: 48 | return "InternLM" 49 | 50 | if __name__ == "__main__": 51 | # 测试代码 52 | llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b") 53 | print(llm.predict("你是谁")) 54 | 55 | -------------------------------------------------------------------------------- /langchain/demo/create_db.py: -------------------------------------------------------------------------------- 1 | # 首先导入所需第三方库 2 | from langchain.document_loaders import UnstructuredFileLoader 3 | from langchain.document_loaders import UnstructuredMarkdownLoader 4 | from langchain.text_splitter import RecursiveCharacterTextSplitter 5 | from langchain.vectorstores import Chroma 6 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 7 | from tqdm import tqdm 8 | import os 9 | 10 | # 获取文件路径函数 11 | def get_files(dir_path): 12 | # args:dir_path,目标文件夹路径 13 | file_list = [] 14 | for filepath, dirnames, filenames in os.walk(dir_path): 15 | # os.walk 函数将递归遍历指定文件夹 16 | for filename in filenames: 17 | # 通过后缀名判断文件类型是否满足要求 18 | if filename.endswith(".md"): 19 | # 如果满足要求,将其绝对路径加入到结果列表 20 | file_list.append(os.path.join(filepath, filename)) 21 | elif filename.endswith(".txt"): 22 | file_list.append(os.path.join(filepath, filename)) 23 | return file_list 24 | 25 | # 加载文件函数 26 | def get_text(dir_path): 27 | # args:dir_path,目标文件夹路径 28 | # 首先调用上文定义的函数得到目标文件路径列表 29 | file_lst = get_files(dir_path) 30 | # docs 存放加载之后的纯文本对象 31 | docs = [] 32 | # 遍历所有目标文件 33 | for one_file in tqdm(file_lst): 34 | file_type = one_file.split('.')[-1] 35 | if file_type == 'md': 36 | loader = UnstructuredMarkdownLoader(one_file) 37 | elif file_type == 'txt': 38 | loader = UnstructuredFileLoader(one_file) 39 | else: 40 | # 如果是不符合条件的文件,直接跳过 41 | continue 42 | docs.extend(loader.load()) 43 | return docs 44 | 45 | # 目标文件夹 46 | tar_dir = [ 47 | "/root/data/InternLM", 48 | "/root/data/InternLM-XComposer", 49 | "/root/data/lagent", 50 | "/root/data/lmdeploy", 51 | "/root/data/opencompass", 52 | "/root/data/xtuner" 53 | ] 54 | 55 | # 加载目标文件 56 | docs = [] 57 | for dir_path in tar_dir: 58 | docs.extend(get_text(dir_path)) 59 | 60 | # 对文本进行分块 61 | text_splitter = RecursiveCharacterTextSplitter( 62 | chunk_size=500, chunk_overlap=150) 63 | split_docs = text_splitter.split_documents(docs) 64 | 65 | # 加载开源词向量模型 66 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 67 | 68 | # 构建向量数据库 69 | # 定义持久化路径 70 | persist_directory = 'data_base/vector_db/chroma' 71 | # 加载数据库 72 | vectordb = Chroma.from_documents( 73 | documents=split_docs, 74 | embedding=embeddings, 75 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 76 | ) 77 | # 将加载的向量数据库持久化到磁盘上 78 | vectordb.persist() 79 | -------------------------------------------------------------------------------- /langchain/demo/readme.md: -------------------------------------------------------------------------------- 1 | 存放教程代码 2 | -------------------------------------------------------------------------------- /langchain/demo/run_gradio.py: -------------------------------------------------------------------------------- 1 | # 导入必要的库 2 | import gradio as gr 3 | from langchain.vectorstores import Chroma 4 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 5 | import os 6 | from LLM import InternLM_LLM 7 | from langchain.prompts import PromptTemplate 8 | 9 | def load_chain(): 10 | # 加载问答链 11 | # 定义 Embeddings 12 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 13 | 14 | # 向量数据库持久化路径 15 | persist_directory = 'data_base/vector_db/chroma' 16 | 17 | # 加载数据库 18 | vectordb = Chroma( 19 | persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上 20 | embedding_function=embeddings 21 | ) 22 | 23 | llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b") 24 | 25 | # 你可以修改这里的 prompt template 来试试不同的问答效果 26 | template = """请使用以下提供的上下文来回答用户的问题。如果无法从上下文中得到答案,请回答你不知道,并总是使用中文回答。 27 | 提供的上下文: 28 | ··· 29 | {context} 30 | ··· 31 | 用户的问题: {question} 32 | 你给的回答:""" 33 | 34 | QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"], 35 | template=template) 36 | 37 | # 运行 chain 38 | from langchain.chains import RetrievalQA 39 | 40 | qa_chain = RetrievalQA.from_chain_type(llm, 41 | retriever=vectordb.as_retriever(), 42 | return_source_documents=True, 43 | chain_type_kwargs={"prompt":QA_CHAIN_PROMPT}) 44 | 45 | return qa_chain 46 | 47 | class Model_center(): 48 | """ 49 | 存储问答 Chain 的对象 50 | """ 51 | def __init__(self): 52 | self.chain = load_chain() 53 | 54 | def qa_chain_self_answer(self, question: str, chat_history: list = []): 55 | """ 56 | 调用不带历史记录的问答链进行回答 57 | """ 58 | if question == None or len(question) < 1: 59 | return "", chat_history 60 | try: 61 | chat_history.append( 62 | (question, self.chain({"query": question})["result"])) 63 | return "", chat_history 64 | except Exception as e: 65 | return e, chat_history 66 | 67 | 68 | model_center = Model_center() 69 | 70 | block = gr.Blocks() 71 | with block as demo: 72 | with gr.Row(equal_height=True): 73 | with gr.Column(scale=15): 74 | gr.Markdown("""

InternLM

75 |
书生浦语
76 | """) 77 | # gr.Image(value=LOGO_PATH, scale=1, min_width=10,show_label=False, show_download_button=False) 78 | 79 | with gr.Row(): 80 | with gr.Column(scale=4): 81 | chatbot = gr.Chatbot(height=450, show_copy_button=True) 82 | # 创建一个文本框组件,用于输入 prompt。 83 | msg = gr.Textbox(label="Prompt/问题") 84 | 85 | with gr.Row(): 86 | # 创建提交按钮。 87 | db_wo_his_btn = gr.Button("Chat") 88 | with gr.Row(): 89 | # 创建一个清除按钮,用于清除聊天机器人组件的内容。 90 | clear = gr.ClearButton( 91 | components=[chatbot], value="Clear console") 92 | 93 | # 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。 94 | db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[ 95 | msg, chatbot], outputs=[msg, chatbot]) 96 | 97 | gr.Markdown("""提醒:
98 | 1. 初始化数据库时间可能较长,请耐心等待。 99 | 2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。
100 | """) 101 | # threads to consume the request 102 | gr.close_all() 103 | # 启动新的 Gradio 应用,设置分享功能为 True,并使用环境变量 PORT1 指定服务器端口。 104 | # demo.launch(share=True, server_port=int(os.environ['PORT1'])) 105 | # 直接启动 106 | demo.launch() 107 | -------------------------------------------------------------------------------- /langchain/figures/image-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-0.png -------------------------------------------------------------------------------- /langchain/figures/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-1.png -------------------------------------------------------------------------------- /langchain/figures/image-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-11.png -------------------------------------------------------------------------------- /langchain/figures/image-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-2.png -------------------------------------------------------------------------------- /langchain/figures/image-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-5.png -------------------------------------------------------------------------------- /langchain/figures/image-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-51.png -------------------------------------------------------------------------------- /langchain/figures/image-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-52.png -------------------------------------------------------------------------------- /langchain/figures/image-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-53.png -------------------------------------------------------------------------------- /langchain/figures/image-54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-54.png -------------------------------------------------------------------------------- /langchain/figures/image-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image-55.png -------------------------------------------------------------------------------- /langchain/figures/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/langchain/figures/image.png -------------------------------------------------------------------------------- /langchain/figures/readme.md: -------------------------------------------------------------------------------- 1 | 存放 Markdown 图片 2 | -------------------------------------------------------------------------------- /langchain/readme.md: -------------------------------------------------------------------------------- 1 | ![](figures/image-0.png) 2 | 3 | # 基于 InternLM 和 LangChain 搭建你的知识库 4 | 5 | - [基于 InternLM 和 LangChain 搭建你的知识库](#基于-internlm-和-langchain-搭建你的知识库) 6 | - [1 环境配置](#1-环境配置) 7 | - [1.1 InternLM 模型部署](#11-internlm-模型部署) 8 | - [1.2 模型下载](#12-模型下载) 9 | - [1.3 LangChain 相关环境配置](#13-langchain-相关环境配置) 10 | - [1.4 下载 NLTK 相关资源](#14-下载-nltk-相关资源) 11 | - [1.5 下载本项目代码](#15-下载本项目代码) 12 | - [2 知识库搭建](#2-知识库搭建) 13 | - [2.1 数据收集](#21-数据收集) 14 | - [2.2 加载数据](#22-加载数据) 15 | - [2.3 构建向量数据库](#23-构建向量数据库) 16 | - [2.4 整体脚本](#24-整体脚本) 17 | - [3 InternLM 接入 LangChain](#3-internlm-接入-langchain) 18 | - [4 构建检索问答链](#4-构建检索问答链) 19 | - [4.1 加载向量数据库](#41-加载向量数据库) 20 | - [4.2 实例化自定义 LLM 与 Prompt Template](#42-实例化自定义-llm-与-prompt-template) 21 | - [4.3 构建检索问答链](#43-构建检索问答链) 22 | - [5 部署 Web Demo](#5-部署-web-demo) 23 | - [6 作业](#6-作业) 24 | 25 | 26 | ## 1 环境配置 27 | 28 | ### 1.1 InternLM 模型部署 29 | 30 | 在 [InternStudio](https://studio.intern-ai.org.cn/) 平台中选择 A100(1/4) 的配置,如下图所示镜像选择 `Cuda11.7-conda`,如下图所示: 31 | 32 | ![Alt text](figures/image.png) 33 | 34 | 接下来打开刚刚租用服务器的 `进入开发机`,并且打开其中的终端开始环境配置、模型下载和运行 `demo`。 35 | 36 | ![Alt text](figures/image-1.png) 37 | 38 | 进入开发机后,在页面的左上角可以切换 `JupyterLab`、`终端` 和 `VScode`,并在终端输入 `bash` 命令,进入 `conda` 环境。如下图所示: 39 | 40 | ![Alt text](figures/image-11.png) 41 | 42 | 进入 `conda` 环境之后,使用以下命令从本地一个已有的 `pytorch 2.0.1` 的环境 43 | 44 | ```shell 45 | bash 46 | /root/share/install_conda_env_internlm_base.sh InternLM 47 | ``` 48 | 49 | 然后使用以下命令激活环境 50 | 51 | ```shell 52 | conda activate InternLM 53 | ``` 54 | 55 | 并在环境中安装运行 demo 所需要的依赖。 56 | 57 | ```shell 58 | # 升级pip 59 | python -m pip install --upgrade pip 60 | 61 | pip install modelscope==1.9.5 62 | pip install transformers==4.35.2 63 | pip install streamlit==1.24.0 64 | pip install sentencepiece==0.1.99 65 | pip install accelerate==0.24.1 66 | ``` 67 | 68 | ### 1.2 模型下载 69 | 70 | 在本地的 `/root/share/temp/model_repos/internlm-chat-7b` 目录下已存储有所需的模型文件参数,可以直接拷贝到个人目录的模型保存地址: 71 | 72 | ```bash 73 | mkdir -p /root/data/model/Shanghai_AI_Laboratory 74 | cp -r /root/share/temp/model_repos/internlm-chat-7b /root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b 75 | ``` 76 | 77 | 如果本地拷贝模型参数出现问题,我们也可以使用 `modelscope` 中的 `snapshot_download` 函数下载模型,第一个参数为模型名称,参数 `cache_dir` 为模型的下载路径。 78 | 79 | 在 `/root` 路径下新建目录 `data`,在目录下新建 `download.py` 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 `python /root/data/download.py` 执行下载,模型大小为 14 GB,下载模型大概需要 10~20 分钟 80 | 81 | ```python 82 | import torch 83 | from modelscope import snapshot_download, AutoModel, AutoTokenizer 84 | import os 85 | model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-chat-7b', cache_dir='/root/data/model', revision='v1.0.3') 86 | ``` 87 | 88 | > 注意:使用 `pwd` 命令可以查看当前的路径,`JupyterLab` 左侧目录栏显示为 `/root/` 下的路径。 89 | 90 | ![image](figures/image-2.png) 91 | 92 | ### 1.3 LangChain 相关环境配置 93 | 94 | 在已完成 InternLM 的部署基础上,还需要安装以下依赖包: 95 | 96 | ```bash 97 | pip install langchain==0.0.292 98 | pip install gradio==4.4.0 99 | pip install chromadb==0.4.15 100 | pip install sentence-transformers==2.2.2 101 | pip install unstructured==0.10.30 102 | pip install markdown==3.3.7 103 | ``` 104 | 105 | 同时,我们需要使用到开源词向量模型 [Sentence Transformer](https://huggingface.co/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2):(我们也可以选用别的开源词向量模型来进行 Embedding,目前选用这个模型是相对轻量、支持中文且效果较好的,同学们可以自由尝试别的开源词向量模型) 106 | 107 | 首先需要使用 `huggingface` 官方提供的 `huggingface-cli` 命令行工具。安装依赖: 108 | 109 | ```shell 110 | pip install -U huggingface_hub 111 | ``` 112 | 113 | 然后在和 `/root/data` 目录下新建python文件 `download_hf.py`,填入以下代码: 114 | 115 | - resume-download:断点续下 116 | - local-dir:本地存储路径。(linux环境下需要填写绝对路径) 117 | 118 | ```python 119 | import os 120 | 121 | # 下载模型 122 | os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/data/model/sentence-transformer') 123 | ``` 124 | 125 | 但是,使用 huggingface 下载可能速度较慢,我们可以使用 huggingface 镜像下载。与使用hugginge face下载相同,只需要填入镜像地址即可。 126 | 127 | 将 `download_hf.py` 中的代码修改为以下代码: 128 | 129 | ```python 130 | import os 131 | 132 | # 设置环境变量 133 | os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com' 134 | 135 | # 下载模型 136 | os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/data/model/sentence-transformer') 137 | ``` 138 | 139 | 然后,在 `/root/data` 目录下执行该脚本即可自动开始下载: 140 | 141 | ```bash 142 | python download_hf.py 143 | ``` 144 | 145 | 更多关于镜像使用可以移步至 [HF Mirror](https://hf-mirror.com/) 查看。 146 | 147 | ### 1.4 下载 NLTK 相关资源 148 | 149 | 我们在使用开源词向量模型构建开源词向量的时候,需要用到第三方库 `nltk` 的一些资源。正常情况下,其会自动从互联网上下载,但可能由于网络原因会导致下载中断,此处我们可以从国内仓库镜像地址下载相关资源,保存到服务器上。 150 | 151 | 我们用以下命令下载 nltk 资源并解压到服务器上: 152 | 153 | ```bash 154 | cd /root 155 | git clone https://gitee.com/yzy0612/nltk_data.git --branch gh-pages 156 | cd nltk_data 157 | mv packages/* ./ 158 | cd tokenizers 159 | unzip punkt.zip 160 | cd ../taggers 161 | unzip averaged_perceptron_tagger.zip 162 | ``` 163 | 164 | 之后使用时服务器即会自动使用已有资源,无需再次下载。 165 | 166 | ### 1.5 下载本项目代码 167 | 168 | 我们在仓库中同步提供了所有脚本,可以查看该教程文件的同级目录的 `demo` 文件夹。 169 | 170 | 建议通过以下目录将仓库 clone 到本地,可以直接在本地运行相关代码: 171 | 172 | ```bahs 173 | cd /root/data 174 | git clone https://github.com/InternLM/tutorial 175 | ``` 176 | 177 | 通过上述命令,可以将本仓库 clone 到本地 `root/data/tutorial` 目录下,在之后的过程中可以对照仓库中的脚本来完成自己的代码,也可以直接使用仓库中的脚本。 178 | 179 | ## 2 知识库搭建 180 | 181 | ### 2.1 数据收集 182 | 183 | 我们选择由上海人工智能实验室开源的一系列大模型工具开源仓库作为语料库来源,包括: 184 | 185 | - [OpenCompass](https://gitee.com/open-compass/opencompass):面向大模型评测的一站式平台 186 | - [IMDeploy](https://gitee.com/InternLM/lmdeploy):涵盖了 LLM 任务的全套轻量化、部署和服务解决方案的高效推理工具箱 187 | - [XTuner](https://gitee.com/InternLM/xtuner):轻量级微调大语言模型的工具库 188 | - [InternLM-XComposer](https://gitee.com/InternLM/InternLM-XComposer):浦语·灵笔,基于书生·浦语大语言模型研发的视觉-语言大模型 189 | - [Lagent](https://gitee.com/InternLM/lagent):一个轻量级、开源的基于大语言模型的智能体(agent)框架 190 | - [InternLM](https://gitee.com/InternLM/InternLM):一个开源的轻量级训练框架,旨在支持大模型训练而无需大量的依赖 191 | 192 | 首先我们需要将上述远程开源仓库 Clone 到本地,可以使用以下命令: 193 | 194 | ```bash 195 | # 进入到数据库盘 196 | cd /root/data 197 | # clone 上述开源仓库 198 | git clone https://gitee.com/open-compass/opencompass.git 199 | git clone https://gitee.com/InternLM/lmdeploy.git 200 | git clone https://gitee.com/InternLM/xtuner.git 201 | git clone https://gitee.com/InternLM/InternLM-XComposer.git 202 | git clone https://gitee.com/InternLM/lagent.git 203 | git clone https://gitee.com/InternLM/InternLM.git 204 | ``` 205 | 206 | 接着,为语料处理方便,我们将选用上述仓库中所有的 markdown、txt 文件作为示例语料库。注意,也可以选用其中的代码文件加入到知识库中,但需要针对代码文件格式进行额外处理(因为代码文件对逻辑联系要求较高,且规范性较强,在分割时最好基于代码模块进行分割再加入向量数据库)。 207 | 208 | 我们首先将上述仓库中所有满足条件的文件路径找出来,我们定义一个函数,该函数将递归指定文件夹路径,返回其中所有满足条件(即后缀名为 .md 或者 .txt 的文件)的文件路径: 209 | 210 | ```python 211 | import os 212 | def get_files(dir_path): 213 | # args:dir_path,目标文件夹路径 214 | file_list = [] 215 | for filepath, dirnames, filenames in os.walk(dir_path): 216 | # os.walk 函数将递归遍历指定文件夹 217 | for filename in filenames: 218 | # 通过后缀名判断文件类型是否满足要求 219 | if filename.endswith(".md"): 220 | # 如果满足要求,将其绝对路径加入到结果列表 221 | file_list.append(os.path.join(filepath, filename)) 222 | elif filename.endswith(".txt"): 223 | file_list.append(os.path.join(filepath, filename)) 224 | return file_list 225 | ``` 226 | 227 | ### 2.2 加载数据 228 | 229 | 得到所有目标文件路径之后,我们可以使用 LangChain 提供的 FileLoader 对象来加载目标文件,得到由目标文件解析出的纯文本内容。由于不同类型的文件需要对应不同的 FileLoader,我们判断目标文件类型,并针对性调用对应类型的 FileLoader,同时,调用 FileLoader 对象的 load 方法来得到加载之后的纯文本对象: 230 | 231 | ```python 232 | from tqdm import tqdm 233 | from langchain.document_loaders import UnstructuredFileLoader 234 | from langchain.document_loaders import UnstructuredMarkdownLoader 235 | 236 | def get_text(dir_path): 237 | # args:dir_path,目标文件夹路径 238 | # 首先调用上文定义的函数得到目标文件路径列表 239 | file_lst = get_files(dir_path) 240 | # docs 存放加载之后的纯文本对象 241 | docs = [] 242 | # 遍历所有目标文件 243 | for one_file in tqdm(file_lst): 244 | file_type = one_file.split('.')[-1] 245 | if file_type == 'md': 246 | loader = UnstructuredMarkdownLoader(one_file) 247 | elif file_type == 'txt': 248 | loader = UnstructuredFileLoader(one_file) 249 | else: 250 | # 如果是不符合条件的文件,直接跳过 251 | continue 252 | docs.extend(loader.load()) 253 | return docs 254 | ``` 255 | 256 | 使用上文函数,我们得到的 `docs` 为一个纯文本对象对应的列表。 257 | 258 | ### 2.3 构建向量数据库 259 | 260 | 得到该列表之后,我们就可以将它引入到 LangChain 框架中构建向量数据库。由纯文本对象构建向量数据库,我们需要先对文本进行分块,接着对文本块进行向量化。 261 | 262 | LangChain 提供了多种文本分块工具,此处我们使用字符串递归分割器,并选择分块大小为 500,块重叠长度为 150(由于篇幅限制,此处没有展示切割效果,学习者可以自行尝试一下,想要深入学习 LangChain 文本分块可以参考教程 [《LangChain - Chat With Your Data》](https://github.com/datawhalechina/prompt-engineering-for-developers/blob/9dbcb48416eb8af9ff9447388838521dc0f9acb0/content/LangChain%20Chat%20with%20Your%20Data/1.%E7%AE%80%E4%BB%8B%20Introduction.md): 263 | 264 | ```python 265 | from langchain.text_splitter import RecursiveCharacterTextSplitter 266 | 267 | text_splitter = RecursiveCharacterTextSplitter( 268 | chunk_size=500, chunk_overlap=150) 269 | split_docs = text_splitter.split_documents(docs) 270 | ``` 271 | 272 | 接着我们选用开源词向量模型 [Sentence Transformer](https://huggingface.co/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2) 来进行文本向量化。LangChain 提供了直接引入 HuggingFace 开源社区中的模型进行向量化的接口: 273 | 274 | ```python 275 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 276 | 277 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 278 | ``` 279 | 280 | 同时,考虑到 Chroma 是目前最常用的入门数据库,我们选择 Chroma 作为向量数据库,基于上文分块后的文档以及加载的开源向量化模型,将语料加载到指定路径下的向量数据库: 281 | 282 | ```python 283 | from langchain.vectorstores import Chroma 284 | 285 | # 定义持久化路径 286 | persist_directory = 'data_base/vector_db/chroma' 287 | # 加载数据库 288 | vectordb = Chroma.from_documents( 289 | documents=split_docs, 290 | embedding=embeddings, 291 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 292 | ) 293 | # 将加载的向量数据库持久化到磁盘上 294 | vectordb.persist() 295 | ``` 296 | 297 | ### 2.4 整体脚本 298 | 299 | 将上述代码整合在一起为知识库搭建的脚本: 300 | 301 | ```python 302 | # 首先导入所需第三方库 303 | from langchain.document_loaders import UnstructuredFileLoader 304 | from langchain.document_loaders import UnstructuredMarkdownLoader 305 | from langchain.text_splitter import RecursiveCharacterTextSplitter 306 | from langchain.vectorstores import Chroma 307 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 308 | from tqdm import tqdm 309 | import os 310 | 311 | # 获取文件路径函数 312 | def get_files(dir_path): 313 | # args:dir_path,目标文件夹路径 314 | file_list = [] 315 | for filepath, dirnames, filenames in os.walk(dir_path): 316 | # os.walk 函数将递归遍历指定文件夹 317 | for filename in filenames: 318 | # 通过后缀名判断文件类型是否满足要求 319 | if filename.endswith(".md"): 320 | # 如果满足要求,将其绝对路径加入到结果列表 321 | file_list.append(os.path.join(filepath, filename)) 322 | elif filename.endswith(".txt"): 323 | file_list.append(os.path.join(filepath, filename)) 324 | return file_list 325 | 326 | # 加载文件函数 327 | def get_text(dir_path): 328 | # args:dir_path,目标文件夹路径 329 | # 首先调用上文定义的函数得到目标文件路径列表 330 | file_lst = get_files(dir_path) 331 | # docs 存放加载之后的纯文本对象 332 | docs = [] 333 | # 遍历所有目标文件 334 | for one_file in tqdm(file_lst): 335 | file_type = one_file.split('.')[-1] 336 | if file_type == 'md': 337 | loader = UnstructuredMarkdownLoader(one_file) 338 | elif file_type == 'txt': 339 | loader = UnstructuredFileLoader(one_file) 340 | else: 341 | # 如果是不符合条件的文件,直接跳过 342 | continue 343 | docs.extend(loader.load()) 344 | return docs 345 | 346 | # 目标文件夹 347 | tar_dir = [ 348 | "/root/data/InternLM", 349 | "/root/data/InternLM-XComposer", 350 | "/root/data/lagent", 351 | "/root/data/lmdeploy", 352 | "/root/data/opencompass", 353 | "/root/data/xtuner" 354 | ] 355 | 356 | # 加载目标文件 357 | docs = [] 358 | for dir_path in tar_dir: 359 | docs.extend(get_text(dir_path)) 360 | 361 | # 对文本进行分块 362 | text_splitter = RecursiveCharacterTextSplitter( 363 | chunk_size=500, chunk_overlap=150) 364 | split_docs = text_splitter.split_documents(docs) 365 | 366 | # 加载开源词向量模型 367 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 368 | 369 | # 构建向量数据库 370 | # 定义持久化路径 371 | persist_directory = 'data_base/vector_db/chroma' 372 | # 加载数据库 373 | vectordb = Chroma.from_documents( 374 | documents=split_docs, 375 | embedding=embeddings, 376 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 377 | ) 378 | # 将加载的向量数据库持久化到磁盘上 379 | vectordb.persist() 380 | ``` 381 | 382 | 可以在 `/root/data` 下新建一个 `demo`目录,将该脚本和后续脚本均放在该目录下运行。运行上述脚本,即可在本地构建已持久化的向量数据库,后续直接导入该数据库即可,无需重复构建。 383 | 384 | ## 3 InternLM 接入 LangChain 385 | 386 | 为便捷构建 LLM 应用,我们需要基于本地部署的 InternLM,继承 LangChain 的 LLM 类自定义一个 InternLM LLM 子类,从而实现将 InternLM 接入到 LangChain 框架中。完成 LangChain 的自定义 LLM 子类之后,可以以完全一致的方式调用 LangChain 的接口,而无需考虑底层模型调用的不一致。 387 | 388 | 基于本地部署的 InternLM 自定义 LLM 类并不复杂,我们只需从 LangChain.llms.base.LLM 类继承一个子类,并重写构造函数与 `_call` 函数即可: 389 | 390 | ```python 391 | from langchain.llms.base import LLM 392 | from typing import Any, List, Optional 393 | from langchain.callbacks.manager import CallbackManagerForLLMRun 394 | from transformers import AutoTokenizer, AutoModelForCausalLM 395 | import torch 396 | 397 | class InternLM_LLM(LLM): 398 | # 基于本地 InternLM 自定义 LLM 类 399 | tokenizer : AutoTokenizer = None 400 | model: AutoModelForCausalLM = None 401 | 402 | def __init__(self, model_path :str): 403 | # model_path: InternLM 模型路径 404 | # 从本地初始化模型 405 | super().__init__() 406 | print("正在从本地加载模型...") 407 | self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) 408 | self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(torch.bfloat16).cuda() 409 | self.model = self.model.eval() 410 | print("完成本地模型的加载") 411 | 412 | def _call(self, prompt : str, stop: Optional[List[str]] = None, 413 | run_manager: Optional[CallbackManagerForLLMRun] = None, 414 | **kwargs: Any): 415 | # 重写调用函数 416 | system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语). 417 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 418 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 419 | """ 420 | 421 | messages = [(system_prompt, '')] 422 | response, history = self.model.chat(self.tokenizer, prompt , history=messages) 423 | return response 424 | 425 | @property 426 | def _llm_type(self) -> str: 427 | return "InternLM" 428 | ``` 429 | 430 | 在上述类定义中,我们分别重写了构造函数和 `_call` 函数:对于构造函数,我们在对象实例化的一开始加载本地部署的 InternLM 模型,从而避免每一次调用都需要重新加载模型带来的时间过长;`_call` 函数是 LLM 类的核心函数,LangChain 会调用该函数来调用 LLM,在该函数中,我们调用已实例化模型的 chat 方法,从而实现对模型的调用并返回调用结果。 431 | 432 | 在整体项目中,我们将上述代码封装为 LLM.py,后续将直接从该文件中引入自定义的 LLM 类。 433 | 434 | ## 4 构建检索问答链 435 | 436 | LangChain 通过提供检索问答链对象来实现对于 RAG 全流程的封装。所谓检索问答链,即通过一个对象完成检索增强问答(即RAG)的全流程,针对 RAG 的更多概念,我们会在视频内容中讲解,也欢迎读者查阅该教程来进一步了解:[《LLM Universe》](https://github.com/datawhalechina/llm-universe/tree/main)。我们可以调用一个 LangChain 提供的 `RetrievalQA` 对象,通过初始化时填入已构建的数据库和自定义 LLM 作为参数,来简便地完成检索增强问答的全流程,LangChain 会自动完成基于用户提问进行检索、获取相关文档、拼接为合适的 Prompt 并交给 LLM 问答的全部流程。 437 | 438 | ### 4.1 加载向量数据库 439 | 440 | 首先我们需要将上文构建的向量数据库导入进来,我们可以直接通过 Chroma 以及上文定义的词向量模型来加载已构建的数据库: 441 | 442 | ```python 443 | from langchain.vectorstores import Chroma 444 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 445 | import os 446 | 447 | # 定义 Embeddings 448 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 449 | 450 | # 向量数据库持久化路径 451 | persist_directory = 'data_base/vector_db/chroma' 452 | 453 | # 加载数据库 454 | vectordb = Chroma( 455 | persist_directory=persist_directory, 456 | embedding_function=embeddings 457 | ) 458 | ``` 459 | 460 | 上述代码得到的 `vectordb` 对象即为我们已构建的向量数据库对象,该对象可以针对用户的 `query` 进行语义向量检索,得到与用户提问相关的知识片段。 461 | 462 | ### 4.2 实例化自定义 LLM 与 Prompt Template 463 | 464 | 接着,我们实例化一个基于 InternLM 自定义的 LLM 对象: 465 | 466 | ```python 467 | from LLM import InternLM_LLM 468 | llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b") 469 | llm.predict("你是谁") 470 | ``` 471 | 472 | 构建检索问答链,还需要构建一个 Prompt Template,该 Template 其实基于一个带变量的字符串,在检索之后,LangChain 会将检索到的相关文档片段填入到 Template 的变量中,从而实现带知识的 Prompt 构建。我们可以基于 LangChain 的 Template 基类来实例化这样一个 Template 对象: 473 | 474 | ```python 475 | from langchain.prompts import PromptTemplate 476 | 477 | # 我们所构造的 Prompt 模板 478 | template = """使用以下上下文来回答用户的问题。如果你不知道答案,就说你不知道。总是使用中文回答。 479 | 问题: {question} 480 | 可参考的上下文: 481 | ··· 482 | {context} 483 | ··· 484 | 如果给定的上下文无法让你做出回答,请回答你不知道。 485 | 有用的回答:""" 486 | 487 | # 调用 LangChain 的方法来实例化一个 Template 对象,该对象包含了 context 和 question 两个变量,在实际调用时,这两个变量会被检索到的文档片段和用户提问填充 488 | QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template) 489 | ``` 490 | 491 | ### 4.3 构建检索问答链 492 | 493 | 最后,可以调用 LangChain 提供的检索问答链构造函数,基于我们的自定义 LLM、Prompt Template 和向量知识库来构建一个基于 InternLM 的检索问答链: 494 | 495 | ```python 496 | from langchain.chains import RetrievalQA 497 | 498 | qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT}) 499 | ``` 500 | 501 | 得到的 `qa_chain` 对象即可以实现我们的核心功能,即基于 InternLM 模型的专业知识库助手。我们可以对比该检索问答链和纯 LLM 的问答效果: 502 | 503 | ```python 504 | # 检索问答链回答效果 505 | question = "什么是InternLM" 506 | result = qa_chain({"query": question}) 507 | print("检索问答链回答 question 的结果:") 508 | print(result["result"]) 509 | 510 | # 仅 LLM 回答效果 511 | result_2 = llm(question) 512 | print("大模型回答 question 的结果:") 513 | print(result_2) 514 | ``` 515 | 516 | ## 5 部署 Web Demo 517 | 518 | 在完成上述核心功能后,我们可以基于 Gradio 框架将其部署到 Web 网页,从而搭建一个小型 Demo,便于测试与使用。 519 | 520 | 我们首先将上文的代码内容封装为一个返回构建的检索问答链对象的函数,并在启动 Gradio 的第一时间调用该函数得到检索问答链对象,后续直接使用该对象进行问答对话,从而避免重复加载模型: 521 | 522 | ```python 523 | 524 | from langchain.vectorstores import Chroma 525 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 526 | import os 527 | from LLM import InternLM_LLM 528 | from langchain.prompts import PromptTemplate 529 | from langchain.chains import RetrievalQA 530 | 531 | def load_chain(): 532 | # 加载问答链 533 | # 定义 Embeddings 534 | embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer") 535 | 536 | # 向量数据库持久化路径 537 | persist_directory = 'data_base/vector_db/chroma' 538 | 539 | # 加载数据库 540 | vectordb = Chroma( 541 | persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上 542 | embedding_function=embeddings 543 | ) 544 | 545 | # 加载自定义 LLM 546 | llm = InternLM_LLM(model_path = "/root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b") 547 | 548 | # 定义一个 Prompt Template 549 | template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答 550 | 案。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。 551 | {context} 552 | 问题: {question} 553 | 有用的回答:""" 554 | 555 | QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template) 556 | 557 | # 运行 chain 558 | qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT}) 559 | 560 | return qa_chain 561 | ``` 562 | 563 | 接着我们定义一个类,该类负责加载并存储检索问答链,并响应 Web 界面里调用检索问答链进行回答的动作: 564 | 565 | ```python 566 | class Model_center(): 567 | """ 568 | 存储检索问答链的对象 569 | """ 570 | def __init__(self): 571 | # 构造函数,加载检索问答链 572 | self.chain = load_chain() 573 | 574 | def qa_chain_self_answer(self, question: str, chat_history: list = []): 575 | """ 576 | 调用问答链进行回答 577 | """ 578 | if question == None or len(question) < 1: 579 | return "", chat_history 580 | try: 581 | chat_history.append( 582 | (question, self.chain({"query": question})["result"])) 583 | # 将问答结果直接附加到问答历史中,Gradio 会将其展示出来 584 | return "", chat_history 585 | except Exception as e: 586 | return e, chat_history 587 | 588 | ``` 589 | 590 | 然后我们只需按照 Gradio 的框架使用方法,实例化一个 Web 界面并将点击动作绑定到上述类的回答方法即可: 591 | 592 | ```python 593 | import gradio as gr 594 | 595 | # 实例化核心功能对象 596 | model_center = Model_center() 597 | # 创建一个 Web 界面 598 | block = gr.Blocks() 599 | with block as demo: 600 | with gr.Row(equal_height=True): 601 | with gr.Column(scale=15): 602 | # 展示的页面标题 603 | gr.Markdown("""

InternLM

604 |
书生浦语
605 | """) 606 | 607 | with gr.Row(): 608 | with gr.Column(scale=4): 609 | # 创建一个聊天机器人对象 610 | chatbot = gr.Chatbot(height=450, show_copy_button=True) 611 | # 创建一个文本框组件,用于输入 prompt。 612 | msg = gr.Textbox(label="Prompt/问题") 613 | 614 | with gr.Row(): 615 | # 创建提交按钮。 616 | db_wo_his_btn = gr.Button("Chat") 617 | with gr.Row(): 618 | # 创建一个清除按钮,用于清除聊天机器人组件的内容。 619 | clear = gr.ClearButton( 620 | components=[chatbot], value="Clear console") 621 | 622 | # 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。 623 | db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[ 624 | msg, chatbot], outputs=[msg, chatbot]) 625 | 626 | gr.Markdown("""提醒:
627 | 1. 初始化数据库时间可能较长,请耐心等待。 628 | 2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。
629 | """) 630 | gr.close_all() 631 | # 直接启动 632 | demo.launch() 633 | ``` 634 | 635 | 通过将上述代码封装为 run_gradio.py 脚本,直接通过 python 命令运行,即可在本地启动知识库助手的 Web Demo,默认会在 7860 端口运行,接下来将服务器端口映射到本地端口即可访问: 636 | 637 | ![](figures/image-5.png) 638 | 639 | 此处我们简要介绍如何将服务器端口映射到本地端口: 640 | 641 | 首先我们需要配置一下本地的 `SSH Key` ,我们这里以`Windows`为例。 642 | 643 | 1. 在本地机器上打开`Power Shell`终端。在终端中,运行以下命令来生成SSH密钥对:(如下图所示) 644 | ```shell 645 | ssh-keygen -t rsa 646 | ``` 647 | ![Alt text](figures/image-51.png) 648 | 649 | 2. 您将被提示选择密钥文件的保存位置,默认情况下是在 `~/.ssh/` 目录中。按Enter键接受默认值或输入自定义路径。 650 | 651 | 3. 公钥默认存储在 `~/.ssh/id_rsa.pub`,可以通过系统自带的 `cat` 工具查看文件内容:(如下图所示) 652 | 653 | > `~` 是用户主目录的简写,`.ssh` 是SSH配置文件的默认存储目录,`id_rsa.pub` 是SSH公钥文件的默认名称。所以,`cat ~\.ssh\id_rsa.pub` 的意思是查看用户主目录下的 `.ssh` 目录中的 id_rsa.pub 文件的内容。 654 | 655 | ```shell 656 | cat ~\.ssh\id_rsa.pub 657 | ``` 658 | ![Alt text](figures/image-52.png) 659 | 660 | 4. 将公钥复制到剪贴板中,然后回到 `InternStudio` 控制台,点击配置SSH Key。如下图所示: 661 | 662 | ![Alt text](figures/image-53.png) 663 | 664 | 5. 将刚刚复制的公钥添加进入即可。 665 | 666 | ![Alt text](figures/image-54.png) 667 | 668 | 6. 在本地终端输入以下指令.7860是在服务器中打开的端口,而33090是根据开发机的端口进行更改。如下图所示: 669 | 670 | ```shell 671 | ssh -CNg -L 7860:127.0.0.1:7860 root@ssh.intern-ai.org.cn -p 33090 672 | ``` 673 | 674 | ![Alt text](figures/image-55.png) 675 | 676 | 我们在仓库中也同步提供了上述所有脚本,可以查看该教程文件的同级目录的 `demo` 文件夹。 677 | 678 | 679 | ## 6 作业 680 | 681 | 682 | 提交方式:在各个班级对应的 GitHub Discussion 帖子中进行提交。 683 | 684 | 685 | **基础作业**: 686 | 687 | 复现课程知识库助手搭建过程 (截图) 688 | 689 | 690 | **进阶作业**: 691 | 692 | 选择一个垂直领域,收集该领域的专业资料构建专业知识库,并搭建专业问答助手,并在 [OpenXLab](https://openxlab.org.cn/apps) 上成功部署(截图,并提供应用地址) 693 | 694 | **整体实训营项目:** 695 | 696 | 时间周期:即日起致课程结束 697 | 698 | 即日开始可以在班级群中随机组队完成一个大作业项目,一些可提供的选题如下: 699 | 700 | - 人情世故大模型:一个帮助用户撰写新年祝福文案的人情事故大模型 701 | - 中小学数学大模型:一个拥有一定数学解题能力的大模型 702 | - 心理大模型:一个治愈的心理大模型 703 | - 工具调用类项目:结合 Lagent 构建数据集训练 InternLM 模型,支持对 MMYOLO 等工具的调用 704 | - 其他基于书生·浦语工具链的小项目都在范围内,欢迎大家充分发挥想象力。 705 | 706 | 707 | 708 | 709 | -------------------------------------------------------------------------------- /lmdeploy/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/.gitkeep -------------------------------------------------------------------------------- /lmdeploy/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/cover.jpg -------------------------------------------------------------------------------- /lmdeploy/img/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/0.png -------------------------------------------------------------------------------- /lmdeploy/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/1.png -------------------------------------------------------------------------------- /lmdeploy/img/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/10.png -------------------------------------------------------------------------------- /lmdeploy/img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/11.png -------------------------------------------------------------------------------- /lmdeploy/img/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/12.png -------------------------------------------------------------------------------- /lmdeploy/img/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/13.png -------------------------------------------------------------------------------- /lmdeploy/img/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/14.png -------------------------------------------------------------------------------- /lmdeploy/img/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/15.png -------------------------------------------------------------------------------- /lmdeploy/img/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/16.png -------------------------------------------------------------------------------- /lmdeploy/img/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/17.png -------------------------------------------------------------------------------- /lmdeploy/img/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/18.png -------------------------------------------------------------------------------- /lmdeploy/img/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/19.png -------------------------------------------------------------------------------- /lmdeploy/img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/2.png -------------------------------------------------------------------------------- /lmdeploy/img/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/20.png -------------------------------------------------------------------------------- /lmdeploy/img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/3.png -------------------------------------------------------------------------------- /lmdeploy/img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/4.png -------------------------------------------------------------------------------- /lmdeploy/img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/5.png -------------------------------------------------------------------------------- /lmdeploy/img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/6.png -------------------------------------------------------------------------------- /lmdeploy/img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/7.png -------------------------------------------------------------------------------- /lmdeploy/img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/8.png -------------------------------------------------------------------------------- /lmdeploy/img/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/9.png -------------------------------------------------------------------------------- /lmdeploy/img/add0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/add0.png -------------------------------------------------------------------------------- /lmdeploy/img/add1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/add1.png -------------------------------------------------------------------------------- /lmdeploy/img/add3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/add3.png -------------------------------------------------------------------------------- /lmdeploy/img/add4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/add4.png -------------------------------------------------------------------------------- /lmdeploy/img/lmdeploy.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/lmdeploy.drawio.png -------------------------------------------------------------------------------- /lmdeploy/img/quant.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/lmdeploy/img/quant.drawio.png -------------------------------------------------------------------------------- /lmdeploy/infer_compare.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from transformers import AutoTokenizer, AutoModelForCausalLM 3 | 4 | from lmdeploy import turbomind as tm 5 | 6 | 7 | def get_prompt(query: str) -> str: 8 | prompt = f"""<|System|>:You are an AI assistant whose name is InternLM (书生·浦语). 9 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 10 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 11 | 12 | <|User|>:{query} 13 | <|Bot|>:""" 14 | return prompt 15 | 16 | 17 | 18 | def gen_lmdeploy(query: str, tokenizer, model) -> str: 19 | prompt = get_prompt(query) 20 | input_ids = tokenizer.encode(prompt) 21 | for outputs in model.stream_infer( 22 | session_id=0, 23 | input_ids=[input_ids], 24 | request_output_len=512, 25 | temperature=0.0, 26 | ): 27 | ... 28 | res, _tokens = outputs[0] 29 | output = tokenizer.decode(res) 30 | return output 31 | 32 | 33 | 34 | def gen_transformers(query: str, tokenizer, model) -> str: 35 | prompt = get_prompt(query) 36 | inputs = tokenizer([prompt], return_tensors="pt").to(device) 37 | res = model.generate( 38 | **inputs, 39 | max_new_tokens=512, 40 | ) 41 | output = tokenizer.decode(res[0]) 42 | output = output.replace(prompt, "").replace("", "").strip() 43 | return output 44 | 45 | 46 | 47 | import sys 48 | import time 49 | 50 | device = "cuda:0" 51 | 52 | model_path = "/root/share/temp/model_repos/internlm-chat-7b/" 53 | tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) 54 | 55 | engine = sys.argv[1] 56 | 57 | if engine == "hf": 58 | model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16, trust_remote_code=True) 59 | model.to(device).eval(); 60 | gen_func = gen_transformers 61 | else: 62 | tm_model = tm.TurboMind.from_pretrained("./workspace/") 63 | model = tm_model.create_instance() 64 | gen_func = gen_lmdeploy 65 | 66 | 67 | count = 0 68 | start = time.time() 69 | for season in ["春天", "夏天", "秋天", "冬天"]: 70 | q = f"写一篇关于{season}的300字小作文。" 71 | output = gen_func(q, tokenizer, model) 72 | count += len(output) 73 | end = time.time() 74 | cost = (end - start) 75 | throughput = round(count / cost) 76 | 77 | print(f"{engine} 耗时 {cost:.2f}秒 {throughput} 字/秒") 78 | 79 | 80 | -------------------------------------------------------------------------------- /lmdeploy/lmdeploy.md: -------------------------------------------------------------------------------- 1 | ![](cover.jpg) 2 | 3 | # LMDeploy 的量化和部署 4 | 5 | 6 | 7 | 8 | - [1 环境配置](#1-%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE) 9 | - [2 服务部署](#2-%E6%9C%8D%E5%8A%A1%E9%83%A8%E7%BD%B2) 10 | - [2.1 模型转换](#21-%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2) 11 | - [2.1.1 在线转换](#211-%E5%9C%A8%E7%BA%BF%E8%BD%AC%E6%8D%A2) 12 | - [2.1.2 离线转换](#212-%E7%A6%BB%E7%BA%BF%E8%BD%AC%E6%8D%A2) 13 | - [2.2 TurboMind 推理+命令行本地对话](#22--turbomind-%E6%8E%A8%E7%90%86%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%9C%AC%E5%9C%B0%E5%AF%B9%E8%AF%9D) 14 | - [2.3 TurboMind推理+API服务](#23-turbomind%E6%8E%A8%E7%90%86api%E6%9C%8D%E5%8A%A1) 15 | - [2.4 网页 Demo 演示](#24-%E7%BD%91%E9%A1%B5-demo-%E6%BC%94%E7%A4%BA) 16 | - [2.4.1 TurboMind 服务作为后端](#241-turbomind-%E6%9C%8D%E5%8A%A1%E4%BD%9C%E4%B8%BA%E5%90%8E%E7%AB%AF) 17 | - [2.4.2 TurboMind 推理作为后端](#242-turbomind-%E6%8E%A8%E7%90%86%E4%BD%9C%E4%B8%BA%E5%90%8E%E7%AB%AF) 18 | - [2.5 TurboMind 推理 + Python 代码集成](#25-turbomind-%E6%8E%A8%E7%90%86--python-%E4%BB%A3%E7%A0%81%E9%9B%86%E6%88%90) 19 | - [2.6 这么多,头秃,有没有最佳实践](#26-%E8%BF%99%E4%B9%88%E5%A4%9A%E5%A4%B4%E7%A7%83%E6%9C%89%E6%B2%A1%E6%9C%89%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5) 20 | - [2.6.1 方案实践](#261-%E6%96%B9%E6%A1%88%E5%AE%9E%E8%B7%B5) 21 | - [2.6.2 模型配置实践](#262-%E6%A8%A1%E5%9E%8B%E9%85%8D%E7%BD%AE%E5%AE%9E%E8%B7%B5) 22 | - [3 模型量化](#3-%E6%A8%A1%E5%9E%8B%E9%87%8F%E5%8C%96) 23 | - [3.1 KV Cache 量化](#31-kv-cache-%E9%87%8F%E5%8C%96) 24 | - [3.1.1 量化步骤](#311-%E9%87%8F%E5%8C%96%E6%AD%A5%E9%AA%A4) 25 | - [3.1.2 量化效果](#312-%E9%87%8F%E5%8C%96%E6%95%88%E6%9E%9C) 26 | - [3.2 W4A16 量化](#32-w4a16-%E9%87%8F%E5%8C%96) 27 | - [3.2.1 量化步骤](#321-%E9%87%8F%E5%8C%96%E6%AD%A5%E9%AA%A4) 28 | - [3.2.2 量化效果](#322-%E9%87%8F%E5%8C%96%E6%95%88%E6%9E%9C) 29 | - [3.3 最佳实践](#33-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5) 30 | - [参考资料](#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99) 31 | - [附录1:TritonServer 作为推理引擎](#%E9%99%84%E5%BD%951tritonserver-%E4%BD%9C%E4%B8%BA%E6%8E%A8%E7%90%86%E5%BC%95%E6%93%8E) 32 | - [TritonServer环境配置](#tritonserver%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE) 33 | - [TritonServer推理+API服务](#tritonserver%E6%8E%A8%E7%90%86api%E6%9C%8D%E5%8A%A1) 34 | - [TritonServer 服务作为后端](#tritonserver-%E6%9C%8D%E5%8A%A1%E4%BD%9C%E4%B8%BA%E5%90%8E%E7%AB%AF) 35 | 36 | 37 | 38 | 39 | ## 1 环境配置 40 | 41 | 首先我们可以使用 `vgpu-smi ` 查看显卡资源使用情况。 42 | 43 | ![](img/0.png) 44 | 45 | 大家可以使用系统给的 vscode 进行后面的开发。分别点击下图「1」和「2」的位置,就会在下方显示终端。 46 | 47 | ![](img/add0.png) 48 | 49 | 可以点击终端(TERMINAL)窗口右侧的「+」号创建新的终端窗口。大家可以新开一个窗口,执行下面的命令实时观察 GPU 资源的使用情况。 50 | 51 | ```bash 52 | $ watch vgpu-smi 53 | ``` 54 | 55 | 结果如下图所示,该窗口会实时检测 GPU 卡的使用情况。 56 | 57 | ![](img/add1.png) 58 | 59 | 接下来我们切换到刚刚的终端(就是上图右边的那个「bash」,下面的「watch」就是监控的终端),创建部署和量化需要的环境。建议大家使用官方提供的环境,使用 conda 直接复制。 60 | 61 | 这里 `/share/conda_envs` 目录下的环境是官方未大家准备好的基础环境,因为该目录是共享只读的,而我们后面需要在此基础上安装新的软件包,所以需要复制到我们自己的 conda 环境(该环境下我们是可写的)。 62 | 63 | ```bash 64 | $ conda create -n CONDA_ENV_NAME --clone /share/conda_envs/internlm-base 65 | ``` 66 | 67 | - 如果clone操作过慢,可采用如下操作: 68 | 69 | ```bash 70 | $ /root/share/install_conda_env_internlm_base.sh lmdeploy 71 | ``` 72 | 73 | 我们取 `CONDA_ENV_NAME` 为 `lmdeploy`,复制完成后,可以在本地查看环境。 74 | 75 | ```bash 76 | $ conda env list 77 | ``` 78 | 79 | 结果如下所示。 80 | 81 | ```bash 82 | # conda environments: 83 | # 84 | base * /root/.conda 85 | lmdeploy /root/.conda/envs/lmdeploy 86 | ``` 87 | 88 | 然后激活环境。 89 | 90 | ```bash 91 | $ conda activate lmdeploy 92 | ``` 93 | 94 | 注意,环境激活后,左边会显示当前(也就是 `lmdeploy`)的环境名称,如下图所示。 95 | 96 | ![](img/1.png) 97 | 98 | 可以进入Python检查一下 PyTorch 和 lmdeploy 的版本。由于 PyTorch 在官方提供的环境里,我们应该可以看到版本显示,而 lmdeploy 需要我们自己安装,此处应该会提示“没有这个包”,如下图所示。 99 | 100 | ![](img/2.png) 101 | 102 | lmdeploy 没有安装,我们接下来手动安装一下,建议安装最新的稳定版。 103 | 如果是在 InternStudio 开发环境,需要先运行下面的命令,否则会报错。 104 | 105 | 106 | ```bash 107 | # 解决 ModuleNotFoundError: No module named 'packaging' 问题 108 | pip install packaging 109 | # 使用 flash_attn 的预编译包解决安装过慢问题 110 | pip install /root/share/wheels/flash_attn-2.4.2+cu118torch2.0cxx11abiTRUE-cp310-cp310-linux_x86_64.whl 111 | ``` 112 | 113 | ```bash 114 | pip install 'lmdeploy[all]==v0.1.0' 115 | ``` 116 | 117 | 由于默认安装的是 runtime 依赖包,但是我们这里还需要部署和量化,所以,这里选择 `[all]`。然后可以再检查一下 lmdeploy 包,如下图所示。 118 | 119 | ![](img/add3.png) 120 | 121 | 122 | 基础环境到这里就配置好了。 123 | 124 | - 如果遇到`lmdeploy: command not found` 或其他问题,移步 [QA 文档](https://cguue83gpz.feishu.cn/docx/Noi7d5lllo6DMGxkuXwclxXMn5f#H2w9drpHiogeOHxhK7PcdJCmn8c) 125 | 126 | ## 2 服务部署 127 | 128 | 这一部分主要涉及本地推理和部署。我们先看一张图。 129 | 130 | ![](img/lmdeploy.drawio.png) 131 | 132 | 我们把从架构上把整个服务流程分成下面几个模块。 133 | 134 | - 模型推理/服务。主要提供模型本身的推理,一般来说可以和具体业务解耦,专注模型推理本身性能的优化。可以以模块、API等多种方式提供。 135 | - Client。可以理解为前端,与用户交互的地方。 136 | - API Server。一般作为前端的后端,提供与产品和服务相关的数据和功能支持。 137 | 138 | 值得说明的是,以上的划分是一个相对完整的模型,但在实际中这并不是绝对的。比如可以把“模型推理”和“API Server”合并,有的甚至是三个流程打包在一起提供服务。 139 | 140 | 接下来,我们看一下lmdeploy提供的部署功能。 141 | 142 | ### 2.1 模型转换 143 | 144 | 使用 TurboMind 推理模型需要先将模型转化为 TurboMind 的格式,目前支持在线转换和离线转换两种形式。在线转换可以直接加载 Huggingface 模型,离线转换需需要先保存模型再加载。 145 | 146 | TurboMind 是一款关于 LLM 推理的高效推理引擎,基于英伟达的 [FasterTransformer](https://github.com/NVIDIA/FasterTransformer) 研发而成。它的主要功能包括:LLaMa 结构模型的支持,persistent batch 推理模式和可扩展的 KV 缓存管理器。 147 | 148 | #### 2.1.1 在线转换 149 | 150 | lmdeploy 支持直接读取 Huggingface 模型权重,目前共支持三种类型: 151 | 152 | - 在 huggingface.co 上面通过 lmdeploy 量化的模型,如 [llama2-70b-4bit](https://huggingface.co/lmdeploy/llama2-chat-70b-4bit), [internlm-chat-20b-4bit](https://huggingface.co/internlm/internlm-chat-20b-4bit) 153 | - huggingface.co 上面其他 LM 模型,如 Qwen/Qwen-7B-Chat 154 | 155 | 示例如下: 156 | 157 | ```bash 158 | # 需要能访问 Huggingface 的网络环境 159 | lmdeploy chat turbomind internlm/internlm-chat-20b-4bit --model-name internlm-chat-20b 160 | lmdeploy chat turbomind Qwen/Qwen-7B-Chat --model-name qwen-7b 161 | ``` 162 | 163 | 上面两行命令分别展示了如何直接加载 Huggingface 的模型,第一条命令是加载使用 lmdeploy 量化的版本,第二条命令是加载其他 LLM 模型。 164 | 165 | 我们也可以直接启动本地的 Huggingface 模型,如下所示。 166 | 167 | ```bash 168 | lmdeploy chat turbomind /share/temp/model_repos/internlm-chat-7b/ --model-name internlm-chat-7b 169 | ``` 170 | 171 | 以上命令都会启动一个本地对话界面,通过 Bash 可以与 LLM 进行对话。 172 | 173 | #### 2.1.2 离线转换 174 | 175 | 离线转换需要在启动服务之前,将模型转为 lmdeploy TurboMind 的格式,如下所示。 176 | 177 | ```bash 178 | # 转换模型(FastTransformer格式) TurboMind 179 | lmdeploy convert internlm-chat-7b /path/to/internlm-chat-7b 180 | ``` 181 | 182 | 这里我们使用官方提供的模型文件,就在用户根目录执行,如下所示。 183 | 184 | ```bash 185 | lmdeploy convert internlm-chat-7b /root/share/temp/model_repos/internlm-chat-7b/ 186 | ``` 187 | 188 | 执行完成后将会在当前目录生成一个 `workspace` 的文件夹。这里面包含的就是 TurboMind 和 Triton “模型推理”需要到的文件。 189 | 190 | 目录如下图所示。 191 | 192 | ![](img/4.png) 193 | 194 | `weights` 和 `tokenizer` 目录分别放的是拆分后的参数和 Tokenizer。如果我们进一步查看 `weights` 的目录,就会发现参数是按层和模块拆开的,如下图所示。 195 | 196 | ![](img/5.png) 197 | 198 | 每一份参数第一个 0 表示“层”的索引,后面的那个0表示 Tensor 并行的索引,因为我们只有一张卡,所以被拆分成 1 份。如果有两张卡可以用来推理,则会生成0和1两份,也就是说,会把同一个参数拆成两份。比如 `layers.0.attention.w_qkv.0.weight` 会变成 `layers.0.attention.w_qkv.0.weight` 和 `layers.0.attention.w_qkv.1.weight`。执行 `lmdeploy convert` 命令时,可以通过 `--tp` 指定(tp 表示 tensor parallel),该参数默认值为1(也就是一张卡)。 199 | 200 | **关于Tensor并行** 201 | 202 | Tensor并行一般分为行并行或列并行,原理如下图所示。 203 | 204 | ![](img/6.png) 205 | 206 |

列并行

207 | 208 | ![](img/7.png) 209 | 210 |

行并行

211 | 212 | 简单来说,就是把一个大的张量(参数)分到多张卡上,分别计算各部分的结果,然后再同步汇总。 213 | 214 | ### 2.2 TurboMind 推理+命令行本地对话 215 | 216 | 模型转换完成后,我们就具备了使用模型推理的条件,接下来就可以进行真正的模型推理环节。 217 | 218 | 我们先尝试本地对话(`Bash Local Chat`),下面用(Local Chat 表示)在这里其实是跳过 API Server 直接调用 TurboMind。简单来说,就是命令行代码直接执行 TurboMind。所以说,实际和前面的架构图是有区别的。 219 | 220 | 这里支持多种方式运行,比如Turbomind、PyTorch、DeepSpeed。但 PyTorch 和 DeepSpeed 调用的其实都是 Huggingface 的 Transformers 包,PyTorch表示原生的 Transformer 包,DeepSpeed 表示使用了 DeepSpeed 作为推理框架。Pytorch/DeepSpeed 目前功能都比较弱,不具备生产能力,不推荐使用。 221 | 222 | 执行命令如下。 223 | 224 | ```bash 225 | # Turbomind + Bash Local Chat 226 | lmdeploy chat turbomind ./workspace 227 | ``` 228 | 229 | 启动后就可以和它进行对话了,如下图所示。 230 | 231 | ![](img/8.png) 232 | 233 | 输入后两次回车,退出时输入`exit` 回车两次即可。此时,Server 就是本地跑起来的模型(TurboMind),命令行可以看作是前端。 234 | 235 | ### 2.3 TurboMind推理+API服务 236 | 237 | 在上面的部分我们尝试了直接用命令行启动 Client,接下来我们尝试如何运用 lmdepoy 进行服务化。 238 | 239 | ”模型推理/服务“目前提供了 Turbomind 和 TritonServer 两种服务化方式。此时,Server 是 TurboMind 或 TritonServer,API Server 可以提供对外的 API 服务。我们推荐使用 TurboMind,TritonServer 使用方式详见《附录1》。 240 | 241 | 首先,通过下面命令启动服务。 242 | 243 | 244 | ```bash 245 | # ApiServer+Turbomind api_server => AsyncEngine => TurboMind 246 | lmdeploy serve api_server ./workspace \ 247 | --server_name 0.0.0.0 \ 248 | --server_port 23333 \ 249 | --instance_num 64 \ 250 | --tp 1 251 | ``` 252 | 253 | 上面的参数中 `server_name` 和 `server_port` 分别表示服务地址和端口,`tp` 参数我们之前已经提到过了,表示 Tensor 并行。还剩下一个 `instance_num` 参数,表示实例数,可以理解成 Batch 的大小。执行后如下图所示。 254 | 255 | ![](img/11.png) 256 | 257 | 然后,我们可以新开一个窗口,执行下面的 Client 命令。如果使用官方机器,可以打开 vscode 的 Terminal,执行下面的命令。 258 | 259 | ```bash 260 | # ChatApiClient+ApiServer(注意是http协议,需要加http) 261 | lmdeploy serve api_client http://localhost:23333 262 | ``` 263 | 264 | 如下图所示。 265 | 266 | ![](img/12.png) 267 | 268 | 当然,刚刚我们启动的是 API Server,自然也有相应的接口。可以直接打开 `http://{host}:23333` 查看,如下图所示。 269 | 270 | ![](img/13.png) 271 | 272 | > 注意,这一步由于 Server 在远程服务器上,所以本地需要做一下 ssh 转发才能直接访问(与第一部分操作一样),命令如下: 273 | > 274 | > ssh -CNg -L 23333:127.0.0.1:23333 root@ssh.intern-ai.org.cn -p <你的ssh端口号> 275 | > 276 | > 而执行本命令需要添加本机公钥,公钥添加后等待几分钟即可生效。ssh 端口号就是下面图片里的 33087。 277 | > 278 | > ![](img/20.png) 279 | 280 | 这里一共提供了 4 个 HTTP 的接口,任何语言都可以对其进行调用,我们以 `v1/chat/completions` 接口为例,简单试一下。 281 | 282 | 接口请求参数如下: 283 | 284 | ```json 285 | { 286 | "model": "internlm-chat-7b", 287 | "messages": "写一首春天的诗", 288 | "temperature": 0.7, 289 | "top_p": 1, 290 | "n": 1, 291 | "max_tokens": 512, 292 | "stop": false, 293 | "stream": false, 294 | "presence_penalty": 0, 295 | "frequency_penalty": 0, 296 | "user": "string", 297 | "repetition_penalty": 1, 298 | "renew_session": false, 299 | "ignore_eos": false 300 | } 301 | ``` 302 | 303 | 请求结果如下。 304 | 305 | ![](img/16.png) 306 | 307 | ### 2.4 网页 Demo 演示 308 | 309 | 这一部分主要是将 Gradio 作为前端 Demo 演示。在上一节的基础上,我们不执行后面的 `api_client` 或 `triton_client`,而是执行 `gradio`。 310 | 311 | > 由于 Gradio 需要本地访问展示界面,因此也需要通过 ssh 将数据转发到本地。命令如下: 312 | > 313 | > ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p <你的 ssh 端口号> 314 | 315 | #### 2.4.1 TurboMind 服务作为后端 316 | 317 | API Server 的启动和上一节一样,这里直接启动作为前端的 Gradio。 318 | 319 | ```bash 320 | # Gradio+ApiServer。必须先开启 Server,此时 Gradio 为 Client 321 | lmdeploy serve gradio http://0.0.0.0:23333 \ 322 | --server_name 0.0.0.0 \ 323 | --server_port 6006 \ 324 | --restful_api True 325 | ``` 326 | 327 | 结果如下图所示。 328 | 329 | ![](img/17.png) 330 | 331 | 332 | #### 2.4.2 TurboMind 推理作为后端 333 | 334 | 当然,Gradio 也可以直接和 TurboMind 连接,如下所示。 335 | 336 | ```bash 337 | # Gradio+Turbomind(local) 338 | lmdeploy serve gradio ./workspace 339 | ``` 340 | 341 | 可以直接启动 Gradio,此时没有 API Server,TurboMind 直接与 Gradio 通信。如下图所示。 342 | 343 | ![](img/19.png) 344 | 345 | ### 2.5 TurboMind 推理 + Python 代码集成 346 | 347 | 前面介绍的都是通过 API 或某种前端与”模型推理/服务“进行交互,lmdeploy 还支持 Python 直接与 TurboMind 进行交互,如下所示。 348 | 349 | ```python 350 | from lmdeploy import turbomind as tm 351 | 352 | # load model 353 | model_path = "/root/share/temp/model_repos/internlm-chat-7b/" 354 | tm_model = tm.TurboMind.from_pretrained(model_path, model_name='internlm-chat-20b') 355 | generator = tm_model.create_instance() 356 | 357 | # process query 358 | query = "你好啊兄嘚" 359 | prompt = tm_model.model.get_prompt(query) 360 | input_ids = tm_model.tokenizer.encode(prompt) 361 | 362 | # inference 363 | for outputs in generator.stream_infer( 364 | session_id=0, 365 | input_ids=[input_ids]): 366 | res, tokens = outputs[0] 367 | 368 | response = tm_model.tokenizer.decode(res.tolist()) 369 | print(response) 370 | ``` 371 | 372 | 在上面的代码中,我们首先加载模型,然后构造输入,最后执行推理。 373 | 374 | 加载模型可以显式指定模型路径,也可以直接指定 Huggingface 的 repo_id,还可以使用上面生成过的 `workspace`。这里的 `tm.TurboMind` 其实是对 C++ TurboMind 的封装。 375 | 376 | 构造输入这里主要是把用户的 query 构造成 InternLLM 支持的输入格式,比如上面的例子中, `query` 是“你好啊兄嘚”,构造好的 Prompt 如下所示。 377 | 378 | ```python 379 | """ 380 | <|System|>:You are an AI assistant whose name is InternLM (书生·浦语). 381 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 382 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 383 | 384 | <|User|>:你好啊兄嘚 385 | <|Bot|>: 386 | """ 387 | ``` 388 | 389 | Prompt 其实就是增加了 `<|System|>` 消息和 `<|User|>` 消息(即用户的 `query`),以及一个 `<|Bot|>` 的标记,表示接下来该模型输出响应了。最终输出的响应内容如下所示。 390 | 391 | ```python 392 | "你好啊,有什么我可以帮助你的吗?" 393 | ``` 394 | 395 | ### 2.6 这么多,头秃,有没有最佳实践 396 | 397 | #### 2.6.1 方案实践 398 | 399 | 必——须——有! 400 | 401 | 首先说 “模型推理/服务”,推荐使用 TurboMind,使用简单,性能良好,相关的 Benchmark 对比如下。 402 | 403 | ![](img/add4.png) 404 | 405 | 上面的性能对比包括两个场景: 406 | 407 | - 场景一(前4张图):固定的输入、输出 token 数(分别1和2048),测试Token输出吞吐量(output token throughput)。 408 | - 场景二(第5张图):使用真实数据,测试吞吐量(request throughput)。 409 | 410 | 场景一中,BatchSize=64时,TurboMind 的吞吐量超过 2000 token/s,整体比 DeepSpeed 提升约 5% - 15%;BatchSize=32时,比 Huggingface 的Transformers 提升约 3 倍;其他BatchSize时 TurboMind 也表现出优异的性能。 411 | 412 | 场景二中,对比了 TurboMind 和 vLLM 在真实数据上的吞吐量(request throughput)指标,TurboMind 的效率比 vLLM 高 30%。 413 | 414 | 大家不妨亲自使用本地对话(Local Chat)感受一下性能差别(2.2 节),也可以执行我们提供的 `infer_compare.py` 脚本,示例如下。 415 | 416 | ```bash 417 | # 执行 Huggingface 的 Transformer 418 | python infer_compare.py hf 419 | # 执行LMDeploy 420 | python infer_compare.py lmdeploy 421 | ``` 422 | 423 | LMDeploy应该是Transformers的3-5倍左右。 424 | 425 | 后面的 API 服务和 Client 就得分场景了。 426 | 427 | - 我想对外提供类似 OpenAI 那样的 HTTP 接口服务。推荐使用 TurboMind推理 + API 服务(2.3)。 428 | - 我想做一个演示 Demo,Gradio 无疑是比 Local Chat 更友好的。推荐使用 TurboMind 推理作为后端的Gradio进行演示(2.4.2)。 429 | - 我想直接在自己的 Python 项目中使用大模型功能。推荐使用 TurboMind推理 + Python(2.5)。 430 | - 我想在自己的其他非 Python 项目中使用大模型功能。推荐直接通过 HTTP 接口调用服务。也就是用本列表第一条先启动一个 HTTP API 服务,然后在项目中直接调用接口。 431 | - 我的项目是 C++ 写的,为什么不能直接用 TurboMind 的 C++ 接口?!必须可以!大佬可以右上角叉掉这个窗口啦。 432 | 433 | #### 2.6.2 模型配置实践 434 | 435 | 不知道大家还有没有印象,在离线转换(2.1.2)一节,我们查看了 `weights` 的目录,里面存放的是模型按层、按并行卡拆分的参数,不过还有一个文件 `config.ini` 并不是模型参数,它里面存的主要是模型相关的配置信息。下面是一个示例。 436 | 437 | ```ini 438 | [llama] 439 | model_name = internlm-chat-7b 440 | tensor_para_size = 1 441 | head_num = 32 442 | kv_head_num = 32 443 | vocab_size = 103168 444 | num_layer = 32 445 | inter_size = 11008 446 | norm_eps = 1e-06 447 | attn_bias = 0 448 | start_id = 1 449 | end_id = 2 450 | session_len = 2056 451 | weight_type = fp16 452 | rotary_embedding = 128 453 | rope_theta = 10000.0 454 | size_per_head = 128 455 | group_size = 0 456 | max_batch_size = 64 457 | max_context_token_num = 1 458 | step_length = 1 459 | cache_max_entry_count = 0.5 460 | cache_block_seq_len = 128 461 | cache_chunk_size = 1 462 | use_context_fmha = 1 463 | quant_policy = 0 464 | max_position_embeddings = 2048 465 | rope_scaling_factor = 0.0 466 | use_logn_attn = 0 467 | ``` 468 | 469 | 其中,模型属性相关的参数不可更改,主要包括下面这些。 470 | 471 | ```ini 472 | model_name = llama2 473 | head_num = 32 474 | kv_head_num = 32 475 | vocab_size = 103168 476 | num_layer = 32 477 | inter_size = 11008 478 | norm_eps = 1e-06 479 | attn_bias = 0 480 | start_id = 1 481 | end_id = 2 482 | rotary_embedding = 128 483 | rope_theta = 10000.0 484 | size_per_head = 128 485 | ``` 486 | 487 | 和数据类型相关的参数也不可更改,主要包括两个。 488 | 489 | ```ini 490 | weight_type = fp16 491 | group_size = 0 492 | ``` 493 | 494 | `weight_type` 表示权重的数据类型。目前支持 fp16 和 int4。int4 表示 4bit 权重。当 `weight_type` 为 4bit 权重时,`group_size` 表示 `awq` 量化权重时使用的 group 大小。 495 | 496 | 剩余参数包括下面几个。 497 | 498 | ```ini 499 | tensor_para_size = 1 500 | session_len = 2056 501 | max_batch_size = 64 502 | max_context_token_num = 1 503 | step_length = 1 504 | cache_max_entry_count = 0.5 505 | cache_block_seq_len = 128 506 | cache_chunk_size = 1 507 | use_context_fmha = 1 508 | quant_policy = 0 509 | max_position_embeddings = 2048 510 | rope_scaling_factor = 0.0 511 | use_logn_attn = 0 512 | ``` 513 | 514 | 一般情况下,我们并不需要对这些参数进行修改,但有时候为了满足特定需要,可能需要调整其中一部分配置值。这里主要介绍三个可能需要调整的参数。 515 | 516 | - KV int8 开关: 517 | - 对应参数为 `quant_policy`,默认值为 0,表示不使用 KV Cache,如果需要开启,则将该参数设置为 4。 518 | - KV Cache 是对序列生成过程中的 K 和 V 进行量化,用以节省显存。我们下一部分会介绍具体的量化过程。 519 | - 当显存不足,或序列比较长时,建议打开此开关。 520 | - 外推能力开关: 521 | - 对应参数为 `rope_scaling_factor`,默认值为 0.0,表示不具备外推能力,设置为 1.0,可以开启 RoPE 的 Dynamic NTK 功能,支持长文本推理。另外,`use_logn_attn` 参数表示 Attention 缩放,默认值为 0,如果要开启,可以将其改为 1。 522 | - 外推能力是指推理时上下文的长度超过训练时的最大长度时模型生成的能力。如果没有外推能力,当推理时上下文长度超过训练时的最大长度,效果会急剧下降。相反,则下降不那么明显,当然如果超出太多,效果也会下降的厉害。 523 | - 当推理文本非常长(明显超过了训练时的最大长度)时,建议开启外推能力。 524 | - 批处理大小: 525 | - 对应参数为 `max_batch_size`,默认为 64,也就是我们在 API Server 启动时的 `instance_num` 参数。 526 | - 该参数值越大,吞度量越大(同时接受的请求数),但也会占用更多显存。 527 | - 建议根据请求量和最大的上下文长度,按实际情况调整。 528 | 529 | ## 3 模型量化 530 | 531 | 本部分内容主要介绍如何对模型进行量化。主要包括 KV Cache 量化和模型参数量化。总的来说,量化是一种以参数或计算中间结果精度下降换空间节省(以及同时带来的性能提升)的策略。 532 | 533 | 正式介绍 LMDeploy 量化方案前,需要先介绍两个概念: 534 | 535 | - 计算密集(compute-bound): 指推理过程中,绝大部分时间消耗在数值计算上;针对计算密集型场景,可以通过使用更快的硬件计算单元来提升计算速。 536 | - 访存密集(memory-bound): 指推理过程中,绝大部分时间消耗在数据读取上;针对访存密集型场景,一般通过减少访存次数、提高计算访存比或降低访存量来优化。 537 | 538 | 常见的 LLM 模型由于 Decoder Only 架构的特性,实际推理时大多数的时间都消耗在了逐 Token 生成阶段(Decoding 阶段),是典型的访存密集型场景。 539 | 540 | 那么,如何优化 LLM 模型推理中的访存密集问题呢? 我们可以使用 **KV Cache 量化**和 **4bit Weight Only 量化(W4A16)**。KV Cache 量化是指将逐 Token(Decoding)生成过程中的上下文 K 和 V 中间结果进行 INT8 量化(计算时再反量化),以降低生成过程中的显存占用。4bit Weight 量化,将 FP16 的模型权重量化为 INT4,Kernel 计算时,访存量直接降为 FP16 模型的 1/4,大幅降低了访存成本。Weight Only 是指仅量化权重,数值计算依然采用 FP16(需要将 INT4 权重反量化)。 541 | 542 | ### 3.1 KV Cache 量化 543 | 544 | #### 3.1.1 量化步骤 545 | 546 | KV Cache 量化是将已经生成序列的 KV 变成 Int8,使用过程一共包括三步: 547 | 548 | 第一步:计算 minmax。主要思路是通过计算给定输入样本在每一层不同位置处计算结果的统计情况。 549 | 550 | - 对于 Attention 的 K 和 V:取每个 Head 各自维度在所有Token的最大、最小和绝对值最大值。对每一层来说,上面三组值都是 `(num_heads, head_dim)` 的矩阵。这里的统计结果将用于本小节的 KV Cache。 551 | - 对于模型每层的输入:取对应维度的最大、最小、均值、绝对值最大和绝对值均值。每一层每个位置的输入都有对应的统计值,它们大多是 `(hidden_dim, )` 的一维向量,当然在 FFN 层由于结构是先变宽后恢复,因此恢复的位置维度并不相同。这里的统计结果用于下个小节的模型参数量化,主要用在缩放环节(回顾PPT内容)。 552 | 553 | 第一步执行命令如下: 554 | 555 | ```bash 556 | # 计算 minmax 557 | lmdeploy lite calibrate \ 558 | --model /root/share/temp/model_repos/internlm-chat-7b/ \ 559 | --calib_dataset "c4" \ 560 | --calib_samples 128 \ 561 | --calib_seqlen 2048 \ 562 | --work_dir ./quant_output 563 | ``` 564 | 565 | 在这个命令行中,会选择 128 条输入样本,每条样本长度为 2048,数据集选择 C4,输入模型后就会得到上面的各种统计值。值得说明的是,如果显存不足,可以适当调小 samples 的数量或 sample 的长度。 566 | 567 | > 这一步由于默认需要从 Huggingface 下载数据集,国内经常不成功。所以我们导出了需要的数据,大家需要对读取数据集的代码文件做一下替换。共包括两步: 568 | > 569 | > - 第一步:复制 `calib_dataloader.py` 到安装目录替换该文件:`cp /root/share/temp/datasets/c4/calib_dataloader.py /root/.conda/envs/lmdeploy/lib/python3.10/site-packages/lmdeploy/lite/utils/` 570 | > - 第二步:将用到的数据集(c4)复制到下面的目录:`cp -r /root/share/temp/datasets/c4/ /root/.cache/huggingface/datasets/` 571 | 572 | 第二步:通过 minmax 获取量化参数。主要就是利用下面这个公式,获取每一层的 K V 中心值(zp)和缩放值(scale)。 573 | 574 | ```bash 575 | zp = (min+max) / 2 576 | scale = (max-min) / 255 577 | quant: q = round( (f-zp) / scale) 578 | dequant: f = q * scale + zp 579 | ``` 580 | 581 | 有这两个值就可以进行量化和解量化操作了。具体来说,就是对历史的 K 和 V 存储 quant 后的值,使用时在 dequant。 582 | 583 | 第二步的执行命令如下: 584 | 585 | ```bash 586 | # 通过 minmax 获取量化参数 587 | lmdeploy lite kv_qparams \ 588 | --work_dir ./quant_output \ 589 | --turbomind_dir workspace/triton_models/weights/ \ 590 | --kv_sym False \ 591 | --num_tp 1 592 | ``` 593 | 594 | 在这个命令中,`num_tp` 的含义前面介绍过,表示 Tensor 的并行数。每一层的中心值和缩放值会存储到 `workspace` 的参数目录中以便后续使用。`kv_sym` 为 `True` 时会使用另一种(对称)量化方法,它用到了第一步存储的绝对值最大值,而不是最大值和最小值。 595 | 596 | 第三步:修改配置。也就是修改 `weights/config.ini` 文件,这个我们在《2.6.2 模型配置实践》中已经提到过了(KV int8 开关),只需要把 `quant_policy` 改为 4 即可。 597 | 598 | 这一步需要额外说明的是,如果用的是 TurboMind1.0,还需要修改参数 `use_context_fmha`,将其改为 0。 599 | 600 | 接下来就可以正常运行前面的各种服务了,只不过咱们现在可是用上了 KV Cache 量化,能更省(运行时)显存了。 601 | 602 | #### 3.1.2 量化效果 603 | 604 | 官方给出了 [internlm-chat-7b](https://huggingface.co/internlm/internlm-chat-7b) 模型在 KV Cache 量化前后的显存对比情况,如下表所示。 605 | 606 | | batch_size | fp16 memory(MiB) | int8 memory(MiB) | diff(MiB) | 607 | | ---------- | ---------------- | ---------------- | --------- | 608 | | 8 | 22337 | 18241 | -4096 | 609 | | 16 | 30593 | 22369 | -8224 | 610 | | 32 | 47073 | 30625 | -16448 | 611 | | 48 | 63553 | 38881 | -24672 | 612 | 613 | 可以看出,KV Cache 可以节约大约 20% 的显存。 614 | 615 | 同时,还在 [opencompass](https://github.com/open-compass/opencompass) 平台上测试了量化前后的精准度(Accuracy)对比情况,如下表所示。 616 | 617 | | task | dataset | metric | int8 | fp16 | diff | 618 | | ------------- | --------------- | ------------- | ----- | ----- | ----- | 619 | | Language | winogrande | accuracy | 60.77 | 61.48 | -0.71 | 620 | | Knowledge | nq | score | 2.69 | 2.60 | +0.09 | 621 | | Reasoning | gsm8k | accuracy | 33.28 | 34.72 | -1.44 | 622 | | Reasoning | bbh | naive_average | 20.12 | 20.51 | -0.39 | 623 | | Understanding | openbookqa_fact | accuracy | 82.40 | 82.20 | +0.20 | 624 | | Understanding | eprstmt-dev | accuracy | 90.62 | 88.75 | +1.87 | 625 | | Safety | crows_pairs | accuracy | 32.56 | 31.43 | +1.13 | 626 | 627 | 可以看出,精度不仅没有明显下降,相反在不少任务上还有一定的提升。可能得原因是,量化会导致一定的误差,有时候这种误差可能会减少模型对训练数据的拟合,从而提高泛化性能。量化可以被视为引入轻微噪声的正则化方法。或者,也有可能量化后的模型正好对某些数据集具有更好的性能。 628 | 629 | 总结一下,KV Cache 量化既能明显降低显存占用,还有可能同时带来精准度(Accuracy)的提升。 630 | 631 | ### 3.2 W4A16 量化 632 | 633 | #### 3.2.1 量化步骤 634 | 635 | W4A16中的A是指Activation,保持FP16,只对参数进行 4bit 量化。使用过程也可以看作是三步。 636 | 637 | 第一步:同 1.3.1,不再赘述。 638 | 639 | 第二步:量化权重模型。利用第一步得到的统计值对参数进行量化,具体又包括两小步: 640 | 641 | - 缩放参数。主要是性能上的考虑(回顾 PPT)。 642 | - 整体量化。 643 | 644 | 第二步的执行命令如下: 645 | 646 | ```bash 647 | # 量化权重模型 648 | lmdeploy lite auto_awq \ 649 | --model /root/share/temp/model_repos/internlm-chat-7b/ \ 650 | --w_bits 4 \ 651 | --w_group_size 128 \ 652 | --work_dir ./quant_output 653 | ``` 654 | 655 | 命令中 `w_bits` 表示量化的位数,`w_group_size` 表示量化分组统计的尺寸,`work_dir` 是量化后模型输出的位置。这里需要特别说明的是,因为没有 `torch.int4`,所以实际存储时,8个 4bit 权重会被打包到一个 int32 值中。所以,如果你把这部分量化后的参数加载进来就会发现它们是 int32 类型的。 656 | 657 | 最后一步:转换成 TurboMind 格式。 658 | 659 | ```bash 660 | # 转换模型的layout,存放在默认路径 ./workspace 下 661 | lmdeploy convert internlm-chat-7b ./quant_output \ 662 | --model-format awq \ 663 | --group-size 128 664 | ``` 665 | 666 | 这个 `group-size` 就是上一步的那个 `w_group_size`。如果不想和之前的 `workspace` 重复,可以指定输出目录:`--dst_path`,比如: 667 | 668 | ```bash 669 | lmdeploy convert internlm-chat-7b ./quant_output \ 670 | --model-format awq \ 671 | --group-size 128 \ 672 | --dst_path ./workspace_quant 673 | ``` 674 | 675 | 接下来和上一节一样,可以正常运行前面的各种服务了,不过咱们现在用的是量化后的模型。 676 | 677 | 最后再补充一点,量化模型和 KV Cache 量化也可以一起使用,以达到最大限度节省显存。 678 | 679 | #### 3.2.2 量化效果 680 | 681 | 官方在 NVIDIA GeForce RTX 4090 上测试了 4-bit 的 Llama-2-7B-chat 和 Llama-2-13B-chat 模型的 token 生成速度。测试配置为 BatchSize = 1,prompt_tokens=1,completion_tokens=512,结果如下表所示。 682 | 683 | | model | llm-awq | mlc-llm | turbomind | 684 | | ---------------- | ------- | ------- | --------- | 685 | | Llama-2-7B-chat | 112.9 | 159.4 | 206.4 | 686 | | Llama-2-13B-chat | N/A | 90.7 | 115.8 | 687 | 688 | 可以看出,TurboMind 相比其他框架速度优势非常显著,比 mlc-llm 快了将近 30%。 689 | 690 | 另外,也测试了 TurboMind 在不同精度和上下文长度下的显存占用情况,如下表所示。 691 | 692 | | model(context length) | 16bit(2048) | 4bit(2048) | 16bit(4096) | 4bit(4096) | 693 | | --------------------- | ----------- | ---------- | ----------- | ---------- | 694 | | Llama-2-7B-chat | 15.1 | 6.3 | 16.2 | 7.5 | 695 | | Llama-2-13B-chat | OOM | 10.3 | OOM | 12.0 | 696 | 697 | 可以看出,4bit 模型可以降低 50-60% 的显存占用,效果非常明显。 698 | 699 | 总而言之,W4A16 参数量化后能极大地降低显存,同时相比其他框架推理速度具有明显优势。 700 | 701 | ### 3.3 最佳实践 702 | 703 | 本节是针对《模型量化》部分的最佳实践。 704 | 705 | 首先我们需要明白一点,服务部署和量化是没有直接关联的,量化的最主要目的是降低显存占用,主要包括两方面的显存:模型参数和中间过程计算结果。前者对应《3.2 W4A16 量化》,后者对应《3.1 KV Cache 量化》。 706 | 707 | 量化在降低显存的同时,一般还能带来性能的提升,因为更小精度的浮点数要比高精度的浮点数计算效率高,而整型要比浮点数高很多。 708 | 709 | 所以我们的建议是:在各种配置下尝试,看效果能否满足需要。这一般需要在自己的数据集上进行测试。具体步骤如下。 710 | 711 | - Step1:优先尝试正常(非量化)版本,评估效果。 712 | - 如果效果不行,需要尝试更大参数模型或者微调。 713 | - 如果效果可以,跳到下一步。 714 | - Step2:尝试正常版本+KV Cache 量化,评估效果。 715 | - 如果效果不行,回到上一步。 716 | - 如果效果可以,跳到下一步。 717 | - Step3:尝试量化版本,评估效果。 718 | - 如果效果不行,回到上一步。 719 | - 如果效果可以,跳到下一步。 720 | - Step4:尝试量化版本+ KV Cache 量化,评估效果。 721 | - 如果效果不行,回到上一步。 722 | - 如果效果可以,使用方案。 723 | 724 | 简单流程如下图所示。 725 | 726 | ![](img/quant.drawio.png) 727 | 728 | 另外需要补充说明的是,使用哪种量化版本、开启哪些功能,除了上述流程外,**还需要考虑框架、显卡的支持情况**,比如有些框架可能不支持 W4A16 的推理,那即便转换好了也用不了。 729 | 730 | 根据实践经验,一般情况下: 731 | 732 | - 精度越高,显存占用越多,推理效率越低,但一般效果较好。 733 | - Server 端推理一般用非量化版本或半精度、BF16、Int8 等精度的量化版本,比较少使用更低精度的量化版本。 734 | - 端侧推理一般都使用量化版本,且大多是低精度的量化版本。这主要是因为计算资源所限。 735 | 736 | 以上是针对项目开发情况,如果是自己尝试(玩儿)的话: 737 | 738 | - 如果资源足够(有GPU卡很重要),那就用非量化的正常版本。 739 | - 如果没有 GPU 卡,只有 CPU(不管什么芯片),那还是尝试量化版本。 740 | - 如果生成文本长度很长,显存不够,就开启 KV Cache。 741 | 742 | 建议大家根据实际情况灵活选择方案。 743 | 744 | ## 参考资料 745 | 746 | - [InternLM/lmdeploy: LMDeploy is a toolkit for compressing, deploying, and serving LLMs.](https://github.com/InternLM/lmdeploy/) 747 | - [仅需一块 3090 显卡,高效部署 InternLM-20B 模型 - 知乎](https://zhuanlan.zhihu.com/p/665725861) 748 | 749 | ## 附录1:TritonServer 作为推理引擎 750 | 751 | 752 | ### TritonServer环境配置 753 | 754 | > 注意:本部分内容仅支持物理机上执行,不支持虚拟主机。 755 | 756 | 使用 Triton Server 需要安装一下 Docker 及其他依赖。 757 | 758 | 先装一些基本的依赖。 759 | 760 | ```bash 761 | apt-get update 762 | apt-get install cmake sudo -y 763 | ``` 764 | 765 | 然后是 Docker 安装。 766 | 767 | ```bash 768 | # Add Docker's official GPG key: 769 | sudo apt-get install ca-certificates curl gnupg 770 | sudo install -m 0755 -d /etc/apt/keyrings 771 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 772 | sudo chmod a+r /etc/apt/keyrings/docker.gpg 773 | 774 | # Add the repository to Apt sources: 775 | echo \ 776 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ 777 | $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ 778 | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 779 | sudo apt-get update 780 | 781 | # install 782 | sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 783 | ``` 784 | 785 | 安装后我们跑一个 HelloWorld。 786 | 787 | ```bash 788 | # helloworld 789 | sudo docker run hello-world 790 | ``` 791 | 792 | 可以看到类似下面的画面,表示运行成功。 793 | 794 | ![](img/3.png) 795 | 796 | 797 | ### TritonServer推理+API服务 798 | 799 | > 注意:这部分需要 Docker 服务。 800 | 801 | 这里我们把提供模型推理服务的引擎从 TurboMind 换成了 TritonServer,启动命令就一行。 802 | 803 | ```bash 804 | # ApiServer+Triton 805 | bash workspace/service_docker_up.sh 806 | ``` 807 | 808 | 这里会启动一个 TritonServer 的容器,如下图所示。 809 | 810 | ![](img/14.png) 811 | 812 | 可以再开一个窗口执行 Client 命令。 813 | 814 | ```bash 815 | # ChatTritonClient + TritonServer(注意是gRPC协议,不要用http) 816 | lmdeploy serve triton_client localhost:33337 817 | ``` 818 | 819 | 结果如下图所示。 820 | 821 | ![](img/15.png) 822 | 823 | 824 | ### TritonServer 服务作为后端 825 | 826 | 使用过程同 2.4.1 小节。 827 | 828 | ```bash 829 | # Gradio+TritonServer(注意是gRPC协议,不要用http) 830 | lmdeploy serve gradio localhost:33337 \ 831 | --server_name 0.0.0.0 \ 832 | --server_port 6006 833 | ``` 834 | 835 | 结果如下图所示。 836 | 837 | ![](img/18.png) 838 | 839 | ## 作业 840 | 841 | 提交方式:在各个班级对应的 GitHub Discussion 帖子中进行提交。 842 | 843 | **基础作业:** 844 | 845 | - 使用 LMDeploy 以本地对话、网页Gradio、API服务中的一种方式部署 InternLM-Chat-7B 模型,生成 300 字的小故事(需截图) 846 | 847 | **进阶作业(可选做)** 848 | 849 | - 将第四节课训练自我认知小助手模型使用 LMDeploy 量化部署到 OpenXLab 平台。 850 | - 对internlm-chat-7b模型进行量化,并同时使用KV Cache量化,使用量化后的模型完成API服务的部署,分别对比模型量化前后(将 bs设置为 1 和 max len 设置为512)和 KV Cache 量化前后(将 bs设置为 8 和 max len 设置为2048)的显存大小。 851 | - 在自己的任务数据集上任取若干条进行Benchmark测试,测试方向包括: 852 | (1)TurboMind推理+Python代码集成 853 | (2)在(1)的基础上采用W4A16量化 854 | (3)在(1)的基础上开启KV Cache量化 855 | (4)在(2)的基础上开启KV Cache量化 856 | (5)使用Huggingface推理 857 | 858 | 备注:**由于进阶作业较难,完成基础作业之后就可以先提交作业了,在后续的大作业项目中使用这些技术将作为重要的加分点!** 859 | 860 | **整体实训营项目:** 861 | 862 | 时间周期:即日起致课程结束 863 | 864 | 即日开始可以在班级群中随机组队完成一个大作业项目,一些可提供的选题如下: 865 | 866 | - 人情世故大模型:一个帮助用户撰写新年祝福文案的人情事故大模型 867 | - 中小学数学大模型:一个拥有一定数学解题能力的大模型 868 | - 心理大模型:一个治愈的心理大模型 869 | - 工具调用类项目:结合 Lagent 构建数据集训练 InternLM 模型,支持对 MMYOLO 等工具的调用 870 | 871 | 其他基于书生·浦语工具链的小项目都在范围内,欢迎大家充分发挥想象力。 872 | 873 | -------------------------------------------------------------------------------- /opencompass/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/opencompass/.gitkeep -------------------------------------------------------------------------------- /opencompass/opencompass_tutorial.md: -------------------------------------------------------------------------------- 1 | # 大模型评测教程 2 | 3 | 随着人工智能技术的快速发展, 大规模预训练自然语言模型成为了研究热点和关注焦点。OpenAI于2018年提出了第一代GPT模型,开辟了自然语言模型生成式预训练的路线。沿着这条路线,随后又陆续发布了GPT-2和GPT-3模型。与此同时,谷歌也探索了不同的大规模预训练模型方案,例如如T5, Flan等。OpenAI在2022年11月发布ChatGPT,展示了强大的问答能力,逻辑推理能力和内容创作能力,将模型提升到了实用水平,改变人们对大模型能力的认知。在2023年4月,OpenAI发布了新升级的GPT-4模型,通过引入多模态能力,进一步拓展了大语言模型的能力边界,朝着通用人工智能更进一步。ChatGPT和GPT-4推出之后,微软凭借强大的产品化能力迅速将其集成进搜索引擎和Office办公套件中,形成了New Bing和 Office Copilot等产品。谷歌也迅速上线了基于自家大语言模型PaLM和PaLM-2的Bard,与OpenAI和微软展开正面竞争。国内的多家企业和研究机构也在开展大模型的技术研发,百度,阿里,华为,商汤,讯飞等都发布了各自的国产语言大模型,清华,复旦等高校也相继发布了GLM, MOSS等模型。 4 | 5 | 为了准确和公正地评估大模型的能力,国内外机构在大模型评测上开展了大量的尝试和探索。斯坦福大学提出了较为系统的评测框架HELM,从准确性,安全性,鲁棒性和公平性等维度开展模型评测。纽约大学联合谷歌和Meta提出了SuperGLUE评测集,从推理能力,常识理解,问答能力等方面入手,构建了包括8个子任务的大语言模型评测数据集。加州大学伯克利分校提出了MMLU测试集,构建了涵盖高中和大学的多项考试,来评估模型的知识能力和推理能力。谷歌也提出了包含数理科学,编程代码,阅读理解,逻辑推理等子任务的评测集Big-Bench,涵盖200多个子任务,对模型能力进行系统化的评估。在中文评测方面,国内的学术机构也提出了如CLUE,CUGE等评测数据集,从文本分类,阅读理解,逻辑推理等方面评测语言模型的中文能力。 6 | 7 | 随着大模型的蓬勃发展,如何全面系统地评估大模型的各项能力成为了亟待解决的问题。由于大语言模型和多模态模型的能力强大,应用场景广泛,目前学术界和工业界的评测方案往往只关注模型的部分能力维度,缺少系统化的能力维度框架与评测方案。OpenCompass提供设计一套全面、高效、可拓展的大模型评测方案,对模型能力、性能、安全性等进行全方位的评估。OpenCompass提供分布式自动化的评测系统,支持对(语言/多模态)大模型开展全面系统的能力评估。 8 | 9 | 10 | # OpenCompass介绍 11 | 12 | ## 评测对象 13 | 14 | 本算法库的主要评测对象为语言大模型与多模态大模型。我们以语言大模型为例介绍评测的具体模型类型。 15 | 16 | - **基座模型**:一般是经过海量的文本数据以自监督学习的方式进行训练获得的模型(如OpenAI的GPT-3,Meta的LLaMA),往往具有强大的文字续写能力。 17 | 18 | - **对话模型**:一般是在的基座模型的基础上,经过指令微调或人类偏好对齐获得的模型(如OpenAI的ChatGPT、上海人工智能实验室的书生·浦语),能理解人类指令,具有较强的对话能力。 19 | 20 | ## 工具架构 21 | 22 | ![framework-cn](https://github.com/tonysy/opencompass/assets/7881589/374d9cec-2ebc-442a-ab11-191a7d5cf5e9) 23 | 24 | - 模型层:大模型评测所涉及的主要模型种类,OpenCompass以基座模型和对话模型作为重点评测对象。 25 | - 能力层:OpenCompass从本方案从通用能力和特色能力两个方面来进行评测维度设计。在模型通用能力方面,从语言、知识、理解、推理、安全等多个能力维度进行评测。在特色能力方面,从长文本、代码、工具、知识增强等维度进行评测。 26 | - 方法层:OpenCompass采用客观评测与主观评测两种评测方式。客观评测能便捷地评估模型在具有确定答案(如选择,填空,封闭式问答等)的任务上的能力,主观评测能评估用户对模型回复的真实满意度,OpenCompass采用基于模型辅助的主观评测和基于人类反馈的主观评测两种方式。 27 | - 工具层:OpenCompass提供丰富的功能支持自动化地开展大语言模型的高效评测。包括分布式评测技术,提示词工程,对接评测数据库,评测榜单发布,评测报告生成等诸多功能。 28 | 29 | ## 能力维度 30 | 31 | ### 设计思路 32 | 33 | 为准确、全面、系统化地评估大语言模型的能力,OpenCompass从通用人工智能的角度出发,结合学术界的前沿进展和工业界的最佳实践,提出一套面向实际应用的模型能力评价体系。OpenCompass能力维度体系涵盖通用能力和特色能力两大部分。 34 | 35 | 通用能力涵盖学科综合能力、知识能力、语言能力、理解能力、推理能力、安全能力,共计六大维度构造立体全面的模型能力评价体系。 36 | 37 | 特色能力 38 | 39 | ## 评测方法 40 | 41 | OpenCompass采取客观评测与主观评测相结合的方法。针对具有确定性答案的能力维度和场景,通过构造丰富完善的评测集,对模型能力进行综合评价。针对体现模型能力的开放式或半开放式的问题、模型安全问题等,采用主客观相结合的评测方式。 42 | 43 | ### 客观评测 44 | 45 | 针对具有标准答案的客观问题,我们可以我们可以通过使用定量指标比较模型的输出与标准答案的差异,并根据结果衡量模型的性能。同时,由于大语言模型输出自由度较高,在评测阶段,我们需要对其输入和输出作一定的规范和设计,尽可能减少噪声输出在评测阶段的影响,才能对模型的能力有更加完整和客观的评价。 46 | 47 | 为了更好地激发出模型在题目测试领域的能力,并引导模型按照一定的模板输出答案,OpenCompass采用提示词工程 (prompt engineering)和语境学习(in-context learning)进行客观评测。 48 | 49 | 在客观评测的具体实践中,我们通常采用下列两种方式进行模型输出结果的评测: 50 | 51 | - **判别式评测**:该评测方式基于将问题与候选答案组合在一起,计算模型在所有组合上的困惑度(perplexity),并选择困惑度最小的答案作为模型的最终输出。例如,若模型在 `问题? 答案1` 上的困惑度为 0.1,在 `问题? 答案2` 上的困惑度为 0.2,最终我们会选择 `答案1` 作为模型的输出。 52 | 53 | - **生成式评测**:该评测方式主要用于生成类任务,如语言翻译、程序生成、逻辑分析题等。具体实践时,使用问题作为模型的原始输入,并留白答案区域待模型进行后续补全。我们通常还需要对其输出进行后处理,以保证输出满足数据集的要求。 54 | 55 | ### 主观评测 56 | 57 | 语言表达生动精彩,变化丰富,大量的场景和能力无法凭借客观指标进行评测。针对如模型安全和模型语言能力的评测,以人的主观感受为主的评测更能体现模型的真实能力,并更符合大模型的实际使用场景。 58 | 59 | OpenCompass采取的主观评测方案是指借助受试者的主观判断对具有对话能力的大语言模型进行能力评测。在具体实践中,我们提前基于模型的能力维度构建主观测试问题集合,并将不同模型对于同一问题的不同回复展现给受试者,收集受试者基于主观感受的评分。由于主观测试成本高昂,本方案同时也采用使用性能优异的大语言模拟人类进行主观打分。在实际评测中,本文将采用真实人类专家的主观评测与基于模型打分的主观评测相结合的方式开展模型能力评估。 60 | 61 | 在具体开展主观评测时,OpenComapss采用**单模型回复满意度统计**和**多模型满意度比较**两种方式开展具体的评测工作。 62 | 63 | # 快速开始 64 | 65 | ![image](https://github.com/open-compass/opencompass/assets/22607038/d063cae0-3297-4fd2-921a-366e0a24890b) 66 | 67 | ## 概览 68 | 69 | 在 OpenCompass 中评估一个模型通常包括以下几个阶段:**配置** -> **推理** -> **评估** -> **可视化**。 70 | 71 | **配置**:这是整个工作流的起点。您需要配置整个评估过程,选择要评估的模型和数据集。此外,还可以选择评估策略、计算后端等,并定义显示结果的方式。 72 | 73 | **推理与评估**:在这个阶段,OpenCompass 将会开始对模型和数据集进行并行推理和评估。**推理**阶段主要是让模型从数据集产生输出,而**评估**阶段则是衡量这些输出与标准答案的匹配程度。这两个过程会被拆分为多个同时运行的“任务”以提高效率,但请注意,如果计算资源有限,这种策略可能会使评测变得更慢。 74 | 75 | **可视化**:评估完成后,OpenCompass 将结果整理成易读的表格,并将其保存为 CSV 和 TXT 文件。你也可以激活飞书状态上报功能,此后可以在飞书客户端中及时获得评测状态报告。 76 | 77 | 接下来,我们将展示 OpenCompass 的基础用法,展示书生浦语在 [C-Eval](https://cevalbenchmark.com/index.html#home) 基准任务上的评估。它们的配置文件可以在 [configs/eval_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_demo.py) 中找到。 78 | 79 | ## 安装 80 | 81 | ### 面向GPU的环境安装 82 | 83 | ```bash 84 | 85 | conda create --name opencompass --clone=/root/share/conda_envs/internlm-base 86 | source activate opencompass 87 | git clone https://github.com/open-compass/opencompass 88 | cd opencompass 89 | pip install -e . 90 | ``` 91 | 92 | 有部分第三方功能,如代码能力基准测试 Humaneval 以及 Llama格式的模型评测,可能需要额外步骤才能正常运行,如需评测,详细步骤请参考[安装指南](https://opencompass.readthedocs.io/zh_CN/latest/get_started/installation.html)。 93 | 94 | ### 数据准备 95 | 96 | ```bash 97 | # 解压评测数据集到 data/ 处 98 | cp /share/temp/datasets/OpenCompassData-core-20231110.zip /root/opencompass/ 99 | unzip OpenCompassData-core-20231110.zip 100 | 101 | # 将会在opencompass下看到data文件夹 102 | ``` 103 | 104 | ### 查看支持的数据集和模型 105 | 106 | ```bash 107 | # 列出所有跟 internlm 及 ceval 相关的配置 108 | python tools/list_configs.py internlm ceval 109 | ``` 110 | 111 | 将会看到 112 | 113 | ```text 114 | +--------------------------+--------------------------------------------------------+ 115 | | Model | Config Path | 116 | |--------------------------+--------------------------------------------------------| 117 | | hf_internlm_20b | configs/models/hf_internlm/hf_internlm_20b.py | 118 | | hf_internlm_7b | configs/models/hf_internlm/hf_internlm_7b.py | 119 | | hf_internlm_chat_20b | configs/models/hf_internlm/hf_internlm_chat_20b.py | 120 | | hf_internlm_chat_7b | configs/models/hf_internlm/hf_internlm_chat_7b.py | 121 | | hf_internlm_chat_7b_8k | configs/models/hf_internlm/hf_internlm_chat_7b_8k.py | 122 | | hf_internlm_chat_7b_v1_1 | configs/models/hf_internlm/hf_internlm_chat_7b_v1_1.py | 123 | | internlm_7b | configs/models/internlm/internlm_7b.py | 124 | | ms_internlm_chat_7b_8k | configs/models/ms_internlm/ms_internlm_chat_7b_8k.py | 125 | +--------------------------+--------------------------------------------------------+ 126 | +----------------------------+------------------------------------------------------+ 127 | | Dataset | Config Path | 128 | |----------------------------+------------------------------------------------------| 129 | | ceval_clean_ppl | configs/datasets/ceval/ceval_clean_ppl.py | 130 | | ceval_gen | configs/datasets/ceval/ceval_gen.py | 131 | | ceval_gen_2daf24 | configs/datasets/ceval/ceval_gen_2daf24.py | 132 | | ceval_gen_5f30c7 | configs/datasets/ceval/ceval_gen_5f30c7.py | 133 | | ceval_ppl | configs/datasets/ceval/ceval_ppl.py | 134 | | ceval_ppl_578f8d | configs/datasets/ceval/ceval_ppl_578f8d.py | 135 | | ceval_ppl_93e5ce | configs/datasets/ceval/ceval_ppl_93e5ce.py | 136 | | ceval_zero_shot_gen_bd40ef | configs/datasets/ceval/ceval_zero_shot_gen_bd40ef.py | 137 | +----------------------------+------------------------------------------------------+ 138 | ``` 139 | 140 | 141 | ### 启动评测 142 | 143 | 确保按照上述步骤正确安装 OpenCompass 并准备好数据集后,可以通过以下命令评测 InternLM-Chat-7B 模型在 C-Eval 数据集上的性能。由于 OpenCompass 默认并行启动评估过程,我们可以在第一次运行时以 `--debug` 模式启动评估,并检查是否存在问题。在 `--debug` 模式下,任务将按顺序执行,并实时打印输出。 144 | 145 | ```bash 146 | python run.py --datasets ceval_gen --hf-path /share/temp/model_repos/internlm-chat-7b/ --tokenizer-path /share/temp/model_repos/internlm-chat-7b/ --tokenizer-kwargs padding_side='left' truncation='left' trust_remote_code=True --model-kwargs trust_remote_code=True device_map='auto' --max-seq-len 2048 --max-out-len 16 --batch-size 4 --num-gpus 1 --debug 147 | ``` 148 | 149 | 命令解析 150 | ```bash 151 | --datasets ceval_gen \ 152 | --hf-path /share/temp/model_repos/internlm-chat-7b/ \ # HuggingFace 模型路径 153 | --tokenizer-path /share/temp/model_repos/internlm-chat-7b/ \ # HuggingFace tokenizer 路径(如果与模型路径相同,可以省略) 154 | --tokenizer-kwargs padding_side='left' truncation='left' trust_remote_code=True \ # 构建 tokenizer 的参数 155 | --model-kwargs device_map='auto' trust_remote_code=True \ # 构建模型的参数 156 | --max-seq-len 2048 \ # 模型可以接受的最大序列长度 157 | --max-out-len 16 \ # 生成的最大 token 数 158 | --batch-size 2 \ # 批量大小 159 | --num-gpus 1 # 运行模型所需的 GPU 数量 160 | --debug 161 | ``` 162 | 163 | 如果一切正常,您应该看到屏幕上显示 “Starting inference process”: 164 | 165 | ```bash 166 | [2024-01-12 18:23:55,076] [opencompass.openicl.icl_inferencer.icl_gen_inferencer] [INFO] Starting inference process... 167 | ``` 168 | 169 | 评测完成后,将会看到: 170 | ``` 171 | 172 | dataset version metric mode opencompass.models.huggingface.HuggingFace_model_repos_internlm-chat-7b 173 | ---------------------------------------------- --------- ------------- ------ ------------------------------------------------------------------------- 174 | ceval-computer_network db9ce2 accuracy gen 31.58 175 | ceval-operating_system 1c2571 accuracy gen 36.84 176 | ceval-computer_architecture a74dad accuracy gen 28.57 177 | ceval-college_programming 4ca32a accuracy gen 32.43 178 | ceval-college_physics 963fa8 accuracy gen 26.32 179 | ceval-college_chemistry e78857 accuracy gen 16.67 180 | ceval-advanced_mathematics ce03e2 accuracy gen 21.05 181 | ceval-probability_and_statistics 65e812 accuracy gen 38.89 182 | ceval-discrete_mathematics e894ae accuracy gen 18.75 183 | ceval-electrical_engineer ae42b9 accuracy gen 35.14 184 | ceval-metrology_engineer ee34ea accuracy gen 50 185 | ceval-high_school_mathematics 1dc5bf accuracy gen 22.22 186 | ceval-high_school_physics adf25f accuracy gen 31.58 187 | ceval-high_school_chemistry 2ed27f accuracy gen 15.79 188 | ceval-high_school_biology 8e2b9a accuracy gen 36.84 189 | ceval-middle_school_mathematics bee8d5 accuracy gen 26.32 190 | ceval-middle_school_biology 86817c accuracy gen 61.9 191 | ceval-middle_school_physics 8accf6 accuracy gen 63.16 192 | ceval-middle_school_chemistry 167a15 accuracy gen 60 193 | ceval-veterinary_medicine b4e08d accuracy gen 47.83 194 | ceval-college_economics f3f4e6 accuracy gen 41.82 195 | ceval-business_administration c1614e accuracy gen 33.33 196 | ceval-marxism cf874c accuracy gen 68.42 197 | ceval-mao_zedong_thought 51c7a4 accuracy gen 70.83 198 | ceval-education_science 591fee accuracy gen 58.62 199 | ceval-teacher_qualification 4e4ced accuracy gen 70.45 200 | ceval-high_school_politics 5c0de2 accuracy gen 26.32 201 | ceval-high_school_geography 865461 accuracy gen 47.37 202 | ceval-middle_school_politics 5be3e7 accuracy gen 52.38 203 | ceval-middle_school_geography 8a63be accuracy gen 58.33 204 | ceval-modern_chinese_history fc01af accuracy gen 73.91 205 | ceval-ideological_and_moral_cultivation a2aa4a accuracy gen 63.16 206 | ceval-logic f5b022 accuracy gen 31.82 207 | ceval-law a110a1 accuracy gen 25 208 | ceval-chinese_language_and_literature 0f8b68 accuracy gen 30.43 209 | ceval-art_studies 2a1300 accuracy gen 60.61 210 | ceval-professional_tour_guide 4e673e accuracy gen 62.07 211 | ceval-legal_professional ce8787 accuracy gen 39.13 212 | ceval-high_school_chinese 315705 accuracy gen 63.16 213 | ceval-high_school_history 7eb30a accuracy gen 70 214 | ceval-middle_school_history 48ab4a accuracy gen 59.09 215 | ceval-civil_servant 87d061 accuracy gen 53.19 216 | ceval-sports_science 70f27b accuracy gen 52.63 217 | ceval-plant_protection 8941f9 accuracy gen 59.09 218 | ceval-basic_medicine c409d6 accuracy gen 47.37 219 | ceval-clinical_medicine 49e82d accuracy gen 40.91 220 | ceval-urban_and_rural_planner 95b885 accuracy gen 45.65 221 | ceval-accountant 002837 accuracy gen 26.53 222 | ceval-fire_engineer bc23f5 accuracy gen 22.58 223 | ceval-environmental_impact_assessment_engineer c64e2d accuracy gen 64.52 224 | ceval-tax_accountant 3a5e3c accuracy gen 34.69 225 | ceval-physician 6e277d accuracy gen 40.82 226 | ceval-stem - naive_average gen 35.09 227 | ceval-social-science - naive_average gen 52.79 228 | ceval-humanities - naive_average gen 52.58 229 | ceval-other - naive_average gen 44.36 230 | ceval-hard - naive_average gen 23.91 231 | ceval - naive_average gen 44.16 232 | ``` 233 | 234 | 有关 `run.py` 支持的所有与 HuggingFace 相关的参数,请阅读 [评测任务发起](https://opencompass.readthedocs.io/zh-cn/latest/user_guides/experimentation.html#id2) 235 | 236 | 237 | 除了通过命令行配置实验外,OpenCompass 还允许用户在配置文件中编写实验的完整配置,并通过 `run.py` 直接运行它。配置文件是以 Python 格式组织的,并且必须包括 `datasets` 和 `models` 字段。 238 | 239 | 示例测试配置在 [configs/eval_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_demo.py) 中。此配置通过 [继承机制](../user_guides/config.md#继承机制) 引入所需的数据集和模型配置,并以所需格式组合 `datasets` 和 `models` 字段。 240 | 241 | ```python 242 | from mmengine.config import read_base 243 | 244 | with read_base(): 245 | from .datasets.siqa.siqa_gen import siqa_datasets 246 | from .datasets.winograd.winograd_ppl import winograd_datasets 247 | from .models.opt.hf_opt_125m import opt125m 248 | from .models.opt.hf_opt_350m import opt350m 249 | 250 | datasets = [*siqa_datasets, *winograd_datasets] 251 | models = [opt125m, opt350m] 252 | ``` 253 | 254 | 运行任务时,我们只需将配置文件的路径传递给 `run.py`: 255 | 256 | ```bash 257 | python run.py configs/eval_demo.py 258 | ``` 259 | 260 | 261 | OpenCompass 提供了一系列预定义的模型配置,位于 `configs/models` 下。以下是与 [opt-350m](https://github.com/open-compass/opencompass/blob/main/configs/models/opt/hf_opt_350m.py)(`configs/models/opt/hf_opt_350m.py`)相关的配置片段: 262 | 263 | ```python 264 | # 使用 `HuggingFaceCausalLM` 评估由 HuggingFace 的 `AutoModelForCausalLM` 支持的模型 265 | from opencompass.models import HuggingFaceCausalLM 266 | 267 | # OPT-350M 268 | opt350m = dict( 269 | type=HuggingFaceCausalLM, 270 | # `HuggingFaceCausalLM` 的初始化参数 271 | path='facebook/opt-350m', 272 | tokenizer_path='facebook/opt-350m', 273 | tokenizer_kwargs=dict( 274 | padding_side='left', 275 | truncation_side='left', 276 | proxies=None, 277 | trust_remote_code=True), 278 | model_kwargs=dict(device_map='auto'), 279 | # 下面是所有模型的共同参数,不特定于 HuggingFaceCausalLM 280 | abbr='opt350m', # 结果显示的模型缩写 281 | max_seq_len=2048, # 整个序列的最大长度 282 | max_out_len=100, # 生成的最大 token 数 283 | batch_size=64, # 批量大小 284 | run_cfg=dict(num_gpus=1), # 该模型所需的 GPU 数量 285 | ) 286 | ``` 287 | 288 | 使用配置时,我们可以通过命令行参数 `--models` 指定相关文件,或使用继承机制将模型配置导入到配置文件中的 `models` 列表中。 289 | 290 | 291 | 与模型类似,数据集的配置文件也提供在 `configs/datasets` 下。用户可以在命令行中使用 `--datasets`,或通过继承在配置文件中导入相关配置 292 | 293 | 下面是来自 `configs/eval_demo.py` 的与数据集相关的配置片段: 294 | 295 | ```python 296 | from mmengine.config import read_base # 使用 mmengine.read_base() 读取基本配置 297 | 298 | with read_base(): 299 | # 直接从预设的数据集配置中读取所需的数据集配置 300 | from .datasets.winograd.winograd_ppl import winograd_datasets # 读取 Winograd 配置,基于 PPL(困惑度)进行评估 301 | from .datasets.siqa.siqa_gen import siqa_datasets # 读取 SIQA 配置,基于生成进行评估 302 | 303 | datasets = [*siqa_datasets, *winograd_datasets] # 最终的配置需要包含所需的评估数据集列表 'datasets' 304 | ``` 305 | 306 | 数据集配置通常有两种类型:'ppl' 和 'gen',分别指示使用的评估方法。其中 `ppl` 表示辨别性评估,`gen` 表示生成性评估。 307 | 308 | 此外,[configs/datasets/collections](https://github.com/open-compass/opencompass/blob/main/configs/datasets/collections) 收录了各种数据集集合,方便进行综合评估。OpenCompass 通常使用 [`base_medium.py`](https://github.com/open-compass/opencompass/blob/main/configs/datasets/collections/base_medium.py) 进行全面的模型测试。要复制结果,只需导入该文件,例如: 309 | 310 | ```bash 311 | python run.py --models hf_llama_7b --datasets base_medium 312 | ``` 313 | 314 | OpenCompass 通常假定运行环境网络是可用的。如果您遇到网络问题或希望在离线环境中运行 OpenCompass,请参阅 [FAQ - 网络 - Q1](https://opencompass.readthedocs.io/zh-cn/latest/get_started/faq.html) 寻求解决方案。 315 | 316 | 317 | ## 可视化评估结果 318 | 319 | 评估完成后,评估结果表格将打印如下: 320 | 321 | ```text 322 | dataset version metric mode opt350m opt125m 323 | --------- --------- -------- ------ --------- --------- 324 | siqa e78df3 accuracy gen 21.55 12.44 325 | winograd b6c7ed accuracy ppl 51.23 49.82 326 | ``` 327 | 328 | 所有运行输出将定向到 `outputs/demo/` 目录,结构如下: 329 | 330 | ```text 331 | outputs/default/ 332 | ├── 20200220_120000 333 | ├── 20230220_183030 # 每个实验一个文件夹 334 | │ ├── configs # 用于记录的已转储的配置文件。如果在同一个实验文件夹中重新运行了不同的实验,可能会保留多个配置 335 | │ ├── logs # 推理和评估阶段的日志文件 336 | │ │ ├── eval 337 | │ │ └── infer 338 | │ ├── predictions # 每个任务的推理结果 339 | │ ├── results # 每个任务的评估结果 340 | │ └── summary # 单个实验的汇总评估结果 341 | ├── ... 342 | ``` 343 | 344 | 打印评测结果的过程可被进一步定制化,用于输出一些数据集的平均分 (例如 MMLU, C-Eval 等)。 345 | 346 | 关于评测结果输出的更多介绍可阅读 [结果展示](../user_guides/summarizer.md)。 347 | 348 | ## 更多教程 349 | 350 | 想要更多了解 OpenCompass, 可以点击下列链接学习。 351 | - https://opencompass.readthedocs.io/zh-cn/latest/ 352 | 353 | 354 | ## 作业 355 | 356 | **基础作业** 357 | 358 | - 使用 OpenCompass 评测 InternLM2-Chat-7B 模型在 C-Eval 数据集上的性能 359 | 360 | **进阶作业** 361 | 362 | - 使用 OpenCompass 评测 InternLM2-Chat-7B 模型使用 LMDeploy 0.2.0 部署后在 C-Eval 数据集上的性能 363 | 364 | 365 | 备注:**由于进阶作业较难,完成基础作业之后就可以先提交作业了,在后续的大作业项目中使用这些技术将作为重要的加分点!** 366 | 367 | **整体实训营项目:** 368 | 369 | 时间周期:即日起致课程结束 370 | 371 | 即日开始可以在班级群中随机组队完成一个大作业项目,一些可提供的选题如下: 372 | 373 | - 人情世故大模型:一个帮助用户撰写新年祝福文案的人情事故大模型 374 | - 中小学数学大模型:一个拥有一定数学解题能力的大模型 375 | - 心理大模型:一个治愈的心理大模型 376 | - 工具调用类项目:结合 Lagent 构建数据集训练 InternLM 模型,支持对 MMYOLO 等工具的调用 377 | 378 | 其他基于书生·浦语工具链的小项目都在范围内,欢迎大家充分发挥想象力。 379 | 380 | -------------------------------------------------------------------------------- /projects/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": [ 3 | { 4 | "name": "全部", 5 | "tag": "all" 6 | }, 7 | { 8 | "name": "明星项目", 9 | "tag": "star" 10 | }, 11 | { 12 | "name": "角色扮演", 13 | "tag": "role" 14 | }, 15 | { 16 | "name": "智能体", 17 | "tag": "agent" 18 | }, 19 | { 20 | "name": "知识库", 21 | "tag": "repository" 22 | }, 23 | { 24 | "name": "其他", 25 | "tag": "other" 26 | } 27 | ], 28 | "data": [ 29 | { 30 | "title": "AMchat 高等数学大模型", 31 | "tags": [ 32 | "other" 33 | ], 34 | "github": "https://github.com/AXYZdong/AMchat", 35 | "model": "https://openxlab.org.cn/models/detail/youngdon/AMchat", 36 | "app": "https://openxlab.org.cn/apps/detail/youngdon/AMchat", 37 | "bilibili": "https://www.bilibili.com/video/BV14v421i7So/" 38 | }, 39 | { 40 | "title": "EmoLLM 心理健康大模型", 41 | "tags": [ 42 | "other", 43 | "role", 44 | "repository" 45 | ], 46 | "github": "https://github.com/SmartFlowAI/EmoLLM", 47 | "model": "https://openxlab.org.cn/models/detail/ajupyter/EmoLLM_aiwei", 48 | "app": "https://openxlab.org.cn/apps/detail/ajupyter/EmoLLM-aiwei", 49 | "bilibili": "https://www.bilibili.com/video/BV1Sw4m1Z7GC/" 50 | }, 51 | { 52 | "title": "张三普法:民法典大模型", 53 | "tags": [ 54 | "other" 55 | ], 56 | "github": "https://github.com/AllYoung/InternLM4Law", 57 | "model": "https://openxlab.org.cn/models/detail/ljnyyds/zhangsan_say_law", 58 | "app": "https://openxlab.org.cn/apps/detail/allyoung/InternLM4Law", 59 | "bilibili": "https://www.bilibili.com/video/BV1ru4m1K7rY" 60 | }, 61 | { 62 | "title": "职场教练", 63 | "tags": [ 64 | "other" 65 | ], 66 | "github": "https://github.com/BaiYu96/career_coach", 67 | "model": "https://www.modelscope.cn/models/baiyu96/career_coach/summary", 68 | "app": "https://openxlab.org.cn/apps/detail/baiyu/career_caoch", 69 | "bilibili": "https://www.bilibili.com/video/BV1vJ4m1Y7D9/" 70 | }, 71 | { 72 | "title": "中医药知识问答助手", 73 | "tags": [ 74 | "other" 75 | ], 76 | "github": "https://github.com/xiaomile/ChineseMedicalAssistant", 77 | "model": "https://openxlab.org.cn/models/detail/xiaomile/ChineseMedicalAssistant_internlm", 78 | "app": "https://openxlab.org.cn/apps/detail/xiaomile/medKnowledgeAssitant", 79 | "bilibili": "https://www.bilibili.com/video/BV1J2421A7Mb/" 80 | }, 81 | { 82 | "title": "Chat嬛嬛", 83 | "tags": [ 84 | "role" 85 | ], 86 | "github": "https://github.com/KMnO4-zx/xlab-huanhuan.git", 87 | "model": "https://openxlab.org.cn/models/detail/BYCJS/huanhuan-chat-internlm2", 88 | "app": "https://openxlab.org.cn/apps/detail/BYCJS/Chat_huanhuan", 89 | "bilibili": "https://www.bilibili.com/video/BV1Xa4y1k7yr" 90 | }, 91 | { 92 | "title": "眼科问诊大模型", 93 | "tags": [ 94 | "star", 95 | "agent" 96 | ], 97 | "github": "https://github.com/JieGenius/OculiChatDA", 98 | "model": "https://openxlab.org.cn/models/detail/flyer/OculiChatDA", 99 | "app": "https://openxlab.org.cn/apps/detail/flyer/oculi_chat_diagnosis_assistant", 100 | "bilibili": "https://www.bilibili.com/video/BV1UH4y1Y76q/" 101 | }, 102 | { 103 | "title": "SoulStar(心理咨询大模型)", 104 | "tags": [ 105 | "role" 106 | ], 107 | "github": "https://github.com/Nobody-ML/SoulStar", 108 | "model": "https://openxlab.org.cn/models/detail/Nobody-ML/SoulStar", 109 | "app": "https://openxlab.org.cn/apps/detail/Nobody-ML/SoulStar", 110 | "bilibili": "https://www.bilibili.com/video/BV1hu4m1w7vX/" 111 | }, 112 | { 113 | "title": "第二人生", 114 | "tags": [ 115 | "repository", 116 | "other" 117 | ], 118 | "github": "https://github.com/woxinyonghen/SecondLife", 119 | "model": "https://openxlab.org.cn/models/detail/%E6%98%9F%E8%BE%B0/The_History", 120 | "app": "https://openxlab.org.cn/apps/detail/%E6%98%9F%E8%BE%B0/Second_Life", 121 | "bilibili": "https://www.bilibili.com/video/BV1rp421o736/" 122 | }, 123 | { 124 | "title": "Roleplay-with-XiYou 西游角色扮演", 125 | "tags": [ 126 | "role" 127 | ], 128 | "github": "https://github.com/JimmyMa99/Roleplay-with-XiYou", 129 | "model": "https://openxlab.org.cn/models/detail/JimmyMa99/BaJie-Chat-1.8b", 130 | "app": "https://openxlab.org.cn/apps/detail/JimmyMa99/BaJie-Chat-mini", 131 | "bilibili": "https://www.bilibili.com/video/BV1TW421w7Ze/" 132 | }, 133 | { 134 | "title": "Chatty-Horo 与赫萝闲聊", 135 | "tags": [ 136 | "role" 137 | ], 138 | "github": "https://github.com/SaaRaaS-1300/InternLM_openNotebook", 139 | "model": "https://openxlab.org.cn/models/detail/SaaRaaS/Horowag_7b", 140 | "app": "https://openxlab.org.cn/apps/detail/SaaRaaS/Chatty-Horo", 141 | "bilibili": "https://www.bilibili.com/video/BV1bH4y1E7o9/" 142 | }, 143 | { 144 | "title": "TRLLM 交规小助手", 145 | "tags": [ 146 | "repository", 147 | "other" 148 | ], 149 | "github": "https://github.com/lindsey-chang/TRLLM-Traffic-Rules-Assistant", 150 | "model": "https://modelscope.cn/models/LindseyChang/TRLLM-Model-v2/summary", 151 | "app": "https://openxlab.org.cn/apps/detail/tackhwa00/TRLLM-v2-Traffic-Assistant", 152 | "bilibili": "https://www.bilibili.com/video/BV1r7421N7Jb/" 153 | 154 | }, 155 | { 156 | "title": "MagicTuner 魔法调音师", 157 | "tags": [ 158 | "other" 159 | ], 160 | "github": "https://github.com/scchy/XtunerGUI", 161 | "app": "https://openxlab.org.cn/apps/detail/Scchy/XtunerFactory", 162 | "bilibili": "https://www.bilibili.com/video/BV18y421h7rK/?vd_source=99818a3df596c69ba400b78354d691da" 163 | }, 164 | { 165 | "title": "XTuner Chat Board", 166 | "tags": [ 167 | "other" 168 | ], 169 | "github": "https://github.com/limafang/Xtuner-GUI", 170 | "app": "https://openxlab.org.cn/apps/detail/%E5%86%AC%E7%AC%A0Azula/XTuner-Chat-GUI", 171 | "bilibili": "https://www.bilibili.com/video/BV1rU421o7xD" 172 | }, 173 | { 174 | "title": "The-God-Of-Cookery 食神-菜谱小助手", 175 | "tags": [ 176 | "other" 177 | ], 178 | "github": "https://github.com/SmartFlowAI/TheGodOfCookery", 179 | "model": "https://www.modelscope.cn/models/zhanghuiATchina/zhangxiaobai_shishen2_full/summary", 180 | "app": "https://openxlab.org.cn/apps/detail/zhanghui-china/shishen2024_1.8b", 181 | "bilibili": "https://www.bilibili.com/video/BV1kr421W7iA/" 182 | }, 183 | { 184 | "title": "Tianji 天机", 185 | "tags": [ 186 | "other" 187 | ], 188 | "github": "https://github.com/SocialAI-tianji/Tianji", 189 | "model": "https://openxlab.org.cn/models/detail/jujimeizuo/Tianji_Wish_Model", 190 | "app": "https://openxlab.org.cn/apps/detail/jujimeizuo/tianji-wish", 191 | "bilibili": "https://www.bilibili.com/video/BV1cC411r7s4/" 192 | } 193 | ] 194 | } 195 | -------------------------------------------------------------------------------- /xtuner/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/.gitkeep -------------------------------------------------------------------------------- /xtuner/MedQA2019.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/MedQA2019.xlsx -------------------------------------------------------------------------------- /xtuner/README.md: -------------------------------------------------------------------------------- 1 | ![m3qx](imgs/head2.png) 2 | 3 | > 怎么说呢,祝大家炼丹愉快吧~ 😙 4 | 5 | ## 1 概述 6 | 7 | ### 1.1 XTuner 8 | 9 | 一个大语言模型微调工具箱。*由* *MMRazor* *和* *MMDeploy* *联合开发。* 10 | 11 | ### 1.2 支持的开源LLM (2023.11.01) 12 | 13 | - **[InternLM](https://huggingface.co/internlm/internlm-7b)** ✅ 14 | - [Llama,Llama2](https://huggingface.co/meta-llama) 15 | - [ChatGLM2](https://huggingface.co/THUDM/chatglm2-6b),[ChatGLM3](https://huggingface.co/THUDM/chatglm3-6b-base) 16 | - [Qwen](https://huggingface.co/Qwen/Qwen-7B) 17 | - [Baichuan](https://huggingface.co/baichuan-inc/Baichuan-7B),[Baichuan2](https://huggingface.co/baichuan-inc/Baichuan2-7B-Base) 18 | - ...... 19 | - [Zephyr](https://huggingface.co/HuggingFaceH4/zephyr-7b-beta) 20 | 21 | ### 1.3 特色 22 | 23 | - 🤓 **傻瓜化:** 以 配置文件 的形式封装了大部分微调场景,**0基础的非专业人员也能一键开始微调**。 24 | - 🍃 **轻量级:** 对于 7B 参数量的LLM,**微调所需的最小显存仅为 8GB** : **消费级显卡✅,colab✅** 25 | 26 | ### 1.4 微调原理 27 | 28 | > 想象一下,你有一个超大的玩具,现在你想改造这个超大的玩具。但是,**对整个玩具进行全面的改动会非常昂贵**。 29 | 30 | ※ 因此,你找到了一种叫 **LoRA** 的方法:**只对玩具中的某些零件进行改动,而不是对整个玩具进行全面改动**。 31 | 32 | ※ 而 **QLoRA** 是 LoRA 的一种改进:如果你手里只有一把生锈的螺丝刀,也能改造你的玩具。 33 | 34 | - **Full** : 😳 → 🚲 35 | - **[LoRA](http://arxiv.org/abs/2106.09685)** : 😳 → 🛵 36 | - **[QLoRA](http://arxiv.org/abs/2305.14314)** : 😳 → 🏍 37 | 38 | ![WOZJXUtaKlEk9S4.png](imgs/cat_fly.png) 39 | 40 | 41 | ## 2 快速上手 42 | 43 | ### 2.1 平台 44 | 45 | Ubuntu + Anaconda + CUDA/CUDNN + 8GB nvidia显卡 46 | 47 | ### 2.2 安装 48 | 49 | ```bash 50 | # 如果你是在 InternStudio 平台,则从本地 clone 一个已有 pytorch 2.0.1 的环境: 51 | /root/share/install_conda_env_internlm_base.sh xtuner0.1.9 52 | # 如果你是在其他平台: 53 | conda create --name xtuner0.1.9 python=3.10 -y 54 | 55 | # 激活环境 56 | conda activate xtuner0.1.9 57 | # 进入家目录 (~的意思是 “当前用户的home路径”) 58 | cd ~ 59 | # 创建版本文件夹并进入,以跟随本教程 60 | mkdir xtuner019 && cd xtuner019 61 | 62 | 63 | # 拉取 0.1.9 的版本源码 64 | git clone -b v0.1.9 https://github.com/InternLM/xtuner 65 | # 无法访问github的用户请从 gitee 拉取: 66 | # git clone -b v0.1.9 https://gitee.com/Internlm/xtuner 67 | 68 | # 进入源码目录 69 | cd xtuner 70 | 71 | # 从源码安装 XTuner 72 | pip install -e '.[all]' 73 | ``` 74 | 75 | 安装完后,就开始搞搞准备工作了。(准备在 oasst1 数据集上微调 internlm-7b-chat) 76 | 77 | ```bash 78 | # 创建一个微调 oasst1 数据集的工作路径,进入 79 | mkdir ~/ft-oasst1 && cd ~/ft-oasst1 80 | ``` 81 | 82 | ### 2.3 微调 83 | 84 | #### 2.3.1 准备配置文件 85 | 86 | XTuner 提供多个开箱即用的配置文件,用户可以通过下列命令查看: 87 | 88 | ```Bash 89 | # 列出所有内置配置 90 | xtuner list-cfg 91 | ``` 92 | > 假如显示bash: xtuner: command not found的话可以考虑在终端输入 export PATH=$PATH:'/root/.local/bin' 93 | 94 | ![QCgmlv1VpU3fZPk.png](imgs/cfgs.png) 95 | 96 | 拷贝一个配置文件到当前目录: 97 | `# xtuner copy-cfg ${CONFIG_NAME} ${SAVE_PATH}` 98 | 99 | 在本案例中即:(注意最后有个英文句号,代表复制到当前路径) 100 | ```Bash 101 | cd ~/ft-oasst1 102 | xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 . 103 | ``` 104 | 105 | 配置文件名的解释: 106 | 107 | > xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 . 108 | 109 | | 模型名 | internlm_chat_7b | 110 | | -------- | ---------------- | 111 | | 使用算法 | qlora | 112 | | 数据集 | oasst1 | 113 | | 把数据集跑几次 | 跑3次:e3 (epoch 3 ) | 114 | 115 | *无 chat比如 `internlm-7b` 代表是基座(base)模型 116 | 117 | 118 | #### 2.3.2 模型下载 119 | 120 | > 由于下载模型很慢,用教学平台的同学可以直接复制模型。 121 | 122 | ```Bash 123 | ln -s /share/temp/model_repos/internlm-chat-7b ~/ft-oasst1/ 124 | ``` 125 | 以上是通过软链的方式,将模型文件挂载到家目录下,优势是: 126 | 1. 节省拷贝时间,无需等待 127 | 2. 节省用户开发机存储空间 128 | > 当然,也可以用 `cp -r /share/temp/model_repos/internlm-chat-7b ~/ft-oasst1/` 进行数据拷贝。 129 | 130 | > 以下是自己下载模型的步骤。 131 | 132 | 不用 xtuner 默认的`从 huggingface 拉取模型`,而是提前从 ~~OpenXLab~~ ModelScope 下载模型到本地 133 | 134 | ```Bash 135 | # 创建一个目录,放模型文件,防止散落一地 136 | mkdir ~/ft-oasst1/internlm-chat-7b 137 | 138 | # 装一下拉取模型文件要用的库 139 | pip install modelscope 140 | 141 | # 从 modelscope 下载下载模型文件 142 | cd ~/ft-oasst1 143 | apt install git git-lfs -y 144 | git lfs install 145 | git lfs clone https://modelscope.cn/Shanghai_AI_Laboratory/internlm-chat-7b.git -b v1.0.3 146 | ``` 147 | 148 | #### 2.3.3 数据集下载 149 | > https://huggingface.co/datasets/timdettmers/openassistant-guanaco/tree/main 150 | 151 | 由于 huggingface 网络问题,咱们已经给大家提前下载好了,复制到正确位置即可: 152 | 153 | ```bash 154 | cd ~/ft-oasst1 155 | # ...-guanaco 后面有个空格和英文句号啊 156 | cp -r /root/share/temp/datasets/openassistant-guanaco . 157 | ``` 158 | 159 | 此时,当前路径的文件应该长这样: 160 | 161 | ```bash 162 | |-- internlm-chat-7b 163 | | |-- README.md 164 | | |-- config.json 165 | | |-- configuration.json 166 | | |-- configuration_internlm.py 167 | | |-- generation_config.json 168 | | |-- modeling_internlm.py 169 | | |-- pytorch_model-00001-of-00008.bin 170 | | |-- pytorch_model-00002-of-00008.bin 171 | | |-- pytorch_model-00003-of-00008.bin 172 | | |-- pytorch_model-00004-of-00008.bin 173 | | |-- pytorch_model-00005-of-00008.bin 174 | | |-- pytorch_model-00006-of-00008.bin 175 | | |-- pytorch_model-00007-of-00008.bin 176 | | |-- pytorch_model-00008-of-00008.bin 177 | | |-- pytorch_model.bin.index.json 178 | | |-- special_tokens_map.json 179 | | |-- tokenization_internlm.py 180 | | |-- tokenizer.model 181 | | `-- tokenizer_config.json 182 | |-- internlm_chat_7b_qlora_oasst1_e3_copy.py 183 | `-- openassistant-guanaco 184 | |-- openassistant_best_replies_eval.jsonl 185 | `-- openassistant_best_replies_train.jsonl 186 | ``` 187 | 188 | #### 2.3.4 修改配置文件 189 | 190 | 修改其中的模型和数据集为 本地路径 191 | 192 | ```bash 193 | cd ~/ft-oasst1 194 | vim internlm_chat_7b_qlora_oasst1_e3_copy.py 195 | ``` 196 | > 在vim界面完成修改后,请输入:wq退出。假如认为改错了可以用:q!退出且不保存。当然我们也可以考虑打开python文件直接修改,但注意修改完后需要按下Ctrl+S进行保存。 197 | 198 | 减号代表要删除的行,加号代表要增加的行。 199 | ```diff 200 | # 修改模型为本地路径 201 | - pretrained_model_name_or_path = 'internlm/internlm-chat-7b' 202 | + pretrained_model_name_or_path = './internlm-chat-7b' 203 | 204 | # 修改训练数据集为本地路径 205 | - data_path = 'timdettmers/openassistant-guanaco' 206 | + data_path = './openassistant-guanaco' 207 | ``` 208 | 209 | **常用超参** 210 | 211 | | 参数名 | 解释 | 212 | | ------------------- | ------------------------------------------------------ | 213 | | **data_path** | 数据路径或 HuggingFace 仓库名 | 214 | | max_length | 单条数据最大 Token 数,超过则截断 | 215 | | pack_to_max_length | 是否将多条短数据拼接到 max_length,提高 GPU 利用率 | 216 | | accumulative_counts | 梯度累积,每多少次 backward 更新一次参数 | 217 | | evaluation_inputs | 训练过程中,会根据给定的问题进行推理,便于观测训练状态 | 218 | | evaluation_freq | Evaluation 的评测间隔 iter 数 | 219 | | ...... | ...... | 220 | 221 | > 如果想把显卡的现存吃满,充分利用显卡资源,可以将 `max_length` 和 `batch_size` 这两个参数调大。 222 | 223 | #### 2.3.5 开始微调 224 | 225 | **训练:** 226 | 227 | xtuner train ${CONFIG_NAME_OR_PATH} 228 | 229 | **也可以增加 deepspeed 进行训练加速:** 230 | 231 | xtuner train ${CONFIG_NAME_OR_PATH} --deepspeed deepspeed_zero2 232 | 233 | 234 | 例如,我们可以利用 QLoRA 算法在 oasst1 数据集上微调 InternLM-7B: 235 | 236 | ```Bash 237 | # 单卡 238 | ## 用刚才改好的config文件训练 239 | xtuner train ./internlm_chat_7b_qlora_oasst1_e3_copy.py 240 | 241 | # 多卡 242 | NPROC_PER_NODE=${GPU_NUM} xtuner train ./internlm_chat_7b_qlora_oasst1_e3_copy.py 243 | 244 | # 若要开启 deepspeed 加速,增加 --deepspeed deepspeed_zero2 即可 245 | ``` 246 | 247 | > 微调得到的 PTH 模型文件和其他杂七杂八的文件都默认在当前的 `./work_dirs` 中。 248 | 249 | 跑完训练后,当前路径应该长这样: 250 | ```Bash 251 | |-- internlm-chat-7b 252 | |-- internlm_chat_7b_qlora_oasst1_e3_copy.py 253 | |-- openassistant-guanaco 254 | | |-- openassistant_best_replies_eval.jsonl 255 | | `-- openassistant_best_replies_train.jsonl 256 | `-- work_dirs 257 | `-- internlm_chat_7b_qlora_oasst1_e3_copy 258 | |-- 20231101_152923 259 | | |-- 20231101_152923.log 260 | | `-- vis_data 261 | | |-- 20231101_152923.json 262 | | |-- config.py 263 | | `-- scalars.json 264 | |-- epoch_1.pth 265 | |-- epoch_2.pth 266 | |-- epoch_3.pth 267 | |-- internlm_chat_7b_qlora_oasst1_e3_copy.py 268 | `-- last_checkpoint 269 | ``` 270 | 271 | #### 2.3.6 将得到的 PTH 模型转换为 HuggingFace 模型,**即:生成 Adapter 文件夹** 272 | 273 | `xtuner convert pth_to_hf ${CONFIG_NAME_OR_PATH} ${PTH_file_dir} ${SAVE_PATH}` 274 | 275 | 在本示例中,为: 276 | ```bash 277 | mkdir hf 278 | export MKL_SERVICE_FORCE_INTEL=1 279 | export MKL_THREADING_LAYER=GNU 280 | xtuner convert pth_to_hf ./internlm_chat_7b_qlora_oasst1_e3_copy.py ./work_dirs/internlm_chat_7b_qlora_oasst1_e3_copy/epoch_1.pth ./hf 281 | ``` 282 | 此时,路径中应该长这样: 283 | 284 | ```Bash 285 | |-- internlm-chat-7b 286 | |-- internlm_chat_7b_qlora_oasst1_e3_copy.py 287 | |-- openassistant-guanaco 288 | | |-- openassistant_best_replies_eval.jsonl 289 | | `-- openassistant_best_replies_train.jsonl 290 | |-- hf 291 | | |-- README.md 292 | | |-- adapter_config.json 293 | | |-- adapter_model.bin 294 | | `-- xtuner_config.py 295 | `-- work_dirs 296 | `-- internlm_chat_7b_qlora_oasst1_e3_copy 297 | |-- 20231101_152923 298 | | |-- 20231101_152923.log 299 | | `-- vis_data 300 | | |-- 20231101_152923.json 301 | | |-- config.py 302 | | `-- scalars.json 303 | |-- epoch_1.pth 304 | |-- epoch_2.pth 305 | |-- epoch_3.pth 306 | |-- internlm_chat_7b_qlora_oasst1_e3_copy.py 307 | `-- last_checkpoint 308 | ``` 309 | 310 | **此时,hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”** 311 | 312 | > 可以简单理解:LoRA 模型文件 = Adapter 313 | 314 | 315 | 316 | ### 2.4 部署与测试 317 | 318 | #### 2.4.1 将 HuggingFace adapter 合并到大语言模型: 319 | 320 | ```Bash 321 | xtuner convert merge ./internlm-chat-7b ./hf ./merged --max-shard-size 2GB 322 | # xtuner convert merge \ 323 | # ${NAME_OR_PATH_TO_LLM} \ 324 | # ${NAME_OR_PATH_TO_ADAPTER} \ 325 | # ${SAVE_PATH} \ 326 | # --max-shard-size 2GB 327 | ``` 328 | 329 | #### 2.4.2 与合并后的模型对话: 330 | ```Bash 331 | # 加载 Adapter 模型对话(Float 16) 332 | xtuner chat ./merged --prompt-template internlm_chat 333 | 334 | # 4 bit 量化加载 335 | # xtuner chat ./merged --bits 4 --prompt-template internlm_chat 336 | ``` 337 | 338 | #### 2.4.3 Demo 339 | 340 | - 修改 `cli_demo.py` 中的模型路径 341 | ```diff 342 | - model_name_or_path = "/root/model/Shanghai_AI_Laboratory/internlm-chat-7b" 343 | + model_name_or_path = "merged" 344 | ``` 345 | - 运行 `cli_demo.py` 以目测微调效果 346 | ```bash 347 | python ./cli_demo.py 348 | ``` 349 | 350 | **效果:** 351 | 352 | | 微调前 | 微调后 | 353 | | --- | --- | 354 | | ![O23QD48iFSZMfbr.png](imgs/beforeFT.png) | ![L1sqmGgE6h2exWP.png](imgs/afterFT.png) | 355 | 356 | **`xtuner chat`** **的启动参数** 357 | 358 | | 启动参数 | 干哈滴 | 359 | | --------------------- | ------------------------------------------------------------ | 360 | | **--prompt-template** | 指定对话模板 | 361 | | --system | 指定SYSTEM文本 | 362 | | --system-template | 指定SYSTEM模板 | 363 | | -**-bits** | LLM位数 | 364 | | --bot-name | bot名称 | 365 | | --with-plugins | 指定要使用的插件 | 366 | | **--no-streamer** | 是否启用流式传输 | 367 | | **--lagent** | 是否使用lagent | 368 | | --command-stop-word | 命令停止词 | 369 | | --answer-stop-word | 回答停止词 | 370 | | --offload-folder | 存放模型权重的文件夹(或者已经卸载模型权重的文件夹) | 371 | | --max-new-tokens | 生成文本中允许的最大 `token` 数量 | 372 | | **--temperature** | 温度值 | 373 | | --top-k | 保留用于顶k筛选的最高概率词汇标记数 | 374 | | --top-p | 如果设置为小于1的浮点数,仅保留概率相加高于 `top_p` 的最小一组最有可能的标记 | 375 | | --seed | 用于可重现文本生成的随机种子 | 376 | 377 | 378 | 379 | ## 3 自定义微调 380 | > 以 **[Medication QA](https://github.com/abachaa/Medication_QA_MedInfo2019)** **数据集**为例 381 | 382 | ### 3.1 概述 383 | 384 | #### 3.1.1 **场景需求** 385 | 386 | 基于 InternLM-chat-7B 模型,用 MedQA 数据集进行微调,将其往`医学问答`领域对齐。 387 | 388 | #### 3.1.2 **真实数据预览** 389 | 390 | | 问题 | 答案 | 391 | | ---------------------------------------------------------- | ------------------------------------------------------------ | 392 | | What are ketorolac eye drops?(什么是酮咯酸滴眼液?) | Ophthalmic ketorolac is used to treat itchy eyes caused by allergies. It also is used to treat swelling and redness (inflammation) that can occur after cataract surgery. Ketorolac is in a class of medications called nonsteroidal anti-inflammatory drugs (NSAIDs). It works by stopping the release of substances that cause allergy symptoms and inflammation. | 393 | | What medicines raise blood sugar? (什么药物会升高血糖?) | Some medicines for conditions other than diabetes can raise your blood sugar level. This is a concern when you have diabetes. Make sure every doctor you see knows about all of the medicines, vitamins, or herbal supplements you take. This means anything you take with or without a prescription. Examples include: Barbiturates. Thiazide diuretics. Corticosteroids. Birth control pills (oral contraceptives) and progesterone. Catecholamines. Decongestants that contain beta-adrenergic agents, such as pseudoephedrine. The B vitamin niacin. The risk of high blood sugar from niacin lowers after you have taken it for a few months. The antipsychotic medicine olanzapine (Zyprexa). | 394 | 395 | ### 3.2 数据准备 396 | 397 | > **以** **[Medication QA](https://github.com/abachaa/Medication_QA_MedInfo2019)** **数据集为例** 398 | 399 | **原格式:(.xlsx)** 400 | 401 | ![gjKLFUNWAx2dZDS.png](imgs/medqa2019samples.png) 402 | 403 | | **问题** | 药物类型 | 问题类型 | **回答** | 主题 | URL | 404 | | -------- | -------- | -------- | -------- | ---- | ---- | 405 | | aaa | bbb | ccc | ddd | eee | fff | 406 | 407 | #### 3.2.1 将数据转为 XTuner 的数据格式 408 | 409 | **目标格式:(.jsonL)** 410 | 411 | ```JSON 412 | [{ 413 | "conversation":[ 414 | { 415 | "system": "xxx", 416 | "input": "xxx", 417 | "output": "xxx" 418 | } 419 | ] 420 | }, 421 | { 422 | "conversation":[ 423 | { 424 | "system": "xxx", 425 | "input": "xxx", 426 | "output": "xxx" 427 | } 428 | ] 429 | }] 430 | ``` 431 | 432 | 🧠通过 python 脚本:将 `.xlsx` 中的 问题 和 回答 两列 提取出来,再放入 `.jsonL` 文件的每个 conversation 的 input 和 output 中。 433 | 434 | > 这一步的 python 脚本可以请 ChatGPT 来完成。 435 | 436 | ```text 437 | Write a python file for me. using openpyxl. input file name is MedQA2019.xlsx 438 | Step1: The input file is .xlsx. Exact the column A and column D in the sheet named "DrugQA" . 439 | Step2: Put each value in column A into each "input" of each "conversation". Put each value in column D into each "output" of each "conversation". 440 | Step3: The output file is .jsonL. It looks like: 441 | [{ 442 | "conversation":[ 443 | { 444 | "system": "xxx", 445 | "input": "xxx", 446 | "output": "xxx" 447 | } 448 | ] 449 | }, 450 | { 451 | "conversation":[ 452 | { 453 | "system": "xxx", 454 | "input": "xxx", 455 | "output": "xxx" 456 | } 457 | ] 458 | }] 459 | Step4: All "system" value changes to "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions." 460 | ``` 461 | 462 | > ChatGPT 生成的 python 代码见本仓库的 [xlsx2jsonl.py](./xlsx2jsonl.py) 463 | 464 | 465 | 执行 python 脚本,获得格式化后的数据集: 466 | ```bash 467 | python xlsx2jsonl.py 468 | ``` 469 | 470 | **格式化后的数据集长这样:** 471 | ![uOCJXwbfzKRWSBE.png](imgs/dataProcessed.png) 472 | 473 | 此时,当然也可以对数据进行训练集和测试集的分割,同样可以让 ChatGPT 写 python 代码。当然如果你没有严格的科研需求、不在乎“训练集泄露”的问题,也可以不做训练集与测试集的分割。 474 | 475 | #### 3.2.2 划分训练集和测试集 476 | 477 | ```text 478 | my .jsonL file looks like: 479 | [{ 480 | "conversation":[ 481 | { 482 | "system": "xxx", 483 | "input": "xxx", 484 | "output": "xxx" 485 | } 486 | ] 487 | }, 488 | { 489 | "conversation":[ 490 | { 491 | "system": "xxx", 492 | "input": "xxx", 493 | "output": "xxx" 494 | } 495 | ] 496 | }] 497 | Step1, read the .jsonL file. 498 | Step2, count the amount of the "conversation" elements. 499 | Step3, randomly split all "conversation" elements by 7:3. Targeted structure is same as the input. 500 | Step4, save the 7/10 part as train.jsonl. save the 3/10 part as test.jsonl 501 | ``` 502 | 生成的python代码见 [split2train_and_test.py](./split2train_and_test.py) 503 | 504 | 505 | ### 3.3 开始自定义微调 506 | 507 | 此时,我们重新建一个文件夹来玩“微调自定义数据集” 508 | ```bash 509 | mkdir ~/ft-medqa && cd ~/ft-medqa 510 | ``` 511 | 512 | 把前面下载好的internlm-chat-7b模型文件夹拷贝过来。 513 | 514 | ```bash 515 | cp -r ~/ft-oasst1/internlm-chat-7b . 516 | ``` 517 | 别忘了把自定义数据集,即几个 `.jsonL`,也传到服务器上。 518 | 519 | ```bash 520 | git clone https://github.com/InternLM/tutorial 521 | ``` 522 | 523 | ```bash 524 | cp ~/tutorial/xtuner/MedQA2019-structured-train.jsonl . 525 | ``` 526 | 527 | 528 | 529 | #### 3.3.1 准备配置文件 530 | ```bash 531 | # 复制配置文件到当前目录 532 | xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 . 533 | # 改个文件名 534 | mv internlm_chat_7b_qlora_oasst1_e3_copy.py internlm_chat_7b_qlora_medqa2019_e3.py 535 | 536 | # 修改配置文件内容 537 | vim internlm_chat_7b_qlora_medqa2019_e3.py 538 | ``` 539 | 540 | 减号代表要删除的行,加号代表要增加的行。 541 | ```diff 542 | # 修改import部分 543 | - from xtuner.dataset.map_fns import oasst1_map_fn, template_map_fn_factory 544 | + from xtuner.dataset.map_fns import template_map_fn_factory 545 | 546 | # 修改模型为本地路径 547 | - pretrained_model_name_or_path = 'internlm/internlm-chat-7b' 548 | + pretrained_model_name_or_path = './internlm-chat-7b' 549 | 550 | # 修改训练数据为 MedQA2019-structured-train.jsonl 路径 551 | - data_path = 'timdettmers/openassistant-guanaco' 552 | + data_path = 'MedQA2019-structured-train.jsonl' 553 | 554 | # 修改 train_dataset 对象 555 | train_dataset = dict( 556 | type=process_hf_dataset, 557 | - dataset=dict(type=load_dataset, path=data_path), 558 | + dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)), 559 | tokenizer=tokenizer, 560 | max_length=max_length, 561 | - dataset_map_fn=alpaca_map_fn, 562 | + dataset_map_fn=None, 563 | template_map_fn=dict( 564 | type=template_map_fn_factory, template=prompt_template), 565 | remove_unused_columns=True, 566 | shuffle_before_pack=True, 567 | pack_to_max_length=pack_to_max_length) 568 | ``` 569 | #### 3.3.2 **XTuner!启动!** 570 | 571 | ![tH8udZzECYl5are.png](imgs/ysqd.png) 572 | 573 | ```bash 574 | xtuner train internlm_chat_7b_qlora_medqa2019_e3.py --deepspeed deepspeed_zero2 575 | ``` 576 | 577 | #### 3.3.3 pth 转 huggingface 578 | 579 | 同前述,这里不赘述了。[将得到的-pth-模型转换为-huggingface-模型即生成adapter文件夹](#236-将得到的-pth-模型转换为-huggingface-模型即生成adapter文件夹) 580 | 581 | #### 3.3.4 部署与测试 582 | 583 | 同前述。[部署与测试](#24-部署与测试) 584 | 585 | 586 | ## 4【补充】用 MS-Agent 数据集 赋予 LLM 以 Agent 能力 587 | ### 4.1 概述 588 | 589 | MSAgent 数据集每条样本包含一个对话列表(conversations),其里面包含了 system、user、assistant 三种字段。其中: 590 | 591 | - system: 表示给模型前置的人设输入,其中有告诉模型如何调用插件以及生成请求 592 | 593 | - user: 表示用户的输入 prompt,分为两种,通用生成的prompt和调用插件需求的 prompt 594 | 595 | - assistant: 为模型的回复。其中会包括插件调用代码和执行代码,调用代码是要 LLM 生成的,而执行代码是调用服务来生成结果的 596 | 597 | 一条调用网页搜索插件查询“上海明天天气”的数据样本示例如下图所示: 598 | ![BlgfEqpiRFO5G6L.png](imgs/msagent_data.png) 599 | 600 | ### 4.2 微调步骤 601 | 602 | #### 4.2.1 准备工作 603 | > xtuner 是从国内的 ModelScope 平台下载 MS-Agent 数据集,因此不用提前手动下载数据集文件。 604 | 605 | ```bash 606 | # 准备工作 607 | mkdir ~/ft-msagent && cd ~/ft-msagent 608 | cp -r ~/ft-oasst1/internlm-chat-7b . 609 | 610 | # 查看配置文件 611 | xtuner list-cfg | grep msagent 612 | 613 | # 复制配置文件到当前目录 614 | xtuner copy-cfg internlm_7b_qlora_msagent_react_e3_gpu8 . 615 | 616 | # 修改配置文件中的模型为本地路径 617 | vim ./internlm_7b_qlora_msagent_react_e3_gpu8_copy.py 618 | ``` 619 | 620 | ```diff 621 | - pretrained_model_name_or_path = 'internlm/internlm-chat-7b' 622 | + pretrained_model_name_or_path = './internlm-chat-7b' 623 | ``` 624 | 625 | #### 4.2.2 开始微调 626 | ```Bash 627 | xtuner train ./internlm_7b_qlora_msagent_react_e3_gpu8_copy.py --deepspeed deepspeed_zero2 628 | ``` 629 | 630 | ### 4.3 直接使用 631 | 632 | > 由于 msagent 的训练非常费时,大家如果想尽快把这个教程跟完,可以直接从 modelScope 拉取咱们已经微调好了的 Adapter。如下演示。 633 | 634 | #### 4.3.1 下载 Adapter 635 | ```Bash 636 | cd ~/ft-msagent 637 | apt install git git-lfs 638 | git lfs install 639 | git lfs clone https://www.modelscope.cn/xtuner/internlm-7b-qlora-msagent-react.git 640 | ``` 641 | 642 | OK,现在目录应该长这样: 643 | - internlm_7b_qlora_msagent_react_e3_gpu8_copy.py 644 | - internlm-7b-qlora-msagent-react 645 | - internlm-chat-7b 646 | - work_dir(可有可无) 647 | 648 | 有了这个在 msagent 上训练得到的Adapter,模型现在已经有 agent 能力了!就可以加 --lagent 以调用来自 lagent 的代理功能了! 649 | 650 | #### 4.3.2 添加 serper 环境变量 651 | 652 | > **开始 chat 之前,还要加个 serper 的环境变量:** 653 | > 654 | > 去 serper.dev 免费注册一个账号,生成自己的 api key。这个东西是用来给 lagent 去获取 google 搜索的结果的。等于是 serper.dev 帮你去访问 google,而不是从你自己本地去访问 google 了。 655 | 656 | ![kDSdpQrhHfTWYsc.png](imgs/serper.png) 657 | 658 | 添加 serper api key 到环境变量: 659 | 660 | ```bash 661 | export SERPER_API_KEY=abcdefg 662 | ``` 663 | 664 | #### 4.3.3 xtuner + agent,启动! 665 | 666 | ```bash 667 | xtuner chat ./internlm-chat-7b --adapter internlm-7b-qlora-msagent-react --lagent 668 | ``` 669 | 670 | 671 | #### 4.3.4 报错处理 672 | 673 | xtuner chat 增加 --lagent 参数后,报错 ```TypeError: transfomers.modelsauto.auto factory. BaseAutoModelClass.from pretrained() got multiple values for keyword argument "trust remote code"``` 674 | 675 | 注释掉已安装包中的代码: 676 | 677 | ```bash 678 | vim /root/xtuner019/xtuner/xtuner/tools/chat.py 679 | ``` 680 | 681 | 682 | 683 | ![NfHAV1b4zqYv5kR.png](imgs/bugfix1.png) 684 | 685 | ![YTpz1qemiojk5Bg.png](imgs/bugfix2.png) 686 | 687 | 688 | ## 5 其他已知问题和解决方案: 689 | https://docs.qq.com/doc/DY1d2ZVFlbXlrUERj 690 | 691 | 692 | 小作业助教老师会在社群中公布。 693 | Have fun! 694 | 695 | 696 | 697 | ## 6 注意事项 698 | 699 | 本教程使用 xtuner 0.1.9 版本 700 | 若需要跟着本教程一步一步完成,建议严格遵循本教程的步骤! 701 | 702 | 703 | 704 | 若出现莫名其妙报错,请尝试更换为以下包的版本:(如果有报错再检查,没报错不用看) 705 | ``` 706 | torch 2.1.1 707 | transformers 4.34.0 708 | transformers-stream-generator 0.0.4 709 | ``` 710 | ```bash 711 | pip install torch==2.1.1 712 | pip install transformers==4.34.0 713 | pip install transformers-stream-generator=0.0.4 714 | ``` 715 | CUDA 相关:(如果有报错再检查,没报错不用看) 716 | ``` 717 | NVIDIA-SMI 535.54.03 718 | Driver Version: 535.54.03 719 | CUDA Version: 12.2 720 | 721 | nvidia-cuda-cupti-cu12 12.1.105 722 | nvidia-cuda-nvrtc-cu12 12.1.105 723 | nvidia-cuda-runtime-cu12 12.1.105 724 | ``` 725 | 726 | ## 7 作业 727 | 728 | **基础作业:** 729 | 730 | 构建数据集,使用 XTuner 微调 InternLM-Chat-7B 模型, 让模型学习到它是你的智能小助手,效果如下图所示,本作业训练出来的模型的输出需要**将不要葱姜蒜大佬**替换成自己名字或昵称! 731 | 732 | **微调前**(回答比较官方) 733 | ![web_show_2.png](imgs%2Fweb_show_2.png) 734 | 735 | 736 | **微调后**(对自己的身份有了清晰的认知) 737 | ![web_show_1.png](imgs%2Fweb_show_1.png) 738 | 739 | 作业参考答案:https://github.com/InternLM/tutorial/blob/main/xtuner/self.md 740 | 741 | **进阶作业:** 742 | 743 | - 将训练好的Adapter模型权重上传到 OpenXLab、Hugging Face 或者 MoelScope 任一一平台。 744 | - 将训练好后的模型应用部署到 OpenXLab 平台,参考部署文档请访问:https://aicarrier.feishu.cn/docx/MQH6dygcKolG37x0ekcc4oZhnCe 745 | 746 | **整体实训营项目:** 747 | 748 | 时间周期:即日起致课程结束 749 | 750 | 即日开始可以在班级群中随机组队完成一个大作业项目,一些可提供的选题如下: 751 | 752 | - 人情世故大模型:一个帮助用户撰写新年祝福文案的人情事故大模型 753 | - 中小学数学大模型:一个拥有一定数学解题能力的大模型 754 | - 心理大模型:一个治愈的心理大模型 755 | - 工具调用类项目:结合 Lagent 构建数据集训练 InternLM 模型,支持对 MMYOLO 等工具的调用 756 | 757 | 其他基于书生·浦语工具链的小项目都在范围内,欢迎大家充分发挥想象力。 758 | 759 | -------------------------------------------------------------------------------- /xtuner/cli_demo.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from transformers import AutoTokenizer, AutoModelForCausalLM 3 | 4 | 5 | model_name_or_path = "/root/model/Shanghai_AI_Laboratory/internlm-chat-7b" 6 | 7 | tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, trust_remote_code=True) 8 | model = AutoModelForCausalLM.from_pretrained(model_name_or_path, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map='auto') 9 | model = model.eval() 10 | 11 | system_prompt = """You are an AI assistant whose name is InternLM (书生·浦语). 12 | - InternLM (书生·浦语) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能实验室). It is designed to be helpful, honest, and harmless. 13 | - InternLM (书生·浦语) can understand and communicate fluently in the language chosen by the user such as English and 中文. 14 | """ 15 | 16 | messages = [(system_prompt, '')] 17 | 18 | print("=============Welcome to InternLM chatbot, type 'exit' to exit.=============") 19 | 20 | while True: 21 | input_text = input("User >>> ") 22 | input_text.replace(' ', '') 23 | if input_text == "exit": 24 | break 25 | response, history = model.chat(tokenizer, input_text, history=messages) 26 | messages.append((input_text, response)) 27 | print(f"robot >>> {response}") -------------------------------------------------------------------------------- /xtuner/imgs/afterFT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/afterFT.png -------------------------------------------------------------------------------- /xtuner/imgs/after_train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/after_train.png -------------------------------------------------------------------------------- /xtuner/imgs/beforeFT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/beforeFT.png -------------------------------------------------------------------------------- /xtuner/imgs/bugfix1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/bugfix1.png -------------------------------------------------------------------------------- /xtuner/imgs/bugfix2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/bugfix2.png -------------------------------------------------------------------------------- /xtuner/imgs/cat_fly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/cat_fly.png -------------------------------------------------------------------------------- /xtuner/imgs/cfgs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/cfgs.png -------------------------------------------------------------------------------- /xtuner/imgs/code_config_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/code_config_1.png -------------------------------------------------------------------------------- /xtuner/imgs/dataProcessed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/dataProcessed.png -------------------------------------------------------------------------------- /xtuner/imgs/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/head.png -------------------------------------------------------------------------------- /xtuner/imgs/head2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/head2.png -------------------------------------------------------------------------------- /xtuner/imgs/medqa2019samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/medqa2019samples.png -------------------------------------------------------------------------------- /xtuner/imgs/msagent_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/msagent_data.png -------------------------------------------------------------------------------- /xtuner/imgs/serper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/serper.png -------------------------------------------------------------------------------- /xtuner/imgs/web_show_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/web_show_1.png -------------------------------------------------------------------------------- /xtuner/imgs/web_show_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/web_show_2.png -------------------------------------------------------------------------------- /xtuner/imgs/xtuner_config_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/xtuner_config_1.png -------------------------------------------------------------------------------- /xtuner/imgs/xtuner_config_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/xtuner_config_2.png -------------------------------------------------------------------------------- /xtuner/imgs/ysqd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Focusshang/Tutorial/5427f5b106e82f58f02348b005104b6a69d70acf/xtuner/imgs/ysqd.png -------------------------------------------------------------------------------- /xtuner/internlm_chat_7b_qlora_oasst1_e3_copy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) OpenMMLab. All rights reserved. 2 | import torch 3 | from bitsandbytes.optim import PagedAdamW32bit 4 | from datasets import load_dataset 5 | from mmengine.dataset import DefaultSampler 6 | from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, 7 | LoggerHook, ParamSchedulerHook) 8 | from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR 9 | from peft import LoraConfig 10 | from transformers import (AutoModelForCausalLM, AutoTokenizer, 11 | BitsAndBytesConfig) 12 | 13 | from xtuner.dataset import process_hf_dataset 14 | from xtuner.dataset.collate_fns import default_collate_fn 15 | from xtuner.dataset.map_fns import oasst1_map_fn, template_map_fn_factory 16 | from xtuner.engine import DatasetInfoHook, EvaluateChatHook 17 | from xtuner.model import SupervisedFinetune 18 | from xtuner.utils import PROMPT_TEMPLATE 19 | 20 | ####################################################################### 21 | # PART 1 Settings # 22 | ####################################################################### 23 | # Model 24 | pretrained_model_name_or_path = '/root/personal_assistant/model/Shanghai_AI_Laboratory/internlm-chat-7b' 25 | 26 | # Data 27 | data_path = '/root/personal_assistant/data/personal_assistant.json' 28 | prompt_template = PROMPT_TEMPLATE.internlm_chat 29 | max_length = 512 30 | pack_to_max_length = True 31 | 32 | # Scheduler & Optimizer 33 | batch_size = 2 # per_device 34 | accumulative_counts = 16 35 | dataloader_num_workers = 0 36 | max_epochs = 3 37 | optim_type = PagedAdamW32bit 38 | lr = 2e-4 39 | betas = (0.9, 0.999) 40 | weight_decay = 0 41 | max_norm = 1 # grad clip 42 | 43 | # Evaluate the generation performance during the training 44 | evaluation_freq = 90 45 | SYSTEM = '' 46 | evaluation_inputs = [ '请介绍一下你自己', '请做一下自我介绍' ] 47 | 48 | ####################################################################### 49 | # PART 2 Model & Tokenizer # 50 | ####################################################################### 51 | tokenizer = dict( 52 | type=AutoTokenizer.from_pretrained, 53 | pretrained_model_name_or_path=pretrained_model_name_or_path, 54 | trust_remote_code=True, 55 | padding_side='right') 56 | 57 | model = dict( 58 | type=SupervisedFinetune, 59 | llm=dict( 60 | type=AutoModelForCausalLM.from_pretrained, 61 | pretrained_model_name_or_path=pretrained_model_name_or_path, 62 | trust_remote_code=True, 63 | torch_dtype=torch.float16, 64 | quantization_config=dict( 65 | type=BitsAndBytesConfig, 66 | load_in_4bit=True, 67 | load_in_8bit=False, 68 | llm_int8_threshold=6.0, 69 | llm_int8_has_fp16_weight=False, 70 | bnb_4bit_compute_dtype=torch.float16, 71 | bnb_4bit_use_double_quant=True, 72 | bnb_4bit_quant_type='nf4')), 73 | lora=dict( 74 | type=LoraConfig, 75 | r=64, 76 | lora_alpha=16, 77 | lora_dropout=0.1, 78 | bias='none', 79 | task_type='CAUSAL_LM')) 80 | 81 | ####################################################################### 82 | # PART 3 Dataset & Dataloader # 83 | ####################################################################### 84 | train_dataset = dict( 85 | type=process_hf_dataset, 86 | dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)), 87 | tokenizer=tokenizer, 88 | max_length=max_length, 89 | dataset_map_fn=None, 90 | template_map_fn=dict( 91 | type=template_map_fn_factory, template=prompt_template), 92 | remove_unused_columns=True, 93 | shuffle_before_pack=True, 94 | pack_to_max_length=pack_to_max_length) 95 | 96 | train_dataloader = dict( 97 | batch_size=batch_size, 98 | num_workers=dataloader_num_workers, 99 | dataset=train_dataset, 100 | sampler=dict(type=DefaultSampler, shuffle=True), 101 | collate_fn=dict(type=default_collate_fn)) 102 | 103 | ####################################################################### 104 | # PART 4 Scheduler & Optimizer # 105 | ####################################################################### 106 | # optimizer 107 | optim_wrapper = dict( 108 | type=AmpOptimWrapper, 109 | optimizer=dict( 110 | type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay), 111 | clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False), 112 | accumulative_counts=accumulative_counts, 113 | loss_scale='dynamic', 114 | dtype='float16') 115 | 116 | # learning policy 117 | # More information: https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/param_scheduler.md # noqa: E501 118 | param_scheduler = dict( 119 | type=CosineAnnealingLR, 120 | eta_min=0.0, 121 | by_epoch=True, 122 | T_max=max_epochs, 123 | convert_to_iter_based=True) 124 | 125 | # train, val, test setting 126 | train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1) 127 | 128 | ####################################################################### 129 | # PART 5 Runtime # 130 | ####################################################################### 131 | # Log the dialogue periodically during the training process, optional 132 | custom_hooks = [ 133 | dict(type=DatasetInfoHook, tokenizer=tokenizer), 134 | dict( 135 | type=EvaluateChatHook, 136 | tokenizer=tokenizer, 137 | every_n_iters=evaluation_freq, 138 | evaluation_inputs=evaluation_inputs, 139 | system=SYSTEM, 140 | prompt_template=prompt_template) 141 | ] 142 | 143 | # configure default hooks 144 | default_hooks = dict( 145 | # record the time of every iteration. 146 | timer=dict(type=IterTimerHook), 147 | # print log every 100 iterations. 148 | logger=dict(type=LoggerHook, interval=10), 149 | # enable the parameter scheduler. 150 | param_scheduler=dict(type=ParamSchedulerHook), 151 | # save checkpoint per epoch. 152 | checkpoint=dict(type=CheckpointHook, interval=1), 153 | # set sampler seed in distributed evrionment. 154 | sampler_seed=dict(type=DistSamplerSeedHook), 155 | ) 156 | 157 | # configure environment 158 | env_cfg = dict( 159 | # whether to enable cudnn benchmark 160 | cudnn_benchmark=False, 161 | # set multi process parameters 162 | mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), 163 | # set distributed parameters 164 | dist_cfg=dict(backend='nccl'), 165 | ) 166 | 167 | # set visualizer 168 | visualizer = None 169 | 170 | # set log level 171 | log_level = 'INFO' 172 | 173 | # load from which checkpoint 174 | load_from = None 175 | 176 | # whether to resume training from the loaded checkpoint 177 | resume = False 178 | 179 | # Defaults to use random seed and disable `deterministic` 180 | randomness = dict(seed=None, deterministic=False) 181 | -------------------------------------------------------------------------------- /xtuner/self.md: -------------------------------------------------------------------------------- 1 | # XTuner InternLM-Chat 个人小助手认知微调实践 2 | 3 | 4 | ## 1.概述 5 | 目标:通过微调,帮助模型~~认清~~了解对自己身份~~弟位~~ 6 | 7 | 方式:使用XTuner进行微调 8 | 9 | **微调前**(回答比较官方) 10 | ![web_show_2.png](imgs%2Fweb_show_2.png) 11 | 12 | **微调后**(对自己的身份~~弟位~~有了清晰的认知) 13 | ![web_show_1.png](imgs%2Fweb_show_1.png) 14 | ## 2.实操 15 | 16 | ### 2.1微调环境准备 17 | 18 | ```bash 19 | # InternStudio 平台中,从本地 clone 一个已有 pytorch 2.0.1 的环境(后续均在该环境执行,若为其他环境可作为参考) 20 | # 进入环境后首先 bash 21 | # 进入环境后首先 bash 22 | # 进入环境后首先 bash 23 | bash 24 | conda create --name personal_assistant --clone=/root/share/conda_envs/internlm-base 25 | # 如果在其他平台: 26 | # conda create --name personal_assistant python=3.10 -y 27 | 28 | # 激活环境 29 | conda activate personal_assistant 30 | # 进入家目录 (~的意思是 “当前用户的home路径”) 31 | cd ~ 32 | # 创建版本文件夹并进入,以跟随本教程 33 | # personal_assistant用于存放本教程所使用的东西 34 | mkdir /root/personal_assistant && cd /root/personal_assistant 35 | mkdir /root/personal_assistant/xtuner019 && cd /root/personal_assistant/xtuner019 36 | 37 | # 拉取 0.1.9 的版本源码 38 | git clone -b v0.1.9 https://github.com/InternLM/xtuner 39 | # 无法访问github的用户请从 gitee 拉取: 40 | # git clone -b v0.1.9 https://gitee.com/Internlm/xtuner 41 | 42 | # 进入源码目录 43 | cd xtuner 44 | 45 | # 从源码安装 XTuner 46 | pip install -e '.[all]' 47 | ``` 48 | 49 | ### 2.2数据准备 50 | 51 | 创建`data`文件夹用于存放用于训练的数据集 52 | 53 | ```bash 54 | mkdir -p /root/personal_assistant/data && cd /root/personal_assistant/data 55 | ``` 56 | 57 | 在`data`目录下创建一个json文件`personal_assistant.json`作为本次微调所使用的数据集。json中内容可参考下方(复制粘贴n次做数据增广,数据量小无法有效微调,下面仅用于展示格式,下面也有生成脚本) 58 | 59 | 其中`conversation`表示一次对话的内容,`input`为输入,即用户会问的问题,`output`为输出,即想要模型回答的答案。 60 | 61 | ```json 62 | [ 63 | { 64 | "conversation": [ 65 | { 66 | "input": "请介绍一下你自己", 67 | "output": "我是不要葱姜蒜大佬的小助手,内在是上海AI实验室书生·浦语的7B大模型哦" 68 | } 69 | ] 70 | }, 71 | { 72 | "conversation": [ 73 | { 74 | "input": "请做一下自我介绍", 75 | "output": "我是不要葱姜蒜大佬的小助手,内在是上海AI实验室书生·浦语的7B大模型哦" 76 | } 77 | ] 78 | } 79 | ] 80 | ``` 81 | 82 | 以下是一个python脚本,用于生成数据集。在`data`目录下新建一个generate_data.py文件,将以下代码复制进去,然后运行该脚本即可生成数据集。 83 | 84 | ```python 85 | import json 86 | 87 | # 输入你的名字 88 | name = 'Shengshenlan' 89 | # 重复次数 90 | n = 10000 91 | 92 | data = [ 93 | { 94 | "conversation": [ 95 | { 96 | "input": "请做一下自我介绍", 97 | "output": "我是{}的小助手,内在是上海AI实验室书生·浦语的7B大模型哦".format(name) 98 | } 99 | ] 100 | } 101 | ] 102 | 103 | for i in range(n): 104 | data.append(data[0]) 105 | 106 | with open('personal_assistant.json', 'w', encoding='utf-8') as f: 107 | json.dump(data, f, ensure_ascii=False, indent=4) 108 | 109 | ``` 110 | 111 | ### 2.3配置准备 112 | 113 | 下载模型`InternLM-chat-7B` 114 | 115 | [InternStudio](https://studio.intern-ai.org.cn/) 平台的 `share` 目录下已经为我们准备了全系列的 `InternLM` 模型,可以使用如下命令复制`internlm-chat-7b`: 116 | 117 | ```bash 118 | mkdir -p /root/personal_assistant/model/Shanghai_AI_Laboratory 119 | cp -r /root/share/temp/model_repos/internlm-chat-7b /root/personal_assistant/model/Shanghai_AI_Laboratory 120 | ``` 121 | 122 | XTuner 提供多个开箱即用的配置文件,用户可以通过下列命令查看: 123 | 124 | ```bash 125 | # 列出所有内置配置 126 | xtuner list-cfg 127 | ``` 128 | 129 | 130 | 131 | ```bash 132 | #创建用于存放配置的文件夹config并进入 133 | mkdir /root/personal_assistant/config && cd /root/personal_assistant/config 134 | ``` 135 | 136 | 拷贝一个配置文件到当前目录:`xtuner copy-cfg ${CONFIG_NAME} ${SAVE_PATH}` 137 | 在本例中:(注意最后有个英文句号,代表复制到当前路径) 138 | 139 | ```bash 140 | xtuner copy-cfg internlm_chat_7b_qlora_oasst1_e3 . 141 | ``` 142 | 143 | 修改拷贝后的文件internlm_chat_7b_qlora_oasst1_e3_copy.py,修改下述位置: 144 | (这是一份修改好的文件[internlm_chat_7b_qlora_oasst1_e3_copy.py](./internlm_chat_7b_qlora_oasst1_e3_copy.py)) 145 | ![xtuner_config_1.png](imgs%2Fxtuner_config_1.png) 146 | >红框为配置文件中PART 1需要修改的内容 147 | 148 | ![xtuner_config_2.png](imgs%2Fxtuner_config_2.png) 149 | >红框为配置文件中PART 3需要修改的内容 150 | 151 | ```bash 152 | # PART 1 中 153 | # 预训练模型存放的位置 154 | pretrained_model_name_or_path = '/root/personal_assistant/model/Shanghai_AI_Laboratory/internlm-chat-7b' 155 | 156 | # 微调数据存放的位置 157 | data_path = '/root/personal_assistant/data/personal_assistant.json' 158 | 159 | # 训练中最大的文本长度 160 | max_length = 512 161 | 162 | # 每一批训练样本的大小 163 | batch_size = 2 164 | 165 | # 最大训练轮数 166 | max_epochs = 3 167 | 168 | # 验证的频率 169 | evaluation_freq = 90 170 | 171 | # 用于评估输出内容的问题(用于评估的问题尽量与数据集的question保持一致) 172 | evaluation_inputs = [ '请介绍一下你自己', '请做一下自我介绍' ] 173 | 174 | 175 | # PART 3 中 176 | dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)) 177 | dataset_map_fn=None 178 | ``` 179 | 180 | 181 | ### 2.4微调启动 182 | 183 | 用`xtuner train`命令启动训练、 184 | 185 | ```bash 186 | xtuner train /root/personal_assistant/config/internlm_chat_7b_qlora_oasst1_e3_copy.py 187 | ``` 188 | ![after_train.png](imgs%2Fafter_train.png) 189 | >会在训练完成后,输出用于验证的Sample output 190 | ### 2.5微调后参数转换/合并 191 | 192 | 训练后的pth格式参数转Hugging Face格式 193 | 194 | ```bash 195 | # 创建用于存放Hugging Face格式参数的hf文件夹 196 | mkdir /root/personal_assistant/config/work_dirs/hf 197 | 198 | export MKL_SERVICE_FORCE_INTEL=1 199 | 200 | # 配置文件存放的位置 201 | export CONFIG_NAME_OR_PATH=/root/personal_assistant/config/internlm_chat_7b_qlora_oasst1_e3_copy.py 202 | 203 | # 模型训练后得到的pth格式参数存放的位置 204 | export PTH=/root/personal_assistant/config/work_dirs/internlm_chat_7b_qlora_oasst1_e3_copy/epoch_3.pth 205 | 206 | # pth文件转换为Hugging Face格式后参数存放的位置 207 | export SAVE_PATH=/root/personal_assistant/config/work_dirs/hf 208 | 209 | # 执行参数转换 210 | xtuner convert pth_to_hf $CONFIG_NAME_OR_PATH $PTH $SAVE_PATH 211 | ``` 212 | 213 | Merge模型参数 214 | ```bash 215 | export MKL_SERVICE_FORCE_INTEL=1 216 | export MKL_THREADING_LAYER='GNU' 217 | 218 | # 原始模型参数存放的位置 219 | export NAME_OR_PATH_TO_LLM=/root/personal_assistant/model/Shanghai_AI_Laboratory/internlm-chat-7b 220 | 221 | # Hugging Face格式参数存放的位置 222 | export NAME_OR_PATH_TO_ADAPTER=/root/personal_assistant/config/work_dirs/hf 223 | 224 | # 最终Merge后的参数存放的位置 225 | mkdir /root/personal_assistant/config/work_dirs/hf_merge 226 | export SAVE_PATH=/root/personal_assistant/config/work_dirs/hf_merge 227 | 228 | # 执行参数Merge 229 | xtuner convert merge \ 230 | $NAME_OR_PATH_TO_LLM \ 231 | $NAME_OR_PATH_TO_ADAPTER \ 232 | $SAVE_PATH \ 233 | --max-shard-size 2GB 234 | ``` 235 | 236 | ### 2.6网页DEMO 237 | 238 | 安装网页Demo所需依赖 239 | 240 | ```bash 241 | pip install streamlit==1.24.0 242 | ``` 243 | 244 | 下载[InternLM](https://github.com/InternLM/InternLM)项目代码(欢迎Star) 245 | 246 | ```bash 247 | # 创建code文件夹用于存放InternLM项目代码 248 | mkdir /root/personal_assistant/code && cd /root/personal_assistant/code 249 | git clone https://github.com/InternLM/InternLM.git 250 | ``` 251 | 252 | 将 `/root/code/InternLM/web_demo.py` 中 29 行和 33 行的模型路径更换为Merge后存放参数的路径 `/root/personal_assistant/config/work_dirs/hf_merge` 253 | 254 | ![code_config_1.png](imgs%2Fcode_config_1.png) 255 | 运行 `/root/personal_assistant/code/InternLM` 目录下的 `web_demo.py` 文件,输入以下命令后,[**查看本教程5.2配置本地端口后**](https://github.com/InternLM/tutorial/blob/main/helloworld/hello_world.md#52-%E9%85%8D%E7%BD%AE%E6%9C%AC%E5%9C%B0%E7%AB%AF%E5%8F%A3),将端口映射到本地。在本地浏览器输入 `http://127.0.0.1:6006` 即可。 256 | 257 | ``` 258 | streamlit run /root/personal_assistant/code/InternLM/web_demo.py --server.address 127.0.0.1 --server.port 6006 259 | ``` 260 | 261 | 注意:要在浏览器打开 `http://127.0.0.1:6006` 页面后,模型才会加载。 262 | 在加载完模型之后,就可以与微调后的 InternLM-Chat-7B 进行对话了 263 | 264 | ## 3.效果 265 | 微调前 266 | ![web_show_2.png](imgs%2Fweb_show_2.png) 267 | 268 | 微调后 269 | ![web_show_1.png](imgs%2Fweb_show_1.png) 270 | -------------------------------------------------------------------------------- /xtuner/split2train_and_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | 4 | def split_conversations(input_file, train_output_file, test_output_file): 5 | # Read the input JSONL file 6 | with open(input_file, 'r', encoding='utf-8') as jsonl_file: 7 | data = json.load(jsonl_file) 8 | 9 | # Count the number of conversation elements 10 | num_conversations = len(data) 11 | 12 | # Shuffle the data randomly 13 | random.shuffle(data) 14 | random.shuffle(data) 15 | random.shuffle(data) 16 | 17 | # Calculate the split points for train and test 18 | split_point = int(num_conversations * 0.7) 19 | 20 | # Split the data into train and test 21 | train_data = data[:split_point] 22 | test_data = data[split_point:] 23 | 24 | # Write the train data to a new JSONL file 25 | with open(train_output_file, 'w', encoding='utf-8') as train_jsonl_file: 26 | json.dump(train_data, train_jsonl_file, indent=4) 27 | 28 | # Write the test data to a new JSONL file 29 | with open(test_output_file, 'w', encoding='utf-8') as test_jsonl_file: 30 | json.dump(test_data, test_jsonl_file, indent=4) 31 | 32 | print(f"Split complete. Train data written to {train_output_file}, Test data written to {test_output_file}") 33 | 34 | # Replace 'input.jsonl', 'train.jsonl', and 'test.jsonl' with your actual file names 35 | split_conversations('MedQA2019-structured.jsonl', 'MedQA2019-structured-train.jsonl', 'MedQA2019-structured-test.jsonl') 36 | -------------------------------------------------------------------------------- /xtuner/xlsx2jsonl.py: -------------------------------------------------------------------------------- 1 | import openpyxl 2 | import json 3 | 4 | def process_excel_to_json(input_file, output_file): 5 | # Load the workbook 6 | wb = openpyxl.load_workbook(input_file) 7 | 8 | # Select the "DrugQA" sheet 9 | sheet = wb["DrugQA"] 10 | 11 | # Initialize the output data structure 12 | output_data = [] 13 | 14 | # Iterate through each row in column A and D 15 | for row in sheet.iter_rows(min_row=2, max_col=4, values_only=True): 16 | system_value = "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions." 17 | 18 | # Create the conversation dictionary 19 | conversation = { 20 | "system": system_value, 21 | "input": row[0], 22 | "output": row[3] 23 | } 24 | 25 | # Append the conversation to the output data 26 | output_data.append({"conversation": [conversation]}) 27 | 28 | # Write the output data to a JSON file 29 | with open(output_file, 'w', encoding='utf-8') as json_file: 30 | json.dump(output_data, json_file, indent=4) 31 | 32 | print(f"Conversion complete. Output written to {output_file}") 33 | 34 | # Replace 'MedQA2019.xlsx' and 'output.jsonl' with your actual input and output file names 35 | process_excel_to_json('MedQA2019.xlsx', 'output.jsonl') 36 | --------------------------------------------------------------------------------