From 3b0654daad8fbe3f36d19099aac756736e25e40d Mon Sep 17 00:00:00 2001 From: guanjihuan Date: Sat, 27 Jan 2024 03:45:36 +0800 Subject: [PATCH] update --- README.md | 140 +++ 开源模型 ChatGLM/ChatGLM.py | 105 ++ 开源模型 ChatGLM/requirements.txt | 33 + 开源模型 InternLM/InternLM.py | 112 ++ 开源模型 InternLM/tools/README.md | 111 ++ 开源模型 InternLM/tools/README_EN.md | 109 ++ 开源模型 InternLM/tools/V7_sft.model | Bin 0 -> 1658691 bytes 开源模型 InternLM/tools/alpaca_tokenizer.py | 164 +++ 开源模型 InternLM/tools/pal_inference.py | 320 ++++++ 开源模型 InternLM/tools/tokenizer.py | 142 +++ .../tools/transformers/README-zh-Hans.md | 25 + .../tools/transformers/README.md | 23 + .../tools/transformers/configuration_internlm.py | 120 +++ .../tools/transformers/convert2hf.py | 175 +++ .../tools/transformers/interface.py | 137 +++ .../tools/transformers/intern_moss_example.py | 69 ++ .../tools/transformers/internlm_sft_on_moss.py | 105 ++ .../tools/transformers/modeling_internlm.py | 998 ++++++++++++++++++ .../tools/transformers/tokenization_internlm.py | 242 +++++ 开源模型 Qwen/Qwen.py | 109 ++ 开源模型 Qwen/requirements.txt | 6 + 智谱 - ChatGLM Turbo API/ChatGLM_Turbo.py | 91 ++ 讯飞 - 星火大模型 API/星火大模型.py | 283 +++++ 23 files changed, 3619 insertions(+) create mode 100644 README.md create mode 100644 开源模型 ChatGLM/ChatGLM.py create mode 100644 开源模型 ChatGLM/requirements.txt create mode 100644 开源模型 InternLM/InternLM.py create mode 100644 开源模型 InternLM/tools/README.md create mode 100644 开源模型 InternLM/tools/README_EN.md create mode 100644 开源模型 InternLM/tools/V7_sft.model create mode 100644 开源模型 InternLM/tools/alpaca_tokenizer.py create mode 100644 开源模型 InternLM/tools/pal_inference.py create mode 100644 开源模型 InternLM/tools/tokenizer.py create mode 100644 开源模型 InternLM/tools/transformers/README-zh-Hans.md create mode 100644 开源模型 InternLM/tools/transformers/README.md create mode 100644 开源模型 InternLM/tools/transformers/configuration_internlm.py create mode 100644 开源模型 InternLM/tools/transformers/convert2hf.py create mode 100644 开源模型 InternLM/tools/transformers/interface.py create mode 100644 开源模型 InternLM/tools/transformers/intern_moss_example.py create mode 100644 开源模型 InternLM/tools/transformers/internlm_sft_on_moss.py create mode 100644 开源模型 InternLM/tools/transformers/modeling_internlm.py create mode 100644 开源模型 InternLM/tools/transformers/tokenization_internlm.py create mode 100644 开源模型 Qwen/Qwen.py create mode 100644 开源模型 Qwen/requirements.txt create mode 100644 智谱 - ChatGLM Turbo API/ChatGLM_Turbo.py create mode 100644 讯飞 - 星火大模型 API/星火大模型.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..b08bb6b --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +## chat.guanjihuan.com + +这里把 https://chat.guanjihuan.com 的主要实现代码进行开源,主要参考开源大模型的 GitHub 或 HuggingFace 主页、第三方模型的 API 官网,以及 HuggingFace 和 Pytorch 的文档等。 + +此外,还有很多开源大模型,这里只测试了几个,感兴趣的可以自行测试,通常 16G 显存的显卡可以完整加载 7B 左右的模型(70亿参数)以及量化地加载 14B 左右的模型(14亿参数),更大参数空间的模型的运行需要更大显存的显卡。 + +运行代码需要安装 Python 环境,可以选择安装 Anaconda:https://www.anaconda.com 。如果是本地 GPU 运行模型,还需要 Nvidia 显卡。特别说明:本篇提供了在本地 CPU 加载 ChatGLM 模型的代码,没有独立显卡的可以考虑这个,只是对话速度会比较慢。 + +Web 框架是使用 Streamlit:https://streamlit.io、https://github.com/streamlit/streamlit 。 + +Streamlit 的安装: + +``` +pip install streamlit +``` + +运行命令: + +``` +streamlit run web_demo.py +``` + +或 + +``` +python -m streamlit run web_demo.py +``` + +如果是在公网IP下访问,并指定8501端口和黑色主题,那么运行命令为: + +``` +streamlit run web_demo.py --theme.base dark --server.port 8501 --server.address 0.0.0.0 +``` + +为了防止一些不必要的报错,可以更新一下操作系统的显卡驱动并重启: + +``` +sudo apt-get update + +sudo apt-get install ubuntu-drivers-common + +sudo ubuntu-drivers autoinstall +``` + +此外,可以更新一下 Pytorch(https://pytorch.org/get-started/locally/),也可以防止一些报错: + +``` +conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia +``` + +### 一、本地运行开源模型 + + +#### 1. 开源模型 ChatGLM + +ChatGLM3-6B 主页:https://github.com/THUDM/ChatGLM3 。 安装该模型依赖的环境: + +``` +pip install -r requirements.txt +``` + +模型文件下载:https://huggingface.co/THUDM/chatglm3-6b-32k + +显存/内存要求:量化加载大概要 6G 显存;默认加载大概需要 13G 显存;CPU加载大概需要 25G 内存。 + +运行: + +``` +python -m streamlit run ./ChatGLM3.py --theme.base dark --server.port 8501 +``` + +如果量化加载时 bitsandbytes 报错,那么安装该软件包:pip install bitsandbytes + +#### 2. 开源模型 Qwen + +Qwen 主页:https://github.com/QwenLM/Qwen 。 安装该模型依赖的环境: + +``` +pip install -r requirements.txt +``` + +Qwen-7B-Chat-Int4 模型文件下载:https://huggingface.co/Qwen/Qwen-7B-Chat-Int4 + +Qwen-14B-Chat-Int4 模型文件下载:https://huggingface.co/Qwen/Qwen-14B-Chat-Int4 + +显存要求:Qwen-7B-Chat-Int4 大概需要 8G 显存;Qwen-14B-Chat-Int4 大概需要 12G 显存。 + +运行: + +``` +python -m streamlit run ./Qwen.py --theme.base dark --server.port 8501 +``` + +此外,如果运行有报错,可能还需要安装: + +``` +pip install optimum +pip install auto-gptq +pip install --upgrade s3fs aiobotocore botocore +``` + +#### 3. 开源模型 InternLM + +InternLM 主页:https://github.com/InternLM/InternLM 。运行代码时,需要调用其中的 tools 文件夹。 + +internlm-chat-7b 模型文件下载:https://huggingface.co/internlm/internlm-chat-7b + +internlm2-chat-7b 模型文件下载:https://huggingface.co/internlm/internlm2-chat-7b + +目前提供的代码是加载 internlm-chat-7b 模型,加载 internlm2-chat-7b 模型的未测试。 + +显存要求:大概需要 7B 的显存。 + +运行: + +``` +python -m streamlit run ./InternLM.py --theme.base dark --server.port 8501 +``` + +### 二、使用第三方模型 API + +#### 1. 智谱 - ChatGLM_Turbo + +智谱 - ChatGLM Turbo 的 API key 获取(收费,可免费试用):https://maas.aminer.cn + +运行: + +``` +python -m streamlit run ./ChatGLM_Turbo.py --theme.base dark --server.port 8501 +``` + +#### 2. 讯飞 - 星火大模型 + +讯飞 - 星火大模型的 API key 获取(收费,可免费试用):https://xinghuo.xfyun.cn + +运行: + +``` +python -m streamlit run ./星火大模型.py --theme.base dark --server.port 8501 +``` \ No newline at end of file diff --git a/开源模型 ChatGLM/ChatGLM.py b/开源模型 ChatGLM/ChatGLM.py new file mode 100644 index 0000000..4087b33 --- /dev/null +++ b/开源模型 ChatGLM/ChatGLM.py @@ -0,0 +1,105 @@ +""" +This code is supported by the website: https://www.guanjihuan.com +The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38502 +""" + +import streamlit as st +st.set_page_config( + page_title="Chat", + layout='wide' +) + +choose_load_method = 1 # 选择加载模型的方式 + +if choose_load_method == 0: + # 默认加载(需要13G显存) + @st.cache_resource + def load_model_chatglm3(): + from transformers import AutoModel, AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm3-6b-32k", trust_remote_code=True) + model = AutoModel.from_pretrained("THUDM/chatglm3-6b-32k",trust_remote_code=True).half().cuda() + model = model.eval() + return model, tokenizer + model_chatglm3, tokenizer_chatglm3 = load_model_chatglm3() + +elif choose_load_method == 1: + # 量化加载(需要6G显存) + @st.cache_resource + def load_model_chatglm3(): + from transformers import AutoTokenizer, BitsAndBytesConfig, AutoModelForCausalLM + tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm3-6b-32k", trust_remote_code=True) + nf4_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_quant_type="nf4", + ) + model = AutoModelForCausalLM.from_pretrained("THUDM/chatglm3-6b-32k", trust_remote_code=True, quantization_config=nf4_config) + model = model.eval() + return model, tokenizer + model_chatglm3, tokenizer_chatglm3 = load_model_chatglm3() + +elif choose_load_method == 2: + # 在CPU上加载(需要25G内存,对话速度会比较慢) + @st.cache_resource + def load_model_chatglm3(): + from transformers import AutoModel, AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm3-6b-32k", trust_remote_code=True) + model = AutoModel.from_pretrained("THUDM/chatglm3-6b-32k",trust_remote_code=True).float() + model = model.eval() + return model, tokenizer + model_chatglm3, tokenizer_chatglm3 = load_model_chatglm3() + +with st.sidebar: + with st.expander('参数', expanded=True): + max_length = 409600 + top_p = st.slider('top_p', 0.01, 1.0, step=0.01, value=0.8, key='top_p_session') + temperature = st.slider('temperature', 0.51, 1.0, step=0.01, value=0.8, key='temperature_session') + def reset_parameter(): + st.session_state['top_p_session'] = 0.8 + st.session_state['temperature_session'] = 0.8 + reset_parameter_button = st.button('重置参数', on_click=reset_parameter) + +prompt = st.chat_input("在这里输入您的命令") + +def chat_response_chatglm3(prompt): + history, past_key_values = st.session_state.history_ChatGLM3, st.session_state.past_key_values_ChatGLM3 + for response, history, past_key_values in model_chatglm3.stream_chat(tokenizer_chatglm3, prompt, history, + past_key_values=past_key_values, + max_length=max_length, top_p=top_p, + temperature=temperature, + return_past_key_values=True): + message_placeholder_chatglm3.markdown(response) + if stop_button: + break + st.session_state.ai_response.append({"role": "robot", "content": response, "avatar": "assistant"}) + st.session_state.history_ChatGLM3 = history + st.session_state.past_key_values_ChatGLM3 = past_key_values + return response + +def clear_all(): + st.session_state.history_ChatGLM3 = [] + st.session_state.past_key_values_ChatGLM3 = None + st.session_state.ai_response = [] + +if 'history_ChatGLM3' not in st.session_state: + st.session_state.history_ChatGLM3 = [] +if 'past_key_values_ChatGLM3' not in st.session_state: + st.session_state.past_key_values_ChatGLM3 = None +if 'ai_response' not in st.session_state: + st.session_state.ai_response = [] + +for ai_response in st.session_state.ai_response: + with st.chat_message(ai_response["role"], avatar=ai_response.get("avatar")): + st.markdown(ai_response["content"]) + +prompt_placeholder = st.chat_message("user", avatar='user') +with st.chat_message("robot", avatar="assistant"): + message_placeholder_chatglm3 = st.empty() + +if prompt: + prompt_placeholder.markdown(prompt) + st.session_state.ai_response.append({"role": "user", "content": prompt, "avatar": 'user'}) + stop = st.empty() + stop_button = stop.button('停止', key='break_response') + chat_response_chatglm3(prompt) + stop.empty() +button_clear = st.button("清空", on_click=clear_all, key='clear') \ No newline at end of file diff --git a/开源模型 ChatGLM/requirements.txt b/开源模型 ChatGLM/requirements.txt new file mode 100644 index 0000000..066db69 --- /dev/null +++ b/开源模型 ChatGLM/requirements.txt @@ -0,0 +1,33 @@ +# basic requirements + +protobuf>=4.25.2 +transformers>=4.36.2 +tokenizers>=0.15.0 +cpm_kernels>=1.0.11 +torch>=2.1.0 +gradio>=4.14.0 +sentencepiece>=0.1.99 +sentence_transformers>=2.2.2 +accelerate>=0.26.1 +streamlit>=1.30.0 +fastapi>=0.109.0 +loguru~=0.7.2 +mdtex2html>=1.2.0 +latex2mathml>=3.77.0 + +# for openai demo + +openai>=1.7.2 +zhipuai>=2.0.0 + +pydantic>=2.5.3 +sse-starlette>=1.8.2 +uvicorn>=0.25.0 +timm>=0.9.12 +tiktoken>=0.5.2 + +# for langchain demo + +langchain>=0.1.0 +langchainhub>=0.1.14 +arxiv>=2.1.0 \ No newline at end of file diff --git a/开源模型 InternLM/InternLM.py b/开源模型 InternLM/InternLM.py new file mode 100644 index 0000000..b56c7c3 --- /dev/null +++ b/开源模型 InternLM/InternLM.py @@ -0,0 +1,112 @@ +""" +This code is supported by the website: https://www.guanjihuan.com +The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38502 +""" + +import streamlit as st +st.set_page_config( + page_title="Chat", + layout='wide' +) + +@st.cache_resource +def load_model_internlm_7B(): + # internlm(大概需要 7B 显存) + import torch + from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig + nf4_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_quant_type="nf4", + ) + model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True, quantization_config=nf4_config) + tokenizer = AutoTokenizer.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True, torch_dtype=torch.bfloat16) + model = model.eval() + return model, tokenizer +model_internlm_7B, tokenizer_internlm_7B = load_model_internlm_7B() + +with st.sidebar: + with st.expander('参数', expanded=True): + max_length = 409600 + top_p = st.slider('top_p', 0.01, 1.0, step=0.01, value=0.8, key='top_p_session') + temperature = st.slider('temperature', 0.51, 1.0, step=0.01, value=0.8, key='temperature_session') + def reset_parameter(): + st.session_state['top_p_session'] = 0.8 + st.session_state['temperature_session'] = 0.8 + reset_parameter_button = st.button('重置参数', on_click=reset_parameter) + +prompt = st.chat_input("在这里输入您的命令") + +from tools.transformers.interface import GenerationConfig, generate_interactive + +def prepare_generation_config(): + generation_config = GenerationConfig(max_length=max_length, top_p=top_p, temperature=temperature) + return generation_config + +def combine_history(prompt, messages): + total_prompt = "" + for message in messages: + cur_content = message["content"] + if message["role"] == "user": + cur_prompt = user_prompt.replace("{user}", cur_content) + elif message["role"] == "robot": + cur_prompt = robot_prompt.replace("{robot}", cur_content) + else: + raise RuntimeError + total_prompt += cur_prompt + total_prompt = total_prompt + cur_query_prompt.replace("{user}", prompt) + return total_prompt + +user_prompt = "<|User|>:{user}\n" +robot_prompt = "<|Bot|>:{robot}\n" +cur_query_prompt = "<|User|>:{user}\n<|Bot|>:" +generation_config = prepare_generation_config() + +if "messages_internlm_7B" not in st.session_state: + st.session_state.messages_internlm_7B = [] + +from dataclasses import asdict + +def chat_response_internlm_7B(prompt): + real_prompt = combine_history(prompt, messages = st.session_state.messages_internlm_7B) + st.session_state.messages_internlm_7B.append({"role": "user", "content": prompt, "avatar": 'user'}) + for cur_response in generate_interactive( + model=model_internlm_7B, + tokenizer=tokenizer_internlm_7B, + prompt=real_prompt, + additional_eos_token_id=103028, + **asdict(generation_config), + ): + message_placeholder_internlm_7B.markdown(cur_response + "▌") + if stop_button: + break + message_placeholder_internlm_7B.markdown(cur_response) + st.session_state.messages_internlm_7B.append({"role": "robot", "content": cur_response, "avatar": "assistant"}) + st.session_state.ai_response.append({"role": "robot", "content": cur_response, "avatar": "assistant"}) + return cur_response + + +def clear_all(): + st.session_state.messages_internlm_7B = [] + st.session_state.ai_response = [] + +if 'messages_internlm_7B' not in st.session_state: + st.session_state.messages_internlm_7B = [] +if 'ai_response' not in st.session_state: + st.session_state.ai_response = [] + +for ai_response in st.session_state.ai_response: + with st.chat_message(ai_response["role"], avatar=ai_response.get("avatar")): + st.markdown(ai_response["content"]) + +prompt_placeholder = st.chat_message("user", avatar='user') +with st.chat_message("robot", avatar="assistant"): + message_placeholder_internlm_7B = st.empty() + +if prompt: + prompt_placeholder.markdown(prompt) + st.session_state.ai_response.append({"role": "user", "content": prompt, "avatar": 'user'}) + stop = st.empty() + stop_button = stop.button('停止', key='break_response') + chat_response_internlm_7B(prompt) + stop.empty() +button_clear = st.button("清空", on_click=clear_all, key='clear') \ No newline at end of file diff --git a/开源模型 InternLM/tools/README.md b/开源模型 InternLM/tools/README.md new file mode 100644 index 0000000..0c78a56 --- /dev/null +++ b/开源模型 InternLM/tools/README.md @@ -0,0 +1,111 @@ +本目录提供辅助模型训练的一些工具,文件结构如下所示: + +```bash +├── transformers # 适配hugging face的transformers的一些工具 +│ ├── configuration_internlm.py # config适配工具 +│ ├── modeling_internlm.py # model适配工具 +│ ├── tokenization_internlm.py # tokenizer适配工具 +│ └── convert2hf.py # 模型适配hugging face工具 +└── tokenizer.py # 将原始数据转换成bin和meta文件的工具 +``` + +# tokenizer.py + +生成原始数据的`bin`和`meta`文件需要使用`tokenizer`,我们通过在`tools/tokenizer.py`中指定模型参数路径的方式来导入tokenizer模型。目前我们提供了`V7_sft.model`来生成tokens。若想使用不同的模型,可直接修改`tokernizer.py`中的模型参数路径。 + +可以运行以下命令生成原始数据对应的`bin`和`meta`文件,其中参数`text_input_path`表示原始文本数据路径,目前支持`txt`、`json`和`jsonl`三种输入格式,`bin_output_path`表示生成的`bin`文件的保存路径。 + +```bash +$ python tools/tokenizer.py --text_input_path your_input_text_path --bin_output_path your_output_bin_path +``` + +下面是一个数据处理的例子: + +给定一个包含原始数据集的文件`raw_data.txt`,原始数据集如下所示: + +```bash +感恩生活中的每一个细节,才能真正体会到幸福的滋味。 +梦想是人生的动力源泉,努力追逐,才能实现自己的目标。 +学会宽容和理解,才能建立真正和谐的人际关系。 +``` + +可以通过运行以下命令来生成`bin`和`meta`文件: +```bash +$ python tools/tokenizer.py --text_input_path raw_data.txt --bin_output_path cn/output.bin +``` + +需要注意的是,生成的`bin`文件需要保存在`cn`或者`en`或者`code`或者`ja`或者`ar`或者`kaoshi`这五个目录下,以区分数据集的类型。 + +其中,`cn`表示中文数据集;`en`表示英文数据集;`code`表示代码数据集;`ja`表示日语数据集;`ar`表示阿拉伯语数据集;`kaoshi`表示考试数据集。 + +生成的bin文件的格式如下: + +```python +{"tokens": [73075, 75302, 69522, 69022, 98899, 67713, 68015, 81269, 74637, 75445, 99157]} +{"tokens": [69469, 60355, 73026, 68524, 60846, 61844, 98899, 67775, 79241, 98899, 67713, 67800, 67453, 67838, 99157]} +{"tokens": [68057, 79017, 60378, 68014, 98899, 67713, 67990, 68015, 70381, 67428, 61003, 67622, 99157]} +``` + +`bin`文件中的每一行均对应原始数据集中的每一个句子,表示每个句子的`token`(下文将用sequence指定)。 + +生成的`meta`文件的格式如下: + +```bash +(0, 11), (90, 15), (208, 13) +``` + +在`meta`文件中,每个元组对应着`bin`文件中每一个`sequence`的元信息。其中,元组的第一个元素表示每个`sequence`在所有`sequence`中的`starting index`,第二个元素表示每个`sequence`中有多少个`tokens`。 + +例如,对于第一个`sequence`,`starting index`为 0,有 11 个`tokens`;对于第二个`sequence`,由于第一个`sequence`转换为`string`后的长度为`89`,因此它的`starting index`为 90,有 15 个`tokens`。 + +`json`和`jsonl`类型的文件的`bin`和`meta`文件格式和`txt`一致,此处不再赘叙。 + +# pal_inference.py + +在 [GSM8K](https://huggingface.co/datasets/gsm8k) 数据集上使用 [PAL](https://github.com/reasoning-machines/pal) 范式推理,使模型编写代码并通过 Python 解释器执行来解决数学问题。其用法如下: + +```python +# 用法: +python pal_inference.py [--dataset ] [--max_length ] [--top_p ] [--eoh ] [--eoa ] [--eos ] [--temperature ] [--time_out