zyg18181818 / Llama-3-Chinese

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Llama-3-Chinese

🀄🇨🇳中文 | 🔤English

⚗️ 主要内容

  • 💡我们提供了一个完整的工作流,包括增量预训练,微调(全参微调以及lora微调),对齐,评估,从而得到一个拥有强大中文能力的Llama模型
  • 💡开源了使用中文数据预训练的Llama以及经过指令精调的模型
  • 💡开源了所使用的所有数据集,并提供了数据筛选方式
  • 💡开源了所有训练脚本,用户可以根据自身需求进一步训练
  • 💡提供了各阶段微调设置参数对应时间消耗以及显存占用,并列出影响显存以及训练时间的参数

🗂️ 目录

🆙 更新

⚡️ 快速开始

  • 运行Llama-3-8B-Chinese-chat
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"     #before torch
from transformers import AutoTokenizer, AutoConfig, AddedToken, AutoModelForCausalLM, BitsAndBytesConfig
from peft import PeftModel
from dataclasses import dataclass
from typing import Dict
import torch
import copy

## template
@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,
    )

# not match with my version
register_template(
    template_name='llama3',
    # system_format='<|begin_of_text|><<SYS>>\n{content}\n<</SYS>>\n\n',     #previous
    system_format="<|start_header_id|>system<|end_header_id|>\n\n{content}<|eot_id|>",   #same
    user_format='<|start_header_id|>user<|end_header_id|>\n\n{content}<|eot_id|>',  #same
    # assistant_format='<|start_header_id|>assistant<|end_header_id|>\n\n{content}<|end_of_text|>\n',    #previous
    assistant_format='<|start_header_id|>assistant<|end_header_id|>\n\n{content}<|eot_id|>\n',
    system="You are a helpful assistant. ",  #same
    stop_word='<|eot_id|>'    #same
)



def load_model(model_name_or_path, adapter_name_or_path=None):

    model = AutoModelForCausalLM.from_pretrained(
        model_name_or_path,
        trust_remote_code=True,
        # low_cpu_mem_usage=True,
        torch_dtype=torch.float16,
        device_map='auto'
    )

    
    if adapter_name_or_path is not None:
        model = PeftModel.from_pretrained(model, adapter_name_or_path)

    return model


def load_tokenizer(model_name_or_path):
    tokenizer = AutoTokenizer.from_pretrained(
        model_name_or_path,
        trust_remote_code=True,
        use_fast=False
    )
    # print("pad token:", tokenizer.pad_token)
    if tokenizer.pad_token is None:
        # print("set pad token")
        tokenizer.pad_token = tokenizer.eos_token

    return tokenizer


def build_prompt(tokenizer, template, query, history, system=None):
    template_name = template.template_name
    system_format = template.system_format   # '<|begin_of_text|><<SYS>>\n{content}\n<</SYS>>\n\n'
    user_format = template.user_format      # '<|start_header_id|>user<|end_header_id|>\n\n{content}<|eot_id|>'
    assistant_format = template.assistant_format   #'<|start_header_id|>assistant<|end_header_id|>\n\n{content}<|end_of_text|>\n'
    system = system if system is not None else template.system   # "You are a helpful assistant. "

    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():
    model_name_or_path = 'unstoppable123/Llama-3-8B-Chinese-chat-v0.1' # your path
    template_name = 'llama3'
    adapter_name_or_path = None

    template = template_dict[template_name]

    max_new_tokens = 256 
    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,
        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]

    history = []

    query = input('# User:')
    while True:
        query = query.strip()
        input_ids = build_prompt(tokenizer, template, query, copy.deepcopy(history), system=None).to(model.device)
        # print("tokenizer.pad_token_id", tokenizer.pad_token_id)
        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
        history.append({"role": 'user', 'message': query})
        history.append({"role": 'assistant', 'message': response})


        if len(history) > 12:
            history = history[:-12]
        if response.startswith("<|start_header_id|>assistant<|end_header_id|>"):
            response = response[len("<|start_header_id|>assistant<|end_header_id|>"):]
        if response.startswith("system<|end_header_id|>"):
            response = response[len("system<|end_header_id|>"):]
        print("# Llama3-Chinese:{}".format(response))
        query = input('# User:')


