general-deep-learning / docs /architecture.md
yetrun's picture
ver3: 将源码迁入 src/deep_learning 包,重塑训练流水线,规范 data/model 契约
07cb7d3
|
Raw History Blame Contribute Delete
9.48 kB
# 项目架构说明
这份文档说明当前项目的代码结构,以及一次任务从入口脚本到训练、导出、样例测试的执行链路。重点说明四件事:
- 数据从哪里来,如何变成训练数据
- 模型在哪里构建,在哪里编译,如何转换成推理模型
- 训练、导出、样例测试如何共用一套路径、日志和检查点规则
- Gradio 展示如何复用导出的模型,而不参与训练抽象
## 总体分层
项目主要分成五层。
### `tasks`
`tasks/*/runner.py` 是每个任务的命令入口。
它负责声明开发配置和生产配置,包括数据源、模型构建器、训练规则、生成规则和检查点加载规则。入口脚本本身不写训练循环,而是把配置好的 Pipeline 交给 `PipelineRunner`。
典型结构是:
```python
pipeline = resolve_env(
SupervisedModelPipeline(...),
SupervisedModelPipeline(...)
)
pipeline_runner = PipelineRunner(pipeline)
```
文本生成任务也遵循同样形状,只是 Pipeline 类型换成 `TextGenerationPipeline`。
`tasks/*/gradio.py` 是展示入口。它通常加载已导出的模型或生成器,负责页面交互,不承担训练编排职责。
### `data`
`src/deep_learning/data` 负责把原始数据变成 Pipeline 能消费的数据源。
当前对外契约集中在 `src/deep_learning/data/spec/__init__.py`:
- `SupervisedDataSource`:用于分类、分割、检测这类有监督任务,需要提供 `training_ds()` 和 `test_examples(model)`
- `TextGenerationDataSource`:用于文本生成任务,需要提供原始文档、token 数据、分词资源和数据配置
- `TokenizerBundle`:文本推理时模型之外需要携带的分词器、解码函数、词表大小、结束标记等资源
这里的设计取向是让数据源自己说明训练数据怎么构建。比如 batch size、validation batches、sequence length 这类更贴近数据切分的配置,放在具体 DataSource 里,而不是塞进通用训练规则里。
### `models`
`src/deep_learning/models` 负责模型构建、训练模型编译、推理模型转换和模型加载。
当前对外契约集中在 `src/deep_learning/models/spec/__init__.py`:
- `SupervisedModelBuilder`:负责构建有监督任务的训练模型、编译训练模型、转换或加载推理模型
- `TextGenerationModelBuilder`:负责构建文本生成训练产物、编译模型、转换或加载文本推理产物
- `ModelArtifact` 和 `TextGenerationModel`:用统一对象承载模型产物
模型层不负责找数据、不负责写训练循环,也不负责 Gradio 页面。它只回答“这个任务的模型长什么样,怎么训练,怎么用于推理”。
### `pipeline`
`src/deep_learning/pipeline` 是训练、导出和测试样例的统一编排层。
它负责:
- 创建运行目录、日志目录、检查点目录和 TensorBoard 目录
- 开启通用运行环境,例如 mixed precision
- 写出配置日志
- 加载或创建训练模型
- 编译模型并组织 callbacks
- 执行 Keras 训练
- 按检查点导出完整模型
- 从导出模型或训练检查点执行样例测试
`PipelineRunner` 暴露三个动作:
- `train`
- `export`
- `test`
因此任务入口只需要声明一个 Pipeline,再交给 `PipelineRunner`。调用方不需要知道训练、导出和测试内部要走哪些目录和检查点规则。
### `ui`
`src/deep_learning/ui` 和 `tasks/*/gradio.py` 负责展示层。
展示层的定位是“使用推理产物”,而不是“参与训练流程”。它可以复用数据集里的标签、分词器、样例展示能力,也可以复用 Pipeline 或模型构建器的加载能力,但不应该成为训练抽象的一部分。
## 两条主流程
当前项目主要有两条流程:有监督任务和文本生成任务。
### 有监督任务
有监督任务使用:
- `SupervisedDataSource`
- `SupervisedModelBuilder`
- `SupervisedModelPipeline`
适用场景包括图片分类、语义分割,以及后续可以统一进来的其他监督学习任务。
训练链路是:
1. `tasks/*/runner.py` 声明 `SupervisedModelPipeline`
2. `PipelineRunner.train()` 调用 `pipeline.train()`
3. Pipeline 创建运行目录,写配置日志
4. Pipeline 从检查点恢复训练模型,或调用 `model_builder.build_training_artifact()` 创建新模型
5. Pipeline 调用 `model_builder.compile_training_model(model)` 编译模型
6. Pipeline 调用 `data_source.training_ds()` 得到训练集和验证集
7. Pipeline 追加通用 callbacks,包括检查点和日志
8. Pipeline 调用 `model.fit(...)`
导出链路是:
1. `PipelineRunner.export()` 调用 `pipeline.export_model()`
2. Pipeline 按导出规则加载训练检查点
3. Pipeline 调用 `model_builder.convert_to_inference_artifact(...)`
4. Pipeline 用 `SaveKerasModelStage` 保存完整 `.keras` 模型到 `saved/models/<task_name>`
样例测试链路是:
1. `PipelineRunner.test()` 调用 `pipeline.test_examples(checkpoint=...)`
2. 如果 checkpoint 是 `test`,Pipeline 从 `saved/models/<task_name>` 加载导出模型
3. 如果 checkpoint 是 `train`,Pipeline 从训练检查点加载权重并转换推理模型
4. Pipeline 调用 `data_source.test_examples(model)` 展示样例结果
### 文本生成任务
文本生成任务使用:
- `TextGenerationDataSource`
- `TextGenerationModelBuilder`
- `TextGenerationPipeline`
适用场景包括诗词 GPT、Wiki GPT,以及字符级或 token 级文本生成任务。
训练链路是:
1. `tasks/*/runner.py` 声明 `TextGenerationPipeline`
2. `PipelineRunner.train()` 调用 `pipeline.train()`
3. Pipeline 加载原始文档和 tokenizer 信息
4. Pipeline 从 `tokens_ds()` 切出验证数据和训练数据
5. Pipeline 从检查点恢复模型,或根据词表大小和序列长度创建新模型
6. Pipeline 调用 `model_builder.compile_training_model(model)` 编译模型
7. Pipeline 根据 `GenerationRule` 追加生成日志回调
8. Pipeline 调用通用 `KerasTrainStage` 执行训练
导出链路是:
1. Pipeline 准备文本数据和 tokenizer 资源
2. Pipeline 按导出规则加载训练检查点
3. Pipeline 调用 `model_builder.convert_to_inference_artifact(...)`
4. Pipeline 保存完整推理模型
样例测试链路是:
1. Pipeline 准备文本数据和 tokenizer 资源
2. 如果 checkpoint 是 `test`,从导出模型加载推理产物
3. 如果 checkpoint 是 `train`,从训练检查点加载训练产物并转换推理产物
4. Pipeline 构建 `TextGenerator`
5. Pipeline 使用 `GenerationRule.prompts_generator` 生成提示词,并打印生成结果
## 配置与产物
当前配置主要分为几类。
- `TrainingRule`:训练轮数和每轮步数
- `GenerationRule`:文本生成提示词来源和采样策略
- `CheckpointLoadRules`:训练、导出、测试各自如何选择检查点
- `CheckpointConfig`:检查点目录、具体路径、轮次和文件后缀
运行时目录由 `build_runtime` 统一生成,主要包括:
- `logs/<task_name>`:配置日志和生成日志
- `checkpoints/<task_name>`:训练过程中的权重检查点
- `saved/models/<task_name>`:导出的完整模型
这样的划分让任务入口只声明“我想怎么跑”,Pipeline 统一处理“文件放哪里、检查点怎么找、导出怎么命名”。
## 历史结构与当前结构
上一版结构更强调通用阶段编排:
- 一个通用 `Pipeline` 串联 runtime、data source、preprocess、model、compile、train、inference、export 等阶段
- 每类任务通过 builder 装配 Pipeline,例如 image classification builder、segmentation builder、text builder、yolo builder
- 任务目录里常见多个入口脚本,例如 `train.py`、`save_model.py`、`generate.py`
- 一些数据切分相关配置也放在训练规则中统一传递
这种设计的优点是阶段边界清楚,也更容易表达“所有任务都经过同一套通用流程”。但它的阅读成本更高:读者通常需要在任务入口、任务 builder、通用 Pipeline、各个 Stage、模型构建器和数据集之间多次跳转,才能理解一次训练具体发生了什么。
当前结构的设计取向是降低抽象层级,减少装配跳转,提升可读性和可改造性:
- 任务入口统一为 `tasks/*/runner.py`
- 入口脚本直接声明 DataSource、ModelBuilder 和 Pipeline
- 有监督任务用 `SupervisedModelPipeline` 直接表达主流程
- 文本任务保留必要的文本阶段对象,但主入口仍收敛到 `TextGenerationPipeline`
- batch、validation、sequence length 等数据切分配置回到 DataSource
- 模型构建、编译、训练产物和推理产物转换回到 ModelBuilder
- `PipelineRunner` 统一暴露 `train`、`export`、`test`
这不是在否定上一版设计。更准确地说,这是一次项目定位变化:从“抽象完整、阶段统一”,转向“入口更清楚、跳转更少、读者更容易改”。对于当前项目规模,读者能快速看懂数据、模型、训练和展示之间的关系,比保留更通用的阶段装配能力更重要。
## 当前边界
这个项目目前仍是小型 Keras 任务框架,不是完整生产级训练平台。
它适合:
- 学习 Keras 任务如何从数据走到训练、导出和展示
- 快速复制一个已有任务并改成自己的数据和模型
- 在个人实验里保持统一目录、统一入口和统一检查点习惯