chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:59:13 +08:00
commit f2d31077b9
1276 changed files with 194291 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
name: Bug Report
description: 报告项目中的bug问题
title: "[Bug] 具体模型-具体教程-负责人-具体bug"
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
感谢您报告bug!请填写以下信息帮助我们更好地定位和解决问题。
- type: input
id: model
attributes:
label: 出bug的具体模型
description: 请填写出现问题的具体模型名称
placeholder: 例如:Qwen3-8B、ChatGLM3-6B、InternLM2-7B等
validations:
required: true
- type: input
id: tutorial
attributes:
label: 出bug的具体模型教程
description: 请填写出现问题的具体教程名称
placeholder: 例如:Qwen3-8B vLLM 部署调用、ChatGLM3-6B FastApi部署调用等
validations:
required: true
- type: input
id: maintainer
attributes:
label: 教程负责人
description: 请填写该教程的具体负责人(对应教程@后的名字)
placeholder: 例如:不要葱姜蒜、张三、李四等
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Bug描述
description: 请详细描述遇到的问题
placeholder: 请描述您遇到的具体问题,包括错误信息、异常行为等
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: 复现步骤
description: 请提供复现该bug的详细步骤
placeholder: |
1. 执行命令...
2. 运行代码...
3. 出现错误...
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: 期望行为
description: 请描述您期望的正确行为
placeholder: 描述您期望应该发生什么
validations:
required: true
- type: textarea
id: environment
attributes:
label: 环境信息
description: 请提供您的运行环境信息
placeholder: |
- 操作系统:
- Python版本:
- CUDA版本:
- GPU型号:
- 其他相关依赖版本:
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: 其他信息
description: 请提供任何其他有助于解决问题的信息
placeholder: 包括日志、截图、相关配置等
validations:
required: true
- type: checkboxes
id: checks
attributes:
label: 确认事项 / Verification
description: 请确认以下事项 / Please confirm the following
options:
- label: 此问题未在过往Issue中被报告过 / This issue hasn't been reported before
required: true
+9
View File
@@ -0,0 +1,9 @@
blank_issues_enabled: false
contact_links:
- name: 📚 查看文档
url: https://github.com/datawhalechina/self-llm
about: 查看项目文档和使用指南
- name: 🔍 搜索已有Issue
url: https://github.com/datawhalechina/self-llm/issues
about: 搜索是否已有相关问题或请求
@@ -0,0 +1,119 @@
name: New Model Request
description: 请求新增模型或新增模型教程
title: "[New Model] "
labels: ["feature", "enhancement", "new-model"]
body:
- type: markdown
attributes:
value: |
感谢您提出新模型请求!请填写以下信息帮助我们了解您的需求。
- type: dropdown
id: request-type
attributes:
label: 请求类型
description: 请选择您的请求类型
options:
- 新增模型支持
- 新增模型教程
- 新增模型部署方式
- 其他
validations:
required: true
- type: input
id: model-name
attributes:
label: 模型名称
description: 请填写您希望新增的模型名称
placeholder: 例如:MiniCPM 4.0、Qwen4
validations:
required: true
- type: input
id: model-source
attributes:
label: 模型来源
description: 请提供模型的官方链接或Hugging Face链接
placeholder: 例如:https://huggingface.co/Qwen/Qwen3-14B
validations:
required: true
- type: textarea
id: tutorial-type
attributes:
label: 希望的教程类型
description: 请描述您希望的教程类型(如果是新增教程请求)
placeholder: |
例如:
- FastAPI 部署调用
- WebDemo 部署
- Langchain 接入
- LoRA 微调
- vLLM 部署调用
- 全量微调
validations:
required: false
- type: textarea
id: model-description
attributes:
label: 模型描述
description: 请简要描述该模型的特点和用途
placeholder: 请描述模型的主要特性、参数规模、适用场景等
validations:
required: true
- type: textarea
id: use-case
attributes:
label: 使用场景
description: 请描述您计划如何使用这个模型
placeholder: 例如:用于对话系统、代码生成、文本分析等
validations:
required: true
- type: textarea
id: technical-requirements
attributes:
label: 技术要求
description: 请描述模型的技术要求(如果已知)
placeholder: |
例如:
- 最低GPU显存要求
- 推荐的硬件配置
- 特殊的依赖库
- 许可证要求
validations:
required: false
- type: checkboxes
id: contribution-willingness
attributes:
label: 贡献意愿
description: 请选择您的参与意愿
options:
- label: 我愿意协助编写相关教程
required: false
- label: 我愿意提供测试和反馈
required: false
- label: 我愿意分享使用经验
required: false
- type: input
id: contact-info
attributes:
label: 联系方式(可选)
description: 如果您愿意参与贡献,请提供联系方式
placeholder: 例如:GitHub用户名、邮箱等
validations:
required: false
- type: textarea
id: additional-info
attributes:
label: 其他信息
description: 请提供任何其他相关信息
placeholder: 包括相关资料链接、参考文档等
validations:
required: false
+176
View File
@@ -0,0 +1,176 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
.idea/
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
.history
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.DS_Store
.obsidian
# self-llm/models/BGE-M3-finetune-embedding-with-valid
./models/BGE-M3-finetune-embedding-with-valid/bge-m3
./models/BGE-M3-finetune-embedding-with-valid/models
./models/BGE-M3-finetune-embedding-with-valid/sanitized-mbpp.json
./models/BGE-M3-finetune-embedding-with-valid/mbpp.jsonl
./models/BGE-M3-finetune-embedding-with-valid/mbpp_val.jsonl
./models/BGE-M3-finetune-embedding-with-valid/mbpp_train.jsonl
./models/BGE-M3-finetune-embedding-with-valid/c_mteb_results
# model_mlx
models_mlx/models
.vscode
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+310
View File
@@ -0,0 +1,310 @@
<div align=center>
<img src="./images/head-img.png" >
<h1>开源大模型食用指南</h1>
</div>
<div align="center">
中文 | [English](./README_en.md)
</div>
&emsp;&emsp;本项目是一个围绕开源大模型、针对国内初学者、基于 Linux 平台的中国宝宝专属大模型教程,针对各类开源大模型提供包括环境配置、本地部署、高效微调等技能在内的全流程指导,简化开源大模型的部署、使用和应用流程,让更多的普通学生、研究者更好地使用开源大模型,帮助开源、自由的大模型更快融入到普通学习者的生活中。
&emsp;&emsp;本项目的主要内容包括:
1. 基于 Linux 平台的开源 LLM 环境配置指南,针对不同模型要求提供不同的详细环境配置步骤;
2. 针对国内外主流开源 LLM 的部署使用教程,包括 LLaMA、ChatGLM、InternLM 等;
3. 开源 LLM 的部署应用指导,包括命令行调用、在线 Demo 部署、LangChain 框架集成等;
4. 开源 LLM 的全量微调、高效微调方法,包括分布式全量微调、LoRA、ptuning 等。
&emsp;&emsp;**项目的主要内容就是教程,让更多的学生和未来的从业者了解和熟悉开源大模型的食用方法!任何人都可以提出issue或是提交PR,共同构建维护这个项目。**
&emsp;&emsp;想要深度参与的同学可以联系我们,我们会将你加入到项目的维护者中。
> &emsp;&emsp;***学习建议:本项目的学习建议是,先学习环境配置,然后再学习模型的部署使用,最后再学习微调。因为环境配置是基础,模型的部署使用是基础,微调是进阶。初学者可以选择Qwen1.5InternLM2MiniCPM等模型优先学习。***
> &emsp;&emsp;**进阶学习推荐** :如果您在学习完本项目后,希望更深入地理解大语言模型的核心原理,并渴望亲手从零开始训练属于自己的大模型,我们强烈推荐关注 Datawhale 的另一个开源项目—— [Happy-LLM 从零开始的大语言模型原理与实践教程](https://github.com/datawhalechina/happy-llm) 。该项目将带您深入探索大模型的底层机制,掌握完整的训练流程。
> 注:如果有同学希望了解大模型的模型构成,以及从零手写RAG、Agent和Eval等任务,可以学习Datawhale的另一个项目[Tiny-Universe](https://github.com/datawhalechina/tiny-universe),大模型是当下深度学习领域的热点,但现有的大部分大模型教程只在于教给大家如何调用api完成大模型的应用,而很少有人能够从原理层面讲清楚模型结构、RAG、Agent 以及 Eval。所以该仓库会提供全部手写,不采用调用api的形式,完成大模型的 RAG 、 Agent 、Eval 任务。
> 注:考虑到有同学希望在学习本项目之前,希望学习大模型的理论部分,如果想要进一步深入学习 LLM 的理论基础,并在理论的基础上进一步认识、应用 LLM,可以参考 Datawhale 的 [so-large-llm](https://github.com/datawhalechina/so-large-lm.git)课程。
> 注:如果有同学在学习本课程之后,想要自己动手开发大模型应用。同学们可以参考 Datawhale 的 [动手学大模型应用开发](https://github.com/datawhalechina/llm-universe) 课程,该项目是一个面向小白开发者的大模型应用开发教程,旨在基于阿里云服务器,结合个人知识库助手项目,向同学们完整的呈现大模型应用开发流程。
## 项目意义
&emsp;&emsp;什么是大模型?
>大模型(LLM)狭义上指基于深度学习算法进行训练的自然语言处理(NLP)模型,主要应用于自然语言理解和生成等领域,广义上还包括机器视觉(CV)大模型、多模态大模型和科学计算大模型等。
&emsp;&emsp;百模大战正值火热,开源 LLM 层出不穷。如今国内外已经涌现了众多优秀开源 LLM,国外如 LLaMA、Alpaca,国内如 ChatGLM、BaiChuan、InternLM(书生·浦语)等。开源 LLM 支持用户本地部署、私域微调,每一个人都可以在开源 LLM 的基础上打造专属于自己的独特大模型。
&emsp;&emsp;然而,当前普通学生和用户想要使用这些大模型,需要具备一定的技术能力,才能完成模型的部署和使用。对于层出不穷又各有特色的开源 LLM,想要快速掌握一个开源 LLM 的应用方法,是一项比较有挑战的任务。
&emsp;&emsp;本项目旨在首先基于核心贡献者的经验,实现国内外主流开源 LLM 的部署、使用与微调教程;在实现主流 LLM 的相关部分之后,我们希望充分聚集共创者,一起丰富这个开源 LLM 的世界,打造更多、更全面特色 LLM 的教程。星火点点,汇聚成海。
&emsp;&emsp;***我们希望成为 LLM 与普罗大众的阶梯,以自由、平等的开源精神,拥抱更恢弘而辽阔的 LLM 世界。***
## 项目受众
&emsp;&emsp;本项目适合以下学习者:
* 想要使用或体验 LLM,但无条件获得或使用相关 API;
* 希望长期、低成本、大量应用 LLM;
* 对开源 LLM 感兴趣,想要亲自上手开源 LLM;
* NLP 在学,希望进一步学习 LLM;
* 希望结合开源 LLM,打造领域特色的私域 LLM;
* 以及最广大、最普通的学生群体。
## 项目规划及进展
&emsp;&emsp; 本项目拟围绕开源 LLM 应用全流程组织,包括环境配置及使用、部署应用、微调等,每个部分覆盖主流及特点开源 LLM:
### Example 系列
- [Chat-嬛嬛](./examples/Chat-嬛嬛/readme.md): Chat-甄嬛是利用《甄嬛传》剧本中所有关于甄嬛的台词和语句,基于LLM进行LoRA微调得到的模仿甄嬛语气的聊天语言模型。
- [Tianji-天机](./examples/Tianji-天机/readme.md):天机是一款基于人情世故社交场景,涵盖提示词工程 、智能体制作、 数据获取与模型微调、RAG 数据清洗与使用等全流程的大语言模型系统应用教程。
- [AMChat](./examples/AMchat-高等数学/readme.md): AM (Advanced Mathematics) chat 是一个集成了数学知识和高等数学习题及其解答的大语言模型。该模型使用 Math 和高等数学习题及其解析融合的数据集,基于 InternLM2-Math-7B 模型,通过 xtuner 微调,专门设计用于解答高等数学问题。
- [数字生命](./examples/数字生命/readme.md): 本项目将以我为原型,利用特制的数据集对大语言模型进行微调,致力于创造一个能够真正反映我的个性特征的AI数字人——包括但不限于我的语气、表达方式和思维模式等等,因此无论是日常聊天还是分享心情,它都以一种既熟悉又舒适的方式交流,仿佛我在他们身边一样。整个流程是可迁移复制的,亮点是数据集的制作。
### 已支持模型
<p align="center">
<strong>✨ 已支持 50+ 主流大语言模型 ✨</strong><br>
<em>每个模型都提供完整的部署、微调和使用教程</em><br>
📖 <strong><a href="./support_model.md">查看完整模型列表和教程</a></strong> |
🎯 <strong><a href="./support_model.md#通用环境配置">快速开始</a></strong>
</p>
<table align="center">
<tr>
<td valign="top" width="25%">
• <a href="./support_model.md#minicpm5">MiniCPM5</a><br>
• <a href="./support_model.md#qwen35">Qwen3.5</a><br>
• <a href="./support_model.md#kimi-k25">Kimi-K2.5</a><br>
• <a href="./support_model.md#step-35-flash">Step-3.5-Flash</a><br>
• <a href="./support_model.md#glm-47-flash">GLM-4.7-Flash</a><br>
• <a href="./support_model.md#gemma3">Gemma3</a><br>
• <a href="./support_model.md#minimax-m3">MiniMax-M3</a><br>
• <a href="./support_model.md#minimax-m25">MiniMax-M2.5</a><br>
• <a href="./support_model.md#minimax-m2">MiniMax-M2</a><br>
• <a href="./support_model.md#qwen3">Qwen3</a><br>
• <a href="./support_model.md#qwen3-vl-4b-instruct">Qwen3-VL</a><br>
• <a href="./support_model.md#spatiallm">SpatialLM</a><br>
• <a href="./support_model.md#hunyuan3d-2">Hunyuan3D-2</a><br>
• <a href="./support_model.md#qwen2-vl">Qwen2-VL</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#minicpm-o-2_6">MiniCPM-o</a><br>
• <a href="./support_model.md#qwen25-coder">Qwen2.5-Coder</a><br>
• <a href="./support_model.md#deepseek-coder-v2">DeepSeek-Coder-V2</a><br>
• <a href="./support_model.md#gpt-oss-20b">gpt-oss-20b</a><br>
• <a href="./support_model.md#glm-41-thinking">GLM-4.1-Thinking</a><br>
• <a href="./support_model.md#deepseek-r1-distill">DeepSeek-R1</a><br>
• <a href="./support_model.md#internlm3">InternLM3</a><br>
• <a href="./support_model.md#phi4">phi4</a><br>
• <a href="./support_model.md#glm-45-air">GLM-4.5-Air</a><br>
• <a href="./support_model.md#hunyuan-a13b-instruct">Hunyuan-A13B</a><br>
• <a href="./support_model.md#deepseek-深度求索">DeepSeek</a><br>
• <a href="./support_model.md#baichuan-百川智能">Baichuan</a><br>
• <a href="./support_model.md#internlm">InternLM</a><br>
• <a href="./support_model.md#kimi">Kimi</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#ernie-45">ERNIE-4.5</a><br>
• <a href="./support_model.md#llama4">Llama4</a><br>
• <a href="./support_model.md#apple-openelm">Apple OpenELM</a><br>
• <a href="./support_model.md#llama31-8b-instruct">Llama3.1</a><br>
• <a href="./support_model.md#gemma-2-9b-it">Gemma-2</a><br>
• <a href="./support_model.md#qwen25">Qwen2.5</a><br>
• <a href="./support_model.md#qwen2">Qwen2</a><br>
• <a href="./support_model.md#glm-4">GLM-4</a><br>
• <a href="./support_model.md#qwen-15">Qwen 1.5</a><br>
• <a href="./support_model.md#phi-3">phi-3</a><br>
• <a href="./support_model.md#minicpm">MiniCPM</a><br>
• <a href="./support_model.md#yi-零一万物">Yi 零一万物</a><br>
• <a href="./support_model.md#yuan20">Yuan2.0</a><br>
• <a href="./support_model.md#yuan20-m32">Yuan2.0-M32</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#哔哩哔哩-index-19b">哔哩哔哩 Index</a><br>
• <a href="./support_model.md#characterglm-6b">CharacterGLM</a><br>
• <a href="./support_model.md#bluelm-vivo-蓝心大模型">BlueLM</a><br>
• <a href="./support_model.md#qwen-audio">Qwen-Audio</a><br>
• <a href="./support_model.md#transnormerllm">TransNormerLLM</a><br>
• <a href="./support_model.md#atom-llama2">Atom</a><br>
• <a href="./support_model.md#chatglm3">ChatGLM3</a><br>
• <a href="./support_model.md#qwen2-57b-a14b-instruct">Qwen2-57B-A14B-Instruct</a><br>
• <a href="./support_model.md#qwen2-72b-instruct">Qwen2-72B-Instruct</a><br>
• <a href="./support_model.md#qwen2-7b-instruct">Qwen2-7B-Instruct</a><br>
• <a href="./support_model.md#internlm2-20b">InternLM2-20B</a><br>
• <a href="./support_model.md#tele-chat">Tele-Chat</a><br>
• <a href="./support_model.md#xverse2">XVERSE2</a>
</td>
</tr>
</table>
### AMD GPU 专区
<p align="center">
<strong>🚀 AMD GPU 平台已支持模型</strong><br>
<em>每个模型都提供完整的 AMD 环境配置和部署教程</em><br>
<em>感谢 AMD University Program 对本项目的支持</em><br>
📖 <strong><a href="./support_model_amd.md">查看完整 AMD 平台模型列表和教程</a></strong><br>
</p>
<table align="center">
<tr>
<td valign="top" width="50%">
• <a href="./support_model_amd.md#谷歌-gemma3">谷歌 Gemma3</a><br>
• AMD 环境准备与配置<br>
• NPU 推理加速支持
</td>
<td valign="top" width="50%">
• <a href="./support_model_amd.md#qwen3">Qwen3</a><br>
• lemonade-server SDK 部署<br>
• Ryzen AI 300 系列优化
</td>
</tr>
</table>
### 昇腾Ascend NPU 专区
<p align="center">
<strong>🚀 昇腾Ascend NPU 平台已支持模型</strong><br>
<em>每个模型都提供完整的昇腾Ascend NPU 环境配置和部署教程</em><br>
📖 <strong><a href="./support_model_Ascend.md">查看完整昇腾 NPU 平台模型列表和教程</a></strong><br>
</p>
<table align="center">
<tr>
<td valign="top" width="30%">
• <a href="./support_model_Ascend.md#qwen3536">Qwen3.6</a><br>
• vLLM-ascend 部署调用
</td>
<td valign="top" width="30%">
• <a href="./support_model_Ascend.md#qwen3">Qwen3</a><br>
• Ascend NPU 环境配置通用指南<br>
• MindIE 服务化部署调用<br>
• vLLM-ascend 部署调用<br>
• sglang-ascend 部署调用
</td>
<td valign="top" width="40%">
• <a href="./support_model_Ascend.md#大模型服务化性能和精度测试">大模型服务化性能和精度测试</a><br>
• AISBench 测试工具环境配置<br>
• 昇腾大模型服务化性能测试<br>
• 昇腾大模型服务化精度测试
</td>
</tr>
</table>
### 沐曦专区
<p align="center">
<strong><em>Coming Soon!</em></strong>
</p>
### Apple M 专区
<p align="center">
📖 <strong><a href="./models_mlx/README.md">点击跳转 Apple M 专区</a></strong><br>
</p>
### Welcome More Platforms!
- 🚀 即将支持更多平台(Apple M 系列已有设备测试),敬请期待!
- 🤝 欢迎昇腾 Ascend、摩尔线程 MUSA、沐曦等平台提供技术支持、硬件支持或参与贡献
- 🌟 欢迎各平台开发者共建共享,推动大模型技术在更多国产硬件生态中的繁荣发展!
## 致谢
### 核心贡献者
- [宋志学(不要葱姜蒜)-项目负责人](https://github.com/KMnO4-zx) Datawhale成员)
- [邹雨衡-项目负责人](https://github.com/logan-zou) Datawhale成员-对外经济贸易大学)
- [刘十一-Ascend专区负责人](https://github.com/Zhiwen-Liu)Datawhale成员-鲸英助教)
- [姜舒凡](https://github.com/Tsumugii24)(内容创作者-Datawhale成员)
- [郭宣伯](https://github.com/Twosugar666)(内容创作者-北京航空航天大学)
- [林泽毅](https://github.com/Zeyi-Lin)(内容创作者-SwanLab产品负责人)
- [林恒宇](https://github.com/LINHYYY)(内容创作者-广东东软学院-鲸英助教)
- [王泽宇](https://github.com/moyitech)(内容创作者-太原理工大学-鲸英助教)
- [郭志航](https://github.com/acwwt)(内容创作者)
- [陈榆](https://github.com/LucaChen)(内容创作者-谷歌开发者机器学习技术专家)
- [肖鸿儒](https://github.com/Hongru0306) Datawhale成员-同济大学)
- [张帆](https://github.com/zhangfanTJU)(内容创作者-Datawhale成员)
- [李娇娇](https://github.com/Aphasia0515) Datawhale成员)
- [高立业](https://github.com/0-yy-0)(内容创作者-DataWhale成员)
- [Kailigithub](https://github.com/Kailigithub) Datawhale成员)
- [丁悦](https://github.com/dingyue772) Datawhale-鲸英助教)
- [谢好冉](https://github.com/ilovexsir)(内容创作者-鲸英助教)
- [惠佳豪](https://github.com/L4HeyXiao) Datawhale-宣传大使)
- [王茂霖](https://github.com/mlw67)(内容创作者-Datawhale成员)
- [孙健壮](https://github.com/Caleb-Sun-jz)(内容创作者-对外经济贸易大学)
- [郑皓桦](https://github.com/BaiYu96) (内容创作者)
- [荞麦](https://github.com/yeyeyeyeeeee)(内容创作者-Datawhale成员)
- [骆秀韬](https://github.com/anine09)(内容创作者-Datawhale成员-似然实验室)
- [李柯辰](https://github.com/Joe-2002) Datawhale成员)
- [程宏](https://github.com/chg0901)(内容创作者-Datawhale意向成员)
- [李秀奇](https://github.com/li-xiu-qi)(内容创作者-DataWhale意向成员)
- [余洋](https://github.com/YangYu-NUAA)(内容创作者-安徽理工大学副教授-Datawhale成员)
- [陈思州](https://github.com/jjyaoao) Datawhale成员)
- [颜鑫](https://github.com/thomas-yanxin) Datawhale成员)
- [杜森](https://github.com/study520ai520)(内容创作者-Datawhale成员-南阳理工学院)
- [散步](https://github.com/sanbuphy) Datawhale成员)
- [郑远婧](https://github.com/isaacahahah)(内容创作者-鲸英助教-福州大学)
- [Swiftie](https://github.com/cswangxiaowei) (小米NLP算法工程师)
- [张友东](https://github.com/AXYZdong)(内容创作者-Datawhale成员)
- [张晋](https://github.com/Jin-Zhang-Yaoguang)(内容创作者-Datawhale成员)
- [娄天奥](https://github.com/lta155)(内容创作者-中国科学院大学-鲸英助教)
- [小罗](https://github.com/lyj11111111) (内容创作者-Datawhale成员)
- [邓恺俊](https://github.com/Kedreamix)(内容创作者-Datawhale成员)
- [赵文恺](https://github.com/XiLinky)(内容创作者-太原理工大学-鲸英助教)
- [王熠明](https://github.com/Bald0Wang)(内容创作者-Datawhale成员)
- [黄柏特](https://github.com/KashiwaByte)(内容创作者-西安电子科技大学)
- [左春生](https://github.com/LinChentang)(内容创作者-Datawhale成员)
- [杨卓](https://github.com/little1d)(内容创作者-西安电子科技大学-鲸英助教)
- [付志远](https://github.com/comfzy)(内容创作者-海南大学)
- [三水](https://github.com/sssanssss)(内容创作者-鲸英助教)
- [樊奇](https://github.com/fanqiNO1)(内容创作者-上海交通大学)
- [陈辅元](https://github.com/Fyuan0206)(内容创作者-Datawhale成员)
- [谭逸珂](https://github.com/LikeGiver)(内容创作者-对外经济贸易大学)
- [何至轩](https://github.com/pod2c)(内容创作者-鲸英助教)
- [康婧淇](https://github.com/jodie-kang)(内容创作者-Datawhale成员)
- [杨晨旭](https://github.com/langlibai66)(内容创作者-太原理工大学-鲸英助教)
- [赵伟](https://github.com/2710932616)(内容创作者-鲸英助教)
- [苏向标](https://github.com/gzhuuser)(内容创作者-广州大学-鲸英助教)
- [陈睿](https://github.com/riannyway)(内容创作者-西交利物浦大学-鲸英助教)
- [张龙斐](https://github.com/Feimike09)(内容创作者-鲸英助教)
- [孙超](https://github.com/anarchysaiko)(内容创作者-Datawhale成员)
- [卓堂越](https://github.com/nusakom)(内容创作者-鲸英助教)
- [fancy](https://github.com/fancyboi999)(内容创作者-鲸英助教)
- [谭斐然](https://github.com/frtanxidian)(西安电子科技大学-鲸英助教)
> 注:排名根据贡献程度排序
### 其他
- 特别感谢[@Sm1les](https://github.com/Sm1les)对本项目的帮助与支持
- 感谢 AMD University Program 对本项目的支持
- 部分lora代码和讲解参考仓库:https://github.com/zyds/transformers-code.git
- 如果有任何想法可以联系我们 DataWhale 也欢迎大家多多提出 issue
- 特别感谢以下为教程做出贡献的同学!
<div align=center style="margin-top: 30px;">
<a href="https://github.com/datawhalechina/self-llm/graphs/contributors">
<img src="https://contrib.rocks/image?repo=datawhalechina/self-llm" />
</a>
</div>
### Star History
<div align=center style="margin-top: 30px;">
<img src="./images/star-history-20251220.png"/>
</div>
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`datawhalechina/self-llm`
- 原始仓库:https://github.com/datawhalechina/self-llm
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+302
View File
@@ -0,0 +1,302 @@
<div align=center>
<img src="./images/head-img.png" >
<h1>Open Source Large Model Usage Guide</h1>
</div>
<div align="center">
[中文](./README.md) | English
</div>
&emsp;&emsp;This project is a Chinese baby's exclusive large model tutorial based on the Linux platform, focusing on open source large models for domestic beginners. It provides full-process guidance including environment configuration, local deployment, and efficient fine-tuning for various open source large models. It simplifies the deployment, usage, and application processes of open source large models, enabling more ordinary students and researchers to better use open source large models, and helping open source and free large models to integrate into the lives of ordinary learners faster.
&emsp;&emsp;The main contents of this project include:
1. Open source LLM environment configuration guide based on Linux platform, providing different detailed environment configuration steps according to different model requirements;
2. Deployment and usage tutorials for mainstream open source LLMs at home and abroad, including LLaMA, ChatGLM, InternLM, etc.;
3. Open source LLM deployment and application guidance, including command-line invocation, online Demo deployment, LangChain framework integration, etc.;
4. Full fine-tuning and efficient fine-tuning methods for open source LLMs, including distributed full fine-tuning, LoRA, ptuning, etc.
&emsp;&emsp;**The main content of this project is tutorials, letting more students and future practitioners understand and become familiar with the usage methods of open source large models! Anyone can raise issues or submit PRs to jointly build and maintain this project.**
&emsp;&emsp;Students who want to participate deeply can contact us, and we will add you to the project maintainers.
> &emsp;&emsp;***Learning suggestions: The learning suggestion for this project is to first learn environment configuration, then learn model deployment and usage, and finally learn fine-tuning. Because environment configuration is the foundation, model deployment and usage are the basics, and fine-tuning is advanced. Beginners can choose models like Qwen1.5, InternLM2, MiniCPM, etc. for priority learning.***
> &emsp;&emsp;**Advanced Learning Recommendation**: After studying this project, if you wish to understand the core principles of large language models more deeply and desire to train your own large model from scratch, we highly recommend focusing on another open source project from Datawhale — [Happy-LLM: A Beginner's Guide to Large Language Model Principles and Practice from Scratch](https://github.com/datawhalechina/happy-llm). This project will take you deep into exploring the underlying mechanisms of large models and mastering the complete training process.
> Note: If some students want to understand the model composition of large models and write RAG, Agent, and Eval tasks from scratch, they can learn from another Datawhale project [Tiny-Universe](https://github.com/datawhalechina/tiny-universe). Large models are currently a hot topic in the deep learning field, but most existing large model tutorials only teach how to call APIs to complete large model applications. Few people can clearly explain model structures, RAG, Agent, and Eval from a principled perspective. Therefore, this repository will provide all handwritten content without using API calls to complete RAG, Agent, and Eval tasks for large models.
> Note: Considering that some students hope to learn the theoretical part of large models before studying this project, if they want to further learn the theoretical foundation of LLM and further understand and apply LLM based on theory, they can refer to Datawhale's [so-large-llm](https://github.com/datawhalechina/so-large-lm.git) course.
> Note: If students want to develop large model applications themselves after studying this course. Students can refer to Datawhale's [Hands-on Large Model Application Development](https://github.com/datawhalechina/llm-universe) course. This project is a large model application development tutorial for novice developers, aiming to present the complete large model application development process to students based on Alibaba Cloud servers combined with a personal knowledge base assistant project.
## Project Significance
&emsp;&emsp;What are large models?
>Large models (LLM) narrowly refer to natural language processing (NLP) models trained based on deep learning algorithms, mainly applied in fields such as natural language understanding and generation. Broadly, they also include computer vision (CV) large models, multimodal large models, and scientific computing large models.
&emsp;&emsp;The "Hundred Models Battle" is in full swing, and open source LLMs are emerging endlessly. Today, many excellent open source LLMs have emerged both domestically and internationally, such as LLaMA and Alpaca abroad, and ChatGLM, BaiChuan, InternLM (Shusheng·Puyu) domestically. Open source LLMs support local deployment and private fine-tuning, allowing everyone to create their own unique large model based on open source LLMs.
&emsp;&emsp;However, for ordinary students and users to use these large models, certain technical capabilities are required to complete model deployment and usage. For the numerous and distinctive open source LLMs, it is a challenging task to quickly master the application methods of an open source LLM.
&emsp;&emsp;This project aims to first implement deployment, usage, and fine-tuning tutorials for mainstream open source LLMs at home and abroad based on the experience of core contributors. After implementing relevant parts for mainstream LLMs, we hope to fully gather co-creators to enrich this open source LLM world and create more comprehensive tutorials for characteristic LLMs. Sparks gather to form a sea.
&emsp;&emsp;***We hope to become a ladder between LLMs and the general public, embracing a more magnificent and vast LLM world with a spirit of freedom and equality in open source.***
## Target Audience
&emsp;&emsp;This project is suitable for the following learners:
* Students who want to use or experience LLMs but have no conditions to obtain or use relevant APIs;
* Students who hope to apply LLMs long-term, low-cost, and in large quantities;
* Students interested in open source LLMs and want to personally work with open source LLMs;
* NLP students who hope to further study LLMs;
* Students who hope to combine open source LLMs to create domain-specific private LLMs;
* And the largest and most ordinary student population.
## Project Planning and Progress
&emsp;&emsp;This project is organized around the entire process of open source LLM application, including environment configuration and usage, deployment applications, fine-tuning, etc. Each part covers mainstream and characteristic open source LLMs:
### Example Series
- [Chat-Huanhuan](./examples/Chat-嬛嬛/readme.md): Chat-Zhenhuan is a chat language model that imitates Zhenhuan's tone, obtained by LoRA fine-tuning based on LLM using all lines and dialogues about Zhenhuan from the "Legend of Zhenhuan" script.
- [Tianji](./examples/Tianji-天机/readme.md): Tianji is a comprehensive large language model system application tutorial covering social scenarios based on interpersonal relationships, including prompt engineering, intelligent agent creation, data acquisition and model fine-tuning, RAG data cleaning and usage, etc.
- [AMChat](./examples/AMchat-高等数学/readme.md): AM (Advanced Mathematics) chat is a large language model that integrates mathematical knowledge and advanced mathematics exercises and their solutions. This model uses a dataset fused with mathematics and advanced mathematics exercises and their analysis, based on the InternLM2-Math-7B model, fine-tuned through xtuner, specifically designed to answer advanced mathematics problems.
- [Digital Life](./examples/数字生命/readme.md): This project will use me as a prototype, utilizing a specially crafted dataset to fine-tune a large language model, dedicated to creating an AI digital persona that can truly reflect my personality traits—including but not limited to my tone, expression patterns, and thinking modes. Therefore, whether it's daily chat or sharing emotions, it communicates in a familiar and comfortable way, as if I were right there with them. The entire process is transferable and replicable, with dataset creation as the highlight.
### Supported Models
<p align="center">
<strong>✨ 50+ Mainstream Large Language Models Supported ✨</strong><br>
<em>Each model provides complete deployment, fine-tuning, and usage tutorials</em><br>
📖 <strong><a href="./support_model.md">View complete model list and tutorials</a></strong> |
🎯 <strong><a href="#通用环境配置">Quick Start</a></strong>
</p>
<table align="center">
<tr>
<td valign="top" width="25%">
• <a href="./support_model.md#minicpm5">MiniCPM5</a><br>
• <a href="./support_model.md#qwen35">Qwen3.5</a><br>
• <a href="./support_model.md#kimi-k25">Kimi-K2.5</a><br>
• <a href="./support_model.md#step-35-flash">Step-3.5-Flash</a><br>
• <a href="./support_model.md#glm-47-flash">GLM-4.7-Flash</a><br>
• <a href="./support_model.md#gemma3">Gemma3</a><br>
• <a href="./support_model.md#minimax-m3">MiniMax-M3</a><br>
• <a href="./support_model.md#minimax-m25">MiniMax-M2.5</a><br>
• <a href="./support_model.md#minimax-m2">MiniMax-M2</a><br>
• <a href="./support_model.md#qwen3">Qwen3</a><br>
• <a href="./support_model.md#qwen3-vl-4b-instruct">Qwen3-VL</a><br>
• <a href="./support_model.md#spatiallm">SpatialLM</a><br>
• <a href="./support_model.md#hunyuan3d-2">Hunyuan3D-2</a><br>
• <a href="./support_model.md#qwen2-vl">Qwen2-VL</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#minicpm-o-2_6">MiniCPM-o</a><br>
• <a href="./support_model.md#qwen25-coder">Qwen2.5-Coder</a><br>
• <a href="./support_model.md#deepseek-coder-v2">DeepSeek-Coder-V2</a><br>
• <a href="./support_model.md#gpt-oss-20b">gpt-oss-20b</a><br>
• <a href="./support_model.md#glm-41-thinking">GLM-4.1-Thinking</a><br>
• <a href="./support_model.md#deepseek-r1-distill">DeepSeek-R1</a><br>
• <a href="./support_model.md#internlm3">InternLM3</a><br>
• <a href="./support_model.md#phi4">phi4</a><br>
• <a href="./support_model.md#glm-45-air">GLM-4.5-Air</a><br>
• <a href="./support_model.md#hunyuan-a13b-instruct">Hunyuan-A13B</a><br>
• <a href="./support_model.md#deepseek-深度求索">DeepSeek</a><br>
• <a href="./support_model.md#baichuan-百川智能">Baichuan</a><br>
• <a href="./support_model.md#internlm">InternLM</a><br>
• <a href="./support_model.md#kimi">Kimi</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#ernie-45">ERNIE-4.5</a><br>
• <a href="./support_model.md#llama4">Llama4</a><br>
• <a href="./support_model.md#apple-openelm">Apple OpenELM</a><br>
• <a href="./support_model.md#llama31-8b-instruct">Llama3.1</a><br>
• <a href="./support_model.md#gemma-2-9b-it">Gemma-2</a><br>
• <a href="./support_model.md#qwen25">Qwen2.5</a><br>
• <a href="./support_model.md#qwen2">Qwen2</a><br>
• <a href="./support_model.md#glm-4">GLM-4</a><br>
• <a href="./support_model.md#qwen-15">Qwen 1.5</a><br>
• <a href="./support_model.md#phi-3">phi-3</a><br>
• <a href="./support_model.md#minicpm">MiniCPM</a><br>
• <a href="./support_model.md#yi-零一万物">Yi 零一万物</a><br>
• <a href="./support_model.md#yuan20">Yuan2.0</a><br>
• <a href="./support_model.md#yuan20-m32">Yuan2.0-M32</a>
</td>
<td valign="top" width="25%">
• <a href="./support_model.md#哔哩哔哩-index-19b">Bilibili Index</a><br>
• <a href="./support_model.md#characterglm-6b">CharacterGLM</a><br>
• <a href="./support_model.md#bluelm-vivo-蓝心大模型">BlueLM</a><br>
• <a href="./support_model.md#qwen-audio">Qwen-Audio</a><br>
• <a href="./support_model.md#transnormerllm">TransNormerLLM</a><br>
• <a href="./support_model.md#atom-llama2">Atom</a><br>
• <a href="./support_model.md#chatglm3">ChatGLM3</a><br>
• <a href="./support_model.md#qwen2-57b-a14b-instruct">Qwen2-57B-A14B-Instruct</a><br>
• <a href="./support_model.md#qwen2-72b-instruct">Qwen2-72B-Instruct</a><br>
• <a href="./support_model.md#qwen2-7b-instruct">Qwen2-7B-Instruct</a><br>
• <a href="./support_model.md#internlm2-20b">InternLM2-20B</a><br>
• <a href="./support_model.md#tele-chat">Tele-Chat</a><br>
• <a href="./support_model.md#xverse2">XVERSE2</a>
</td>
</tr>
</table>
### AMD GPU Section
<p align="center">
<strong>🚀 AMD GPU Platform Supported Models</strong><br>
<em>Each model provides complete AMD environment configuration and deployment tutorials</em><br>
<em>Thanks to AMD University Program for supporting this project</em><br>
📖 <strong><a href="./support_model_amd.md">View complete AMD platform model list and tutorials</a></strong><br>
</p>
<table align="center">
<tr>
<td valign="top" width="50%">
• <a href="./support_model_amd.md#谷歌-gemma3">Google Gemma3</a><br>
• AMD Environment Preparation and Configuration<br>
• NPU Inference Acceleration Support
</td>
<td valign="top" width="50%">
• <a href="./support_model_amd.md#qwen3">Qwen3</a><br>
• lemonade-server SDK Deployment<br>
• Ryzen AI 300 Series Optimization
</td>
</tr>
</table>
### Ascend NPU Section
<p align="center">
<strong>🚀 Ascend NPU Platform Supported Models</strong><br>
<em>Each model provides complete Ascend NPU environment configuration and deployment tutorials</em><br>
📖 <strong><a href="./support_model_Ascend.md">View Complete Ascend NPU Platform Model List and Tutorials</a></strong><br>
</p>
<table align="center">
<tr>
<td valign="top" width="30%">
• <a href="./support_model_Ascend.md#qwen3536">Qwen3.6</a><br>
• vLLM-ascend Deployment and Invocation<br>
</td>
<td valign="top" width="30%">
• <a href="./support_model_Ascend.md#qwen3">Qwen3</a><br>
• Ascend NPU Environment Configuration General Guide<br>
• MindIE Service Deployment and Invocation<br>
• vLLM-ascend Deployment and Invocation<br>
• sglang-ascend Deployment and Invocation
</td>
<td valign="top" width="40%">
• <a href="./support_model_Ascend.md#大模型服务化性能和精度测试">LLM Service Performance and Accuracy Testing</a><br>
• AISBench Testing Tool Environment Configuration<br>
• Ascend LLM Service Performance Testing<br>
• Ascend LLM Service Accuracy Testing
</td>
</tr>
</table>
### Apple M Section
<p align="center">
📖 <strong><a href="./models_mlx/README_en.md">Click to go to Apple M Section</a></strong><br>
</p>
### Other Platforms ...
- 🚀 Coming soon: Support for more platforms (such as Apple M-series chips, etc.) environment configuration and model deployment tutorials, stay tuned!
- 🤝 We warmly welcome developers from all walks of life to contribute environment configuration and model deployment tutorials for different platforms, enabling large model technology to thrive on more hardware platforms!
## Acknowledgments
### Core Contributors
- [Song Zhixue (KMnO4-zx) - Project Leader](https://github.com/KMnO4-zx) (Datawhale Member)
- [Zou Yuheng - Project Leader](https://github.com/logan-zou) (Datawhale Member - University of International Business and Economics)
- [Jiang Shufan](https://github.com/Tsumugii24) (Content Creator - Datawhale Member)
- [Guo Xuanbo](https://github.com/Twosugar666) (Content Creator - Beihang University)
- [Lin Zeyi](https://github.com/Zeyi-Lin) (Content Creator - SwanLab Product Manager)
- [Lin Hengyu](https://github.com/LINHYYY) (Content Creator - Guangdong Neusoft Institute - Whale Elite Teaching Assistant)
- [Wang Zeyu](https://github.com/moyitech) (Content Creator - Taiyuan University of Technology - Whale Elite Teaching Assistant)
- [Guo Zhihang](https://github.com/acwwt) (Content Creator)
- [Chen Yu](https://github.com/LucaChen) (Content Creator - Google Developer Machine Learning Technical Expert)
- [Xiao Hongru](https://github.com/Hongru0306) (Datawhale Member - Tongji University)
- [Zhang Fan](https://github.com/zhangfanTJU) (Content Creator - Datawhale Member)
- [Li Jiaojiao](https://github.com/Aphasia0515) (Datawhale Member)
- [Gao Liye](https://github.com/0-yy-0) (Content Creator - DataWhale Member)
- [Kailigithub](https://github.com/Kailigithub) (Datawhale Member)
- [Ding Yue](https://github.com/dingyue772) (Datawhale - Whale Elite Teaching Assistant)
- [Hui Jiahao](https://github.com/L4HeyXiao) (Datawhale - Ambassador)
- [Wang Maolin](https://github.com/mlw67) (Content Creator - Datawhale Member)
- [Sun Jianzhuang](https://github.com/Caleb-Sun-jz) (Content Creator - University of International Business and Economics)
- [Zheng Haohua](https://github.com/BaiYu96) (Content Creator)
- [Qiaomai](https://github.com/yeyeyeyeeeee) (Content Creator - Datawhale Member)
- [Luo Xiutao](https://github.com/anine09) (Content Creator - Datawhale Member - Likelihood Lab)
- [Li Kechen](https://github.com/Joe-2002) (Datawhale Member)
- [Cheng Hong](https://github.com/chg0901) (Content Creator - Datawhale Prospective Member)
- [Xie Haoran](https://github.com/ilovexsir) (Content Creator - Whale Elite Teaching Assistant)
- [Li Xiuqi](https://github.com/li-xiu-qi) (Content Creator - DataWhale Prospective Member)
- [Chen Sizhou](https://github.com/jjyaoao) (Datawhale Member)
- [Yan Xin](https://github.com/thomas-yanxin) (Datawhale Member)
- [Du Sen](https://github.com/study520ai520) (Content Creator - Datawhale Member - Nanyang Institute of Technology)
- [Sanbu](https://github.com/sanbuphy) (Datawhale Member)
- [Swiftie](https://github.com/cswangxiaowei) (Xiaomi NLP Algorithm Engineer)
- [Zhang Youdong](https://github.com/AXYZdong) (Content Creator - Datawhale Member)
- [Zhang Jin](https://github.com/Jin-Zhang-Yaoguang) (Content Creator - Datawhale Member)
- [Lou Tian'ao](https://github.com/lta155) (Content Creator - University of Chinese Academy of Sciences - Whale Elite Teaching Assistant)
- [Xiao Luo](https://github.com/lyj11111111) (Content Creator - Datawhale Member)
- [Deng Kaijun](https://github.com/Kedreamix) (Content Creator - Datawhale Member)
- [Zhao Wenkai](https://github.com/XiLinky) (Content Creator - Taiyuan University of Technology - Whale Elite Teaching Assistant)
- [Wang Yiming](https://github.com/Bald0Wang) (Content Creator - Datawhale Member)
- [Huang Baite](https://github.com/KashiwaByte) (Content Creator - Xidian University)
- [Yu Yang](https://github.com/YangYu-NUAA) (Content Creator - Datawhale Member)
- [Zuo Chunsheng](https://github.com/LinChentang) (Content Creator - Datawhale Member)
- [Yang Zhuo](https://github.com/little1d) (Content Creator - Xidian University - Whale Elite Teaching Assistant)
- [Fu Zhiyuan](https://github.com/comfzy) (Content Creator - Hainan University)
- [Zheng Yuanjing](https://github.com/isaacahahah) (Content Creator - Whale Elite Teaching Assistant - Fuzhou University)
- [Tan Yike](https://github.com/LikeGiver) (Content Creator - University of International Business and Economics)
- [He Zhixuan](https://github.com/pod2c) (Content Creator - Whale Elite Teaching Assistant)
- [Kang Jingqi](https://github.com/jodie-kang) (Content Creator - Datawhale Member)
- [Sanshui](https://github.com/sssanssss) (Content Creator - Whale Elite Teaching Assistant)
- [Yang Chenxu](https://github.com/langlibai66) (Content Creator - Taiyuan University of Technology - Whale Elite Teaching Assistant)
- [Zhao Wei](https://github.com/2710932616) (Content Creator - Whale Elite Teaching Assistant)
- [Su Xiangbiao](https://github.com/gzhuuser) (Content Creator - Guangzhou University - Whale Elite Teaching Assistant)
- [Chen Rui](https://github.com/riannyway) (Content Creator - Xi'an Jiaotong-Liverpool University - Whale Elite Teaching Assistant)
- [Zhang Longfei](https://github.com/Feimike09) (Content Creator - Whale Elite Teaching Assistant)
- [Sun Chao](https://github.com/anarchysaiko) (Content Creator - Datawhale Member)
- [Fan Qi](https://github.com/fanqiNO1) (Content Creator - Shanghai Jiao Tong University)
- [Zhuo Tangyue](https://github.com/nusakom) (Content Creator - Whale Elite Teaching Assistant)
- [fancy](https://github.com/fancyboi999) (Content Creator - Whale Elite Teaching Assistant)
> Note: Ranking is based on contribution level
### Others
- Special thanks to [@Sm1les](https://github.com/Sm1les) for their help and support for this project
- Thanks to AMD University Program for supporting this project
- Some lora code and explanations reference repository: https://github.com/zyds/transformers-code.git
- If you have any ideas, you can contact DataWhale. We also welcome everyone to raise more issues
- Special thanks to the following students who contributed to the tutorials!
<div align=center style="margin-top: 30px;">
<a href="https://github.com/datawhalechina/self-llm/graphs/contributors">
<img src="https://contrib.rocks/image?repo=datawhalechina/self-llm" />
</a>
</div>
### Star History
<div align=center style="margin-top: 30px;">
<img src="./images/star-history-20251220.png"/>
</div>
+238
View File
@@ -0,0 +1,238 @@
{
"不要葱姜蒜": {
"info": "[宋志学(不要葱姜蒜)-项目负责人](https://github.com/KMnO4-zx) Datawhale成员)",
"task_num": 351
},
"Logan Zou": {
"info": "[邹雨衡-项目负责人](https://github.com/logan-zou) Datawhale成员-对外经济贸易大学)",
"task_num": 306
},
"刘十一": {
"info": "[刘十一-Ascend专区负责人](https://github.com/Zhiwen-Liu)Datawhale成员-鲸英助教)",
"task_num": 150
},
"姜舒凡": {
"info": "[姜舒凡](https://github.com/Tsumugii24)(内容创作者-Datawhale成员)",
"task_num": 18
},
"郭宣伯": {
"info": "[郭宣伯](https://github.com/Twosugar666)(内容创作者-北京航空航天大学)",
"task_num": 13
},
"林泽毅": {
"info": "[林泽毅](https://github.com/Zeyi-Lin)(内容创作者-SwanLab产品负责人)",
"task_num": 12
},
"林恒宇": {
"info": "[林恒宇](https://github.com/LINHYYY)(内容创作者-广东东软学院-鲸英助教)",
"task_num": 11
},
"王泽宇": {
"info": "[王泽宇](https://github.com/moyitech)(内容创作者-太原理工大学-鲸英助教)",
"task_num": 11
},
"郭志航": {
"info": "[郭志航](https://github.com/acwwt)(内容创作者)",
"task_num": 11
},
"陈榆": {
"info": "[陈榆](https://github.com/LucaChen)(内容创作者-谷歌开发者机器学习技术专家)",
"task_num": 11
},
"肖鸿儒": {
"info": "[肖鸿儒](https://github.com/Hongru0306) Datawhale成员-同济大学)",
"task_num": 11
},
"张帆": {
"info": "[张帆](https://github.com/zhangfanTJU)(内容创作者-Datawhale成员)",
"task_num": 9
},
"李娇娇": {
"info": "[李娇娇](https://github.com/Aphasia0515) Datawhale成员)",
"task_num": 8
},
"高立业": {
"info": "[高立业](https://github.com/0-yy-0)(内容创作者-DataWhale成员)",
"task_num": 8
},
"Kailigithub": {
"info": "[Kailigithub](https://github.com/Kailigithub) Datawhale成员)",
"task_num": 7
},
"丁悦": {
"info": "[丁悦](https://github.com/dingyue772) Datawhale-鲸英助教)",
"task_num": 6
},
"谢好冉": {
"info": "[谢好冉](https://github.com/ilovexsir)(内容创作者-鲸英助教)",
"task_num": 6
},
"惠佳豪": {
"info": "[惠佳豪](https://github.com/L4HeyXiao) Datawhale-宣传大使)",
"task_num": 5
},
"王茂霖": {
"info": "[王茂霖](https://github.com/mlw67)(内容创作者-Datawhale成员)",
"task_num": 5
},
"孙健壮": {
"info": "[孙健壮](https://github.com/Caleb-Sun-jz)(内容创作者-对外经济贸易大学)",
"task_num": 5
},
"郑皓桦": {
"info": "[郑皓桦](https://github.com/BaiYu96) (内容创作者)",
"task_num": 5
},
"荞麦": {
"info": "[荞麦](https://github.com/yeyeyeyeeeee)(内容创作者-Datawhale成员)",
"task_num": 5
},
"骆秀韬": {
"info": "[骆秀韬](https://github.com/anine09)(内容创作者-Datawhale成员-似然实验室)",
"task_num": 4
},
"李柯辰": {
"info": "[李柯辰](https://github.com/Joe-2002) Datawhale成员)",
"task_num": 4
},
"程宏": {
"info": "[程宏](https://github.com/chg0901)(内容创作者-Datawhale意向成员)",
"task_num": 4
},
"李秀奇": {
"info": "[李秀奇](https://github.com/li-xiu-qi)(内容创作者-DataWhale意向成员)",
"task_num": 4
},
"余洋": {
"info": "[余洋](https://github.com/YangYu-NUAA)(内容创作者-安徽理工大学副教授-Datawhale成员)",
"task_num": 4
},
"陈思州": {
"info": "[陈思州](https://github.com/jjyaoao) Datawhale成员)",
"task_num": 3
},
"颜鑫": {
"info": "[颜鑫](https://github.com/thomas-yanxin) Datawhale成员)",
"task_num": 3
},
"杜森": {
"info": "[杜森](https://github.com/study520ai520)(内容创作者-Datawhale成员-南阳理工学院)",
"task_num": 3
},
"散步": {
"info": "[散步](https://github.com/sanbuphy) Datawhale成员)",
"task_num": 3
},
"郑远婧": {
"info": "[郑远婧](https://github.com/isaacahahah)(内容创作者-鲸英助教-福州大学)",
"task_num": 3
},
"Swiftie": {
"info": "[Swiftie](https://github.com/cswangxiaowei) (小米NLP算法工程师)",
"task_num": 2
},
"张友东": {
"info": "[张友东](https://github.com/AXYZdong)(内容创作者-Datawhale成员)",
"task_num": 2
},
"张晋": {
"info": "[张晋](https://github.com/Jin-Zhang-Yaoguang)(内容创作者-Datawhale成员)",
"task_num": 2
},
"娄天奥": {
"info": "[娄天奥](https://github.com/lta155)(内容创作者-中国科学院大学-鲸英助教)",
"task_num": 2
},
"小罗": {
"info": "[小罗](https://github.com/lyj11111111) (内容创作者-Datawhale成员)",
"task_num": 2
},
"邓恺俊": {
"info": "[邓恺俊](https://github.com/Kedreamix)(内容创作者-Datawhale成员)",
"task_num": 2
},
"赵文恺": {
"info": "[赵文恺](https://github.com/XiLinky)(内容创作者-太原理工大学-鲸英助教)",
"task_num": 2
},
"王熠明": {
"info": "[王熠明](https://github.com/Bald0Wang)(内容创作者-Datawhale成员)",
"task_num": 2
},
"黄柏特": {
"info": "[黄柏特](https://github.com/KashiwaByte)(内容创作者-西安电子科技大学)",
"task_num": 2
},
"左春生": {
"info": "[左春生](https://github.com/LinChentang)(内容创作者-Datawhale成员)",
"task_num": 2
},
"杨卓": {
"info": "[杨卓](https://github.com/little1d)(内容创作者-西安电子科技大学-鲸英助教)",
"task_num": 2
},
"付志远": {
"info": "[付志远](https://github.com/comfzy)(内容创作者-海南大学)",
"task_num": 2
},
"三水": {
"info": "[三水](https://github.com/sssanssss)(内容创作者-鲸英助教)",
"task_num": 2
},
"樊奇": {
"info": "[樊奇](https://github.com/fanqiNO1)(内容创作者-上海交通大学)",
"task_num": 2
},
"陈辅元": {
"info": "[陈辅元](https://github.com/Fyuan0206)(内容创作者-Datawhale成员)",
"task_num": 2
},
"谭逸珂": {
"info": "[谭逸珂](https://github.com/LikeGiver)(内容创作者-对外经济贸易大学)",
"task_num": 1
},
"何至轩": {
"info": "[何至轩](https://github.com/pod2c)(内容创作者-鲸英助教)",
"task_num": 1
},
"康婧淇": {
"info": "[康婧淇](https://github.com/jodie-kang)(内容创作者-Datawhale成员)",
"task_num": 1
},
"杨晨旭": {
"info": "[杨晨旭](https://github.com/langlibai66)(内容创作者-太原理工大学-鲸英助教)",
"task_num": 1
},
"赵伟": {
"info": "[赵伟](https://github.com/2710932616)(内容创作者-鲸英助教)",
"task_num": 1
},
"苏向标": {
"info": "[苏向标](https://github.com/gzhuuser)(内容创作者-广州大学-鲸英助教)",
"task_num": 1
},
"陈睿": {
"info": "[陈睿](https://github.com/riannyway)(内容创作者-西交利物浦大学-鲸英助教)",
"task_num": 1
},
"张龙斐": {
"info": "[张龙斐](https://github.com/Feimike09)(内容创作者-鲸英助教)",
"task_num": 1
},
"孙超": {
"info": "[孙超](https://github.com/anarchysaiko)(内容创作者-Datawhale成员)",
"task_num": 1
},
"卓堂越": {
"info": "[卓堂越](https://github.com/nusakom)(内容创作者-鲸英助教)",
"task_num": 1
},
"fancy": {
"info": "[fancy](https://github.com/fancyboi999)(内容创作者-鲸英助教)",
"task_num": 1
},
"谭斐然": {
"info": "[谭斐然](https://github.com/frtanxidian)(西安电子科技大学-鲸英助教)",
"task_num": 1
}
}
+502
View File
@@ -0,0 +1,502 @@
[
{
"instruction": "娘娘。",
"input": "",
"output": "你放心,本宫到任何时候都不会自轻自贱委屈了这孩子。"
},
{
"instruction": "是皇上有心,惦记着咱们爱看戏。",
"input": "",
"output": "一早出来便这么热,到了午后还不知要什么样子呢。"
},
{
"instruction": "皇上驾到!",
"input": "",
"output": "皇上万福金安。"
},
{
"instruction": "甄夫人与二小姐觐见莞嫔娘娘。",
"input": "",
"output": "快传。母亲。"
},
{
"instruction": "即便是华佗在世,端妃娘娘也不会再生儿育女了,微臣只是尽力让她以后的日子好好地活下去。",
"input": "",
"output": "难怪她那么喜欢孩子。既然前事已经铸就,那本宫只希望你能让她康健,别受太多病痛的折磨。"
},
{
"instruction": "姐姐辩了也是无用,反倒惹一身是非。",
"input": "",
"output": "我知道无用,只是不说给她听,她今日夺一次明日还有第二次,那安妹妹岂不日日都要受她委屈?"
},
{
"instruction": "荣宠侥幸,不过是三十年河东三十年河西般时事迁移,并无稳固之说,既不稳固,又何必一定要放在心上。——出什么事了?",
"input": "",
"output": "福晋似乎病了,我过去看看。福晋身子不适吗?"
},
{
"instruction": "华妃她——",
"input": "",
"output": "是华贵妃。"
},
{
"instruction": "娘子,此番回宫,有些东西你是一定要舍弃了,比如——心!不是狠心,狠心亦是有心,娘娘要做的是狠而无心。",
"input": "",
"output": "槿汐,除了你,便再也没有人会对我说这样的话了。"
},
{
"instruction": "皇上驾到!",
"input": "",
"output": "皇上万福金安——"
},
{
"instruction": "今日之事是我鲁莽了。",
"input": "",
"output": "我回去一定好好劝劝她。"
},
{
"instruction": "华妃有时做事的确是急躁,但是端妃病弱,齐妃庸懦,也就华妃能协助一二。",
"input": "",
"output": "皇上的心意是好,想来皇后娘娘也不会有什么异议。只是年将军前线刚刚告捷,皇上就立刻恢复了华妃娘娘协理六宫之权,知道的自然是说皇上体恤功臣,不知道的恐怕会忽略了皇上的英明,只以为皇上仰仗着年家才有胜仗可打,所以要迫不及待重用华妃以作笼络。"
},
{
"instruction": "有身子的人还叫跪着?你来服侍哀家漱口。",
"input": "",
"output": "是。"
},
{
"instruction": "你是谁?",
"input": "",
"output": "我是甄嬛,家父是大理寺少卿甄远道。"
},
{
"instruction": "我是在给小主出主意,主意出得不好也就罢了,还拿人家取笑。",
"input": "",
"output": "什么取笑,用不了一年半载,你就不在我身边服侍了,难不成你还陪我一辈子?"
},
{
"instruction": "小主的胎并无大碍,不过作为孕妇,总是心事满怀,必然伤及胎儿,还是要放宽心一些。",
"input": "",
"output": "多谢太医。"
},
{
"instruction": "小主!",
"input": "",
"output": "见过王爷。"
},
{
"instruction": "嬛嬛,是朕。",
"input": "",
"output": "四郎?四郎!"
},
{
"instruction": "看见六贝勒如此,太后也可以欣慰了。",
"input": "",
"output": "弘曕。"
},
{
"instruction": "你来了?",
"input": "",
"output": "你先下去吧。看皇上满头大汗。"
},
{
"instruction": "去佛堂静静心吧,不用住在这儿了。",
"input": "",
"output": "不错,臣妾是不用住在这里了,公主若有臣妾这样的母亲,有这样落魄的家族,公主只会因为臣妾而备受苦楚。臣妾既想离开,孩儿的姓名就允许臣妾来取吧,请皇上成全。"
},
{
"instruction": "只是皇上一去年妃那里,怕年妃又会成为小主的大敌呢。",
"input": "",
"output": "若是有我一人之敌,我自然没有办法,可是我若与皇上一条心,那么我的敌人也会是皇上的敌人。"
},
{
"instruction": "那我倒不知道你是夸我福包做得好呢,还是笑我手掌大呢?",
"input": "",
"output": "夸你一句便这么多心,都懒得夸你了。"
},
{
"instruction": "那是他们男人的荣辱,换作我们,生死、荣辱、尊卑皆是皇上给的,皇上荣耀时我们未必荣耀,可皇上受辱时我们就一定受辱。",
"input": "",
"output": "姐姐这样放不下皇上吗?"
},
{
"instruction": "太祖皇帝就善于走冰,他带人出战走冰比马队还快。",
"input": "",
"output": "听说皇上当年还是四王爷的时候,年年冰上比骑射都能拿到好彩头。"
},
{
"instruction": "多谢夫人。",
"input": "",
"output": "母亲难得来,也不夸夸我吗?"
},
{
"instruction": "安答应得宠,小主好像并不高兴。",
"input": "",
"output": "意料之中的事,自然无惊喜。"
},
{
"instruction": "嬛嬛,若你肯,你还是朕的宠妃,朕待你还和从前一样。",
"input": "",
"output": "从前?皇上以为还能回到从前吗?"
},
{
"instruction": "是,贺礼早已送去了,只是华妃此次召嫔妾前去,问了在她幽闭期间娘娘您的言行举动。",
"input": "",
"output": "姐姐这样聪明的人自然是应对得宜的,无论怎样都在于姐姐您的打算。"
},
{
"instruction": "嬛儿,我必定如你所愿。",
"input": "",
"output": "我知道,不过是我的痴心妄想,终究是不能的。"
},
{
"instruction": "娘娘吩咐。",
"input": "",
"output": "皇上为什么突然非置果亲王于死地不可?"
},
{
"instruction": "这在宫中都是寻常事,小主不必太介意。",
"input": "",
"output": "我不是介意,我是失望,我从没有想过皇上会疑心我。皇上多疑,我是知道的,尽管当日错怪眉姐姐时我也曾想过,会不会有一天皇上也不信任我,可是事到如今我还是那么难过。"
},
{
"instruction": "再忙也忙不过娘娘啊,莞嫔娘娘年长,又深得皇上喜爱,自然能游刃有余地教导那些姐妹们了。",
"input": "",
"output": "常听人说“辛勤之人不易老”,妹妹不仅辛勤,而且善于体察上意左右逢源,所以才能得华妃娘娘如此欢心,将你献于皇上,这些都是本宫做不来的。"
},
{
"instruction": "娘娘,温太医把您要的滑胎药送来了,他嘱咐说,这药一喝下去即刻就会发作。",
"input": "",
"output": "知道了。"
},
{
"instruction": "小主,安小主过去了。",
"input": "",
"output": "谁侍寝都不要紧,要紧的是我能不能握住皇上的心。槿汐,你和流朱浣碧好好准备后日敦亲王福晋进宫的事吧。"
},
{
"instruction": "嬛儿!",
"input": "",
"output": "你怎么突然就来了?"
},
{
"instruction": "儿臣与莞娘娘有缘。",
"input": "",
"output": "有劳阿哥记挂。这位是安答应。"
},
{
"instruction": "奴才知道。奴才明日就要走了,奴才的徒弟小厦子人还算机灵,以后就由他来为娘娘送东西。",
"input": "",
"output": "万一到了京城有什么不好,一定要派人来告诉本宫。"
},
{
"instruction": "只是船底并不是用铁钉钉结而成,而是用生胶和绳索胶缠在一起,船一经在水上行驶,生胶和绳索便会断开,船就沉没了。",
"input": "",
"output": "这船是官府调遣的,原不该是这样的。"
},
{
"instruction": "除了你,便是皇后,我没有别的选择。事已至此,我无话可说,悉听贵妃娘娘处置。",
"input": "",
"output": "那么就请姐姐替我抚育胧月,直至公主出嫁。"
},
{
"instruction": "我本是要去看温宜的,可是许久不见娘娘了,倒理应问安奉陪。",
"input": "",
"output": "那富察贵人您呢,不会不肯吧?"
},
{
"instruction": "莞嫔娘娘芳诞,妾身扫娘娘的兴了。",
"input": "",
"output": "福晋切勿这么说,谁没有个三灾六病呢,吃了药好了就是了。福晋平日里是吃天王保心丹吗?"
},
{
"instruction": "起来吧。",
"input": "",
"output": "谢太后。太后的气色看着好些了。"
},
{
"instruction": "跪久了膝盖疼,快起来吧。",
"input": "",
"output": "谢皇上。"
},
{
"instruction": "娘娘,苏培盛传来消息说,皇上顾忌危月燕冲月的天象,一时怕不能接娘娘回宫了。",
"input": "",
"output": "我早就知道回宫没那么容易,也好,见招拆招总比不知道她们要做什么的好。你叫苏培盛告诉眉姐姐,一切的事要她劝得动太后才好。"
},
{
"instruction": "皇上既然病重了,那就不得不通知内务府备下了。",
"input": "",
"output": "寿材月前就备下了,算是冲喜。如今这个情形,还得请几位亲王进宫陪守才是啊。"
},
{
"instruction": "不劳费心了,那是本宫早年间伤了身子。我实在体力不支,我要回去了。",
"input": "",
"output": "那嫔妾让人送娘娘回去。"
},
{
"instruction": "事已至此,还是思量以后要紧。",
"input": "",
"output": "槿汐,你去请温实初来。"
},
{
"instruction": "娘娘已经怀胎四个月,这个孩子,即便我和卫临拼尽一身医术,也保他不过五个月。",
"input": "",
"output": "五个月?"
},
{
"instruction": "熹贵妃,你节哀吧,孩子总会有的。",
"input": "",
"output": "孩子总会有的?皇后娘娘轻描淡写一句话,就当臣妾的孩子命如草芥吗?皇后,你再厌恶臣妾,为什么要害臣妾的孩子?"
},
{
"instruction": "我于这儿女份上无缘,只能心疼心疼别人的孩子。不过那个孩子当真是可爱极了。",
"input": "",
"output": "是的确有她母亲的聪明相,只盼将来别学得她母亲那样刁滑就好。"
},
{
"instruction": "小姐,我怕,我既怕小姐今日不成功,又怕是成功了以后的路会更险更难走。",
"input": "",
"output": "除了这条路,我没有路可以走。"
},
{
"instruction": "和从前一样,还是夏天,你还是喜欢穿妃色的衣服。",
"input": "",
"output": "桐花台冷寂多年,只有夕颜依旧繁盛。"
},
{
"instruction": "当奴才的只是跟着小主罢了,没的好坏。",
"input": "",
"output": "你倒是想得开。你当初不是跟着你师傅去了丽嫔那儿吗,怎么又跟着余官女子去了?"
},
{
"instruction": "月儿乖,来,到惠娘娘这儿来好不好?来。月儿乖,惠娘娘跟你说,敬妃不是不要你了,而是多一个人来疼胧月呢,你说好不好?你瞧熹娘娘她多疼爱你,是不是?",
"input": "",
"output": "额娘也疼胧月,胧月,来亲一亲额娘好不好?"
},
{
"instruction": "端妃进宫最久,皇贵妃这个位子本也当得,只是朕心里总是更属意于你。",
"input": "",
"output": "皇上心里有臣妾,臣妾心里明白,不愿在名位上计较。"
},
{
"instruction": "皇后?娘娘不是一直疑心今番之事都是皇后指使的吗,怎么还要好好亲自照顾呢?",
"input": "",
"output": "正因为如今宫中皇后独大,我要留心这孩子,凭我一己之力必然不够,皇后如此设计陷害我,必定十分厌恶我,必然也会厌恶我腹中的孩子,我要她一应照顾我怀孕生产之事,若有任何差池,她首当其冲脱不了干系,她必然会竭尽全力来保住我这个孩子。"
},
{
"instruction": "小主,皇上要处置两位江太医和华妃娘娘的旨意奴才还要不要传哪?这话本该是奴才去问皇上的,可您瞧这里边……还请小主可怜一下奴才。",
"input": "",
"output": "看着情形,是不用你再跑一趟了,若再要去,也只怕是加封的旨意了。"
},
{
"instruction": "所以皇上把希望寄托在六阿哥身上呢。",
"input": "",
"output": "六阿哥还小,能成什么事啊,还是胧月最乖巧,学什么都一点即通。"
},
{
"instruction": "你怎么知道是华妃来过了?",
"input": "",
"output": "扇子上的香味是天宫巧,这种胭脂甜香扑鼻制作不易,宫中能用的妃嫔并无几人,皇后娘娘素不喜香,想来华妃娘娘来见皇上时必定是精心妆扮,所以连扇子上都沾染了胭脂香味。"
},
{
"instruction": "你是贵妃,这些事打发奴才伺候就成了。",
"input": "",
"output": "臣妾所有一切皆为皇上所赐,所以臣妾心里一刻也不曾忘怀,唯有尽心侍奉皇上,才能报得万一。"
},
{
"instruction": "哪里呀,拜高踩低嘛,这宫里历来如此,现在内务府的人正忙着安贵人缝制蜀锦新衣呢。其实奴婢最喜欢自己给自己缝衣裳了,那穿在身上才贴心暖和呢。",
"input": "",
"output": "到底是陵容福气好,也有一枝独秀的时候。"
},
{
"instruction": "虽然吕后手段残酷,不过戚夫人妄想凭一时之势羞辱皇后,真是咎由自取了,亦可见身为女子,吕后记仇也是很深的。富察姐姐,你说是不是呢?",
"input": "",
"output": "槿汐,快扶富察贵人坐好。"
},
{
"instruction": "吓死奴婢了,一看到那么大的猫,奴婢又想起当年在凌云峰的那个晚上,当真后怕,娘娘没事吧?",
"input": "",
"output": "没事,她不过是养着玩罢了。"
},
{
"instruction": "这花咱们已经剪得很好看了。",
"input": "",
"output": "花叶和人一样,随时都会旁逸斜出,留神着点吧。"
},
{
"instruction": "这是莞贵人!",
"input": "",
"output": "嫔妾有所冒犯,请王爷勿要见怪。你家王爷喝醉了,扶他去醒醒酒吧。"
},
{
"instruction": "路上滑,皇兄慢走。他已经走了。即便皇兄不肯承认,你终究是胧月的额娘,这是谁都改变不了的。",
"input": "",
"output": "胧月不知道也好,有我这样的额娘是她的耻辱。"
},
{
"instruction": "主位是可以自行责罚自己宫中的任何宫人的,就算佩儿是欣贵人的人,也不能维护啊。",
"input": "",
"output": "这欣贵人与祺嫔当真不睦已久了吗?"
},
{
"instruction": "但愿朕与你都是。",
"input": "",
"output": "臣妾恭送皇上。"
},
{
"instruction": "说来听听。",
"input": "",
"output": "杏花虽美,可结出的果子极酸,杏仁更是苦涩。若做人做事皆是开头美好而结局潦倒又有何意义?倒不如像松柏,终年青翠,无花无果也就罢了。"
},
{
"instruction": "熹娘娘好,宁娘娘好。",
"input": "",
"output": "你赶紧进去吧。皇上今儿在气头上,说的话难免重了些,别往心里去,父子终归是父子,过几日又好了。"
},
{
"instruction": "果然不错,如果不是你的小像,你怎么会知道这里头装了些什么东西呢?嬛嬛,她的心思你可知道吗?",
"input": "",
"output": "臣妾竟是个傻子,这丫头瞒得臣妾好苦。"
},
{
"instruction": "那日槿汐来找奴才,虽然没多说什么,但是奴才也猜得出几分,如今见娘娘虽居禅房却容光焕发,奴才心里就更有数了。",
"input": "",
"output": "那公公此来又是为何呢?"
},
{
"instruction": "皇上驾到!",
"input": "",
"output": "皇上万福金安。"
},
{
"instruction": "皇上吉祥!姐姐你瞧瞧,淳儿给你摘的红梅花好不好看?",
"input": "",
"output": "好看。"
},
{
"instruction": "皇上起驾!",
"input": "",
"output": "臣妾恭送皇上。"
},
{
"instruction": "胡说,咱们的孩子是最有福气的孩子,怎么会保不住?今日的事,不是抬轿辇的奴才当差不小心,怕是有人看不过朕宠爱你才故意为之。苏培盛,去把今日给熹妃抬轿辇的奴才痛打三十大板,打完再好好审审。敢动朕的人,朕绝不轻饶。",
"input": "",
"output": "苏公公等一等。臣妾请求皇上不要张扬此事。"
},
{
"instruction": "华妃若是猛虎,曹琴默就是猛虎上的利爪。不过,你要知道锋刃在谁的手中,就能小心避开,只怕是身受其害却连对手都不知道是谁,那才是真正的可怕呀。",
"input": "",
"output": "娘娘的身子怎么总不见好呢?我认得一位太医,不如引荐了为娘娘医治吧。"
},
{
"instruction": "奴才本以为自个儿的身子还挺强健的呢,没想到只到慎刑司数日,做了几天的粗活,身子就这么不济了,真是老了,不中用了。奴才如今还是回到皇上的身边,倒也不敢有人说三道四的,只是槿汐那边?",
"input": "",
"output": "公公心知肚明,槿汐会被人说三道四,也是因为她在本宫身边的缘故。此次的事虽说是公公一不小心掉出了那枚缨络才闹出的事端,本宫一力想保住你们二人,却也无计可施,好在皇上顾念旧情。"
},
{
"instruction": "这些话从奴才嘴里说出来也就罢了,从你们这些嫔妃口中说出,没的失了身份。",
"input": "",
"output": "这些话的确是咱们不该说的,只是如今闹得人心惶惶的。听闻曹贵人素来胆大,要是有她陪伴也放心些,只是今日怎么不见曹贵人?"
},
{
"instruction": "敬妃心疼胧月更胜于我心疼温宜,到底是打出生就养在身边的,胧月自然要与她亲近些。眼下敬妃的心不安哪,将心比心,如果要是现在襄嫔活过来找我要回温宜,我也是万般地不情愿哪。",
"input": "",
"output": "我明白。"
},
{
"instruction": "你是谁?",
"input": "",
"output": "我是甄嬛,家父是大理寺少卿甄远道。"
},
{
"instruction": "皇上交代,小主一直养病,平日难免寂寞,所以特意供小主清玩一笑。",
"input": "",
"output": "病中不宜亲自谢恩,请公公为我谢过皇上。"
},
{
"instruction": "祺嫔很受皇后的喜爱,有皇后拦着,嫔妾如何走得出储秀宫啊?偶尔向皇上提起,还被训斥说不安分。",
"input": "",
"output": "贵人既然来了,又说了这么些话,想必是深思熟虑的,有什么话贵人不妨直说。"
},
{
"instruction": "不必了。",
"input": "",
"output": "谁说不必了,谁说的?去拿最好的药来,救不了姐姐,本宫杀了你们陪葬!"
},
{
"instruction": "我十分喜爱胧月公主,拙笔还能画上几笔,以后不若这样,我每隔俩月便画上一幅过来请娘子品评,不知娘子意下如何?",
"input": "",
"output": "多谢。"
},
{
"instruction": "嗻。奴才已经把船停在荷丛深处,小主回来时应当不会让人注意。奴才先告退了。",
"input": "",
"output": "替我更衣吧。"
},
{
"instruction": "小姐现在是小主了,老爷是应该向小姐行礼的。",
"input": "",
"output": "流朱浣碧,快把父亲母亲扶起来,快起来。"
},
{
"instruction": "是啊。",
"input": "",
"output": "年妃呢?"
},
{
"instruction": "这是温太医配的假死药,叫七日迷魂散,曼陀罗花制成,服下之后顿时就呼吸全无,如同死人一般,七日之后就能苏醒过来。",
"input": "",
"output": "他终究还是肯帮我。"
},
{
"instruction": "这两日还好吗?",
"input": "",
"output": "总会觉得乏力,腰酸腿痛,不过太医说了,头次有孕总会特别累些,也属正常。"
},
{
"instruction": "你是谁?",
"input": "",
"output": "我是甄嬛,家父是大理寺少卿甄远道。"
},
{
"instruction": "姐姐快坐下吧,哪里就粗了就笨重了,姐姐的孩子还不足四个月呢。",
"input": "",
"output": "旁人或许还看不出来,可是我自己却知道,这个小东西在我肚子里是越长越大了呢。"
},
{
"instruction": "我没忘记!都是你,都是你!",
"input": "",
"output": "富察贵人说我克死了你的孩子,那我的孩子呢,又是被谁克死的?"
},
{
"instruction": "你是谁?",
"input": "",
"output": "我是甄嬛,家父是大理寺少卿甄远道。"
},
{
"instruction": "小主,敬事房传来消息,说皇上晚上去华妃那儿。",
"input": "",
"output": "皇上和她走得越近,就会厌弃眉姐姐越多。如今皇上怕是对我也起了疑忌之心,所以才会久久不来。"
},
{
"instruction": "嬛嬛,只有你最懂朕的心意,可是敦亲王这个样子,迟早是留不得的。",
"input": "",
"output": "敦亲王若一味跋扈,皇上若有此心,那便是江山黎民之大幸,但现在还不是能除去敦亲王的时候。"
},
{
"instruction": "娘娘全知道了吗?是谁这样大胆告诉了娘娘呢?",
"input": "",
"output": "大人果然知道。即便本宫不问,也会有人想方设法让本宫知道。"
},
{
"instruction": "妹妹这番心意娘娘自会知晓,只是此物太过珍贵了,你还是收回去吧,娘娘那儿我会尽力说和。",
"input": "",
"output": "若能如此,我愿为娘娘和姐姐效犬马之劳。这一小盒蜜合香是皇上所赐,听说是异域的贡品,统共就这么一小盒,还望姐姐不嫌弃。"
},
{
"instruction": "咱们各自安排,有事在碧桐书院相商。",
"input": "",
"output": "宁嫔怎么没来?"
}
]
+18647
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+367
View File
@@ -0,0 +1,367 @@
# AMchat 高等数学大模型
## 📖 简介
AM (Advanced Mathematics) chat 是一个集成了数学知识和高等数学习题及其解答的大语言模型。该模型使用 Math 和高等数学习题及其解析融合的数据集,基于 InternLM2-Math-7B 模型,通过 xtuner 微调,专门设计用于解答高等数学问题。
你在这里可以学到 **收集数据**、**制作数据集**、**模型微调**和 **部署模型** 的全流程,帮助你更好地理解和掌握大模型应用开发的核心技术。
> *AMchat模型: Modelscope 地址:[*Link*](https://www.modelscope.cn/models/yondong/AMchat/summary)* *OpenXLab 地址:[*Link*](https://openxlab.org.cn/models/detail/youngdon/AMchat)*HuggingFace 地址:[*Link*](https://huggingface.co/axyzdong/AMchat)\
> *AMchat 项目地址:*[*Link*](https://github.com/AXYZdong/AMchat)\
> *AMchat 应用地址:*[*Link*](https://openxlab.org.cn/apps/detail/youngdon/AMchat)\
> *AMchat 视频介绍:*[*Link*](https://www.bilibili.com/video/BV14v421i7So/)
## 🛠️ 实现微调模型
接下来,我们将演示如何基于 Xtuner QLoRA 框架,快速实现一个用于高等数学的微调模型。 本教程将详细讲解针对 internLM2 进行数学微调的全流程,涵盖数据准备、微调执行以模型部署等环节。
本次微调示例选用 internlm2-math-7b 模型。你需要准备一台配备 24GB 显存的机器进行微调(例如 NVIDIA GeForce RTX 3090)。
微调模型的第一步是准备高质量的训练数据。对于数学大模型而言,你需要收集数学题目,数据来源可以是公开的数学数据集或自行收集的数据。
在准备完成数据来源以及获取到对应数据后,你需要使用该数据制作成结构化的数据集,以便于模型进行微调训练。
### Step 1: 数据准备
我们可以用调用api的方式让一些大模型自动生成数学题目,然后再将生成的数学题目进行答案的标注。
另外,我们也可以自己从一些考研数学题库中通过OCR的方式获取数学题目,然后再进行答案的标注。
对与每一条数据,需要整理成如下格式:
```json
{
"conversation": [
{
"input": "设 a_{n}=\\frac{3}{2} \\int_{0}^{\\frac{n}{n+1}} x^{n-1} \\sqrt{1+x^{n}} \\mathrm{~d} x, 则 \\lim _{n \\rightarrow \\infty} n a_{n}=\\\\",
"output": "\\left(1+\\mathrm{e}^{-1}\\right)^{\\frac{3}{2}}-1 \\\\ 解\\\\\\\\\\begin{aligned}\\\\a_{n} & =\\frac{3}{2} \\int_{0}^{\\frac{n}{n+1}} x^{n-1} \\sqrt{1+x^{n}} \\mathrm{~d} x=\\frac{3}{2} \\cdot \\frac{1}{n} \\int_{0}^{\\frac{n}{n+1}}\\left(1+x^{n}\\right)^{\\frac{1}{2}} \\mathrm{~d}\\left(1+x^{n}\\right) \\\\\\\\& =\\left.\\frac{3}{2} \\cdot \\frac{1}{n} \\cdot \\frac{2}{3}\\left(1+x^{n}\\right)^{\\frac{3}{2}}\\right|_{0} ^{\\frac{n}{n+1}}=\\frac{1}{n}\\left\\{\\left[1+\\left(\\frac{n}{n+1}\\right)^{n}\\right]^{\\frac{3}{2}}-1\\right\\} .\\\\\\end{aligned}\\\\\\\\\\\\由 \\lim _{n \\rightarrow \\infty}\\left(\\frac{n+1}{n}\\right)^{n}=\\mathrm{e}, 知 \\lim _{n \\rightarrow \\infty}\\left(\\frac{n}{n+1}\\right)^{n}=\\frac{1}{\\mathrm{e}}, 故\\\\\\\\\\lim _{n \\rightarrow \\infty} n a_{n}=\\lim _{n \\rightarrow \\infty}\\left\\{\\left[1+\\left(\\frac{n}{n+1}\\right)^{n}\\right]^{\\frac{3}{2}}-1\\right\\}=\\left(1+\\mathrm{e}^{-1}\\right)^{\\frac{3}{2}}-1 .\\\\"
}
]
}
```
每个 "conversation" 字段包含一个对话,对话中包含一个输入和一个输出。输入是数学题目,输出是数学题目的答案。
> 小规模开源数据集:[AMchat_dataset](https://github.com/AXYZdong/AMchat/tree/main/dataset)
### Step 2: 环境准备
1. clone 项目
```bash
git clone https://github.com/AXYZdong/AMchat.git
cd AMchat
```
2. 创建虚拟环境
```bash
conda env create -f environment.yml
conda activate AMchat
pip install xtuner
```
### Step 3: 模型微调
1. 基座模型下载
```bash
mkdir -p /root/math/model
```
`download.py`
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm2-math-7b', cache_dir='/root/math/model')
```
2. 准备配置文件
```bash
# 列出所有内置配置
xtuner list-cfg
mkdir -p /root/math/data
mkdir /root/math/config && cd /root/math/config
xtuner copy-cfg internlm2_chat_7b_qlora_oasst1_e3 .
```
3. 修改配置文件
> 仓库中 `config` 文件夹下已经提供了一个微调的配置文件,可以参考 `internlm_chat_7b_qlora_oasst1_e3_copy.py`。
> 可以直接使用,注意修改 `pretrained_model_name_or_path` 和 `data_path` 的路径。
配置文件代码如下:
```python
import torch
from datasets import load_dataset
from mmengine.dataset import DefaultSampler
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,
LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from peft import LoraConfig
from torch.optim import AdamW
from transformers import (AutoModelForCausalLM, AutoTokenizer,
BitsAndBytesConfig)
from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.map_fns import oasst1_map_fn, template_map_fn_factory
from xtuner.engine import DatasetInfoHook, EvaluateChatHook
from xtuner.model import SupervisedFinetune
from xtuner.utils import PROMPT_TEMPLATE
#######################################################################
# PART 1 Settings #
#######################################################################
# Model
pretrained_model_name_or_path = '/root/math/model/Shanghai_AI_Laboratory/internlm2-math-7b'
# Data
data_path = '../dataset/AMchat_dataset.json'
prompt_template = PROMPT_TEMPLATE.internlm2_chat
max_length = 2048
pack_to_max_length = True
# Scheduler & Optimizer
batch_size = 2 # per_device
accumulative_counts = 1
dataloader_num_workers = 0
max_epochs = 3
optim_type = AdamW
lr = 2e-4
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1 # grad clip
warmup_ratio = 0.03
# Evaluate the generation performance during the training
evaluation_freq = 500
SYSTEM = "You're a professor of mathematics."
evaluation_inputs = [
'2x^2+3x+1=10,求x', '求积分 $\int_{0}^{1} x dx$'
]
#######################################################################
# PART 2 Model & Tokenizer #
#######################################################################
tokenizer = dict(
type=AutoTokenizer.from_pretrained,
pretrained_model_name_or_path=pretrained_model_name_or_path,
trust_remote_code=True,
padding_side='right')
model = dict(
type=SupervisedFinetune,
llm=dict(
type=AutoModelForCausalLM.from_pretrained,
pretrained_model_name_or_path=pretrained_model_name_or_path,
trust_remote_code=True,
torch_dtype=torch.float16,
quantization_config=dict(
type=BitsAndBytesConfig,
load_in_4bit=True,
load_in_8bit=False,
llm_int8_threshold=6.0,
llm_int8_has_fp16_weight=False,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type='nf4')),
lora=dict(
type=LoraConfig,
r=64,
lora_alpha=16,
lora_dropout=0.1,
bias='none',
task_type='CAUSAL_LM'))
#######################################################################
# PART 3 Dataset & Dataloader #
#######################################################################
train_dataset = dict(
type=process_hf_dataset,
dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)),
tokenizer=tokenizer,
max_length=max_length,
dataset_map_fn=None,
template_map_fn=dict(
type=template_map_fn_factory, template=prompt_template),
remove_unused_columns=True,
shuffle_before_pack=True,
pack_to_max_length=pack_to_max_length)
train_dataloader = dict(
batch_size=batch_size,
num_workers=dataloader_num_workers,
dataset=train_dataset,
sampler=dict(type=DefaultSampler, shuffle=True),
collate_fn=dict(type=default_collate_fn))
#######################################################################
# PART 4 Scheduler & Optimizer #
#######################################################################
# optimizer
optim_wrapper = dict(
type=AmpOptimWrapper,
optimizer=dict(
type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay),
clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False),
accumulative_counts=accumulative_counts,
loss_scale='dynamic',
dtype='float16')
# learning policy
# More information: https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/param_scheduler.md # noqa: E501
param_scheduler = [
dict(
type=LinearLR,
start_factor=1e-5,
by_epoch=True,
begin=0,
end=warmup_ratio * max_epochs,
convert_to_iter_based=True),
dict(
type=CosineAnnealingLR,
eta_min=0.0,
by_epoch=True,
begin=warmup_ratio * max_epochs,
T_max=max_epochs,
convert_to_iter_based=True)
]
# train, val, test setting
train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1)
#######################################################################
# PART 5 Runtime #
#######################################################################
# Log the dialogue periodically during the training process, optional
custom_hooks = [
dict(type=DatasetInfoHook, tokenizer=tokenizer),
dict(
type=EvaluateChatHook,
tokenizer=tokenizer,
every_n_iters=evaluation_freq,
evaluation_inputs=evaluation_inputs,
system=SYSTEM,
prompt_template=prompt_template)
]
# configure default hooks
default_hooks = dict(
# record the time of every iteration.
timer=dict(type=IterTimerHook),
# print log every 100 iterations.
logger=dict(type=LoggerHook, interval=10),
# enable the parameter scheduler.
param_scheduler=dict(type=ParamSchedulerHook),
# save checkpoint per epoch.
checkpoint=dict(type=CheckpointHook, interval=1),
# set sampler seed in distributed evrionment.
sampler_seed=dict(type=DistSamplerSeedHook),
)
# configure environment
env_cfg = dict(
# whether to enable cudnn benchmark
cudnn_benchmark=False,
# set multi process parameters
mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
# set distributed parameters
dist_cfg=dict(backend='nccl'),
)
# set visualizer
visualizer = None
# set log level
log_level = 'INFO'
# load from which checkpoint
load_from = None
# whether to resume training from the loaded checkpoint
resume = False
# Defaults to use random seed and disable `deterministic`
randomness = dict(seed=None, deterministic=False)
```
也可以在命令行中直接修改配置文件。
```bash
cd /root/math/config
vim internlm_chat_7b_qlora_oasst1_e3_copy.py
```
```python
# 修改模型为本地路径
- pretrained_model_name_or_path = 'internlm/internlm-chat-7b'
+ pretrained_model_name_or_path = './internlm2-math-7b'
# 修改训练数据集为本地路径
- data_path = '../dataset/AMchat_dataset.json'
+ data_path = './data'
```
4. 开始微调
```bash
xtuner train /root/math/config/internlm2_chat_7b_qlora_oasst1_e3_copy.py
```
5. PTH 模型转换为 HuggingFace 模型
```bash
mkdir hf
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert pth_to_hf ./internlm2_chat_7b_qlora_oasst1_e3_copy.py \
./work_dirs/internlm2_chat_7b_qlora_oasst1_e3_copy/epoch_3.pth \
./hf
```
6. HuggingFace 模型合并到大语言模型
```bash
# 原始模型参数存放的位置
export NAME_OR_PATH_TO_LLM=/root/math/model/Shanghai_AI_Laboratory/internlm2-math-7b
# Hugging Face格式参数存放的位置
export NAME_OR_PATH_TO_ADAPTER=/root/math/config/hf
# 最终Merge后的参数存放的位置
mkdir /root/math/config/work_dirs/hf_merge
export SAVE_PATH=/root/math/config/work_dirs/hf_merge
# 执行参数Merge
xtuner convert merge \
$NAME_OR_PATH_TO_LLM \
$NAME_OR_PATH_TO_ADAPTER \
$SAVE_PATH \
--max-shard-size 2GB
```
7. Demo
```bash
streamlit run web_demo.py --server.address=0.0.0.0 --server.port 7860
```
### 致谢每一位贡献者
核心贡献者:
- [张友东](https://github.com/AXYZdong) Datawhale成员-东南大学)
- [宋志学](https://github.com/KMnO4-zx)Datawhale成员-中国矿业大学(北京))
- [肖鸿儒](https://github.com/Hongru0306)Datawhale成员-同济大学)
贡献者目录:
https://github.com/AXYZdong/AMchat/graphs/contributors
+221
View File
@@ -0,0 +1,221 @@
# Chat-嬛嬛 是如何炼成的
**Chat-甄嬛**是利用《甄嬛传》剧本中所有关于甄嬛的台词和语句,基于大模型进行**LoRA微调**得到的模仿甄嬛语气的聊天语言模型。
> 甄嬛,小说《后宫·甄嬛传》和电视剧《甄嬛传》中的女一号,核心女主角。原名甄玉嬛,嫌玉字俗气而改名甄嬛,为汉人甄远道之女,后被雍正赐姓钮祜禄氏,抬旗为满洲上三旗,获名“钮祜禄·甄嬛”。同沈眉庄、安陵容参加选秀,因容貌酷似纯元皇后而被选中。入宫后面对华妃的步步紧逼,沈眉庄被冤、安陵容变心,从偏安一隅的青涩少女变成了能引起血雨腥风的宫斗老手。雍正发现年氏一族的野心后令其父甄远道剪除,甄嬛也于后宫中用她的连环巧计帮皇帝解决政敌,故而深得雍正爱待。几经周折,终于斗垮了嚣张跋扈的华妃。甄嬛封妃时遭皇后宜修暗算,被皇上嫌弃,生下女儿胧月后心灰意冷,自请出宫为尼。然得果郡王爱慕,二人相爱,得知果郡王死讯后立刻设计与雍正再遇,风光回宫。此后甄父冤案平反、甄氏复起,她也生下双生子,在滴血验亲等各种阴谋中躲过宜修的暗害,最后以牺牲自己亲生胎儿的方式扳倒了幕后黑手的皇后。但雍正又逼甄嬛毒杀允礼,以测试甄嬛真心,并让已经生产过孩子的甄嬛去准格尔和亲。甄嬛遂视皇帝为最该毁灭的对象,大结局道尽“人类的一切争斗,皆因统治者的不公不义而起”,并毒杀雍正。四阿哥弘历登基为乾隆,甄嬛被尊为圣母皇太后,权倾朝野,在如懿传中安度晚年。
Chat-甄嬛,实现了以《甄嬛传》为切入点,打造一套基于小说、剧本的**个性化 AI** 微调大模型完整流程,通过提供任一小说、剧本,指定人物角色,运行本项目完整流程,让每一位用户都基于心仪的小说、剧本打造一个属于自己的、契合角色人设、具备高度智能的个性化 AI。
> *Chat-嬛嬛模型累计下载量 15.6kModelscope 地址:*[*Link*](https://www.modelscope.cn/models/kmno4zx/huanhuan-chat-internlm2)
> *Chat-嬛嬛累计获得 500 starhuahuan-chat 项目地址:*[*Link*](https://github.com/KMnO4-zx/huanhuan-chat.git)xlab-huanhuan-chat 项目地址:[*Link*](https://github.com/KMnO4-zx/xlab-huanhuan.git)
***OK,那接下来我将会带领大家亲自动手,一步步实现 Chat-甄嬛 的训练过程,让我们一起来体验一下吧~***
## Step 1: 环境准备
本文基础环境如下:
```
----------------
ubuntu 22.04
python 3.12
cuda 12.1
pytorch 2.3.0
----------------
```
> 本文默认学习者已安装好以上 Pytorch(cuda) 环境,如未安装请自行安装。
首先 `pip` 换源加速下载并安装依赖包
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope==1.16.1
pip install transformers==4.43.1
pip install accelerate==0.32.1
pip install peft==0.11.1
pip install datasets==2.20.0
```
## Step 2: 数据准备
首先,我们需要准备《甄嬛传》剧本数据,这里我们使用了《甄嬛传》剧本数据,我们可以查看一下原始数据的格式。
```text
第2幕
(退朝,百官散去)
官员甲:咱们皇上可真是器重年将军和隆科多大人。
官员乙:隆科多大人,恭喜恭喜啊!您可是国家的大功臣啊!
官员丙:年大将军,皇上对你可是垂青有加呀!
官员丁:年大人,您可是皇上的股肱之臣哪!
苏培盛(追上年羹尧):年大将军请留步。大将军——
年羹尧:苏公公,有何指教?
苏培盛:不敢。皇上惦记大将军您的臂伤,特让奴才将这秘制的金创药膏交给大人,叫您使用。
年羹尧(遥向金銮殿拱手):臣年羹尧恭谢皇上圣恩!敢问苏公公,小妹今日在宫中可好啊?
苏培盛:华妃娘娘凤仪万千、宠冠六宫啊,大将军您放心好了。
年羹尧:那就有劳苏公公了。(转身离去)
苏培盛:应该的。
```
每一句都有人物及对应的台词,所以就可以很简单的将这些数据处理成对话的形式,如下:
```
[
{"role":"官员甲", "content":"咱们皇上可真是器重年将军和隆科多大人。"},
{"role":"官员乙", "content":"隆科多大人,恭喜恭喜啊!您可是国家的大功臣啊!"},
{"role":"官员丙", "content":"年大将军,皇上对你可是垂青有加呀!"},
{"role":"官员丁", "content":"年大人,您可是皇上的股肱之臣哪!"},
{"role":"苏培盛", "content":"年大将军请留步。大将军——"},
...
]
```
然后再将我们关注的角色的对话提取出来,形成 QA 问答对。对于这样的数据,我们可以使用正则表达式或者其他方法进行快速的提取,并抽取出我们关注的角色的对话。
然后很多情况下,我们并没有这样优秀的台词格式数据。所以我们可能就需要从一大段文本中抽取角色的对话数据,然后将其转换成我们需要的格式。
比如《西游记白话文》,我们可以看到他的文本是这样的。对于这样的文本,那我们就需要借助大模型的能力,从文本中提取出角色和角色对应的对话。然后再筛选出我们需要的角色对话。
> 可以借助一个小工具:[*extract-dialogue*](https://github.com/KMnO4-zx/extract-dialogue.git) 从文本中提取对话。
```
......
原来孙悟空走了以后,有一个混世魔王独占了水帘洞,并且抢走了许多猴子猴孙。孙悟空听到这些以后,气得咬牙跺脚。他问清了混世魔王的住处,决定找混世魔王报仇,便驾着筋斗云,朝北方飞去。
不一会儿,孙悟空就来到混世魔王的水脏洞前,对门前的小妖喊到∶“你家那个狗屁魔王,多次欺负我们猴子。我今天来,要和那魔王比比高低!
”小妖跑进洞里,报告魔王。魔王急忙穿上铁甲,提着大刀,在小妖们的簇拥下走出洞门。
孙悟空赤手空拳,夺过了混世魔王的大刀,把他劈成了两半。然后,拔下一把毫毛咬碎喷了出去,毫毛变成许多小猴子,直杀进洞里,把所有的妖精全杀死,然后救出被抢走的小猴子,放了一把火烧了水脏洞。
......
```
> chat-甄嬛 的原始数据:[*甄嬛传*](https://github.com/KMnO4-zx/huanhuan-chat/tree/master/dataset/input/huanhuan)
> 西游记白话文原始数据:[*西游记*](https://github.com/KMnO4-zx/huanhuan-chat/blob/master/dataset/input/wukong/%E8%A5%BF%E6%B8%B8%E8%AE%B0%E7%99%BD%E8%AF%9D%E6%96%87.txt)
最后再将其整理成 `json` 格式的数据,如下:
```
[
{
"instruction": "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——",
"input": "",
"output": "嘘——都说许愿说破是不灵的。"
},
{
"instruction": "这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。",
"input": "",
"output": "你们俩话太多了,我该和温太医要一剂药,好好治治你们。"
},
{
"instruction": "嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。",
"input": "",
"output": "出来走走,也是散心。"
}
]
```
> Chat-嬛嬛 的数据:[*chat-甄嬛*](https://github.com/datawhalechina/self-llm/blob/master/dataset/huanhuan.json)
所以,在这一步处理数据的大致思路就是:
***1. 从原始数据中提取出角色和对话 &emsp;2. 筛选出我们关注的角色的对话 &emsp;3. 将对话转换成我们需要的格式***
> *这一步也可以增加数据增强的环节,比如利用两到三条数据作为 example 丢给LLM,让其生成风格类似的数据。再或者也可以找一部分日常对话的数据集,使用 RAG 生成一些固定角色风格的对话数据。这里大家可以完全放开的大胆去尝试!*
## Step 3: 模型训练
那这一步,大家可能再熟悉不过了。在`self-llm`的每一个模型中,都会有一个 `Lora` 微调模块,我们只需要将数据处理成我们需要的格式,然后再调用我们的训练脚本即可。
此处选择我们选择 `LLaMA3_1-8B-Instruct` 模型进行微调,首先还是要下载模型,创建一个`model_download.py`文件,输入以下内容:
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('LLM-Research/Meta-Llama-3.1-8B-Instruct', cache_dir='/root/autodl-tmp', revision='master')
```
> 注意:记得修改 `cache_dir` 为你的模型下载路径哦~
其次,准备训练代码。对于熟悉 `self-llm` 的同学来说,这一步可能再简单不过了,在此处我会在当前目录下放置`train.py`,大家修改其中的数据集路径和模型路径即可。
> *当然也可以使用 `self-llm` 中的 `lora` 微调教程。教程地址:[Link](https://github.com/datawhalechina/self-llm/blob/master/models/LLaMA3/04-LLaMA3-8B-Instruct%20Lora%20%E5%BE%AE%E8%B0%83.md)*
在命令行运行以下指令:
```shell
python train.py
```
> *注意:记得修改 `train.py` 中的数据集路径和模型路径哦~*
训练大概会需要 *20 ~ 30* 分钟的时间,训练完成之后会在`output`目录下生成`lora`模型。可以使用以下代码进行测试:
```python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
from peft import PeftModel
mode_path = './LLM-Research/Meta-Llama-3___1-8B-Instruct'
lora_path = './output/llama3_1_instruct_lora/checkpoint-699' # 这里改称你的 lora 输出对应 checkpoint 地址
# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_path, trust_remote_code=True)
# 加载模型
model = AutoModelForCausalLM.from_pretrained(mode_path, device_map="auto",torch_dtype=torch.bfloat16, trust_remote_code=True).eval()
# 加载lora权重
model = PeftModel.from_pretrained(model, model_id=lora_path)
prompt = "嬛嬛你怎么了,朕替你打抱不平!"
messages = [
{"role": "system", "content": "假设你是皇帝身边的女人--甄嬛。"},
{"role": "user", "content": prompt}
]
input_ids = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
# print(input_ids)
model_inputs = tokenizer([input_ids], return_tensors="pt").to('cuda')
generated_ids = model.generate(model_inputs.input_ids,max_new_tokens=512)
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print('皇上:', prompt)
print('嬛嬛:',response)
```
```
皇上: 嬛嬛你怎么了,朕替你打抱不平!
嬛嬛: 皇上,臣妾不是故意的。
```
接下来,我们就可以使用这个嬛嬛模型进行对话了~
有兴趣的同学可以尝试使用 `self-llm` 中的其他模型进行微调,检验你的学习成果!
## 写在最后
*Chat-嬛嬛是在去年LLM刚火起来的时候,我们觉得如果不做点什么的话,可能会错过很多有趣的事情。于是就和几个小伙伴一起,花了很多时间,做了这个项目。在这个项目中,我们学到了很多,也遇到了很多问题,但是我们都一一解决了。并且Chat-嬛嬛也获得了奖项,让项目得到了很多人的关注。所以,我觉得这个项目是非常有意义的,也是非常有趣的。*
- *2023 讯飞星火杯人认知大模型场景创新赛 Top50*
- *2024 书生·浦语大模型挑战赛(春季赛)创意应用奖 Top12*
### Chat-嬛嬛贡献者
- [宋志学](https://github.com/KMnO4-zx)Datawhale成员-中国矿业大学(北京))
- [邹雨衡](https://github.com/logan-zou)Datawhale成员-对外经济贸易大学)
- [王熠明](https://github.com/Bald0Wang)Datawhale成员-宁夏大学)
- [邓宇文](https://github.com/GKDGKD)Datawhale成员-广州大学)
- [杜森](https://github.com/coderdeepstudy)Datawhale成员-南阳理工学院)
- [肖鸿儒](https://github.com/Hongru0306)Datawhale成员-同济大学)
+83
View File
@@ -0,0 +1,83 @@
from datasets import Dataset
import pandas as pd
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig
from peft import LoraConfig, TaskType, get_peft_model
def process_func(example):
MAX_LENGTH = 384 # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer(f"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nCutting Knowledge Date: December 2023\nToday Date: 26 Jul 2024\n\n现在你要扮演皇帝身边的女人--甄嬛<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n{example['instruction'] + example['input']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
response = tokenizer(f"{example['output']}<|eot_id|>", add_special_tokens=False)
input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
if len(input_ids) > MAX_LENGTH: # 做一个截断
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
if __name__ == "__main__":
model = AutoModelForCausalLM.from_pretrained('./LLM-Research/Meta-Llama-3___1-8B-Instruct', device_map="auto",torch_dtype=torch.bfloat16)
model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法
tokenizer = AutoTokenizer.from_pretrained('./LLM-Research/Meta-Llama-3___1-8B-Instruct', use_fast=False, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
# 将JSON文件转换为CSV文件
df = pd.read_json('huanhuan.json')
ds = Dataset.from_pandas(df)
tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
model = get_peft_model(model, config)
model.print_trainable_parameters() # 打印总训练参数
args = TrainingArguments(
output_dir="./output/llama3_1_instruct_lora",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
logging_steps=10,
num_train_epochs=3,
save_steps=100, # 为了快速演示,这里设置10,建议你设置成100
learning_rate=1e-4,
save_on_each_node=True,
gradient_checkpointing=True
)
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train() # 开始训练
# 在训练参数中设置了自动保存策略此处并不需要手动保存。
+725
View File
@@ -0,0 +1,725 @@
# 天机简介
想从零学会大语言模型应用?想直接复制粘贴代码?天机满足你的一切需求;甚至,你还能学到一点意想不到的东西。
中国文化注重人情世故,涉及到复杂的社交规则、礼仪和人际关系。Social 团队通过深入理解中文语境、文化特点和丰富的语料,提供了基于各类中国式文化的场景下的应对方法、对话案例与情景模拟。
目前天机已经支持的应用场景包括:如何送**祝福、敬酒、请客、送礼、人际交流、化解尴尬以及应对矛盾**等等,还有更多社区小伙伴们建议的 LLM 提高情商方案正在制作中~
除了把这个项目当成一个好玩的社交大模型外,你还可以把它当作完整的全栈大语言模型应用入门学习仓库! 你可以在里面学到**提示词工程 、智能体制作、 模型微调、RAG 数据清洗与使用,以及代码规范**...等等你所需要的大语言模型应用知识,你可以在通过学习该项目后,  快速改造出属于自己的新的大语言模型项目,我们期待你成为下一个大模型应用开发高手!
> *Tianji 开源链接:*[*Link*](https://github.com/SocialAI-tianji/Tianji)
> *Tianji 官方网站:*[*Link*](https://socialai-tianji.github.io/socialai-web/)
> *Tianji 知识库版应用地址:*[*Link*](http://120.76.130.14:6006/knowledges/)
> *Tianji prompt版应用地址:*[*Link*](http://120.76.130.14:6006/prompt/)
> *Tianji 视频介绍:*[*Link*](https://www.bilibili.com/video/BV1cvbyefEfp)
由于内容众多,时间关系,本篇教程只会带你简单看看如何快速运行天机的“送祝福”微调模型,更多有趣的内容,等你来天机项目和文档亲自探索!
## 实现送祝福微调模型
接下来,让我们快速实现一个属于自己的送祝福微调模型。我们将基于 Xtuner Qlora,详细讲解如何对 internLM2 进行天机送祝福模块的微调,全流程包括数据制造、推理微调等所有环节。
在本次微调示范中,我们选用的是 internlm2-chat-7b 模型,你需要准备一台24G显存的机器用于微调(3090即可)。
微调一个模型的第一步是准备高质量的训练数据。对于一个送祝福模型,你需要收集各种祝福语的数据,数据来源可以是公开的祝福语数据集、社交媒体、电子书籍或者任何包含丰富祝福语的文本。
在准备完成数据来源以及获取到对应数据后,你需要使用该数据文本进行数据制造(比如下面演示的few shot,但这只是最小的例子,真正意义的数据制造你需要用一个数据“知识”切块去生成对应的QA对,这是才是我们最后期望得到的数据。
所以,理论上最好的数据是利用这些现有知识,通过更聪明的大模型基于这些知识得到高精度的回复QA对数据,也有的人是通过大模型抽取小说文本对话的方式来实现格式抽取,但总之你需要的是一个最好无限火力的聪明大模型来帮助你进行文本数据清洗。
当你成功打通微调后,你会发现**真正复杂的工作都是在清洗数据、处理、生成数据、归类数据**上,这些才是影响最后效果的**最大难点问题**。
这里推荐你使用本地的llm去进行数据清洗(除非你财大气粗),否则api key很容易分分钟用完,你可以通过部署本地 llama3-chinese 或者 qwen 进行数据制造工作。
接下来我们来看看如何进行数据制造:
### 数据处理
#### 数据制造
在清洗数据前,请确保你已经安装对应SDK如zhipuai以及openai SDK,安装后直接运行即可。
```python
from zhipuai import ZhipuAI
import time
import json
import random
import datetime
# zhipuai
# 此处填写您自己的APIKey
# zhipu_api_key = ""
# client = ZhipuAI(api_key=zhipu_api_key)
# def get_data_zhipu(content):
# response = client.chat.completions.create(
# model="glm-4", # 填写需要调用的模型名称
# messages=[
# {"role": "system", "content": "你现在是一个精通言语表达、热爱他人、尊重长辈、富有文采的送祝福大师,请你编辑一条文本,表示对应场景的祝福语"},
# {"role": "user",
# "content": content,
# "temperature": 1} # 多样化输出
# ],
# )
# res = response.choices[0].message.content
# return res
# deepseek
from openai import OpenAI
deepseek_key = "" #此处填写deepseek的key
client = OpenAI(api_key=deepseek_key, base_url="https://api.deepseek.com/v1")
def get_data_ds(content):
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你现在是一个精通言语表达、热爱他人、尊重长辈、富有文采的送祝福大师,请你编辑一条文本,表示对应场景的祝福语"},
{"role": "user",
"content": content,
"temperature": 1} # 多样化输出
]
)
res = response.choices[0].message.content
return res
# 可利用大模型补充不同对象 当前28种
name_list = ['赵老师', '大舅', '大伯', '李总', '邻居赵大妈', '母亲', '姐姐', '妹妹', '哥哥', '弟弟', '爷爷', '奶奶', '外公',
'外婆', '伯母', '叔叔', '阿姨', '堂兄', '堂妹', '表哥', '表妹', '导师', '同学', '同事', '领导',
'邻居', '老板', '医生', ]
# 可利用大模型补充对应场景 当前18种
scenes = ['生日', '春节', '元宵节', '端午节', '七夕节', '中秋节',
'重阳节', '除夕', '腊八节','谈判顺利','乔迁新居', '周年纪念' ,'新婚快乐' ,'家庭和睦', '比赛取得好成绩' ,'发财','工作升职 ','康复', ]
# 可利用大模型补充不同风格,加入更多 fewshot 造出更好的数据
styles = {
"小红书":
{
"style_temple":"小红书风格,每条加入1-2个emoji表情包来增加趣味性。\n### 注意,你要参考下列句子的艺术风格进行祝福语撰写(注意!只看造句风格),祝福语结尾都带上语气助词词,参考句子为:{} ###",
"if_example":True,
"examples":
[
'默念你的名,祝你前途云蒸霞蔚,灿若星河。愿你度过的叫吉时,得到的叫如愿!',
'希望你岁末将至,敬颂冬绥,平安喜乐,万事胜意。',
'希望你不用奔赴大海,也能看到春暖花开;不用颠沛流离,也能遇到一生所伴!',
'祝我们好在春夏秋冬,祝你阔谈,祝你烂漫,祝你和自己相约在风里,此后只剩欢愉。',
'希望你可以明确地爱,直接的厌恶,真诚的喜欢,站在太阳下的坦荡,大声无愧地称赞自己,学会爱自己!',
'前方荣光万丈,身后温暖一方,凡是过往,皆为序章。',
'愿所念之人 平安喜乐。愿所想之事 顺心如意!',
]
},
"正常":
{
"style_temple":"正常风格,有礼貌即可",
"if_example":False,
"examples":[]
},
"严肃":
{
"style_temple":"商业严肃风格,要求用在职场或长辈祝福上,显得有礼貌、干练,句子可以长一些",
"if_example":False,
"examples":[]
}
}
random_finalprompt_sentence = [
'', #默认情况
'回答中可以不出现对象称谓和场景信息,也不用出现“愿你”“祝你”(对自己的长辈需要出现对象称谓和祝你),',
'回答中可以不出现对象称谓和场景信息,',
'回答中不用出现“愿你”“祝你”',
]
final_prompt = """
该祝福语字数小于 {} 字。 \n
请根据对象称谓及场景,写出符合对象的身份和场景气氛的祝福文案。要求的风格是:{} \n,注意不要有标题混在其中,对象称谓是:{},祝福场景是:{}\n
{} 根据不同对象用不同的语气(尊敬、诙谐搞笑、亲近),请直接返回祝福文本,不要说任何其他话:
"""
if __name__ == "__main__":
##### 此处配置 #####
roop_count = 2
now_count = 0
stylename = "小红书" # 小红书、正常、严肃
output_number_limit = 50 # 限制回答输出长度,严肃的100,普通的小于20
##### 此处配置 #####
for roop in range(roop_count):
conversations = []
for name in name_list:
for scene in scenes:
try:
if styles[stylename]['if_example']:
style_prompt = styles[stylename]['style_temple'].format(random.choice(styles[stylename]['examples']))
else:
style_prompt = styles[stylename]['style_temple']
input_prompt = final_prompt.format(output_number_limit, style_prompt, name, scene,random.choice(random_finalprompt_sentence))
response = get_data_ds(input_prompt)
now_count += 1
if '\n' in str(response):
response = str(response).split('\n')[0]
print(name,scene,'response:',response)
print("当前生成数目:", now_count)
if stylename == '正常':
# 默认不加风格指定
_input_prompt = f"{name}{scene}"
else:
_input_prompt = f"{name}{scene},{stylename}风格"
print("input:",_input_prompt)
conversation = {
"conversation": [
{
"system": "你现在是一个送祝福大师,帮我针对不同人和事情、节日送对应的祝福",
"src_input":input_prompt,
"style_name":stylename,
"input": _input_prompt,
"output": str(response).replace('\"','')
}
]
}
# 将对话加入到列表中
conversations.append(conversation)
except Exception as e:
print(e)
continue
now_time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
file_path = f"./wishes_{stylename}_{now_time}.json"
with open(file_path, "w", encoding='utf8') as f:
json.dump(conversations, f, ensure_ascii=False, indent=4)
```
**注意**,这里为什么需要把 input 替换成 `f"祝{name}{scene}"` 的格式——是因为这里的input需要尽可能模拟人的输入,而不能是制造数据时候的输入。此外,我们在此设定了三种风格:正常、小红书、严肃;期待当加上风格名触发后可以有预期的输出。
这只是最简单的示例,如何根据祝福语的长短不同而生成后的语法风格要对应变化、如何更接近真人的风格化;这些都需要高质量的数据 + 良好的数据制造方式才可获得。
举个例子,如果在这里我们想要控制祝福语长短和语法风格,首先前者我们就要在之前的制造条件中(比如之前的对象、场景是一个条件)加入新的祝福语长短控制条件(比如我这里的小红书和正常风),而且此时few shot参考的句子也应当有所不同,这样才能保证我们造数据的llm可以返回预期长度的结果。如果是控制语法风格,我们就需要爬取大量文艺书籍、小红书等真正人类写的文案进行清洗,然后利用这些作为few shot得到严格的返回,需要用严格的提示词让模型写出类似的语句或者单独微调一个属于该文艺范畴的模型版本用于制造对应数据(有时候few shot指令跟随不那么有用)。
💡代码中有 `random_xxxxxxx_sentence` 的部分表明这是一个随机性注入列表,我们可以维护一些语句用于提高随机性(比如附加条件的修改),让大模型返回的结果更具特色。
若成功运行,你将看到类似如下输出结果,等待片刻后将得到属于本地的json文件 `wishes_0501_5000.json`
```
同学 家庭和睦 response: "烟火年年,暖意洋洋,🏡❤️家是心之所向。"
当前生成数目: 914
同学 比赛取得好成绩 response: "灿若星河,前程似锦🌟,所得皆所愿!"
当前生成数目: 915
同学 发财 response: "春风得意马蹄疾,财源滚滚至君前🎉💰"
当前生成数目: 916
同学 工作升职 response: "升职之光,照亮星河,未来灿烂如霞。🌟🌈"
当前生成数目: 917
同学 康复祝福 response: "挥别病痛,如花开坚强。🌱✨愿你前程,云蒸霞蔚,身心俱灿。"
当前生成数目: 918
```
💡注意,这里只是粗暴的进行所有角色和场景的遍历,但**并非所有角色都适配所有场景**(很多是不合适的),这里为了改进应该做一个heatmap进行映射,若不合适生产该数据,将直接跳过;又或者是在得到数据后做一个匹配,如果同时满足不合适的角色+场景就去除该数据QA对。
#### 数据合并
因为我们之前的数据都是跑完一轮存一次(以防前功尽弃),所以可能你有多个json需要组合,这里提供了一个脚本合并一个文件夹中的所有json,并把json格式清洗成和训练脚本一致适配的格式:
```bash
import os
import json
def extract_and_merge_conversations(folder_path, output_file):
all_conversations = []
# 遍历指定文件夹
for filename in os.listdir(folder_path):
if filename.endswith('.json'):
file_path = os.path.join(folder_path, filename)
# 打开并读取JSON文件
with open(file_path, 'r', encoding='utf-8') as file:
data = json.load(file)
# 提取需要的字段
for item in data:
for conversation in item['conversation']:
extracted = {
'system': conversation['system'],
'input': conversation['input'],
'output': conversation['output']
}
# 将每个对话包装在一个 'conversation' 键中,并作为独立对象加入列表
all_conversations.append({'conversation': [extracted]})
# 将合并后的所有对话数据写入一个新的JSON文件
with open(output_file, 'w', encoding='utf-8') as file:
json.dump(all_conversations, file, ensure_ascii=False, indent=4)
# 使用示例
folder_path = 'tianji_wishes_datasets' # 要扫描的文件夹路径
output_file = 'tianji-wishes-chinese-v0.1.json' # 输出文件的名称和路径
extract_and_merge_conversations(folder_path, output_file)
```
合并后就是我们所需要的微调数据集。
#### 二次清洗
得到最初数据后,可能还存在一些奇怪的东西,比如句子长度返回错误,不是回答而是很短的一句 `当前祝福语如下` ,加入语气助词后容易出现 `!啦~` `。哦!` 如此在前面出现标点的奇怪现象,故我们需要利用清洗脚本对数据进行一定的筛选,由于比较冗长(还没有优雅的迭代),清洗脚本放在 [https://github.com/SocialAI-tianji/Tianji](https://github.com/SocialAI-tianji/Tianji),可以自行查看
当然,如果你有时间和精力,最重要的还是可以用人工进行清洗。当然,**最重要的还是最好在数据制造的时候就记录比较完好的信息和做出比较好的output,能大大节约二次清洗的时间。**
#### 直接下载
为了方便大家使用,这里提供了已制造数据的下载地址,大家可以自行从huggingface上获取:
[https://huggingface.co/datasets/sanbu/tianji-wishes-chinese/blob/main/tianji-wishes-chinese-v0.1.json](https://huggingface.co/datasets/sanbu/tianji-wishes-chinese/blob/main/tianji-wishes-chinese-v0.1.json)
镜像站下载:
[https://hf-mirror.com/datasets/sanbu/tianji-wishes-chinese](https://hf-mirror.com/datasets/sanbu/tianji-wishes-chinese)
### 环境准备
接下来我们准备微调的环境,由于时间关系(标准流程是一样的),这里只做省略快速操作,详细操作请参考 xtuner的官方教程 [https://github.com/InternLM/Tutorial/tree/main/xtuner](https://github.com/InternLM/Tutorial/tree/main/xtuner),或者是self-llm 项目中关于Xtuner Qlora的部分:[https://github.com/datawhalechina/self-llm/blob/master/InternLM2/04-InternLM2-7B-chat Xtuner Qlora 微调.md](https://github.com/datawhalechina/self-llm/blob/master/InternLM2/04-InternLM2-7B-chat%20Xtuner%20Qlora%20%E5%BE%AE%E8%B0%83.md)
⚠ 以下基于 **python 3.10** 构建全过程,请注意版本
首先创建一个虚拟环境,随后安装如下依赖
```python
python -m pip install --upgrade pip
pip install modelscope==1.9.5
pip install transformers==4.36.2
pip install streamlit==1.39.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
pip install einops ujson
pip install protobuf
```
安装xtuner
```
git clone -b v0.1.18 https://github.com/InternLM/xtuner
cd xtuner && pip install -e '.[all]'
# 验证成功
xtuner version
```
模型下载
找地方执行下列python文件
```python
from modelscope import snapshot_download
model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm2-chat-7b', cache_dir='./model_temp', revision='master')
```
完成上述过程后就可以正式进入微调阶段。
### 正式微调
为了微调自己的数据集配置,我们需要修改xtuner的config,首先查看有哪些配置:
```python
xtuner list-cfg | grep internlm2
internlm2_7b_full_finetune_custom_dataset_e1
internlm2_7b_full_finetune_custom_dataset_e1_sequence_parallel_4
internlm2_7b_qlora_alpaca_e3
internlm2_7b_qlora_arxiv_gentitle_e3
internlm2_7b_qlora_code_alpaca_e3
internlm2_7b_qlora_colorist_e5
internlm2_7b_qlora_json_e3
internlm2_7b_qlora_lawyer_e3
internlm2_7b_qlora_msagent_react_e3_gpu8
internlm2_7b_qlora_oasst1_512_e3
internlm2_7b_qlora_oasst1_e3
internlm2_7b_qlora_sql_e3
```
```python
# 新建一个用于微调工作的文件夹
mkdir /home/finetune
# 复制配置文件
cd /home/finetune && xtuner copy-cfg internlm2_chat_7b_qlora_oasst1_e3 ./
```
接下来我们需要修改配置文件,简单来说你要做这几处修改:
```python
# 修改模型为本地路径
- pretrained_model_name_or_path = 'internlm2/internlm2-chat-7b'
+ pretrained_model_name_or_path = '/home/model_temp/Shanghai_AI_Laboratory/internlm2-chat-7b'
# 修改训练数据集为本地路径
- data_path = 'timdettmers/openassistant-guanaco'
+ data_path = '/home/merged_data.json'
# 修改Evaluate
-
evaluation_freq = 500
SYSTEM = ''
evaluation_inputs = [
'请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai'
]
+
evaluation_freq = 50
SYSTEM = '你现在是一个送祝福大师,帮我针对不同人和事情、节日送对应的祝福'
evaluation_inputs = [
'祝姐姐生日快乐', '祝妹妹谈判顺利','祝大家元宵节快乐'
]
# 修改数据集加载
- dataset=dict(type=load_dataset, path=data_path),
+ dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)),
```
以下是修改后的结果,你可以直接复制(只要修改模型路径和训练集路径,以及Evaluate的input,就可以把他变为你自己的配置文件开始训练。)
或者,你也可以在 tianji 的主仓库中获得所有使用 xtuner 的微调配置 `https://github.com/SocialAI-tianji/Tianji/tree/main/tianji/finetune/xtuner`
```python
# Copyright (c) OpenMMLab. All rights reserved.
import torch
from datasets import load_dataset
from mmengine.dataset import DefaultSampler
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,
LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from peft import LoraConfig
from torch.optim import AdamW
from transformers import (AutoModelForCausalLM, AutoTokenizer,
BitsAndBytesConfig)
from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.map_fns import oasst1_map_fn, template_map_fn_factory
from xtuner.engine.hooks import (DatasetInfoHook, EvaluateChatHook,
VarlenAttnArgsToMessageHubHook)
from xtuner.engine.runner import TrainLoop
from xtuner.model import SupervisedFinetune
from xtuner.utils import PROMPT_TEMPLATE
#######################################################################
# PART 1 Settings #
#######################################################################
# Model
pretrained_model_name_or_path = '/home/model_temp/Shanghai_AI_Laboratory/internlm2-chat-7b'
use_varlen_attn = False
# Data
data_path = '/home/tianji-wishes-test_0502.json'
prompt_template = PROMPT_TEMPLATE.internlm2_chat
max_length = 2048
pack_to_max_length = True
# Scheduler & Optimizer
batch_size = 1 # per_device
accumulative_counts = 16
dataloader_num_workers = 0
max_epochs = 3
optim_type = AdamW
lr = 2e-4
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1 # grad clip
warmup_ratio = 0.03
# Save
save_steps = 50
save_total_limit = 10 # Maximum checkpoints to keep (-1 means unlimited)
# Evaluate the generation performance during the training
evaluation_freq = 50
SYSTEM = '你现在是一个送祝福大师,帮我针对不同人和事情、节日送对应的祝福'
evaluation_inputs = [
'祝姐姐生日快乐','祝姐姐生日快乐,严肃风格','祝姐姐生日快乐,小红书风格', '祝妹妹谈判顺利,小红书风格','祝大家元宵节快乐','祝领导春节快乐,严肃风格'
]
#######################################################################
# PART 2 Model & Tokenizer #
#######################################################################
tokenizer = dict(
type=AutoTokenizer.from_pretrained,
pretrained_model_name_or_path=pretrained_model_name_or_path,
trust_remote_code=True,
padding_side='right')
model = dict(
type=SupervisedFinetune,
use_varlen_attn=use_varlen_attn,
llm=dict(
type=AutoModelForCausalLM.from_pretrained,
pretrained_model_name_or_path=pretrained_model_name_or_path,
trust_remote_code=True,
torch_dtype=torch.float16,
quantization_config=dict(
type=BitsAndBytesConfig,
load_in_4bit=True,
load_in_8bit=False,
llm_int8_threshold=6.0,
llm_int8_has_fp16_weight=False,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type='nf4')),
lora=dict(
type=LoraConfig,
r=64,
lora_alpha=16,
lora_dropout=0.1,
bias='none',
task_type='CAUSAL_LM'))
#######################################################################
# PART 3 Dataset & Dataloader #
#######################################################################
train_dataset = dict(
type=process_hf_dataset,
dataset=dict(type=load_dataset, path='json', data_files=dict(train=data_path)),
tokenizer=tokenizer,
max_length=max_length,
dataset_map_fn=None,
template_map_fn=dict(
type=template_map_fn_factory, template=prompt_template),
remove_unused_columns=True,
shuffle_before_pack=True,
pack_to_max_length=pack_to_max_length,
use_varlen_attn=use_varlen_attn)
train_dataloader = dict(
batch_size=batch_size,
num_workers=dataloader_num_workers,
dataset=train_dataset,
sampler=dict(type=DefaultSampler, shuffle=True),
collate_fn=dict(type=default_collate_fn, use_varlen_attn=use_varlen_attn))
#######################################################################
# PART 4 Scheduler & Optimizer #
#######################################################################
# optimizer
optim_wrapper = dict(
type=AmpOptimWrapper,
optimizer=dict(
type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay),
clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False),
accumulative_counts=accumulative_counts,
loss_scale='dynamic',
dtype='float16')
# learning policy
# More information: https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/param_scheduler.md # noqa: E501
param_scheduler = [
dict(
type=LinearLR,
start_factor=1e-5,
by_epoch=True,
begin=0,
end=warmup_ratio * max_epochs,
convert_to_iter_based=True),
dict(
type=CosineAnnealingLR,
eta_min=0.0,
by_epoch=True,
begin=warmup_ratio * max_epochs,
end=max_epochs,
convert_to_iter_based=True)
]
# train, val, test setting
train_cfg = dict(type=TrainLoop, max_epochs=max_epochs)
#######################################################################
# PART 5 Runtime #
#######################################################################
# Log the dialogue periodically during the training process, optional
custom_hooks = [
dict(type=DatasetInfoHook, tokenizer=tokenizer),
dict(
type=EvaluateChatHook,
tokenizer=tokenizer,
every_n_iters=evaluation_freq,
evaluation_inputs=evaluation_inputs,
system=SYSTEM,
prompt_template=prompt_template)
]
if use_varlen_attn:
custom_hooks += [dict(type=VarlenAttnArgsToMessageHubHook)]
# configure default hooks
default_hooks = dict(
# record the time of every iteration.
timer=dict(type=IterTimerHook),
# print log every 10 iterations.
logger=dict(type=LoggerHook, log_metric_by_epoch=False, interval=10),
# enable the parameter scheduler.
param_scheduler=dict(type=ParamSchedulerHook),
# save checkpoint per `save_steps`.
checkpoint=dict(
type=CheckpointHook,
by_epoch=False,
interval=save_steps,
max_keep_ckpts=save_total_limit),
# set sampler seed in distributed evrionment.
sampler_seed=dict(type=DistSamplerSeedHook),
)
# configure environment
env_cfg = dict(
# whether to enable cudnn benchmark
cudnn_benchmark=False,
# set multi process parameters
mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
# set distributed parameters
dist_cfg=dict(backend='nccl'),
)
# set visualizer
visualizer = None
# set log level
log_level = 'INFO'
# load from which checkpoint
load_from = None
# whether to resume training from the loaded checkpoint
resume = False
# Defaults to use random seed and disable `deterministic`
randomness = dict(seed=None, deterministic=False)
# set log processor
log_processor = dict(by_epoch=False)
```
接下来对新的配置直接开始训练(如果你显存不够,可以切换成 `--deepspeed deepspeed_zero3` )
```bash
xtuner train ./internlm2_chat_7b_qlora_oasst1_e3_copy.py --deepspeed deepspeed_zero2
```
训练结束后,所有权重文件放置在训练目录下的work_dirs中,目录大致为:
```python
drwxr-xr-x 3 root root 4096 May 2 12:23 20240502_122337/
-rw-r--r-- 1 root root 6413 May 2 12:24 internlm2_chat_7b_qlora_oasst1_e3_copy.py
-rw-r--r-- 1 root root 1886589762 May 2 12:43 iter_500.pth
-rw-r--r-- 1 root root 1886601474 May 2 12:50 iter_657.pth
-rw-r--r-- 1 root root 76 May 2 12:50 last_checkpoint
```
值得注意的是,这里通常只需要微调一轮就好,原因是llm通常是过目不忘(有很多相关研究)容易过拟合。
- 如果你想查看更多超参数对结果带来的变动,请参考:
LoRA和QLoRA微调语言大模型:数百次实验后的见解 - OneFlow的文章 - 知乎
[https://zhuanlan.zhihu.com/p/664912829](https://zhuanlan.zhihu.com/p/664912829)
- 如果你想使用全量微调,对于 internlm2-7B 请至少准备 2xA100 80G 的显卡使用下列命令启用微调。(建议你使用“万”级别的数据再进行全量微调,目前天机相关数据还不足以支持好的全量微调)推荐混入更多正常对话数据来确保全量微调效果正常。NPROC_PER_NODE 的值表示使用几张显卡进行微调,此时双卡每张卡显存占用接近 79G。
```bash
NPROC_PER_NODE=2 xtuner train ./全量微调配置.py --deepspeed deepspeed_zero3
```
### 效果验证
首先我们需要转换格式为hf,再与原模型合并,这里提供了统一脚本:
```bash
HF_OUTPUT_DIR="./hf" # lora转为hf格式后的输出地址
MERGE_OUTPUT_DIR="./merge" # 与原模型合并后的输出地址
SCRIPT_PATH="./internlm2_chat_7b_qlora_oasst1_e3_copy.py" # 训练配置文件
SRC_MODEL_PATH="/home/model_temp/Shanghai_AI_Laboratory/internlm2-chat-7b" # 原模型地址
WEIGHTS_PATH="/home/finetune/work_dirs/internlm2_chat_7b_qlora_oasst1_e3_copy/iter_150.pth" # lora权重地址
rm -rf $HF_OUTPUT_DIR
rm -rf $MERGE_OUTPUT_DIR
mkdir -p $HF_OUTPUT_DIR
mkdir -p $MERGE_OUTPUT_DIR
xtuner convert pth_to_hf "${SCRIPT_PATH}" "${WEIGHTS_PATH}" "${HF_OUTPUT_DIR}"
xtuner convert merge \
"${SRC_MODEL_PATH}" \
"${HF_OUTPUT_DIR}" \
"${MERGE_OUTPUT_DIR}" \
--max-shard-size "2GB"
```
如果这步报错,请检查 WEIGHTS_PATH 是否正确。
当然,你也可以不合并(合并后就可以上传权重),而是转换后直接加载lora,对应脚本如下:
```bash
HF_OUTPUT_DIR="./hf" # lora转为hf格式后的输出地址
SCRIPT_PATH="./internlm2_chat_7b_qlora_oasst1_e3_copy.py" # 训练配置文件
SRC_MODEL_PATH="/home/model_temp/Shanghai_AI_Laboratory/internlm2-chat-7b"
WEIGHTS_PATH="/home/finetune/work_dirs/internlm2_chat_7b_qlora_oasst1_e3_copy/iter_150.pth"
rm -rf $HF_OUTPUT_DIR
rm -rf $MERGE_OUTPUT_DIR
mkdir -p $HF_OUTPUT_DIR
xtuner convert pth_to_hf "${SCRIPT_PATH}" "${WEIGHTS_PATH}" "${HF_OUTPUT_DIR}"
xtuner chat "${SRC_MODEL_PATH}" --adapter "${HF_OUTPUT_DIR}" --prompt-template internlm2_chat --system "你现在是一个送祝福大师,帮我针对不同人和事情、节日送对应的祝福" --temperature 0.7
```
启动对话:
```python
# 如果想要多样性更强加上 --temperature 1
xtuner chat ./merge --prompt-template internlm2_chat --system "你现在是一个送祝福大师,帮我针对不同人和事情、节日送对应的祝福" --temperature 0.7
```
此时你会看到如下显示,你只需要恰当的输入之前的prompt和触发风格即可验证。这里比较不方便的是为了去除上下文影响,我们需要反复输入RESET进行重置。
```bash
double enter to end input (EXIT: exit chat, RESET: reset history) >>> 祝弟弟工作升职 ,小红书风格
弟弟呀,你的才华如同春日里的花朵,绽放出绚烂的光彩。工作如鱼得水,升职之路顺顺利利,愿你继续闪耀,成为职场的明星!加油哦!🌟🌈<|im_end|>
double enter to end input (EXIT: exit chat, RESET: reset history) >>> RESET
Log: History responses have been removed!
double enter to end input (EXIT: exit chat, RESET: reset history) >>> 我想送哥哥中秋节祝福,小红书风格
🌕🎉 哥,中秋月圆人团圆,愿你事业如月圆,家庭幸福似团圆,快乐满怀,幸福满满!🌟<|im_end|>
double enter to end input (EXIT: exit chat, RESET: reset history) >>> RESET
Log: History responses have been removed!
double enter to end input (EXIT: exit chat, RESET: reset history) >>> 我想送赵老师生日祝福,严肃风格
尊敬的赵老师,值此佳辰,恭祝您福寿安康,事业蒸蒸日上。愿您在未来的岁月里,如同春日之花,绽放出更加绚烂的光彩,为莘莘学子树立起崇高的榜样。愿您的生活如同诗篇般美好,每一天都充满着智慧与喜悦。愿您的工作如同乐章般动听,每一个音符都承载着对教育事业的热爱与执着。在此,衷心祝愿您生日快乐,万事胜意!<|im_end|>
```
### 网页demo
为了方便测试,我们还可以使用streamlit的demo,使用方法如下:
`pip install streamlit==1.39.0`
```
# 找地方clone仓库
git clone https://github.com/InternLM/InternLM.git
```
将 `/root/code/InternLM/web_demo.py` 中 29 行和 33 行的模型路径更换为Merge后存放参数的路径 `/home/finetune/merge`
按照如下命令运行 `/root/personal_assistant/code/InternLM` 目录下的 `web_demo.py` 文件即可。
```python
streamlit run /root/personal_assistant/code/InternLM/web_demo.py --server.address 127.0.0.1 --server.port 6006
```
通过以上步骤,你就可以成功地微调出最初版本的天机送祝福模块并成功运行推理。
但由于制造数据的质量仍有改善空间、回答随机性注入、输入input的随机性加强仍有很多方式可以实现,送祝福完全可以变得更好、更智能、更通用,从而真正更接近中文下的使用场景,让llm对话更富有“人情味”。
## 感谢每一位贡献者
由于贡献者人数众多无法一一列举,我们由衷的感谢每一位为天机项目做出贡献的小伙伴,是他们让这个项目变得更好。我们也期待你的加入。相信我,你也可以变成光!
https://github.com/SocialAI-tianji/Tianji/blob/main/docs/contributor.md
+54
View File
@@ -0,0 +1,54 @@
# Examples
在学习者完成了基础知识的学习之后,我们将提供一系列精选的实际案例,帮助学习者更深入地理解和掌握大模型应用开发的核心技术。通过这些案例,学习者可以基于实际应用类型,探讨和实践如何有效地利用大模型来解决实际问题。我们的目标是,通过提供这些优秀的大模型应用项目示范(Demo),使学习者能够在完成我们的示例后,更全面地掌握大模型应用开发的技术要点,并具备独立进行大模型应用的二次开发或自主开发的能力。
## Examples 目录
### [Chat-嬛嬛](./Chat-嬛嬛/readme.md)
**Chat-甄嬛**是利用《甄嬛传》剧本中所有关于甄嬛的台词和语句,基于LLM进行**LoRA微调**得到的模仿甄嬛语气的聊天语言模型。
> 甄嬛,小说《后宫·甄嬛传》和电视剧《甄嬛传》中的女一号,核心女主角。原名甄玉嬛,嫌玉字俗气而改名甄嬛,为汉人甄远道之女,后被雍正赐姓钮祜禄氏,抬旗为满洲上三旗,获名“钮祜禄·甄嬛”。同沈眉庄、安陵容参加选秀,因容貌酷似纯元皇后而被选中。入宫后面对华妃的步步紧逼,沈眉庄被冤、安陵容变心,从偏安一隅的青涩少女变成了能引起血雨腥风的宫斗老手。雍正发现年氏一族的野心后令其父甄远道剪除,甄嬛也于后宫中用她的连环巧计帮皇帝解决政敌,故而深得雍正爱待。几经周折,终于斗垮了嚣张跋扈的华妃。甄嬛封妃时遭皇后宜修暗算,被皇上嫌弃,生下女儿胧月后心灰意冷,自请出宫为尼。然得果郡王爱慕,二人相爱,得知果郡王死讯后立刻设计与雍正再遇,风光回宫。此后甄父冤案平反、甄氏复起,她也生下双生子,在滴血验亲等各种阴谋中躲过宜修的暗害,最后以牺牲自己亲生胎儿的方式扳倒了幕后黑手的皇后。但雍正又逼甄嬛毒杀允礼,以测试甄嬛真心,并让已经生产过孩子的甄嬛去准格尔和亲。甄嬛遂视皇帝为最该毁灭的对象,大结局道尽“人类的一切争斗,皆因统治者的不公不义而起”,并毒杀雍正。四阿哥弘历登基为乾隆,甄嬛被尊为圣母皇太后,权倾朝野,在如懿传中安度晚年。
Chat-甄嬛,实现了以《甄嬛传》为切入点,打造一套基于小说、剧本的**个性化 AI** 微调大模型完整流程,通过提供任一小说、剧本,指定人物角色,运行本项目完整流程,让每一位用户都基于心仪的小说、剧本打造一个属于自己的、契合角色人设、具备高度智能的个性化 AI。
> *Chat-嬛嬛模型累计下载量 15.6k+Modelscope 地址:*[*Link*](https://www.modelscope.cn/models/kmno4zx/huanhuan-chat-internlm2)
> *Chat-嬛嬛累计获得 500 starhuahuan-chat 项目地址:*[*Link*](https://github.com/KMnO4-zx/huanhuan-chat.git)xlab-huanhuan-chat 项目地址:[*Link*](https://github.com/KMnO4-zx/xlab-huanhuan.git)
- *2023 讯飞星火杯人认知大模型场景创新赛 Top50*
- *2024 书生·浦语大模型挑战赛(春季赛)创意应用奖 Top12*
### [天机](./Tianji-天机/readme.md)
想从零学会大语言模型应用?想直接复制粘贴代码?天机满足你的一切需求;甚至,你还能学到一点意想不到的东西。
中国文化注重人情世故,涉及到复杂的社交规则、礼仪和人际关系。Social 团队通过深入理解中文语境、文化特点和丰富的语料,提供了基于各类中国式文化的场景下的应对方法、对话案例与情景模拟。
目前天机已经支持的应用场景包括:如何送**祝福、敬酒、请客、送礼、人际交流、化解尴尬以及应对矛盾**等等,还有更多社区小伙伴们建议的 LLM 提高情商方案正在制作中~
除了把这个项目当成一个好玩的社交大模型外,你还可以把它当作完整的全栈大语言模型应用入门学习仓库! 你可以在里面学到**提示词工程 、智能体制作、 模型微调、RAG 数据清洗与使用,以及代码规范**...等等你所需要的大语言模型应用知识,你可以在通过学习该项目后,  快速改造出属于自己的新的大语言模型项目,我们期待你成为下一个大模型应用开发高手!
> *Tianji 开源链接:*[*Link*](https://github.com/SocialAI-tianji/Tianji)
> *Tianji 官方网站:*[*Link*](https://socialai-tianji.github.io/socialai-web/)
> *Tianji 官方文档:*[*Link*](https://tianji.readthedocs.io/en/latest/)
> *Tianji 知识库版应用地址:*[*Link*](http://120.76.130.14:6006/knowledges/)
> *Tianji prompt版应用地址:*[*Link*](http://120.76.130.14:6006/prompt/)
> *Tianji 视频介绍:*[*Link*](https://www.bilibili.com/video/BV1cvbyefEfp)
- *2024 书生·浦语社区优秀大模型应用*
### [AMchat-高等数学](./AMchat-高等数学/readme.md)
AM (Advanced Mathematics) chat 是一个集成了数学知识和高等数学习题及其解答的大语言模型。该模型使用 Math 和高等数学习题及其解析融合的数据集,基于 InternLM2-Math-7B 模型,通过 xtuner 微调,专门设计用于解答高等数学问题。
> *AMchat 项目地址:*[*Link*](https://github.com/AXYZdong/AMchat)
> *AMchat模型: Modelscope 地址:[*Link*](https://www.modelscope.cn/models/yondong/AMchat/summary)* *OpenXLab 地址:[*Link*](https://openxlab.org.cn/models/detail/youngdon/AMchat)*HuggingFace 地址:[*Link*](https://huggingface.co/axyzdong/AMchat)
> *AMchat GGFU模型地址:[Link](https://huggingface.co/axyzdong/AMchat-GGUF)*
> *AMchat 应用地址:*[*Link*](https://openxlab.org.cn/apps/detail/youngdon/AMchat)
> *AMchat 视频介绍:*[*Link*](https://www.bilibili.com/video/BV14v421i7So/)
- *2024 书生·浦语大模型挑战赛(春季赛)创意应用奖 Top12*
### [数字生命](./数字生命/readme.md)
本项目将以我为原型,利用特制的数据集对大语言模型进行微调,致力于创造一个能够真正反映我的个性特征的AI数字人——包括但不限于我的语气、表达方式和思维模式等等,因此无论是日常聊天还是分享心情,它都以一种既熟悉又舒适的方式交流,仿佛我在他们身边一样。整个流程是可迁移复制的,亮点是数据集的制作。
> *MBTI数据集github地址([[https://huggingface.co/datasets/pandalla/Machine_Mindset_MBTI_dataset`]]
- *2024 大模型微调挑战赛(冬季赛)最佳创意奖 Top3*
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+251
View File
@@ -0,0 +1,251 @@
# 如何练就一个我
本项目将以我为原型,利用特制的数据集对大语言模型进行微调,致力于创造一个能够真正反映我的个性特征的AI数字人——包括但不限于我的语气、表达方式和思维模式等等,因此无论是日常聊天还是分享心情,它都以一种既熟悉又舒适的方式交流,仿佛我在他们身边一样。整个流程是可迁移复制的,亮点是数据集的制作。
> 项目背景详情
>
> 由于现下生活节奏加快,许多人因工作繁忙或地理距离而难以时常陪伴家人与朋友,导致情感上的疏离感加剧。在这个数字化快速发展的时代,人们越来越渴望通过技术手段弥补时间和空间上的隔阂。因而AI情感陪伴类产品应运而生,然而,尽管市场需求巨大,现有的AI情感陪伴服务仍存在诸多不足。一个是定制化服务成本高昂,难以普及,一个是信息安全难以保障,还有一个是人格化缺失,容易让人出戏。综合考量下,我们认为在角色扮演上微调不失为一个可行的路子。因为微调是在预训练模型基础上再学习,模型本身已经有较强的文本理解能力、逻辑能力、泛化能力等,只需要一些特定人物个性风格的数据加成就能很好的扮演我们想要的角色了。
*好的~接下来就让我们开始沉浸式体验一下一个暖心AI的完整训练流程吧~*
---
注意,本次演示,是基于github开源项目[“留痕”](https://github.com/LC044/WeChatMsg)、 [讯飞星辰MaaS平台](https://training.xfyun.cn/modelSquare)
## 数据集的制作
首先我们需要获取原始数据,即微信聊天记录的JSON格式。先在电脑端登录微信,同步聊天信息,接着我们进github项目页把“留痕”相关的文件下载到电脑本地,然后运行MemoTrace.exe文件,把应用激活。选择和某个朋友的聊天记录,将聊天内容导出为JSON格式保存至电脑(由于时间考虑,我就不赘述了,大家可以按照项目自述文档操作),结束可以在VSCode中打开查看,内容包括conversations、role和content三个字段,为了便于模型更好地学习,我们需要再“精修”一下,可参考以下数据处理的大致思路:
```
# -*- coding: utf-8 -*-
import json
from copy import deepcopy
#标准化角色命名   
def convert_to_sharegpt_format(original_data,new_system_value=None):
    sharegpt_data = []
    for conversation in original_data:
        new_conversation = {
            "conversations": [],
            "system":  new_system_value,
            "tools": "[]"  # 如果没有工具调用,可以留空或设置为空列表
        }      
        system_message = None
        for msg in conversation["conversations"]:
            # if msg["role"] == "system":
            #     system_message = msg["content"]
            if msg["role"] == "user":
                new_conversation["conversations"].append({
                    "from": "human",
                    "value": clean_content(msg["content"])
                })
            elif msg["role"] == "assistant":
                new_conversation["conversations"].append({
                    "from": "gpt",
                    "value": clean_content(msg["content"])
                })
               
#如果原始数据中已经存在"role": "system"的消息,那么这个消息的内容会被优先用于设置新对话的"system"字段。因此,即使你在调用convert_to_sharegpt_format时传递了new_system_value参数,一旦遇到原始数据中定义的系统消息,它就会覆盖你传入的新值。     
        # # 将系统消息设置为system字段
        # if system_message:
        #     new_conversation["system"] = system_message
        sharegpt_data.append(new_conversation)
    return sharegpt_data
# 读取原始JSON数据
with open('z.json', 'r', encoding='utf-8') as f:
    original_data = json.load(f)
# 转换为ShareGPT格式
# 批量修改"system"的值为"New System Value"
#添加优化系统提示词,可以理解为人设前提
new_system_value = "你是(替换为主角名字,人设),对你来说,他人的需求感受在自己之前。此外,你很喜欢倾听......"
sharegpt_formatted_data = convert_to_sharegpt_format(original_data, new_system_value)
# 写入新的JSON文件
with open('sharegpt_formatted_data.json', 'w', encoding='utf-8') as f:
    json.dump(sharegpt_formatted_data, f, ensure_ascii=False, indent=2)
print("数据转换完成并保存为 sharegpt_formatted_data.json")
```
这里我们用ShareGPT的格式主要是它适用于多轮对话的模型训练,相较于别的格式更适用于角色扮演的场景,其次就是规范了角色命名,便于模型的理解,一定程度避免混淆幻觉,还有一个就是人设的完善补充,还有最重要的一点,一定一定要记得对数据集进行敏感信息脱敏(包括电话,密码,地址等)!!!!!~~
记得改系统提示词的值(system),文件保存位置等!!!
*对于这个数据集,有两个特别的点,大家可参考保留优化,一个就是我保留所有的颜文字、表情包转的文字(如[委屈]等),因为经过实验证明,这有助于大模型理解话语的情感色彩特征,并能模仿到个性化的表达方式,我们发现微调后它能根据语境适时也配上颜文字和表情包返回给用户。一个就是我改写了MBTI的数据集,将我自己对应的那个人格的思维数据集按照聊天信息的形式格式改编,把一些比较有代表性的问题场景改成对话加到数据集里,这将更便于模型捕捉角色思维模式的特征。*
MBTI数据集github地址([[https://huggingface.co/datasets/pandalla/Machine_Mindset_MBTI_dataset`]]
再有就是要注意对对话片段内容不完整的进行筛选处理,包括但不限于补充对话、删除一些话题跳跃的片段等。我们大概有3000条数据,考虑到我很多时候话题都比较跳跃,没连着回答问题,所以我是人为再清洗处理。有些话题跳跃严重的片段给模型带来较大的理解难度,一些人为去除,对于某些存在跳跃但有价值的对话,我们尝试添加适当的背景信息,帮助模型建立正确的语境。
当然对于精修,大家可以继续探索,比如接入对话情绪色彩判断的API,添加情感标签、描述角色的性格特点、职业背景、兴趣爱好等的特征标签,都有利于AI数字人的人性化、个性化,示例如下。
```
{ "from": "gpt", "value": "学会了吗[笑]", "character_traits": { "personality": "聪明、热情、善良", "occupation": "程序员", "interests": ["编程", "阅读", "旅行"] } }
```
> [!NOTE] 数据集说明
> 为什么我们选择聊天记录来做数据集,原因无他,我们日常的交流就能在脑海中渐渐描摹出一个人的模样,慈眉善目的,或是天真可爱的,都通过我们和朋友家人的日常交流中的很多细节不断在显现,那让模型学一个人模仿一个人,不就是在这些细节里磨炼吗,这无疑是造就一个灵魂分身最好的模版,所以我们选择在聊天场景、内容中下功夫~~
好了,那数据集就先告一段落,接下来就到讯飞星辰MaaS平台进行微调.
## 模型微调训练
这一步,我们使用的是[讯飞星辰MaaS平台](https://training.xfyun.cn/modelSquare),大家可以根据自己的需要自行选择,其实主要就是需要开源的通用大模型,然后把数据集给它进行训练学习(微调),这里使用教程可以看看Datawhale的官方教程[零基础定制你的专属大模型](https://www.datawhale.cn/activity/110?subactivity=21)作为参考,这里就不赘述了~
不过要注意一点,按照我们上面的步骤,我们的数据集属于ShareGPT格式,别选错了~
>
> 首先是对一些参数的设置提一些建议以供参考:学习率(Learning Rate)和训练次数(Epochs)是两个关键的超参数,它们对最终模型性能有着重要影响。选择合适的学习率和训练次数需要结合具体任务、数据集特征以及计算资源来综合考虑。一个过大的学习率可能会导致模型无法收敛,而太小的学习率则可能导致训练过程缓慢甚至陷入局部最优解。因此,在微调阶段通常使用较小的学习率,以避免破坏已经学到的有用信息 。可以将这个参数理解为它依据学习内容去改变它自己认知的幅度的大小,建议是从小开始,这样会较大程度保证损失函数曲线的平缓,不太震荡。训练次数即整个训练集被遍历的次数。微调通常不需要太多的训练周期,因为预训练的模型已经具备了一定的知识基础。还有,如果数据集本身不大(少于500条),过多的训练周期可能会导致过拟合,即模型在训练集上表现很好,但在未见过的数据上表现不佳。对于这两个参数,可以结合训练的Loss曲线进行不断地调整,目的就是让曲线不要过于震荡,也不能太平,太平可能过拟合~然后就是温度系数,我的实验结果显示0.9为佳,大家也可以根据回应的效果多调试。
> 其次就是微调方式的选择,主要考虑Lora和全量精调,那为什么我最终选择Lora,而不是全量精调,我们综合考虑时间和资源成本,我们采用LoRa微调,当数据集规模较小时,实际上没有必要对所有参数进行全面调整,因为大部分预训练模型已经具备了良好的初始化和特征提取能力。在这种情况下,采用全量精调不仅增加了不必要的计算负担,还可能导致训练过程变得冗长且低效。当然数据集很大的话另说(几万条)。
比较好的微调效果大概会像下面这样:
![](/images/图片1.png)
![](/images/图片2.png)
(里面的原型就是我,我回答喜欢颜文字和各种表情包,会让对方感觉很温馨,我也比较在意一些标点符号的情感表达,可以看到我是对感叹号波浪号等非常情有独钟的哈哈哈哈,整体来说,效果是比较不错的~)
## 前端页面展示
这一步主要是需要调用你微调好的模型的API,我们做了一个比较美观的聊天界面展示,大家可以模仿探索一下,还是比较有意思的,考验你的审美了。这里主要展示一下API调用的相关代码,我们的API调用是通过*WebSocket连接*到训练好的模型的API:
```
            async function handleSendMessage() {
                const message = userInput.value.trim();
                if (!message) return;
                addMessage('用户', message, 'user-message');
                userInput.value = '';
#这里是在讯飞平台里微调好并发布的模型的地址,改成你自己的!!
                const ws = new WebSocket('wss://maas-api.cn-huabei-XX');
#以下几行为API调用,在“服务管控”页的右下角“信息调用”处
                ws.onopen = () => {
                    const requestData = {
#这要改成你自己的相关API!!
                        header: {
                            app_id: "XXXXXXXX",
                            uid: "XXXXX",
                            patch_id: ["XXXXXXXXXXXXXXXXXXX"]
                        },
                        parameter: {
                            chat: {
#这里我们选用的事星火13b的模型进行微调,如果不是用的这个,记得看讯飞平台的API调用文档说明,对应的改!!
                                domain: "xspark13b6k",
#这是温度系数
                                temperature: 0.9
                            }
                        },
                        payload: {
                            message: {
                                text: [
                                    { "role": "user", "content": message }
                                ]
                            }
                        }
                    };
                    console.log(message)
                    ws.send(JSON.stringify(requestData));
                };
                let fullResponse = ''; // 用于存储完整的AI响应
                ws.onmessage = (event) => {
                    const response = JSON.parse(event.data);
                    if (response.header.code === 0) {
                        // 拼接每次接收到的内容
                        const aiResponsePart = response.payload.choices.text.map(choice => choice.content).join('');
                        fullResponse += aiResponsePart;
                        // 检查是否是最后一次响应
                        if (response.payload.choices.status === 2) {
                            addMessage('AI', fullResponse, 'ai-message');
                        }
                    } else {
                        console.error('Error:', response.header.message);
                        addMessage('AI', '抱歉,服务器出现错误,请稍后再试。', 'ai-message');
                    }
                };
                ws.onerror = (error) => {
                    console.error('WebSocket Error:', error);
                    addMessage('AI', '抱歉,连接出现错误,请稍后再试。', 'ai-message');
                };
                ws.onclose = () => {
                    console.log('WebSocket connection closed');
                };
            }
```
这段代码定义了一个名为`handleSendMessage`的异步函数,它在用户点击发送按钮时被调用。函数首先获取用户输入的消息,然后通过 ___WebSocket连接___ 到指定的API端点。在连接成功后,它发送一个包含用户消息的JSON请求数据。接着,它监听WebSocket的`onmessage`事件,接收并处理API返回的响应,将响应内容拼接起来,并在接收到完整响应后将其显示在聊天界面中。如果发生错误或连接关闭,它会相应地处理这些情况并在聊天界面中显示错误信息~~
成功后,效果大概会是下面这样:
![](屏幕截图 2025-01-23 010103.png)
那现在你就可以日常没事逗逗他/她啦~
好啦,如果你到这一步结束了,恭喜你!!!!已经拥有了你梦寐以求的那个人的灵魂分身了,它应该可以让你或者别的用户沉浸式体验有温度的陪伴啦!!!当然,这个还可以拓展,主要是这个思路,还能继续迁移到别的应用场景,比如你喜欢的世界上可能不存在的动漫角色,比如早已离你而去的亲人,都可以,只要是情感陪伴相关的,其实都可以尝试一下,*我们的终极目标就是降低成本,让更多的人可以享受到这种形式的暖心陪伴,然后探索怎么在这个过程中不让人出戏,想想,要是在你向它倾诉时,出于一些敏感词的规避设置,它回你一句对不起,我只是一个语言大模型,那真是让人心都凉了呢~*
后续,我还会探索语音功能的加成,有兴趣的朋友欢迎交流鸭~~
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

+82
View File
@@ -0,0 +1,82 @@
# Atom-7B-chat
## 环境准备
在[autodl](https://www.autodl.com/)平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择`PyTorch`-->`2.0.0`-->`3.8(ubuntu20.04)`-->`11.8`
![Alt text](images/image-1.png)
接下来打开刚刚租用服务器的`JupyterLab`,并且打开其中的终端开始环境配置、模型下载和运行`demo`
pip换源和安装依赖包
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
#安装项目相关依赖包
pip install modelscope==1.9.5 transformers==4.35.2 gradio==4.4.1 SentencePiece==0.1.99 accelerate==0.24.1 bitsandbytes==0.41.2.post2
# 如遇 flash_attn 安装失败,请根据环境手动安装匹配的 wheel 包
# 例如:PyTorch 2.0.0 + Python 3.8 + CUDA 11.8Ubuntu 20.04
# 可直接使用下述预编译 wheel
# 参考来源:https://github.com/Dao-AILab/flash-attention/releases
pip install https://github.com/Dao-AILab/flash-attention/releases/download/v2.6.3/flash_attn-2.6.3+cu118torch2.0cxx11abiFALSE-cp38-cp38-linux_x86_64.whl
# 其他环境请从 flash-attention Releases 页面选择与自身 CUDA / PyTorch / Python 版本匹配的 wheel
# 若无匹配 wheel,亦可参考官方文档源码编译安装
```
## 模型下载
使用 `modelscope` 中的`snapshot_download`函数下载模型,第一个参数为模型名称,参数`cache_dir`为模型的下载路径。
`/root/autodl-tmp` 路径下新建 `download.py` 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 `python /root/autodl-tmp/download.py`执行下载,模型大小为 13 GB,下载模型大概需要 10~20 分钟
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('FlagAlpha/Atom-7B-Chat', cache_dir='/root/autodl-tmp', revision='master')
```
## 代码准备
首先`clone`代码,打开autodl平台自带的学术镜像加速。学术镜像加速详细使用请看:https://www.autodl.com/docs/network_turbo/
```shell
source /etc/network_turbo
```
然后切换路径, clone代码.
```shell
cd /root/autodl-tmp
git clone https://github.com/FlagAlpha/Llama2-Chinese.git
```
切换commit版本,与教程commit版本保持一致,可以让大家更好的复现。
```shell
cd Llama2-Chinese
git checkout 0a2b588c5716f26f1e37affa308283354b3612be
```
最后取消镜像加速,因为该加速可能对正常网络造成一定影响,避免对后续下载其他模型造成困扰。
```shell
unset http_proxy && unset https_proxy
```
## demo运行
进入代码目录,运行demo启动脚本,在--model_name_or_path 参数后填写下载的模型目录
```shell
cd /root/autodl-tmp/Llama2-Chinese/
python examples/chat_gradio.py --model_name_or_path /root/autodl-tmp/FlagAlpha/Atom-7B-Chat/
```
启动成功后终端显示如下:
![Alt text](images/image-2.png)
## 设置代理访问
在Autodl容器实例页面找到自定义服务,下载对应的代理工具
![Alt text](images/image-3.png)
![Alt text](images/image-4.png)
启动代理工具,拷贝对应的ssh指令及密码,设置代理端口为7860,点击开始代理
![Alt text](images/image-5.png)
代理成功后点击下方链接即可访问web-demo
![Alt text](images/image-6.png)
+345
View File
@@ -0,0 +1,345 @@
# Atom-7B-Chat 的 Lora 指令微调
## 概述
本节我们简要介绍如何基于 transformers、peft 等框架,对 Atom-7B-Chat 模型进行 Lora 微调。Lora 是一种高效微调方法,深入了解其原理可参见博客:[知乎|深入浅出Lora](https://zhuanlan.zhihu.com/p/650197598)。
本节所讲述的代码脚本在同级目录 [02-Atom-7B-Chat Lora](../Atom/02-Atom-7B-Chat%20Lora%20微调/train.py) 下,可以通过运行目录下 [train.sh](../Atom/02-Atom-7B-Chat%20Lora%20微调/train.sh) 脚本来执行微调过程,但注意,本文代码未使用分布式框架,微调 Atom-7B 模型至少需要 32G 及以上的显存。
## 环境配置
在完成基本环境配置和本地模型部署的情况下,你还需要安装一些第三方库,可以使用以下命令:
```bash
pip install transformers==4.36.0.dev0
pip install peft==0.4.0.dev0
pip install datasets==2.10.1
pip install accelerate==0.20.3
```
在本节教程里,我们将微调数据集放置在根目录 [/dataset](../../dataset/huanhuan.jsonl),将基座模型参数放置在根目录 [/model](../../models)。
## 指令集构建
LLM 的微调一般指指令微调过程。所谓指令微调,是说我们使用的微调数据形如:
```json
{
"instrution":"回答以下用户问题,仅输出答案。",
"input":"1+1等于几?",
"output":"2"
}
```
其中,`instruction` 是用户指令,告知模型其需要完成的任务;`input` 是用户输入,是完成用户指令所必须的输入内容;`output` 是模型应该给出的输出。
即我们的核心训练目标是让模型具有理解并遵循用户指令的能力。因此,在指令集构建时,我们应针对我们的目标任务,针对性构建任务指令集。例如,在本节我们使用由笔者合作开源的 [Chat-甄嬛](https://github.com/KMnO4-zx/huanhuan-chat) 项目作为示例,我们的目标是构建一个能够模拟甄嬛对话风格的个性化 LLM,因此我们构造的指令形如:
```json
{
"instruction": "请参考下面内容中的甄嬛的说话风格和语气,回答我的问题。甄嬛的说话风格需要是口语化的,回复内容不要超过30个字,尽可能字数简短一些。\n对话风格案例内容:\n```用户:这首歌虽未直写男女相悦,可字字写着两心相悦后女子的欢喜神态,而且'双双金鹧鹄'也是并蒂成双之意。\n用户:既然如此,安常在怎么就没唱出花好之情?难不成是看见皇上跟本宫在一起,心有不悦才唱不好的吗?\n甄嬛:回禀华妃娘娘,安常在早上受了风寒,嗓子有些不适。\n\n用户:你不是要看院子里的白梅吗,怎么那么快就回来了?\n甄嬛:雪景看久了反倒眼晕,四郎本是好意在园子里种植白梅,可是一下雪反倒与雪景融为一色,倒看不出来了。",
"input":"你是谁?",
"output":"家父是大理寺少卿甄远道。"
}
```
我们所构造的全部指令数据集在根目录下。
## 数据格式化
Lora 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 Pytorch 模型训练流程的同学会知道,我们一般需要将输入文本编码为 `input_ids`,将输出文本编码为 `labels`,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:
```python
def preprocess(tokenizer, config, example, max_seq_length):
'''
args:
tokenizer:分词器,导入的 Atom 模型分词器
config:模型配置,导入的 Atom 模型配置
example: 待处理的样本
max_seq_length:文本的最大长度
returns:字典,包括 inputs_id 和 seq_len
'''
# 将 instruction 和 input 按照 Atom SFT 时的格式拼接起来
prompt = "<s>Human: " + example["instruction"] + "请回答用户问题: " + example["input"] + "\n" + "</s><s>Assistant:"
target = example["output"]
# 使用分词器进行编码,设置 truncation 为 True,避免出现过长的样本
prompt_ids = tokenizer.encode(prompt, max_length=max_seq_length, truncation=True)
target_ids = tokenizer.encode(
target,
max_length=max_seq_length,
truncation=True,
add_special_tokens=False)
# 加入结束符 EOS
input_ids = prompt_ids + target_ids + [config.eos_token_id]
# 将 inputs_ids 和 seq_len 一起传回,后续会根据 seq_len 来切分 inputs 和 labels
return {"input_ids": input_ids, "seq_len": len(prompt_ids)}
```
上述代码会对每一条样本进行格式化处理,我们再定义一个函数,这个函数基于上文函数,对源训练数据进行处理:
```python
# 读取源训练数据并处理
def read_jsonl(path, max_seq_length, model_path, skip_overlength=False):
'''
args:
path:训练数据路径
max_seq_length:文本的最大长度
model_path:模型路径,此处主要是为了加载分词器和配置
returns:使用 yield 返回格式化的特征
'''
# 加载模型的分词器和配置参数
tokenizer = transformers.AutoTokenizer.from_pretrained(
model_path, trust_remote_code=True)
config = transformers.AutoConfig.from_pretrained(
model_path, trust_remote_code=True, device_map='auto')
# 读取源文件
with open(path, "r") as f:
# jsonl 数据需要先 readlines 读取成字符转,再使用 json 加载
lst = [json.loads(line) for line in f.readlines()]
print("加载jsonl数据集,数据总量为{}".format(len(lst)))
# 依次处理每一个样本
for example in tqdm(lst):
# 调用上文的预处理函数
feature = preprocess(tokenizer, config, example, max_seq_length)
# 如果设置了跳过过长的样本
if skip_overlength and len(feature["input_ids"]) > max_seq_length:
continue
# 截断过长的样本
feature["input_ids"] = feature["input_ids"][:max_seq_length]
# 通过 yield 返回迭代器
yield feature
```
完成上述函数后,我们使用 datasets 库提供的 from_generator 函数来根据上述函数生成我们数据的 Dataset 对象:
```python
# 通过 read_jsonl 函数返回的迭代器来生成 Dataset 对象,这个 Dataset 对象可以直接用在 transformers 框架中
dataset = datasets.Dataset.from_generator(
lambda: read_jsonl(
finetune_args.dataset_path, finetune_args.max_seq_length, finetune_args.model_path, finetune_args.skip_overlength
)
)
```
## 采样函数
为了对每一个 batch 的数据进行动态补齐,避免造成资源浪费,我们没有在生成函数中进行补齐操作,因此我们需要定义一个自定义采样函数,这个函数代替了 torch 中默认的采样函数功能,并自定义地实现了补齐、labels 遮蔽等操作,后续其会以 lambda 函数的方式传入 trainer
```python
# 自定义采样函数
def data_collator(features: list, tokenizer) -> dict:
'''
args:
features: 一个批量的数据
tokenizer:分词器
returns:格式化的特征
'''
# 统计 batch 内所有数据的长度,将它们补齐
len_ids = [len(feature["input_ids"]) for feature in features]
# 补齐至最大长度
longest = max(len_ids)
# 分别存放 input_ids 和 labels
input_ids = []
labels_list = []
# 有的模型没有定义 PAD,那么我们就用 UNK 来代替
if tokenizer.pad_token_id is None:
tokenizer.pad_token_id = tokenizer.unk_token_id
# 从最长的文本开始处理,可以优化内存使用
for ids_l, feature in sorted(zip(len_ids, features), key=lambda x: -x[0]):
ids = feature["input_ids"]
seq_len = feature["seq_len"]
# labels 是将输入 PAD 之后保留输出的结果,用-100表示遮蔽,并且进行补齐,计算 loss 时会自动忽略 -100
labels = (
[-100] * (seq_len - 1) + ids[(seq_len - 1) :] + [-100] * (longest - ids_l)
)
ids = ids + [tokenizer.pad_token_id] * (longest - ids_l)
_ids = torch.LongTensor(ids)
labels_list.append(torch.LongTensor(labels))
input_ids.append(_ids)
# 在第0维进行拼接,也就是组成 batch_size*n*n 的矩阵
input_ids = torch.stack(input_ids)
labels = torch.stack(labels_list)
return {
"input_ids": input_ids,
"labels": labels,
}
```
## 自定义 Trainer
对于 Lora 微调,我们需要在基础 Trainer 的基础上继承一个自定义 Trainer,实现 Loss 计算(部分模型需要)和 Lora 参数的保存:
```python
# 自定义 Trainer,继承自 transformers.trainer
class ModifiedTrainer(Trainer):
# 重写损失计算函数,避免 LLaMA 类模型未定义 loss 的计算
def compute_loss(self, model, inputs, return_outputs=False):
# 7B
return model(
input_ids=inputs["input_ids"],
labels=inputs["labels"],
).loss
# 重写模型保存函数,从而保存模型的 Lora 参数
def save_model(self, output_dir=None, _internal_call=False):
from transformers.trainer import TRAINING_ARGS_NAME
# 如果输出路径不存在,创建一个
os.makedirs(output_dir, exist_ok=True)
# 保存了模型训练的各种超参数
torch.save(self.args, os.path.join(output_dir, TRAINING_ARGS_NAME))
# 选出了所有梯度没有被冻结的参数,也就是所有参与更新的 Lora 参数
saved_params = {
k: v.to("cpu") for k, v in self.model.named_parameters() if v.requires_grad
}
# 保存所有 Lora 参数
torch.save(saved_params, os.path.join(output_dir, "adapter_model.bin"))
```
## 参数解析
由于模型微调需要用到众多参数,最好以命令行方式传入,再通过 bash 脚本调用(例如 [train.sh](../Atom/02-Atom-7B-Chat-Lora/train.sh) 脚本)。微调参数众多,transformers 提供了众多参数的解析,我们需要额外定义一个参数解析类,解析 transformers 没有提供的、用于 Lora 微调的参数解析:
```python
# dataclassPython 类修饰符,数据类,封装了__init__()、 __repr__()和__eq__()函数
@dataclass
class FinetuneArguments:
# 微调参数
# fielddataclass 函数,用于指定变量初始化
# 训练集路径
dataset_path: str = field(default="../../dataset/huanhuan.jsonl")
# 基座模型参数路径
model_path: str = field(default="../../dataset/model")
# Lora 秩
lora_rank: int = field(default=8)
# 最大文本长度
max_seq_length: int = field(default=256)
# 是否跳过超长文本
skip_overlength: bool = field(default=False)
# 是否从断点继续训练
continue_training: bool = field(default=False)
# 断点路径,如果从断点继续训练需要传入
checkpoint: str = field(default=None)
```
## 训练
完成上述定义和实现之后,我们可以正式开始我们的训练流程。首先我们需要解析脚本传入的训练参数,我们使用了 transformers 提供的 HfArgumentParser 函数,解析的参数包括 transformers 提供的 TrainingArguments 类(包括了一些常用训练参数)和我们自定义的 FinetuneArguments 类:
```python
# 解析命令行参数
finetune_args, training_args = HfArgumentParser(
(FinetuneArguments, TrainingArguments)
).parse_args_into_dataclasses()
```
接下来加载底座模型并进行一定的配置:
```python
# 初始化底座模型
tokenizer = AutoTokenizer.from_pretrained(finetune_args.model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
finetune_args.model_path, trust_remote_code=True, device_map="auto")
print("{}加载模型成功".format(finetune_args.model_path))
# 启用梯度检查点,允许模型在前向计算时丢弃一些中间激活值,并在反向传播中重新计算,从而优化内存使用
model.gradient_checkpointing_enable()
# 确保输入向量能够计算梯度
model.enable_input_require_grads()
# 在训练过程中关闭缓存,提高计算效率,推理时应该开启
model.config.use_cache = (
False
)
```
然后设定 Lora 参数:
```python
# 设定 peft 参数
# 手动确定 LoRA 层(注:理论上我们可以自动查找所有 Lora 层,但是在 LLaMA 类模型上出现 bug)
target_modules = ['W_pack', 'down_proj', 'o_proj', 'gate_proj', 'up_proj']
# 配置 Lora 参数
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 任务为语言模型建模
inference_mode=False, # 训练模式
r=finetune_args.lora_rank, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1,# Dropout 比例
target_modules= target_modules # Lora 层
)
```
再基于 Lora 配置和底座模型,得到待训练的 Lora 模型(即冻结了非 Lora 层)。同时,需要判断是否是断点继续训练,如果是则要加载断点信息:
```python
# 是否从断点继续训练
# 源点训练
if not finetune_args.continue_training:
# 对基座模型进行 Lora 融合
model = get_peft_model(model, peft_config)
print("加载 LoRA 参数成功")
else:
if finetune_args.check_point == None:
print("断点训练需要给出 checkpoint 地址")
raise ValueError("断点训练需要给出 checkpoint 地址")
# 断点继续训练则直接加载断点的 Lora 参数
model = PeftModel.from_pretrained(model, finetune_args.check_point, is_trainable=True)
print("{}加载断点成功".format(finetune_args.check_point))
```
然后基于上述定义加载数据集,在这一部分,我们使用了 try except 来捕捉异常:
```python
# 加载数据集
try:
# 调用上述定义函数生成迭代器
dataset = datasets.Dataset.from_generator(
lambda: read_jsonl(finetune_args.dataset_path, finetune_args.max_seq_length, finetune_args.model_path, finetune_args.skip_overlength)
)
except Exception as e:
print("{}加载数据集失败".format(finetune_args.dataset_path))
print("错误信息为:")
print(e.__repr__())
raise e
print("{}加载数据集成功".format(finetune_args.dataset_path))
```
最后,加载一个自定义的 trainer 并开始训练:
```python
# 加载自定义 trainer
trainer = ModifiedTrainer(
model=model, # 待训练模型
train_dataset=dataset, # 数据集
args=training_args, # 训练参数
data_collator=lambda x : data_collator(x, tokenizer), # 自定义采样函数
)
print("成功加载 Trainer")
# 进行训练
trainer.train()
print("训练完成,训练结果保存在{}".format(training_args.output_dir))
# 保存模型
model.save_pretrained(training_args.output_dir)
print("模型参数保存在{}".format(training_args.output_dir))
```
通过上述代码,我们即可完成 Atom-7B-Chat 模型的 Lora 微调。我们将上述代码封装为 [train.py](../Atom/02-Atom-7B-Chat-Lora/train.py) 脚本,同时,提供一个启动训练的 [bash 脚本](../Atom/02-Atom-7B-Chat-Lora/train.sh)
```bash
python train.py \
--dataset_path ../../dataset/huanhuan.jsonl \ # 数据集路径
--model_path /root/autodl-tmp/data/model/Atom \ # 基座模型路径
--lora_rank 8 \ # lora 秩
--per_device_train_batch_size 16 \ # batch_size
--gradient_accumulation_steps 1 \ # 梯度累积轮次
--max_steps 120000 \ # 训练最大步数,训练 epoch 数 = max_steps / (num_whole_data / batch_size)
--save_steps 40000 \ # 每训练多少步保存一次参数
--save_total_limit 3 \ # 最多保存多少个参数
--learning_rate 1e-4 \ # 学习率
--fp16 \ # 使用 float16 的精度
--remove_unused_columns false \ # 数据集处理时是否去除没有使用的特征
--logging_steps 10 \ # 每训练多少步输出一次
--output_dir ../../output # 输出路径
```
直接在目录下运行该脚本(bash train.sh)即可开始训练。
+240
View File
@@ -0,0 +1,240 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : train.py
@Time : 2023/11/22 08:07:45
@Author : Logan Zou
@Version : 1.0
@Contact : loganzou0421@163.com
@License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA
@Desc : Atom-7B-Chat-Lora指令微调
'''
from transformers import TrainingArguments
from transformers import Trainer, HfArgumentParser
from transformers import AutoTokenizer, AutoModel
from transformers import AutoModelForCausalLM
import torch
import torch.nn as nn
from peft import get_peft_model, LoraConfig, TaskType, PeftModel
from dataclasses import dataclass, field
import datasets
import os
import transformers
from tqdm import tqdm
import json
# dataclassPython 类修饰符,数据类,封装了__init__()、 __repr__()和__eq__()函数
@dataclass
class FinetuneArguments:
# 微调参数
# fielddataclass 函数,用于指定变量初始化
dataset_path: str = field(default="../../dataset/lora/huanhuan.json")
model_path: str = field(default="../../dataset/model")
lora_rank: int = field(default=8)
max_seq_length: int = field(default=256)
skip_overlength: bool = field(default=False)
continue_training: bool = field(default=False)
checkpoint: str = field(default=None)
def preprocess(tokenizer, config, example, max_seq_length):
'''
args:
tokenizer:分词器,导入的 Atom 模型分词器
config:模型配置,导入的 Atom 模型配置
example: 待处理的样本
max_seq_length:文本的最大长度
returns:字典,包括 inputs_id 和 seq_len
'''
# 将 instruction 和 input 按照 Atom SFT 时的格式拼接起来
prompt = "<s>Human: " + example["instruction"] + "请回答用户问题: " + example["input"] + "\n" + "</s><s>Assistant:"
target = example["output"]
# 使用分词器进行编码,设置 truncation 为 True,避免出现过长的样本
prompt_ids = tokenizer.encode(prompt, max_length=max_seq_length, truncation=True)
target_ids = tokenizer.encode(
target,
max_length=max_seq_length,
truncation=True,
add_special_tokens=False)
# 加入结束符 EOS
input_ids = prompt_ids + target_ids + [config.eos_token_id]
# 将 inputs_ids 和 seq_len 一起传回,后续会根据 seq_len 来切分 inputs 和 labels
return {"input_ids": input_ids, "seq_len": len(prompt_ids)}
# 读取源训练数据并处理
def read_jsonl(path, max_seq_length, model_path, skip_overlength=False):
'''
args:
path:训练数据路径
max_seq_length:文本的最大长度
model_path:模型路径,此处主要是为了加载分词器和配置
returns:使用 yield 返回格式化的特征
'''
# 加载模型的分词器和配置参数
tokenizer = transformers.AutoTokenizer.from_pretrained(
model_path, trust_remote_code=True)
config = transformers.AutoConfig.from_pretrained(
model_path, trust_remote_code=True, device_map='auto')
# 读取源文件
with open(path, "r") as f:
# jsonl 数据需要先 readlines 读取成字符转,再使用 json 加载
lst = [json.loads(line) for line in f.readlines()]
print("加载jsonl数据集,数据总量为{}".format(len(lst)))
# 依次处理每一个样本
for example in tqdm(lst):
# 调用上文的预处理函数
feature = preprocess(tokenizer, config, example, max_seq_length)
# 如果设置了跳过过长的样本
if skip_overlength and len(feature["input_ids"]) > max_seq_length:
continue
# 截断过长的样本
feature["input_ids"] = feature["input_ids"][:max_seq_length]
# 通过 yield 返回迭代器
yield feature
# 自定义采样函数
def data_collator(features: list, tokenizer) -> dict:
'''
args:
features: 一个批量的数据
tokenizer:分词器
returns:格式化的特征
'''
# 统计 batch 内所有数据的长度,将它们补齐
len_ids = [len(feature["input_ids"]) for feature in features]
# 补齐至最大长度
longest = max(len_ids)
# 分别存放 input_ids 和 labels
input_ids = []
labels_list = []
# 有的模型没有定义 PAD,那么我们就用 UNK 来代替
if tokenizer.pad_token_id is None:
tokenizer.pad_token_id = tokenizer.unk_token_id
# 从最长的文本开始处理,可以优化内存使用
for ids_l, feature in sorted(zip(len_ids, features), key=lambda x: -x[0]):
ids = feature["input_ids"]
seq_len = feature["seq_len"]
# labels 是将输入 PAD 之后保留输出的结果,用-100表示遮蔽,并且进行补齐,计算 loss 时会自动忽略 -100
labels = (
[-100] * (seq_len - 1) + ids[(seq_len - 1) :] + [-100] * (longest - ids_l)
)
ids = ids + [tokenizer.pad_token_id] * (longest - ids_l)
_ids = torch.LongTensor(ids)
labels_list.append(torch.LongTensor(labels))
input_ids.append(_ids)
# 在第0维进行拼接,也就是组成 batch_size*n*n 的矩阵
input_ids = torch.stack(input_ids)
labels = torch.stack(labels_list)
return {
"input_ids": input_ids,
"labels": labels,
}
# 自定义 Trainer,继承自 transformers.trainer
class ModifiedTrainer(Trainer):
# 重写损失计算函数,避免 LLaMA 类模型未定义 loss 的计算
def compute_loss(self, model, inputs, return_outputs=False):
# 7B
return model(
input_ids=inputs["input_ids"],
labels=inputs["labels"],
).loss
# 重写模型保存函数,从而保存模型的 Lora 参数
def save_model(self, output_dir=None, _internal_call=False):
from transformers.trainer import TRAINING_ARGS_NAME
# 如果输出路径不存在,创建一个
os.makedirs(output_dir, exist_ok=True)
# 保存了模型训练的各种超参数
torch.save(self.args, os.path.join(output_dir, TRAINING_ARGS_NAME))
# 选出了所有梯度没有被冻结的参数,也就是所有参与更新的 Lora 参数
saved_params = {
k: v.to("cpu") for k, v in self.model.named_parameters() if v.requires_grad
}
# 保存所有 Lora 参数
torch.save(saved_params, os.path.join(output_dir, "adapter_model.bin"))
def main():
# 解析命令行参数
finetune_args, training_args = HfArgumentParser(
(FinetuneArguments, TrainingArguments)
).parse_args_into_dataclasses()
print("命令行参数")
print("finetune_args:")
print(finetune_args.__repr__())
print("training_args:")
print(training_args.__repr__())
# 初始化底座模型
tokenizer = AutoTokenizer.from_pretrained(finetune_args.model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
finetune_args.model_path, trust_remote_code=True, device_map="auto")
print("{}加载模型成功".format(finetune_args.model_path))
# 启用梯度检查点,允许模型在前向计算时丢弃一些中间激活值,并在反向传播中重新计算,从而优化内存使用
model.gradient_checkpointing_enable()
# 确保输入向量能够计算梯度
model.enable_input_require_grads()
# 在训练过程中关闭缓存,提高计算效率,推理时应该开启
model.config.use_cache = (
False
)
# 设定 peft 参数
# 手动确定 LoRA 层(注:理论上我们可以自动查找所有 Lora 层,但是在 LLaMA 类模型上出现 bug)
target_modules = ['W_pack', 'down_proj', 'o_proj', 'gate_proj', 'up_proj']
# 配置 Lora 参数
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 任务为语言模型建模
inference_mode=False, # 训练模式
r=finetune_args.lora_rank, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1,# Dropout 比例
target_modules= target_modules # Lora 层
)
# 是否从断点继续训练
# 源点训练
if not finetune_args.continue_training:
model = get_peft_model(model, peft_config)
print("加载 LoRA 参数成功")
else:
if finetune_args.check_point == None:
print("断点训练需要给出 checkpoint 地址")
raise ValueError("断点训练需要给出 checkpoint 地址")
model = PeftModel.from_pretrained(model, finetune_args.check_point, is_trainable=True)
print("{}加载断点成功".format(finetune_args.check_point))
# 加载数据集
try:
dataset = datasets.Dataset.from_generator(
lambda: read_jsonl(finetune_args.dataset_path, finetune_args.max_seq_length, finetune_args.model_path, finetune_args.skip_overlength)
)
except Exception as e:
print("{}加载数据集失败".format(finetune_args.dataset_path))
print("错误信息为:")
print(e.__repr__())
raise e
print("{}加载数据集成功".format(finetune_args.dataset_path))
# 加载自定义 trainer
trainer = ModifiedTrainer(
model=model, # 待训练模型
train_dataset=dataset, # 数据集
args=training_args, # 训练参数
data_collator=lambda x : data_collator(x, tokenizer), # 自定义采样函数
)
print("成功加载 Trainer")
# 进行训练
trainer.train()
print("训练完成,训练结果保存在{}".format(training_args.output_dir))
# 保存模型
model.save_pretrained(training_args.output_dir)
print("模型参数保存在{}".format(training_args.output_dir))
if __name__ == "__main__":
main()
+14
View File
@@ -0,0 +1,14 @@
python train.py \
--dataset_path ../../dataset/huanhuan.jsonl \
--model_path /root/autodl-tmp/data/model/Atom \
--lora_rank 8 \
--per_device_train_batch_size 16 \
--gradient_accumulation_steps 1 \
--max_steps 120000 \
--save_steps 40000 \
--save_total_limit 3 \
--learning_rate 1e-4 \
--fp16 \
--remove_unused_columns false \
--logging_steps 10 \
--output_dir ../../output
@@ -0,0 +1,499 @@
# Atom-7B-Chat 接入langchain搭建知识库助手
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8
![Alt text](images/image-1.png)
接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下载和运行demo。
pip换源和安装依赖包
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope==1.9.5
pip install "transformers>=4.32.0" accelerate tiktoken einops scipy transformers_stream_generator==0.0.4 peft deepspeed
pip install -U huggingface_hub
pip install -i https://test.pypi.org/simple/ bitsandbytes
```
## 模型下载
在已完成Atom-7B-chat部署的基础上,我们还需要还需要安装以下依赖包。
请在终端复制粘贴以下命令,并按回车运行:
```shell
pip install langchain==0.0.292
pip install gradio==4.4.0
pip install chromadb==0.4.15
pip install sentence-transformers==2.2.2
pip install unstructured==0.10.30
pip install markdown==3.3.7
```
同时,我们还需要使用到开源词向量模型 [Sentence Transformer](https://huggingface.co/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2)
这里使用huggingface镜像下载到本地 /root/autodl-tmp/embedding_model,你也可以选择其它的方式下载
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py执行下载。
```python
import os
# 设置环境变量
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
# 下载模型
os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/autodl-tmp/embedding_model')
```
使用 `modelscope` 中的`snapshot_download`函数下载模型,第一个参数为模型名称,参数`cache_dir`为模型的下载路径。
`/root/autodl-tmp` 路径下新建 `download.py` 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 `python /root/autodl-tmp/download.py`执行下载,模型大小为 13 GB,下载模型大概需要 10~20 分钟
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('FlagAlpha/Atom-7B-Chat', cache_dir='/root/autodl-tmp', revision='master')
```
## 知识库建设
我们选用以下两个开源仓库作为知识库来源
- [Atom-7B-Chat](https://www.modelscope.cn/models/FlagAlpha/Atom-7B-Chat/)
- [Llama2-Chinese](https://github.com/FlagAlpha/Llama2-Chinese.git)
首先我们需要将上述远程开源仓库 Clone 到本地,可以使用以下命令:
```shell
# 进入到数据库盘
cd /root/autodl-tmp
# 打开学术资源加速
source /etc/network_turbo
# clone 开源仓库
git clone https://github.com/FlagAlpha/Llama2-Chinese
# 关闭学术资源加速
unset http_proxy && unset https_proxy
```
接着,为语料处理方便,我们将选用上述仓库中所有的 markdown、txt 文件作为示例语料库。注意,也可以选用其中的代码文件加入到知识库中,但需要针对代码文件格式进行额外处理。
我们首先将上述仓库中所有满足条件的文件路径找出来,我们定义一个函数,该函数将递归指定文件夹路径,返回其中所有满足条件(即后缀名为 .md 或者 .txt 的文件)的文件路径:
```python
import os
def get_files(dir_path):
# argsdir_path,目标文件夹路径
file_list = []
for filepath, dirnames, filenames in os.walk(dir_path):
# os.walk 函数将递归遍历指定文件夹
for filename in filenames:
# 通过后缀名判断文件类型是否满足要求
if filename.endswith(".md"):
# 如果满足要求,将其绝对路径加入到结果列表
file_list.append(os.path.join(filepath, filename))
elif filename.endswith(".txt"):
file_list.append(os.path.join(filepath, filename))
return file_list
```
得到所有目标文件路径之后,我们可以使用 LangChain 提供的 FileLoader 对象来加载目标文件,得到由目标文件解析出的纯文本内容。由于不同类型的文件需要对应不同的 FileLoader,我们判断目标文件类型,并针对性调用对应类型的 FileLoader,同时,调用 FileLoader 对象的 load 方法来得到加载之后的纯文本对象:
```python
from tqdm import tqdm
from langchain.document_loaders import UnstructuredFileLoader
from langchain.document_loaders import UnstructuredMarkdownLoader
def get_text(dir_path):
# argsdir_path,目标文件夹路径
# 首先调用上文定义的函数得到目标文件路径列表
file_lst = get_files(dir_path)
# docs 存放加载之后的纯文本对象
docs = []
# 遍历所有目标文件
for one_file in tqdm(file_lst):
file_type = one_file.split('.')[-1]
if file_type == 'md':
loader = UnstructuredMarkdownLoader(one_file)
elif file_type == 'txt':
loader = UnstructuredFileLoader(one_file)
else:
# 如果是不符合条件的文件,直接跳过
continue
docs.extend(loader.load())
return docs
```
使用上文函数,我们得到的 docs 为一个纯文本对象对应的列表。得到该列表之后,我们就可以将它引入到 LangChain 框架中构建向量数据库。由纯文本对象构建向量数据库,我们需要先对文本进行分块,接着对文本块进行向量化。
LangChain 提供了多种文本分块工具,此处我们使用字符串递归分割器,并选择分块大小为 500,块重叠长度为 150:
```python
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)
```
接着我们选用开源词向量模型 [Sentence Transformer](https://huggingface.co/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2) 来进行文本向量化
LangChain 提供了直接引入 HuggingFace 开源社区中的模型进行向量化的接口:
```python
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
```
同时,我们选择 Chroma 作为向量数据库,基于上文分块后的文档以及加载的开源向量化模型,将语料加载到指定路径下的向量数据库:
```python
from langchain.vectorstores import Chroma
# 定义持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上
)
# 将加载的向量数据库持久化到磁盘上
vectordb.persist()
```
将上述代码整合在一起为知识库搭建的脚本:
```python
# 首先导入所需第三方库
from langchain.document_loaders import UnstructuredFileLoader
from langchain.document_loaders import UnstructuredMarkdownLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from tqdm import tqdm
import os
import nltk
nltk.download('punkt')
# 获取文件路径函数
def get_files(dir_path):
# argsdir_path,目标文件夹路径
file_list = []
for filepath, dirnames, filenames in os.walk(dir_path):
# os.walk 函数将递归遍历指定文件夹
for filename in filenames:
# 通过后缀名判断文件类型是否满足要求
if filename.endswith(".md"):
# 如果满足要求,将其绝对路径加入到结果列表
file_list.append(os.path.join(filepath, filename))
elif filename.endswith(".txt"):
file_list.append(os.path.join(filepath, filename))
return file_list
# 加载文件函数
def get_text(dir_path):
# argsdir_path,目标文件夹路径
# 首先调用上文定义的函数得到目标文件路径列表
file_lst = get_files(dir_path)
# docs 存放加载之后的纯文本对象
docs = []
# 遍历所有目标文件
for one_file in tqdm(file_lst):
file_type = one_file.split('.')[-1]
if file_type == 'md':
loader = UnstructuredMarkdownLoader(one_file)
elif file_type == 'txt':
loader = UnstructuredFileLoader(one_file)
else:
# 如果是不符合条件的文件,直接跳过
continue
docs.extend(loader.load())
return docs
# 目标文件夹
tar_dir = [
"/root/autodl-tmp/Llama2-Chinese",
]
# 加载目标文件
docs = []
for dir_path in tar_dir:
docs.extend(get_text(dir_path))
# 对文本进行分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)
# 加载开源词向量模型
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
# 构建向量数据库
# 定义持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上
)
# 将加载的向量数据库持久化到磁盘上
vectordb.persist()
```
运行上述脚本,即可在本地构建已持久化的向量数据库,后续直接导入该数据库即可,无需重复构建。
## Atom 接入LangChain
为便捷构建 LLM 应用,我们需要基于本地部署的 Atom,自定义一个 LLM 类,将 Atom 接入到 LangChain 框架中。完成自定义 LLM 类之后,可以以完全一致的方式调用 LangChain 的接口,而无需考虑底层模型调用的不一致。
基于本地部署的 Atom 自定义 LLM 类并不复杂,我们只需从 LangChain.llms.base.LLM 类继承一个子类,并重写构造函数与 _call 函数即可:
```python
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
class Atom(LLM):
# 基于本地 Atom 自定义 LLM 类
tokenizer : AutoTokenizer = None
model: AutoModelForCausalLM = None
def __init__(self, model_path :str):
# model_path: Atom 模型路径
# 从本地初始化模型
super().__init__()
print("正在从本地加载模型...")
model_dir = '/root/autodl-tmp/FlagAlpha/Atom-7B-Chat'
self.tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(model_dir, device_map="auto", trust_remote_code=True,torch_dtype=torch.float16,load_in_8bit=True).eval()
print("完成本地模型的加载")
def _call(self, prompt: str, stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any):
input_ids = self.tokenizer([f'<s>Human: {prompt}\n</s><s>Assistant: '], return_tensors="pt", add_special_tokens=False).input_ids.to('cuda')
generate_input = {
"input_ids": input_ids,
"max_new_tokens": 512,
"do_sample": True,
"top_k": 50,
"top_p": 0.95,
"temperature": 0.3,
"repetition_penalty": 1.3,
"eos_token_id": self.tokenizer.eos_token_id,
"bos_token_id": self.tokenizer.bos_token_id,
"pad_token_id": self.tokenizer.pad_token_id
}
generate_ids = self.model.generate(**generate_input)
text = self.tokenizer.decode(generate_ids[0])
return text
@property
def _llm_type(self) -> str:
return "Atom"
```
在上述类定义中,我们分别重写了构造函数和 _call 函数:对于构造函数,我们在对象实例化的一开始加载本地部署的 Atom 模型,从而避免每一次调用都需要重新加载模型带来的时间过长;_call 函数是 LLM 类的核心函数,LangChain 会调用该函数来调用 LLM,在该函数中,我们调用已实例化模型的 generate 方法,从而实现对模型的调用并返回调用结果。
在整体项目中,我们将上述代码封装为 LLM.py,后续将直接从该文件中引入自定义的 LLM 类。
## 构建检索问答链
LangChain 通过提供检索问答链对象来实现对于 RAG 全流程的封装。即我们可以调用一个 LangChain 提供的 RetrievalQA 对象,通过初始化时填入已构建的数据库和自定义 LLM 作为参数,来简便地完成检索增强问答的全流程,LangChain 会自动完成基于用户提问进行检索、获取相关文档、拼接为合适的 Prompt 并交给 LLM 问答的全部流程。
首先我们需要将上文构建的向量数据库导入进来,我们可以直接通过 Chroma 以及上文定义的词向量模型来加载已构建的数据库:
```python
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import os
# 定义 Embeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
# 向量数据库持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma(
persist_directory=persist_directory,
embedding_function=embeddings
)
```
上述代码得到的 vectordb 对象即为我们已构建的向量数据库对象,该对象可以针对用户的 query 进行语义向量检索,得到与用户提问相关的知识片段。
接着,我们实例化一个基于 Atom 自定义的 LLM 对象:
```python
from LLM import Atom
llm = Atom(model_path = "/root/autodl-tmp/FlagAlpha/Atom-7B-Chat")
llm.predict("你是谁")
```
![Alt text](images/image-7.png)
构建检索问答链,还需要构建一个 Prompt Template,该 Template 其实基于一个带变量的字符串,在检索之后,LangChain 会将检索到的相关文档片段填入到 Template 的变量中,从而实现带知识的 Prompt 构建。我们可以基于 LangChain 的 Template 基类来实例化这样一个 Template 对象:
```python
from langchain.prompts import PromptTemplate
# 我们所构造的 Prompt 模板
template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答案。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
有用的回答:"""
# 调用 LangChain 的方法来实例化一个 Template 对象,该对象包含了 context 和 question 两个变量,在实际调用时,这两个变量会被检索到的文档片段和用户提问填充
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template)
```
最后,可以调用 LangChain 提供的检索问答链构造函数,基于我们的自定义 LLM、Prompt Template 和向量知识库来构建一个基于 Atom 的检索问答链:
```python
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(llm,retriever=vectordb.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
```
得到的 qa_chain 对象即可以实现我们的核心功能,即基于 Atom 模型的专业知识库助手。我们可以对比该检索问答链和纯 LLM 的问答效果:
```python
question = "什么是Atom"
result = qa_chain({"query": question})
print("检索问答链回答 question 的结果:")
print(result["result"])
# 仅 LLM 回答效果
result_2 = llm(question)
print("大模型回答 question 的结果:")
print(result_2)
```
![Alt text](images/image-8.png)可以看到,使用检索问答链生成的答案更接近知识库里的内容。
## 部署WebDemo
在完成上述核心功能后,我们可以基于 Gradio 框架将其部署到 Web 网页,从而搭建一个小型 Demo,便于测试与使用。
我们首先将上文的代码内容封装为一个返回构建的检索问答链对象的函数,并在启动 Gradio 的第一时间调用该函数得到检索问答链对象,后续直接使用该对象进行问答对话,从而避免重复加载模型:
```python
# 导入必要的库
import gradio as gr
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import os
from LLM import Atom
from langchain.prompts import PromptTemplate
def load_chain():
# 加载问答链
# 定义 Embeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
# 向量数据库持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma(
persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上
embedding_function=embeddings
)
llm = Atom(model_path = "/root/autodl-tmp/FlagAlpha")
template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
template=template)
# 运行 chain
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(llm,
retriever=vectordb.as_retriever(),
return_source_documents=True,
chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
return qa_chain
```
接着我们定义一个类,该类负责加载并存储检索问答链,并响应 Web 界面里调用检索问答链进行回答的动作:
```python
class Model_center():
"""
存储问答 Chain 的对象
"""
def __init__(self):
self.chain = load_chain()
def qa_chain_self_answer(self, question: str, chat_history: list = []):
"""
调用不带历史记录的问答链进行回答
"""
if question == None or len(question) < 1:
return "", chat_history
try:
chat_history.append(
(question, self.chain({"query": question})["result"]))
return "", chat_history
except Exception as e:
return e, chat_history
def clear_history(self):
self.chain.clear_history()
```
然后我们只需按照 Gradio 的框架使用方法,实例化一个 Web 界面并将点击动作绑定到上述类的回答方法即可:
```python
import gradio as gr
model_center = Model_center()
block = gr.Blocks()
with block as demo:
with gr.Row(equal_height=True):
with gr.Column(scale=15):
gr.Markdown("""<h1><center>Atom</center></h1>
<center>Llama2-chinese(教程来自DataWhale Self-LM团队)</center>
""")
# gr.Image(value=LOGO_PATH, scale=1, min_width=10,show_label=False, show_download_button=False)
with gr.Row():
with gr.Column(scale=4):
chatbot = gr.Chatbot(height=450, show_copy_button=True)
# 创建一个文本框组件,用于输入 prompt。
msg = gr.Textbox(label="Prompt/问题")
with gr.Row():
# 创建提交按钮。
db_wo_his_btn = gr.Button("Chat")
with gr.Row():
# 创建一个清除按钮,用于清除聊天机器人组件的内容。
clear = gr.ClearButton(
components=[chatbot], value="Clear console")
# 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[msg, chatbot], outputs=[msg, chatbot])
# 点击后清空后端存储的聊天记录
clear.click(model_center.clear_history)
gr.Markdown("""提醒:<br>
1. 初始化数据库时间可能较长,请耐心等待。
2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。 <br>
""")
# threads to consume the request
gr.close_all()
# 启动新的 Gradio 应用,设置分享功能为 True,并使用环境变量 PORT1 指定服务器端口。
# demo.launch(share=True, server_port=int(os.environ['PORT1']))
# 直接启动
demo.launch()
```
通过将上述代码封装为 run_gradio.py 脚本,直接通过在终端运行命令 python run_gradio.py ,即可在本地启动知识库助手的 Web Demo,默认会在 7860 端口运行,使用类似于部署的方式将服务器端口映射到本地端口即可访问:
![Alt text](images/image-9.png)
@@ -0,0 +1,42 @@
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
class Atom(LLM):
# 基于本地 Atom 自定义 LLM 类
tokenizer : AutoTokenizer = None
model: AutoModelForCausalLM = None
def __init__(self, model_path :str):
# model_path: Atom 模型路径
# 从本地初始化模型
super().__init__()
print("正在从本地加载模型...")
model_dir = '/root/autodl-tmp/FlagAlpha/Atom-7B-Chat'
self.tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(model_dir, device_map="auto", trust_remote_code=True,torch_dtype=torch.float16).eval()
print("完成本地模型的加载")
def _call(self, prompt: str, stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any):
input_ids = self.tokenizer([f'<s>Human: {prompt}\n</s><s>Assistant: '], return_tensors="pt", add_special_tokens=False).input_ids.to('cuda')
generate_input = {
"input_ids": input_ids,
"max_new_tokens": 512,
"do_sample": True,
"top_k": 50,
"top_p": 0.95,
"temperature": 0.3,
"repetition_penalty": 1.3,
"eos_token_id": self.tokenizer.eos_token_id,
"bos_token_id": self.tokenizer.bos_token_id,
"pad_token_id": self.tokenizer.pad_token_id
}
generate_ids = self.model.generate(**generate_input)
text = self.tokenizer.decode(generate_ids[0])
return text
@property
def _llm_type(self) -> str:
return "Atom"
@@ -0,0 +1,75 @@
# 首先导入所需第三方库
from langchain.document_loaders import UnstructuredFileLoader
from langchain.document_loaders import UnstructuredMarkdownLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from tqdm import tqdm
import os
import nltk
nltk.download('punkt')
# 获取文件路径函数
def get_files(dir_path):
# argsdir_path,目标文件夹路径
file_list = []
for filepath, dirnames, filenames in os.walk(dir_path):
# os.walk 函数将递归遍历指定文件夹
for filename in filenames:
# 通过后缀名判断文件类型是否满足要求
if filename.endswith(".md"):
# 如果满足要求,将其绝对路径加入到结果列表
file_list.append(os.path.join(filepath, filename))
elif filename.endswith(".txt"):
file_list.append(os.path.join(filepath, filename))
return file_list
# 加载文件函数
def get_text(dir_path):
# argsdir_path,目标文件夹路径
# 首先调用上文定义的函数得到目标文件路径列表
file_lst = get_files(dir_path)
# docs 存放加载之后的纯文本对象
docs = []
# 遍历所有目标文件
for one_file in tqdm(file_lst):
file_type = one_file.split('.')[-1]
if file_type == 'md':
loader = UnstructuredMarkdownLoader(one_file)
elif file_type == 'txt':
loader = UnstructuredFileLoader(one_file)
else:
# 如果是不符合条件的文件,直接跳过
continue
docs.extend(loader.load())
return docs
# 目标文件夹
tar_dir = [
"/root/autodl-tmp/Llama2-Chinese",
]
# 加载目标文件
docs = []
for dir_path in tar_dir:
docs.extend(get_text(dir_path))
# 对文本进行分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)
# 加载开源词向量模型
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
# 构建向量数据库
# 定义持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上
)
# 将加载的向量数据库持久化到磁盘上
vectordb.persist()
@@ -0,0 +1,7 @@
存储本项目相关代码文件。包括:
--creat_db.py 构建向量数据库的脚本
--llm.py 将 InternLM 封装为自定义 LLM 的脚本
--run_gradio.py 启动 Gradio 服务的脚本
@@ -0,0 +1,108 @@
# 导入必要的库
import gradio as gr
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import os
from LLM import Atom
from langchain.prompts import PromptTemplate
def load_chain():
# 加载问答链
# 定义 Embeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")
# 向量数据库持久化路径
persist_directory = 'data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma(
persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上
embedding_function=embeddings
)
llm = Atom(model_path = "/root/autodl-tmp/FlagAlpha")
template = """
{context}
问题: {question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
template=template)
# 运行 chain
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(llm,
retriever=vectordb.as_retriever(),
return_source_documents=True,
chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
return qa_chain
class Model_center():
"""
存储问答 Chain 的对象
"""
def __init__(self):
self.chain = load_chain()
def qa_chain_self_answer(self, question: str, chat_history: list = []):
"""
调用不带历史记录的问答链进行回答
"""
if question == None or len(question) < 1:
return "", chat_history
try:
chat_history.append(
(question, self.chain({"query": question})["result"]))
return "", chat_history
except Exception as e:
return e, chat_history
def clear_history(self):
self.chain.clear_history()
import gradio as gr
model_center = Model_center()
block = gr.Blocks()
with block as demo:
with gr.Row(equal_height=True):
with gr.Column(scale=15):
gr.Markdown("""<h1><center>Atom</center></h1>
<center>Llama2-chinese(教程来自DataWhale Self-LM团队)</center>
""")
# gr.Image(value=LOGO_PATH, scale=1, min_width=10,show_label=False, show_download_button=False)
with gr.Row():
with gr.Column(scale=4):
chatbot = gr.Chatbot(height=450, show_copy_button=True)
# 创建一个文本框组件,用于输入 prompt。
msg = gr.Textbox(label="Prompt/问题")
with gr.Row():
# 创建提交按钮。
db_wo_his_btn = gr.Button("Chat")
with gr.Row():
# 创建一个清除按钮,用于清除聊天机器人组件的内容。
clear = gr.ClearButton(
components=[chatbot], value="Clear console")
# 设置按钮的点击事件。当点击时,调用上面定义的 qa_chain_self_answer 函数,并传入用户的消息和聊天历史记录,然后更新文本框和聊天机器人组件。
db_wo_his_btn.click(model_center.qa_chain_self_answer, inputs=[msg, chatbot], outputs=[msg, chatbot])
# 点击后清空后端存储的聊天记录
clear.click(model_center.clear_history)
gr.Markdown("""提醒:<br>
1. 初始化数据库时间可能较长,请耐心等待。
2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。 <br>
""")
# threads to consume the request
gr.close_all()
# 启动新的 Gradio 应用,设置分享功能为 True,并使用环境变量 PORT1 指定服务器端口。
# demo.launch(share=True, server_port=int(os.environ['PORT1']))
# 直接启动
demo.launch()
+200
View File
@@ -0,0 +1,200 @@
# Atom-7B-chat 全量微调
## 修改代码
首先我们要准备训练模型的代码,这里我们使用的 `modelscope` 上的 `Atom-7B-chat` 模型,大家自行下载即可。
OK,模型下载完毕之后,我们就要准备代码文件。其实全量微调和 `Lora` 微调的代码基本一样,都采用了 `Trainer` 类来进行训练。只不过在全量微调的时候没有加载 `LoraConfig`,那我就直接给出代码,如果对代有什么问题,大家可以先自行探索Qwen lora的代码解释,有什么不懂的地方可以提`Issue`
需要把代码中的模型地址修改一下,改成自己的模型地址。
```python
from datasets import Dataset
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, HfArgumentParser, Trainer
import os
import torch
from dataclasses import dataclass, field
import deepspeed
deepspeed.ops.op_builder.CPUAdamBuilder().load()
@dataclass
class FinetuneArguments:
# 微调参数
# fielddataclass 函数,用于指定变量初始化
model_path: str = field(default="../../model/FlagAlpha/Atom-7B-Chat/")
# 用于处理数据集的函数
def process_func(example):
MAX_LENGTH = 128 # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer("\n".join(["<s>Human:", "现在你要扮演皇帝身边的女人--甄嬛,请以甄嬛口吻回答用户问题:" + example["instruction"] + example["input"] + "</s>\n"]).strip(), add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
response = tokenizer("<s>Assistant:" + example["output"] + "<\s>\n", add_special_tokens=False)
input_ids = instruction["input_ids"] + response["input_ids"]
attention_mask = instruction["attention_mask"] + response["attention_mask"]
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"]
if len(input_ids) > MAX_LENGTH: # 做一个截断
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
if "__main__" == __name__:
# 解析参数
# Parse 命令行参数
finetune_args, training_args = HfArgumentParser(
(FinetuneArguments, TrainingArguments)
).parse_args_into_dataclasses()
# 处理数据集
# 将JSON文件转换为CSV文件
df = pd.read_json('./data/huanhuan.json')
ds = Dataset.from_pandas(df)
# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(finetune_args.model_path, use_fast=False, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
# 将数据集变化为token形式
tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
# 创建模型并以半精度形式加载
model = AutoModelForCausalLM.from_pretrained(finetune_args.model_path, trust_remote_code=True, torch_dtype=torch.half, device_map={"": int(os.environ.get("LOCAL_RANK") or 0)})
# 使用trainer训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train() # 开始训练
response, history = model.chat(tokenizer, "你是谁", history=[], system="现在你要扮演皇帝身边的女人--甄嬛.")
print(response)
```
## DeepSpeed 环境配置
`DeepSpeed` 是微软开源的一个深度学习训练框架,可以用于分布式训练,同时还可以加速训练,减少显存占用。这里我们使用的是 `DeepSpeed` 的半精度训练,可以减少显存占用,加快训练速度。
首先我们需要安装 `DeepSpeed``DeepSpeed` 的安装很简单,但如果没有按照如下步骤安装,可能会出现一些问题。
首先创建一个崭新的,干净的conda环境,注意一定要使用当前目录下提供的`environment.yml`文件来创建环境,否则可能会出现一些问题。接着激活环境,安装`deepspeed`,使用`DS_BUILD_OPS=1`来安装`deepspeed`,这样会避免后续的很多报错。
```bash
conda env create -n deepspeed -f environment.yml --force
conda activate deepspeed
DS_BUILD_OPS=1 pip install deepspeed
```
然后就是安装`transformers`等其他依赖,注意不需要再安装`torch`了,在创建环境的时候`torch`已经安装了。
```bash
pip install modelscope==1.9.5
pip install transformers==4.35.2
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install datasets sentencepiece
pip install tiktoken
pip install transformers_stream_generator
```
注意:本环境是在`aws`服务器上安装并运行的,假如您在安装或者运行过程中遇到其他问题,欢迎提出`issue`,然后您解决之后,可以顺便提交`PR`,为项目添砖加瓦。
## 模型训练
首先创建`deepspeed``config.json`文件。我使用的是stage-2的配置。如果不懂也没关系,直接粘贴复制,创建为`ds_config.json`文件即可。
```json
{
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16,
"hysteresis": 2,
"min_loss_scale": 1
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": "auto",
"betas": "auto",
"eps": "auto",
"weight_decay": "auto"
}
},
"scheduler": {
"type": "WarmupDecayLR",
"params": {
"last_batch_iteration": -1,
"total_num_steps": "auto",
"warmup_min_lr": "auto",
"warmup_max_lr": "auto",
"warmup_num_steps": "auto"
}
},
"zero_optimization": {
"stage": 2,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
"offload_param": {
"device": "cpu",
"pin_memory": true
},
"allgather_partitions": true,
"allgather_bucket_size": 5e8,
"overlap_comm": true,
"reduce_scatter": true,
"reduce_bucket_size": 5e8,
"contiguous_gradients": true
},
"activation_checkpointing": {
"partition_activations": false,
"cpu_checkpointing": false,
"contiguous_memory_optimization": false,
"number_checkpoints": null,
"synchronize_checkpoint_boundary": false,
"profile": false
},
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"steps_per_print": 2000,
"train_batch_size": "auto",
"min_lr": 5e-7,
"train_micro_batch_size_per_gpu": "auto",
"wall_clock_breakdown": false
}
```
然后我们来创建运行所需的`bash`脚本,创建一个`train.sh`文件,内容如下:
```shell
num_gpus=4
deepspeed --num_gpus $num_gpus train.py \
--deepspeed ./ds_config.json \
--output_dir="./output/Atom" \
--per_device_train_batch_size=1 \
--gradient_accumulation_steps=1 \
--logging_steps=10 \
--num_train_epochs=3 \
--save_steps=100 \
--learning_rate=1e-4 \
--save_on_each_node=True \
```
接着在命令行输入:`bash train.sh`,开始训练。
## 注意:
- 因为本脚本使用了`adam_cpu`来加载优化器参数,所以全量微调所需的显存会比较小,但仍然需要使用至少4张24G显存的卡来训练。
- 如果第一步创建`deepspeed`环境时候,没有使用`DS_BUILD_OPS=1`,那么可能会出现一些问题,比如`RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!`,这个时候需要重新创建环境,然后再次运行。
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

@@ -0,0 +1,15 @@
torch
transformers
sentence-transformers
numpy
matplotlib
tqdm
scipy
scikit-learn
pandas
seaborn
FlagEmbedding
mteb
ipykernel
notebook
modelscope
@@ -0,0 +1,180 @@
# Baichuan2-7B-chat FastApi 部署调用
## Baichuan2 介绍
Baichuan 2 是百川智能推出的新一代开源大语言模型,采用 2.6 万亿 Tokens 的高质量语料训练。在多个权威的中文、英文和多语言的通用、领域 benchmark 上取得同尺寸最佳的效果。
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.811.3版本以上的都可以) 接下来打开刚刚租用服务器的JupyterLab, 图像 并且打开其中的终端开始环境配置、模型下载和运行演示。
![Alt text](images/image1.png)
pip换源和安装依赖包
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install fastapi==0.104.1
pip install uvicorn==0.24.0.post1
pip install requests==2.25.1
pip install modelscope==1.9.5
pip install transformers==4.35.2
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
pip install xformers==0.0.23
```
## 模型下载:
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py 执行下载,模型大小为15 GB,下载模型大概需要10~20分钟
```Python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('baichuan-inc/Baichuan2-7B-Chat',cache_dir='/root/autodl-tmp', revision='v1.0.4')
```
## 代码准备:
在/root/autodl-tmp路径下新建api.py文件并在其中输入以下内容,粘贴代码后记得保存文件。下面的代码有很详细的注释,大家如有不理解的地方,欢迎提出issue。
```Python
from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM
from transformers.generation.utils import GenerationConfig
import uvicorn
import json
import datetime
import torch
# 设置设备参数
DEVICE = "cuda" # 使用CUDA
DEVICE_ID = "0" # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE # 组合CUDA设备信息
# 清理GPU内存函数
def torch_gc():
if torch.cuda.is_available(): # 检查是否可用CUDA
with torch.cuda.device(CUDA_DEVICE): # 指定CUDA设备
torch.cuda.empty_cache() # 清空CUDA缓存
torch.cuda.ipc_collect() # 收集CUDA内存碎片
# 创建FastAPI应用
app = FastAPI()
# 处理POST请求的端点
@app.post("/")
async def create_item(request: Request):
global model, tokenizer # 声明全局变量以便在函数内部使用模型和分词器
json_post_raw = await request.json() # 获取POST请求的JSON数据
json_post = json.dumps(json_post_raw) # 将JSON数据转换为字符串
json_post_list = json.loads(json_post) # 将字符串转换为Python对象
prompt = json_post_list.get('prompt') # 获取请求中的提示
# 构建 messages
messages = [
{"role": "user", "content": prompt}
]
result= model.chat(tokenizer, messages)
now = datetime.datetime.now() # 获取当前时间
time = now.strftime("%Y-%m-%d %H:%M:%S") # 格式化时间为字符串
# 构建响应JSON
answer = {
"response": result,
"status": 200,
"time": time
}
# 构建日志信息
log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(result) + '"'
print(log) # 打印日志
torch_gc() # 执行GPU内存清理
return answer # 返回响应
# 主函数入口
if __name__ == '__main__':
# 加载预训练的分词器和模型
tokenizer = AutoTokenizer.from_pretrained("/root/autodl-tmp/baichuan-inc/Baichuan2-7B-Chat", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("/root/autodl-tmp/baichuan-inc/Baichuan2-7B-Chat", trust_remote_code=True).to(torch.bfloat16).cuda()
g_config = GenerationConfig.from_pretrained("/root/autodl-tmp/baichuan-inc/Baichuan2-7B-Chat")
g_config.temperature = 0.3 # 可改参数:温度参数控制生成文本的随机性。较低的值使输出更加确定性和一致。
g_config.top_p = 0.85 # 可改参数:top-p(或nucleus sampling)截断,只考虑累积概率达到此值的最高概率的词汇。
g_config.top_k = 5 # 可改参数:top-k截断,只考虑概率最高的k个词汇。
g_config.max_new_tokens = 2048 # 可改参数:设置生成文本的最大长度(以token为单位)。
model.generation_config = g_config
model.eval() # 设置模型为评估模式
# 启动FastAPI应用
# 用6006端口可以将autodl的端口映射到本地,从而在本地使用api
uvicorn.run(app, host='0.0.0.0', port=6006, workers=1) # 在指定端口和主机上启动应用
```
## Api 部署:
在终端输入以下命令启动api服务
```Python
cd /root/autodl-tmp
python api.py
```
加载完毕后出现如下信息说明成功。
![Alt text](images/image2.png)
默认部署在 6006 端口,通过 POST 方法进行调用,可以使用curl调用,如下所示:
```Python
curl -X POST "http://127.0.0.1:6006"
-H 'Content-Type: application/json'
-d '{"prompt": "你是谁"}'
```
得到的返回值如下所示:
```Python
{
'response': '我是百川大模型,是由百川智能的工程师们创造的大语言模型',
'status': 200,
'time': '2023-12-01 17:06:10'
}
```
运行显示:
![Alt text](images/image3.png)
也可以使用python中的requests库进行调用,如下所示:
```Python
import requests
import json
def get_completion(prompt):
headers = {'Content-Type': 'application/json'}
data = {"prompt": prompt}
response = requests.post(url='http://127.0.0.1:6006', headers=headers, data=json.dumps(data))
return response.json()['response']
if __name__ == '__main__':
print(get_completion('你是谁,请给我介绍下自己'))
```
运行显示:
![Alt text](images/image4.png)
@@ -0,0 +1,122 @@
# Baichuan-7B-chat WebDemo 部署调用
## Baichuan2 介绍
Baichuan 2 是百川智能推出的新一代开源大语言模型,采用 2.6 万亿 Tokens 的高质量语料训练。在多个权威的中文、英文和多语言的通用、领域 benchmark 上取得同尺寸最佳的效果。
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.811.3版本以上的都可以) 接下来打开刚刚租用服务器的JupyterLab, 图像 并且打开其中的终端开始环境配置、模型下载和运行演示。
![Alt text](images/image1.png)
pip换源和安装依赖包
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope==1.9.5
pip install transformers==4.35.2
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
```
## 模型下载:
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py 执行下载,模型大小为15 GB,下载模型大概需要10~20分钟
```Python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('baichuan-inc/Baichuan2-7B-Chat',cache_dir='/root/autodl-tmp', revision='v1.0.4')
```
## 代码准备
`/root/autodl-tmp`路径下新建 `chatBot.py` 文件并在其中输入以下内容,粘贴代码后记得保存文件。下面的代码有很详细的注释,大家如有不理解的地方,欢迎提出issue。
```Python
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import torch
import streamlit as st
# 在侧边栏中创建一个标题和一个链接
with st.sidebar:
st.markdown("## Baichuan2 LLM")
"[开源大模型食用指南 self-llm](https://github.com/datawhalechina/self-llm.git)"
# 创建一个滑块,用于选择最大长度,范围在0到1024之间,默认值为512
max_length = st.slider("max_length", 0, 1024, 512, step=1)
# 创建一个标题和一个副标题
st.title("💬 Baichuan2 Chatbot")
st.caption("🚀 A streamlit chatbot powered by Self-LLM")
# 定义模型路径
mode_name_or_path = '/root/autodl-tmp/baichuan-inc/Baichuan2-7B-Chat'
# 定义一个函数,用于获取模型和tokenizer
@st.cache_resource
def get_model():
# 从预训练的模型中获取tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)
# 从预训练的模型中获取模型,并设置模型参数
model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, trust_remote_code=True,torch_dtype=torch.bfloat16, device_map="auto")
# 从预训练的模型中获取生成配置
model.generation_config = GenerationConfig.from_pretrained(mode_name_or_path)
# 设置模型为评估模式
model.eval()
return tokenizer, model
# 加载Baichuan-7B-chat的model和tokenizer
tokenizer, model = get_model()
# 如果session_state中没有"messages",则创建一个包含默认消息的列表
if "messages" not in st.session_state:
st.session_state["messages"] = [{"role": "assistant", "content": "有什么可以帮您的?"}]
# 遍历session_state中的所有消息,并显示在聊天界面上
for msg in st.session_state.messages:
st.chat_message(msg["role"]).write(msg["content"])
# 如果用户在聊天输入框中输入了内容,则执行以下操作
if prompt := st.chat_input():
# 将用户的输入添加到session_state中的messages列表中
st.session_state.messages.append({"role": "user", "content": prompt})
# 在聊天界面上显示用户的输入
st.chat_message("user").write(prompt)
# 构建输入
input_tensor = tokenizer.apply_chat_template(st.session_state.messages, add_generation_prompt=True, return_tensors="pt")
# 通过模型获得输出
outputs = model.generate(input_tensor.to(model.device), max_new_tokens=max_length)
# 解码模型的输出,并去除特殊标记
response = tokenizer.decode(outputs[0][input_tensor.shape[1]:], skip_special_tokens=True)
# 将模型的输出添加到session_state中的messages列表中
st.session_state.messages.append({"role": "assistant", "content": response})
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(response)
```
## 运行 demo
在终端中运行以下命令,启动streamlit服务,并按照 `autodl` 的指示将端口映射到本地,然后在浏览器中打开链接 [http://localhost:6006/](http://localhost:6006/) ,即可看到聊天界面。
```Python
streamlit run /root/autodl-tmp/chatBot.py --server.address 127.0.0.1 --server.port 6006
```
如下所示:
![Alt text](images/image20.png)
@@ -0,0 +1,171 @@
# Baichuan2-7B-chat langchain 接入
这篇主要讲 `Baichuan2-7B-chat` 如何对接`Langchain``langchain.llms.base``LLM` 模块,并且提供一个快捷搭建向量数据库、Agent等多功能的Langchain应用的部署方案;关于如何具体对接向量数据库和`gradio`的部分请参考[internLM langchain](https://github.com/datawhalechina/self-llm/blob/master/InternLM/06-InternLM%E6%8E%A5%E5%85%A5LangChain%E6%90%AD%E5%BB%BA%E7%9F%A5%E8%AF%86%E5%BA%93%E5%8A%A9%E6%89%8B.md)模块。
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.811.3版本以上的都可以) 接下来打开刚刚租用服务器的JupyterLab, 图像 并且打开其中的终端开始环境配置、模型下载和运行演示。
![Alt text](images/image1.png)
## 安装依赖
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope==1.9.5
pip install transformers==4.35.2
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install langchain==0.0.292
```
## 模型下载:
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py 执行下载,模型大小为15 GB,下载模型大概需要10~20分钟
```Python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('baichuan-inc/Baichuan2-7B-Chat',cache_dir='/root/autodl-tmp', revision='v1.0.4')
```
## Baichuan2-7B-chat 接入 LangChain
为便捷构建 LLM 应用,我们需要基于本地部署的 Baichuan2-7B-chat,自定义一个 LLM 类,将 Baichuan2-7B-chat 接入到 LangChain 框架中。完成自定义 LLM 类之后,可以以完全一致的方式调用 LangChain 的接口,而无需考虑底层模型调用的不一致。
基于本地部署的 Baichuan2-7B-chat 自定义 LLM 类并不复杂,我们只需从LangChain.llms.base.LLM 类继承一个子类,并重写构造函数与 `_call` 函数即可:
```Python
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import torch
class baichuan2_LLM(LLM):
# 基于本地 Baichuan 自定义 LLM 类
tokenizer : AutoTokenizer = None
model: AutoModelForCausalLM = None
def __init__(self, model_path :str):
# model_path: Baichuan-7B-chat模型路径
# 从本地初始化模型
super().__init__()
print("正在从本地加载模型...")
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True,torch_dtype=torch.bfloat16, device_map="auto")
self.model.generation_config = GenerationConfig.from_pretrained(model_path)
self.model = self.model.eval()
print("完成本地模型的加载")
def _call(self, prompt : str, stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any):
# 重写调用函数
messages = [
{"role": "user", "content": prompt}
]
# 重写调用函数
response= self.model.chat(self.tokenizer, messages)
return response
@property
def _llm_type(self) -> str:
return "baichuan2_LLM"
```
## 调用
然后就可以像使用任何其他的langchain大模型功能一样使用了。
```Python
llm = baichuan2_LLM('/root/autodl-tmp/baichuan-inc/Baichuan2-7B-Chat')
llm('你是谁')
```
![Alt text](images/image6.png)
## 附加案例:使用Langchain-Chatchat快速搭建基于百川2的多功能问答平台
参考项目链接:[Langchain-Chatchat](https://github.com/chatchat-space/Langchain-Chatchat)
参考该项目AutoDL 镜像:[https://www.codewithgpu.com/i/chatchat-space/Langchain-Chatchat/Langchain-Chatchat](https://www.codewithgpu.com/i/chatchat-space/Langchain-Chatchat/Langchain-Chatchat)
### 具体部署流程:
进入该项目AutoDL 镜像:[https://www.codewithgpu.com/i/chatchat-space/Langchain-Chatchat/Langchain-Chatchat](https://www.codewithgpu.com/i/chatchat-space/Langchain-Chatchat/Langchain-Chatchat)
### 创建实例:
![Alt text](images/image7.png)
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器
![Alt text](images/image8.png)
## 默认的模型:
![Alt text](images/image9.png)
## 模型下载:
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py 执行下载,模型大小为15 GB,下载模型大概需要10~20分钟
```Python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('baichuan-inc/Baichuan2-7B-Chat',cache_dir='/root/autodl-tmp', revision='v1.0.4')
```
## 修改模型配置:
进入Langchain-Chatchat/configs/model_config.py文件,修改以下几个配置,调整成百川2模型
可选择多种模型:
![Alt text](images/image10.png)
添加本地模型地址:
![Alt text](images/image11.png)
## 调用:
选择新的终端
```Python
cd /root/Langchain-Chatchat/
conda activate /root/pyenv
python startup.py -a
```
![Alt text](images/image12.png)
可以考虑vsc的端口vsc端口转发功能,转发端口,本地运行
## 使用效果:
多模型选择对话:
![Alt text](images/image13.png)
知识库管理:
![Alt text](images/image14.png)
还有其他功能,可以自行尝试
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,220 @@
# Baichuan2-7B-chat lora 微调
## 概述:
本节我们简要介绍如何基于 transformers、peft 等框架,对 Baichuan2-7B-chat模型进行 Lora 微调。Lora 是一种高效微调方法,深入了解其原理可参见博客:[知乎|深入浅出Lora](https://zhuanlan.zhihu.com/p/650197598)。
这个教程会在同目录下给大家提供一个 [nodebook](https://github.com/datawhalechina/self-llm/blob/master/DeepSeek/04-DeepSeek-7B-chat%20Lora%20%E5%BE%AE%E8%B0%83.ipynb) 文件,来让大家更好的学习。
## 安装依赖
```shell
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope==1.9.5
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
pip install transformers==4.33.1
pip install peft==0.4.0
pip install datasets==2.10.1
pip install accelerate==0.20.3
pip install tiktoken
pip install transformers_stream_generator
```
## 模型下载:
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py 执行下载,模型大小为15 GB,下载模型大概需要10~20分钟
```Python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('baichuan-inc/Baichuan2-7B-Chat',cache_dir='/root/autodl-tmp', revision='v1.0.4')
```
## 指令集构建:
LLM 的微调一般指指令微调过程。所谓指令微调,是说我们使用的微调数据形如:
```Python
{
"instrution":"回答以下用户问题,仅输出答案。",
"input":"1+1等于几?",
"output":"2"
}
```
其中,`instruction` 是用户指令,告知模型其需要完成的任务;`input` 是用户输入,是完成用户指令所必须的输入内容;`output` 是模型应该给出的输出。
即我们的核心训练目标是让模型具有理解并遵循用户指令的能力。因此,在指令集构建时,我们应针对我们的目标任务,针对性构建任务指令集。例如,在本节我们使用由笔者合作开源的 [Chat-甄嬛](https://github.com/KMnO4-zx/huanhuan-chat) 项目作为示例,我们的目标是构建一个能够模拟甄嬛对话风格的个性化 LLM,因此我们构造的指令形如:
```Python
{
"instruction": "现在你要扮演皇帝身边的女人--甄嬛",
"input":"你是谁?",
"output":"家父是大理寺少卿甄远道。"
}
```
我们所构造的全部指令数据集在根目录下。
## 数据格式化:
`Lora` 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 `Pytorch` 模型训练流程的同学会知道,我们一般需要将输入文本编码为 input_ids,将输出文本编码为 `labels`,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:
```Python
def process_func(example):
MAX_LENGTH = 256
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer("\n".join(["<|im_start|>system", "现在你要扮演皇帝身边的女人--甄嬛.<|im_end|>" + "\n<|im_start|>user\n" + example["instruction"] + example["input"] + "<|im_end|>\n"]).strip()+"\n\nAssistant: ",add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
response = tokenizer(example["output"]+tokenizer.eos_token, add_special_tokens=False)
input_ids = instruction["input_ids"] + response["input_ids"]
attention_mask = instruction["attention_mask"] + response["attention_mask"]
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"]
if len(input_ids) > MAX_LENGTH: # 做一个截断
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
```
## 加载tokenizer和半精度模型:
```Python
import torch
model = AutoModelForCausalLM.from_pretrained('baichuan-inc/Baichuan2-7B-Chat', trust_remote_code=True, torch_dtype=torch.half, device_map="auto")
model.generation_config = GenerationConfig.from_pretrained('baichuan-inc/Baichuan2-7B-Chat/')
model
```
## 定义LoraConfig
`LoraConfig`这个类中可以设置很多参数,但主要的参数没多少,简单讲一讲,感兴趣的同学可以直接看源码。
- `task_type`:模型类型
- `target_modules`:需要训练的模型层的名字,主要就是`attention`部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。
- `r``lora`的秩,具体可以看`Lora`原理
- `lora_alpha``Lora alaph`,具体作用参见 `Lora` 原理
```Python
from peft import LoraConfig, TaskType, get_peft_model
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["W_pack", "o_proj", "gate_proj", "up_proj", "down_proj"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
config
```
## 自定义 TrainingArguments 参数:
`TrainingArguments`这个类的源码也介绍了每个参数的具体作用,当然大家可以来自行探索,这里就简单说几个常用的。
- `output_dir`:模型的输出路径
- `per_device_train_batch_size`:顾名思义 `batch_size`
- `gradient_accumulation_steps`: 梯度累加,如果你的显存比较小,那可以把 `batch_size` 设置小一点,梯度累加增大一些。
- `logging_steps`:多少步,输出一次`log`
- `num_train_epochs`:顾名思义 `epoch`
- `gradient_checkpointing`:梯度检查,这个一旦开启,模型就必须执行`model.enable_input_require_grads()`,这个原理大家可以自行探索,这里就不细说了。
```Python
args = TrainingArguments(
output_dir="./output/Baichuan2",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
logging_steps=10,
num_train_epochs=3,
save_steps=100,
learning_rate=5e-5,
save_on_each_node=True,
gradient_checkpointing=True
)
```
## 使用 Trainer 训练
```Python
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
```
![Alt text](images/image25.png)
## 模型推理
可以用这种比较经典的方式推理:
```Python
model.eval()
inputs = tokenizer("<|im_start|>system\n现在你要扮演皇帝身边的女人--甄嬛.<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n".format("你是谁", "").strip() + "\nassistant\n ", return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=100, eos_token_id=2)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(result)
```
![Alt text](images/image26.png)
或者重新加载模型:
```Python
from transformers import AutoModelForSeq2SeqLM
from peft import PeftModel, PeftConfig
peft_model_id = "output/Baichuan3/checkpoint-600" # 这里我训练出效果最好的一版是 checkpoint-600,所以调用了这个,大家可以根据自己情况选择
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForCausalLM.from_pretrained("baichuan-inc/Baichuan2-7B-Chat", use_fast=False, trust_remote_code=True)
model = PeftModel.from_pretrained(model, peft_model_id)
model.eval()
input = tokenizer("<|im_start|>system\n现在你要扮演皇帝身边的女人--甄嬛.<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n".format("你是谁", "").strip() + "\nassistant\n ", return_tensors="pt").to(model.device)
max_length = 512
outputs = model.generate(
**input,
max_length=max_length,
eos_token_id=2,
do_sample=True,
repetition_penalty=1.3,
no_repeat_ngram_size=5,
temperature=0.1,
top_k=40,
top_p=0.8,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
```
![Alt text](images/image27.png)
Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -0,0 +1,168 @@
# BlueLM-7B-Chat FastApi 部署
## 模型介绍
BlueLM-7B 是由 vivo AI 全球研究院自主研发的大规模预训练语言模型,参数规模为 70 亿。BlueLM-7B 在 [C-Eval](https://cevalbenchmark.com/index.html) 和 [CMMLU](https://github.com/haonan-li/CMMLU) 上均取得领先结果,对比同尺寸开源模型中具有较强的竞争力(截止11月1号)。本次发布共包含 7B 模型的 Base 和 Chat 两个版本。
模型下载链接见:
| 基座模型 | 对齐模型 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| 🤗 [BlueLM-7B-Base](https://huggingface.co/vivo-ai/BlueLM-7B-Base) | 🤗 [BlueLM-7B-Chat](https://huggingface.co/vivo-ai/BlueLM-7B-Chat) |
| 🤗 [BlueLM-7B-Base-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Base-32K) | 🤗 [BlueLM-7B-Chat-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-32K) |
| | 🤗 [BlueLM-7B-Chat-4bits](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-4bits) |
## 环境准备
这里在 [Autodl](https://www.autodl.com/) 平台中租赁一个3090 等 24G 显存的显卡机器,如下图所示镜像选择 PyTorch-->1.11.0-->3.8(ubuntu20.04)-->11.3Cuda版本在11.3以上都可以。
![image-20240319162858866](./images/202403191628941.png)
接下来打开刚刚租用服务器的 JupyterLab(也可以使用vscode ssh远程连接服务器),并且打开其中的终端开始环境配置、模型下载和运行 demo。
pip 换源加速下载并安装依赖包
```bash
# 升级pip
python -m pip install --upgrade pip
# 设置pip镜像源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 安装软件依赖
pip install fastapi==0.104.1
pip install uvicorn==0.24.0.post1
pip install requests==2.25.1
pip install modelscope==1.11.0
pip install transformers==4.37.0
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
```
## 模型下载
使用`Modelscope API` 下载`BlueLM-7B-Chat`模型,模型路径为`/root/autodl-tmp`。在 /root/autodl-tmp 下创建model_download.py文件内容如下:
```python
from modelscope import snapshot_download
model_dir = snapshot_download("vivo-ai/BlueLM-7B-Chat", cache_dir='/root/autodl-tmp', revision="master")
```
## 代码准备
在 /root/autodl-tmp 路径下新建 api.py 文件内容如下:
```python
from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import uvicorn
import json
import datetime
import torch
# 设置设备参数
DEVICE = "cuda" # 使用CUDA
DEVICE_ID = "0" # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE # 组合CUDA设备信息
# 清理GPU内存函数
def torch_gc():
if torch.cuda.is_available(): # 检查是否可用CUDA
with torch.cuda.device(CUDA_DEVICE): # 指定CUDA设备
torch.cuda.empty_cache() # 清空CUDA缓存
torch.cuda.ipc_collect() # 收集CUDA内存碎片
# 创建FastAPI应用
app = FastAPI()
# 处理POST请求的端点
@app.post("/")
async def create_item(request: Request):
global model, tokenizer # 声明全局变量以便在函数内部使用模型和分词器
json_post_raw = await request.json() # 获取POST请求的JSON数据
json_post = json.dumps(json_post_raw) # 将JSON数据转换为字符串
json_post_list = json.loads(json_post) # 将字符串转换为Python对象
prompt = json_post_list.get('prompt') # 获取请求中的提示
max_length = json_post_list.get('max_length') # 获取请求中的最大长度
# 构建 messages
messages = f"[|Human|]:{prompt}[|AI|]:"
# 构建输入
inputs = tokenizer(messages, return_tensors="pt")
inputs = inputs.to("cuda:0")
# 通过模型获得输出
outputs = model.generate(**inputs, max_new_tokens=max_length)
result = tokenizer.decode(outputs.cpu()[0], skip_special_tokens=True)
now = datetime.datetime.now() # 获取当前时间
time = now.strftime("%Y-%m-%d %H:%M:%S") # 格式化时间为字符串
# 构建响应JSON
answer = {
"response": result,
"status": 200,
"time": time
}
# 构建日志信息
log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(result) + '"'
print(log) # 打印日志
torch_gc() # 执行GPU内存清理
return answer # 返回响应
# 主函数入口
if __name__ == '__main__':
mode_name_or_path="vivo-ai/BlueLM-7B-Chat"
# 加载预训练的分词器和模型
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, trust_remote_code=True,torch_dtype=torch.bfloat16, device_map="auto")
model.generation_config = GenerationConfig.from_pretrained(mode_name_or_path)
model.generation_config.pad_token_id = model.generation_config.eos_token_id
model.eval() # 设置模型为评估模式
# 启动FastAPI应用
# 用6006端口可以将autodl的端口映射到本地,从而在本地使用api
uvicorn.run(app, host='127.0.0.1', port=6006, workers=1) # 在指定端口和主机上启动应用
```
## Api 部署
在bash终端中输入以下命令运行api服务:
```bash
cd /root/autodl-tmp
python api.py
```
终端出现以下输出表示服务正在运行
![image-20240319181346315](./images/202403191813385.png)
默认服务端口为6006,通过 POST 方法进行调用,可以使用 curl 调用,新建一个终端在里面输入以下内容:
```bash
curl -X POST "http://127.0.0.1:6006" \
-H 'Content-Type: application/json' \
-d '{"prompt": "你好"}'
```
也可以使用 python 中的 requests 库进行调用,如下所示:
```python
import requests
import json
def get_completion(prompt):
headers = {'Content-Type': 'application/json'}
data = {"prompt": prompt}
response = requests.post(url='http://127.0.0.1:6006', headers=headers, data=json.dumps(data))
return response.json()['response']
if __name__ == '__main__':
print(get_completion('你好'))
```
运行以后得到的返回值如下所示:
```json
{"response":"你好 你好!很高兴见到你,有什么我可以帮助你的吗?","status":200,"time":"2024-03-20 12:09:29"}
```
![image-20240320121025609](./images/202403201210690.png)
@@ -0,0 +1,108 @@
# BlueLM-7B-Chat langchain 接入
## 模型介绍
BlueLM-7B 是由 vivo AI 全球研究院自主研发的大规模预训练语言模型,参数规模为 70 亿。BlueLM-7B 在 [C-Eval](https://cevalbenchmark.com/index.html) 和 [CMMLU](https://github.com/haonan-li/CMMLU) 上均取得领先结果,对比同尺寸开源模型中具有较强的竞争力(截止11月1号)。本次发布共包含 7B 模型的 Base 和 Chat 两个版本。
模型下载链接见:
| 基座模型 | 对齐模型 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| 🤗 [BlueLM-7B-Base](https://huggingface.co/vivo-ai/BlueLM-7B-Base) | 🤗 [BlueLM-7B-Chat](https://huggingface.co/vivo-ai/BlueLM-7B-Chat) |
| 🤗 [BlueLM-7B-Base-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Base-32K) | 🤗 [BlueLM-7B-Chat-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-32K) |
| | 🤗 [BlueLM-7B-Chat-4bits](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-4bits) |
## 环境准备
在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器,如下图所示镜像选择 PyTorch-->1.11.0-->3.8(ubuntu20.04)-->11.3Cuda版本在11.3以上都可以。
![](./images/202403191628941.png)
接下来打开刚刚租用服务器的 JupyterLab(也可以使用vscode ssh远程连接服务器),并且打开其中的终端开始环境配置、模型下载和运行 demo。
pip 换源加速下载并安装依赖包
```bash
# 升级pip
python -m pip install --upgrade pip
# 设置pip镜像源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 安装软件依赖
pip install langchain==0.1.12
pip install modelscope==1.11.0
pip install transformers==4.37.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
```
## 模型下载
使用`Modelscope API` 下载`BlueLM-7B-Chat`模型,模型路径为`/root/autodl-tmp`。在 /root/autodl-tmp 下创建model_download.py文件内容如下:
```python
from modelscope import snapshot_download
model_dir = snapshot_download("vivo-ai/BlueLM-7B-Chat", cache_dir='/root/autodl-tmp', revision="master")
```
## 代码准备
为便捷构建 LLM 应用,我们需要基于本地部署的 BlueLM,自定义一个 LLM 类,将 BlueLM 接入到 LangChain 框架中。完成自定义 LLM 类之后,可以以完全一致的方式调用 LangChain 的接口,而无需考虑底层模型调用的不一致。
基于本地部署的 BlueLM 自定义 LLM 类并不复杂,我们只需从 `LangChain.llms.base.LLM` 类继承一个子类,并重写构造函数与 `_call` 函数即可,创建一个LLM.py文件内容如下:
```bash
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig, LlamaTokenizerFast
import torch
class BlueLM(LLM):
# 基于本地 BlueLM 自定义 LLM 类
tokenizer: AutoTokenizer = None
model: AutoModelForCausalLM = None
def __init__(self, mode_name_or_path :str):
super().__init__()
print("正在从本地加载模型...")
self.tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, torch_dtype=torch.float16, trust_remote_code=True).cuda()
self.model = self.model.eval()
print("完成本地模型的加载")
def _call(self, prompt : str, stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any):
# 重写调用函数
messages = f"[|Human|]:{prompt}[|AI|]:"
# 构建输入
inputs_tensor = self.tokenizer(messages, return_tensors="pt")
inputs_tensor = inputs_tensor.to("cuda:0")
# 通过模型获得输出
outputs = self.model.generate(**inputs_tensor, max_new_tokens=100)
response = self.tokenizer.decode(outputs.cpu()[0], skip_special_tokens=True)
return response
@property
def _llm_type(self) -> str:
return "BlueLM"
```
## 调用
然后就可以像使用任何其他的langchain大模型功能一样使用了。
```python
from LLM import BlueLM
llm = BlueLM('/root/autodl-tmp/vivo-ai/BlueLM-7B-Chat')
llm('你好')
```
如下图所示:
![image-20240320122929440](./images/202403201229542.png)
@@ -0,0 +1,193 @@
# BlueLM-7B-Chat WebDemo 部署
## 模型介绍
BlueLM-7B 是由 vivo AI 全球研究院自主研发的大规模预训练语言模型,参数规模为 70 亿。BlueLM-7B 在 [C-Eval](https://cevalbenchmark.com/index.html) 和 [CMMLU](https://github.com/haonan-li/CMMLU) 上均取得领先结果,对比同尺寸开源模型中具有较强的竞争力(截止11月1号)。本次发布共包含 7B 模型的 Base 和 Chat 两个版本。
模型下载链接见:
| 基座模型 | 对齐模型 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| 🤗 [BlueLM-7B-Base](https://huggingface.co/vivo-ai/BlueLM-7B-Base) | 🤗 [BlueLM-7B-Chat](https://huggingface.co/vivo-ai/BlueLM-7B-Chat) |
| 🤗 [BlueLM-7B-Base-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Base-32K) | 🤗 [BlueLM-7B-Chat-32K](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-32K) |
| | 🤗 [BlueLM-7B-Chat-4bits](https://huggingface.co/vivo-ai/BlueLM-7B-Chat-4bits) |
## 环境准备
在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器,如下图所示镜像选择 PyTorch-->1.11.0-->3.8(ubuntu20.04)-->11.3Cuda版本在11.3以上都可以。
![](./images/202403191628941.png)
接下来打开刚刚租用服务器的 JupyterLab(也可以使用vscode ssh远程连接服务器),并且打开其中的终端开始环境配置、模型下载和运行 demo。
pip 换源加速下载并安装依赖包
```bash
# 升级pip
python -m pip install --upgrade pip
# 设置pip镜像源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 安装软件依赖
pip install modelscope==1.11.0
pip install transformers==4.37.0
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
pip install transformers_stream_generator==0.0.4
```
## 模型下载
使用`Modelscope API` 下载`BlueLM-7B-Chat`模型,模型路径为`/root/autodl-tmp`。在 /root/autodl-tmp 下创建model_download.py文件内容如下:
```python
from modelscope import snapshot_download
model_dir = snapshot_download("vivo-ai/BlueLM-7B-Chat", cache_dir='/root/autodl-tmp', revision="master")
```
## 代码准备
`/root/autodl-tmp`路径下新建 `chatBot.py` 文件并在其中输入以下内容:
```python
# 导入所需的库
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig, TextStreamer
import torch
import streamlit as st
# 在侧边栏中创建一个标题和一个链接
with st.sidebar:
st.markdown("## BlueLM-7B-Chat")
"[开源大模型食用指南 self-llm](https://github.com/datawhalechina/self-llm.git)"
# 创建一个滑块,用于选择最大长度,范围在0到1024之间,默认值为512
max_length = st.slider("max_length", 0, 1024, 512, step=1)
# 创建一个标题和一个副标题
st.title("💬 BlueLM Chatbot")
st.caption("🚀 A streamlit chatbot powered by Self-LLM")
# 定义模型路径
mode_name_or_path = '/root/autodl-tvivo-ai/BlueLM-7B-Chat'
# 定义一个函数,用于获取模型和tokenizer
@st.cache_resource
def get_model():
# 从预训练的模型中获取tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True)
# 从预训练的模型中获取模型,并设置模型参数
model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, trust_remote_code=True,torch_dtype=torch.bfloat16, device_map="auto")
# 从预训练的模型中获取生成配置
model.generation_config = GenerationConfig.from_pretrained(mode_name_or_path)
# 设置生成配置的pad_token_id为生成配置的eos_token_id
model.generation_config.pad_token_id = model.generation_config.eos_token_id
# 设置模型为评估模式
model.eval()
return tokenizer, model
# 加载BlueLM的model和tokenizer
tokenizer, model = get_model()
def build_prompt(messages, prompt):
"""
构建会话提示信息。
参数:
messages - 包含会话历史的元组列表,每个元组是(用户查询,AI响应)。
prompt - 当前用户输入的文本。
返回值:
res - 构建好的包含会话历史和当前用户提示的字符串。
"""
res = ""
# 遍历历史消息,构建会话历史字符串
for query, response in messages:
res += f"[|Human|]:{query}[|AI|]:{response}</s>"
# 添加当前用户提示
res += f"[|Human|]:{prompt}[|AI|]:"
return res
class BlueLMStreamer(TextStreamer):
"""
BlueLM流式处理类,用于处理模型的输入输出流。
参数:
tokenizer - 用于分词和反分词的tokenizer实例。
"""
def __init__(self, tokenizer: "AutoTokenizer"):
self.tokenizer = tokenizer
self.tokenIds = []
self.prompt = ""
self.response = ""
self.first = True
def put(self, value):
"""
添加token id到流中。
参数:
value - 要添加的token id。
"""
if self.first:
self.first = False
return
self.tokenIds.append(value.item())
# 将token ids解码为文本
text = tokenizer.decode(self.tokenIds, skip_special_tokens=True)
def end(self):
"""
结束流处理,将当前流中的文本作为响应,并重置流状态。
"""
self.first = True
# 将token ids解码为文本
text = tokenizer.decode(self.tokenIds, skip_special_tokens=True)
self.response = text
self.tokenIds = []
# 初始化session状态,如果messages不存在则初始化为空,并添加欢迎信息
if "messages" not in st.session_state:
st.session_state.messages = []
st.session_state.messages.append(("", "你好,有什么可以帮助你吗?"))
# 遍历并显示历史消息
for msg in st.session_state.messages:
st.chat_message("assistant").write(msg[1])
# 处理用户输入
if prompt_text := st.chat_input():
prompt_text = prompt_text.strip()
st.chat_message("user").write(prompt_text)
messages = st.session_state.messages
# 使用BlueLMStreamer处理流式模型输入
streamer = BlueLMStreamer(tokenizer=tokenizer)
# 构建当前会话的提示信息
prompt = build_prompt(messages=messages, prompt=prompt_text)
# 将提示信息编码为模型输入
inputs_tensor = tokenizer(prompt, return_tensors="pt")
inputs_tensor = inputs_tensor.to("cuda:0")
input_ids = inputs_tensor["input_ids"]
# 通过模型生成响应
outputs = model.generate(input_ids=input_ids, max_new_tokens=max_length, streamer=streamer)
# 将模型的响应显示给用户
st.chat_message("assistant").write(streamer.response)
# 更新会话历史
st.session_state.messages.append((prompt_text, streamer.response))
```
## 运行 demo
在终端中运行以下命令,启动streamlit服务,并按照 `autodl` 的指示将端口映射到本地,然后在浏览器中打开链接 http://localhost:6006/ ,即可看到聊天界面。
```bash
streamlit run /root/autodl-tmp/chatBot.py --server.address 127.0.0.1 --server.port 6006
```
如下所示:
![image-20240320215320315](./images/202403202153465.png)
@@ -0,0 +1,914 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "de53995b-32ed-4722-8cac-ba104c8efacb",
"metadata": {},
"source": [
"## 导入环境"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "52fac949-4150-4091-b0c3-2968ab5e385c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"from datasets import Dataset\n",
"import pandas as pd\n",
"from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig"
]
},
{
"cell_type": "markdown",
"id": "96484398",
"metadata": {},
"source": [
"## 数据转换"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "e098d9eb",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [],
"source": [
"# 将JSON文件转换为CSV文件\n",
"df = pd.read_json('./huanhuan.json')\n",
"ds = Dataset.from_pandas(df)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "8ac92d42-efae-49b1-a00e-ccaa75b98938",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"{'instruction': ['小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——',\n",
" '这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。',\n",
" '嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。'],\n",
" 'input': ['', '', ''],\n",
" 'output': ['嘘——都说许愿说破是不灵的。', '你们俩话太多了,我该和温太医要一剂药,好好治治你们。', '出来走走,也是散心。']}"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ds[:3]"
]
},
{
"cell_type": "markdown",
"id": "51d05e5d-d14e-4f03-92be-9a9677d41918",
"metadata": {},
"source": [
"## 处理数据集"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "74ee5a67-2e55-4974-b90e-cbf492de500a",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"BlueLMTokenizer(name_or_path='vivo-ai/BlueLM-7B-Chat', vocab_size=100000, model_max_length=1000000000000000019884624838656, is_fast=False, padding_side='right', truncation_side='right', special_tokens={'bos_token': '<s>', 'eos_token': '</s>', 'unk_token': '<unk>', 'pad_token': '<pad>', 'additional_special_tokens': ['[|Human|]:', '[|AI|]:', '[SEH]', '[SEA]']}, clean_up_tokenization_spaces=False), added_tokens_decoder={\n",
"\t0: AddedToken(\"<unk>\", rstrip=False, lstrip=False, single_word=False, normalized=True, special=True),\n",
"\t1: AddedToken(\"<s>\", rstrip=False, lstrip=False, single_word=False, normalized=True, special=True),\n",
"\t2: AddedToken(\"</s>\", rstrip=False, lstrip=False, single_word=False, normalized=True, special=True),\n",
"\t3: AddedToken(\"<pad>\", rstrip=False, lstrip=False, single_word=False, normalized=True, special=True),\n",
"\t100000: AddedToken(\"[|Human|]:\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
"\t100001: AddedToken(\"[|AI|]:\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
"\t100002: AddedToken(\"[SEH]\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
"\t100003: AddedToken(\"[SEA]\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
"}"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer = AutoTokenizer.from_pretrained('vivo-ai/BlueLM-7B-Chat', use_fast=False, trust_remote_code=True)\n",
"tokenizer.padding_side = 'right'\n",
"tokenizer"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "2475a864-b319-45de-81fa-a4941e7a0fb8",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [],
"source": [
"def process_func(example):\n",
" MAX_LENGTH = 384\n",
" input_ids = []\n",
" labels = []\n",
"\n",
" instruction = tokenizer(text=f\"[|Human|]:现在你要扮演皇帝身边的女人--甄嬛\\n\\n {example['instruction']}{example['input']}[|AI|]:\", add_special_tokens=False)\n",
" response = tokenizer(text=f\"{example['output']}\", add_special_tokens=False)\n",
" input_ids = [tokenizer.bos_token_id] + instruction[\"input_ids\"] + response[\"input_ids\"] + [tokenizer.eos_token_id]\n",
" labels = [tokenizer.bos_token_id] + [-100] * len(instruction[\"input_ids\"]) + response[\"input_ids\"] + [tokenizer.eos_token_id]\n",
" if len(input_ids) > MAX_LENGTH:\n",
" input_ids = input_ids[:MAX_LENGTH]\n",
" labels = labels[:MAX_LENGTH]\n",
"\n",
" return {\n",
" \"input_ids\": input_ids,\n",
" \"labels\": labels\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "84f870d6-73a9-4b0f-8abf-687b32224ad8",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Map: 0%| | 0/3729 [00:00<?, ? examples/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Dataset({\n",
" features: ['input_ids', 'labels'],\n",
" num_rows: 3729\n",
"})"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenized_id = ds.map(process_func, remove_columns=ds.column_names)\n",
"tokenized_id"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "1f7e15a0-4d9a-4935-9861-00cc472654b1",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"'<s> [|Human|]: 现在你要扮演皇帝身边的女人--甄嬛\\n\\n 这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。 [|AI|]: 你们俩话太多了,我该和温太医要一剂药,好好治治你们。</s>'"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.decode(tokenized_id[1]['input_ids'])"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "97f16f66-324a-454f-8cc3-ef23b100ecff",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"'<s> 你们俩话太多了,我该和温太医要一剂药,好好治治你们。</s>'"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.decode(list(filter(lambda x: x != -100, tokenized_id[1][\"labels\"])))"
]
},
{
"cell_type": "markdown",
"id": "424823a8-ed0d-4309-83c8-3f6b1cdf274c",
"metadata": {},
"source": [
"## 创建模型"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "170764e5-d899-4ef4-8c53-36f6dec0d198",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e0bae2f9e8ce4c3b918a37c71c0a9b29",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading checkpoint shards: 0%| | 0/8 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/root/miniconda3/lib/python3.8/site-packages/torch/_utils.py:776: UserWarning: TypedStorage is deprecated. It will be removed in the future and UntypedStorage will be the only storage class. This should only matter to you if you are using storages directly. To access UntypedStorage directly, use tensor.untyped_storage() instead of tensor.storage()\n",
" return self.fget.__get__(instance, owner)()\n"
]
},
{
"data": {
"text/plain": [
"BlueLMForCausalLM(\n",
" (model): BlueLMModel(\n",
" (embed_tokens): Embedding(100008, 4096, padding_idx=3)\n",
" (embed_layer_norm): LayerNorm((4096,), eps=1e-06, elementwise_affine=True)\n",
" (layers): ModuleList(\n",
" (0-31): 32 x BlueLMDecoderLayer(\n",
" (self_attn): BlueLMAttention(\n",
" (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
" (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
" (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
" (o_proj): Linear(in_features=4096, out_features=4096, bias=False)\n",
" (rotary_emb): BlueLMRotaryEmbedding()\n",
" )\n",
" (mlp): BlueLMMLP(\n",
" (gate_proj): Linear(in_features=4096, out_features=11008, bias=False)\n",
" (down_proj): Linear(in_features=11008, out_features=4096, bias=False)\n",
" (up_proj): Linear(in_features=4096, out_features=11008, bias=False)\n",
" (act_fn): SiLU()\n",
" (dropout): Dropout(p=0, inplace=False)\n",
" )\n",
" (input_layernorm): BlueLMRMSNorm()\n",
" (post_attention_layernorm): BlueLMRMSNorm()\n",
" )\n",
" )\n",
" (norm): BlueLMRMSNorm()\n",
" )\n",
" (lm_head): Linear(in_features=4096, out_features=100008, bias=False)\n",
")"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"model = AutoModelForCausalLM.from_pretrained('vivo-ai/BlueLM-7B-Chat', trust_remote_code=True, torch_dtype=torch.half, device_map=\"auto\")\n",
"model.generation_config = GenerationConfig.from_pretrained('vivo-ai/BlueLM-7B-Chat')\n",
"model.generation_config.pad_token_id = model.generation_config.eos_token_id\n",
"model"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "2323eac7-37d5-4288-8bc5-79fac7113402",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "f808b05c-f2cb-48cf-a80d-0c42be6051c7",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"torch.float16"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.dtype"
]
},
{
"cell_type": "markdown",
"id": "13d71257-3c1c-4303-8ff8-af161ebc2cf1",
"metadata": {},
"source": [
"## lora "
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "2d304ae2-ab60-4080-a80d-19cac2e3ade3",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path=None, revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules=['q_proj', 'k_proj', 'v_proj', 'o_proj', 'gate_proj', 'up_proj', 'down_proj'], lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from peft import LoraConfig, TaskType, get_peft_model\n",
"\n",
"config = LoraConfig(\n",
" task_type=TaskType.CAUSAL_LM, \n",
" target_modules=[\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\", \"gate_proj\", \"up_proj\", \"down_proj\"],\n",
" inference_mode=False, # 训练模式\n",
" r=8, # Lora 秩\n",
" lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理\n",
" lora_dropout=0.1# Dropout 比例\n",
")\n",
"config"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "2c2489c5-eaab-4e1f-b06a-c3f914b4bf8e",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path='vivo-ai/BlueLM-7B-Chat', revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules=['q_proj', 'k_proj', 'v_proj', 'o_proj', 'gate_proj', 'up_proj', 'down_proj'], lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = get_peft_model(model, config)\n",
"config"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "ebf5482b-fab9-4eb3-ad88-c116def4be12",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"trainable params: 19,988,480 || all params: 7,315,533,824 || trainable%: 0.27323337545681203\n"
]
}
],
"source": [
"model.print_trainable_parameters()"
]
},
{
"cell_type": "markdown",
"id": "ca055683-837f-4865-9c57-9164ba60c00f",
"metadata": {},
"source": [
"## 配置训练参数"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "7e76bbff-15fd-4995-a61d-8364dc5e9ea0",
"metadata": {
"ExecutionIndicator": {
"show": true
},
"tags": []
},
"outputs": [],
"source": [
"args = TrainingArguments(\n",
" output_dir=\"./output/BlueLM\",\n",
" per_device_train_batch_size=8,\n",
" gradient_accumulation_steps=2,\n",
" logging_steps=10,\n",
" num_train_epochs=3,\n",
" save_steps=100,\n",
" learning_rate=1e-4,\n",
" save_on_each_node=True,\n",
" gradient_checkpointing=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "f142cb9c-ad99-48e6-ba86-6df198f9ed96",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/root/miniconda3/lib/python3.8/site-packages/accelerate/accelerator.py:432: FutureWarning: Passing the following arguments to `Accelerator` is deprecated and will be removed in version 1.0 of Accelerate: dict_keys(['dispatch_batches', 'split_batches', 'even_batches', 'use_seedable_sampler']). Please pass an `accelerate.DataLoaderConfiguration` instead: \n",
"dataloader_config = DataLoaderConfiguration(dispatch_batches=None, split_batches=False, even_batches=True, use_seedable_sampler=True)\n",
" warnings.warn(\n",
"Detected kernel version 5.4.0, which is below the recommended minimum of 5.5.0; this can cause the process to hang. It is recommended to upgrade the kernel to the minimum version or higher.\n"
]
}
],
"source": [
"trainer = Trainer(\n",
" model=model,\n",
" args=args,\n",
" train_dataset=tokenized_id,\n",
" data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "aec9bc36-b297-45af-99e1-d4c4d82be081",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"You are using an old version of the checkpointing format that is deprecated (We will also silently ignore `gradient_checkpointing_kwargs` in case you passed it).Please update to the new format on your modeling file. To use the new format, you need to completely remove the definition of the method `_set_gradient_checkpointing` in your model.\n",
"`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`...\n"
]
},
{
"data": {
"text/html": [
"\n",
" <div>\n",
" \n",
" <progress value='699' max='699' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
" [699/699 19:13, Epoch 2/3]\n",
" </div>\n",
" <table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: left;\">\n",
" <th>Step</th>\n",
" <th>Training Loss</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <td>10</td>\n",
" <td>4.757700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>20</td>\n",
" <td>4.205300</td>\n",
" </tr>\n",
" <tr>\n",
" <td>30</td>\n",
" <td>4.267400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>40</td>\n",
" <td>3.967800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>50</td>\n",
" <td>4.019700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>60</td>\n",
" <td>3.953000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>70</td>\n",
" <td>4.016100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>80</td>\n",
" <td>4.133200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>90</td>\n",
" <td>4.092700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>100</td>\n",
" <td>3.978900</td>\n",
" </tr>\n",
" <tr>\n",
" <td>110</td>\n",
" <td>3.964600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>120</td>\n",
" <td>4.054300</td>\n",
" </tr>\n",
" <tr>\n",
" <td>130</td>\n",
" <td>3.998100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>140</td>\n",
" <td>3.893700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>150</td>\n",
" <td>3.992800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>160</td>\n",
" <td>3.956400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>170</td>\n",
" <td>3.955800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>180</td>\n",
" <td>3.811200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>190</td>\n",
" <td>3.891700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>200</td>\n",
" <td>3.913600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>210</td>\n",
" <td>3.762400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>220</td>\n",
" <td>3.756400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>230</td>\n",
" <td>3.917800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>240</td>\n",
" <td>3.540800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>250</td>\n",
" <td>3.116500</td>\n",
" </tr>\n",
" <tr>\n",
" <td>260</td>\n",
" <td>2.834200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>270</td>\n",
" <td>2.949700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>280</td>\n",
" <td>2.986600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>290</td>\n",
" <td>3.052400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>300</td>\n",
" <td>2.939600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>310</td>\n",
" <td>3.038000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>320</td>\n",
" <td>2.957600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>330</td>\n",
" <td>2.921300</td>\n",
" </tr>\n",
" <tr>\n",
" <td>340</td>\n",
" <td>2.918400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>350</td>\n",
" <td>3.000800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>360</td>\n",
" <td>2.884400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>370</td>\n",
" <td>2.962400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>380</td>\n",
" <td>2.973700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>390</td>\n",
" <td>3.014500</td>\n",
" </tr>\n",
" <tr>\n",
" <td>400</td>\n",
" <td>2.842000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>410</td>\n",
" <td>3.038500</td>\n",
" </tr>\n",
" <tr>\n",
" <td>420</td>\n",
" <td>2.928600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>430</td>\n",
" <td>3.047200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>440</td>\n",
" <td>2.936800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>450</td>\n",
" <td>2.944400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>460</td>\n",
" <td>2.857200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>470</td>\n",
" <td>2.594800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>480</td>\n",
" <td>1.990700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>490</td>\n",
" <td>1.990900</td>\n",
" </tr>\n",
" <tr>\n",
" <td>500</td>\n",
" <td>1.932000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>510</td>\n",
" <td>1.930000</td>\n",
" </tr>\n",
" <tr>\n",
" <td>520</td>\n",
" <td>1.879200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>530</td>\n",
" <td>1.995700</td>\n",
" </tr>\n",
" <tr>\n",
" <td>540</td>\n",
" <td>2.035100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>550</td>\n",
" <td>2.158200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>560</td>\n",
" <td>2.031600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>570</td>\n",
" <td>2.086100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>580</td>\n",
" <td>1.979400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>590</td>\n",
" <td>1.964100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>600</td>\n",
" <td>1.907600</td>\n",
" </tr>\n",
" <tr>\n",
" <td>610</td>\n",
" <td>1.972200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>620</td>\n",
" <td>1.960400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>630</td>\n",
" <td>2.018400</td>\n",
" </tr>\n",
" <tr>\n",
" <td>640</td>\n",
" <td>1.948500</td>\n",
" </tr>\n",
" <tr>\n",
" <td>650</td>\n",
" <td>1.960900</td>\n",
" </tr>\n",
" <tr>\n",
" <td>660</td>\n",
" <td>1.960800</td>\n",
" </tr>\n",
" <tr>\n",
" <td>670</td>\n",
" <td>1.954200</td>\n",
" </tr>\n",
" <tr>\n",
" <td>680</td>\n",
" <td>1.937100</td>\n",
" </tr>\n",
" <tr>\n",
" <td>690</td>\n",
" <td>1.937400</td>\n",
" </tr>\n",
" </tbody>\n",
"</table><p>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"TrainOutput(global_step=699, training_loss=2.9865300038000715, metrics={'train_runtime': 1156.1019, 'train_samples_per_second': 9.676, 'train_steps_per_second': 0.605, 'total_flos': 4.36795893785641e+16, 'train_loss': 2.9865300038000715, 'epoch': 2.99})"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"trainer.train()"
]
},
{
"cell_type": "markdown",
"id": "0a5d2418",
"metadata": {},
"source": [
"## 推理"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "4b2cee5d-3d58-4f82-8d26-0eb0158f61f9",
"metadata": {
"ExecutionIndicator": {
"show": false
},
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/root/miniconda3/lib/python3.8/site-packages/torch/utils/checkpoint.py:31: UserWarning: None of the inputs have requires_grad=True. Gradients will be None\n",
" warnings.warn(\"None of the inputs have requires_grad=True. Gradients will be None\")\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的—— 姐姐,您别急,咱们还有机会的。\n"
]
}
],
"source": [
"text = \"小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——\"\n",
"inputs = tokenizer(f\"[|Human|]:{text}[|AI|]:\", return_tensors=\"pt\")\n",
"outputs = model.generate(**inputs.to(model.device), max_new_tokens=100)\n",
"result = tokenizer.decode(outputs[0], skip_special_tokens=True)\n",
"print(result)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,161 @@
# BlueLM-7B-Chat Lora 微调
## 概述
本节我们简要介绍如何基于 transformers、peft 等框架,对 BlueLM-7B-Chat 模型进行 Lora 微调。Lora 是一种高效微调方法,深入了解其原理可参见博客:[知乎|深入浅出Lora](https://zhuanlan.zhihu.com/p/650197598)。
这个教程会在同目录下给大家提供一个 [notebook](./04-BlueLM-7B-Chat%20Lora%20微调.ipynb) 文件,来让大家更好的学习。
## 环境配置
在完成基本环境配置和本地模型部署的情况下,你还需要安装一些第三方库,可以使用以下命令:
```bash
pip install transformers==4.35.2
pip install peft==0.4.0
pip install datasets==2.10.1
pip install accelerate==0.20.3
pip install tiktoken
pip install transformers_stream_generator
```
在本节教程里,我们将微调数据集放置在根目录 [/dataset](https://github.com/datawhalechina/self-llm/blob/master/dataset/huanhuan.json)。
## 指令集构建
LLM 的微调一般指指令微调过程。所谓指令微调,是说我们使用的微调数据形如:
```json
{
"instruction": "解释什么是人工智能。\n",
"input": "",
"output": "人工智能是一种利用计算机程序和算法创造出类似人类智能的技术,可以让计算机在解决问题、学习、推理和自然语言处理等方面表现出类似人类的能力。"
}
```
其中,`instruction` 是用户指令,告知模型其需要完成的任务;`input` 是用户输入,是完成用户指令所必须的输入内容;`output` 是模型应该给出的输出。而在BlueLM中数据的目标格式是这样的
```json
{
"inputs": "[|Human|]:解释什么是人工智能。\n[|AI|]:",
"targets": "人工智能是一种利用计算机程序和算法创造出类似人类智能的技术,可以让计算机在解决问题、学习、推理和自然语言处理等方面表现出类似人类的能力。"}
```
## 数据格式化
`Lora` 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 `Pytorch` 模型训练流程的同学会知道,我们一般需要将输入文本编码为 input_ids,将输出文本编码为 `labels`,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:
```python
def process_func(example):
MAX_LENGTH = 384
input_ids = []
labels = []
instruction = tokenizer(text=f"[|Human|]:现在你要扮演皇帝身边的女人--甄嬛\n\n {example['instruction']}{example['input']}[|AI|]:", add_special_tokens=False)
response = tokenizer(text=f"{example['output']}", add_special_tokens=False)
input_ids = [tokenizer.bos_token_id] + instruction["input_ids"] + response["input_ids"] + [tokenizer.eos_token_id]
labels = [tokenizer.bos_token_id] + [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.eos_token_id]
if len(input_ids) > MAX_LENGTH:
input_ids = input_ids[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"labels": labels
}
```
经过格式化的数据,也就是送入模型的每一条数据,都是一个字典,包含了 `input_ids``labels` 两个键值对,其中 `input_ids` 是输入文本的编码,`labels` 是输出文本的编码。decode之后应该是这样的:
```json
<s> [|Human|]: --\n\n 便 [|AI|]: </s>
```
为什么会是这个形态呢?好问题!不同模型所对应的格式化输入都不一样,BlueLM只有`[|Human|]和[|AI|]`两个角色,所以自然而然数据格式就是这样的啦。
## 加载tokenizer和模型
```python
import torch
model = AutoModelForCausalLM.from_pretrained('vivo-ai/BlueLM-7B-Chat', trust_remote_code=True, torch_dtype=torch.half, device_map="auto")
model.generation_config = GenerationConfig.from_pretrained('vivo-ai/BlueLM-7B-Chat')
model.generation_config.pad_token_id = model.generation_config.eos_token_id
```
## 定义LoraConfig
`LoraConfig`这个类中可以设置很多参数,但主要的参数没多少,简单讲一讲,感兴趣的同学可以直接看源码。
- `task_type`:模型类型
- `target_modules`:需要训练的模型层的名字,主要就是`attention`部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。
- `r``lora`的秩,具体可以看`Lora`原理
- `lora_alpha``Lora alaph`,具体作用参见 `Lora` 原理
`Lora`的缩放是啥嘞?当然不是`r`(秩),这个缩放就是`lora_alpha/r`, 在这个`LoraConfig`中缩放就是4倍。
```python
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["c_attn", "c_proj", "w1", "w2"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
```
## 自定义 TrainingArguments 参数
`TrainingArguments`这个类的源码也介绍了每个参数的具体作用,当然大家可以来自行探索,这里就简单说几个常用的。
- `output_dir`:模型的输出路径
- `per_device_train_batch_size`:顾名思义 `batch_size`
- `gradient_accumulation_steps`: 梯度累加,如果你的显存比较小,那可以把 `batch_size` 设置小一点,梯度累加增大一些。
- `logging_steps`:多少步,输出一次`log`
- `num_train_epochs`:顾名思义 `epoch`
- `gradient_checkpointing`:梯度检查,这个一旦开启,模型就必须执行`model.enable_input_require_grads()`,这个原理大家可以自行探索,这里就不细说了。
```python
args = TrainingArguments(
output_dir="./output/Qwen",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
logging_steps=10,
num_train_epochs=3,
gradient_checkpointing=True,
save_steps=100,
learning_rate=1e-4,
save_on_each_node=True
)
```
## 使用 Trainer 训练
把 model 放进去,把上面设置的参数放进去,数据集放进去,OK!开始训练!
```python
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train()
```
## 模型推理
使用最常用的方式进行推理
```python
text = "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——"
inputs = tokenizer(f"[|Human|]:{text}[|AI|]:", return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=100)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(result)
```
完整代码请看:[BlueLM-7B-Chat Lora 微调](./04-BlueLM-7B-Chat%20Lora%20微调.ipynb)
@@ -0,0 +1,79 @@
from datasets import Dataset
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig
import torch
from peft import LoraConfig, TaskType, get_peft_model
def process_func(example):
MAX_LENGTH = 384
input_ids = []
labels = []
instruction = tokenizer(
text=f"[|Human|]:现在你要扮演皇帝身边的女人--甄嬛\n\n {example['instruction']}{example['input']}[|AI|]:",
add_special_tokens=False)
response = tokenizer(text=f"{example['output']}", add_special_tokens=False)
input_ids = [tokenizer.bos_token_id] + instruction["input_ids"] + response["input_ids"] + [tokenizer.eos_token_id]
labels = [tokenizer.bos_token_id] + [-100] * len(instruction["input_ids"]) + response["input_ids"] + [
tokenizer.eos_token_id]
if len(input_ids) > MAX_LENGTH:
input_ids = input_ids[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"labels": labels
}
# lora配置
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
# 训练参数
args = TrainingArguments(
output_dir="./output/BlueLM",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
logging_steps=10,
num_train_epochs=3,
save_steps=100,
learning_rate=1e-4,
save_on_each_node=True,
gradient_checkpointing=True
)
if __name__ == '__main__':
# 将JSON文件转换为CSV文件
df = pd.read_json('./huanhuan.json')
ds = Dataset.from_pandas(df)
# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained('vivo-ai/BlueLM-7B-Chat', use_fast=False, trust_remote_code=True)
# 将数据集变化为token形式
tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
# 创建模型
model = AutoModelForCausalLM.from_pretrained('vivo-ai/BlueLM-7B-Chat', trust_remote_code=True,
torch_dtype=torch.half, device_map="auto")
model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法
# 模型合并
model = get_peft_model(model, config)
# 使用trainer训练
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train() # 开始训练
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

@@ -0,0 +1,77 @@
# CharacterGLM-6B Transformers部署调用
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8
![image](https://github.com/suncaleb1/self-llm/assets/155936975/fc4c6323-d338-4d66-a244-bbefe7da3746)
接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下载和运行demo。
pip换源和安装依赖包
```python
#升级pip
python -m pip install --upgrade pip
#更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope
pip install transformers
pip install sentencepiece
```
## 模型下载
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py执行下载,模型大小为 12 GB,下载模型大概需要 10~15 分钟
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('THUCoAI/CharacterGLM-6B', cache_dir='/root/autodl-tmp', revision='master')
```
## 代码准备
```python
from transformers import AutoTokenizer,AutoModelForCausalLM
import torch
# 使用模型下载到的本地路径以加载
model_dir = '/root/autodl-tmp/THUCoAI/CharacterGLM-6B'
# 分词器的加载,本地加载,trust_remote_code=True设置允许从网络上下载模型权重和相关的代码
tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)
# 模型加载,本地加载,使用AutoModelForCausalLM类
model = AutoModelForCausalLM.from_pretrained(model_dir, trust_remote_code=True)
# 将模型移动到GPU上进行加速(如果有GPU的话)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
# 使用模型的评估模式来产生对话
model.eval()
session_meta = {'user_info': '我是陆星辰,是一个男性,是一位知名导演,也是苏梦远的合作导演。我擅长拍摄音乐题材的电影。苏梦远对我的态度是尊敬的,并视我为良师益友。', 'bot_info': '苏梦远,本名苏远心,是一位当红的国内女歌手及演员。在参加选秀节目后,凭借独特的嗓音及出众的舞台魅力迅速成名,进入娱乐圈。她外表美丽动人,但真正的魅力在于她的才华和勤奋。苏梦远是音乐学院毕业的优秀生,善于创作,拥有多首热门原创歌曲。除了音乐方面的成就,她还热衷于慈善事业,积极参加公益活动,用实际行动传递正能量。在工作中,她对待工作非常敬业,拍戏时总是全身心投入角色,赢得了业内人士的赞誉和粉丝的喜爱。虽然在娱乐圈,但她始终保持低调、谦逊的态度,深得同行尊重。在表达时,苏梦远喜欢使用“我们”和“一起”,强调团队精神。', 'bot_name': '苏梦远', 'user_name': '陆星辰'}
# 第一轮对话
response, history = model.chat(tokenizer, session_meta,"你好呀,小苏", history=[])
print(response)
# 第二轮对话
response, history = model.chat(tokenizer, session_meta,"最近对音乐有什么新的想法吗", history=history)
print(response)
# 第三轮对话
response, history = model.chat(tokenizer,session_meta, "那我们商量一下下一部音乐电影的拍摄,好嘛?", history=history)
print(response)
```
## 部署
在终端输入以下命令运行trans.py,即实现CharacterGLM-6B的Transformers部署调用
```python
cd /root/autodl-tmp
python trans.py
```
观察命令行中loading checkpoint表示模型正在加载,等待模型加载完成产生对话,如下图所示
![image](https://github.com/suncaleb1/self-llm/assets/155936975/f9d65275-fa89-4039-95c5-7cc0615753e2)
@@ -0,0 +1,183 @@
# CharacterGLM-6B FastApi部署调用
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8
![image](https://github.com/suncaleb1/self-llm/assets/155936975/2992ca12-7566-4916-94a6-1367df1a0d35)
接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下载和运行demo。
pip换源和安装依赖包
```python
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install fastapi==0.104.1
pip install uvicorn==0.24.0.post1
pip install requests==2.25.1
pip install modelscope==1.9.5
pip install transformers==4.37.2
pip install streamlit==1.24.0
pip install sentencepiece==0.1.99
pip install accelerate==0.24.1
```
## 模型下载
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py执行下载,模型大小为 12 GB,下载模型大概需要 10~15 分钟
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('THUCoAI/CharacterGLM-6B', cache_dir='/root/autodl-tmp', revision='master')
```
## 代码准备
在/root/autodl-tmp路径下新建api.py文件并在其中输入以下内容,粘贴代码后记得保存文件。下面的代码有很详细的注释,大家如有不理解的地方,欢迎提出issue。
```python
from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM
import uvicorn
import json
import datetime
import torch
# 设置设备参数
DEVICE = "cuda" # 使用CUDA
DEVICE_ID = "0" # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE # 组合CUDA设备信息
# 清理GPU内存函数
def torch_gc():
if torch.cuda.is_available(): # 检查是否可用CUDA
with torch.cuda.device(CUDA_DEVICE): # 指定CUDA设备
torch.cuda.empty_cache() # 清空CUDA缓存
torch.cuda.ipc_collect() # 收集CUDA内存碎片
# 创建FastAPI应用
app = FastAPI()
# 处理POST请求的端点
@app.post("/")
async def create_item(request: Request):
global model, tokenizer # 声明全局变量以便在函数内部使用模型和分词器
json_post_raw = await request.json() # 获取POST请求的JSON数据
json_post = json.dumps(json_post_raw) # 将JSON数据转换为字符串
json_post_list = json.loads(json_post) # 将字符串转换为Python对象
prompt = json_post_list.get('prompt') # 获取请求中的提示
history = json_post_list.get('history') # 获取请求中的历史记录
max_length = json_post_list.get('max_length') # 获取请求中的最大长度
top_p = json_post_list.get('top_p') # 获取请求中的top_p参数
temperature = json_post_list.get('temperature') # 获取请求中的温度参数
session_meta = {'user_info': '我是陆星辰,是一个男性,是一位知名导演,也是苏梦远的合作导演。我擅长拍摄音乐题材的电影。苏梦远对我的态度是尊敬的,并视我为良师益友。', 'bot_info': '苏梦远,本名苏远心,是一位当红的国内女歌手及演员。在参加选秀节目后,凭借独特的嗓音及出众的舞台魅力迅速成名,进入娱乐圈。她外表美丽动人,但真正的魅力在于她的才华和勤奋。苏梦远是音乐学院毕业的优秀生,善于创作,拥有多首热门原创歌曲。除了音乐方面的成就,她还热衷于慈善事业,积极参加公益活动,用实际行动传递正能量。在工作中,她对待工作非常敬业,拍戏时总是全身心投入角色,赢得了业内人士的赞誉和粉丝的喜爱。虽然在娱乐圈,但她始终保持低调、谦逊的态度,深得同行尊重。在表达时,苏梦远喜欢使用“我们”和“一起”,强调团队精神。', 'bot_name': '苏梦远', 'user_name': '陆星辰'}
# 调用模型进行对话生成
response, history = model.chat(
tokenizer,
session_meta,
prompt,
history=history,
max_length=max_length if max_length else 2048, # 如果未提供最大长度,默认使用2048
top_p=top_p if top_p else 0.7, # 如果未提供top_p参数,默认使用0.7
temperature=temperature if temperature else 0.95 # 如果未提供温度参数,默认使用0.95
)
now = datetime.datetime.now() # 获取当前时间
time = now.strftime("%Y-%m-%d %H:%M:%S") # 格式化时间为字符串
# 构建响应JSON
answer = {
"response": response,
"history": history,
"status": 200,
"time": time
}
# 构建日志信息
log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(response) + '"'
print(log) # 打印日志
torch_gc() # 执行GPU内存清理
return answer # 返回响应
# 主函数入口
if __name__ == '__main__':
# 加载预训练的分词器和模型
tokenizer = AutoTokenizer.from_pretrained("/root/autodl-tmp/THUCoAI/CharacterGLM-6B", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("/root/autodl-tmp/THUCoAI/CharacterGLM-6B", trust_remote_code=True).to(torch.bfloat16).cuda()
model.eval() # 设置模型为评估模式
# 启动FastAPI应用
# 用6006端口可以将autodl的端口映射到本地,从而在本地使用api
uvicorn.run(app, host='0.0.0.0', port=6006, workers=1) # 在指定端口和主机上启动应用
```
## Api部署调用
在终端输入以下命令启动api服务
```python
cd /root/autodl-tmp
python api.py
```
默认部署在 6006 端口,通过 POST 方法进行调用,可以使用curl调用,如下所示:
```python
curl -X POST "http://127.0.0.1:6006" \
-H 'Content-Type: application/json' \
-d '{"prompt": "你好", "history": []}'
```
调用示例结果如下图所示
![image](https://github.com/suncaleb1/self-llm/assets/155936975/c5568fe4-ae2a-4679-b795-f3fe17458310)
也可以使用python中的requests库进行调用,新建api-requests.py文件,写入如下代码:
```python
import requests
import json
def get_completion(prompt):
headers = {'Content-Type': 'application/json'}
data = {"prompt": prompt, "history": []}
response = requests.post(url='http://127.0.0.1:6006', headers=headers, data=json.dumps(data))
return response.json()['response']
if __name__ == '__main__':
print(get_completion('你是谁呀?'))
```
新开一个终端,输入如下指令
```python
cd /root/autodl-tmp
python api-requests.py
```
得到的返回值及结果展示如下
```python
{
'response': '嗨,你好,我叫苏梦远。(微笑着向对方走去)',
'history': [['你是谁呀?', '嗨,你好,我叫苏梦远。(微笑着向对方走去)']],
'status': 200,
'time': '2024-03-05 22:44:35'
}
```
![image](https://github.com/suncaleb1/self-llm/assets/155936975/f14d739e-addf-4b1b-bcf3-da4d714130fe)
@@ -0,0 +1,96 @@
# CharacterGLM-6B-chat
## 环境准备
在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8
![image](https://github.com/suncaleb1/self-llm/assets/155936975/0dddbee9-df80-4033-9568-185ea585f261)
接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下载和运行demo。
pip换源和安装依赖包
```python
# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install modelscope
pip install transformers
```
## 模型下载
使用 modelscope 中的snapshot_download函数下载模型,第一个参数为模型名称,参数cache_dir为模型的下载路径。
在 /root/autodl-tmp 路径下新建 download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python /root/autodl-tmp/download.py执行下载,模型大小为 12 GB,下载模型大概需要 10~15 分钟
```python
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('THUCoAI/CharacterGLM-6B', cache_dir='/root/autodl-tmp', revision='master')
```
## 代码准备
首先clone代码,打开autodl平台自带的学术镜像加速。学术镜像加速详细使用请看:
https://www.autodl.com/docs/network_turbo/
```python
source /etc/network_turbo
```
然后切换路径, clone代码.
```python
cd /root/autodl-tmp
git clone https://github.com/thu-coai/CharacterGLM-6B
```
## demo运行
修改代码路径,将 /root/autodl-tmp/CharacterGLM-6B/basic_demo/web_demo_streamlit.py中第20行的模型更换为本地的/root/autodl-tmp/THUCoAI/CharacterGLM-6B
![image](https://github.com/suncaleb1/self-llm/assets/155936975/1edc97a2-3d6e-43e3-b176-644b756b615f)
修改requirements.txt文件,将其中的torch删掉,环境中已经有了torch,不需要再安装。然后执行下面的命令:
```python
cd /root/autodl-tmp/CharacterGLM-6B
pip install -r requirements.txt
```
在终端运行以下命令即可启动推理服务,尽量cd到basic_demo文件夹下,防止找不到character.json文件
```python
cd /root/autodl-tmp/CharacterGLM-6B/basic_demo
streamlit run ./web_demo2.py --server.address 127.0.0.1 --server.port 6006
```
![image](https://github.com/suncaleb1/self-llm/assets/155936975/2fff8bd4-6d4b-449f-81ee-dc9e42b8ceb8)
在将 autodl 的端口映射到本地的 http://localhost:6006 后,即可看到demo界面。具体映射步骤参考文档General-Setting文件夹下/02-AutoDL开放端口.md文档。
在浏览器打开 http://localhost:6006 界面,模型加载,即可使用,如下图所示。
![image](https://github.com/suncaleb1/self-llm/assets/155936975/ac7a9887-4628-4539-9297-caccfb523530)
## 命令行运行
修改代码路径,将 /root/autodl-tmp/CharacterGLM-6B/basic_demo/cli_demo.py中的模型路径更换为本地的/root/autodl-tmp/THUCoAI/CharacterGLM-6B
在终端运行以下命令即可启动推理服务
```python
cd /root/autodl-tmp/CharacterGLM-6B/basic_demo
python ./cli_demo.py
```
![image](https://github.com/suncaleb1/self-llm/assets/155936975/1eb29dd5-8bae-458f-908f-f7388ae248c0)
@@ -0,0 +1,195 @@
# 04-CharacterGLM-6B-Chat Lora微调
## 概述
本文简要介绍如何基于transformers、peft等框架,对CharacterGLM-6B-chat模型进行Lora微调。Lora原理可参考博客:[知乎|深入浅出Lora](https://zhuanlan.zhihu.com/p/650197598)
本文代码未使用分布式框架,微调 ChatGLM3-6B-Chat 模型至少需要 21G 及以上的显存,且需要修改脚本文件中的模型路径和数据集路径。
## 环境配置
在完成基本环境配置和本地模型部署的情况下,还需要安装一些第三方库,可以使用如下命令:
```python
pip install transformers==4.37.2
pip install peft==0.4.0.dev0
pip install datasets==2.10.1
pip install accelerate==0.21.0
```
在本节内容中,将微调数据集放置在根目录[/dataset](https://github.com/datawhalechina/self-llm/blob/master/dataset/huanhuan.json)。
## 指令集构建
LLM微调一般指指令微调过程。所谓指令微调,是说我们使用的微调数据形如:
```python
{
"instruction":"回答用户以下问题,直接给出结果。"
"input":"中国第一个诺贝尔奖得主是谁?"
"output":"莫言"
}
```
其中instruction是用户指令,告知模型需要完成的任务;input是用户输入,是完成用户指令所必需的输入内容;output是模型应该给出的输出。
即我们的核心训练目标是让模型具有理解并遵循用户指令的能力。因此,在指令集构建时,我们应针对我们的目标任务,针对性构建任务指令集。在本文我们使用由笔者合作开源的[Chat-甄嬛项目](https://github.com/KMnO4-zx/huanhuan-chat)作为示例,我们的目标是构建一个能够模拟甄嬛对话风格的个性化LLM,因此我们构建的指令形如:
```python
{
"instruction": "",
"input":"你是谁?",
"output":"家父是大理寺少卿甄远道。"
}
```
我们构造的全部指令数据集在根目录下。
## QA和Instruction的区别和联系
QA是指一问一答的形式,通常是用户提问,模型给出回答。而instruction则源自于Prompt Engineering,将问题拆分成两个部分:Instruction用于描述任务,Input用于描述待处理的对象。
问答(QA)格式的训练数据通常用于训练模型执行具体任务。例如,对于问题“请解释INFJ和ENTP两种MBTI性格之间的区别”
*问答(QA)格式:
```python
指令(instruction)
输入(input)INFJ和ENTP这两种MBTI性格之间的区别是什么
```
*指令(Instruction)格式:
```python
指令(Instruction):请解释下面两种MBTI性格的区别
输入(input):INFJ和ENTP
```
## 数据格式化
Lora训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,我们一般需要将输入文本编码为input_ids,将输出文本编码为labels,编码之后的结果都是多维向量。我们首先定义一个与处理函数,这个函数用于对每一个样本,编码其输入,输出文本并返回一个编码后的字典:
```python
def process_func(example):
MAX_LENGTH = 512
input_ids, labels = [], []
prompt = tokenizer.encode("用户:\n"+"现在你要扮演皇帝身边的女人--甄嬛。", add_special_tokens=False)
instruction_ = tokenizer.encode("\n".join([example["instruction"], example["input"]]).strip(), add_special_tokens=False,max_length=512)
instruction = tokenizer.encode(prompt + instruction_)
response = tokenizer.encode("CharacterGLM-6B:\n:" + example["output"], add_special_tokens=False)
input_ids = instruction + response + [tokenizer.eos_token_id]
labels = [tokenizer.pad_token_id] * len(instruction) + response + [tokenizer.eos_token_id]
pad_len = MAX_LENGTH - len(input_ids)
# print()
input_ids += [tokenizer.pad_token_id] * pad_len
labels += [tokenizer.pad_token_id] * pad_len
labels = [(l if l != tokenizer.pad_token_id else -100) for l in labels]
return {
"input_ids": input_ids,
"labels": labels
}
```
经过格式化的数据,也就是送入模型的每一条数据,都是一个字典,包含了input_ids、labels两个键值对,其中input_ids是输入文本的编码,labels是输出文本的编码。
## 加载tokenizer和半精度模型
模型以版精度形式加载,如果显卡比较新,可以用torch.bfloat形式加载,对于自定义的模型一定要指定trust_remote_code参数为True
```python
tokenizer=AutoTokenizer.from_pretrained('/root/autodl-tmp/THUCoAI/CharacterGLM-6B',use_fast=False,trust_remote_code=True)
model=AutoModelForCausalLM.from_pretrained('/root/autodl-tmp/THUCoAI/CharacterGLM-6B',trust_remote_code=True,torch_dtype=torch.half,device_map="auto")
```
## 定义LoraConfig
LoraConfig这个类中可以设置很多参数,部分参数展示如下:
task_type:模型类型
target——modules:需要训练的模型层的名字,主要就是attention部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。
r:lora的秩
lora_alpha:Lora alpha
modules_to_save:指定的是除了拆成lora的模块,其它的模块可以完整的指定训练
Lora的所方式lora_alpha/r,在这个LoraConfig中缩放就是4倍。这个缩放的本质并没有改变Lora的参数量大小,本质在于将里面的参数数值做广播乘法,进行线性的缩放。
```python
config=LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["query_key_value"],
inference_mode=False,
r=8,
lora_alpha=32,
lora_dropout=0.1
)
```
## 自定义TraininArguments参数
TrainingArguments这个类的源码也介绍了每个参数的具体作用,常用的参数如下:
output_dir:模型的输出路径
per_device_train_batch_size:batch_size
gradient_accumulation_steps:梯度累加,如果显存比较小,可以把batch_size设置小一点,梯度累积增大一点
logging_steps:多少步,输出一次log
num_train_epochs:顾名思义epoch
gradient_chechpointing:梯度检查,这个一旦开启,模型就必须执行
model.enable_input_require_grads()
```python
data_collator=DataCollatorForSeq2Seq(
tokenizer,
model=model,
label_pad_token_id=-100,
pad_to_multiple_of=None,
padding=False
)
args=TrainingArguments(
output_dir="./output/CharacterGLM",
per_device_train_batch_size=4,
gradient_accumulation_steps=2,
logging_steps=10,
num_train_epochs=3,
gradient_checkpointing=True,
save_steps=100,
learning_rate=1e-4,
)
```
## 使用Trainer训练
把model放进去,把上面设置的参数放进去,数据集放进去,开始训练
```python
trainer=Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=data_collator,
)
trainer.train()
```
## 模型推理
```python
model = model.cuda()
ipt = tokenizer("用户:{}\n{}".format("现在你要扮演皇帝身边的女人--甄嬛。你是谁?", "").strip() + "characterGLM-6B:\n", return_tensors="pt").to(model.device)
tokenizer.decode(model.generate(**ipt, max_length=128, do_sample=True)[0], skip_special_tokens=True)
```
## 从新加载
通过PEFT所微调的模型,都可以使用下面的方法进行重新加载,并推理:
加载源model与tokenizer
使用PeftModel合并源model与PEFT微调后的参数
```python
from peft import Peftmodel
model=AutoModelForCausalLM.from_pretrained("/root/autodl-tmp/THUCoAI/CharacterGLM-6B",trust_remote_code=True,low_cpu_mem_usage=True)
tokenizer=AutoTokenizer.from_pretrained("root/autodl-tmp/THUCoAI/CharacterGLM-6B",use_fast=False,trust_remote_code=True)
p_model=PeftModel.from_pretrained(model,model_id="./output/CharatcerGLM/checkpoint-1000/")
ipt = tokenizer("用户:{}\n{}".format("现在你要扮演皇帝身边的女人--甄嬛。你是谁?", "").strip() + "characterGLM-6B:\n", return_tensors="pt").to(model.device)
tokenizer.decode(p_model.generate(**ipt,max_length=128,do_sample=True)[0],skip_special_tokens=True)
```

Some files were not shown because too many files have changed in this diff Show More