类ChatGPT的部署与微调(下):从ChatGLM-6b到ChatDoctor、可商用

news2024/12/24 20:53:54

前言 

随着『GPT4多模态/Microsoft 365 Copilot/Github Copilot X/ChatGPT插件』的推出,绝大部分公司的技术 产品 服务,以及绝大部分人的工作都将被革新一遍

  • 类似iPhone的诞生 大家面向iOS编程 有了App Store
  • 现在有了ChatGPT插件/GPT应用商店,以后很多公司 很多人面向GPT编程(很快技术人员分两种,一种懂GPT,一种不懂GPT)

然ChatGPT/GPT4基本不可能开源了,而通过上篇文章《类ChatGPT项目的部署与微调(上):从LLaMA到Alpaca、Vicuna、BELLE、ChatLLaMA和ColossalChat》可知,国内外各大公司、研究者推出了很多类ChatGPT开源项目,比如LLaMA、BLOOM

本文则侧重

  • ChatGLM
  • 垂直领域的ChatGPT等,比如ChatDoctor
    毕竟,虽然LLaMA这些模型的通用能力很强,然应用在垂直领域的话,还得再加上各个垂直方向的预料加以训练,由此便诞生了以LLaMA为底层模型的比如ChatDoctor,且可以预见的是,垂直领域的ChatGPT,今年会诞生一大批

第四部分 国内的GLM与类ChatGPT项目ChatGLM-6B

4.1 GLM: General Language Model Pretraining with Autoregressive Blank Infilling

在2022年上半年,当时主流的预训练框架可以分为三种:

  • autoregressive,自回归模型的代表是单向的GPT,本质上是一个从左到右的语言模型,常用于无条件生成任务(unconditional generation),缺点是无法利用到下文的信息
  • autoencoding,自编码模型是通过某个降噪目标(如掩码语言模型,简单理解就是通过挖洞,训练模型做完形填空的能力)训练的语言编码器,如双向的BERT、ALBERT、RoBERTa、DeBERTa
    自编码模型擅长自然语言理解任务(natural language understanding tasks),常被用来生成句子的上下文表示,缺点是不适合生成任务
  • encoder-decoder,则是一个完整的Transformer结构,包含一个编码器和一个解码器,以T5、BART为代表,常用于有条件的生成任务 (conditional generation)
    细致来说,T5的编码器中的注意力是双向,解码器中的注意力是单向的,因此可同时应用于自然语言理解任务和生成任务。但T5为了达到和RoBERTa和DeBERTa相似的性能,往往需要更多的参数量

这三种预训练模型各自称霸一方,那么问题来了,可否结合三种预训练模型,以成天下之一统?这便是2022年5月发表的这篇论文《GLM: General Language Model Pretraining with Autoregressive Blank Infilling》的出发点,它提出了GLM架构(这是张义策关于GLM论文的解读之一,下面三小节的内容主要参考自该篇解读)

4.1.1 如何将生成模型GPT和掩码语言模型BERT结合在一起

首先,考虑到三类预训练模型的训练目标

  • GPT的训练目标是从左到右的文本生成
  • BERT的训练目标是对文本进行随机掩码,然后预测被掩码的词
  • T5则是接受一段文本,从左到右的生成另一段文本

为了大一统,我们必须在结构和训练目标上兼容这三种预训练模型。如何实现呢?文章给出的解决方法

  • 结构上,只需要GLM中同时存在单向注意力和双向注意力即可
    在原本的Transformer模型中,这两种注意力机制是通过修改attention mask实现的
    当attention_mask是全1矩阵的时候,这时注意力是双向的
    当attention_mask是三角矩阵的时候(如下图),注意力就是单向

    类似地,我们可以在只使用Transformer编码器的情况下,自定义attention mask来兼容三种模型结构

  • 训练目标上,这篇文章提出一个自回归空格填充的任务(Autoregressive Blank Infifilling),来兼容三种预训练目标
    自回归填充有些类似掩码语言模型,首先采样输入文本中部分片段,将其替换为[MASK]标记,然后预测[MASK]所对应的文本片段,与掩码语言模型不同的是,预测的过程是采用自回归的方式

    具体来说,
    \rightarrow  当被掩码的片段长度为1的时候,空格填充任务等价于掩码语言建模,类似BERT
    \rightarrow  当将文本1和文本2拼接在一起,然后将文本2整体掩码掉,空格填充任务就等价于条件语言生成任务,类似T5/BART
    \rightarrow  当全部的文本都被掩码时,空格填充任务就等价于无条件语言生成任务,类似GPT

4.1.2 如何理解GLM的自回归空格填充任务

假设原始的文本序列为x_1,x_2,x_3,x_4,x_5,x_6,采样的两个文本片段为 x_3 和 x_5,x_6 ,那么掩码后的文本序列为 x_1,x_2,[M],x_4,[M](以下简称Part A),如上图所示,拆解图中的三块分别可得

  • 我们要根据第一个[M] 解码出 x_3 ,根据第二个[M]依次解码出 x_5,x_6 ,那怎么从 [M] 处解码出变长的序列吗?这就需要用到开始标记 [S] 和结束标记 [E] 了
  • 我们从开始标记 [S]开始依次解码出被掩码的文本片段,直至结束标记 [E] 。通过本博客内的Transformer笔记可知,Transformer中的位置信息是通过位置向量来记录的
    在GLM中,位置向量有两个,一个 用来记录Part A中的相对顺序,一个 用来记录被掩码的文本片段(简称为Part B)中的相对顺序
  • 此外,还需要通过自定义自注意掩码(attention mask)来达到以下目的:
    \rightarrow  双向编码器Part A中的词彼此可见,即图(d)中蓝色框中的区域
    \rightarrow  单向解码器Part B中的词单向可见,即图(d)黄色框的区域
    \rightarrow  Part B可见Part A
    \rightarrow  其余不可见,即图(d)中灰色的区域

需要说明的是,Part B包含所有被掩码的文本片段,但是文本片段的相对顺序是随机打乱的

4.1.3 GLM的预训练和微调

作者使用了两个预训练目标来优化GLM,两个目标交替进行:

  • 文档级别的预测/生成:从文档中随机采样一个文本片段进行掩码,片段的长度为文档长度的50%-100%
  • 句子级别的预测/生成:从文档中随机掩码若干文本片段,每个文本片段必须为完整的句子,被掩码的词数量为整个文档长度的15%

