掘金 人工智能 07月09日 10:20
Bert进行LoRA微调详细流程(附代码)
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍如何使用LoRA(Low-Rank Adaptation)技术对预训练的BERT模型进行微调,以完成句子情感分类任务。通过LoRA,可以在保持预训练模型大部分参数不变的情况下,仅微调少量参数,从而实现高效的迁移学习。文章详细阐述了数据加载、预处理、模型构建、LoRA配置、训练、评估和推理等关键步骤,并提供了代码示例和参数调优建议。

💡LoRA技术的核心在于在预训练模型的某些层中插入低秩矩阵,仅微调这些新增的低秩矩阵,从而实现参数高效的微调。这种方法大大减少了需要更新的参数量,降低了计算和存储成本。

🔑数据集的处理包括加载CSV文件、清洗文本、标签编码、构建Hugging Face Dataset,以及划分训练集和验证集。其中,文本清洗是确保模型性能的关键步骤,而标签编码则将文本标签转换为模型可处理的数值。

🛠️模型构建部分,首先加载预训练的BERT模型和分词器。然后,通过LoRA配置,指定LoRA的参数,如低秩矩阵的秩、缩放因子和目标模块。最后,使用`prepare_model_for_kbit_training`和`get_peft_model`函数将LoRA模块插入到模型中。

🚀训练过程使用Hugging Face Trainer封装,包括定义训练参数、创建Trainer、执行训练和保存模型。在训练过程中,需要关注学习率、batch size、epoch数等超参数的设置,以及评估指标的选择,以优化模型性能。

✅推理阶段,微调后的模型可以直接应用于文本情感分类任务。使用pipeline函数加载模型和分词器,即可对新的句子进行情感预测,并获得预测结果和置信度。

背景说明: 基于 bert-base-uncased模型进行LoRA微调,完成句子情感分类任务,判断句子是属于哪类情感。

数据样例(部分):

sentence,emotioni reached my goal that i realized the anticipated feelings of accomplishment and satisfaction i had been longing for didnt occur as quickly as i would have imagined,lovei go so far in this need where even if i am not around people regularly i will get really depressed and start feeling very alone and sad,sadi said she could do nothing right and she was feeling irritable,angerim feeling threatened i told him with my palms raised,feari feel that i have been given much and i want to be faithful of following through on what i feel like is expected of me as a steward,lovei could feel their curious eyes on me as i walked through each time,suprisei feel enraged and terrified and insane,anger

两列,包括句子(sentence)和标签(emotion) 一共有六种情绪分类(6分类问题):anger,fear,joy,love,sad,suprise

样本总数:81747 条

各类标签样本数分布:fear 13625suprise 13625joy 13625love 13624sad 13624anger 13624

LoRA 微调整体流程(结合代码讲解):

步骤说明关键代码
1. 加载数据并预处理读取CSV,清洗文本、编码标签load_dataset_from_csv()LabelEncoder()
2. 构建HF Dataset转换为 HuggingFace Dataset 格式,并分train/testcreate_hf_dataset()
3. 加载预训练模型从本地加载Transformer模型及其分词器AutoTokenizer.from_pretrained + AutoModelForSequenceClassification.from_pretrained
4. 构建LoRA配置设置LoRA结构(如r、alpha、target_modules等)LoraConfig(...)
5. 准备模型进行PEFT训练冻结模型参数、插入LoRA模块,准备量化友好训练prepare_model_for_kbit_training() + get_peft_model()
6. Tokenize数据用tokenizer将原始文本转为模型输入格式tokenize_dataset()
7. 定义训练参数HuggingFace Trainer训练参数(如学习率、batch size)TrainingArguments(...)
8. 创建Trainer训练器包装模型、数据、评估指标Trainer(...)
9. 执行训练过程实际运行LoRA微调trainer.train()
10. 保存模型与验证推理保存模型及tokenizer,并用pipeline测试效果trainer.save_model() + pipeline(...)

关键代码详解:

1. 准备LoRA配置

