From 92e3f3e0597785bb2e6acf0e9df5b61cbb065a5f Mon Sep 17 00:00:00 2001 From: anyin233 <35858233+anyin233@users.noreply.github.com> Date: Thu, 12 Mar 2026 20:39:45 +0000 Subject: [PATCH] refactor: restructure project and update documentation for second edition (#500) * feat: remove bilingual button on the front page * misc: clean repo * test: fix test suite for v1/v2 restructure and removed language switch * refactor: restructure chapters for the second edition * refactor: restructure project * refactor: remove unused scripts * refactor: move conftest.py to tests directory * refactor: update README with new chapter structure and logo path * fix: update image paths in README and README_EN for consistency * refactor: update directory structure and script references in documentation --- .gitignore | 16 ---- README.md | 46 ++++------- README_EN.md | 52 +++++------- book.toml | 19 ----- build_and_transform.sh | 2 - build_html.sh | 23 ------ build_html_zh.sh | 23 ------ build_mdbook.sh | 23 ------ build_mdbook_zh.sh | 25 ------ conftest.py | 4 - info/editors.md | 49 ------------ info/logo-with-text.png | Bin 0 -> 63767 bytes info/refenence_guide.md | 35 -------- tests/conftest.py | 4 + theme-bkup/dark-mode-images.css | 16 ---- theme-bkup/head.hbs | 12 --- theme-bkup/version-selector.css | 48 ----------- theme-bkup/version-selector.js | 75 ------------------ v1/en_chapters/img | 1 + v1/en_chapters/mlsys.bib | 1 + v1/en_chapters/references | 1 + v1/en_chapters/static | 1 + .../components_of_computational_graph.md | 1 + v1/zh_chapters/img | 1 + v1/zh_chapters/mlsys.bib | 1 + v1/zh_chapters/references | 1 + v1/zh_chapters/static | 1 + .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 v2/en_chapters/SUMMARY.md | 19 +++++ v2/en_chapters/img | 1 + v2/en_chapters/index.md | 21 +++++ v2/en_chapters/mlsys.bib | 1 + v2/en_chapters/references | 1 + v2/en_chapters/static | 1 + v2/info/CONTRIBUTING.md | 10 ++- v2/info/CONTRIBUTING_zh.md | 10 ++- .../Pic_Templates_and_Samples.pptx | Bin .../Requirements and Instructions.md | 0 {info => v2/info}/info.md | 9 +-- {info => v2/info}/issue.md | 0 v2/info/refenence_guide.md | 30 +++++++ v2/info/style.md | 2 +- v2/info/style_zh.md | 2 +- .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 .../index.md | 0 v2/zh_chapters/SUMMARY.md | 19 +++++ v2/zh_chapters/img | 1 + v2/zh_chapters/index.md | 21 +++++ v2/zh_chapters/mlsys.bib | 1 + v2/zh_chapters/references | 1 + v2/zh_chapters/static | 1 + 68 files changed, 186 insertions(+), 446 deletions(-) delete mode 100644 book.toml delete mode 100644 build_and_transform.sh delete mode 100644 build_html.sh delete mode 100755 build_html_zh.sh delete mode 100644 build_mdbook.sh delete mode 100755 build_mdbook_zh.sh delete mode 100644 conftest.py delete mode 100644 info/editors.md create mode 100644 info/logo-with-text.png delete mode 100644 info/refenence_guide.md create mode 100644 tests/conftest.py delete mode 100644 theme-bkup/dark-mode-images.css delete mode 100644 theme-bkup/head.hbs delete mode 100644 theme-bkup/version-selector.css delete mode 100644 theme-bkup/version-selector.js create mode 120000 v1/en_chapters/img create mode 120000 v1/en_chapters/mlsys.bib create mode 120000 v1/en_chapters/references create mode 120000 v1/en_chapters/static create mode 120000 v1/zh_chapters/img create mode 120000 v1/zh_chapters/mlsys.bib create mode 120000 v1/zh_chapters/references create mode 120000 v1/zh_chapters/static rename v2/en_chapters/{chapter_preface => 00_chapter_preface}/index.md (100%) rename v2/en_chapters/{chapter_introduction => 01_chapter_introduction}/index.md (100%) rename v2/en_chapters/{chapter_programming_and_graph => 02_chapter_programming_and_graph}/index.md (100%) rename v2/en_chapters/{chapter_accelerator => 03_chapter_accelerator}/index.md (100%) rename v2/en_chapters/{chapter_compiler_and_runtime => 04_chapter_compiler_and_runtime}/index.md (100%) rename v2/en_chapters/{chapter_data_processing => 05_chapter_data_processing}/index.md (100%) rename v2/en_chapters/{chapter_training_systems => 06_chapter_training_systems}/index.md (100%) rename v2/en_chapters/{chapter_model_serving => 07_chapter_model_serving}/index.md (100%) rename v2/en_chapters/{chapter_rl_systems => 08_chapter_rl_systems}/index.md (100%) rename v2/en_chapters/{chapter_gpu_cluster => 09_chapter_gpu_cluster}/index.md (100%) create mode 120000 v2/en_chapters/img create mode 120000 v2/en_chapters/mlsys.bib create mode 120000 v2/en_chapters/references create mode 120000 v2/en_chapters/static rename {info => v2/info}/Pic-Instruction/Pic_Templates_and_Samples.pptx (100%) rename {info => v2/info}/Pic-Instruction/Requirements and Instructions.md (100%) rename {info => v2/info}/info.md (65%) rename {info => v2/info}/issue.md (100%) create mode 100644 v2/info/refenence_guide.md rename v2/zh_chapters/{chapter_preface => 00_chapter_preface}/index.md (100%) rename v2/zh_chapters/{chapter_introduction => 01_chapter_introduction}/index.md (100%) rename v2/zh_chapters/{chapter_programming_and_graph => 02_chapter_programming_and_graph}/index.md (100%) rename v2/zh_chapters/{chapter_accelerator => 03_chapter_accelerator}/index.md (100%) rename v2/zh_chapters/{chapter_compiler_and_runtime => 04_chapter_compiler_and_runtime}/index.md (100%) rename v2/zh_chapters/{chapter_data_processing => 05_chapter_data_processing}/index.md (100%) rename v2/zh_chapters/{chapter_training_systems => 06_chapter_training_systems}/index.md (100%) rename v2/zh_chapters/{chapter_model_serving => 07_chapter_model_serving}/index.md (100%) rename v2/zh_chapters/{chapter_rl_systems => 08_chapter_rl_systems}/index.md (100%) rename v2/zh_chapters/{chapter_gpu_cluster => 09_chapter_gpu_cluster}/index.md (100%) create mode 120000 v2/zh_chapters/img create mode 120000 v2/zh_chapters/mlsys.bib create mode 120000 v2/zh_chapters/references create mode 120000 v2/zh_chapters/static diff --git a/.gitignore b/.gitignore index b3163ae..585dc00 100644 --- a/.gitignore +++ b/.gitignore @@ -33,19 +33,3 @@ zh_chapters/img zh_chapters/references zh_chapters/static zh_chapters/mlsys.bib -v1/en_chapters/img -v1/en_chapters/references -v1/en_chapters/static -v1/en_chapters/mlsys.bib -v1/zh_chapters/img -v1/zh_chapters/references -v1/zh_chapters/static -v1/zh_chapters/mlsys.bib -v2/en_chapters/img -v2/en_chapters/references -v2/en_chapters/static -v2/en_chapters/mlsys.bib -v2/zh_chapters/img -v2/zh_chapters/references -v2/zh_chapters/static -v2/zh_chapters/mlsys.bib diff --git a/README.md b/README.md index c087086..419ddb7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- OpenMLSys Logo + OpenMLSys Logo

@@ -46,35 +46,19 @@ ## 内容介绍 -本书分为基础篇、进阶篇和扩展篇三个部分: - -### 基础篇 +本书(第二版)共分9章: | 章节 | 内容 | |------|------| -| [编程接口](chapter_programming_interface/) | 框架接口设计哲学、机器学习工作流、深度学习模型定义、C/C++ 框架开发 | -| [计算图](chapter_computational_graph/) | 计算图基本构成、生成方法、调度策略、自动微分 | - -### 进阶篇 - -| 章节 | 内容 | -|------|------| -| [编译器前端和中间表示](chapter_frontend_and_ir/) | 类型推导、中间表示(IR)、自动微分、常见优化 Pass | -| [编译器后端和运行时](chapter_backend_and_runtime/) | 计算图优化、算子选择、内存分配、计算调度与执行 | -| [硬件加速器](chapter_accelerator/) | GPU/Ascend 架构原理、高性能编程接口(CUDA/CANN) | -| [数据处理框架](chapter_data_processing/) | 易用性、高效性、保序性、分布式数据处理 | -| [模型部署](chapter_model_deployment/) | 模型转换、模型压缩、模型推理、安全保护 | -| [分布式训练](chapter_distributed_training/) | 数据并行、模型并行、流水线并行、集合通讯、参数服务器 | - -### 扩展篇 - -| 章节 | 内容 | -|------|------| -| [深度学习推荐系统](chapter_recommender_system/) | 推荐系统原理、大规模工业场景架构设计 | -| [联邦学习系统](chapter_federated_learning/) | 联邦学习方法、隐私保护、系统实现 | -| [强化学习系统](chapter_reinforcement_learning/) | 单智能体/多智能体强化学习系统 | -| [可解释性 AI 系统](chapter_explainable_AI/) | 可解释 AI 方法与落地实践 | -| [机器人学习系统](chapter_rl_sys/) | 机器人感知、规划、控制与系统安全 | +| [第1章 导论](v2/zh_chapters/01_chapter_introduction/) | 机器学习系统架构和技术栈概述 | +| [第2章 编程接口与计算图](v2/zh_chapters/02_chapter_programming_and_graph/) | 张量抽象、自动微分、图表示与执行 | +| [第3章 AI加速器与编程](v2/zh_chapters/03_chapter_accelerator/) | GPU 架构与 CUDA/Triton/CUTLASS 编程模型 | +| [第4章 AI编译器与运行时系统](v2/zh_chapters/04_chapter_compiler_and_runtime/) | IR 设计、图优化、算子生成与运行时执行 | +| [第5章 数据处理系统](v2/zh_chapters/05_chapter_data_processing/) | 数据加载、数据管道和分布式数据处理 | +| [第6章 训练系统](v2/zh_chapters/06_chapter_training_systems/) | 单节点与分布式训练、并行策略与训练优化 | +| [第7章 模型服务](v2/zh_chapters/07_chapter_model_serving/) | 推理优化、在线服务与模型管理 | +| [第8章 强化学习系统](v2/zh_chapters/08_chapter_rl_systems/) | 强化学习管道、环境交互与 RL 系统设计 | +| [第9章 大规模GPU集群管理](v2/zh_chapters/09_chapter_gpu_cluster/) | GPU 调度、资源管理与大规模训练基础设施 | ## 更新日志 @@ -91,6 +75,7 @@ - curl - git +- Python 3 ### 安装步骤 @@ -109,11 +94,12 @@ cargo install mdbook ### 编译HTML ```bash -sh build_mdbook_zh.sh -# 生成结果位于 .mdbook-zh/book +sh build_mdbook_v2.sh +# 英文版生成结果位于 .mdbook-v2/book +# 中文版生成结果位于 .mdbook-v2-zh/book ``` -更多细节请参考 [构建指南](info/info.md)。 +更多细节请参考 [构建指南](v2/info/info.md)。 ## 贡献指南 diff --git a/README_EN.md b/README_EN.md index 05f63e3..dc796c6 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,5 +1,5 @@

- OpenMLSys Logo + OpenMLSys Logo

@@ -48,35 +48,19 @@ An open-source book explaining the design principles and implementation experien ## Content Overview -The book is organized into three parts: Fundamentals, Advanced Topics, and Extensions. - -### Part I: Fundamentals +The book (2nd edition) consists of 9 chapters: | Chapter | Content | |---------|---------| -| [Programming Interface](chapter_programming_interface/) | Framework API design, ML workflows, deep learning model definition, C/C++ framework development | -| [Computational Graph](chapter_computational_graph/) | Graph components, generation methods, scheduling strategies, automatic differentiation | - -### Part II: Advanced Topics - -| Chapter | Content | -|---------|---------| -| [Compiler Frontend & IR](chapter_frontend_and_ir/) | Type inference, intermediate representation (IR), automatic differentiation, common optimization passes | -| [Compiler Backend & Runtime](chapter_backend_and_runtime/) | Graph optimization, operator selection, memory allocation, compute scheduling and execution | -| [Hardware Accelerators](chapter_accelerator/) | GPU/Ascend architecture, high-performance programming interfaces (CUDA/CANN) | -| [Data Processing](chapter_data_processing/) | Usability, efficiency, order preservation, distributed data processing | -| [Model Deployment](chapter_model_deployment/) | Model conversion, compression, inference, and security | -| [Distributed Training](chapter_distributed_training/) | Data parallelism, model parallelism, pipeline parallelism, collective communication, parameter servers | - -### Part III: Extensions - -| Chapter | Content | -|---------|---------| -| [Recommender Systems](chapter_recommender_system/) | Recommendation principles, large-scale industrial architecture | -| [Federated Learning](chapter_federated_learning/) | Federated learning methods, privacy protection, system implementation | -| [Reinforcement Learning Systems](chapter_reinforcement_learning/) | Single-agent and multi-agent RL systems | -| [Explainable AI Systems](chapter_explainable_AI/) | XAI methods and production practices | -| [Robot Learning Systems](chapter_rl_sys/) | Robot perception, planning, control, and system safety | +| [Chapter 1: Introduction](v2/en_chapters/01_chapter_introduction/) | Overview of ML system architecture and technology stack | +| [Chapter 2: Programming Interfaces and Computational Graphs](v2/en_chapters/02_chapter_programming_and_graph/) | Tensor abstraction, automatic differentiation, graph representation and execution | +| [Chapter 3: AI Accelerators and Programming](v2/en_chapters/03_chapter_accelerator/) | GPU architecture and CUDA/Triton/CUTLASS programming models | +| [Chapter 4: AI Compilers and Runtime Systems](v2/en_chapters/04_chapter_compiler_and_runtime/) | IR design, graph optimization, kernel generation, and runtime execution | +| [Chapter 5: Data Processing Systems](v2/en_chapters/05_chapter_data_processing/) | Data loading, data pipelines, and distributed data processing | +| [Chapter 6: Training Systems](v2/en_chapters/06_chapter_training_systems/) | Single-node and distributed training, parallelism strategies, and training optimization | +| [Chapter 7: Model Serving](v2/en_chapters/07_chapter_model_serving/) | Inference optimization, online serving, and model management | +| [Chapter 8: RL Systems](v2/en_chapters/08_chapter_rl_systems/) | Reinforcement learning pipelines, environment interaction, and RL system design | +| [Chapter 9: Large-scale GPU Cluster Management](v2/en_chapters/09_chapter_gpu_cluster/) | GPU scheduling, resource management, and large-scale training infrastructure | ## Changelog @@ -93,6 +77,7 @@ The book is organized into three parts: Fundamentals, Advanced Topics, and Exten - curl - git +- Python 3 ### Installation @@ -111,11 +96,12 @@ cargo install mdbook ### Build HTML ```bash -sh build_mdbook.sh -# Output is in .mdbook/book +sh build_mdbook_v2.sh +# English output: .mdbook-v2/book +# Chinese output: .mdbook-v2-zh/book ``` -For more details, see the [Build Guide](info/info.md). +For more details, see the [Build Guide](v2/info/info.md). ## Contributing @@ -127,7 +113,11 @@ Before contributing, please read: ## Community -Join our WeChat group by scanning the QR code in [info/mlsys_group.png](info/mlsys_group.png). +

+ 微信群二维码 +
+ Join our WeChat group by scanning the QR code +

## Citation diff --git a/book.toml b/book.toml deleted file mode 100644 index f0d4e0e..0000000 --- a/book.toml +++ /dev/null @@ -1,19 +0,0 @@ -[book] -authors = ["OpenMLSys Contributors"] -language = "en" -src = "en_chapters" -title = "Machine Learning Systems: Design and Implementation" - -[build] -build-dir = ".mdbook/book" -create-missing = false - -[preprocessor.openmlsys] -command = "python3 tools/mdbook_preprocessor.py" - -[output.html] -mathjax-support = true -git-repository-url = "https://github.com/openmlsys/openmlsys-zh" -preferred-dark-theme = "navy" -additional-css = ["theme/dark-mode-images.css", "theme/version-selector.css"] -additional-js = ["theme/version-selector.js"] diff --git a/build_and_transform.sh b/build_and_transform.sh deleted file mode 100644 index 70243ca..0000000 --- a/build_and_transform.sh +++ /dev/null @@ -1,2 +0,0 @@ -d2lbook build html -python3 tools/format_tables.py \ No newline at end of file diff --git a/build_html.sh b/build_html.sh deleted file mode 100644 index 904791c..0000000 --- a/build_html.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Build the English (en) version of the book from en_chapters/. -# Output: en_chapters/_build/html/ -# -# Resources (img/, references/, static/, mlsys.bib) live at the repo root and -# are symlinked into en_chapters/ so d2lbook can find them at relative paths. - -set -e - -ROOT="$(cd "$(dirname "$0")" && pwd)" - -# ── Create resource symlinks ────────────────────────────────────────────────── -python3 "$ROOT/tools/ensure_book_resources.py" --chapter-dir "$ROOT/en_chapters" - -# ── Build ───────────────────────────────────────────────────────────────────── -cd "$ROOT/en_chapters" - -rm -rf _build/rst _build/html -d2lbook build rst -cp static/frontpage.html _build/rst/ -d2lbook build html -cp -r static/image/* _build/html/_images/ 2>/dev/null || true -python3 "$ROOT/tools/format_tables.py" diff --git a/build_html_zh.sh b/build_html_zh.sh deleted file mode 100755 index ccefd76..0000000 --- a/build_html_zh.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Build the Chinese (zh) version of the book from zh_chapters/. -# Output: zh_chapters/_build/html/ -# -# Resources (img/, references/, static/, mlsys.bib) live at the repo root and -# are symlinked into zh_chapters/ so d2lbook can find them at relative paths. - -set -e - -ROOT="$(cd "$(dirname "$0")" && pwd)" - -# ── Create resource symlinks ────────────────────────────────────────────────── -python3 "$ROOT/tools/ensure_book_resources.py" --chapter-dir "$ROOT/zh_chapters" - -# ── Build ───────────────────────────────────────────────────────────────────── -cd "$ROOT/zh_chapters" - -rm -rf _build/rst _build/html -d2lbook build rst -cp static/frontpage.html _build/rst/ -d2lbook build html -cp -r static/image/* _build/html/_images/ 2>/dev/null || true -python3 "$ROOT/tools/format_tables.py" diff --git a/build_mdbook.sh b/build_mdbook.sh deleted file mode 100644 index f814264..0000000 --- a/build_mdbook.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PYTHON_BIN="$(command -v python3 || command -v python || true)" - -if [[ -z "${PYTHON_BIN}" ]]; then - echo "Python is required to prepare the mdBook staging tree." >&2 - exit 1 -fi - -if ! command -v mdbook >/dev/null 2>&1; then - echo "mdbook is not installed. Install it first, for example with: cargo install mdbook" >&2 - exit 1 -fi - -"${PYTHON_BIN}" "${ROOT}/tools/ensure_book_resources.py" --chapter-dir "${ROOT}/en_chapters" -"${PYTHON_BIN}" "${ROOT}/tools/prepare_mdbook.py" \ - --source "${ROOT}/en_chapters" \ - --summary-output "${ROOT}/en_chapters/SUMMARY.md" \ - --placeholder-prefix "[TODO: src = zh_chapters/" - -mdbook build "${ROOT}" diff --git a/build_mdbook_zh.sh b/build_mdbook_zh.sh deleted file mode 100755 index fff91c4..0000000 --- a/build_mdbook_zh.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PYTHON_BIN="$(command -v python3 || command -v python || true)" - -if [[ -z "${PYTHON_BIN}" ]]; then - echo "Python is required to prepare the mdBook staging tree." >&2 - exit 1 -fi - -if ! command -v mdbook >/dev/null 2>&1; then - echo "mdbook is not installed. Install it first, for example with: cargo install mdbook" >&2 - exit 1 -fi - -# ── Create resource links ───────────────────────────────────────────────────── -"${PYTHON_BIN}" "${ROOT}/tools/ensure_book_resources.py" --chapter-dir "${ROOT}/zh_chapters" - -# ── Build ───────────────────────────────────────────────────────────────────── -"${PYTHON_BIN}" "${ROOT}/tools/prepare_mdbook_zh.py" \ - --source "${ROOT}/zh_chapters" \ - --summary-output "${ROOT}/zh_chapters/SUMMARY.md" - -mdbook build "${ROOT}/books/zh" diff --git a/conftest.py b/conftest.py deleted file mode 100644 index 4b03990..0000000 --- a/conftest.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).resolve().parent)) diff --git a/info/editors.md b/info/editors.md deleted file mode 100644 index 7d0855e..0000000 --- a/info/editors.md +++ /dev/null @@ -1,49 +0,0 @@ -# 编辑和作者 - -## 章节编辑 - -本书由超过30位人工智能系统领域的学术专家和开发人员共同完成。以下为各个章节编辑: - -项目README: [@luomai](https://github.com/luomai) - -序言:[@luomai](https://github.com/luomai) - -导论:[@luomai](https://github.com/luomai) - -编程接口:[@Laicheng0830](https://github.com/Laicheng0830) - -计算图:[@hanjr92](https://github.com/hanjr92) - -进阶篇序言:[@ganzhiliang](https://github.com/ganzhiliang) - -编译器前端和IR: [@LiangZhibo](https://github.com/LiangZhibo) - -编译器后端和运行时: [@chujinjin101](https://github.com/chujinjin101) - -硬件加速器:[@anyrenwei](https://github.com/anyrenwei) - -数据处理框架: [@eedalong](https://github.com/eedalong) - -模型部署: [@AssassinG](https://github.com/AssassinGQ) - -分布式训练系统: [@luomai](https://github.com/luomai) - -拓展篇序言:[@luomai](https://github.com/luomai) - -深度学习推荐系统:[@future-xy](https://github.com/future-xy) - -联邦学习系统:[@chengtianwu](https://github.com/chengtianwu) - -强化学习系统:[@quantumiracle](https://github.com/quantumiracle) - -可解释性AI系统:[@HaoyangLee](https://github.com/HaoyangLee) - -机器人系统:[@Jack](https://github.com/Jiankai-Sun) - -附录:机器学习介绍:[@Hao](https://github.com/zsdonghao) - -## 加入我们 - -我们创建了OpenMLSys微信群来讨论书籍的写作和拓展。如果希望加入我们,可以扫以下二维码(加的时候请介绍自己,并说明希望参与书籍的哪方面工作): - -![OpenMLSys社区微信群](./mlsys_group.png) diff --git a/info/logo-with-text.png b/info/logo-with-text.png new file mode 100644 index 0000000000000000000000000000000000000000..ee55e2d281d8e414b70190418282e24e26e8ab3d GIT binary patch literal 63767 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 ONM8E3RE~u4v;PItvU2zU literal 0 HcmV?d00001 diff --git a/info/refenence_guide.md b/info/refenence_guide.md deleted file mode 100644 index 3197961..0000000 --- a/info/refenence_guide.md +++ /dev/null @@ -1,35 +0,0 @@ -# 参考文献引用方式 - 下面为参考文献的引用,需要注意引用时前面需要有一个空格: - 1. 单篇参考文献 - 这篇文章参考了论文 :cite:`cnn2015` - 2. 多篇参考文献可以用逗号分开 - 这篇文章参考了论文 :cite:`cnn2015,rnn2015` - 3. 此时在对应bib中应该有如下参考文献 - @inproceedings{cnn2015, - title = {CNN}, - author = {xxx}, - year = {2015}, - keywords = {xxx} - } - @inproceedings{rnn2015, - title = {RNN}, - author = {xxx}, - year = {2015}, - keywords = {xxx} - } - -# 参考文献置于章节末尾方式 -1.将章节所引用的全部参考文献生成一个chapter.pip,放置于references文件夹下。 -如机器人系统章节将该章节参考文献全部放在rlsys.bib,并将其放在reference文件夹下。 - -``` -参考文献目录 - -/references/rlsys.bib` -``` -2.将对应章节参考文献引用添加至文章末尾处,如机器人系统章节在summary最后加上 - ``` - ## 参考文献 - - :bibliography:`../references/rlsys.bib` - ``` diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..ece8e0c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,4 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) diff --git a/theme-bkup/dark-mode-images.css b/theme-bkup/dark-mode-images.css deleted file mode 100644 index e28960b..0000000 --- a/theme-bkup/dark-mode-images.css +++ /dev/null @@ -1,16 +0,0 @@ -/* 暗色模式下仅为正文图片添加浅灰色背景,提高透明背景图片的可读性 */ -.navy .content main img, -.coal .content main img, -.ayu .content main img { - background-color: #e8e8e8; - border-radius: 4px; - padding: 8px; -} - -/* 首页 frontpage 图片保持透明,不添加正文图像底色。 */ -.navy .openmlsys-frontpage img, -.coal .openmlsys-frontpage img, -.ayu .openmlsys-frontpage img { - background-color: transparent !important; - padding: 0 !important; -} diff --git a/theme-bkup/head.hbs b/theme-bkup/head.hbs deleted file mode 100644 index 0709b07..0000000 --- a/theme-bkup/head.hbs +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/theme-bkup/version-selector.css b/theme-bkup/version-selector.css deleted file mode 100644 index d935f4c..0000000 --- a/theme-bkup/version-selector.css +++ /dev/null @@ -1,48 +0,0 @@ -/* Version and Language selectors — inline in .right-buttons */ -.openmlsys-nav-selectors { - display: inline-flex; - align-items: center; - gap: 4px; - margin-right: 4px; - vertical-align: middle; -} - -/* Shared style for all selector links/buttons */ -.openmlsys-selector-link { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 32px; - height: 28px; - padding: 0 8px; - border-radius: 4px; - border: 1px solid transparent; - color: var(--icons, #747474); - font-size: 12px; - font-weight: 600; - text-decoration: none; - cursor: pointer; - line-height: 1; - transition: color 0.1s, background 0.1s; -} - -.openmlsys-selector-link:hover { - color: var(--icons-hover, #333); - background: var(--theme-hover, rgba(0, 0, 0, 0.05)); -} - -/* Active/current indicator */ -.openmlsys-selector-link.active { - color: var(--links, #4183c4); - border-color: var(--links, #4183c4); - font-weight: 700; -} - -/* Separator between version and language groups */ -.openmlsys-selector-sep { - width: 1px; - height: 18px; - background: var(--icons, #747474); - opacity: 0.3; - margin: 0 2px; -} diff --git a/theme-bkup/version-selector.js b/theme-bkup/version-selector.js deleted file mode 100644 index 8f15c5a..0000000 --- a/theme-bkup/version-selector.js +++ /dev/null @@ -1,75 +0,0 @@ -// Version and Language selector for OpenMLSys mdbook -(function () { - "use strict"; - - var path = window.location.pathname; - - // Detect current version and language from URL - var currentVersion = "v2"; - var currentLang = "en"; - - if (path.match(/\/v1(\/|$)/)) { - currentVersion = "v1"; - } - if (path.match(/\/cn(\/|$)/)) { - currentLang = "zh"; - } - - // Build base paths — always navigate to root of target version - function basePath(version, lang) { - // Determine site root: everything before /v1/, /cn/, or first path segment after /docs/ - var root = "/"; - var docsMatch = path.match(/^(\/docs\/)/); - if (docsMatch) root = docsMatch[1]; - - var p = root; - if (version === "v1") p += "v1/"; - if (lang === "zh") p += "cn/"; - return p; - } - - var container = document.createElement("span"); - container.className = "openmlsys-nav-selectors"; - - // --- Version links: V1 | V2 --- - var versions = [ - { label: "V1", value: "v1" }, - { label: "V2", value: "v2" }, - ]; - - versions.forEach(function (v) { - var a = document.createElement("a"); - a.className = "openmlsys-selector-link"; - a.textContent = v.label; - a.href = basePath(v.value, currentLang); - if (v.value === currentVersion) a.classList.add("active"); - container.appendChild(a); - }); - - // Separator - var sep = document.createElement("span"); - sep.className = "openmlsys-selector-sep"; - container.appendChild(sep); - - // --- Language toggle: single button that switches to the other language --- - var otherLang = currentLang === "zh" ? "en" : "zh"; - var langLink = document.createElement("a"); - langLink.className = "openmlsys-selector-link"; - langLink.textContent = currentLang === "zh" ? "EN" : "ZH"; - langLink.href = basePath(currentVersion, otherLang); - container.appendChild(langLink); - - // Insert into .right-buttons, before existing icons - function insertSelector() { - var rightButtons = document.querySelector(".right-buttons"); - if (rightButtons) { - rightButtons.insertBefore(container, rightButtons.firstChild); - } - } - - if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", insertSelector); - } else { - insertSelector(); - } -})(); diff --git a/v1/en_chapters/img b/v1/en_chapters/img new file mode 120000 index 0000000..6ffc6ca --- /dev/null +++ b/v1/en_chapters/img @@ -0,0 +1 @@ +../img \ No newline at end of file diff --git a/v1/en_chapters/mlsys.bib b/v1/en_chapters/mlsys.bib new file mode 120000 index 0000000..ee7c463 --- /dev/null +++ b/v1/en_chapters/mlsys.bib @@ -0,0 +1 @@ +../mlsys.bib \ No newline at end of file diff --git a/v1/en_chapters/references b/v1/en_chapters/references new file mode 120000 index 0000000..3dc6b5c --- /dev/null +++ b/v1/en_chapters/references @@ -0,0 +1 @@ +../references \ No newline at end of file diff --git a/v1/en_chapters/static b/v1/en_chapters/static new file mode 120000 index 0000000..4dab164 --- /dev/null +++ b/v1/en_chapters/static @@ -0,0 +1 @@ +../static \ No newline at end of file diff --git a/v1/zh_chapters/chapter_computational_graph/components_of_computational_graph.md b/v1/zh_chapters/chapter_computational_graph/components_of_computational_graph.md index d7df23a..ff0cfc5 100644 --- a/v1/zh_chapters/chapter_computational_graph/components_of_computational_graph.md +++ b/v1/zh_chapters/chapter_computational_graph/components_of_computational_graph.md @@ -5,6 +5,7 @@ ![简单计算图](../img/ch03/simpledag.png) :width:`300px` :label:`simpledag` + ### 张量和算子 在数学中定义张量是基于标量与向量的推广。在机器学习领域内将多维数据称为张量,使用秩来表示张量的轴数或维度。如 :numref:`tensor`所示,标量为零秩张量,包含单个数值,没有轴;向量为一秩张量,拥有一个轴;拥有RGB三个通道的彩色图像即为三秩张量,包含三个轴。 diff --git a/v1/zh_chapters/img b/v1/zh_chapters/img new file mode 120000 index 0000000..6ffc6ca --- /dev/null +++ b/v1/zh_chapters/img @@ -0,0 +1 @@ +../img \ No newline at end of file diff --git a/v1/zh_chapters/mlsys.bib b/v1/zh_chapters/mlsys.bib new file mode 120000 index 0000000..ee7c463 --- /dev/null +++ b/v1/zh_chapters/mlsys.bib @@ -0,0 +1 @@ +../mlsys.bib \ No newline at end of file diff --git a/v1/zh_chapters/references b/v1/zh_chapters/references new file mode 120000 index 0000000..3dc6b5c --- /dev/null +++ b/v1/zh_chapters/references @@ -0,0 +1 @@ +../references \ No newline at end of file diff --git a/v1/zh_chapters/static b/v1/zh_chapters/static new file mode 120000 index 0000000..4dab164 --- /dev/null +++ b/v1/zh_chapters/static @@ -0,0 +1 @@ +../static \ No newline at end of file diff --git a/v2/en_chapters/chapter_preface/index.md b/v2/en_chapters/00_chapter_preface/index.md similarity index 100% rename from v2/en_chapters/chapter_preface/index.md rename to v2/en_chapters/00_chapter_preface/index.md diff --git a/v2/en_chapters/chapter_introduction/index.md b/v2/en_chapters/01_chapter_introduction/index.md similarity index 100% rename from v2/en_chapters/chapter_introduction/index.md rename to v2/en_chapters/01_chapter_introduction/index.md diff --git a/v2/en_chapters/chapter_programming_and_graph/index.md b/v2/en_chapters/02_chapter_programming_and_graph/index.md similarity index 100% rename from v2/en_chapters/chapter_programming_and_graph/index.md rename to v2/en_chapters/02_chapter_programming_and_graph/index.md diff --git a/v2/en_chapters/chapter_accelerator/index.md b/v2/en_chapters/03_chapter_accelerator/index.md similarity index 100% rename from v2/en_chapters/chapter_accelerator/index.md rename to v2/en_chapters/03_chapter_accelerator/index.md diff --git a/v2/en_chapters/chapter_compiler_and_runtime/index.md b/v2/en_chapters/04_chapter_compiler_and_runtime/index.md similarity index 100% rename from v2/en_chapters/chapter_compiler_and_runtime/index.md rename to v2/en_chapters/04_chapter_compiler_and_runtime/index.md diff --git a/v2/en_chapters/chapter_data_processing/index.md b/v2/en_chapters/05_chapter_data_processing/index.md similarity index 100% rename from v2/en_chapters/chapter_data_processing/index.md rename to v2/en_chapters/05_chapter_data_processing/index.md diff --git a/v2/en_chapters/chapter_training_systems/index.md b/v2/en_chapters/06_chapter_training_systems/index.md similarity index 100% rename from v2/en_chapters/chapter_training_systems/index.md rename to v2/en_chapters/06_chapter_training_systems/index.md diff --git a/v2/en_chapters/chapter_model_serving/index.md b/v2/en_chapters/07_chapter_model_serving/index.md similarity index 100% rename from v2/en_chapters/chapter_model_serving/index.md rename to v2/en_chapters/07_chapter_model_serving/index.md diff --git a/v2/en_chapters/chapter_rl_systems/index.md b/v2/en_chapters/08_chapter_rl_systems/index.md similarity index 100% rename from v2/en_chapters/chapter_rl_systems/index.md rename to v2/en_chapters/08_chapter_rl_systems/index.md diff --git a/v2/en_chapters/chapter_gpu_cluster/index.md b/v2/en_chapters/09_chapter_gpu_cluster/index.md similarity index 100% rename from v2/en_chapters/chapter_gpu_cluster/index.md rename to v2/en_chapters/09_chapter_gpu_cluster/index.md diff --git a/v2/en_chapters/SUMMARY.md b/v2/en_chapters/SUMMARY.md index 97edbd0..0a85f48 100644 --- a/v2/en_chapters/SUMMARY.md +++ b/v2/en_chapters/SUMMARY.md @@ -1,3 +1,22 @@ # Summary [Machine Learning Systems: Design and Implementation, 2nd Edition](index.md) +[前言](00_chapter_preface/index.md) + +# Basic + +- [Chapter 1: Introduction](01_chapter_introduction/index.md) +- [Chapter 2: Programming Interfaces and Computational Graphs](02_chapter_programming_and_graph/index.md) +- [Chapter 3: AI Accelerators and Programming](03_chapter_accelerator/index.md) + +# System + +- [Chapter 4: AI Compilers and Runtime Systems](04_chapter_compiler_and_runtime/index.md) +- [Chapter 5: Data Processing Systems](05_chapter_data_processing/index.md) +- [Chapter 6: Training Systems](06_chapter_training_systems/index.md) + +# Applications and More + +- [Chapter 7: Model Serving](07_chapter_model_serving/index.md) +- [Chapter 8: RL Systems](08_chapter_rl_systems/index.md) +- [Chapter 9: Large-scale GPU Cluster Management](09_chapter_gpu_cluster/index.md) diff --git a/v2/en_chapters/img b/v2/en_chapters/img new file mode 120000 index 0000000..104bf81 --- /dev/null +++ b/v2/en_chapters/img @@ -0,0 +1 @@ +../../v1/img \ No newline at end of file diff --git a/v2/en_chapters/index.md b/v2/en_chapters/index.md index 34aaa7d..64bce19 100644 --- a/v2/en_chapters/index.md +++ b/v2/en_chapters/index.md @@ -3,3 +3,24 @@ This book provides a comprehensive introduction to the design and implementation of modern machine learning systems. It covers the full technology stack, from programming interfaces and AI accelerators to distributed training, model serving, and large-scale GPU cluster management. The 2nd edition has been significantly restructured and expanded to reflect the rapid evolution of the ML systems landscape, including new chapters on AI compilers, RL systems, and GPU cluster management. + +```toc +:maxdepth: 2 + +[前言](00_chapter_preface/index) + +# Basic +01_chapter_introduction/index +02_chapter_programming_and_graph/index +03_chapter_accelerator/index + +# System +04_chapter_compiler_and_runtime/index +05_chapter_data_processing/index +06_chapter_training_systems/index + +# Applications and More +07_chapter_model_serving/index +08_chapter_rl_systems/index +09_chapter_gpu_cluster/index +``` diff --git a/v2/en_chapters/mlsys.bib b/v2/en_chapters/mlsys.bib new file mode 120000 index 0000000..be96dc4 --- /dev/null +++ b/v2/en_chapters/mlsys.bib @@ -0,0 +1 @@ +../../v1/mlsys.bib \ No newline at end of file diff --git a/v2/en_chapters/references b/v2/en_chapters/references new file mode 120000 index 0000000..942987a --- /dev/null +++ b/v2/en_chapters/references @@ -0,0 +1 @@ +../../v1/references \ No newline at end of file diff --git a/v2/en_chapters/static b/v2/en_chapters/static new file mode 120000 index 0000000..f6fbc90 --- /dev/null +++ b/v2/en_chapters/static @@ -0,0 +1 @@ +../../v1/static \ No newline at end of file diff --git a/v2/info/CONTRIBUTING.md b/v2/info/CONTRIBUTING.md index aeca5c6..ac7c2e2 100644 --- a/v2/info/CONTRIBUTING.md +++ b/v2/info/CONTRIBUTING.md @@ -10,12 +10,14 @@ openmlsys/ ├── v2/ # Version 2 (active version, accepting contributions) │ ├── zh_chapters/ # Chinese chapter source files -│ │ ├── chapter_xxx/ # Per-chapter directory, containing index.md and section .md files +│ │ ├── 00_chapter_preface/ # Per-chapter directory (numeric prefix + name) +│ │ ├── 01_chapter_introduction/ +│ │ ├── ... │ │ ├── index.md # Book homepage │ │ └── SUMMARY.md # Auto-generated by script — do not edit manually │ ├── en_chapters/ # English chapter source files (same structure as zh_chapters) │ ├── books/zh/ # Chinese mdBook configuration (used for build) -│ ├── docs/ # Documentation (location of this file) +│ ├── info/ # Documentation (location of this file) │ └── book.toml # English mdBook configuration ├── v1/ # Version 1 (archived) ├── img/ # Shared image assets for the entire book @@ -39,7 +41,7 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 2. Install mdBook cargo install mdbook -# 3. Clone the repository +# 3. Clone the repository (Python 3 must also be installed) git clone https://github.com/openmlsys/openmlsys.git cd openmlsys ``` @@ -54,7 +56,7 @@ cd openmlsys bash build_mdbook_v2.sh ``` -Build output is placed in `.mdbook-v2/book/cn/` (Chinese) and `.mdbook-v2/book/` (English). +Build output is placed in `.mdbook-v2-zh/book` (Chinese) and `.mdbook-v2/book` (English). ### Live Preview diff --git a/v2/info/CONTRIBUTING_zh.md b/v2/info/CONTRIBUTING_zh.md index eed5e04..ee54d1f 100644 --- a/v2/info/CONTRIBUTING_zh.md +++ b/v2/info/CONTRIBUTING_zh.md @@ -10,12 +10,14 @@ openmlsys/ ├── v2/ # 第二版(当前活跃版本,接受贡献) │ ├── zh_chapters/ # 中文章节源文件 -│ │ ├── chapter_xxx/ # 各章目录,包含 index.md 及各节 .md 文件 +│ │ ├── 00_chapter_preface/ # 各章目录(数字前缀 + 名称) +│ │ ├── 01_chapter_introduction/ +│ │ ├── ... │ │ ├── index.md # 全书首页 │ │ └── SUMMARY.md # 由脚本自动生成,勿手动编辑 │ ├── en_chapters/ # 英文章节源文件(结构与中文章节一致) │ ├── books/zh/ # 中文 mdBook 配置(供构建使用) -│ ├── docs/ # 文档(本文件所在位置) +│ ├── info/ # 文档(本文件所在位置) │ └── book.toml # 英文版 mdBook 配置 ├── v1/ # 第一版(已归档) ├── img/ # 全书共享图片资源 @@ -39,7 +41,7 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 2. 安装 mdBook cargo install mdbook -# 3. 克隆仓库 +# 3. 克隆仓库(需预先安装 Python 3) git clone https://github.com/openmlsys/openmlsys.git cd openmlsys ``` @@ -54,7 +56,7 @@ cd openmlsys bash build_mdbook_v2.sh ``` -构建产物输出至 `.mdbook-v2/book/cn/`(中文)和 `.mdbook-v2/book/`(英文)。 +构建产物输出至 `.mdbook-v2-zh/book`(中文)和 `.mdbook-v2/book`(英文)。 ### 实时预览 diff --git a/info/Pic-Instruction/Pic_Templates_and_Samples.pptx b/v2/info/Pic-Instruction/Pic_Templates_and_Samples.pptx similarity index 100% rename from info/Pic-Instruction/Pic_Templates_and_Samples.pptx rename to v2/info/Pic-Instruction/Pic_Templates_and_Samples.pptx diff --git a/info/Pic-Instruction/Requirements and Instructions.md b/v2/info/Pic-Instruction/Requirements and Instructions.md similarity index 100% rename from info/Pic-Instruction/Requirements and Instructions.md rename to v2/info/Pic-Instruction/Requirements and Instructions.md diff --git a/info/info.md b/v2/info/info.md similarity index 65% rename from info/info.md rename to v2/info/info.md index cf76d5d..34f4bf3 100644 --- a/info/info.md +++ b/v2/info/info.md @@ -12,14 +12,13 @@ cargo install mdbook git clone https://github.com/openmlsys/openmlsys-zh.git cd openmlsys-zh ``` -使用mdbook工具编译HTML。 请尽量使用build_mdbook.sh脚本进行编译,保证首页正确合并到书籍中去。 +使用mdbook工具编译HTML。 请尽量使用build_mdbook_v2.sh脚本进行编译,保证首页正确合并到书籍中去。 ```bash -sh build_mdbook.sh -# 中文版本 -sh build_mdbook_zh.sh +sh build_mdbook_v1.sh +sh build_mdbook_v2.sh ``` -生成的html会在`.mdbook/book`或者`.mdbook-zh/book`下。此时我们可以使用`tools/assemble_docs_publish_tree.py`组装最终的双语发布版本,然后将其拷贝至openmlsys.github.io的docs发布。 +生成的html会在`.mdbook-v2/book`或者`.mdbook-v2-zh/book`下。此时我们可以使用`tools/assemble_docs_publish_tree.py`组装最终的双语发布版本,然后将其拷贝至openmlsys.github.io的docs发布。 具体工作流可以参考`.github/workflows/update_docs.yml` diff --git a/info/issue.md b/v2/info/issue.md similarity index 100% rename from info/issue.md rename to v2/info/issue.md diff --git a/v2/info/refenence_guide.md b/v2/info/refenence_guide.md new file mode 100644 index 0000000..4977c23 --- /dev/null +++ b/v2/info/refenence_guide.md @@ -0,0 +1,30 @@ +# 参考文献引用方式 + +所有参考文献统一维护在 `mlsys.bib` 中。 + +## 添加文献条目 + +在 `mlsys.bib` 中添加 BibTeX 格式的条目,添加前请先检索是否已存在同名 key: + +```bibtex +@inproceedings{cnn2015, + title = {CNN}, + author = {xxx}, + year = {2015}, + keywords = {xxx} +} +``` + +## 正文引用 + +引用时前面需要有一个空格: + +1. 单篇参考文献 + ``` + 这篇文章参考了论文 :cite:`cnn2015` + ``` + +2. 多篇参考文献用逗号分隔 + ``` + 这篇文章参考了论文 :cite:`cnn2015,rnn2015` + ``` diff --git a/v2/info/style.md b/v2/info/style.md index a664c6e..2fdce63 100644 --- a/v2/info/style.md +++ b/v2/info/style.md @@ -19,7 +19,7 @@ This document defines the formatting and style requirements for v2 chapter conte ## File Structure -- Each chapter corresponds to a `v2/en_chapters/chapter_/` directory +- Each chapter corresponds to a `v2/en_chapters/_chapter_/` directory (e.g., `02_chapter_programming_and_graph/`) - The chapter entry file is `index.md`; section content goes in separate `.md` files in the same directory - Declare the section structure in `index.md` using a `toc` block (used to auto-generate `SUMMARY.md`): diff --git a/v2/info/style_zh.md b/v2/info/style_zh.md index ea6107d..c199625 100644 --- a/v2/info/style_zh.md +++ b/v2/info/style_zh.md @@ -19,7 +19,7 @@ ## 文件结构 -- 每章对应 `v2/zh_chapters/chapter_<名称>/` 目录 +- 每章对应 `v2/zh_chapters/_chapter_<名称>/` 目录(如 `02_chapter_programming_and_graph/`) - 章节入口为 `index.md`,各节内容放在同目录下的独立 `.md` 文件中 - 在 `index.md` 中使用 `toc` 块声明本章的节结构(脚本据此自动生成 `SUMMARY.md`): diff --git a/v2/zh_chapters/chapter_preface/index.md b/v2/zh_chapters/00_chapter_preface/index.md similarity index 100% rename from v2/zh_chapters/chapter_preface/index.md rename to v2/zh_chapters/00_chapter_preface/index.md diff --git a/v2/zh_chapters/chapter_introduction/index.md b/v2/zh_chapters/01_chapter_introduction/index.md similarity index 100% rename from v2/zh_chapters/chapter_introduction/index.md rename to v2/zh_chapters/01_chapter_introduction/index.md diff --git a/v2/zh_chapters/chapter_programming_and_graph/index.md b/v2/zh_chapters/02_chapter_programming_and_graph/index.md similarity index 100% rename from v2/zh_chapters/chapter_programming_and_graph/index.md rename to v2/zh_chapters/02_chapter_programming_and_graph/index.md diff --git a/v2/zh_chapters/chapter_accelerator/index.md b/v2/zh_chapters/03_chapter_accelerator/index.md similarity index 100% rename from v2/zh_chapters/chapter_accelerator/index.md rename to v2/zh_chapters/03_chapter_accelerator/index.md diff --git a/v2/zh_chapters/chapter_compiler_and_runtime/index.md b/v2/zh_chapters/04_chapter_compiler_and_runtime/index.md similarity index 100% rename from v2/zh_chapters/chapter_compiler_and_runtime/index.md rename to v2/zh_chapters/04_chapter_compiler_and_runtime/index.md diff --git a/v2/zh_chapters/chapter_data_processing/index.md b/v2/zh_chapters/05_chapter_data_processing/index.md similarity index 100% rename from v2/zh_chapters/chapter_data_processing/index.md rename to v2/zh_chapters/05_chapter_data_processing/index.md diff --git a/v2/zh_chapters/chapter_training_systems/index.md b/v2/zh_chapters/06_chapter_training_systems/index.md similarity index 100% rename from v2/zh_chapters/chapter_training_systems/index.md rename to v2/zh_chapters/06_chapter_training_systems/index.md diff --git a/v2/zh_chapters/chapter_model_serving/index.md b/v2/zh_chapters/07_chapter_model_serving/index.md similarity index 100% rename from v2/zh_chapters/chapter_model_serving/index.md rename to v2/zh_chapters/07_chapter_model_serving/index.md diff --git a/v2/zh_chapters/chapter_rl_systems/index.md b/v2/zh_chapters/08_chapter_rl_systems/index.md similarity index 100% rename from v2/zh_chapters/chapter_rl_systems/index.md rename to v2/zh_chapters/08_chapter_rl_systems/index.md diff --git a/v2/zh_chapters/chapter_gpu_cluster/index.md b/v2/zh_chapters/09_chapter_gpu_cluster/index.md similarity index 100% rename from v2/zh_chapters/chapter_gpu_cluster/index.md rename to v2/zh_chapters/09_chapter_gpu_cluster/index.md diff --git a/v2/zh_chapters/SUMMARY.md b/v2/zh_chapters/SUMMARY.md index d36a664..043fabe 100644 --- a/v2/zh_chapters/SUMMARY.md +++ b/v2/zh_chapters/SUMMARY.md @@ -1,3 +1,22 @@ # Summary [机器学习系统:设计和实现(第二版)](index.md) +[前言](00_chapter_preface/index.md) + +# 基础篇 + +- [第1章 导论](01_chapter_introduction/index.md) +- [第2章 编程接口与计算图](02_chapter_programming_and_graph/index.md) +- [第3章 AI加速器与编程](03_chapter_accelerator/index.md) + +# 系统篇 + +- [第4章 AI编译器与运行时系统](04_chapter_compiler_and_runtime/index.md) +- [第5章 数据处理系统](05_chapter_data_processing/index.md) +- [第6章 训练系统](06_chapter_training_systems/index.md) + +# 应用与扩展篇 + +- [第7章 模型服务](07_chapter_model_serving/index.md) +- [第8章 强化学习系统](08_chapter_rl_systems/index.md) +- [第9章 大规模GPU集群管理](09_chapter_gpu_cluster/index.md) diff --git a/v2/zh_chapters/img b/v2/zh_chapters/img new file mode 120000 index 0000000..104bf81 --- /dev/null +++ b/v2/zh_chapters/img @@ -0,0 +1 @@ +../../v1/img \ No newline at end of file diff --git a/v2/zh_chapters/index.md b/v2/zh_chapters/index.md index 5fa64be..aac12c3 100644 --- a/v2/zh_chapters/index.md +++ b/v2/zh_chapters/index.md @@ -1,3 +1,24 @@ # 机器学习系统:设计和实现(第二版) 本书系统性地介绍机器学习系统的设计原理与实现方法,涵盖从编程接口、AI加速器、编译器到分布式训练、模型服务和大规模集群管理等核心主题。第二版在第一版基础上进行了全面更新和重构,反映了机器学习系统领域的最新进展。 + +```toc +:maxdepth: 2 + +[前言](00_chapter_preface/index) + +# 基础篇 +01_chapter_introduction/index +02_chapter_programming_and_graph/index +03_chapter_accelerator/index + +# 系统篇 +04_chapter_compiler_and_runtime/index +05_chapter_data_processing/index +06_chapter_training_systems/index + +# 应用与扩展篇 +07_chapter_model_serving/index +08_chapter_rl_systems/index +09_chapter_gpu_cluster/index +``` diff --git a/v2/zh_chapters/mlsys.bib b/v2/zh_chapters/mlsys.bib new file mode 120000 index 0000000..be96dc4 --- /dev/null +++ b/v2/zh_chapters/mlsys.bib @@ -0,0 +1 @@ +../../v1/mlsys.bib \ No newline at end of file diff --git a/v2/zh_chapters/references b/v2/zh_chapters/references new file mode 120000 index 0000000..942987a --- /dev/null +++ b/v2/zh_chapters/references @@ -0,0 +1 @@ +../../v1/references \ No newline at end of file diff --git a/v2/zh_chapters/static b/v2/zh_chapters/static new file mode 120000 index 0000000..f6fbc90 --- /dev/null +++ b/v2/zh_chapters/static @@ -0,0 +1 @@ +../../v1/static \ No newline at end of file