尽管GLM是BERT、GPT、T5三者的结合,但是在预训练时,为了适应预训练的目标,作者还是选择掩码较长的文本片段,以确保GLM的文本生成能力,并在微调的时候将自然语言理解任务也转化为生成任务,如情感分类任务转化为填充空白的任务

  • 输入:{Sentence},prompt:It is really [M] ,对应的标签为good和bad

此外,模型架构层面,除了整体基于Transformer之外

  1. 重新排列了层归一化和残差连接的顺序
  2. 针对token的输出预测使用单一线性层
  3. 用GeLU替换ReLU激活函数

4.2 GLM-130B:国内为数不多的可比肩GPT3的大模型之一 

2022年8月,清华背景的智谱AI基于GLM框架,正式推出拥有1300亿参数的中英双语稠密模型 GLM-130B(论文地址、代码地址,论文解读之一,GLM-130B is trained on a cluster of 96 DGX-A100 GPU (8×40G) servers with a 60-day,可以较好的支持2048个token的上下文窗口)

其在一些任务上的表现优于GPT3-175B,是国内与2020年5月的GPT3在综合能力上差不多的模型之一(即便放到23年年初也并不多),这是它的一些重要特点

4.3 类ChatGPT开源项目ChatGLM-6B的训练框架与部署步骤

4.3.1 ChatGLM-6B的训练框架

ChatGLM-6B(介绍页面、代码地址),是智谱 AI 开源、支持中英双语的对话语言模型,其

  • 基于General Language Model(GLM)架构,具有62亿参数,无量化下占用显存13G,INT8量化级别下支持在单张11G显存的 2080Ti 上进行推理使用(因为INT8下占用显存10G,而INT4量化级别下部署的话最低只需 6GB显存,另基于 P-Tuning v2 的高效参数微调方法的话,在INT4 下最低只需 7GB 显存即可启动微调)
    量化等级最低 GPU 显存(部署/推理)最低 GPU 显存(高效参数微调)
    FP16(无量化)13 GB14 GB
    INT88 GB9 GB
    INT46 GB7 GB
    这里需要解释下的是,INT8量化是一种将深度学习模型中的权重和激活值从32位浮点数(FP32)减少到8位整数(INT8)的技术。这种技术可以降低模型的内存占用和计算复杂度,从而减少计算资源需求,提高推理速度,同时降低能耗
    量化的过程通常包括以下几个步骤:
    1 量化范围选择:确定权重和激活值的最小值和最大值
    2 量化映射:根据范围将32位浮点数映射到8位整数
    3 反量化:将8位整数转换回浮点数,用于计算
  • ChatGLM-6B参考了 ChatGPT 的训练思路,在千亿基座模型GLM-130B中注入了代码预训练,通过监督微调(Supervised Fine-Tuning)、反馈自助(Feedback Bootstrap)、人类反馈强化学习(Reinforcement Learning from Human Feedback)等方式等技术实现人类意图对齐,并针对中文问答和对话进行优化
  • 最终经过约 1T 标识符的中英双语训练,生成符合人类偏好的回答

虽尚有很多不足(比如因为6B的大小限制,导致模型的记忆能力、编码、推理能力皆有限),但在6B这个参数量级下不错了,部署也非常简单,我七月在线的同事朝阳花了一两个小时即部署好了(主要时间花在模型下载上,实际的部署操作很快)

4.3.2 ChatGLM-6B的部署步骤

以下是具体的部署过程

  1. 硬件配置
    本次实验用的七月的GPU服务器(专门为七月集/高/论文/VIP学员配置的),显存大小为16G的P100,具体配置如下:
    CPU&内存:28核(vCPU)112 GB
    操作系统:Ubuntu_64
    GPU:NVIDIA Tesla P100
    显存:16G
  2. 配置环境
    建议最好自己新建一个conda环境
    pip install -r requirements.txt

    特别注意torch版本不低于1.10(这里安装的1.10),transformers为4.27.1
    torch的安装命令可以参考pytorch官网:https://pytorch.org/

    这里使用的pip命令安装的,命令如下
    pip install torch==1.10.0+cu102 torchvision==0.11.0+cu102 torchaudio==0
  3. 下载项目仓库
    git clone https://github.com/THUDM/ChatGLM-6B
    cd ChatGLM-6B
  4. 下载ChatGLM-6B模型文件
    具体而言,较大的8个模型文件可以从这里下载(下载速度快):清华大学云盘

    其他的小文件可以从这里下载(点击红框的下载按钮即可):THUDM/chatglm-6b · Hugging Face

    注意这里都下载在了/data/chatglm-6b下,在后面执行代码的时候需要将文件中的模型文件路径改为自己的
  5. 推理与部署
    可运行的方式有多种
    \rightarrow  如果在本地运行,可以直接执行代码,或者使用命令行方式运行
    \rightarrow  如果想让别人公网访问,可以用下面两种方式:一种是基于Gradio,一种是基于streamlit
    特别注意:运行代码前请检查模型文件路径是否正确,这里均改为了/data/chatglm-6b

    代码运行demo
    from transformers import AutoTokenizer, AutoModel
    tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
    model = AutoModel.from_pretrained("/data/chatglm-6b", trust_remote_code=True).half().cuda()
    model = model.eval()
    response, history = model.chat(tokenizer, "你好", history=[])
    print(response)
    response, history = model.chat(tokenizer, "晚上睡不着应该怎么办", history=history)
    print(response)
    运行之后 如下截图所示


    命令行 Demo
    运行仓库中 cli_demo.py:
    python cli_demo.py
    程序会在命令行中进行交互式的对话,在命令行中输入指示并回车即可生成回复,输入 clear 可以清空对话历史,输入 stop 终止程序


    基于Gradio的网页版demo
    运行web_demo.py即可(注意可以设置share=True,便于公网访问):python web_demo.py(注意运行前确认下模型文件路径)

    基于streamlit网页版 Demo
    pip install streamlit
    pip install streamlit-chat
    streamlit run web_demo2.py --server.port 6006(可以将6006端口放出,便于公网访问)


    默认情况下,模型以 FP16 精度加载,运行上述代码需要大概 13GB 显存。如果显存有限,还可以考虑模型量化,目前支持4/8 bit 量化

此外,据介绍,GLM团队正在内测130B参数的ChatGLM,相信从6B到130B,效果应该能提升很多

4.4 微调ChatGLM-6B:针对各种数据集通过LoRA或P-Tuning v2

4.4.1 通过Stanford Alpaca的52K数据集基于LoRA(PEFT库)微调ChatGLM-6B