if __name__ == '__main__':
    main()

🚀 工作流

🤗 模型

🤖 Llama-3官方模型

类别 模型名称 🤗模型加载名称 下载地址
预训练 Llama-3-8B meta-llama/Meta-Llama-3-8B HuggingFace
Chat Llama-3-8B-Instrcut meta-llama/Meta-Llama-3-8B-Instruct HuggingFace

🤖 中文预训练模型

🤖 中文微调模型

类别 模型名称 🤗模型加载名称 下载地址
lora微调(已融合) Llama-3-8B-Chinese-chat-v0.1 unstoppable123/Llama-3-8B-Chinese-chat-v0.1 HuggingFace
lora微调(lora权重) Llama-3-8B-Chinese-Chat-lora-v0.1 unstoppable123/Llama-3-8B-chinese-lora-v0.1 HuggingFace
lora微调(lora已融合) Llama-3-8B-Chinese-Chat-lora-v0.2 unstoppable123/LLaMA-3-8B_chinese_lora_sft_v0.2 HuggingFace
lora微调(lora权重) Llama-3-8B-Chinese-Chat-lora-v0.2 unstoppable123/Llama-3-8B-chinese-lora-v0.2 HuggingFace

🤖 中文对齐模型

📝 数据集

📄 预训练数据集

📄 微调数据集

名称 数据量 描述
Firefly 1150k 包含23种常见中文下游任务的优质中文数据,对于每个任务,由人工书写若干种指令模板,保证数据的高质量与丰富度
Ruozhiba 15k 弱智吧数据问答,有助于增强模型回答的逻辑性
GPT-4-LLM 50k 微软开源的数据,是利用 GPT-4 生成的 Alpaca 数据,并做了中文翻译
COIG 160k 包含知乎、小红书历史问答、价值观、代码问题解决等考题型数据

📄 对齐数据集

🔧 设置

📖 样例

🔵 v0.2回答样例(User部分为用户输入,Assistant部分为模型生成回复)

User: 解释一下VUE原理

Assistant: VUE是一种基于响应式编程的前端框架,使用了观察者模式来实现数据的双向绑定。其核心**是使用一个对象来存储状态,并将其观察者模式的观察者列表保存在对象的属性中。这样,当对象的状态发生变化时,观察者列表中的观察者对象将被通知并更新相应的视图。VUE的实现主要包括以下几个部分:

1. 响应式数据源:VUE使用了响应式数据源来存储状态,响应式数据源的值会被实时监测,并且会通知观察者对象进行相应的更新。

2. 观察者模式:VUE使用了观察者模式来实现数据的双向绑定。观察者对象会被通知当响应式数据源的值发生变化时,观察者对象会进行相应的更新。

3. 数据绑定:VUE使用了数据绑定来将响应式数据源的值与视图进行绑定。数据绑定会将响应式数据源的值与视图中的元素进行绑定,并且当响应式数据源的值发生变化时,数据绑定会自动更新视图中的元素。

4. 依赖项管理:VUE使用了依赖项管理来实现响应式数据源的更新。当响应式数据源的值发生变化时,VUE会根据依赖项管理的规则来更新响应式数据源的值,并通知观察者对象进行相应的更新。

5. 组件化:VUE使用了组件化的**来实现前端开发。组件化将应用程序分成多个小的、独立的模块,每个模块都可以单独地开发、测试和部署。组件化使得前端开发更加灵活和高效。

总之,VUE的实现主要基于响应式编程的**,使用了观察者模式和数据绑定来实现数据的双向绑定,并使用依赖项管理和组件化的**来实现前端开发。

🎉 致谢

感谢CrazyBoyM/llama3-Chinese-chat的推广宣传

About