From b8609cad1f5ba49834a3eef9110075d204dfae10 Mon Sep 17 00:00:00 2001 From: HongCheng Date: Sat, 20 Apr 2024 21:14:25 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8E=9F=E5=A7=8B?= =?UTF-8?q?=E7=9A=84llama3=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llama3_8b_512_qlora_alpaca_e3.py | 219 ------------------ xtuner_config/llama3_8b_8k_qlora_alpaca_e3.py | 219 ------------------ 2 files changed, 438 deletions(-) delete mode 100644 xtuner_config/llama3_8b_512_qlora_alpaca_e3.py delete mode 100644 xtuner_config/llama3_8b_8k_qlora_alpaca_e3.py diff --git a/xtuner_config/llama3_8b_512_qlora_alpaca_e3.py b/xtuner_config/llama3_8b_512_qlora_alpaca_e3.py deleted file mode 100644 index 2fde395..0000000 --- a/xtuner_config/llama3_8b_512_qlora_alpaca_e3.py +++ /dev/null @@ -1,219 +0,0 @@ -# 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 alpaca_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.parallel.sequence import SequenceParallelSampler -from xtuner.utils import PROMPT_TEMPLATE, SYSTEM_TEMPLATE - -####################################################################### -# PART 1 Settings # -####################################################################### -# Model -pretrained_model_name_or_path = 'meta-llama/Meta-Llama-3-8B-Instruct' -use_varlen_attn = False - -# Data -alpaca_en_path = 'tatsu-lab/alpaca' -prompt_template = PROMPT_TEMPLATE.llama3_chat -max_length = 512 -pack_to_max_length = True - -# parallel -sequence_parallel_size = 1 - -# Scheduler & Optimizer -batch_size = 1 # per_device -accumulative_counts = 16 -accumulative_counts *= sequence_parallel_size -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 = 500 -save_total_limit = 2 # Maximum checkpoints to keep (-1 means unlimited) - -# Evaluate the generation performance during the training -evaluation_freq = 500 -SYSTEM = SYSTEM_TEMPLATE.alpaca -evaluation_inputs = [ - '请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai' -] - -####################################################################### -# 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=16, - lora_alpha=16, - lora_dropout=0.1, - bias='none', - task_type='CAUSAL_LM')) - -####################################################################### -# PART 3 Dataset & Dataloader # -####################################################################### -alpaca_en = dict( - type=process_hf_dataset, - dataset=dict(type=load_dataset, path=alpaca_en_path), - tokenizer=tokenizer, - max_length=max_length, - dataset_map_fn=alpaca_map_fn, - 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) - -sampler = SequenceParallelSampler \ - if sequence_parallel_size > 1 else DefaultSampler -train_dataloader = dict( - batch_size=batch_size, - num_workers=dataloader_num_workers, - dataset=alpaca_en, - sampler=dict(type=sampler, 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) diff --git a/xtuner_config/llama3_8b_8k_qlora_alpaca_e3.py b/xtuner_config/llama3_8b_8k_qlora_alpaca_e3.py deleted file mode 100644 index 9d65f5f..0000000 --- a/xtuner_config/llama3_8b_8k_qlora_alpaca_e3.py +++ /dev/null @@ -1,219 +0,0 @@ -# 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 alpaca_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.parallel.sequence import SequenceParallelSampler -from xtuner.utils import PROMPT_TEMPLATE, SYSTEM_TEMPLATE - -####################################################################### -# PART 1 Settings # -####################################################################### -# Model -pretrained_model_name_or_path = 'meta-llama/Meta-Llama-3-8B-Instruct' -use_varlen_attn = False - -# Data -alpaca_en_path = 'tatsu-lab/alpaca' -prompt_template = PROMPT_TEMPLATE.llama3_chat -max_length = 8192 -pack_to_max_length = True - -# parallel -sequence_parallel_size = 1 - -# Scheduler & Optimizer -batch_size = 1 # per_device -accumulative_counts = 16 -accumulative_counts *= sequence_parallel_size -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 = 500 -save_total_limit = 2 # Maximum checkpoints to keep (-1 means unlimited) - -# Evaluate the generation performance during the training -evaluation_freq = 500 -SYSTEM = SYSTEM_TEMPLATE.alpaca -evaluation_inputs = [ - '请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai' -] - -####################################################################### -# 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=16, - lora_alpha=16, - lora_dropout=0.1, - bias='none', - task_type='CAUSAL_LM')) - -####################################################################### -# PART 3 Dataset & Dataloader # -####################################################################### -alpaca_en = dict( - type=process_hf_dataset, - dataset=dict(type=load_dataset, path=alpaca_en_path), - tokenizer=tokenizer, - max_length=max_length, - dataset_map_fn=alpaca_map_fn, - 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) - -sampler = SequenceParallelSampler \ - if sequence_parallel_size > 1 else DefaultSampler -train_dataloader = dict( - batch_size=batch_size, - num_workers=dataloader_num_workers, - dataset=alpaca_en, - sampler=dict(type=sampler, 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) From ac4a66cf34b47d5ac8d908276c82debc26aa0560 Mon Sep 17 00:00:00 2001 From: HongCheng Date: Sun, 21 Apr 2024 11:16:17 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E6=9B=B4=E6=96=B0git-lfs=20conda=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/README_Model_Uploading.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/README_Model_Uploading.md b/scripts/README_Model_Uploading.md index 36723e5..6707075 100644 --- a/scripts/README_Model_Uploading.md +++ b/scripts/README_Model_Uploading.md @@ -72,8 +72,12 @@ OpenXLab浦源 内容平台 是面向 AI 研究员和开发者提供 AI 领域 ### 1. 安装git lfs ```bash -curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh -apt install git-lfs +# 更好的方法 +conda install git-lfs + +# 旧方法 +# curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh +# apt install git-lfs ``` ### 2. 配置git和lfs From a4413345c7e1c7f373ae8b97670b22f2640a4a14 Mon Sep 17 00:00:00 2001 From: HongCheng Date: Sun, 21 Apr 2024 11:24:50 +0900 Subject: [PATCH 3/5] cli_Llama3-8B-Instruct --- demo/cli_Llama3-8B-Instruct.py | 233 +++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 demo/cli_Llama3-8B-Instruct.py diff --git a/demo/cli_Llama3-8B-Instruct.py b/demo/cli_Llama3-8B-Instruct.py new file mode 100644 index 0000000..2d1c981 --- /dev/null +++ b/demo/cli_Llama3-8B-Instruct.py @@ -0,0 +1,233 @@ +from transformers import AutoTokenizer, AutoConfig, AddedToken, AutoModelForCausalLM, BitsAndBytesConfig +from peft import PeftModel +from dataclasses import dataclass +from typing import Dict +import torch +import copy + +import warnings + +warnings.filterwarnings("ignore") +warnings.filterwarnings("ignore", category=DeprecationWarning) + +## 定义聊天模板 +@dataclass +class Template: + template_name:str + system_format: str + user_format: str + assistant_format: str + system: str + stop_word: str + +template_dict: Dict[str, Template] = dict() + +def register_template(template_name, system_format, user_format, assistant_format, system, stop_word=None): + template_dict[template_name] = Template( + template_name=template_name, + system_format=system_format, + user_format=user_format, + assistant_format=assistant_format, + system=system, + stop_word=stop_word, + ) + +# 这里的系统提示词是训练时使用的,推理时可以自行尝试修改效果 +register_template( + template_name='llama3', + system_format='<|begin_of_text|>\n{content}\n\n\n<|eot_id|>', + user_format='<|start_header_id|>user<|end_header_id|>\n\n{content}<|eot_id|>', + assistant_format='<|start_header_id|>assistant<|end_header_id|>\n\n{content}\n', # \n\n{content}<|eot_id|>\n + system="你是心理健康助手EmoLLM, 由EmoLLM团队打造, 是一个研究过无数具有心理健康问题的病人与心理健康医生对话的心理专家, 在心理方面拥有广博的知识储备和丰富的研究咨询经验。你旨在通过专业心理咨询, 协助来访者完成心理诊断。请充分利用专业心理学知识与咨询技术, 一步步帮助来访者解决心理问题。", + stop_word='<|eot_id|>' +) + + +## 加载模型 +def load_model(model_name_or_path, load_in_4bit=False, adapter_name_or_path=None): + if load_in_4bit: + quantization_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_compute_dtype=torch.float16, + bnb_4bit_use_double_quant=True, + bnb_4bit_quant_type="nf4", + llm_int8_threshold=6.0, + llm_int8_has_fp16_weight=False, + ) + else: + quantization_config = None + + # 加载base model + model = AutoModelForCausalLM.from_pretrained( + model_name_or_path, + # load_in_4bit=load_in_4bit, + # # ValueError: You can't pass `load_in_4bit`or `load_in_8bit` as a kwarg when passing `quantization_config` argument at the same time. + trust_remote_code=True, + low_cpu_mem_usage=True, + torch_dtype=torch.float16, + device_map='auto', + quantization_config=quantization_config + ) + + # 加载adapter + if adapter_name_or_path is not None: + model = PeftModel.from_pretrained(model, adapter_name_or_path) + + return model + +## 加载tokenzier +def load_tokenizer(model_name_or_path): + tokenizer = AutoTokenizer.from_pretrained( + model_name_or_path, + trust_remote_code=True, + use_fast=False + ) + + if tokenizer.pad_token is None: + tokenizer.pad_token = tokenizer.eos_token + + return tokenizer + +## 构建prompt +def build_prompt(tokenizer, template, query, history, system=None): + template_name = template.template_name + system_format = template.system_format + user_format = template.user_format + assistant_format = template.assistant_format + system = system if system is not None else template.system + + history.append({"role": 'user', 'message': query}) + input_ids = [] + + # 添加系统信息 + if system_format is not None: + if system is not None: + system_text = system_format.format(content=system) + input_ids = tokenizer.encode(system_text, add_special_tokens=False) + # 拼接历史对话 + for item in history: + role, message = item['role'], item['message'] + if role == 'user': + message = user_format.format(content=message, stop_token=tokenizer.eos_token) + else: + message = assistant_format.format(content=message, stop_token=tokenizer.eos_token) + tokens = tokenizer.encode(message, add_special_tokens=False) + input_ids += tokens + input_ids = torch.tensor([input_ids], dtype=torch.long) + + return input_ids + + +def main(): + + # download model in openxlab + # download(model_repo='MrCat/Meta-Llama-3-8B-Instruct', + # output='MrCat/Meta-Llama-3-8B-Instruct') + # model_name_or_path = 'MrCat/Meta-Llama-3-8B-Instruct' + + # # download model in modelscope + # model_name_or_path = snapshot_download('LLM-Research/Meta-Llama-3-8B-Instruct', + # cache_dir='LLM-Research/Meta-Llama-3-8B-Instruct') + + # # offline model + # model_name_or_path = '/root/share/new_models/meta-llama/Meta-Llama-3-8B-Instruct' + # adapter_name_or_path = None + + # model_name_or_path = "xtuner_config/merged_Llama3_8b_instruct_e3" + # adapter_name_or_path = 'xtuner_config/hf_llama3_e1_sc2' + + # model_name_or_path = "xtuner_config/merged_Llama3_8b_instruct_e1_sc" + # adapter_name_or_path = None + + print_user = False # 控制是否输入提示输入框,用于notebook时,改为True + + template_name = 'llama3' + + + template = template_dict[template_name] + + # 若开启4bit推理能够节省很多显存,但效果可能下降 + load_in_4bit = False # True # 6291MiB + + # 生成超参配置,可修改以取得更好的效果 + max_new_tokens = 500 # 每次回复时,AI生成文本的最大长度 + top_p = 0.9 + temperature = 0.6 # 越大越有创造性,越小越保守 + repetition_penalty = 1.1 # 越大越能避免吐字重复 + + # 加载模型 + print(f'Loading model from: {model_name_or_path}') + print(f'adapter_name_or_path: {adapter_name_or_path}') + model = load_model( + model_name_or_path, + load_in_4bit=load_in_4bit, + adapter_name_or_path=adapter_name_or_path + ).eval() + tokenizer = load_tokenizer(model_name_or_path if adapter_name_or_path is None else adapter_name_or_path) + if template.stop_word is None: + template.stop_word = tokenizer.eos_token + stop_token_id = tokenizer.encode(template.stop_word, add_special_tokens=True) + assert len(stop_token_id) == 1 + stop_token_id = stop_token_id[0] + + + print("================================================================================") + print("=============欢迎来到Llama3 EmoLLM 心理咨询室, 输入'exit'退出程序===============") + print("================================================================================") + history = [] + + print("============请输入聊天内容, 按回车键结束输入, 输入'clear'清空聊天信息==============") + print("================================================================================") + print("================================================================================") + print("===============================让我们开启对话吧=================================\n\n") + if print_user: + query = input('用户:') + print("# 用户:{}".format(query)) + else: + query = input('# 用户: ') + + while True: + if query=='exit': + break + if query.strip() == "clear": + history = [] + print("\n\n=============欢迎来到Llama3 EmoLLM 心理咨询室, 输入'exit'退出程序===============") + print("============请输入聊天内容, 按回车键结束输入, 输入'clear'清空聊天信息===========") + print("================================================================================") + print("================================================================================") + if print_user: + query = input('用户:') + print("# 用户:{}".format(query)) + else: + query = input('# 用户: ') + continue + + query = query.strip() + input_ids = build_prompt(tokenizer, template, query, copy.deepcopy(history), system=None).to(model.device) + outputs = model.generate( + input_ids=input_ids, max_new_tokens=max_new_tokens, do_sample=True, + top_p=top_p, temperature=temperature, repetition_penalty=repetition_penalty, + eos_token_id=stop_token_id, pad_token_id=tokenizer.eos_token_id + ) + outputs = outputs.tolist()[0][len(input_ids[0]):] + response = tokenizer.decode(outputs) + response = response.strip().replace(template.stop_word, "").strip() + + # 存储对话历史 + history.append({"role": 'user', 'message': query}) + history.append({"role": 'assistant', 'message': response}) + + # 当对话长度超过6轮时,清空最早的对话,可自行修改 + if len(history) > 12: + history = history[:-12] + + print("# Llama3 EmoLLM 心理咨询师:{}".format(response.replace('\n','').replace('<|start_header_id|>','').replace('assistant<|end_header_id|>','').replace('>',''))) + print() + query = input('# 用户:') + if print_user: + print("# 用户:{}".format(query)) + print("\n\n===============感谢使用Llama3 EmoLLM 心理咨询室, 祝您生活愉快~===============\n\n") + + +if __name__ == '__main__': + main() \ No newline at end of file From 5e1465f1dae60f8981c29a7229bf702be939e548 Mon Sep 17 00:00:00 2001 From: HongCheng Date: Sun, 21 Apr 2024 13:34:43 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9logo=E7=94=A8=E4=BA=8Eweb?= =?UTF-8?q?demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/EmoLLM.png | Bin 0 -> 11752 bytes assets/EmoLLM_logo.png | Bin 0 -> 41909 bytes assets/EmoLLM_logo_L.png | Bin 0 -> 34194 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/EmoLLM.png create mode 100644 assets/EmoLLM_logo.png create mode 100644 assets/EmoLLM_logo_L.png diff --git a/assets/EmoLLM.png b/assets/EmoLLM.png new file mode 100644 index 0000000000000000000000000000000000000000..f61be7057e6e4b95bfdacdba7a734975ace7e3a1 GIT binary patch literal 11752 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 ZYtw}_^LU)gBeJuR6lK+9s--^#{~u<^cenrm literal 0 HcmV?d00001 diff --git a/assets/EmoLLM_logo.png b/assets/EmoLLM_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..24b3bd6fc43e002a6a7f202b37c7c08e2d37611d GIT binary patch literal 41909 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⪼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 literal 0 HcmV?d00001 diff --git a/assets/EmoLLM_logo_L.png b/assets/EmoLLM_logo_L.png new file mode 100644 index 0000000000000000000000000000000000000000..e3cb6029f121856ecc3693ed3cb073dcf494feec GIT binary patch literal 34194 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 H`ucwWxc^9Q literal 0 HcmV?d00001 From f314baf75b08901902e0e21311da6bd81efb2c2f Mon Sep 17 00:00:00 2001 From: HongCheng Date: Sun, 21 Apr 2024 14:45:37 +0900 Subject: [PATCH 5/5] web_demo-Llama3_online --- web_demo-Llama3_online.py | 369 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 web_demo-Llama3_online.py diff --git a/web_demo-Llama3_online.py b/web_demo-Llama3_online.py new file mode 100644 index 0000000..e80f454 --- /dev/null +++ b/web_demo-Llama3_online.py @@ -0,0 +1,369 @@ + +# isort: skip_file +import copy +import warnings +from dataclasses import asdict, dataclass +from typing import Callable, List, Optional + +import streamlit as st +import torch +from torch import nn +from transformers.generation.utils import (LogitsProcessorList, + StoppingCriteriaList) +from transformers.utils import logging + +from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig # isort: skip +from peft import PeftModel + +import warnings + +warnings.filterwarnings("ignore") +warnings.filterwarnings("ignore", category=DeprecationWarning) +logger = logging.get_logger(__name__) + +online = True +if online: + from openxlab.model import download + download(model_repo='chg0901/EmoLLM-Llama3-8B-Instruct2.0', + output='model') + +@dataclass +class GenerationConfig: + # this config is used for chat to provide more diversity + max_length: int = 500 + top_p: float = 0.9 + temperature: float = 0.6 + do_sample: bool = True + repetition_penalty: float = 1.1 + + +@torch.inference_mode() +def generate_interactive( + model, + tokenizer, + prompt, + generation_config: Optional[GenerationConfig] = None, + logits_processor: Optional[LogitsProcessorList] = None, + stopping_criteria: Optional[StoppingCriteriaList] = None, + prefix_allowed_tokens_fn: Optional[Callable[[int, torch.Tensor], + List[int]]] = None, + additional_eos_token_id: Optional[int] = None, + **kwargs, +): + inputs = tokenizer([prompt], return_tensors='pt') + input_length = len(inputs['input_ids'][0]) + for k, v in inputs.items(): + inputs[k] = v.cuda() + input_ids = inputs['input_ids'] + _, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1] + if generation_config is None: + generation_config = model.generation_config + generation_config = copy.deepcopy(generation_config) + model_kwargs = generation_config.update(**kwargs) + bos_token_id, eos_token_id = ( # noqa: F841 # pylint: disable=W0612 + generation_config.bos_token_id, + generation_config.eos_token_id, + ) + if isinstance(eos_token_id, int): + eos_token_id = [eos_token_id] + if additional_eos_token_id is not None: + eos_token_id.append(additional_eos_token_id) + has_default_max_length = kwargs.get( + 'max_length') is None and generation_config.max_length is not None + if has_default_max_length and generation_config.max_new_tokens is None: + warnings.warn( + f"Using 'max_length''s default ({repr(generation_config.max_length)}) \ + to control the generation length. " + 'This behaviour is deprecated and will be removed from the \ + config in v5 of Transformers -- we' + ' recommend using `max_new_tokens` to control the maximum \ + length of the generation.', + UserWarning, + ) + elif generation_config.max_new_tokens is not None: + generation_config.max_length = generation_config.max_new_tokens + \ + input_ids_seq_length + if not has_default_max_length: + logger.warn( # pylint: disable=W4902 + f"Both 'max_new_tokens' (={generation_config.max_new_tokens}) " + f"and 'max_length'(={generation_config.max_length}) seem to " + "have been set. 'max_new_tokens' will take precedence. " + 'Please refer to the documentation for more information. ' + '(https://huggingface.co/docs/transformers/main/' + 'en/main_classes/text_generation)', + UserWarning, + ) + + if input_ids_seq_length >= generation_config.max_length: + input_ids_string = 'input_ids' + logger.warning( + f"Input length of {input_ids_string} is {input_ids_seq_length}, " + f"but 'max_length' is set to {generation_config.max_length}. " + 'This can lead to unexpected behavior. You should consider' + " increasing 'max_new_tokens'.") + + # 2. Set generation parameters if not already defined + logits_processor = logits_processor if logits_processor is not None \ + else LogitsProcessorList() + stopping_criteria = stopping_criteria if stopping_criteria is not None \ + else StoppingCriteriaList() + + logits_processor = model._get_logits_processor( + generation_config=generation_config, + input_ids_seq_length=input_ids_seq_length, + encoder_input_ids=input_ids, + prefix_allowed_tokens_fn=prefix_allowed_tokens_fn, + logits_processor=logits_processor, + ) + + stopping_criteria = model._get_stopping_criteria( + generation_config=generation_config, + stopping_criteria=stopping_criteria) + logits_warper = model._get_logits_warper(generation_config) + + unfinished_sequences = input_ids.new(input_ids.shape[0]).fill_(1) + scores = None + while True: + model_inputs = model.prepare_inputs_for_generation( + input_ids, **model_kwargs) + # forward pass to get next token + outputs = model( + **model_inputs, + return_dict=True, + output_attentions=False, + output_hidden_states=False, + ) + + next_token_logits = outputs.logits[:, -1, :] + + # pre-process distribution + next_token_scores = logits_processor(input_ids, next_token_logits) + next_token_scores = logits_warper(input_ids, next_token_scores) + + # sample + probs = nn.functional.softmax(next_token_scores, dim=-1) + if generation_config.do_sample: + next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1) + else: + next_tokens = torch.argmax(probs, dim=-1) + + # update generated ids, model inputs, and length for next step + input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1) + model_kwargs = model._update_model_kwargs_for_generation( + outputs, model_kwargs, is_encoder_decoder=False) + unfinished_sequences = unfinished_sequences.mul( + (min(next_tokens != i for i in eos_token_id)).long()) + + output_token_ids = input_ids[0].cpu().tolist() + output_token_ids = output_token_ids[input_length:] + for each_eos_token_id in eos_token_id: + if output_token_ids[-1] == each_eos_token_id: + output_token_ids = output_token_ids[:-1] + response = tokenizer.decode(output_token_ids) + + yield response + # stop when each sentence is finished + # or if we exceed the maximum length + if unfinished_sequences.max() == 0 or stopping_criteria( + input_ids, scores): + break + + +def on_btn_click(): + del st.session_state.messages + + +# @st.cache_resource +# def load_model(arg1): +# # model = AutoModelForCausalLM.from_pretrained(args.m).cuda() +# # tokenizer = AutoTokenizer.from_pretrained(args.m, trust_remote_code=True) +# model = AutoModelForCausalLM.from_pretrained(arg1, torch_dtype=torch.float16).cuda() +# tokenizer = AutoTokenizer.from_pretrained(arg1, trust_remote_code=True) + + +# return model, tokenizer +@st.cache_resource +def load_model(model_name_or_path, load_in_4bit=False, adapter_name_or_path=None): + if load_in_4bit: + quantization_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_compute_dtype=torch.float16, + bnb_4bit_use_double_quant=True, + bnb_4bit_quant_type="nf4", + llm_int8_threshold=6.0, + llm_int8_has_fp16_weight=False, + ) + else: + quantization_config = None + + # 加载base model + model = AutoModelForCausalLM.from_pretrained( + model_name_or_path, + # load_in_4bit=load_in_4bit, + # # ValueError: You can't pass `load_in_4bit`or `load_in_8bit` as a kwarg when passing `quantization_config` argument at the same time. + trust_remote_code=True, + low_cpu_mem_usage=True, + torch_dtype=torch.float16, + device_map='auto', + quantization_config=quantization_config + ) + + # 加载adapter + if adapter_name_or_path is not None: + model = PeftModel.from_pretrained(model, adapter_name_or_path) + + ## 加载tokenzier + tokenizer = AutoTokenizer.from_pretrained( + model_name_or_path if adapter_name_or_path is None else adapter_name_or_path, + trust_remote_code=True, + use_fast=False + ) + + if tokenizer.pad_token is None: + tokenizer.pad_token = tokenizer.eos_token + return model, tokenizer + + +def prepare_generation_config(): + with st.sidebar: + + # 使用 Streamlit 的 markdown 函数添加 Markdown 文本 + st.image('assets/EmoLLM_logo_L.png', width=1, caption='EmoLLM Logo', use_column_width=True) + st.markdown("[访问 **EmoLLM** 官方repo: **SmartFlowAI/EmoLLM**](https://github.com/SmartFlowAI/EmoLLM)") + + max_length = st.slider('Max Length', + min_value=8, + max_value=8192, + value=500) + top_p = st.slider('Top P', 0.0, 1.0, 0.9, step=0.01) + temperature = st.slider('Temperature', 0.0, 1.0, 0.6, step=0.01) + repetition_penalty = st.slider('Repetition penalty', 0.0, 1.5, 1.1, step=0.01) + st.button('Clear Chat History', on_click=on_btn_click) + + generation_config = GenerationConfig(max_length=max_length, + top_p=top_p, + temperature=temperature, + repetition_penalty=repetition_penalty, + do_sample=True) + + return generation_config + + +user_prompt = '<|start_header_id|>user<|end_header_id|>\n\n{user}<|eot_id|>' +robot_prompt = '<|start_header_id|>assistant<|end_header_id|>\n\n{robot}<|eot_id|>' +cur_query_prompt = '<|start_header_id|>user<|end_header_id|>\n\n{user}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n' + + +def combine_history(prompt): + messages = st.session_state.messages + + meta_instruction = ( + "你是心理健康助手EmoLLM, 由EmoLLM团队打造, 是一个研究过无数具有心理健康问题的病人与心理健康医生对话的心理专家, 在心理方面拥有广博的知识储备和丰富的研究咨询经验。你旨在通过专业心理咨询, 协助来访者完成心理诊断。请充分利用专业心理学知识与咨询技术, 一步步帮助来访者解决心理问题。。" + ) + total_prompt = f"<|start_header_id|>system<|end_header_id|>\n{meta_instruction}<|eot_id|>\n" + + for message in messages: + cur_content = message['content'] + if message['role'] == 'user': + cur_prompt = user_prompt.format(user=cur_content) + elif message['role'] == 'robot': + cur_prompt = robot_prompt.format(robot=cur_content) + else: + raise RuntimeError + total_prompt += cur_prompt + total_prompt = total_prompt + cur_query_prompt.format(user=prompt) + return total_prompt + + +def main(arg1): + + + if online: + model_name_or_path = 'model' + adapter_name_or_path = None + else: + # model_name_or_path = "/root/StableCascade/emollm2/EmoLLM/xtuner_config/merged_Llama3_8b_instruct_e3" + # adapter_name_or_path = '/root/StableCascade/emollm2/EmoLLM/xtuner_config/hf_llama3_e1_sc2' + + model_name_or_path = "/root/StableCascade/emollm2/EmoLLM/xtuner_config/merged_Llama3_8b_instruct_e1_sc" + adapter_name_or_path = None + + # 若开启4bit推理能够节省很多显存,但效果可能下降 + load_in_4bit = False # True # 6291MiB + + # torch.cuda.empty_cache() + print('load model begin.') + # 加载模型 + print(f'Loading model from: {model_name_or_path}') + print(f'adapter_name_or_path: {adapter_name_or_path}') + # model, tokenizer = load_model(arg1) + model, tokenizer = load_model( + arg1 if arg1 is not None else model_name_or_path, + load_in_4bit=load_in_4bit, + adapter_name_or_path=adapter_name_or_path + ) + model.eval() + print('load model end.') + + user_avator = "assets/user.png" + robot_avator = "assets/EmoLLM.png" + + st.title('EmoLLM Llama3心理咨询室V2.0') + + generation_config = prepare_generation_config() + + # Initialize chat history + if 'messages' not in st.session_state: + st.session_state.messages = [] + + # Display chat messages from history on app rerun + for message in st.session_state.messages: + with st.chat_message(message['role'], avatar=message.get("avatar")): + st.markdown(message['content']) + + # Accept user input + if prompt := st.chat_input('你好,欢迎来到Llama3 EmoLLM 心理咨询室'): + # Display user message in chat message container + with st.chat_message('user', avatar=user_avator): + st.markdown(prompt) + real_prompt = combine_history(prompt) + # Add user message to chat history + st.session_state.messages.append({ + 'role': 'user', + 'content': prompt, + 'avatar': user_avator + }) + + + # stop_token_id = tokenizer.encode('<|eot_id|>', add_special_tokens=True) + # assert len(stop_token_id) == 1 + # stop_token_id = stop_token_id[0] + + with st.chat_message('robot', avatar=robot_avator): + message_placeholder = st.empty() + for cur_response in generate_interactive( + model=model, + tokenizer=tokenizer, + prompt=real_prompt, + additional_eos_token_id=128009, # <|eot_id|> + eos_token_id=128009, + pad_token_id=128009, + **asdict(generation_config), + ): + # Display robot response in chat message container + message_placeholder.markdown(cur_response + '▌') + message_placeholder.markdown(cur_response) + # Add robot response to chat history + st.session_state.messages.append({ + 'role': 'robot', + 'content': cur_response, # pylint: disable=undefined-loop-variable + "avatar": robot_avator, + }) + torch.cuda.empty_cache() + + +if __name__ == '__main__': + + import sys + arg1 = sys.argv[1] + main(arg1)