从上文可知,Stanford Alpaca的52K数据集是通过Self Instruct方式提示GPT3对应的API产生的指令数据,然后通过这批指令数据微调Meta的LLaMA 7B

而GitHub上的这个微调ChatGLM-6B项目(作者:mymusise),则基于Stanford Alpaca的52K数据集通过LoRA(low-rank adaptation)的方式微调ChatGLM-6B

如上一篇文章所说,Huggingface公司推出的PEFT(Parameter-Efficient Fine-Tuning)库便封装了LoRA这个方法,具体而言,通过PEFT-LoRA微调ChatGLM-6B的具体步骤如下

  • 第一步,配置环境与准备
    先下载项目仓库
    git clone https://github.com/mymusise/ChatGLM-Tuning.git

    创建一个python3.8的环境
    conda create -n torch1.13 python==3.8
    conda activate torch1.13

    根据requirements.txt配置环境
    pip install bitsandbytes==0.37.1

    安装1.13,cuda11.6(torch官网命令)
    pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116

    安装其他的包
    pip install accelerate==0.17.1
    pip install tensorboard==2.10
    pip install protobuf==3.19.5
    pip install transformers==4.27.1
    pip install icetk
    pip install cpm_kernels==1.0.11
    pip install datasets==2.10.1
    pip install git+https://github.com/huggingface/peft.git # 最新版本 >=0.3.0.dev0
    遇到冲突问题:icetk 0.0.5 has requirement protobuf<3.19, but you have protobuf 3.19.5.
    最后装了3.18.3的protobuf,发现没有问题

    模型文件准备
    模型文件在前面基于ChatGLM-6B的部署中已经准备好了,注意路径修改正确即可
  • 第二步,数据准备
    项目中提供了数据,数据来源为 Stanford Alpaca 项目的用于微调模型的52K数据,数据生成过程可详见:https://github.com/tatsu-lab/stanford_alpaca#data-release
    alpaca_data.json,包含用于微调羊驼模型的 52K 指令数据,这个 JSON 文件是一个字典列表,每个字典包含以下字段:
    instruction: str,描述了模型应该执行的任务,52K 条指令中的每一条都是唯一的
    input: str,任务的可选上下文或输入。例如,当指令是“总结以下文章”时,输入就是文章,大约 40% 的示例有输入
    output: str,由 text-davinci-003 生成的指令的答案

    示例如下:
    [
        {
            "instruction": "Give three tips for staying healthy.",
            "input": "",
            "output": "1.Eat a balanced diet and make sure to include plenty of fruits and vegetables. \n2. Exercise regularly to keep your body active and strong. \n3. Get enough sleep and maintain a consistent sleep schedule."
        },
        {
            "instruction": "What are the three primary colors?",
            "input": "",
            "output": "The three primary colors are red, blue, and yellow."
        },  
        ...
    ]
  • 第三步,数据处理
    运行 cover_alpaca2jsonl.py 文件
    python cover_alpaca2jsonl.py \ --data_path data/alpaca_data.json \ --save_path data/alpaca_data.jsonl \
    处理后的文件示例如下:
    ​
    {"text": "### Instruction:\nGive three tips for staying healthy.\n\n### Response:\n1.Eat a balanced diet and make sure to include plenty of fruits and vegetables. \n2. Exercise regularly to keep your body active and strong. \n3. Get enough sleep and maintain a consistent sleep schedule.\nEND\n"}
    {"text": "### Instruction:\nWhat are the three primary colors?\n\n### Response:\nThe three primary colors are red, blue, and yellow.\nEND\n"}
    运行 tokenize_dataset_rows.py 文件,注意:修改tokenize_dataset_rows中的model_name为自己的文件路径 :/data/chatglm-6b
    python tokenize_dataset_rows.py \
        --jsonl_path data/alpaca_data.jsonl \
        --save_path data/alpaca \
        --max_seq_length 200 \
        --skip_overlength \
  • 第四步,微调过程
    ​​注意:运行前修改下finetune.py 文件中模型路径:/data/chatglm-6b
    python finetune.py \
        --dataset_path data/alpaca \
        --lora_rank 8 \
        --per_device_train_batch_size 6 \
        --gradient_accumulation_steps 1 \
        --max_steps 52000 \
        --save_steps 1000 \
        --save_total_limit 2 \
        --learning_rate 1e-4 \
        --fp16 \
        --remove_unused_columns false \
        --logging_steps 50 \
        --output_dir output;
    Nvidia驱动报错(如没有可忽略)
    遇到问题,说明Nvidia驱动太老,需要更新驱动
    UserWarning: CUDA initialization: The NVIDIA driver on your system is too old (found version 10020). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver. (Triggered internally at ../c10/cuda/CUDAFunctions.cpp:109.)
    解决:更新驱动即可,参考:Ubuntu 18.04 安装 NVIDIA 显卡驱动 - 知乎

    BUG REPORT报错
    参考:因为peft原因,cuda10.2报错 · Issue #108 · mymusise/ChatGLM-Tuning · GitHub
    CUDA SETUP: CUDA version lower than 11 are currently not supported for LLM.int8()

    考虑安装11以上的cudatooklit,参考下面链接,安装cudatooklit11.3(因为Ubuntu系统版本的原因,不能装11.6的)
    Ubuntu16.04 安装cuda11.3+cudnn8.2.1 - 知乎
    cudatooklit下载地址:
    CUDA Toolkit 11.3 Downloads | NVIDIA 开发者

    运行代码前先执行下面命令:
    export LD_LIBRARY_PATH=/usr/local/cuda-11.3/lib64:$LD_LIBRARY_PATH  
    export CUDA_HOME=/usr/local/cuda-11.3:$CUDA_HOME  
    export PATH=/usr/local/cuda-11.3/bin:$PATH
    内存不够,考虑将per_device_train_batch_size设为1
    python finetune.py \
        --dataset_path data/alpaca \
        --lora_rank 8 \
        --per_device_train_batch_size 1 \
        --gradient_accumulation_steps 1 \
        --max_steps 52000 \
        --save_steps 1000 \
        --save_total_limit 2 \
        --learning_rate 1e-4 \
        --fp16 \
        --remove_unused_columns false \
        --logging_steps 50 \
        --output_dir output;
    报错:RuntimeError: expected scalar type Half but found Float
    https://github.com/mymusise/ChatGLM-Tuning/issues?q=is%3Aissue+is%3Aopen+RuntimeError%3A+expected+scalar+type+Half+but+found+Float

    解决方法:
    一种是,不启用fp16, load_in_8bit设为True,可以运行,但loss为0;
    一种是,启用fp16, load_in_8bit设为False,不行,应该还是显存不够的问题,至少需要24G左右的显存