peft_config = LoraConfig(    task_type=TaskType.SEQ_CLS,      # 任务类型为文本分类    inference_mode=False,    r=8,                             # LoRA 低秩矩阵维度    lora_alpha=32,                   # 缩放因子    lora_dropout=0.1,                # Dropout    target_modules=["query", "key", "value", "dense"]  # 插入LoRA的目标模块)

解释:指定将LoRA插入Transformer中的 attentiondense 层,使得在训练过程中只更新这些参数,而主模型参数保持冻结。


2. 模型准备:冻结参数 + 插入LoRA

model = prepare_model_for_kbit_training(model)  # 冻结LayerNorm之外的大部分参数,适用于量化model = get_peft_model(model, peft_config)      # 注入LoRA Adapter模块

解释

1. prepare_model_for_kbit_training(model)

功能说明: 该函数用于准备模型以支持 k-bit 训练(如 8-bit 或 4-bit 量化训练)。 虽然当前脚本中并未启用量化(QAT/QLoRA),但调用此函数为后续可能的量化训练做好结构上的准备。

具体作用:

⚠️ 注意:即使未开启量化,该函数仍然可以安全调用,并对 LoRA 微调提供支持。(在当前未使用量化,如 8-bit 或 4-bit 训练的情况下,可以安全地删除这行代码)

2. get_peft_model(model, peft_config)

功能说明: 根据提供的 peft_config 配置,将模型包装成一个支持参数高效微调(PEFT)的模型,即注入 LoRA 模块。

具体作用:

即使不调用 prepare_model_for_kbit_training,只要调用了 get_peft_model(...),LoRA 微调就已经完全生效了。


3. Huggingface Trainer 封装训练过程

trainer = Trainer(    model=model,    args=training_args,    train_dataset=encoded_train_dataset,    eval_dataset=encoded_eval_dataset,    tokenizer=tokenizer,    compute_metrics=compute_metrics)

解释:用官方 Trainer 封装了训练流程,只会优化LoRA插入的可训练参数。


4. 推理阶段依然适用

classifier = pipeline(    task="text-classification",    model=model,    tokenizer=tokenizer,    device=device_index)result = classifier(test_sentence)

解释:LoRA训练后模型依然与 HuggingFace pipeline 推理接口兼容。


参数调优建议

一、LoRA 配置相关参数

这些参数直接影响适配器的表达能力和训练效率。

参数默认值建议调整方向说明
r8尝试 16, 32控制低秩矩阵的秩,增大可增强适配器表达能力,但也会增加训练参数。
lora_alpha32可按比例增大至 64128缩放因子,通常与 r 成比例设置,影响 LoRA 的学习强度。
lora_dropout0.1可尝试 0.2, 0.3防止过拟合,适当增加有助于提高泛化能力。
target_modules["query", "key", "value", "dense"]添加 "intermediate.dense" 等模块可尝试插入更多层以获得更强的适配效果。

二、训练超参数(TrainingArguments)

这些参数控制训练过程的整体行为。

参数默认值建议调整方向说明
learning_rate2e-5可尝试 5e-5, 1e-4学习率是影响收敛速度和精度的关键因素,建议尝试不同数值。
num_train_epochs3可增至 5~10增加训练轮数可能带来更好的性能,但需配合早停机制。
per_device_train_batch_size16可尝试 8, 32太大会导致显存不足,太小则训练不稳定。根据GPU容量调整。
weight_decay0.01可尝试 0.001, 0.05正则化项,防止过拟合。
warmup_steps100根据总步数适当增加控制学习率预热阶段长度,有助于稳定训练。
gradient_accumulation_steps1可设为 2~4在 batch size 受限时模拟更大的 batch,提高梯度稳定性。
fp16False若硬件支持可开启使用混合精度训练,加快训练速度并减少显存占用。

三、评估与早停机制

参数默认值建议调整方向说明
eval_strategy"epoch"可改为 "steps" 并设定具体间隔更细粒度地监控模型表现,及时发现过拟合或欠拟合。
metric_for_best_model"accuracy"可换为 "f1""loss"对于类别不平衡的数据集,使用 F1-score 更合理。
load_best_model_at_endTrue保持不变确保最终加载的是验证集上表现最好的模型。

推荐优先调整顺序

    学习率 (learning_rate) 和 epoch 数 (num_train_epochs)LoRA秩 (r) 和缩放系数 (lora_alpha)Dropout (lora_dropout) 和权重衰减 (weight_decay)批次大小 (batch_size) 和梯度累积 (gradient_accumulation_steps)评估指标 (metric_for_best_model) 和评估频率 (eval_strategy)目标模块 (target_modules) 扩展

提示:每次只调整一个或两个参数进行实验,记录训练日志和验证结果,以便分析哪组配置对性能提升最有效。也可以结合 WandB 或 TensorBoard 进行可视化跟踪。


可视化的LoRA流程图简化版

[原始预训练模型]        │        ▼[prepare_model_for_kbit_training]  → 冻结主干参数,准备LoRA        │        ▼[get_peft_model + LoraConfig]      → 注入低秩LoRA模块        │        ▼[Trainer微调LoRA模块参数]        │        ▼[保存LoRA+模型结构] + 推理pipeline

微调脚本带详细注释的完整代码 finetune_peft_lora.py(不能直接跑)

# -*- coding: utf-8 -*-"""基于PEFT-LoRA的参数高效微调脚本本脚本使用PEFT库中的LoRA模块,对预训练Transformer模型进行轻量化微调(仅训练部分Adapter层),可显著减少训练参数数量和GPU显存使用。当前未执行QAT/QLoRA量化,仅为后续量化流程做结构准备。"""import osimport numpy as npimport pandas as pdimport torchimport torch.nn as nnfrom sklearn.metrics import accuracy_score, classification_reportfrom sklearn.preprocessing import LabelEncoderfrom sklearn.model_selection import train_test_splitfrom datasets import Datasetfrom transformers import (    AutoTokenizer,    AutoModelForSequenceClassification,    Trainer,    TrainingArguments,    pipeline)from peft import (    LoraConfig,    get_peft_model,    TaskType,    prepare_model_for_kbit_training)from src.utils.config import Configfrom src.utils.logger import setup_loggerfrom tqdm import tqdm# 获取项目根目录project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../'))# 强制指定设备if torch.cuda.is_available():    torch_device = 'cuda'    device_index = 0else:    torch_device = 'cpu'    device_index = -1# 加载QAT配置文件config_path = os.path.join(project_root, 'configs/finetune_lora.yaml')config = Config(config_path)# 初始化日志log_dir = os.path.join(project_root, 'logs/finetune')os.makedirs(log_dir, exist_ok=True)log_file = os.path.join(log_dir, 'finetune_peft_lora.log')logger = setup_logger(log_file=log_file)def preprocess_text(text):    """    文本预处理函数    对输入的文本进行清洗和标准化处理,确保无缺失值且格式统一。    参数:        text (str or pd.Series): 需要处理的原始文本数据    返回:        str: 清洗后的字符串,若输入为缺失值则返回空字符串    """    if pd.isna(text):        return ""    return str(text).strip()def load_dataset_from_csv(data_path):    """    从指定路径加载CSV文件并进行预处理    功能:        - 读取CSV格式的数据集文件        - 对文本字段执行预处理(调用 [preprocess_text]        - 移除包含缺失值的行(仅保留 'sentence' 和 'emotion' 字段非空的记录)        - 记录加载完成后的样本总数和情绪标签分布情况    参数:        data_path (str): CSV文件的完整路径    返回:        pd.DataFrame: 包含两列(sentence, emotion)且已清洗的DataFrame数据    """    logger.info(f"加载数据文件: {data_path}")    df = pd.read_csv(data_path)    df['sentence'] = [preprocess_text(x) for x in tqdm(df['sentence'], desc='文本预处理')]    df = df.dropna(subset=['sentence', 'emotion']).reset_index(drop=True)    logger.info(f"加载完成,共 {len(df)} 条有效样本")    logger.info(f"标签分布:\n{df['emotion'].value_counts()}")    return dfdef create_hf_dataset(df):    """    将输入的DataFrame转换为 HuggingFace Dataset 格式,并划分训练集和验证集    功能:        - 将原始 DataFrame 转换为 HuggingFace 的 Dataset 对象        - 按照 8:2 的比例进行训练集与验证集的划分(固定随机种子以保证可复现性)        - 分别将训练集和验证集也转换为 HuggingFace Dataset 格式    参数:        df (pd.DataFrame): 包含文本(sentence)和标签(label)列的清洗后数据    返回:        tuple: 包含三个元素的元组            - full_dataset (`Dataset`): 完整的数据集            - train_dataset (`Dataset`): 训练集            - eval_dataset (`Dataset`): 验证集    """    dataset = Dataset.from_pandas(df[['sentence', 'label']])    train_df, test_df = train_test_split(        df, test_size=0.2, random_state=42, stratify=df['label']    )    train_dataset = Dataset.from_pandas(train_df[['sentence', 'label']])    eval_dataset = Dataset.from_pandas(test_df[['sentence', 'label']])    return dataset, train_dataset, eval_datasetdef tokenize_dataset(tokenizer, dataset, batch_size=32, max_length=270):    """    使用指定的 tokenizer 对数据集中的文本进行编码(tokenize),并统一格式    功能:        - 对输入数据集中的 "sentence" 字段执行 tokenization 操作        - 填充或截断至固定长度 `max_length`        - 如果原始数据集中包含 "label" 字段,则将其重命名为 "labels" 以适配 HuggingFace Trainer 接口    参数:        tokenizer (`transformers.PreTrainedTokenizer`): 预训练模型对应的分词器        dataset (`Dataset`): 经过预处理的 HuggingFace Dataset 对象,至少包含 'sentence' 字段        batch_size (int): 批处理大小,用于加速映射过程,默认为 32        max_length (int): 文本最大长度限制,超出则截断,不足则填充,默认为 270    返回:        `Dataset`: 包含 tokenized 文本和标签的 HuggingFace Dataset 对象    """    def tokenize_function(examples):        return tokenizer(            examples["sentence"],            padding="max_length",            truncation=True,            max_length=max_length,            return_special_tokens_mask=True        )    tokenized_dataset = dataset.map(tokenize_function, batched=True, batch_size=batch_size)    if "label" in tokenized_dataset.column_names:        tokenized_dataset = tokenized_dataset.rename_column("label", "labels")    return tokenized_datasetdef finetune_peft_lora():    """使用PEFT的QAT微调流程"""    try:        # Step 1: 加载数据        logger.info("Step 1: 加载数据")        data_path = os.path.join(project_root, config.get('data.raw_data_path'))        df = load_dataset_from_csv(data_path)        # Step 2: 编码标签        logger.info("Step 2: 编码标签")        le = LabelEncoder()        if 'label' not in df.columns:            df['label'] = le.fit_transform(df['emotion'])        else:            df['label'] = df['label'].astype(int)        num_labels = len(le.classes_)        # label2id: 从文本标签到数字 ID 的映射        # id2label: 从数字 ID 到文本标签的映射(用于后续推理时将预测结果还原为可读标签)        label2id = {label: i for i, label in enumerate(le.classes_)}        id2label = {i: label for label, i in label2id.items()}        logger.info(f"识别到 {num_labels} 个类别: {list(label2id.keys())}")        # Step 3: 构建 Dataset        logger.info("Step 3: 构建 Dataset")        dataset, train_dataset, eval_dataset = create_hf_dataset(df)        # Step 4: 加载本地模型和分词器        logger.info("Step 4: 加载本地模型和分词器")        model_name_or_path = os.path.join(project_root, config.get('model.local_model_path'))        logger.info(f"使用本地模型路径: {model_name_or_path}")        tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)        model = AutoModelForSequenceClassification.from_pretrained(            model_name_or_path,  # 预训练模型的路径或名称(本地路径或HuggingFace模型仓库ID)            num_labels=num_labels,  # 分类任务中标签的数量,由数据集中不同情绪类别数决定            label2id=label2id,  # 文本标签到数字ID的映射字典,用于将字符串标签转换为模型可接受的数值            id2label=id2label  # 数字ID到文本标签的映射字典,用于将模型输出的数字预测还原为可读标签        ).to(torch_device)  # 将模型移动到指定设备(如GPU或CPU)上运行        # Step 5: 准备PEFT配置        logger.info("Step 5: 准备PEFT配置")        peft_config = LoraConfig(            task_type=TaskType.SEQ_CLS,  # 指定当前任务类型为序列分类(Sequence Classification)            inference_mode=False,  # 设置为训练模式,若为True则冻结LoRA模块用于推理            r=8,  # LoRA低秩矩阵的秩,控制适配器的参数规模和表达能力            lora_alpha=32,  # LoRA缩放因子,用于调节适配器输出的缩放比例            lora_dropout=0.1,  # 在LoRA模块中应用的Dropout概率,用于防止过拟合            target_modules=["query", "key", "value", "dense"]  # 指定在哪些Transformer层中插入LoRA适配器        )        # Step 6: 准备模型进行PEFT训练(不做任何量化)        logger.info("Step 6: 准备模型进行PEFT训练")        model = prepare_model_for_kbit_training(model)        model = get_peft_model(model, peft_config)        model = model.to(torch_device)        # Step 7: 数据编码        logger.info("Step 7: 数据编码")        # tokenizer: 使用的分词器对象(如 BERT 的 BertTokenizer),负责将文本字符串转换为 token ID 和 attention mask。        encoded_train_dataset = tokenize_dataset(tokenizer, train_dataset)        encoded_eval_dataset = tokenize_dataset(tokenizer, eval_dataset)        # Step 8: 设置训练参数        logger.info("Step 8: 设置训练参数")        output_dir = os.path.join(project_root, config.get('save.finetuned_lora_model_path'))        os.makedirs(output_dir, exist_ok=True)        training_args = TrainingArguments(            output_dir=output_dir,  # 模型输出保存的目录            per_device_train_batch_size=int(config.get('training.batch_size', 16)),  # 每个设备上的训练批次大小            per_device_eval_batch_size=int(config.get('training.batch_size', 16)),  # 每个设备上的评估批次大小            eval_strategy="epoch",  # 每个epoch进行一次评估            save_strategy="epoch",  # 每个epoch保存一次模型            learning_rate=float(config.get('training.learning_rate', 2e-5)),  # 学习率            num_train_epochs=int(config.get('training.num_epochs', 3)),  # 训练的总轮数            weight_decay=float(config.get('training.weight_decay', 0.01)),  # 权重衰减系数,用于正则化            warmup_steps=int(config.get('training.warmup_steps', 100)),  # 预热步数,在开始训练时逐步增加学习率            gradient_accumulation_steps=int(config.get('training.gradient_accumulation_steps', 1)),            # 梯度累积步数,用于模拟更大的batch size            logging_dir=os.path.join(log_dir, "peft_training_logs"),  # 日志保存路径            logging_steps=100,  # 每100步记录一次日志            load_best_model_at_end=True,  # 在训练结束后加载最佳模型            metric_for_best_model="accuracy",  # 使用哪个指标来选择最佳模型            report_to="none",  # 不向任何外部平台报告(如WandB等)            fp16=config.get('training.fp16', False),  # 是否使用混合精度训练            dataloader_pin_memory=config.get('training.dataloader_pin_memory', False),  # 是否将数据加载到固定内存中,以加快传输速度        )        # Step 9: 创建 Trainer        logger.info("Step 9: 创建 Trainer")        def compute_metrics(pred):            """            评估模型预测结果的性能指标,包括准确率、加权平均精确率、召回率和 F1 分数。            功能:                - 接收模型预测输出(logits)和真实标签(labels)                - 计算分类任务中的多个评价指标                - 返回一个包含关键性能指标的字典,供 Trainer 使用以监控训练过程            参数:                pred (tuple): 包含两个元素的元组 `(logits, labels)`:                    - logits (`np.ndarray`): 模型输出的原始预测值(未经过 softmax)                    - labels (`np.ndarray`): 真实标签值(整数形式)            返回:                dict: 包含以下性能指标的字典:                    - 'accuracy' (float): 准确率                    - 'precision' (float): 加权平均精确率(precision)                    - 'recall' (float): 加权平均召回率(recall)                    - 'f1' (float): 加权平均 F1 分数(F1-score)            示例输出:                {                    "accuracy": 0.92,                    "precision": 0.93,                    "recall": 0.92,                    "f1": 0.925                }            """            logits, labels = pred            predictions = np.argmax(logits, axis=-1)            accuracy = accuracy_score(labels, predictions)            report = classification_report(                labels, predictions, target_names=le.classes_, output_dict=True            )            return {                "accuracy": accuracy,                "precision": report["weighted avg"]["precision"],                "recall": report["weighted avg"]["recall"],                "f1": report["weighted avg"]["f1-score"]            }        trainer = Trainer(            model=model,  # 要训练的模型对象(通常是 PEFT 模型,如 LoRA 微调模型)            args=training_args,  # 训练参数配置对象(TrainingArguments),控制训练流程和超参数            train_dataset=encoded_train_dataset,  # 训练数据集,已 tokenized 和格式化后的 Dataset 对象            eval_dataset=encoded_eval_dataset,  # 验证数据集,用于每个 epoch 后评估模型性能            tokenizer=tokenizer,  # 分词器,用于在保存/加载时处理文本输入输出            compute_metrics=compute_metrics  # 评估函数,定义了如何计算模型性能指标(如 accuracy、F1-score 等)        )        # Step 10: 开始LoRA参数高效微调        logger.info("Step 10: 开始LoRA参数高效微调")        trainer.train()        # Step 11: 保存模型        logger.info("Step 11: 保存模型")        trainer.save_model(output_dir)        tokenizer.save_pretrained(output_dir)        logger.info(f"模型已保存至: {output_dir}")        # Step 12: 测试模型推理        logger.info("Step 12: 测试模型推理能力")        test_sentence = "I feel really sad and hopeless."                # 创建推理pipeline        classifier = pipeline(            task="text-classification",  # 指定任务类型为文本分类            model=model,  # 使用的预训练模型对象(已微调的 LoRA 模型)            tokenizer=tokenizer,  # 对应的分词器,用于输入文本的编码处理            device=device_index  # 指定运行设备(0 表示 GPU,-1 表示 CPU)        )                for _ in tqdm(range(1), desc='LoRA推理测试'):            result = classifier(test_sentence)        logger.info(f"测试句子: '{test_sentence}' -> 预测情绪: {result[0]['label']} (置信度: {result[0]['score']:.2f})")        # Step 13: 模型大小对比        logger.info("Step 13: 模型大小对比")        # 统计当前 model 中所有可训练参数(trainable parameters)所占用的总内存大小(单位是字节)。        original_model_size = sum(p.numel() * p.element_size() for p in model.parameters())                logger.info(f"LoRA微调后模型参数大小: {original_model_size / 1024 / 1024:.2f} MB")        logger.info("PEFT训练完成,模型已优化!")        logger.success("LoRA参数高效微调完成!")    except Exception as e:        logger.error(f"PEFT QAT微调过程中出错: {e}")        raiseif __name__ == "__main__":    finetune_peft_lora()

代码中用到的配置文件 finetune_lora.yaml

# BERT模型LoRA微调配置文件# 数据配置data:  raw_data_path: "data/raw/train_processed.csv"  processed_data_path: "data/processed/"# BERT模型配置model:  local_model_path: "models/bert_pretrained/"# 训练配置training:  learning_rate: 2e-5  batch_size: 32  # 增大batch_size,充分利用GPU内存  num_epochs: 3  weight_decay: 0.01  warmup_steps: 100  gradient_accumulation_steps: 1  fp16: true  # 启用混合精度训练,提升训练速度  dataloader_pin_memory: true  # 启用pin_memory,提升数据加载速度# 保存配置save:  model_path: "models/bert/"  log_path: "logs/"  experiment_path: "experiments/bert/"  checkpoint_path: "checkpoints/bert/"  finetuned_model_path: "models/bert/"  finetuned_lora_model_path: "models/bert_lora/"  predictions_path: "experiments/bert/"  onnx_model_path: "models/bert_onnx/"# 评估配置evaluation:  metrics: ["accuracy", "precision", "recall", "f1"]  main_metric: "micro_f1"# 日志配置logging:  level: "INFO"  format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"  file: "logs/bert_lora.log"

测试集8984条

最终的评估结果展示

测试集准确率: 0.9441详细分类报告:              precision    recall  f1-score   support       anger     0.9403    0.9679    0.9539      1497        fear     0.9500    0.8752    0.9110      1498         joy     0.9852    0.8879    0.9340      1498        love     0.9225    0.9940    0.9569      1497         sad     0.9732    0.9452    0.9590      1497     suprise     0.9046    0.9947    0.9475      1497    accuracy                         0.9441      8984   macro avg     0.9460    0.9441    0.9437      8984weighted avg     0.9460    0.9441    0.9437      8984

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LoRA BERT 情感分类 微调
相关文章