ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

使用 Flower 与 Hugging Face Transformers 联邦微调大语言模型:IMDB 情感分类快速入门指南

使用 Flower 与 Hugging Face Transformers 联邦微调大语言模型:IMDB 情感分类快速入门指南 使用 Flower 与 Hugging Face Transformers 联邦微调大语言模型IMDB 情感分类快速入门指南【免费下载链接】flowerFlower: A Friendly Federated AI Framework项目地址: https://gitcode.com/GitHub_Trending/flo/flower本指南基于 Flower 官方 Quickstart 教程讲解如何用 Flower 联合 Hugging Face Transformers在 IMDB 电影评论数据集上联邦微调一个预训练 Transformer 模型bert-tiny实现正面/负面二分类情感分析。读完本文你将掌握用flwr new一键生成 Flower 应用、通过flwr run在本地模拟引擎与 GPU 环境下运行两节点联邦、以及ClientApp/ServerApp中Message、ArrayRecord与 PyTorchstate_dict之间转换的完整实战方法并了解其背后的源码级实现原理。教程概览联邦学习 预训练语言模型本教程在 Flower 与 Hugging Face Transformers 的配合下将大语言模型LLM的微调过程联邦化数据集stanfordnlp/imdb电影评论数据集使用 Flower Datasets 的IidPartitioner划分为多个 IID独立同分布分区每个客户端只持有属于自己的那份数据模型从 Hugging Face Hub 加载预训练bert-tiny序列分类模型输出 2 个类别正面/负面联邦策略默认使用 FedAvg联邦平均在两台节点上运行 3 轮运行时flwr run启动本地受管 SuperLink由 Flower Simulation Runtime模拟运行时执行整轮联邦流程。核心思路是每个客户端用自己本地分区的 IMDB 数据对接收到的全局模型做若干步微调把更新后的权重发回服务端服务端用 FedAvg 聚合出新的全局模型如此迭代多轮。文中所有代码均来自仓库中的 examples/quickstart-huggingface 示例你可直接对照阅读。环境准备与项目创建创建虚拟环境并安装 Flower官方建议先创建一个 Python 虚拟环境venv / virtualenv在干净的环境中运行整个流程具体步骤可参考 contributor-how-to-set-up-a-virtual-env.rst。随后安装 Flower# 在全新的 Python 环境中 $ pip install flwr用flwr new一键生成项目Flower 提供flwr new命令从模板生成一个完整的 Flower Hugging Face 项目$ flwr new flwrlabs/quickstart-huggingface运行后当前目录下会新增一个名为quickstart-huggingface的目录结构如下quickstart-huggingface ├── huggingface_example │ ├── __init__.py │ ├── client_app.py # 定义 ClientApp │ ├── server_app.py # 定义 ServerApp │ └── task.py # 定义模型、训练与数据加载 ├── pyproject.toml # 项目元数据、依赖与配置 └── README.md各文件的职责非常清晰task.py封装与 Flower 无关的纯模型/数据逻辑client_app.py定义参与训练的ClientAppserver_app.py定义编排联邦流程的ServerApppyproject.toml集中声明依赖、入口点与运行配置。安装项目依赖进入项目目录后以可编辑模式安装pyproject.toml中声明的依赖以及huggingface_example包本身$ cd quickstart-huggingface $ pip install -e .该示例的依赖声明位于 pyproject.toml主要包括flwr[simulation]1.36.0Flower 框架及模拟引擎flwr-datasets0.6.1提供FederatedDataset与IidPartitionertorch2.10.0PyTorch 后端transformers4.30.0,5.0Hugging Face Transformersevaluate0.4.0,1.0提供load_metric(accuracy)等评估指标scikit-learn1.3.1, 2.0evaluate库计算准确率的依赖。运行联邦训练使用模拟引擎运行默认配置在项目根目录下执行$ flwr run . --stream带--stream参数会实时流式打印日志不带--stream的flwr run .则只提交运行、打印运行 ID 后立即返回。默认情况下flwr run会使用本地模拟 Profile启动一个受管的本地 SuperLink并把运行任务提交给它由 Flower Simulation Runtime 在两个虚拟节点上执行。默认参数下你会看到类似如下的流式输出Starting local SuperLink on 127.0.0.1:39091... Successfully started run 1859953118041441032 INFO : Starting FedAvg strategy: INFO : ├── Number of rounds: 3 INFO : [ROUND 1/3] INFO : configure_train: Sampled 2 nodes (out of 2) INFO : aggregate_train: Received 2 results and 0 failures INFO : └── Aggregated MetricRecord: {train_loss: 0.6974} INFO : configure_evaluate: Sampled 2 nodes (out of 2) INFO : aggregate_evaluate: Received 2 results and 0 failures INFO : └── Aggregated MetricRecord: {val_loss: 0.0223, val_accuracy: 0.5024} INFO : [ROUND 2/3] INFO : ... INFO : [ROUND 3/3] INFO : ... INFO : Strategy execution finished in 151.02s INFO : Final results: INFO : ServerApp-side Evaluate Metrics: INFO : {}这段日志展示了 FedAvg 每轮的标准流程服务端从 2 个节点中采样参与训练的节点configure_train: Sampled 2 nodes等待各节点返回训练结果后聚合aggregate_train得到train_loss随后进入评估阶段configure_evaluate/aggregate_evaluate得到验证集上的val_loss与val_accuracy。想要了解本地工作流的完整细节可查阅 how-to-run-flower-locally.rst。使用 GPU 运行如果本机有 GPU可以用localhost-gpu这个内置 Profile 运行# 使用默认参数运行 $ flwr run . localhost-gpu --stream该 Profile 的默认资源配置为每个ClientApp使用 4 个 CPU并且同一张 GPU 上最多并发运行 4 个ClientApp即每个客户端占用约 0.25 张 GPU。另一种等价做法是先用flwr federation simulation-config命令显式配置模拟资源再运行应用flwr federation simulation-config \ --client-resources-num-cpus4 \ # 每个 ClientApp 假设使用 4 个 CPU --client-resources-num-gpus0.25 # 每张 GPU 上最多运行 4 个 ClientApp更多模拟配置方式可参考 how-to-run-simulations.rst。覆盖pyproject.toml中的默认参数pyproject.toml的[tool.flwr.app.config]节定义了应用的运行参数详见下一节。你可以通过--run-config在不改动文件的前提下覆盖它们# 覆盖部分参数 $ flwr run . --run-config num-server-rounds5 fraction-train0.2上面的命令把联邦轮数改为 5、训练采样比例改为 0.2其余参数保持默认。配置详解pyproject.tomlpyproject.toml 是 Flower App 的配置中心除了常规的构建系统与依赖声明外还包含以下 Flower 专属配置节[tool.flwr.app] publisher flwrlabs fab-format-version 1 flwr-version-target 1.37.0 [tool.flwr.app.components] serverapp huggingface_example.server_app:app clientapp huggingface_example.client_app:app [tool.flwr.app.config] num-server-rounds 3 model-name prajjwal1/bert-tiny fraction-train 1.0 fraction-evaluate 1.0 save-model false各配置项含义如下配置键默认值说明num-server-rounds3FedAvg 联邦训练的轮数对应strategy.start(num_rounds...)model-nameprajjwal1/bert-tiny从 Hugging Face Hub 加载的预训练模型标识fraction-train1.0每轮参与训练的节点采样比例FedAvg 的fraction_trainfraction-evaluate1.0每轮参与评估的节点采样比例FedAvg 的fraction_evaluatesave-modelfalse若为true服务端在训练结束后把全局模型state_dict保存为final_model.pt[tool.flwr.app.components]指定了ServerApp与ClientApp的 Python 入口点[tool.flwr.app]记录了发布者、FAB 格式版本与目标 Flower 版本供flwr打包与版本校验使用。数据准备Flower Datasets 与 IMDB 分区数据加载逻辑封装在 task.py 的load_data()中。它借助 Flower Datasets 下载 IMDB 数据集用IidPartitioner生成num_partitions个分区并完成分词与 DataLoader 构建partitioner IidPartitioner(num_partitionsnum_partitions) fds FederatedDataset( datasetstanfordnlp/imdb, partitioners{train: partitioner}, ) partition fds.load_partition(partition_id) # 划分数据80% 训练20% 测试 partition_train_test partition.train_test_split(test_size0.2, seed42) tokenizer AutoTokenizer.from_pretrained(model_name, model_max_length512) def tokenize_function(examples): return tokenizer( examples[text], truncationTrue, add_special_tokensTrue ) partition_train_test partition_train_test.map(tokenize_function, batchedTrue) partition_train_test partition_train_test.remove_columns(text) partition_train_test partition_train_test.rename_column(label, labels) data_collator DataCollatorWithPadding(tokenizertokenizer) trainloader DataLoader( partition_train_test[train], shuffleTrue, batch_size32, collate_fndata_collator, ) testloader DataLoader( partition_train_test[test], batch_size32, collate_fndata_collator )要点拆解IID 分区IidPartitioner(num_partitions...)把训练集均匀切分为指定数量的分区。从 iid_partitioner.py 的源码可以看到其load_partition(partition_id)底层是对数据集执行dataset.shard(num_shardsnum_partitions, indexpartition_id, contiguousTrue)即按连续分片方式返回第partition_id个分区。除IidPartitioner外Flower Datasets 还提供多种其他分区器如 Dirichlet 非 IID 分区等可按需选用本地切分每个客户端拿到自己的分区后再用train_test_split(test_size0.2, seed42)在该分区内部切出 80% 训练集与 20% 验证集分词使用与训练模型配套的AutoTokenizer设置model_max_length512、truncationTrue与add_special_tokensTrue把text列分词后移除原始文本、并把label列改名为labels与 Transformers 序列分类模型的输入约定对齐动态填充DataCollatorWithPadding在批次内动态补齐到等长两个DataLoader的batch_size32缓存优化示例中把FederatedDataset缓存在模块级全局变量fdstask.py顶部fds None保证每个客户端进程只下载/初始化数据集一次。每个ClientApp都会调用该函数用自己partition_id对应的数据构建训练与评估 DataLoader。模型与训练/评估函数模型同样在 task.py 中定义。get_model()从 Hugging Face Hub 加载model_name对应的预训练 Transformer并为其套上 2 分类头net AutoModelForSequenceClassification.from_pretrained( model_name, num_labels2 )这里model_name是一个字符串由ClientApp/ServerApp从各自的Context运行配置中读取默认prajjwal1/bert-tiny。目标任务是判断一条电影评论是正面还是负面即 2 分类。如果你的 GPU 显存更大也可以替换成更大的模型。除加载预训练权重与结构外task.py还提供两个与 Flower 无关的标准 PyTorch 工具函数供客户端在本地数据上调用def train_fn(net, trainloader, epochs, device) - None: optimizer AdamW(net.parameters(), lr5e-5) net.train() for _ in range(epochs): for batch in trainloader: batch {k: v.to(device) for k, v in batch.items()} outputs net(**batch) loss outputs.loss loss.backward() optimizer.step() optimizer.zero_grad() def test_fn(net, testloader, device) - tuple[Any | float, Any]: metric load_metric(accuracy) loss 0 net.eval() for batch in testloader: batch {k: v.to(device) for k, v in batch.items()} with torch.no_grad(): outputs net(**batch) logits outputs.logits loss outputs.loss.item() predictions torch.argmax(logits, dim-1) metric.add_batch(predictionspredictions, referencesbatch[labels]) loss / len(testloader.dataset) accuracy metric.compute()[accuracy] return loss, accuracytrain_fn使用AdamW学习率5e-5逐批次前向、反向、更新参数test_fn在no_grad下推理用evaluate库的accuracy指标统计准确率并返回平均损失。这两个函数不包含任何 Flower 特有逻辑可完全复用你熟悉的中心化 PyTorch 训练/评估代码——这正是 Flower 的设计初衷客户端的本地训练逻辑与联邦框架解耦。ClientAppMessage 与 ArrayRecord 的双向转换把 Hugging Face 模型接入 Flower核心改动在于把Message中携带的ArrayRecord转换为 PyTorchstate_dict加载进模型训练完成后再把state_dict转回ArrayRecord放进回复消息。得益于ArrayRecord的内置方法这一转换非常简洁# 加载模型 model get_model(model_name) # 从 Message 中取出 ArrayRecord 并转换为 PyTorch state_dict arrays msg.content[arrays] # 把 state_dict 加载进模型 model.load_state_dict(arrays.to_torch_state_dict(), strictTrue) # ... 进行本地训练 ... # 把 state_dict 转回 ArrayRecord model_record ArrayRecord(model.state_dict())ClientApp提供三个核心方法train用本地数据训练收到的模型、evaluate在本地验证集上评估收到的模型、query查询运行ClientApp的节点信息。本教程只用到前两个。实现app.train()train方法接收来自ServerApp的Message默认携带一个ArrayRecord存放待联邦训练的模型权重通过msg.content[arrays]获取一个ConfigRecord存放ServerApp下发的配置通过msg.content[config]获取。同时它还能拿到Contextrun_config对应pyproject.toml中定义的应用运行超参node_config是节点级配置模拟运行时由系统注入如partition-id、num-partitions部署运行时才可显式设置。完整实现见 client_app.py# Flower ClientApp app ClientApp() app.train() def train(msg: Message, context: Context) - Message: 在本地数据上训练模型。 # 获取该客户端的本地数据分区 partition_id context.node_config[partition-id] num_partitions context.node_config[num-partitions] model_name context.run_config[model-name] trainloader, _ load_data(partition_id, num_partitions, model_name) # 加载模型 model get_model(model_name) # 用接收到的权重初始化模型 arrays msg.content[arrays] model.load_state_dict(arrays.to_torch_state_dict(), strictTrue) device torch.device(cuda:0 if torch.cuda.is_available() else cpu) model.to(device) # 在本地数据上训练模型 train_fn(model, trainloader, epochs1, devicedevice) # 构造并返回回复 Message model_record ArrayRecord(model.state_dict()) metrics MetricRecord({num-examples: len(trainloader)}) # 构造 RecordDict放入 ArrayRecord 与 MetricRecord content RecordDict({arrays: model_record, metrics: metrics}) return Message(contentcontent, reply_tomsg)可见训练流程非常直观按partition-id加载本地数据 → 用服务端下发的全局权重初始化模型 → 本地训练 1 个 epoch → 把更新后的state_dict封装进ArrayRecord连同num-examples指标一起放入RecordDict最后以Message(reply_tomsg)的形式返回给服务端。num-examples是 FedAvg 聚合时的权重依据详见下文FedAvg的weighted_by_key参数。实现app.evaluate()app.evaluate()与train几乎相同仅有两点差异模型不做本地训练而是直接在本地留出的验证集上评估性能回复消息中不再需要携带模型因为模型未被本地修改只需返回评估指标。仓库中的实现会在MetricRecord中额外带上loss与accuracy见 client_app.py 的evaluate方法这正是日志里val_loss、val_accuracy指标的来源。ServerAppFedAvg 策略与全局模型聚合ServerApp的核心是app.main()方法它接收两个参数Grid与服务端交互的接口用于调度运行ClientApp的节点参与每轮 train/evaluate/queryContext提供运行配置。本示例使用FedAvg策略其fraction_train从运行配置读取默认值定义在pyproject.toml。随后调用策略的start方法启动联邦流程传入Grid对象一个携带随机初始化模型的ArrayRecord作为待联邦化的全局模型发送给客户端的训练超参ConfigRecord策略会在下发前自动注入当前轮号num_rounds指定执行多少轮 FedAvg。完整实现见 server_app.py# 创建 ServerApp app ServerApp() app.main() def main(grid: Grid, context: Context) - None: # 定义要联邦化的模型并提取参数 model_name context.run_config[model-name] model get_model(model_name) arrays ArrayRecord(model.state_dict()) # 实例化策略 fraction_train context.run_config[fraction-train] fraction_evaluate context.run_config[fraction-evaluate] strategy FedAvg( fraction_trainfraction_train, fraction_evaluatefraction_evaluate, ) num_rounds context.run_config[num-server-rounds] # 启动策略 result strategy.start( gridgrid, initial_arraysarrays, num_roundsnum_rounds, ) if context.run_config[save-model]: # 把最终模型保存到磁盘 print(\nSaving final model to disk...) state_dict result.arrays.to_torch_state_dict() torch.save(state_dict, final_model.pt)start方法返回一个Result对象其中包含联邦过程的全部关键信息以ArrayRecord形式给出的最终全局模型权重以及各轮训练/评估的MetricRecord指标。你可以用 Python 标准库pprint打印这些指标当save-model为true时result.arrays转回 PyTorchstate_dict后即可用torch.save落盘。底层原理从源码看关键实现ArrayRecord 的 PyTorch 桥接ArrayRecord是 Flower 在客户端与服务端之间传输模型权重的载体其源码位于 arrayrecord.py。与本教程直接相关的两个方法是from_torch_state_dict(state_dict, keep_inputTrue)逐个遍历state_dict的键调用Array.from_numpy_ndarray(v.detach().cpu().numpy())把每个 PyTorch 张量转成 Flower 的Array即Tensor → ArrayRecordto_torch_state_dict()反向遍历用torch.from_numpy(arr.numpy())把每个Array还原成 PyTorch 张量并组装成OrderedDict即ArrayRecord → Tensor。两个方法都会先检查torch是否已导入未安装 PyTorch 时抛出明确的RuntimeError提示。这就是client_app.py中arrays.to_torch_state_dict()与ArrayRecord(model.state_dict())两行代码背后的完整机制。FedAvg 策略与start()的调度循环FedAvg类定义在 fedavg.py其关键参数包括fraction_train训练采样比例、fraction_evaluate评估采样比例、min_train_nodes/min_evaluate_nodes/min_available_nodes各类最小节点数默认 2、以及weighted_by_key默认num-examples聚合时以各客户端上报的样本数作为加权平均的权重键——这解释了为什么ClientApp必须在MetricRecord中上报num-examples。策略基类Strategy.start()的调度循环在 strategy.py 中每一轮按以下顺序执行configure_train(round, arrays, train_config, grid)构造训练消息经grid.send_and_receive(messages..., timeout...)发给采样到的节点并等待回复aggregate_train(...)聚合训练结果得到新一轮全局参数agg_arrays与聚合训练指标对应日志中的train_lossconfigure_evaluate(...)grid.send_and_receive(...)发起客户端评估aggregate_evaluate(...)聚合评估指标对应日志中的val_loss/val_accuracy循环结束后日志打印Strategy execution finished in ...并返回包含最终arrays与各轮指标的Result。整个流程与前面flwr run的流式日志逐行对应理解这段源码即可精确掌握采样 → 下发 → 本地训练/评估 → 聚合的完整时序。小结与进一步阅读至此你已经完成了第一个联邦学习系统的搭建与运行数据经IidPartitioner在客户端间划分bert-tiny模型在本地 IMDB 分区上微调权重经ArrayRecord往返传输FedAvg在服务端聚合出全局模型最终输出联邦训练/评估指标并可选择保存模型权重。如果你希望继续深入仓库中有以下资源可供参考关于模拟引擎的配置与调优阅读 how-to-run-simulations.rst关于本地运行SuperLink 启动、日志流式输出等的完整说明阅读 how-to-run-flower-locally.rst本教程的完整可运行源码位于 examples/quickstart-huggingface内含 task.py、client_app.py、server_app.py 与 README.md若要进行更大规模的 LLM 联邦微调可参考仓库中的 FlowerTune LLM 系列示例如 flowertune-llm它们展示了更完整的训练、评估与实验组织方式若想把这套应用部署到真实分布式环境中可参考 how-to-run-flower-with-deployment-engine.rst并进一步了解 how-to-enable-tls-connections.rst 等安全通信配置。【免费下载链接】flowerFlower: A Friendly Federated AI Framework项目地址: https://gitcode.com/GitHub_Trending/flo/flower创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表