4.4.2 ChatGLM团队:通过ADGEN数据集基于P-Tuning v2微调ChatGLM-6B

此外,ChatGLM团队自身也出了一个基于P-Tuning v2的方式微调ChatGLM-6B的项目:ChatGLM-6B 模型基于 P-Tuning v2 的微调

P-Tuning v2(代码地址,论文地址)意义在于:将需要微调的参数量减少到原来的 0.1%,再通过模型量化、Gradient Checkpoint 等方法,最低只需要 7GB 显存即可运行

 那具体怎么通过P-Tuning v2微调ChatGLM-6B呢,具体步骤如下:

  • 第一步,配置环境与准备
    地址:ChatGLM-6B/ptuning at main · THUDM/ChatGLM-6B · GitHub
    安装以下包即可,这里直接在torch1.13的conda环境下安装的
    pip install rouge_chinese nltk jieba datasets
  • 第二步,模型文件准备
    模型文件在前面基于ChatGLM-6B的部署中已经准备好了,注意路径修改正确即可
    特别注意:如果你是之前下载的可能会报错,下面有详细的错误及说明
  • 第三步,数据准备
    ADGEN数据集的任务为根据输入(content)生成一段广告词(summary)
    {
        "content": "类型#上衣*版型#宽松*版型#显瘦*图案#线条*衣样式#衬衫*衣袖型#泡泡袖*衣款式#抽绳", 
        "summary": "这件衬衫的款式非常的宽松,利落的线条可以很好的隐藏身材上的小缺点,穿在身上有着很好的显瘦效果。领口装饰了一个可爱的抽绳,漂亮的绳结展现出了十足的个性,配合时尚的泡泡袖型,尽显女性甜美可爱的气息。"
    }


    从Google Drive 或者 Tsinghua Cloud 下载处理好的 ADGEN数据集,将解压后的AdvertiseGen目录放到本 ptuning 目录下即可
  • 第四步,微调过程
    修改train.sh文件
    去掉最后的 --quantization_bit 4
    注意修改模型路径,THUDM/chatglm-6b修改为/data/chatglm-6b

    如果你也是在云服务器上运行,建议可以加上nohup后台命令,以免断网引起训练中断的情况修改后train.sh文件如下:
    PRE_SEQ_LEN=8
    LR=1e-2
    
    CUDA_VISIBLE_DEVICES=0 nohup python -u main.py \
        --do_train \
        --train_file AdvertiseGen/train.json \
        --validation_file AdvertiseGen/dev.json \
        --prompt_column content \
        --response_column summary \
        --overwrite_cache \
        --model_name_or_path /data/chatglm-6b \
        --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \
        --overwrite_output_dir \
        --max_source_length 64 \
        --max_target_length 64 \
        --per_device_train_batch_size 1 \
        --per_device_eval_batch_size 1 \
        --gradient_accumulation_steps 16 \
        --predict_with_generate \
        --max_steps 3000 \
        --logging_steps 10 \
        --save_steps 1000 \
        --learning_rate $LR \
        --pre_seq_len $PRE_SEQ_LEN \
        >> log.out 2>&1 &
    执行命令,开始微调
    bash train.sh
    如果报错:'ChatGLMModel' object has no attribute 'prefix_encoder'(如没有可忽略)
    解决方案:需要更新 THUDM/chatglm-6b at main 里面的几个py文件(重新下载下这几个文件就可以了)


    微调过程占用大约13G的显存


    微调过程loss变化情况

    微调完成后,output/adgen-chatglm-6b-pt-8-1e-2路径下会生成对应的模型文件,如下(这里生成了3个):
  • 第五步,推理过程
    只需要在加载模型的位置修改成微调后的路径即可
    将 evaluate.sh 中的 CHECKPOINT 更改为训练时保存的 checkpoint 名称,运行以下指令进行模型推理和评测:
    改这一行即可:--model_name_or_path ./output/$CHECKPOINT/checkpoint-3000
    bash evaluate.sh

    评测指标为中文 Rouge score 和 BLEU-4,生成的结果保存在
    ./output/adgen-chatglm-6b-pt-8-1e-2/generated_predictions.txt


    我们可以对比下微调前后的效果
    以命令行 Demo为例,只需修改cli_demo.py中的模型路径为:ptuning/out/adgen-chatglm-6b-pt-8-1e-2/checkpoint-3000,运行 cli_demo.py即可:
    python cli_demo.py

    用以下数据为例:
    Input: 类型#上衣*材质#牛仔布*颜色#白色*风格#简约*图案#刺绣*衣样式#外套*衣款式#破洞 Label: 简约而不简单的牛仔外套,白色的衣身十分百搭。衣身多处有做旧破洞设计,打破单调乏味,增加一丝造型看点。衣身后背处有趣味刺绣装饰,丰富层次感,彰显别样时尚。 这件上衣的材质是牛仔布,颜色是白色,风格是简约,图案是刺绣,衣样式是外套,衣款式是破洞。

    用户:根据输入生成一段广告词,输入为:类型#上衣*材质#牛仔布*颜色#白色*风格#简约*图案#刺绣*衣样式#外套*衣款式#破洞。
    Output[微调前]: 

    Output[微调后]: 

总结:建议使用官方提供的基于P-Tuning v2微调ChatGLM-6B的方式对自己的数据进行微调

4.5 通过Cursor生成微调ChatGLM的示例代码

