• GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(二)


    GPT实战系列-如何使用P-Tuning本地化训练ChatGLM2等LLM模型?(二)


    P-Tuning v2 将 ChatGLM2-6B 模型需要微调的参数量,减少到原来的 0.1%,再通过模型量化、Gradient Checkpoint 等方法,最低只需要 7GB 显存即可运行。

    本文试图分析程序结构和代码,解释序列转换生成模型的微调训练。为了篇幅不要过长,分两篇文章解读,本文解读训练代码。框架概述请看前篇文章:GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(一)

    对相关的内容感兴趣,也可以到GPT专栏里的文章看看。如果没有你感兴趣的,请留言,后续一起讨论。
    GPT专栏:https://blog.csdn.net/alex_starsky/category_12467518.html

    下面解读ptuning目录下的main.py代码。

    1.训练参数配置传递

    训练环节中,通过命令行配置参数(sh脚本),然后通过HfArgumentParser方法,把配置参数指定到模型,数据和训练的参数类中。通过参数解析器parser,进一步分类为模型参数,数据参数和训练超参数。

    # 新版本的transformers中的ner没有采用传统的parser模块,利用HfArgumentParser方法,将参数类转化为argparse参数,以便于在命令行中指定他们。
    # ModelArguments类为model/config/tokenizer涉及的参数。ModelArguments类 中包含的是关于模型的属性,如model_name,config_name,tokenizer_name等,类在run.py文件中定义;
    # DataTrainingArguments类 为训练、测试数据集操作涉及到的参数。DataTrainingArguments类 中包含的是关于微调数据的属性,如task_name,data_dir等,类在transformers/data/datasets/glue.py文件中定义;
    # TrainingArguments中包含的是关于微调过程的参数,如batch_size,learning_rate等参数,类在transformers/training_args.py中定义。
    
    parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments))
    # 通过参数解析器parser,进一步分类为模型参数,数据参数和训练超参数。    
    # 训练时输入python run_ner.py *******.json,即从.json中读取参数。
    # 当sys.argv参数为2时,此时sys.argv[0]为自己本身,即"run_ner.py",sys.argv[1]为json文件
    if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):
        model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))
    else:
        model_args, data_args, training_args = parser.parse_args_into_dataclasses()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果参数过多,或者需要保存参数,采用json文件格式,比如:

    {
        "do_train": true,
        "train_file": "dataset/AdvertiseGen/train.json",
        "validation_file": "dataset/AdvertiseGen/dev.json",
        "preprocessing_num_workers": 10,
        "prompt_column": "content",
        "response_column": "summary",
        "overwrite_cache": true,
        "model_name_or_path": "/Users/andy/Desktop/LLM/model/chatglm2-6b",
        "output_dir": "output/adgen-chatglm2-6b-lora_version",
        "overwrite_output_dir": true,
        "max_source_length": 64,
        "max_target_length": 128,
        "per_device_train_batch_size": 1,
        "per_device_eval_batch_size": 1,
        "gradient_accumulation_steps": 16,
        "predict_with_generate": true,
        "max_steps": 3000,
        "logging_steps": 10,
        "save_steps": 100,
        "learning_rate": 2e-5,
        "lora_r": 32,
        "model_parallel_mode": true,
        "output_dir": "output"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    训练过程的日志排版,打印信息等相关设置

    #设置日志相关,排版格式,日期格式
    # Setup logging
    logging.basicConfig(
        format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
        datefmt="%m/%d/%Y %H:%M:%S",
        handlers=[logging.StreamHandler(sys.stdout)],
    )
    #设置打印信息
    if training_args.should_log:
        # The default of training_args.log_level is passive, so we set log level at info here to have that default.
        transformers.utils.logging.set_verbosity_info()
    
    #设置日志信息等级,transformer日志配置
    log_level = training_args.get_process_log_level()
    logger.setLevel(log_level)
    # datasets.utils.logging.set_verbosity(log_level)
    transformers.utils.logging.set_verbosity(log_level)
    transformers.utils.logging.enable_default_handler()
    transformers.utils.logging.enable_explicit_format()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.训练前准备

    训练前的准备工作,包括预处理,训练数据集、验证数据集、测试数据集等参数配置

    训练数据准备

    # 加载数据集,训练文件,验证文件,测试文件,文件名,文件类型(扩展名)
        # Load dataset
        data_files = {}
        if data_args.train_file is not None:
            data_files["train"] = data_args.train_file
            extension = data_args.train_file.split(".")[-1]
        if data_args.validation_file is not None:
            data_files["validation"] = data_args.validation_file
            extension = data_args.validation_file.split(".")[-1]
        if data_args.test_file is not None:
            data_files["test"] = data_args.test_file
            extension = data_args.test_file.split(".")[-1]
    
        # 加载训练、验证、测试数据文件,cache目录
        raw_datasets = load_dataset(
            extension,
            data_files=data_files,
            cache_dir=model_args.cache_dir,
            use_auth_token=True if model_args.use_auth_token else None,
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    训练模型的配置

    预训练模型加载,序列长度,序列前缀处理

    # 加载模型配置(模型架构),预训练模型
    # Load pretrained model and tokenizer
    config = AutoConfig.from_pretrained(model_args.model_name_or_path, trust_remote_code=True)
    config.pre_seq_len = model_args.pre_seq_len
    config.prefix_projection = model_args.prefix_projection
    
    • 1
    • 2
    • 3
    • 4
    • 5

    加载分词器,对自然语言序列进行分解,分词处理

    # 分词器
    tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, trust_remote_code=True)
    
    
    • 1
    • 2
    • 3

    预训练模型的加载,有两种方式,一种是把过程加载方式,checkpoint,另一种是整合为一个模型bin格式,然后直接加载。

    # 含有训练过程信息的checkpoint模型的加载模式,如ptuning训练中间结果,需要从pytorch_model.bin加载字典,
    # 或者直接加载模型
    if model_args.ptuning_checkpoint is not None:
        # Evaluation
        # Loading extra state dict of prefix encoder
        model = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True)
        prefix_state_dict = torch.load(os.path.join(model_args.ptuning_checkpoint, "pytorch_model.bin"))
        new_prefix_state_dict = {}
        for k, v in prefix_state_dict.items():
            if k.startswith("transformer.prefix_encoder."):
                new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
        model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
    else:
        model = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    训练量化精度配置
    加载模型后,考虑到模型大小,占用显存大小,以及训练速度,需要配置模型数据精度,一般分为float32为浮点,f16半浮点精度,bf16半浮点精度,及int8,int4等整型8,4位精度。

    # 量化处理,f16半浮点精度,即将pytorch默认的32位浮点型都改成16位浮点型。
    if model_args.quantization_bit is not None:
        print(f"Quantized to {model_args.quantization_bit} bit")
        model = model.quantize(model_args.quantization_bit)
    if model_args.pre_seq_len is not None:
        # P-tuning v2
        model = model.half()
        model.transformer.prefix_encoder.float() #前缀编码器
    else:
        # Finetune
        model = model.float()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    数据预处理
    数据集预处理,包括训练数据集,验证数据集,测试数据集。

    prefix = data_args.source_prefix if data_args.source_prefix is not None else ""
    
        # 数据集预处理,分词处理
        # Preprocessing the datasets.
        # We need to tokenize inputs and targets.
        if training_args.do_train:
            column_names = raw_datasets["train"].column_names
        elif training_args.do_eval:
            column_names = raw_datasets["validation"].column_names
        elif training_args.do_predict:
            column_names = raw_datasets["test"].column_names
        else:
            logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.")
            return
    
        # 输入数据(prompt),标注目标数据(response),上下文历史会话(history)
        # Get the column names for input/target.
        prompt_column = data_args.prompt_column
        response_column = data_args.response_column
        history_column = data_args.history_column
        
        # 最大模板长度
        # Temporarily set max_target_length for training.
        max_target_length = data_args.max_target_length
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.训练参数配置

    训练数据集参数配置,最大训练样本数,数据预处理函数,GPU显卡数,批处理,cache处理等配置

    # 训练前配置和数据集处理,训练,训练数据,最大训练样本数,
        if training_args.do_train:
            if "train" not in raw_datasets:
                raise ValueError("--do_train requires a train dataset")
            train_dataset = raw_datasets["train"]
            if data_args.max_train_samples is not None:
                max_train_samples = min(len(train_dataset), data_args.max_train_samples)
                train_dataset = train_dataset.select(range(max_train_samples))
            with training_args.main_process_first(desc="train dataset map pre-processing"):
                train_dataset = train_dataset.map(
                    preprocess_function_train,
                    batched=True,
                    num_proc=data_args.preprocessing_num_workers,
                    remove_columns=column_names,
                    load_from_cache_file=not data_args.overwrite_cache,
                    desc="Running tokenizer on train dataset",
                )
            print_dataset_example(train_dataset[0])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    同样方式,配置验证数据集,测试数据集参数。

        # 训练前验证评价的配置和数据集处理,验证评价
        if training_args.do_eval:
            max_target_length = data_args.val_max_target_length
            if "validation" not in raw_datasets:
                raise ValueError("--do_eval requires a validation dataset")
            eval_dataset = raw_datasets["validation"]
            #最大验证样本数
            if data_args.max_eval_samples is not None:
                max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples)
                eval_dataset = eval_dataset.select(range(max_eval_samples))
            #
            with training_args.main_process_first(desc="validation dataset map pre-processing"):
                eval_dataset = eval_dataset.map(
                    preprocess_function_eval,
                    batched=True,
                    num_proc=data_args.preprocessing_num_workers,
                    remove_columns=column_names,
                    load_from_cache_file=not data_args.overwrite_cache,
                    desc="Running tokenizer on validation dataset",
                )
            print_dataset_example(eval_dataset[0])
    
        # 训练前预测的配置和数据集处理,预测
        if training_args.do_predict:
            max_target_length = data_args.val_max_target_length
            if "test" not in raw_datasets:
                raise ValueError("--do_predict requires a test dataset")
            predict_dataset = raw_datasets["test"]
            #最大预测样本
            if data_args.max_predict_samples is not None:
                max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples)
                predict_dataset = predict_dataset.select(range(max_predict_samples))
            #数据集重映射
            with training_args.main_process_first(desc="prediction dataset map pre-processing"):
                predict_dataset = predict_dataset.map(
                    preprocess_function_eval,
                    batched=True,
                    num_proc=data_args.preprocessing_num_workers,
                    remove_columns=column_names,
                    load_from_cache_file=not data_args.overwrite_cache,
                    desc="Running tokenizer on prediction dataset",
                )
            print_dataset_example(predict_dataset[0])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    数据分词,类型转换,pad等数据预处理操作

    #训练准备,模型,数据加载
        # Data collator
        label_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_id
        data_collator = DataCollatorForSeq2Seq(
            tokenizer,
            model=model,
            label_pad_token_id=label_pad_token_id,
            pad_to_multiple_of=None,
            padding=False
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.训练对象,seq2seq训练

    序列训练参数配置,生成的length,beams配置,

    # 序列训练参数配置,如有配置则重置解码参数
        # Override the decoding parameters of Seq2SeqTrainer
        training_args.generation_max_length = (
            training_args.generation_max_length
            if training_args.generation_max_length is not None
            else data_args.val_max_target_length
        )
        training_args.generation_num_beams = (
            data_args.num_beams if data_args.num_beams is not None else training_args.generation_num_beams
        )
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    训练器参数配置,预训练模型,训练超参数,相关数据集。分词器,训练度量器等过程参数配置。

    #初始化训练参数,配置模型,训练参数,训练数据,分词器,数据加载工具,过程度量
        # Initialize our Trainer
        trainer = Seq2SeqTrainer(
            model=model,
            args=training_args,
            train_dataset=train_dataset if training_args.do_train else None,
            eval_dataset=eval_dataset if training_args.do_eval else None,
            tokenizer=tokenizer,
            data_collator=data_collator,
            compute_metrics=compute_metrics if training_args.predict_with_generate else None,
            save_changed=model_args.pre_seq_len is not None
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    5.执行训练

    执行训练过程,模型保存方式,过程度量及状态保存。

    # 训练执行过程
        # Training
        if training_args.do_train:
            checkpoint = None
            if training_args.resume_from_checkpoint is not None:
                checkpoint = training_args.resume_from_checkpoint
            # elif last_checkpoint is not None:
            #     checkpoint = last_checkpoint
            model.gradient_checkpointing_enable()
            model.enable_input_require_grads()
            train_result = trainer.train(resume_from_checkpoint=checkpoint)
            # trainer.save_model()  # Saves the tokenizer too for easy upload
    
            metrics = train_result.metrics
            max_train_samples = (
                data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset)
            )
            metrics["train_samples"] = min(max_train_samples, len(train_dataset))
    
            trainer.log_metrics("train", metrics)
            trainer.save_metrics("train", metrics)
            trainer.save_state()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    6.训练模型评估

    训练后,数据集评估模型效果,预测处理。

    #训练结束后评估
        # Evaluation
        results = {}
        max_seq_length = data_args.max_source_length + data_args.max_target_length + 1
        # 训练评估
        if training_args.do_eval:
            logger.info("*** Evaluate ***")
            metrics = trainer.evaluate(metric_key_prefix="eval", do_sample=True, top_p=0.7, max_length=max_seq_length, temperature=0.95)
            max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset)
            metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset))
    
            trainer.log_metrics("eval", metrics)
            trainer.save_metrics("eval", metrics)
    
        # 训练预测
        if training_args.do_predict:
            logger.info("*** Predict ***")
            predict_results = trainer.predict(predict_dataset, metric_key_prefix="predict", max_length=max_seq_length, do_sample=True, top_p=0.7, temperature=0.95)
            metrics = predict_results.metrics
            max_predict_samples = (
                data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset)
            )
            metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset))
    
            trainer.log_metrics("predict", metrics)
            trainer.save_metrics("predict", metrics)
    
            if trainer.is_world_process_zero():
                if training_args.predict_with_generate:
                    predictions = tokenizer.batch_decode(
                        predict_results.predictions, skip_special_tokens=True, clean_up_tokenization_spaces=True
                    )
                    predictions = [pred.strip() for pred in predictions]
                    labels = tokenizer.batch_decode(
                        predict_results.label_ids, skip_special_tokens=True, clean_up_tokenization_spaces=True
                    )
                    labels = [label.strip() for label in labels]
                    output_prediction_file = os.path.join(training_args.output_dir, "generated_predictions.txt")
                    with open(output_prediction_file, "w", encoding="utf-8") as writer:
                        for p, l in zip(predictions, labels):
                            res = json.dumps({"labels": l, "predict": p}, ensure_ascii=False)
                            writer.write(f"{res}\n")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    依赖

    中文分词器,中文评价指标,数据集管理

    pip install rouge_chinese nltk jieba datasets
    
    • 1

    依赖模块解读

    transformers提供数千个预先训练好的模型来执行不同模式的任务,如文本、视觉和音频。

    transformer提供api,可以快速下载,并在给定文本上使用这些预训练的模型,在您自己的数据集上对它们进行微调,然后在Huggingface的模型中心上与社区共享。同时,每个定义架构的python模块都是完全独立的,可以进行修改以进行快速研究实验。

    • AutoConfig模块,模型的配置类是指定模型的构建方式。配置指定模型的属性,如隐藏层或注意力头的数量。当从自定义配置类初始化模型时,将从头开始。模型属性是随机初始化的,在使用模型得到有意义的结果之前,需要对模型进行训练。导入AutoConfig,然后加载要修改的预训练模型。在AutoConfig.from_pretrained()中,可以指定要更改的属性,例如注意力头的数量。
    • AutoModel加载一个预训练模型,Transformers提供简单统一的方法来加载。
    • AutoTokenizer加载的一个自动分词器。
    • DataCollatorForSeq2Seq 是在进行序列生成任务时(QA、文本概括等)使用的数据收集器,需要模型的输出是一个序列。该数据收集器不仅会动态的填充数据的数据,而且也会填充数据对应的标签。
    • HfArgumentParser可以将类对象中的实例属性转换成转换为解析参数。必须注意的是,这里的类对象必须是通过@dataclass()创建的类对象。并且通过HfArgumentParser创建的解析参数,都是可选参数。
    # Transformers 工具已经帮我们封装了用于训练文本生成模型的 Seq2SeqTrainer 类,无需我们自己再去定义损失函数与优化方法了。
    import transformers
    from transformers import (
        AutoConfig,
        AutoModel,
        AutoTokenizer,
        DataCollatorForSeq2Seq,
        HfArgumentParser,
        Seq2SeqTrainingArguments,
        set_seed,
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Trainer 所有模型都是标准的torch.nn.Module,因此可以在任何典型的训练循环中使用它们。虽然您可以编写自己的训练迭代器,但Transformers为PyTorch提供了Trainer类,其中包含基本的训练循环,并添加了额外的功能,如分布式训练、混合精度等。

    • Seq2SeqTrainingArguments 设置训练参数。
    • Seq2SeqTrainer 序列类的训练迭代器
    # Seq2SeqTrainingArguments 设置训练参数。
    # 例如,下面设置训练参数,配置学习率为2e-5,训练时batch大小为8,验证时为batch大小32,训练轮数为5,权重衰减大小为0.01,输出文件夹为model_for_seq2seqlm,日志记录的步长为10,即10个batch记录一次;评估策略为训练完一个epoch之后进行评估,模型保存策略同上,设置训练完成后加载最优模型,并指定最优模型的评估指标为rougeL,最后,需要指定predict_with_generate参数值为True。
    # training_args = Seq2SeqTrainingArguments(
    #     learning_rate=3e-5,
    #     per_device_train_batch_size=8,
    #     per_device_eval_batch_size=32,
    #     num_train_epochs=5,
    #     weight_decay=0.01,
    #     output_dir="model_for_seq2seqlm",
    #     logging_steps=10,
    #     evaluation_strategy = "epoch",
    #     save_strategy = "epoch",
    #     load_best_model_at_end=True,
    #     metric_for_best_model="rougeL",
    #     predict_with_generate=True   # 训练最后会调用generate方法进行生成
    # )
    
    from trainer_seq2seq import Seq2SeqTrainer
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • ModelArguments模型参数,
    • DataTrainingArguments数据集操作涉及的参数
    #ModelArguments类为model/config/tokenizer涉及的参数
    #DataTrainingArguments类为数据涉及到的参数
    from arguments import ModelArguments, DataTrainingArguments
    
    • 1
    • 2
    • 3

    数据集的预处理

    ADGEN数据集任务的数据形式,输入(content),生成输出(summary)

    {
        "content": "类型#上衣*版型#宽松*版型#显瘦*图案#线条*衣样式#衬衫*衣袖型#泡泡袖*衣款式#抽绳",
        "summary": "这件衬衫的款式非常的宽松,利落的线条可以很好的隐藏身材上的小缺点,穿在身上有着很好的显瘦效果。领口装饰了一个可爱的抽绳,漂亮的绳结展现出了十足的个性,配合时尚的泡泡袖型,尽显女性甜美可爱的气息。"
    }
    
    • 1
    • 2
    • 3
    • 4

    觉得有用 点个赞 + 收藏 吧

    End


    GPT专栏文章:
    GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(一)

    GPT实战系列-ChatGLM3本地部署CUDA11+1080Ti+显卡24G实战方案

    GPT实战系列-ChatGLM2模型的微调训练参数解读

    GPT实战系列-如何用自己数据微调ChatGLM2模型训练

    GPT实战系列-ChatGLM2部署Ubuntu+Cuda11+显存24G实战方案

    GPT实战系列-Baichuan2本地化部署实战方案

    决策引擎专栏:
    Falcon构建轻量级的REST API服务

    决策引擎-利用Drools实现简单防火墙策略

  • 相关阅读:
    牛客网Verilog刷题 | 快速入门-基础语法
    【BP-Adaboost预测】基于BP神经网络的Adaboost的单维时间序列预测研究(Matlab代码实现)
    2010年08月04日 Go生态洞察:Defer, Panic, Recover 深度解析
    html form拼凑表单触发后端api
    第五章:Python的集合(下)
    详细javaweb基础
    Linux安装Phantomjs
    可编程数据平面(论文阅读)
    sql主从复制搭建
    操作系统——进程同步、进程互斥及其实现方式、信号量机制
  • 原文地址:https://blog.csdn.net/Alex_StarSky/article/details/83722227