diff --git a/.github/workflows/docs-test-publish.yml b/.github/workflows/docs-test-publish.yml index fc5e7283..85641684 100644 --- a/.github/workflows/docs-test-publish.yml +++ b/.github/workflows/docs-test-publish.yml @@ -22,9 +22,17 @@ permissions: pages: write id-token: write -# Allow one concurrent deployment +# Allow one concurrent deployment: runs that may publish to GitHub Pages +# (pushes to doc/master, manual dispatch) share one lock; pull-request +# builds never publish and each get their own group, so they neither +# cancel nor get cancelled by deploys or by other pull requests concurrency: - group: "pages" + group: >- + ${{ + (github.event_name == 'push' && contains(fromJson('["refs/heads/doc", "refs/heads/master"]'), github.ref)) || github.event_name == 'workflow_dispatch' + && 'pages-deploy' + || format('docs-build-{0}', github.event.pull_request.number) + }} cancel-in-progress: true jobs: diff --git a/docs/source/concepts.rst b/docs/source/concepts.rst index 4e6fb5a6..5e617042 100644 --- a/docs/source/concepts.rst +++ b/docs/source/concepts.rst @@ -3,10 +3,9 @@ Core concepts ============= -This page is the map of fl-sim: the four building blocks of every -experiment and what happens during one round of federated training. It -explains *how the framework thinks* — for a hands-on walk-through, start -with :doc:`quickstart`. +This page summarizes the four building blocks of every experiment and the +sequence of events within one round of federated training. For a hands-on +introduction, start with :doc:`quickstart`. Four building blocks ---------------------- @@ -16,11 +15,11 @@ FedDataset — the data and how it is split A :class:`~fl_sim.data_processing.fed_dataset.FedDataset` bundles a raw dataset with a **partitioning scheme**: it decides how the data is spread -across the simulated clients and hands each client its own dataloaders -through ``get_dataloader(client_idx)``. Built-in datasets (FEMNIST, +across the simulated clients and provides each client with its own +dataloaders through ``get_dataloader(client_idx)``. Built-in datasets (FEMNIST, CIFAR10, …) download on first use; :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` -generates synthetic data locally, which is why every tutorial here runs in -seconds. Each dataset also declares ``candidate_models`` — the models it +generates synthetic data locally, so the tutorials in this documentation +complete in seconds. Each dataset also declares ``candidate_models`` — the models it is meant to be paired with (``dataset.candidate_models["mlp_d1"]``, as in the quickstart). Datasets are **immutable during training**: partitioning happens once, up front. Custom datasets are covered in a how-to guide. @@ -29,8 +28,8 @@ Model — a plain PyTorch module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Models are ordinary :class:`torch.nn.Module` objects; fl-sim does not -wrap them. Whatever ``candidate_models`` offers or you bring yourself -works. The server holds the *global* copy; every sampled client gets its +wrap them. Any module from ``candidate_models`` — or any user-provided +module — can be used. The server holds the *global* copy; every sampled client gets its own copy each round, trains it on its local data slice, and sends the result back. @@ -39,7 +38,7 @@ Server — the orchestrator The :class:`~fl_sim.nodes.Server` owns the global model and the federated schedule (how many rounds, how many clients, how they are -sampled), and drives the loop you will see below. It never touches +sampled), and drives the training loop described below. It never touches client-local data. Algorithm-specific behavior lives in subclasses: :class:`~fl_sim.algorithms.fedopt.FedAvgServer`, :class:`~fl_sim.algorithms.fedprox.FedProxServer`, and 15+ others — each @@ -54,7 +53,7 @@ Client — one participant's local state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each :class:`~fl_sim.nodes.Client` holds its own model copy, its data -slice, and its training state. Its hooks are the mirror image of the +slice, and its training state. The client-side hooks correspond to the server's: - ``update()`` — the **local training**: fit the received model on local @@ -71,9 +70,9 @@ FedPD, ProxSkip, Ditto, … — and they all run in the *same* loop. An algorithm is only a pair of config classes plus hook overrides: FedProx changes the client's local objective; SCAFFOLD adds control variates to the uplink; FedPD lets clients *skip* some uplinks entirely. The -framework calls the hooks in a fixed order (below), so algorithms compose -with the infrastructure — logging, evaluation, reproducibility, parallel -execution — without any of them knowing about each other. +framework calls the hooks in a fixed order (below), so algorithms remain +independent of the infrastructure — logging, evaluation, reproducibility, +parallel execution. Registering your own makes it usable from the CLI and experiment matrices by name: @@ -118,19 +117,19 @@ fixed order: Because steps 1–2 and 5 happen on the main thread in fixed order, the *aggregation arithmetic* is identical no matter how the local steps of step 4 are executed — sequentially, or concurrently on a thread pool -(:doc:`parallel_execution`). That invariant is what makes parallel runs -trustworthy. +(:doc:`parallel_execution`). This invariant underlies the reproducibility +guarantees of parallel execution. -The cast in one table ---------------------- +The four objects at a glance +---------------------------- .. list-table:: :header-rows: 1 * - Object - Configured by - - Knows about - - Never touches + - Responsible for + - Does not access * - :class:`~fl_sim.data_processing.fed_dataset.FedDataset` - constructor args - raw data, partitioning, dataloaders @@ -151,4 +150,4 @@ Where to go next - :doc:`api/nodes` — the full Server/Client API reference. - :ref:`config reference ` — every config field of every algorithm. -- :doc:`viz` — explore the produced logs interactively. +- :doc:`viz` — interactive exploration of the produced logs. diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/concepts.po b/docs/source/locale/zh_CN/LC_MESSAGES/concepts.po index e4b8266a..1e24f723 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/concepts.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/concepts.po @@ -6,17 +6,17 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: fl-sim \n" +"Project-Id-Version: fl-sim\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-26 13:08+0800\n" +"POT-Creation-Date: 2026-10-28 23:45+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: zh_CN\n" "Language-Team: zh_CN \n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.16.0\n" #: ../../source/concepts.rst:4 @@ -24,320 +24,233 @@ msgid "Core concepts" msgstr "核心概念" #: ../../source/concepts.rst:6 -msgid "" -"This page is the map of fl-sim: the four building blocks of every " -"experiment and what happens during one round of federated training. It " -"explains *how the framework thinks* — for a hands-on walk-through, start " -"with :doc:`quickstart`." -msgstr "" -"本页面是 fl-sim 的地图:每次实验的四个构件,以及一轮联邦训练中发生的事。它解释的是" -"框架的*思考方式*——若想先动手体验,请从 :doc:`quickstart` 开始。" +msgid "This page summarizes the four building blocks of every experiment and the sequence of events within one round of federated training. For a hands-on introduction, start with :doc:`quickstart`." +msgstr "本页面概述每次实验的四个构件,以及一轮联邦训练中的事件顺序。若希望先动手实践,可从 :doc:`quickstart` 开始。" -#: ../../source/concepts.rst:12 +#: ../../source/concepts.rst:11 msgid "Four building blocks" msgstr "四个构件" -#: ../../source/concepts.rst:15 +#: ../../source/concepts.rst:14 msgid "FedDataset — the data and how it is split" msgstr "FedDataset——数据及其划分方式" -#: ../../source/concepts.rst:17 +#: ../../source/concepts.rst:16 msgid "" -"A :class:`~fl_sim.data_processing.fed_dataset.FedDataset` bundles a raw " -"dataset with a **partitioning scheme**: it decides how the data is spread" -" across the simulated clients and hands each client its own dataloaders " -"through ``get_dataloader(client_idx)``. Built-in datasets (FEMNIST, " -"CIFAR10, …) download on first use; " -":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` generates " -"synthetic data locally, which is why every tutorial here runs in seconds." -" Each dataset also declares ``candidate_models`` — the models it is meant" -" to be paired with (``dataset.candidate_models[\"mlp_d1\"]``, as in the " -"quickstart). Datasets are **immutable during training**: partitioning " -"happens once, up front. Custom datasets are covered in a how-to guide." +"A :class:`~fl_sim.data_processing.fed_dataset.FedDataset` bundles a raw dataset with a **partitioning scheme**: it decides how the data is spread across the simulated clients and provides each " +"client with its own dataloaders through ``get_dataloader(client_idx)``. Built-in datasets (FEMNIST, CIFAR10, …) download on first use; :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` " +"generates synthetic data locally, so the tutorials in this documentation complete in seconds. Each dataset also declares ``candidate_models`` — the models it is meant to be paired with " +"(``dataset.candidate_models[\"mlp_d1\"]``, as in the quickstart). Datasets are **immutable during training**: partitioning happens once, up front. Custom datasets are covered in a how-to guide." msgstr "" -":class:`~fl_sim.data_processing.fed_dataset.FedDataset` 把原始数据集与 **划分方案** " -"打包在一起:它决定数据如何在模拟的客户端之间分布,并通过 ``get_dataloader(client_idx)`` " -"为每个客户端提供专属的 dataloader。内置数据集(FEMNIST、CIFAR10 等)在首次使用时下载;" -" :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` 在本地生成合成数据," -"这也是本教程都能在几秒内跑完的原因。每个数据集还声明了 ``candidate_models``——" -"适合与它搭配的模型(如 quickstart 中的 ``dataset.candidate_models[\"mlp_d1\"]``)。" -"数据集在 **训练期间不可变** :划分只做一次,且在训练开始前完成。自定义数据集见相应的" -" how-to 指南。" - -#: ../../source/concepts.rst:29 +":class:`~fl_sim.data_processing.fed_dataset.FedDataset` 将原始数据集与 **划分方案** 打包在一起:它决定数据如何在模拟的客户端之间分布,并通过 ``get_dataloader(client_idx)`` 为每个客户端提供专属的 dataloader。内置数据集(FEMNIST、CIFAR10 等)在首次使用时下载; " +":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` 在本地生成合成数据,因此本文档中的教程数秒内即可完成。每个数据集还声明了 ``candidate_models``——适合与它搭配的模型(如 quickstart 中的 ``dataset.candidate_models[\"mlp_d1\"]``)。数据集在 " +"**训练期间不可变** :划分只做一次,且在训练开始前完成。自定义数据集见相应的 how-to 指南。" + +#: ../../source/concepts.rst:28 msgid "Model — a plain PyTorch module" msgstr "模型——普通的 PyTorch 模块" -#: ../../source/concepts.rst:31 +#: ../../source/concepts.rst:30 msgid "" -"Models are ordinary :class:`torch.nn.Module` objects; fl-sim does not " -"wrap them. Whatever ``candidate_models`` offers or you bring yourself " -"works. The server holds the *global* copy; every sampled client gets its " -"own copy each round, trains it on its local data slice, and sends the " -"result back." -msgstr "" -"模型就是普通的 :class:`torch.nn.Module` 对象,fl-sim 不做任何包装。" -"``candidate_models`` 提供的或你自己带来的模型都可以用。服务器持有 *全局* 副本;" -"每轮每个被采样的客户端拿到自己的副本,在本地数据切片上训练,再把结果发回。" +"Models are ordinary :class:`torch.nn.Module` objects; fl-sim does not wrap them. Any module from ``candidate_models`` — or any user-provided module — can be used. The server holds the *global* copy;" +" every sampled client gets its own copy each round, trains it on its local data slice, and sends the result back." +msgstr "模型就是普通的 :class:`torch.nn.Module` 对象,fl-sim 不做任何包装。 ``candidate_models`` 提供的模块或用户自带的模块均可使用。服务器持有 *全局* 副本;每轮每个被采样的客户端拿到自己的副本,在本地数据切片上训练,再把结果发回。" -#: ../../source/concepts.rst:38 +#: ../../source/concepts.rst:37 msgid "Server — the orchestrator" msgstr "服务器——调度者" -#: ../../source/concepts.rst:40 +#: ../../source/concepts.rst:39 msgid "" -"The :class:`~fl_sim.nodes.Server` owns the global model and the federated" -" schedule (how many rounds, how many clients, how they are sampled), and " -"drives the loop you will see below. It never touches client-local data. " -"Algorithm-specific behavior lives in subclasses: " -":class:`~fl_sim.algorithms.fedopt.FedAvgServer`, " -":class:`~fl_sim.algorithms.fedprox.FedProxServer`, and 15+ others — each " +"The :class:`~fl_sim.nodes.Server` owns the global model and the federated schedule (how many rounds, how many clients, how they are sampled), and drives the training loop described below. It never " +"touches client-local data. Algorithm-specific behavior lives in subclasses: :class:`~fl_sim.algorithms.fedopt.FedAvgServer`, :class:`~fl_sim.algorithms.fedprox.FedProxServer`, and 15+ others — each " "customizes a handful of well-defined hooks:" msgstr "" -":class:`~fl_sim.nodes.Server` 持有全局模型与联邦调度(多少轮、多少客户端、如何采样)," -"并驱动下文所示的循环。它从不触碰客户端本地数据。算法特定的行为都在子类里:" -":class:`~fl_sim.algorithms.fedopt.FedAvgServer`、" -":class:`~fl_sim.algorithms.fedprox.FedProxServer` 等 15 个以上——每个算法只定制" -"少数几个定义良好的钩子:" +":class:`~fl_sim.nodes.Server` 持有全局模型与联邦调度(多少轮、多少客户端、如何采样),并驱动下文所述的训练循环。它从不触碰客户端本地数据。算法特定的行为都在子类里: :class:`~fl_sim.algorithms.fedopt.FedAvgServer` 、 :class:`~fl_sim.algorithms.fedprox.FedProxServer` " +"等 15 个以上——每个算法只定制少数几个定义良好的钩子:" -#: ../../source/concepts.rst:48 -msgid "" -"``communicate(target)`` — the **downlink**: what the server sends to a " -"sampled client (typically the current global model);" -msgstr "" -"``communicate(target)``——**下行**:服务器发给被采样客户端的内容(通常是当前全局模型);" +#: ../../source/concepts.rst:47 +msgid "``communicate(target)`` — the **downlink**: what the server sends to a sampled client (typically the current global model);" +msgstr "``communicate(target)``——**下行**:服务器发给被采样客户端的内容(通常是当前全局模型);" -#: ../../source/concepts.rst:50 -msgid "" -"``update()`` — the **aggregation**: how client replies are turned into " -"the new global model." +#: ../../source/concepts.rst:49 +msgid "``update()`` — the **aggregation**: how client replies are turned into the new global model." msgstr "``update()``——**聚合**:客户端回复如何变成新的全局模型。" -#: ../../source/concepts.rst:54 +#: ../../source/concepts.rst:53 msgid "Client — one participant's local state" msgstr "客户端——单个参与方的本地状态" -#: ../../source/concepts.rst:56 -msgid "" -"Each :class:`~fl_sim.nodes.Client` holds its own model copy, its data " -"slice, and its training state. Its hooks are the mirror image of the " -"server's:" -msgstr "" -"每个 :class:`~fl_sim.nodes.Client` 持有自己的模型副本、数据切片与训练状态。" -"它的钩子与服务器互为镜像:" +#: ../../source/concepts.rst:55 +msgid "Each :class:`~fl_sim.nodes.Client` holds its own model copy, its data slice, and its training state. The client-side hooks correspond to the server's:" +msgstr "每个 :class:`~fl_sim.nodes.Client` 持有自己的模型副本、数据切片与训练状态。客户端侧的钩子与服务器侧相对应:" -#: ../../source/concepts.rst:60 -msgid "" -"``update()`` — the **local training**: fit the received model on local " -"data (local epochs, local optimizer — all from the client config);" -msgstr "" -"``update()``——**本地训练**:在本地数据上拟合收到的模型(本地 epoch 数、本地优化器" -"——全部来自客户端配置);" +#: ../../source/concepts.rst:59 +msgid "``update()`` — the **local training**: fit the received model on local data (local epochs, local optimizer — all from the client config);" +msgstr "``update()``——**本地训练**:在本地数据上拟合收到的模型(本地 epoch 数、本地优化器——全部来自客户端配置);" -#: ../../source/concepts.rst:62 +#: ../../source/concepts.rst:61 msgid "" -"``communicate()`` — the **uplink**: build the message sent back to the " -"server. Messages are typed objects " -"(:class:`~fl_sim.messages.ClientToServer`) carrying the updated model " -"state plus algorithm-specific extras." -msgstr "" -"``communicate()``——**上行**:构建发回服务器的消息。消息是带类型的对象" -"(:class:`~fl_sim.messages.ClientToServer`),携带更新后的模型状态与算法特有的附加内容。" +"``communicate()`` — the **uplink**: build the message sent back to the server. Messages are typed objects (:class:`~fl_sim.messages.ClientToServer`) carrying the updated model state plus algorithm-" +"specific extras." +msgstr "``communicate()``——**上行**:构建发回服务器的消息。消息是带类型的对象(:class:`~fl_sim.messages.ClientToServer`),携带更新后的模型状态与算法特有的附加内容。" -#: ../../source/concepts.rst:67 +#: ../../source/concepts.rst:66 msgid "Algorithms customize the hooks, not the loop" msgstr "算法定制钩子,而不是循环" -#: ../../source/concepts.rst:69 +#: ../../source/concepts.rst:68 msgid "" -"fl-sim ships 20 registered algorithms — FedAvg, FedProx, SCAFFOLD, FedPD," -" ProxSkip, Ditto, … — and they all run in the *same* loop. An algorithm " -"is only a pair of config classes plus hook overrides: FedProx changes the" -" client's local objective; SCAFFOLD adds control variates to the uplink; " -"FedPD lets clients *skip* some uplinks entirely. The framework calls the " -"hooks in a fixed order (below), so algorithms compose with the " -"infrastructure — logging, evaluation, reproducibility, parallel execution" -" — without any of them knowing about each other." +"fl-sim ships 20 registered algorithms — FedAvg, FedProx, SCAFFOLD, FedPD, ProxSkip, Ditto, … — and they all run in the *same* loop. An algorithm is only a pair of config classes plus hook overrides:" +" FedProx changes the client's local objective; SCAFFOLD adds control variates to the uplink; FedPD lets clients *skip* some uplinks entirely. The framework calls the hooks in a fixed order (below), " +"so algorithms remain independent of the infrastructure — logging, evaluation, reproducibility, parallel execution." msgstr "" -"fl-sim 内置 20 个注册算法——FedAvg、FedProx、SCAFFOLD、FedPD、ProxSkip、Ditto 等——" -"它们全部运行在*同一个*循环里。一个算法只是一对配置类加上若干钩子覆写:FedProx 改动" -"客户端的本地目标函数;SCAFFOLD 在上行里加入控制变量;FedPD 允许客户端*完全跳过*某些" -"上行。框架按固定顺序(见下)调用这些钩子,因此算法与基础设施——日志、评估、可复现性、" -"并行执行——正交组合,互不知晓。" +"fl-sim 内置 20 个注册算法——FedAvg、FedProx、SCAFFOLD、FedPD、ProxSkip、Ditto 等——它们全部运行在 *同一个* 循环里。一个算法只是一对配置类加上若干钩子覆写:FedProx 改动客户端的本地目标函数;SCAFFOLD 在上行里加入控制变量;FedPD 允许客户端 *完全跳过* " +"某些上行。框架按固定顺序(见下)调用这些钩子,因此算法与基础设施——日志、评估、可复现性、并行执行——保持相互独立。" -#: ../../source/concepts.rst:78 -msgid "" -"Registering your own makes it usable from the CLI and experiment matrices" -" by name:" +#: ../../source/concepts.rst:77 +msgid "Registering your own makes it usable from the CLI and experiment matrices by name:" msgstr "注册自己的算法后,就能在 CLI 与实验矩阵中按名字使用它:" -#: ../../source/concepts.rst:91 +#: ../../source/concepts.rst:90 msgid "" -"The how-to guide on custom algorithms walks through a complete, runnable " -"example; :doc:`parallel_execution` documents the hook contract that keeps" -" custom algorithms compatible with every executor." -msgstr "" -"自定义算法的 how-to 指南给出了完整可运行的例子;:doc:`parallel_execution` 记录了" -"钩子契约,保证自定义算法与所有执行后端兼容。" +"The how-to guide on custom algorithms walks through a complete, runnable example; :doc:`parallel_execution` documents the hook contract that keeps custom algorithms compatible with every executor." +msgstr "自定义算法的 how-to 指南给出了完整可运行的例子;:doc:`parallel_execution` 记录了钩子契约,保证自定义算法与所有执行后端兼容。" -#: ../../source/concepts.rst:96 +#: ../../source/concepts.rst:95 msgid "One round of training" msgstr "一轮训练" -#: ../../source/concepts.rst:98 -msgid "" -"``server.train()`` runs ``num_iters`` rounds. Every round proceeds in a " -"fixed order:" +#: ../../source/concepts.rst:97 +msgid "``server.train()`` runs ``num_iters`` rounds. Every round proceeds in a fixed order:" msgstr "``server.train()`` 运行 ``num_iters`` 轮。每轮按固定顺序进行:" -#: ../../source/concepts.rst:101 -msgid "" -"**Sampling** — the server picks this round's participants (the " -"``clients_sample_ratio`` fraction of ``num_clients``)." -msgstr "" -"**采样**——服务器选出本轮的参与方(``num_clients`` 中按 ``clients_sample_ratio`` " -"比例抽取)。" +#: ../../source/concepts.rst:100 +msgid "**Sampling** — the server picks this round's participants (the ``clients_sample_ratio`` fraction of ``num_clients``)." +msgstr "**采样**——服务器选出本轮的参与方(``num_clients`` 中按 ``clients_sample_ratio`` 比例抽取)。" -#: ../../source/concepts.rst:103 +#: ../../source/concepts.rst:102 msgid "" -"**Uplink decision** — per algorithm: most algorithms have every sampled " -"client respond; communication-skipping algorithms (FedPD, ProxSkip) " -"decide *now*, on the main thread, which clients will upload this round." -msgstr "" -"**上行决策**——因算法而异:多数算法让每个被采样客户端都响应;通信跳过型算法" -"(FedPD、ProxSkip)在 *此刻* 于主线程上决定哪些客户端本轮上传。" +"**Uplink decision** — per algorithm: most algorithms have every sampled client respond; communication-skipping algorithms (FedPD, ProxSkip) decide *now*, on the main thread, which clients will " +"upload this round." +msgstr "**上行决策**——因算法而异:多数算法让每个被采样客户端都响应;通信跳过型算法(FedPD、ProxSkip)在 *此刻* 于主线程上决定哪些客户端本轮上传。" -#: ../../source/concepts.rst:107 -msgid "" -"**Downlink broadcast** — the server sends the global model to each " -"sampled client (``server.communicate(target)``)." -msgstr "" -"**下行广播**——服务器把全局模型发给每个被采样客户端(``server.communicate(target)``)。" +#: ../../source/concepts.rst:106 +msgid "**Downlink broadcast** — the server sends the global model to each sampled client (``server.communicate(target)``)." +msgstr "**下行广播**——服务器把全局模型发给每个被采样客户端(``server.communicate(target)``)。" -#: ../../source/concepts.rst:109 -msgid "" -"**Local steps** — each selected client runs evaluate → local training → " -"build the uplink message. Clients never see each other or the global " -"state; they touch only their own slice." -msgstr "" -"**本地步**——每个被选中的客户端依次执行评估 → 本地训练 → 构建上行消息。" -"客户端之间互不可见,也看不到全局状态;它们只触碰自己的数据切片。" +#: ../../source/concepts.rst:108 +msgid "**Local steps** — each selected client runs evaluate → local training → build the uplink message. Clients never see each other or the global state; they touch only their own slice." +msgstr "**本地步**——每个被选中的客户端依次执行评估 → 本地训练 → 构建上行消息。客户端之间互不可见,也看不到全局状态;它们只触碰自己的数据切片。" -#: ../../source/concepts.rst:112 +#: ../../source/concepts.rst:111 msgid "" -"**Uplink + aggregation** — replies are consumed **in sampled-client " -"order** and the algorithm's ``update()`` produces the new global model. " -"Metrics (server-side and per-client) are logged here." -msgstr "" -"**上行与聚合**——回复 **按被采样客户端的顺序** 被消费,算法的 ``update()`` 产出新的" -"全局模型。指标(服务器侧与每个客户端的)也在这里记录。" +"**Uplink + aggregation** — replies are consumed **in sampled-client order** and the algorithm's ``update()`` produces the new global model. Metrics (server-side and per-client) are logged here." +msgstr "**上行与聚合**——回复 **按被采样客户端的顺序** 被消费,算法的 ``update()`` 产出新的全局模型。指标(服务器侧与每个客户端的)也在这里记录。" -#: ../../source/concepts.rst:115 -msgid "" -"**Repeat** — for ``num_iters`` rounds; logs and metrics land in " -"``~/.cache/fl-sim/.logs/`` (see :doc:`quickstart`)." -msgstr "" -"**重复**——共 ``num_iters`` 轮;日志与指标写入 ``~/.cache/fl-sim/.logs/`` " -"(参见 :doc:`quickstart`)。" +#: ../../source/concepts.rst:114 +msgid "**Repeat** — for ``num_iters`` rounds; logs and metrics land in ``~/.cache/fl-sim/.logs/`` (see :doc:`quickstart`)." +msgstr "**重复**——共 ``num_iters`` 轮;日志与指标写入 ``~/.cache/fl-sim/.logs/`` (参见 :doc:`quickstart`)。" -#: ../../source/concepts.rst:118 +#: ../../source/concepts.rst:117 msgid "" -"Because steps 1–2 and 5 happen on the main thread in fixed order, the " -"*aggregation arithmetic* is identical no matter how the local steps of " -"step 4 are executed — sequentially, or concurrently on a thread pool " -"(:doc:`parallel_execution`). That invariant is what makes parallel runs " -"trustworthy." -msgstr "" -"由于第 1–2 步与第 5 步在主线程上按固定顺序执行,无论第 4 步的本地步是串行执行还是" -"在线程池上并发执行(:doc:`parallel_execution`), *聚合算术* 都完全一致。" -"正是这条不变式让并行运行值得信赖。" +"Because steps 1–2 and 5 happen on the main thread in fixed order, the *aggregation arithmetic* is identical no matter how the local steps of step 4 are executed — sequentially, or concurrently on a " +"thread pool (:doc:`parallel_execution`). This invariant underlies the reproducibility guarantees of parallel execution." +msgstr "由于第 1–2 步与第 5 步在主线程上按固定顺序执行,无论第 4 步的本地步是串行执行还是在线程池上并发执行( :doc:`parallel_execution` ), *聚合算术* 都完全一致。这一不变式是并行执行可复现性保证的基础。" -#: ../../source/concepts.rst:125 -msgid "The cast in one table" -msgstr "一张表看全所有角色" +#: ../../source/concepts.rst:124 +msgid "The four objects at a glance" +msgstr "四个对象一览" -#: ../../source/concepts.rst:130 +#: ../../source/concepts.rst:129 msgid "Object" msgstr "对象" -#: ../../source/concepts.rst:131 +#: ../../source/concepts.rst:130 msgid "Configured by" msgstr "由谁配置" +#: ../../source/concepts.rst:131 +msgid "Responsible for" +msgstr "负责什么" + #: ../../source/concepts.rst:132 -msgid "Knows about" -msgstr "知晓什么" +msgid "Does not access" +msgstr "不访问" #: ../../source/concepts.rst:133 -msgid "Never touches" -msgstr "绝不触碰" - -#: ../../source/concepts.rst:134 msgid ":class:`~fl_sim.data_processing.fed_dataset.FedDataset`" msgstr "" -#: ../../source/concepts.rst:135 +#: ../../source/concepts.rst:134 msgid "constructor args" msgstr "构造参数" -#: ../../source/concepts.rst:136 +#: ../../source/concepts.rst:135 msgid "raw data, partitioning, dataloaders" msgstr "原始数据、划分、dataloader" -#: ../../source/concepts.rst:137 +#: ../../source/concepts.rst:136 msgid "training state" msgstr "训练状态" -#: ../../source/concepts.rst:138 +#: ../../source/concepts.rst:137 msgid ":class:`~fl_sim.nodes.Client`" msgstr "" -#: ../../source/concepts.rst:139 +#: ../../source/concepts.rst:138 msgid "``ClientConfig`` subclass" msgstr "``ClientConfig`` 子类" -#: ../../source/concepts.rst:140 +#: ../../source/concepts.rst:139 msgid "its own data slice and model copy" msgstr "自己的数据切片与模型副本" -#: ../../source/concepts.rst:141 +#: ../../source/concepts.rst:140 msgid "other clients, the global model's evolution" msgstr "其他客户端、全局模型的演化" -#: ../../source/concepts.rst:142 +#: ../../source/concepts.rst:141 msgid ":class:`~fl_sim.nodes.Server`" msgstr "" -#: ../../source/concepts.rst:143 +#: ../../source/concepts.rst:142 msgid "``ServerConfig`` subclass" msgstr "``ServerConfig`` 子类" -#: ../../source/concepts.rst:144 +#: ../../source/concepts.rst:143 msgid "global model, sampling, aggregation, logging" msgstr "全局模型、采样、聚合、日志" -#: ../../source/concepts.rst:145 +#: ../../source/concepts.rst:144 msgid "client-local data" msgstr "客户端本地数据" -#: ../../source/concepts.rst:148 +#: ../../source/concepts.rst:147 msgid "Where to go next" msgstr "接下来去哪里" -#: ../../source/concepts.rst:150 +#: ../../source/concepts.rst:149 msgid ":doc:`quickstart` — run all of this in five rounds on synthetic data." msgstr ":doc:`quickstart`——在合成数据上用五轮跑通以上全部。" -#: ../../source/concepts.rst:151 +#: ../../source/concepts.rst:150 msgid ":doc:`api/nodes` — the full Server/Client API reference." msgstr ":doc:`api/nodes`——完整的 Server/Client API 参考。" -#: ../../source/concepts.rst:152 -msgid "" -":ref:`config reference ` — every config field of every " -"algorithm." +#: ../../source/concepts.rst:151 +msgid ":ref:`config reference ` — every config field of every algorithm." msgstr ":ref:`config reference `——每个算法的全部配置字段。" -#: ../../source/concepts.rst:154 -msgid ":doc:`viz` — explore the produced logs interactively." +#: ../../source/concepts.rst:153 +msgid ":doc:`viz` — interactive exploration of the produced logs." msgstr ":doc:`viz`——交互式地探索产出的日志。" + +#~ msgid "The cast in one table" +#~ msgstr "一张表看全所有角色" + +#~ msgid "Knows about" +#~ msgstr "知晓什么" + +#~ msgid "Never touches" +#~ msgstr "绝不触碰" diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/quickstart.po b/docs/source/locale/zh_CN/LC_MESSAGES/quickstart.po index 7ca7b991..15c2540a 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/quickstart.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/quickstart.po @@ -6,17 +6,17 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: fl-sim \n" +"Project-Id-Version: fl-sim\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-27 08:46+0800\n" +"POT-Creation-Date: 2026-10-28 23:45+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: zh_CN\n" "Language-Team: zh_CN \n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.16.0\n" #: ../../source/quickstart.rst:4 @@ -25,33 +25,21 @@ msgstr "快速上手" #: ../../source/quickstart.rst:6 msgid "" -"This page walks you through your first federated training run with fl-" -"sim: install the package, train :class:`~fl_sim.algorithms.fedopt.FedAvg`" -" on a synthetic dataset, and look at the logs it produces. The whole run " -"takes seconds on a laptop — no dataset download, no GPU required." -msgstr "" -"本页面带你完成第一次联邦训练:安装 fl-sim,在合成数据集上训练 " -":class:`~fl_sim.algorithms.fedopt.FedAvg`,并查看产出的日志。整个过程在笔记本电脑上几秒即可完成——无需下载数据集,也无需" -" GPU。" +"This page describes a first federated training run with fl-sim: install the package, train :class:`~fl_sim.algorithms.fedopt.FedAvg` on a synthetic dataset, and inspect the logs it produces. The run" +" completes in seconds on a laptop and requires neither a dataset download nor a GPU." +msgstr "本页面介绍 fl-sim 上第一次联邦训练的完整流程:安装本包,在合成数据集上训练 :class:`~fl_sim.algorithms.fedopt.FedAvg`,并查看其产出的日志。整个运行在笔记本电脑上数秒内即可完成,既不需要下载数据集,也不需要 GPU。" #: ../../source/quickstart.rst:11 -msgid "" -"If you prefer understanding the concepts first, read :doc:`concepts` and " -"come back." -msgstr "如果你更愿意先了解概念,可以先阅读 :doc:`concepts` 再回来。" +msgid "The core concepts are described in :doc:`concepts`; readers who prefer a conceptual overview first may start there." +msgstr "核心概念见 :doc:`concepts` ;希望先了解概念的读者可从该页开始。" #: ../../source/quickstart.rst:15 msgid "Prerequisites" msgstr "准备条件" #: ../../source/quickstart.rst:17 -msgid "" -"Install fl-sim following :doc:`install` (``pip install " -"git+https://github.com/wenh06/fl-sim.git``). Python 3.10+ with PyTorch is" -" all you need." -msgstr "" -"按照 :doc:`install` 安装 fl-sim(``pip install git+https://github.com/wenh06" -"/fl-sim.git``)。只需 Python 3.10+ 与 PyTorch。" +msgid "Install fl-sim following :doc:`install` (``pip install git+https://github.com/wenh06/fl-sim.git``). Python 3.10+ with PyTorch is required." +msgstr "按照 :doc:`install` 安装 fl-sim(``pip install git+https://github.com/wenh06/fl-sim.git``)。需要 Python 3.10+ 与 PyTorch。" #: ../../source/quickstart.rst:21 msgid "Train your first model" @@ -59,55 +47,33 @@ msgstr "训练第一个模型" #: ../../source/quickstart.rst:23 msgid "" -"Every federated run in fl-sim is built from three objects: a **dataset** " -"(the data plus how it is split across clients), a **model** (a PyTorch " -"module, here taken from the dataset's built-in candidates), and a " -"**server** (which owns the global model, samples clients, and " -"aggregates). The server config carries the federated schedule (rounds, " -"client count, sampling ratio); the client config carries the local " -"training recipe." -msgstr "" -"fl-sim 中的每次联邦训练都由三个对象构成: **数据集** (数据本身以及在客户端之间的划分方式)、 **模型** (一个 PyTorch " -"模块,这里取自数据集内置的候选模型)和 **服务器** " -"(持有全局模型,负责采样客户端与聚合)。服务器配置承载联邦训练的调度(轮数、客户端数量、采样比例);客户端配置承载本地训练方案。" +"Every federated run in fl-sim is built from three objects: a **dataset** (the data plus how it is split across clients), a **model** (a PyTorch module, here taken from the dataset's built-in " +"candidates), and a **server** (which owns the global model, samples clients, and aggregates). The server config carries the federated schedule (rounds, client count, sampling ratio); the client " +"config carries the local training recipe." +msgstr "fl-sim 中的每次联邦训练都由三个对象构成: **数据集** (数据本身以及在客户端之间的划分方式)、 **模型** (一个 PyTorch 模块,这里取自数据集内置的候选模型)和 **服务器** (持有全局模型,负责采样客户端与聚合)。服务器配置承载联邦训练的调度(轮数、客户端数量、采样比例);客户端配置承载本地训练方案。" #: ../../source/quickstart.rst:35 msgid "" -"Paste this into a script (or a REPL) and run it. ``FedSynthetic`` " -"generates a synthetic classification dataset split across 30 clients — " -"nothing is downloaded. ``FedAvgServerConfig(num_iters=5, num_clients=10, " -"clients_sample_ratio=1.0)`` runs **5 rounds**, each sampling **10 of the " -"30 clients** with all of them responding. ``server.train()`` runs the " -"full federated loop; you will see per-round progress and metrics in the " -"console." +"The code runs as a script or in a REPL. ``FedSynthetic`` generates a synthetic classification dataset split across 30 clients; nothing is downloaded. ``FedAvgServerConfig(num_iters=5, " +"num_clients=10, clients_sample_ratio=1.0)`` runs **5 rounds**, each sampling **10 of the 30 clients** with all of them responding. ``server.train()`` executes the full federated loop; per-round " +"progress and metrics are printed to the console." msgstr "" -"把这段代码粘贴到脚本(或 REPL)里运行。``FedSynthetic`` 会在本地生成一个划分给 30 " -"个客户端的合成分类数据集——不下载任何东西。``FedAvgServerConfig(num_iters=5, num_clients=10, " -"clients_sample_ratio=1.0)`` 运行 **5 轮**,每轮从 30 个客户端中采样 **10 " -"个**,且全部参与。``server.train()`` 运行完整的联邦循环;你会在控制台看到每轮的进度与指标。" +"上述代码可作为脚本运行,也可在 REPL 中执行。 ``FedSynthetic`` 在本地生成划分给 30 个客户端的合成分类数据集,不执行任何下载。 ``FedAvgServerConfig(num_iters=5, num_clients=10, clients_sample_ratio=1.0)`` 运行 **5 轮**,每轮从 30 个客户端中采样 **10 个**,且全部响应。 " +"``server.train()`` 执行完整的联邦循环;每轮的进度与指标将打印到控制台。" #: ../../source/quickstart.rst:44 -msgid "" -"``server.train()`` is ``server.train(\"federated\")``. fl-sim can also " -"run ``\"centralized\"`` and ``\"local\"`` baselines with the same objects" -" — see the :meth:`~fl_sim.nodes.Server.train` API." -msgstr "" -"``server.train()`` 即 ``server.train(\"federated\")``。fl-sim 也可以用同样的对象运行 " -"``\"centralized\"`` 与 ``\"local\"`` 基线——参见 " -":meth:`~fl_sim.nodes.Server.train` API。" +msgid "``server.train()`` is ``server.train(\"federated\")``. fl-sim can also run ``\"centralized\"`` and ``\"local\"`` baselines with the same objects — see the :meth:`~fl_sim.nodes.Server.train` API." +msgstr "``server.train()`` 即 ``server.train(\"federated\")``。fl-sim 也可以用同样的对象运行 ``\"centralized\"`` 与 ``\"local\"`` 基线——参见 :meth:`~fl_sim.nodes.Server.train` API。" #: ../../source/quickstart.rst:49 -msgid "Where do the logs go?" -msgstr "日志在哪里?" +msgid "Log files" +msgstr "日志文件" #: ../../source/quickstart.rst:51 msgid "" -"Every run writes its logs to ``~/.cache/fl-sim/.logs/`` (override the " -"subdirectory with ``log_dir=`` in the server config, as done here). The " -"script above reads the metrics back and prints the result:" -msgstr "" -"每次运行都会把日志写入 ``~/.cache/fl-sim/.logs/`` (可通过服务器配置里的 ``log_dir=`` " -"指定子目录,如本例所示)。上面的脚本会把指标读回来并打印结果:" +"Every run writes its logs to ``~/.cache/fl-sim/.logs/`` (the subdirectory can be overridden with ``log_dir=`` in the server config, as done here). The script above reads the metrics back and prints " +"the result:" +msgstr "每次运行的日志写入 ``~/.cache/fl-sim/.logs/``(子目录可经服务器配置中的 ``log_dir=`` 覆盖,如本例所示)。上述脚本读回指标并打印结果:" #: ../../source/quickstart.rst:62 msgid "Three files per run:" @@ -119,37 +85,22 @@ msgstr "一个 ``.txt`` 日志,保存人类可读的控制台历史;" #: ../../source/quickstart.rst:65 msgid "" -"a ``.json`` log with the full metrics history, structured as " -"``{\"train\": {...}, \"val\": {\"Server\": [...], \"Client0\": [...], " -"...}}`` — one dict per evaluation, holding ``step``, ``acc``, ``loss``, " -"etc. This is the file you will plot when visualizing results;" -msgstr "" -"一个 ``.json`` 日志,保存完整的指标历史,结构为 ``{\"train\": {...}, \"val\": {\"Server\": " -"[...], \"Client0\": [...], ...}}``——每次评估对应一个字典,包含 " -"``step``、``acc``、``loss`` 等字段。可视化结果时用的就是这个文件;" +"a ``.json`` log with the full metrics history, structured as ``{\"train\": {...}, \"val\": {\"Server\": [...], \"Client0\": [...], ...}}`` — one dict per evaluation, holding ``step``, ``acc``, " +"``loss``, etc. This file is the input for visualization;" +msgstr "一个 ``.json`` 日志,保存完整的指标历史,结构为 ``{\"train\": {...}, \"val\": {\"Server\": [...], \"Client0\": [...], ...}}``——每次评估对应一个字典,包含 ``step``、``acc``、``loss`` 等字段。该文件是可视化所用的输入;" #: ../../source/quickstart.rst:69 -msgid "" -"``config.json`` — the exact server and client configs of the run, so " -"every experiment can be reproduced later." +msgid "``config.json`` — the exact server and client configs of the run, so every experiment can be reproduced later." msgstr "``config.json``——本次运行的确切服务器与客户端配置,便于日后复现每个实验。" #: ../../source/quickstart.rst:74 msgid "" -"The ``step`` in the logs counts **communications**, not rounds: each " -"round adds one downlink broadcast plus one uplink reply per sampled " -"client (10 sampled clients → step advances by 20 per round here). The " -"json snapshot is taken at the start of each round, so the final " -"communication count is higher than the last logged step." -msgstr "" -"日志中的 ``step`` 统计的是**通信次数**,而不是轮数:每轮对每个被采样客户端包含一次下行广播与一次上行回复(这里每轮采样 10 " -"个客户端,因此 step 每轮前进 20)。json 中的快照记录于每轮开始时,因此最终通信次数会大于最后一条日志的 step。" +"The ``step`` in the logs counts **communications**, not rounds: each round adds one downlink broadcast plus one uplink reply per sampled client (10 sampled clients → step advances by 20 per round " +"here). The json snapshot is taken at the start of each round, so the final communication count is higher than the last logged step." +msgstr "日志中的 ``step`` 统计的是**通信次数**,而不是轮数:每轮对每个被采样客户端包含一次下行广播与一次上行回复(这里每轮采样 10 个客户端,因此 step 每轮前进 20)。json 中的快照记录于每轮开始时,因此最终通信次数会大于最后一条日志的 step。" #: ../../source/quickstart.rst:80 -msgid "" -"(The exact accuracy value may differ across machines and package " -"versions; on one machine this run ends at 0.8767, up from 0.011 — chance " -"level for 10 classes — at initialization.)" +msgid "(The exact accuracy value may differ across machines and package versions; on one machine this run ends at 0.8767, up from 0.011 — chance level for 10 classes — at initialization.)" msgstr "(具体精度数值可能因机器与包版本而异;在一种机器上,该运行的最终精度为 0.8767,初始时为 0.011——即 10 类任务的随机水平。)" #: ../../source/quickstart.rst:85 @@ -157,26 +108,23 @@ msgid "Next steps" msgstr "下一步" #: ../../source/quickstart.rst:87 -msgid "" -":doc:`concepts` — what actually happens in each round: sampling, " -"broadcast, local updates, aggregation." +msgid ":doc:`concepts` — what actually happens in each round: sampling, broadcast, local updates, aggregation." msgstr ":doc:`concepts`——每一轮实际发生了什么:采样、广播、本地更新、聚合。" #: ../../source/quickstart.rst:89 -msgid "" -":doc:`tutorial-first-experiment` — turn this single run into a controlled" -" comparison across algorithms and sampling ratios." -msgstr "" -":doc:`tutorial-first-experiment`——把这个单次运行变成跨算法、跨采样比例的对照实验。" +msgid ":doc:`tutorial-first-experiment` — turn this single run into a controlled comparison across algorithms and sampling ratios." +msgstr ":doc:`tutorial-first-experiment`——把这个单次运行变成跨算法、跨采样比例的对照实验。" #: ../../source/quickstart.rst:91 -msgid "" -":doc:`tutorial-cli-matrix` — run experiment batches from the CLI with " -"YAML config files." +msgid ":doc:`tutorial-cli-matrix` — run experiment batches from the CLI with YAML config files." msgstr ":doc:`tutorial-cli-matrix`——用 YAML 配置文件从命令行跑实验批次。" #: ../../source/quickstart.rst:93 -msgid "" -":doc:`parallel_execution` — speed training up with a parallel executor " -"backend while keeping results reproducible." +msgid ":doc:`parallel_execution` — accelerate training with a parallel executor backend while keeping results reproducible." msgstr ":doc:`parallel_execution`——用并行执行后端加速训练,同时保持结果可复现。" + +#~ msgid "If you prefer understanding the concepts first, read :doc:`concepts` and come back." +#~ msgstr "如果你更愿意先了解概念,可以先阅读 :doc:`concepts` 再回来。" + +#~ msgid "Where do the logs go?" +#~ msgstr "日志在哪里?" diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-cli-matrix.po b/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-cli-matrix.po index ba28f468..07f16e7f 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-cli-matrix.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-cli-matrix.po @@ -6,17 +6,17 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: fl-sim \n" +"Project-Id-Version: fl-sim\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-28 08:06+0800\n" +"POT-Creation-Date: 2026-10-30 01:15+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: zh_CN\n" "Language-Team: zh_CN \n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.16.0\n" #: ../../source/tutorial-cli-matrix.rst:4 @@ -25,154 +25,108 @@ msgstr "教程:用 CLI 跑实验矩阵" #: ../../source/tutorial-cli-matrix.rst:6 msgid "" -"Writing one Python script per experiment does not scale. fl-sim's command" -" line interface runs a whole **experiment matrix** from a single YAML " -"file: you describe the grid of configurations once, and the CLI expands " -"and executes every combination. This tutorial builds a four-run matrix on" -" synthetic data and shows where the results land." -msgstr "" -"每个实验写一个 Python 脚本是无法扩展的。fl-sim 的命令行接口能用单个 YAML 文件跑起一整个 **实验矩阵** " -":你把配置网格描述一次,CLI 负责展开并执行每个组合。本教程在合成数据上构建一个四次运行的矩阵,并展示结果落在哪里。" +"Managing one Python script per experiment becomes impractical as the number of experiments grows. The fl-sim command line interface runs a whole **experiment matrix** from a single YAML file: the " +"grid of configurations is described once, and the CLI expands and executes every combination. This tutorial builds a four-run matrix on synthetic data and shows where the results are written." +msgstr "随着实验数量增长,为每个实验单独编写 Python 脚本将变得难以管理。fl-sim 命令行接口能用单个 YAML 文件运行一整个 **实验矩阵** :配置网格只需描述一次,CLI 负责展开并执行每个组合。本教程在合成数据上构建一个四次运行的矩阵,并展示结果的写入位置。" -#: ../../source/tutorial-cli-matrix.rst:12 -msgid "" -"The YAML syntax reference lives in :doc:`cli`; this page is the workflow " -"narrative. Prerequisites: :doc:`tutorial-first-experiment`." +#: ../../source/tutorial-cli-matrix.rst:13 +msgid "The YAML syntax reference lives in :doc:`cli`; this page is the workflow narrative. Prerequisites: :doc:`tutorial-first-experiment`." msgstr "YAML 语法参考见 :doc:`cli` ;本页讲的是工作流程。前置阅读::doc:`tutorial-first-experiment` 。" -#: ../../source/tutorial-cli-matrix.rst:16 +#: ../../source/tutorial-cli-matrix.rst:17 msgid "The matrix file" msgstr "矩阵文件" -#: ../../source/tutorial-cli-matrix.rst:18 -msgid "" -"Here is the complete config for this tutorial (``example-configs" -"/fedsynthetic-demo.yml``):" +#: ../../source/tutorial-cli-matrix.rst:19 +msgid "Here is the complete config for this tutorial (``example-configs/fedsynthetic-demo.yml``):" msgstr "本教程的完整配置如下(``example-configs/fedsynthetic-demo.yml`` ):" -#: ../../source/tutorial-cli-matrix.rst:24 +#: ../../source/tutorial-cli-matrix.rst:25 msgid "Three sections matter:" msgstr "三个关键部分:" -#: ../../source/tutorial-cli-matrix.rst:26 -msgid "" -"``strategy.matrix`` — the grid. Every combination of the listed values is" -" run once: 2 sampling ratios × 2 seeds = 4 experiments." +#: ../../source/tutorial-cli-matrix.rst:27 +msgid "``strategy.matrix`` — the grid. Every combination of the listed values is run once: 2 sampling ratios × 2 seeds = 4 experiments." msgstr "``strategy.matrix``——网格。列出的值每个组合各跑一次:2 个采样比例 × 2 个种子= 4 个实验。" -#: ../../source/tutorial-cli-matrix.rst:28 +#: ../../source/tutorial-cli-matrix.rst:29 msgid "" -"``${{ matrix. }}`` — interpolation. Wherever this pattern appears, " -"the CLI substitutes the current combination's value. ``seed`` sits at the" -" top level, so it seeds the dataset *and* the server config of that run." -msgstr "" -"``${{ matrix. }}``——插值。该模式出现之处,CLI 都会代入当前组合的值。``seed`` " -"位于顶层,因此它同时为该次运行的数据集 *和* 服务器配置设定种子。" +"``${{ matrix. }}`` — interpolation. Wherever this pattern appears, the CLI substitutes the current combination's value. ``seed`` sits at the top level, so it seeds the dataset *and* the server " +"config of that run." +msgstr "``${{ matrix. }}``——插值。该模式出现之处,CLI 都会代入当前组合的值。``seed`` 位于顶层,因此它同时为该次运行的数据集 *和* 服务器配置设定种子。" -#: ../../source/tutorial-cli-matrix.rst:32 +#: ../../source/tutorial-cli-matrix.rst:33 msgid "" -"everything else — ``algorithm`` (name plus server/client configs), " -"``dataset``, ``model`` — is exactly the config you would pass in Python, " -"per :doc:`quickstart`, just spelled as YAML. Dataset-specific constructor" -" arguments (``alpha``, ``beta``, ``iid``, ``num_clients`` for " -":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic`) are passed " -"straight through." +"everything else — ``algorithm`` (name plus server/client configs), ``dataset``, ``model`` — is exactly the config you would pass in Python, per :doc:`quickstart`, just spelled as YAML. Dataset-" +"specific constructor arguments (``alpha``, ``beta``, ``iid``, ``num_clients`` for :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic`) are passed straight through." msgstr "" -"其余部分—— ``algorithm`` (名字加服务器/客户端配置)、 ``dataset`` 、 ``model`` ——与你在 Python" -" 里传入的配置(见 :doc:`quickstart` )完全一致,只是改写成 YAML。数据集各自的构造参数( " -":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` 的 ``alpha`` 、" -" ``beta`` 、 ``iid`` 、 ``num_clients`` )原样透传。" +"其余部分—— ``algorithm`` (名字加服务器/客户端配置)、 ``dataset`` 、 ``model`` ——与你在 Python 里传入的配置(见 :doc:`quickstart` )完全一致,只是改写成 YAML。数据集各自的构造参数( :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` 的 " +"``alpha`` 、 ``beta`` 、 ``iid`` 、 ``num_clients`` )原样透传。" -#: ../../source/tutorial-cli-matrix.rst:40 -msgid "Run it" -msgstr "运行" +#: ../../source/tutorial-cli-matrix.rst:41 +msgid "Running the matrix" +msgstr "运行矩阵" -#: ../../source/tutorial-cli-matrix.rst:46 -msgid "" -"You will see the four runs execute in sequence, each logging its " -"combination (``ratio=0.5 seed=0``, ...). Total time: seconds — no " -"downloads." -msgstr "你会看到四次运行依次执行,每次都会记录自己的组合(``ratio=0.5 seed=0`` 等)。总耗时:几秒——无下载。" +#: ../../source/tutorial-cli-matrix.rst:47 +msgid "The four runs execute in sequence, each logging its combination (``ratio=0.5 seed=0``, ...). The total time is a few seconds; nothing is downloaded." +msgstr "四次运行依次执行,各自记录自己的组合( ``ratio=0.5 seed=0`` 等)。总耗时数秒,无下载。" -#: ../../source/tutorial-cli-matrix.rst:51 -msgid "Where the results land" -msgstr "结果落在哪里" +#: ../../source/tutorial-cli-matrix.rst:52 +msgid "Results location" +msgstr "结果位置" -#: ../../source/tutorial-cli-matrix.rst:53 +#: ../../source/tutorial-cli-matrix.rst:54 msgid "" -"All runs write into ``~/.cache/fl-sim/.logs/fedsynthetic-demo/`` (the " -"``log_dir`` of this config). Per run you get one ``.txt`` and one " -"``.json`` log — the same files :doc:`quickstart` described — plus one " -"``config.json`` holding the exact server/client configs of the most " -"recent run (a previous ``config.json`` is rotated to " -"``config.json.bak``)." +"All runs write into ``~/.cache/fl-sim/.logs/fedsynthetic-demo/`` (the ``log_dir`` of this config). Per run you get one ``.txt`` and one ``.json`` log — the same files :doc:`quickstart` described — " +"plus one ``config.json`` holding the exact server/client configs of the most recent run (a previous ``config.json`` is rotated to ``config.json.bak``)." msgstr "" -"所有运行都写入 ``~/.cache/fl-sim/.logs/fedsynthetic-demo/``(本配置的 ``log_dir`` " -")。每次运行各有一份 ``.txt`` 与一份 ``.json`` 日志——即 :doc:`quickstart` 描述过的那些文件——另有一份 " -"``config.json`` 保存最近一次运行的确切服务器/客户端配置(已有的 ``config.json`` 会被轮转为 " -"``config.json.bak`` )。" +"所有运行都写入 ``~/.cache/fl-sim/.logs/fedsynthetic-demo/``(本配置的 ``log_dir`` )。每次运行各有一份 ``.txt`` 与一份 ``.json`` 日志——即 :doc:`quickstart` 描述过的那些文件——另有一份 ``config.json`` 保存最近一次运行的确切服务器/客户端配置(已有的 " +"``config.json`` 会被轮转为 ``config.json.bak`` )。" -#: ../../source/tutorial-cli-matrix.rst:60 +#: ../../source/tutorial-cli-matrix.rst:61 msgid "" -"One detail that matters as soon as runs finish within the same minute: " -"log file names carry a timestamp **plus the run's ``tag``**. Without a " -"distinct tag per matrix combination, same-named logs overwrite each " -"other. That is what the ``tag: ratio_${{ ... }}_seed_${{ ... }}`` line in" -" the config above is for — give every matrix arm its own tag." -msgstr "" -"一个在多次运行同一分钟内结束时就会生效的细节:日志文件名带有时间戳 **加上运行的 ``tag``** 。若每个矩阵组合没有独特的 " -"tag,同名的日志会互相覆盖。上面配置里的 ``tag: ratio_${{ ... }}_seed_${{ ... }}`` " -"正是为此——给矩阵的每个分支一个专属 tag。" +"One detail matters as soon as several runs finish within the same minute: log file names carry a timestamp **plus the run's ``tag``**. Without a distinct tag per matrix combination, identically " +"named logs overwrite one another. This is the purpose of the ``tag: ratio_${{ ... }}_seed_${{ ... }}`` line in the config above: every matrix arm receives its own tag." +msgstr "当多次运行在同一分钟内结束时,一个细节便变得重要:日志文件名带有时间戳 **以及该运行的 ``tag``** 。若每个矩阵组合没有独特的 tag,同名的日志会互相覆盖。上面配置中的 ``tag: ratio_${{ ... }}_seed_${{ ... }}`` 一行正是为此:每个矩阵分支都有自己的 tag。" -#: ../../source/tutorial-cli-matrix.rst:67 +#: ../../source/tutorial-cli-matrix.rst:68 msgid "Beyond serial execution" msgstr "超越串行执行" -#: ../../source/tutorial-cli-matrix.rst:69 +#: ../../source/tutorial-cli-matrix.rst:70 msgid "" -"A matrix of long experiments wants more than one process. The " -"``strategy`` section also accepts parallel options (``n_parallel``, or a " -"``parallel: {mode: parallel_task, num_workers: N}`` block) that dispatch " -"matrix arms to worker processes — see ``example-configs/multiprocessing-" -"demo.yml`` for a complete example, and :doc:`parallel_execution` for the " -"in-process executor backend that parallelizes *within* a single run. The " -"two are orthogonal: process-level parallelism across matrix arms, " -"executor-level parallelism across clients." +"Long experiment matrices benefit from more than one process. The ``strategy`` section also accepts parallel options (``n_parallel``, or a ``parallel: {mode: parallel_task, num_workers: N}`` block) " +"that dispatch matrix arms to worker processes — see ``example-configs/multiprocessing-demo.yml`` for a complete example, and :doc:`parallel_execution` for the in-process executor backend that " +"parallelizes *within* a single run. The two are orthogonal: process-level parallelism across matrix arms, executor-level parallelism across clients." msgstr "" -"长实验组成的矩阵需要不止一个进程。 ``strategy`` 节还接受并行选项(``n_parallel``,或 ``parallel: " -"{mode: parallel_task, num_workers: N}`` 块),把矩阵分支派发给工作进程——完整示例见 ``example-" -"configs/multiprocessing-demo.yml``;进程内把 *单次运行* 的客户端并行化的执行器后端见 " -":doc:`parallel_execution` 。两者正交:进程级并行作用于矩阵分支之间,执行器级并行作用于客户端之间。" +"由长时间实验组成的矩阵需要不止一个进程。 ``strategy`` 节还接受并行选项( ``n_parallel``,或 ``parallel: {mode: parallel_task, num_workers: N}`` 块),把矩阵分支派发给工作进程——完整示例见 ``example-configs/multiprocessing-demo.yml``;进程内把 *单次运行* " +"的客户端并行化的执行器后端见 :doc:`parallel_execution` 。两者正交:进程级并行作用于矩阵分支之间,执行器级并行作用于客户端之间。" -#: ../../source/tutorial-cli-matrix.rst:79 +#: ../../source/tutorial-cli-matrix.rst:80 msgid "Next steps" msgstr "下一步" -#: ../../source/tutorial-cli-matrix.rst:81 +#: ../../source/tutorial-cli-matrix.rst:82 msgid ":doc:`cli` — the full YAML syntax reference and CLI options." msgstr ":doc:`cli`——完整的 YAML 语法参考与 CLI 选项。" -#: ../../source/tutorial-cli-matrix.rst:82 +#: ../../source/tutorial-cli-matrix.rst:83 msgid ":doc:`parallel_execution` — speed up each individual run." msgstr ":doc:`parallel_execution`——加速每一次单独的运行。" -#: ../../source/tutorial-cli-matrix.rst:83 +#: ../../source/tutorial-cli-matrix.rst:84 msgid "" -":ref:`howto-custom-algorithm`, :ref:`howto-custom-dataset` and :ref" -":`howto-custom-optimizer` — extend the framework itself; the ``test-" -"files/custom_*.py`` files they walk through are complete, runnable " -"examples that the CLI accepts as algorithm/dataset paths." -msgstr "" -":ref:`howto-custom-algorithm` 、 :ref:`howto-custom-dataset` 与 :ref:`howto-custom-optimizer` ——扩展框架本身;它们讲解的 ``test-files/custom_*.py`` 就是完整可运行的例子,CLI 可直接接受为算法/数据集路径。" +":ref:`howto-custom-algorithm`, :ref:`howto-custom-dataset` and :ref:`howto-custom-optimizer` — extend the framework itself; the ``test-files/custom_*.py`` files they walk through are complete, " +"runnable examples that the CLI accepts as algorithm/dataset paths." +msgstr " :ref:`howto-custom-algorithm` 、 :ref:`howto-custom-dataset` 与 :ref:`howto-custom-optimizer` ——扩展框架本身;它们讲解的 ``test-files/custom_*.py`` 就是完整可运行的例子,CLI 可直接接受为算法/数据集路径。" + +#~ msgid "Run it" +#~ msgstr "运行" + +#~ msgid "Where the results land" +#~ msgstr "结果落在哪里" #~ msgid "" -#~ "How-to guides on custom algorithms, " -#~ "datasets and optimizers are on the " -#~ "way; until then, ``test-files/custom_alg.py``," -#~ " ``test-files/custom_dataset.py`` and ``test-" -#~ "files/custom_optimizer.py`` are complete, runnable" -#~ " examples." -#~ msgstr "" -#~ "自定义算法、数据集与优化器的 how-to 指南正在准备中;在那之前,``test-" -#~ "files/custom_alg.py``、``test-files/custom_dataset.py`` 与" -#~ " ``test-files/custom_optimizer.py`` 就是完整可运行的例子。" +#~ "How-to guides on custom algorithms, datasets and optimizers are on the way; until then, ``test-files/custom_alg.py``, ``test-files/custom_dataset.py`` and ``test-files/custom_optimizer.py`` are " +#~ "complete, runnable examples." +#~ msgstr "自定义算法、数据集与优化器的 how-to 指南正在准备中;在那之前,``test-files/custom_alg.py``、``test-files/custom_dataset.py`` 与 ``test-files/custom_optimizer.py`` 就是完整可运行的例子。" diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-first-experiment.po b/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-first-experiment.po index bcaec410..1e93ec2b 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-first-experiment.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/tutorial-first-experiment.po @@ -6,50 +6,37 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: fl-sim \n" +"Project-Id-Version: fl-sim\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-28 07:53+0800\n" +"POT-Creation-Date: 2026-10-29 23:49+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: zh_CN\n" "Language-Team: zh_CN \n" -"Plural-Forms: nplurals=1; plural=0;\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.16.0\n" #: ../../source/tutorial-first-experiment.rst:4 -msgid "Tutorial: your first controlled experiment" -msgstr "教程:你的第一个对照实验" +msgid "Tutorial: a first controlled experiment" +msgstr "教程:第一个对照实验" #: ../../source/tutorial-first-experiment.rst:6 msgid "" -":doc:`Quickstart ` ran one training once. A real experiment " -"compares configurations under identical conditions and reads the results " -"back. In this tutorial you will compare three algorithms at two sampling " -"ratios, then dissect what \"communication cost\" actually means in fl-" -"sim." -msgstr "" -":doc:`Quickstart ` " -"只跑了一次训练。真正的实验要在相同条件下比较不同配置,并把结果读回来。本教程将比较三个算法在两种采样比例下的表现,然后剖析 fl-sim " -"中\"通信开销\"究竟指什么。" +":doc:`Quickstart ` executes a single training run. A complete experiment compares configurations under identical conditions and reads the results back. This tutorial compares three " +"algorithms at two sampling ratios, then examines what \"communication cost\" denotes in fl-sim." +msgstr ":doc:`Quickstart ` 执行单次训练。完整的实验在相同条件下比较不同配置,并把结果读回。本教程比较三个算法在两种采样比例下的表现,然后考察 fl-sim 中\"通信开销\"的确切含义。" #: ../../source/tutorial-first-experiment.rst:11 msgid "" -"Everything runs on " -":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` — no " -"downloads, seconds per run. The full script shown below lives at ``test-" -"files/tutorial_first_experiment.py`` and is exercised in CI." -msgstr "" -"全部运行基于 " -":class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic`——无需下载,每次运行只需几秒。下文展示的完整脚本位于" -" ``test-files/tutorial_first_experiment.py``,并在 CI 中被执行。" +"Everything runs on :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` — no downloads, seconds per run. The full script shown below lives at ``test-files/tutorial_first_experiment.py`` and " +"is exercised in CI." +msgstr "全部运行基于 :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic`——无需下载,每次运行只需几秒。下文展示的完整脚本位于 ``test-files/tutorial_first_experiment.py``,并在 CI 中被执行。" #: ../../source/tutorial-first-experiment.rst:15 -msgid "" -"Prerequisites: :doc:`quickstart` (the three-object model: dataset, model," -" server) and :doc:`concepts` (what a round does)." +msgid "Prerequisites: :doc:`quickstart` (the three-object model: dataset, model, server) and :doc:`concepts` (what a round does)." msgstr "前置阅读: :doc:`quickstart` (三对象模型:数据集、模型、服务器)与 :doc:`concepts` (一轮训练做了什么)。" #: ../../source/tutorial-first-experiment.rst:19 @@ -58,77 +45,49 @@ msgstr "搭建对照" #: ../../source/tutorial-first-experiment.rst:21 msgid "" -"Six runs: **FedAvg** (plain averaging), **FedProx** (proximal-regularized" -" local objectives) and **SCAFFOLD** (control variates) — the classic " -"gradient, proximal and variance-reduction axes — each at **sampling " -"ratios 0.5 and 1.0**." -msgstr "" -"六次运行: **FedAvg** (朴素平均)、 **FedProx** (近端正则的本地目标)与 **SCAFFOLD** " -"(控制变量)——梯度、近端、方差缩减三条经典轴线——各自在 **采样比例 0.5 与 1.0** 下运行。" +"Six runs: **FedAvg** (plain averaging), **FedProx** (proximal-regularized local objectives) and **SCAFFOLD** (control variates) — the classic gradient, proximal and variance-reduction axes — each at" +" **sampling ratios 0.5 and 1.0**." +msgstr "六次运行: **FedAvg** (朴素平均)、 **FedProx** (近端正则的本地目标)与 **SCAFFOLD** (控制变量)——梯度、近端、方差缩减三条经典轴线——各自在 **采样比例 0.5 与 1.0** 下运行。" #: ../../source/tutorial-first-experiment.rst:26 msgid "" -"One deliberate choice: the dataset is constructed **once, before any " -"config or server**. Config constructors re-seed the global RNG as they " -"are built, so whatever was constructed last would otherwise shift the " -"sampling stream of everything after it. The order *dataset → config → " -"server* keeps every run reproducible:" -msgstr "" -"一个刻意的选择:数据集 **只构造一次,且先于任何配置或服务器** 。配置类的构造器在构建时会重置全局 " -"RNG,谁最后构造谁生效,其后的采样流都会被移动。按 *数据集 → 配置 → 服务器* 的顺序构造,每次运行都可复现:" +"One deliberate choice: the dataset is constructed **once, before any config or server**. Config constructors re-seed the global RNG as they are built, so whatever was constructed last would " +"otherwise shift the sampling stream of everything after it. The order *dataset → config → server* keeps every run reproducible:" +msgstr "一个刻意的选择:数据集 **只构造一次,且先于任何配置或服务器** 。配置类的构造器在构建时会重置全局 RNG,谁最后构造谁生效,其后的采样流都会被移动。按 *数据集 → 配置 → 服务器* 的顺序构造,每次运行都可复现:" #: ../../source/tutorial-first-experiment.rst:37 msgid "" -"``final_accuracy`` reads a run's JSON log — the same file format you saw " -"in :doc:`quickstart`. SCAFFOLD needs its global step size ``lr`` passed " -"explicitly (its config has no default for it); FedPD will need a " -"frequency parameter later. Both are per-algorithm server keywords, " -"collected in ``SERVER_KW``." -msgstr "" -"``final_accuracy`` 读取一次运行的 JSON 日志——与 :doc:`quickstart` 中相同的文件格式。SCAFFOLD" -" 需要显式传入全局步长 ``lr``(它的配置没有默认值);FedPD 稍后也需要一个频率参数。两者都是算法各自的服务器关键字,统一收在 " -"``SERVER_KW`` 里。" +"``final_accuracy`` reads a run's JSON log — the same file format you saw in :doc:`quickstart`. SCAFFOLD needs its global step size ``lr`` passed explicitly (its config has no default for it); FedPD " +"will need a frequency parameter later. Both are per-algorithm server keywords, collected in ``SERVER_KW``." +msgstr "``final_accuracy`` 读取一次运行的 JSON 日志——与 :doc:`quickstart` 中相同的文件格式。SCAFFOLD 需要显式传入全局步长 ``lr``(它的配置没有默认值);FedPD 稍后也需要一个频率参数。两者都是算法各自的服务器关键字,统一收在 ``SERVER_KW`` 里。" #: ../../source/tutorial-first-experiment.rst:44 msgid "Run and read the results" msgstr "运行并读取结果" #: ../../source/tutorial-first-experiment.rst:46 -msgid "" -"The comparison itself is a loop, and the results land in a " -":class:`pandas.DataFrame`:" +msgid "The comparison itself is a loop, and the results land in a :class:`pandas.DataFrame`:" msgstr "对照本身就是一个循环,结果落入 :class:`pandas.DataFrame` :" #: ../../source/tutorial-first-experiment.rst:54 -msgid "" -"Output on one machine (your numbers may differ slightly by package " -"version):" +msgid "Output on one machine (your numbers may differ slightly by package version):" msgstr "在一种机器上的输出(你的数字可能因包版本略有差异):" #: ../../source/tutorial-first-experiment.rst:67 -msgid "Two honest observations about this table:" -msgstr "对这张表的两点如实观察:" +msgid "Two observations about this table:" +msgstr "关于这张表的两点观察:" #: ../../source/tutorial-first-experiment.rst:69 msgid "" -"This synthetic task is *easy* — FedProx and SCAFFOLD reach the same " -"accuracy ceiling as FedAvg at full sampling. Their advantages show up on " -"harder, more heterogeneous tasks (see the :doc:`algorithm theory pages " -"` for when each helps)." -msgstr "" -"这个合成任务 *太容易* ——全采样下 FedProx 与 SCAFFOLD 达到了和 FedAvg " -"相同的精度天花板。它们的优势要在更难、异质性更强的任务上才显现(何时用哪个,见 :doc:`算法理论页 " -"` )。" +"This synthetic task is *easy* — FedProx and SCAFFOLD reach the same accuracy ceiling as FedAvg at full sampling. Their advantages appear on harder, more heterogeneous tasks (see the :doc:`algorithm " +"theory pages ` for when each helps)." +msgstr "这个合成任务 *过于简单* ——全采样下 FedProx 与 SCAFFOLD 达到了与 FedAvg 相同的精度上限。它们的优势在更难、异质性更强的任务上才会显现(何时用哪个算法,见 :doc:`算法理论页 ` )。" #: ../../source/tutorial-first-experiment.rst:74 msgid "" -"The accuracy story saturates; the **communication** story does not. Every" -" run at ratio 0.5 used exactly 90 communications and every run at ratio " -"1.0 used exactly 180 — regardless of the algorithm. That number deserves " -"a closer look, because it is easy to misread." -msgstr "" -"精度的故事饱和了, **通信** 的故事没有:比例 0.5 的每次运行都恰好用了 90 次通信,比例 1.0 的都恰好 180 " -"次——与算法无关。这个数字值得细看,因为它很容易被误读。" +"Accuracy saturates on this task; the **communication** cost does not. Every run at ratio 0.5 used exactly 90 communications and every run at ratio 1.0 used exactly 180 — regardless of the algorithm." +" This number warrants a closer look, because it is easy to misread." +msgstr "该任务上精度已饱和, **通信** 开销则没有:比例 0.5 的每次运行都恰好使用 90 次通信,比例 1.0 的都恰好 180 次——与算法无关。这个数字值得仔细考察,因为它很容易被误读。" #: ../../source/tutorial-first-experiment.rst:80 msgid "What ``num_communications`` counts" @@ -136,26 +95,15 @@ msgstr "``num_communications`` 数的是什么" #: ../../source/tutorial-first-experiment.rst:82 msgid "" -"``num_communications`` counts **messages, not rounds**: each round adds " -"one downlink broadcast *per sampled client* plus one uplink reply *per " -"sampled client*. With 30 clients at ratio 0.5, every round is 15 " -"downlinks + 15 uplinks = 30 messages, so 3 rounds = 90; at ratio 1.0 that" -" doubles to 180." -msgstr "" -"``num_communications`` 统计的是 **消息数,不是轮数** :每轮对 *每个被采样客户端* " -"加一次下行广播,再加一次上行回复。30 个客户端、比例 0.5 时,每轮是 15 下行 + 15 上行 = 30 条消息,3 轮 = 90;比例 " -"1.0 时翻倍为 180。" +"``num_communications`` counts **messages, not rounds**: each round adds one downlink broadcast *per sampled client* plus one uplink reply *per sampled client*. With 30 clients at ratio 0.5, every " +"round is 15 downlinks + 15 uplinks = 30 messages, so 3 rounds = 90; at ratio 1.0 that doubles to 180." +msgstr "``num_communications`` 统计的是 **消息数,不是轮数** :每轮对 *每个被采样客户端* 加一次下行广播,再加一次上行回复。30 个客户端、比例 0.5 时,每轮是 15 下行 + 15 上行 = 30 条消息,3 轮 = 90;比例 1.0 时翻倍为 180。" #: ../../source/tutorial-first-experiment.rst:88 msgid "" -"The discriminating check: **3 rounds at full sampling and 6 rounds at " -"half sampling both land on 180.** The counter scales with ``2 × " -"sampled_clients × rounds``, not with rounds. Reading it as " -"\"communication rounds\" would make 90 look like \"90 rounds\" — off by a" -" factor of 30." -msgstr "" -"判别性的检验: **3 轮全采样与 6 轮半采样都恰好是 180。** 计数随 ``2 × 采样数 × 轮数`` " -"缩放,而不是随轮数。把它读成\"通信轮数\",90 就会被当成\"90 轮\"——差了 30 倍。" +"A discriminating check: **3 rounds at full sampling and 6 rounds at half sampling both give 180.** The counter scales with ``2 × sampled_clients × rounds``, not with rounds. Reading it as " +"\"communication rounds\" would make 90 look like \"90 rounds\" — off by a factor of 30." +msgstr "一个判别性检验: **3 轮全采样与 6 轮半采样都恰好得到 180。** 计数随 ``2 × 采样数 × 轮数`` 缩放,而不是随轮数。把它读成\"通信轮数\",90 就会被当成\"90 轮\"——差了 30 倍。" #: ../../source/tutorial-first-experiment.rst:94 msgid "The decomposition to keep in mind:" @@ -167,13 +115,9 @@ msgstr "\\text{FedAvg} = 2 \\times \\text{sampled} \\times \\text{rounds}" #: ../../source/tutorial-first-experiment.rst:100 msgid "" -"(Note also that the ``step`` recorded in the JSON log is a snapshot taken" -" at the *start* of each round: it trails the final counter by the last " -"round's full cost — read the final count from the server, as the scripts " -"here do.)" -msgstr "" -"(另注:JSON 日志里记录的 ``step`` 是 *每轮开始时* " -"的快照:它比最终计数少最后一轮的全部开销——最终值请从服务器读取,正如本页脚本的做法。)" +"(Note also that the ``step`` recorded in the JSON log is a snapshot taken at the *start* of each round: it trails the final counter by the last round's full cost — read the final count from the " +"server, as the scripts here do.)" +msgstr "(另注:JSON 日志里记录的 ``step`` 是 *每轮开始时* 的快照:它比最终计数少最后一轮的全部开销——最终值请从服务器读取,正如本页脚本的做法。)" #: ../../source/tutorial-first-experiment.rst:106 msgid "Sampling is not communicating" @@ -181,14 +125,9 @@ msgstr "被采样不等于在通信" #: ../../source/tutorial-first-experiment.rst:108 msgid "" -"All three algorithms above communicate every round. fl-sim also ships " -"**communication-skipping** algorithms, and they break the ``2 × sampled ×" -" rounds`` identity in an instructive way. Run FedPD — which uploads only " -"every ``int(1/p)``-th round — for five rounds next to a five-round " -"FedAvg:" -msgstr "" -"上面三个算法每一轮都在通信。fl-sim 还内置 **可跳过通信** 的算法,它们会以很有启发性的方式打破 ``2 × 采样数 × 轮数`` " -"的恒等式。让 FedPD(每 ``int(1/p)`` 轮才上传一次)与五轮 FedAvg 并排各跑五轮:" +"All three algorithms above communicate every round. fl-sim also provides **communication-skipping** algorithms, which modify the ``2 × sampled × rounds`` identity in a way that clarifies its two " +"terms. Run FedPD — which uploads only every ``int(1/p)``-th round — for five rounds next to a five-round FedAvg:" +msgstr "上面三个算法每一轮都在通信。fl-sim 还提供 **可跳过通信** 的算法,它们以能澄清该恒等式两个乘子的方式修改它。让 FedPD(每 ``int(1/p)`` 轮上传一次)与五轮 FedAvg 并排各跑五轮:" #: ../../source/tutorial-first-experiment.rst:119 msgid "Output on one machine:" @@ -196,77 +135,47 @@ msgstr "在一种机器上的输出:" #: ../../source/tutorial-first-experiment.rst:126 msgid "" -"The decomposition says it precisely: **the downlink is identical** (75 = " -"5 rounds × 15 clients — broadcasting to the sampled set is never " -"skipped); FedPD saves *uplinks only*. Five FedPD rounds cost the same 90 " -"messages as three FedAvg rounds — the same communication budget buys two " -"extra local iterations." -msgstr "" -"分解式把话说得非常准: **下行完全相同** (75 = 5 轮 × 15 客户端——对被采样集合的广播从不跳过);FedPD 省下的 " -"*全是上行* 。五轮 FedPD 花费的 90 条消息与三轮 FedAvg 相同——同样的通信预算换来了多两轮的本地迭代。" +"The decomposition is precise: **the downlink is identical** (75 = 5 rounds × 15 clients — broadcasting to the sampled set is never skipped); FedPD saves *uplinks only*. Five FedPD rounds cost the " +"same 90 messages as three FedAvg rounds: at equal communication cost, FedPD performs two more local iterations." +msgstr "分解式给出了准确的表述: **下行完全相同** (75 = 5 轮 × 15 客户端——对被采样集合的广播从不跳过);FedPD 节省的 *全部是上行* 。五轮 FedPD 花费的 90 条消息与三轮 FedAvg 相同:在相同通信开销下,FedPD 多执行两轮本地迭代。" #: ../../source/tutorial-first-experiment.rst:132 -msgid "Three practical details when you run this yourself:" -msgstr "自己动手跑时的三个实用细节:" +msgid "Three practical details for running this example:" +msgstr "运行本例的三个实用细节:" #: ../../source/tutorial-first-experiment.rst:134 msgid "" -"``p`` must satisfy **0 < p < 1**. With p = 1 FedPD uploads every round " -"(degenerating to FedAvg); with p > 1 the upload frequency becomes zero " -"and the run crashes. The config exposes ``p`` but the derived upload " -"frequency ``int(1/p)`` always wins — passing a ``comm_freq`` yourself is " -"silently overwritten." -msgstr "" -"``p`` 必须满足 **0 < p < 1** 。p = 1 时 FedPD 每轮都上传(退化为 FedAvg);p > 1 " -"时上传频率变为零,运行直接崩溃。配置暴露的是 ``p`` ,派生的上传频率 ``int(1/p)`` 始终说了算——自己传 " -"``comm_freq`` 会被静默覆写。" +"``p`` must satisfy **0 < p < 1**. With p = 1 FedPD uploads every round (degenerating to FedAvg); with p > 1 the upload frequency becomes zero and the run crashes. The config exposes ``p`` but the " +"derived upload frequency ``int(1/p)`` always wins — passing a ``comm_freq`` yourself is silently overwritten." +msgstr "``p`` 必须满足 **0 < p < 1** 。p = 1 时 FedPD 每轮都上传(退化为 FedAvg);p > 1 时上传频率变为零,运行直接崩溃。配置暴露的是 ``p`` ,派生的上传频率 ``int(1/p)`` 始终说了算——自己传 ``comm_freq`` 会被静默覆写。" #: ../../source/tutorial-first-experiment.rst:139 msgid "" -"**You will see RuntimeWarnings — they are expected, not errors.** The " -"server logs ``No message received from the clients...`` once per skipped " -"round (\"nobody uploaded this round, so the global model did not move\")," -" and each skipping client logs ``No parameters received from server...`` " -"(\"I was not given a new global model this round, so I keep working from " -"my current parameters\"). At tutorial scale the client-side message " -"appears once per (skipped client × skipped round), so it dominates the " -"console. Both are how FedPD is designed to behave." +"**You will see RuntimeWarnings — they are expected, not errors.** The server logs ``No message received from the clients...`` once per skipped round (\"nobody uploaded this round, so the global " +"model did not move\"), and each skipping client logs ``No parameters received from server...`` (\"I was not given a new global model this round, so I keep working from my current parameters\"). At " +"tutorial scale the client-side message appears once per (skipped client × skipped round), so it accounts for most of the console output. Both are how FedPD is designed to behave." msgstr "" -" **你会看到 RuntimeWarning——那是预期行为,不是错误。** 服务器对每个跳过的轮次记录 ``No message " -"received from the clients...`` (\"这轮没人上传,全局模型没有动\");每个跳过的客户端记录 ``No " -"parameters received from server...`` " -"(\"这轮没收到新的全局模型,我继续用当前参数\")。教程规模下,客户端侧的消息每个(跳过客户端 × 跳过轮次)出现一次,会刷满控制台。两者都是 " -"FedPD 的设计行为。" +" **你会看到 RuntimeWarning——那是预期行为,不是错误。** 服务器对每个跳过的轮次记录 ``No message received from the clients...`` (\"这轮没人上传,全局模型没有动\");每个跳过的客户端记录 ``No parameters received from server...`` " +"(\"这轮没收到新的全局模型,我继续用当前参数\")。教程规模下,客户端侧的消息每个(跳过客户端 × 跳过轮次)出现一次,因此它占据了控制台输出的大部分。两者都是 FedPD 的设计行为。" -#: ../../source/tutorial-first-experiment.rst:147 +#: ../../source/tutorial-first-experiment.rst:148 msgid "" -"The JSON ``step`` snapshot trails differently per algorithm: for the " -"five-round FedAvg it ends at 120 (the last round's 30 messages are " -"unlogged), for FedPD at 75 (its last round never uploads). The final " -"counts come from ``server._num_communications``." -msgstr "" -"JSON 的 ``step`` 快照落后多少因算法而异:五轮 FedAvg 终于 120(最后一轮的 30 条消息未入日志),FedPD 终于 " -"75(它的最后一轮从不上传)。最终计数请以 ``server._num_communications`` 为准。" +"The JSON ``step`` snapshot trails differently per algorithm: for the five-round FedAvg it ends at 120 (the last round's 30 messages are unlogged), for FedPD at 75 (its last round never uploads). The" +" final counts come from ``server._num_communications``." +msgstr "JSON 的 ``step`` 快照落后多少因算法而异:五轮 FedAvg 终于 120(最后一轮的 30 条消息未入日志),FedPD 终于 75(它的最后一轮从不上传)。最终计数请以 ``server._num_communications`` 为准。" -#: ../../source/tutorial-first-experiment.rst:153 +#: ../../source/tutorial-first-experiment.rst:154 msgid "Next steps" msgstr "下一步" -#: ../../source/tutorial-first-experiment.rst:155 -msgid "" -":doc:`tutorial-cli-matrix` — run the same kind of comparison from the " -"command line, as a YAML-driven experiment matrix." +#: ../../source/tutorial-first-experiment.rst:156 +msgid ":doc:`tutorial-cli-matrix` — run the same kind of comparison from the command line, as a YAML-driven experiment matrix." msgstr ":doc:`tutorial-cli-matrix`——用 YAML 实验矩阵从命令行跑同样的对照。" -#: ../../source/tutorial-first-experiment.rst:157 -msgid "" -":doc:`tutorial-visualization` — merge multi-seed runs of this comparison " -"into mean curves with error bounds." -msgstr "" -":doc:`tutorial-visualization`——把本次对照的多 seed 运行合并成带误差带的均值曲线。" +#: ../../source/tutorial-first-experiment.rst:158 +msgid ":doc:`tutorial-visualization` — merge multi-seed runs of this comparison into mean curves with error bounds." +msgstr " :doc:`tutorial-visualization` ——把本次对照的多 seed 运行合并成带误差带的均值曲线。" -#: ../../source/tutorial-first-experiment.rst:159 -msgid "" -":doc:`parallel_execution` — speed these runs up with a parallel executor " -"without changing the results." +#: ../../source/tutorial-first-experiment.rst:160 +msgid ":doc:`parallel_execution` — speed these runs up with a parallel executor without changing the results." msgstr ":doc:`parallel_execution`——用并行执行后端加速这些运行,且不改变结果。" diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index 6c95e653..3ab01adf 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -3,19 +3,19 @@ Quickstart ========== -This page walks you through your first federated training run with fl-sim: -install the package, train :class:`~fl_sim.algorithms.fedopt.FedAvg` on a -synthetic dataset, and look at the logs it produces. The whole run takes -seconds on a laptop — no dataset download, no GPU required. +This page describes a first federated training run with fl-sim: install +the package, train :class:`~fl_sim.algorithms.fedopt.FedAvg` on a synthetic +dataset, and inspect the logs it produces. The run completes in seconds on +a laptop and requires neither a dataset download nor a GPU. -If you prefer understanding the concepts first, read :doc:`concepts` and -come back. +The core concepts are described in :doc:`concepts`; readers who prefer a +conceptual overview first may start there. Prerequisites ------------- Install fl-sim following :doc:`install` (``pip install git+https://github.com/wenh06/fl-sim.git``). -Python 3.10+ with PyTorch is all you need. +Python 3.10+ with PyTorch is required. Train your first model ---------------------- @@ -32,12 +32,12 @@ sampling ratio); the client config carries the local training recipe. :start-after: # --- begin: core --- :end-before: # --- end: core --- -Paste this into a script (or a REPL) and run it. ``FedSynthetic`` generates -a synthetic classification dataset split across 30 clients — nothing is +The code runs as a script or in a REPL. ``FedSynthetic`` generates a +synthetic classification dataset split across 30 clients; nothing is downloaded. ``FedAvgServerConfig(num_iters=5, num_clients=10, clients_sample_ratio=1.0)`` runs **5 rounds**, each sampling **10 of the 30 -clients** with all of them responding. ``server.train()`` runs the full -federated loop; you will see per-round progress and metrics in the console. +clients** with all of them responding. ``server.train()`` executes the full +federated loop; per-round progress and metrics are printed to the console. .. note:: @@ -45,12 +45,12 @@ federated loop; you will see per-round progress and metrics in the console. ``"centralized"`` and ``"local"`` baselines with the same objects — see the :meth:`~fl_sim.nodes.Server.train` API. -Where do the logs go? ---------------------- +Log files +--------- -Every run writes its logs to ``~/.cache/fl-sim/.logs/`` (override the -subdirectory with ``log_dir=`` in the server config, as done here). The -script above reads the metrics back and prints the result: +Every run writes its logs to ``~/.cache/fl-sim/.logs/`` (the subdirectory +can be overridden with ``log_dir=`` in the server config, as done here). +The script above reads the metrics back and prints the result: .. code-block:: text @@ -65,7 +65,7 @@ Three files per run: - a ``.json`` log with the full metrics history, structured as ``{"train": {...}, "val": {"Server": [...], "Client0": [...], ...}}`` — one dict per evaluation, holding ``step``, ``acc``, ``loss``, etc. - This is the file you will plot when visualizing results; + This file is the input for visualization; - ``config.json`` — the exact server and client configs of the run, so every experiment can be reproduced later. @@ -90,5 +90,5 @@ Next steps controlled comparison across algorithms and sampling ratios. - :doc:`tutorial-cli-matrix` — run experiment batches from the CLI with YAML config files. -- :doc:`parallel_execution` — speed training up with a parallel executor +- :doc:`parallel_execution` — accelerate training with a parallel executor backend while keeping results reproducible. diff --git a/docs/source/tutorial-cli-matrix.rst b/docs/source/tutorial-cli-matrix.rst index 6a24a07d..d291ec2f 100644 --- a/docs/source/tutorial-cli-matrix.rst +++ b/docs/source/tutorial-cli-matrix.rst @@ -3,11 +3,12 @@ Tutorial: experiment matrices from the CLI ========================================== -Writing one Python script per experiment does not scale. fl-sim's command -line interface runs a whole **experiment matrix** from a single YAML file: -you describe the grid of configurations once, and the CLI expands and -executes every combination. This tutorial builds a four-run matrix on -synthetic data and shows where the results land. +Managing one Python script per experiment becomes impractical as the +number of experiments grows. The fl-sim command line interface runs a +whole **experiment matrix** from a single YAML file: the grid of +configurations is described once, and the CLI expands and executes every +combination. This tutorial builds a four-run matrix on synthetic data and +shows where the results are written. The YAML syntax reference lives in :doc:`cli`; this page is the workflow narrative. Prerequisites: :doc:`tutorial-first-experiment`. @@ -36,19 +37,19 @@ Three sections matter: for :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic`) are passed straight through. -Run it ------- +Running the matrix +------------------ .. code-block:: bash fl-sim example-configs/fedsynthetic-demo.yml -You will see the four runs execute in sequence, each logging its -combination (``ratio=0.5 seed=0``, ...). Total time: seconds — no -downloads. +The four runs execute in sequence, each logging its combination +(``ratio=0.5 seed=0``, ...). The total time is a few seconds; nothing is +downloaded. -Where the results land ----------------------- +Results location +---------------- All runs write into ``~/.cache/fl-sim/.logs/fedsynthetic-demo/`` (the ``log_dir`` of this config). Per run you get one ``.txt`` and one @@ -57,17 +58,17 @@ All runs write into ``~/.cache/fl-sim/.logs/fedsynthetic-demo/`` (the recent run (a previous ``config.json`` is rotated to ``config.json.bak``). -One detail that matters as soon as runs finish within the same minute: +One detail matters as soon as several runs finish within the same minute: log file names carry a timestamp **plus the run's ``tag``**. Without a -distinct tag per matrix combination, same-named logs overwrite each -other. That is what the ``tag: ratio_${{ ... }}_seed_${{ ... }}`` line -in the config above is for — give every matrix arm its own tag. +distinct tag per matrix combination, identically named logs overwrite one +another. This is the purpose of the ``tag: ratio_${{ ... }}_seed_${{ ... }}`` +line in the config above: every matrix arm receives its own tag. Beyond serial execution ----------------------- -A matrix of long experiments wants more than one process. The ``strategy`` -section also accepts parallel options (``n_parallel``, or a +Long experiment matrices benefit from more than one process. The +``strategy`` section also accepts parallel options (``n_parallel``, or a ``parallel: {mode: parallel_task, num_workers: N}`` block) that dispatch matrix arms to worker processes — see ``example-configs/multiprocessing-demo.yml`` for a complete example, and :doc:`parallel_execution` for the in-process diff --git a/docs/source/tutorial-first-experiment.rst b/docs/source/tutorial-first-experiment.rst index 736aa0a2..bf4ce2ea 100644 --- a/docs/source/tutorial-first-experiment.rst +++ b/docs/source/tutorial-first-experiment.rst @@ -1,12 +1,12 @@ .. _tutorial-first-experiment: -Tutorial: your first controlled experiment -========================================== +Tutorial: a first controlled experiment +======================================= -:doc:`Quickstart ` ran one training once. A real experiment -compares configurations under identical conditions and reads the results -back. In this tutorial you will compare three algorithms at two sampling -ratios, then dissect what "communication cost" actually means in fl-sim. +:doc:`Quickstart ` executes a single training run. A complete +experiment compares configurations under identical conditions and reads +the results back. This tutorial compares three algorithms at two sampling +ratios, then examines what "communication cost" denotes in fl-sim. Everything runs on :class:`~fl_sim.data_processing.fed_synthetic.FedSynthetic` — no downloads, seconds per run. The full script shown below lives at @@ -64,17 +64,17 @@ version): SCAFFOLD 0.5 90 0.8767 SCAFFOLD 1.0 180 0.8767 -Two honest observations about this table: +Two observations about this table: - This synthetic task is *easy* — FedProx and SCAFFOLD reach the same - accuracy ceiling as FedAvg at full sampling. Their advantages show up - on harder, more heterogeneous tasks (see the + accuracy ceiling as FedAvg at full sampling. Their advantages appear on + harder, more heterogeneous tasks (see the :doc:`algorithm theory pages ` for when each helps). -- The accuracy story saturates; the **communication** story does not. +- Accuracy saturates on this task; the **communication** cost does not. Every run at ratio 0.5 used exactly 90 communications and every run at - ratio 1.0 used exactly 180 — regardless of the algorithm. That number - deserves a closer look, because it is easy to misread. + ratio 1.0 used exactly 180 — regardless of the algorithm. This number + warrants a closer look, because it is easy to misread. What ``num_communications`` counts ---------------------------------- @@ -85,8 +85,8 @@ sampled client*. With 30 clients at ratio 0.5, every round is 15 downlinks + 15 uplinks = 30 messages, so 3 rounds = 90; at ratio 1.0 that doubles to 180. -The discriminating check: **3 rounds at full sampling and 6 rounds at -half sampling both land on 180.** The counter scales with +A discriminating check: **3 rounds at full sampling and 6 rounds at half +sampling both give 180.** The counter scales with ``2 × sampled_clients × rounds``, not with rounds. Reading it as "communication rounds" would make 90 look like "90 rounds" — off by a factor of 30. @@ -105,11 +105,11 @@ scripts here do.) Sampling is not communicating ----------------------------- -All three algorithms above communicate every round. fl-sim also ships -**communication-skipping** algorithms, and they break the -``2 × sampled × rounds`` identity in an instructive way. Run FedPD — -which uploads only every ``int(1/p)``-th round — for five rounds next to -a five-round FedAvg: +All three algorithms above communicate every round. fl-sim also provides +**communication-skipping** algorithms, which modify the +``2 × sampled × rounds`` identity in a way that clarifies its two terms. +Run FedPD — which uploads only every ``int(1/p)``-th round — for five +rounds next to a five-round FedAvg: .. literalinclude:: ../../test-files/tutorial_first_experiment.py :language: python @@ -123,13 +123,13 @@ Output on one machine: FedAvg: 150 communications = 75 downlink + 75 uplink (5 of 5 rounds uploaded) FedPD: 90 communications = 75 downlink + 15 uplink (1 of 5 rounds uploaded) -The decomposition says it precisely: **the downlink is identical** (75 = -5 rounds × 15 clients — broadcasting to the sampled set is never -skipped); FedPD saves *uplinks only*. Five FedPD rounds cost the same -90 messages as three FedAvg rounds — the same communication budget -buys two extra local iterations. +The decomposition is precise: **the downlink is identical** (75 = 5 +rounds × 15 clients — broadcasting to the sampled set is never skipped); +FedPD saves *uplinks only*. Five FedPD rounds cost the same 90 messages as +three FedAvg rounds: at equal communication cost, FedPD performs two more +local iterations. -Three practical details when you run this yourself: +Three practical details for running this example: - ``p`` must satisfy **0 < p < 1**. With p = 1 FedPD uploads every round (degenerating to FedAvg); with p > 1 the upload frequency becomes zero @@ -143,7 +143,8 @@ Three practical details when you run this yourself: from server...`` ("I was not given a new global model this round, so I keep working from my current parameters"). At tutorial scale the client-side message appears once per (skipped client × skipped round), - so it dominates the console. Both are how FedPD is designed to behave. + so it accounts for most of the console output. Both are how FedPD is + designed to behave. - The JSON ``step`` snapshot trails differently per algorithm: for the five-round FedAvg it ends at 120 (the last round's 30 messages are unlogged), for FedPD at 75 (its last round never uploads). The final diff --git a/test-files/quickstart.py b/test-files/quickstart.py index 9adedbb4..36344b66 100644 --- a/test-files/quickstart.py +++ b/test-files/quickstart.py @@ -4,7 +4,7 @@ This script is the source of the code blocks shown in the Quickstart page of the documentation (``docs/source/quickstart.rst``): the marked sections are included verbatim via Sphinx ``literalinclude`` directives, -so the docs and this script can never drift apart. The size is pinned to +so the docs and this script cannot drift apart. The size is pinned to the tutorial budget (``num_iters <= 5``, ``num_clients <= 30``, one local epoch), enforced by ``test/test_tutorial_scripts.py``. """ @@ -24,7 +24,7 @@ num_iters=5, num_clients=10, clients_sample_ratio=1.0, - log_dir="quickstart", # logs land in ~/.cache/fl-sim/.logs/quickstart/ + log_dir="quickstart", # logs are written to ~/.cache/fl-sim/.logs/quickstart/ ), FedAvgClientConfig(batch_size=32, num_epochs=1), )