可能有读者会有疑问,到底怎么微调ChatGLM-6B呢,接下来我们通过Cursor一步一步生成一份示例代码(且参考此文),如下所示

  1. 导入所需的库:PyTorch、TensorDataset 和 DataLoader(用于处理数据集)、transformers(加载预训练模型和分词器)、Lora(此处指Layer-wise Optimized Rate Adaptation,非另一个简称为LoRA的微调LLM的Low-Rank Adaptation)和 SummaryWriter(用于将训练和验证损失记录到 TensorBoard)
    import torch
    from torch.utils.data import TensorDataset, DataLoader
    from transformers import AutoTokenizer, AutoModelForCausalLM
    from lora import Lora
    from torch.utils.tensorboard import SummaryWriter
  2. 下载并加载预训练的 ChatGLM-6B 模型和相应的分词器
    # Download and load the ChatGLM-6B model
    model_name = "TsinghuaAI/ChatGLM-6B"
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForCausalLM.from_pretrained(model_name)
  3. 初始化Lora优化器,并设置学习率和秩(rank)
    # Initialize the Lora optimizer
    optimizer = Lora(model.parameters(), lr=1e-5, rank=16)
    值得一提的是,关于学习率应该怎么设置更好
    实际上,学习率的选择取决于你的模型和数据集
    \rightarrow  如果你的模型和数据集很大,那么你可能需要使用较小的学习率,以避免模型过拟合或者没有收敛
    \rightarrow  如果你的模型和数据集很小,那么你可能需要使用较大的学习率,以加快模型的训练速度
    通常来说,学习率的初始值可以设置为1e-5或1e-4,然后根据模型在训练集和验证集上的表现来调整学习率
    \Rightarrow  如果模型在训练集上的表现很好,但在验证集上的表现很差,那么你可能需要降低学习率;
    \Rightarrow  如果模型在训练集和验证集上的表现都很差,那么你可能需要增加学习率
  4. 定义输入文本input_text,和输出文本output_text
    并使用分词器将输入文本和输出文本转换为张量(tensor)
    # Define your input text
    input_text = "Hello, how are you?"
    
    # Tokenize the input text
    input_ids = torch.tensor(tokenizer.encode(input_text)).unsqueeze(0)
    attention_mask = torch.ones_like(input_ids)
    
    # Define your output text
    output_text = "I'm doing well, thank you for asking."
    
    # Tokenize the output text
    labels = torch.tensor(tokenizer.encode(output_text)).unsqueeze(0)
  5. 将训练数据转换为 TensorDataset,并使用 DataLoader 创建批处理数据加载器
    # Convert your training data to a TensorDataset
    train_dataset = TensorDataset(input_ids, attention_mask, labels)
    
    # Create a DataLoader to load
    # the data in batches
    batch_size = 32
    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    其中,batch_size参数指定了每个batch的大小,shuffle参数指定了是否打乱数据的顺序,当然,可以根据实际需要调整这些参数
  6. 定义验证数据,并将其转换为 TensorDataset 和 DataLoader
    # Define your validation data
    val_input_text = "How are you doing?"
    val_output_text = "I'm doing well, thank you for asking."
    val_input_ids = torch.tensor(tokenizer.encode(val_input_text)).unsqueeze(0)
    val_attention_mask = torch.ones_like(val_input_ids)
    val_labels = torch.tensor(tokenizer.encode(val_output_text)).unsqueeze(0)
    val_dataset = TensorDataset(val_input_ids, val_attention_mask, val_labels)
    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=True)
    其中,nput_ids是一个包含输入文本的token ID的tensor
    attention_mask是一个指示哪些token是padding token的tensor
    labels是一个包含输出文本的token ID的tensor

    在这个示例中,我们首先加载了ChatGLM-6B模型的tokenizer
    然后,我们定义了输入文本和输出文本,并使用tokenizer将它们转换成了input_ids和labels
    其中,attention_mask被设置为一个与input_ids相同大小的tensor,其中所有的值都是1,表示所有的token都是有效的
    当然,你可以根据自己的训练数据和tokenizer来调整这些代码

    另外,要说明的是要判断模型是否过拟合或者没有收敛,你可以观察模型在训练集和验证集上的表现
    如果模型在训练集上的表现很好,但在验证集上的表现很差,那么就说明模型过拟合了
    如果模型在训练集和验证集上的表现都很差,那么就说明模型没有收敛
    如果模型在训练集和验证集上的表现都很好,那么就说明模型训练得很好

    也可以使用PyTorch的DataLoader和TensorDataset来加载训练集和验证集,并在每个epoch结束时计算模型在训练集和验证集上的损失值
  7. 定义训练损失和验证损失的列表
    # Define your training and validation losses
    train_losses = []
    val_losses = []
  8. 初始化 SummaryWriter,用于将损失写入 TensorBoard
    # Initialize the SummaryWriter
    writer = SummaryWriter()
  9. 对模型进行微调:
    a. 在 10 个epoch内进行迭代
    for epoch in range(10):
        total_train_loss = 0
        total_val_loss = 0
        model.train()
    b. 在每个时期中,对训练数据进行遍历,并计算损失。使用优化器进行梯度更新
        for batch in train_loader:
            optimizer.zero_grad()
            input_ids, attention_mask, labels = batch
            outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
            loss = outputs.loss
            loss.backward()
            optimizer.step()
    
            # 每次迭代的loss可以帮助我们更好地了解模型的训练过程,以及每个batch的训练效果
            total_train_loss += loss.item()
    
        # 每轮的平均loss则可以帮助我们更好地了解模型的整体训练效果
        # 以及模型是否出现了过拟合或欠拟合的情况
        avg_train_loss = total_train_loss / len(train_loader)
        train_losses.append(avg_train_loss)
    其中,optimizer.zero_grad()这行代码是用来清空模型的梯度的,为何要做这个操作呢?
    因为在每次迭代中,我们需要计算模型的梯度,并使用优化器来更新模型的参数。但是,在计算新的梯度之前,我们需要先清空之前的梯度。否则,新的梯度会与之前的梯度相加,导致模型的参数更新不正确
    因此,我们需要在每次迭代之前调用optimizer.zero_grad()来清空模型的梯度
    ————————————————
    在每次迭代中,我们需要计算模型的梯度,并使用优化器来更新模型的参数
    loss.backward()会自动计算模型的梯度,并将梯度保存在模型的参数中。这样,我们就可以使用优化器来更新模型的参数了
    ————————————————
    optimizer.step()是用来更新模型的参数的。在每次迭代中,我们需要使用优化器来更新模型的参数,以使模型的输出更接近于真实输出。optimizer.step()会根据模型的梯度和优化器的参数来更新模型的参数。具体来说,它会根据模型的梯度和学习率来计算参数的更新量,并将更新量加到模型的参数中。这样,模型的参数就会被更新了
    如果没有调用optimizer.step(),那么模型的参数就不会被更新,每次迭代都是无用功。在每次迭代中,我们需要计算模型的梯度,并使用优化器来更新模型的参数。loss.backward()会自动计算模型的梯度,并将梯度保存在模型的参数中。但是,如果没有调用optimizer.step(),那么模型的参数就不会被更新,模型的输出也不会得到改善。因此,我们必须在每次迭代中调用optimizer.step(),以更新模型的参数

    c. 在每个时期结束时,评估模型在验证数据上的表现,并计算损失
        total_val_loss = 0
        model.eval()
        with torch.no_grad():
            for batch in val_loader:
                input_ids, attention_mask, labels = batch
                outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
                loss = outputs.loss
                total_val_loss += loss.item()
        avg_val_loss = total_val_loss / len(val_loader)
        val_losses.append(avg_val_loss)
    其中,model.eval()是用来将模型设置为评估模式的。在评估模式下,模型的行为会有所不同。具体来说,评估模式下,模型不会计算梯度,也不会更新模型的参数。这是因为,在评估模式下,我们只需要使用模型来进行预测,而不需要对模型进行训练
    因此,为了提高模型的预测性能,我们需要将模型设置为评估模式。在这个示例中,我们在计算验证集上的损失值时,将模型设置为评估模式,以确保模型的参数不会被更新
    ————————————————
    with torch.no_grad():是一个上下文管理器,它可以临时禁用PyTorch的自动求导功能。在这个上下文中,所有的计算都不会被记录在计算图中,也不会影响模型的梯度。这个上下文通常用于评估模型或者进行推理时,因为在这些情况下,我们不需要计算梯度,也不需要更新模型的参数。禁用自动求导功能可以提高计算效率,并减少内存消耗。在这个示例中,我们在计算验证集上的损失值时,使用了with torch.no_grad():上下文,以提高计算效率
    ————————————————
    outputs.loss是模型在当前batch上的损失值。在这个示例中,我们使用了AutoModelForCausalLM模型,它是一个自回归语言模型,可以根据输入文本生成输出文本。在每个batch中,我们将输入文本和输出文本传递给模型,模型会根据输入文本生成输出文本,并计算输出文本与真实输出文本之间的交叉熵损失。这个交叉熵损失就是outputs.loss,我们可以使用这个损失来更新模型的参数,以使模型的输出更接近于真实输出

    d. 打印训练损失和验证损失
        print(f"Epoch {epoch+1} train loss: {avg_train_loss:.4f} val loss: {avg_val_loss:.4f}")
    e. 将训练损失和验证损失写入 TensorBoard
        # Write the training and validation losses to TensorBoard
        writer.add_scalar("Training loss", avg_train_loss, epoch)
        writer.add_scalar("Validation loss", avg_val_loss, epoch)
  10. 关闭 SummaryWriter
    # Close the SummaryWriter
    writer.close()

第五部分 ChatDoctor:基于LLaMA或BART做增强

Github上有一个ChatDoctor项目(ChatDoctor: A Medical Chat Model Fine-tuned on LLaMA Model using Medical Domain Knowledge)

核心思想就是基于Meta 的LLaMA进行各种微调,具体而言主要是以下4个步骤

  1. 首先使用 Stanford Alpaca 提供的 52K instruction-following 数据训练了一个通用的对话模型
    对于数据集构建这块,用的instruction, input, output的结构
    instruction 可以是类似'你现在的身份是医生,请以这个身份跟我对话',input,output 就是问答对

    实际微调时,使用的 6 个 A*100 GPU 进行,持续时间为 30 分钟
    训练过程中使用的超参数如下:总的batch size 192,学习率(learning rate)设为2e-5,总共3个epoch,最大序列长度512个token,warmup ratio 0.03,无权重衰减
    ————————————————
    至于斯坦福团队微调LLaMA 7B所用的52K指令数据咋来的呢,
    说来也有趣,它是通过Self-Instruct『Self-Instruct是来自华盛顿大学Yizhong Wang等22年12月通过这篇论文《SELF-INSTRUCT: Aligning Language Model with Self Generated Instructions》提出的』提示GPT3的API拿到的
    具体可以看下上一篇文章的3.1节:类ChatGPT开源项目的部署与微调
  2. 通过ChatGPT GenMedGPT-5k(将疾病数据库中的每条消息提示 ChatGPT API 以自动生成指令数据,且对ChatGPT API的提示包含了疾病和症状、药物的标准),和疾病数据库(包含大约 700 种疾病及其相关症状、医学检查和推荐药物)生成的『患者和医生之间的5K对话数据集』,再次微调模型

    数据格式继续用的instruction, input, output的结构,比如
          {
                "instruction": "If you are a doctor, please answer the medical questions based on the patient's description.",
                "input": "Doctor, I have been experiencing sudden and frequent panic attacks. I don't know what to do.",
                "output": "Well, based on what you're telling me, it sounds like you may be suffering from panic disorder. The best course of action is to start with psychotherapy and mental health counseling. Additionally, we should conduct an electrocardiogram to make sure that there are no physical issues causing your panic attacks. We will also need to perform a depression screen and a toxicology screen to rule out any other underlying causes. Finally, I would recommend a comprehensive psychological and psychiatric evaluation and therapy to help manage your symptoms."
          }
  3. 通过HealthCareMagic-100k(来自在线问答的医疗咨询服务网站HealthCareMagic.com)的患者和医生之间的真实对话进行第三轮微调
  4. 通过icliniq-15k的患者和医生之间的真实对话进行第四轮微调

当然,也有业内研究者基于BART-base,且利用他们自己公司的数据,微调出他们版本的ChatDoctor(截取自邓老师朋友圈)


第六部分 可商用的数据集与可商用的模型

有的朋友可能已经注意到了,我们已经部署/微调了不少模型,包括且不限于LLaMA、以及基于LLaMA做各种微调的Alpaca、Vicuna、BELLE、Chinese-LLaMA/Chinese-Alpaca,以及LLaMA的RLHF版:ChatLLaMA(英文版)、ColossalChat,甚至包括国内的ChatGLM等模型
但感到遗憾的是,目前这些模型 都不能商用,当然 对于其中有些模型不允许商用也能理解,比如Alpaca扩展数据集的方式毕竟是通过self-instruct技术提示OpenAI的API生成数据,如果去商用,则和OpenAI本身产生不可避免的直接商业冲突

很多模型不允许商用还只是一方面,另一方面,数据集也是很大的一个问题,既然通过self-instruct技术提示OpenAI的API生成数据没法商用,那什么样的数据集允许商用呢,本部分便为大家探讨可以商用的数据集和可以商用的模型

6.1 4.12发布的Dolly 2.0:数据集由数千名 Databricks 员工生成的超过 1.5 万条记录的语料库

2023年4 月 12 日,Databricks 发布了Dolly 2.0 ,表示这是业内第一个开源、遵循指令的 LLM,它在透明且免费提供的数据集上进行了微调,该数据集也是开源的,可用于商业目的。这意味着 Dolly 2.0 可用于构建商业应用程序,无需支付 API 访问费用或与第三方共享数据。

项目链接:https://huggingface.co/databricks/dolly-v2-12b
数据集:https://github.com/databrickslabs/dolly/tree/master/data

以下是它的一些特点

  • Dolly 2.0 是一个 120 亿参数的语言模型,它基于开源 EleutherAI pythia 模型系列
  • Databricks 还发布了 Dolly 2.0 在其上进行微调的数据集,称为 databricks-dolly-15k。这是由数千名 Databricks 员工生成的超过 1.5 万条记录的语料库。
    数据集包含7 项非常具体的任务:
    1 公开问答:例如「为什么人们喜欢喜剧电影?」或「法国的首都是什么?」在某些情况下,没有一个正确的答案,而在其他情况下,需要借助于整个世界的知识;
    2 封闭式问答:这些问题只用一段参考文献中的信息就可以回答。例如,给定维基百科中关于原子的一段,人们可能会问:「原子核中质子和中子的比例是多少?」;
    3 从维基百科中提取信息:在这里,标注者会从维基百科上复制一个段落,并从该段落中提取实体或其他事实信息,如重量或测量;
    4 总结维基百科上的信息:对于这一点,注释者从维基百科上提供了一段话,并被要求将其提炼为一个简短的摘要;
    5 集思广益:这项任务要求进行开放式的构思,并列出相关的可能选项。例如「这个周末我可以和我的朋友做哪些有趣的活动?」;
    6 分类:在这项任务中,标注者被要求对类别成员进行判断(例如,列表中的项目是动物、矿物还是蔬菜),或者判断一段短文的属性,例如电影评论的情绪;
    7 创意写作:这项任务将包括写一首诗或一封情书等内容。
  • 模型权重及微调数据集均可下载,要下载 Dolly 2.0 模型的权重,只需访问 Databricks Hugging Face 页面,并访问 databricks-labs 的 Dolly repo,下载 databricks-dolly-15k 数据集。

6.2 4.17发布的RedPajama开源数据集:1.2万亿token 容量5个T

2023年4月17日,RedPajama开源1.2万亿token数据集,帮助开发者训练类ChatGPT大语言模型。这也是目前类ChatGPT领域,全球最大的开源训练数据集(地址:https://huggingface.co/datasets/togethercomputer/RedPajama-Data-1T)
RedPajama完美复制了LLaMA模型上的1.2万亿训练数据集,由维基百科、GitHub、普通抓取、C4、图书、ArXiv(知名论文网站)、Stack Exchange七部分组成。完整数据集容量约5T,根据数据使用条例已经允许商业化

6.3 4.17发布的COIG:首个大规模、可商用的中文开源指令数据

https://hub.baai.ac.cn/view/25750

2023年4月17日,北京智源人工智能研究院第一期总共发布了 5 个子数据集,包括翻译指令、考试指令、人类价值观对齐指令、反事实修正多轮聊天、Leetcode指令,总计 191k  数据,聚焦中文语料、数据类型多样、经过了人工质检与修正、数据质量可靠,而且可以商用。

  • 对应的论文:Chinese Open Instruction Generalist: a Preliminary Release
    https://arxiv.org/pdf/2304.07987.pdf 
    对应的数据链接:
    https://huggingface.co/datasets/BAAI/COIG
    包括翻译指令、考试指令、人类价值观对齐指令、反事实修正多轮聊天、Leetcode指令,总计 191k  数据,聚焦中文语料、数据类型多样、经过了人工质检与修正、数据质量可靠,而且可以商用

6.4 4.19 发布的StableLM

2023年4月19日,Stability AI发布了一款名为StableLM的开源语言模型,旨在让基础AI技术更加透明、易于访问和支持。该模型可以生成文本和代码,并将支持一系列下游应用。它们展示了如何通过适当的训练,小型且高效的模型可以实现高性能
github链接:https://github.com/Stability-AI/StableLM
huggingface链接:https://huggingface.co/stabilityai/stablelm-base-alpha-7b

  • 参数规模上
    StableLM 模型的alpha版本有3B和7B参数,接着会推出14B和65B的模型。在CC BY-SA-4.0许可条款的约束下,开发者可以自由查看、使用并调整我们的StableLM基础模型,用于商业或研究目的。
  • 数据集上
    StableLM是在一个基于The Pile的新实验数据集上进行训练的,但其规模是The Pile的三倍,包含1.5万亿个内容标记。The Pile这个数据集包含的数据来源就有维基百科、Stack Exchange 和 PubMed。不过,Stability AI 在 the Pile 的基础上进行了扩展,所使用的数据集大小是标准 the Pile 的 3 倍。
  • 模型架构上
    StableLM使用了一些常用的模型架构,比如LSTM、Transformer等,还使用了一些先进的技术,比如自注意力机制、残差连接等,以提高模型的效果和精度
  • 应用上
    StableLM已经被广泛应用于自然语言处理任务,比如机器翻译、情感分析、文本分类和问答系统等,但StableLM 会说中文,但只会一点点(回复内容对应不上,语句也不通顺)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/462162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产CMS61850那些事-服务端

前面两篇文章国产CMS61850那些事-总述_LinuxZQ的博客-CSDN博客&#xff0c;cms61850那些事-实现_LinuxZQ的博客-CSDN博客分别对国产61850做了一些简单介绍和相关实现。本文接着给大家提供一款服务端demo&#xff0c;可以用来进行抓包等相关学习。 与之前分享的mms 61850一样&am…

如此这般,好吗?

让我们回顾一下 Linux 社区最新的愿景——推动去中心化的应用来解决发行版的碎片化。继上周的文章&#xff1a;“Snap、Flatpak 这种通吃所有发行版的打包方式真的有用吗&#xff1f;” 之后&#xff0c;一系列新观点浮出水面&#xff0c;其中可能包含关于这样应用是否有用的重…

Vmware安装Ubuntu出现 unable to find a medium containing a live file system

一、前言 由于未知的原因&#xff0c;使用Vmware安装Ubuntu的时候&#xff0c;总是遇到奇怪的问题。&#xff08;忘记截图了…&#xff09; 大致是&#xff1a; unable to find a medium containing a live file system找了几个帖子&#xff0c;参考1、参考2&#xff0c;但都…

GPT模型成功的背后用到了哪些以数据为中心的人工智能(Data-centric AI)技术?

人工智能&#xff08;Artificial Intelligence, AI&#xff09;最近取得了巨大的进展&#xff0c;特别是大语言模型&#xff08;Large Language Models, LLMs&#xff09;&#xff0c;比如最近火爆全网的ChatGPT和GPT-4。GPT模型在各项自然语言处理任务上有着惊人的效果。至于具…

JAVA Future类详解及Thread线程是如何运行Future类的

一、Future基本介绍 Future(java.util.concurrent Interface Future<V>)表示异步计算的结果。Future接口提供了检查计算是否完成、检查计算是否被取消、等待计算完成并获取计算结果等方法。 在并发编程中&#xff0c;我们经常用到非阻塞的模型&#xff0c;但继承thread类…

基于 SpringBoot+Vue+Java 的留守儿童系统的研究与实现(附源码,教程)

文章目录 1.研究背景2. 技术栈3.系统分析4系统设计5系统的详细设计与实现5.1系统功能模块5.2管理员功能模块 1.研究背景 以往的留守儿童爱心的管理&#xff0c;一般都是纸质文件来管理留守儿童爱心信息&#xff0c;传统的管理方式已经无法满足现代人们的需求&#xff1b;使用留…

[激光原理与应用-69]:激光器-器件 - 三极管

第1章 什么是三级管 三极管&#xff0c;全称应为半导体三极管&#xff0c;也称双极型晶体管、晶体三极管&#xff0c;是一种控制电流的半导体器件。其作用是把微弱电流信号放大成幅度值较大的电流信号&#xff0c;也用作无触点开关。电流信号经过电阻后&#xff0c;就变成了电压…

ARM嵌入式编译器编译优化选项 -O

Arm嵌入式编译器可以执行一些优化来减少代码量并提高应用程序的性能。不同的优化级别有不同的优化目标&#xff0c;不仅如此&#xff0c;针对某个目标进行优化会对其他目标产生影响。比如想减小生成的代码量&#xff0c;势必会影响到该代码的性能。所以优化级别总是这些不同目标…

Python中 re.findAll()、re.sub()、set()的使用

1. re.findall() re.findall()&#xff1a;函数返回包含所有匹配项的列表。返回string中所有与pattern相匹配的全部字串&#xff0c;返回形式为list / 数组。 由函数原型代码可知&#xff0c;findall() 函数存在三个参数&#xff1a; 1. pattern&#xff1a;正则表达式中的 ‘模…

RK3568平台开发系列讲解(驱动基础篇)IO 模型的分类

🚀返回专栏总目录 文章目录 一、阻塞 IO二、非阻塞 IO三、IO 多路复用四、信号驱动五、异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将针对IO模型进行分类。 假设有这样一个场景,从磁盘中循环读取 100M 的数据并处理,磁盘读取 100M 需要花费 20 秒的…

HR真的会嫌弃跳槽频繁的测试人员吗?

我们都知道&#xff1a;“跳槽≠涨薪”&#xff0c;但是对于测试人来说&#xff0c;跳槽绝哔能和升职加薪画上等号啊。 所以&#xff0c;有很多测试人在一家公司常常待不到1年&#xff0c;就另觅新东家&#xff0c;来借此达成升职加薪的目的。 有人提出质疑&#xff1a;为什么测…

【老王读SpringMVC-2】url 与 controller method 的映射关系注册

上文提到&#xff0c;如果我们自己要实现 spring mvc 框架的话&#xff0c;大致需要实现如下功能&#xff1a; 0、将 url 与 Controller method 的对应关系进行注册1、通过请求的 url 找到 Controller method (即 url 与 Controller method 的映射)2、将请求参数进行绑定&…

【python中的迭代器了解一下?】

基本说明 在 Python 中&#xff0c;迭代器是一种用于遍历可迭代对象&#xff08;如列表、元组、字符串等&#xff09;的方式。迭代器提供了一种简洁而有效的方法来遍历序列&#xff0c;而不需要创建临时变量或使用循环语句。 在 Python 中&#xff0c;迭代器是一个实现了 __i…

没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统)

环境: DELL7080台式机 Ubuntu20.04 两块硬盘 问题描述: 没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统) 解决方案: 一、下载镜像文件 1.上线自行下载安装镜像文件 二、分区 1.win10下磁盘管理压缩2个分区一个10G左右制作安装盘,一个几百G安装系统使用 10…

【Android入门到项目实战-- 7.1】—— 如何使用通知?

目录 一、创建通知的步骤 1、创建一个NotificationManager实例 2、使用一个Builder构造器来创建Notification对象 3、设置标题、文字、时间和图标等信息 4、显示通知 二、通知实例演示 三、实现通知的点击效果 1、PendingIntent 什么是PendingIntent&#xff1f; 如何使…

后台-husky提交代码规范使用

husky是一个git hook工具&#xff0c;可以帮助我们触发git提交的各个阶段&#xff1a;pre-commit、commit-msg、pre-push 1.如何使用husky呢&#xff1f; npx husky-init && npm installWindows安装不成功试试npx husky-init && npm install 2.git commit规范…

线索二叉树的前序遍历

线索二叉树原理 遍历二叉树的其实就是以一定规则将二叉树中的结点排列成一个线性序列&#xff0c;得到二叉树中结点的先序序列、中序序列或后序序列。这些线性序列中的每一个元素都有且仅有一个前驱结点和后继结点。 但是当我们希望得到二叉树中某一个结点的前驱或者后继结点时…

计算机组成原理---第 6 章总线系统

一、总线的概念和结构形态 总线的基本概念 ⑴概述 总线是构成计算机系统的互联机构&#xff0c;是多个系统功能部件之间进行数据传送的公共通路。 ⑵ 分类 总线的分类方式有很多&#xff1a;如被分为外部总线和内部总线、系统总线和非系统总线、片内总线和PCB板级总线、串行…

VS2022+opengl环境配置

glfw下载Download | GLFW glad下载https://glad.dav1d.de/ Freeglut下载 https://freeglut.sourceforge.net/index.php#download cmake下载 Download | CMake glfwFreeglut 用cmake配置Freeglut&#xff0c;生成vs工程项目&#xff0c;用vs2022编译项目&#xff0c;生成fr…

27.Spring的事务控制

目录 一、编程式事务控制相关对象。 &#xff08;1&#xff09;事务管理器。 &#xff08;2&#xff09;事务定义信息对象&#xff08;如隔离级别、传播行为&#xff09;。 &#xff08;3&#xff09;事务状态对象。 &#xff08;4&#xff09; 知识要点。 二、声明式事务…