Spaces:
Sleeping
Sleeping
File size: 9,476 Bytes
07cb7d3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | # 项目架构说明
这份文档说明当前项目的代码结构,以及一次任务从入口脚本到训练、导出、样例测试的执行链路。重点说明四件事:
- 数据从哪里来,如何变成训练数据
- 模型在哪里构建,在哪里编译,如何转换成推理模型
- 训练、导出、样例测试如何共用一套路径、日志和检查点规则
- 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 任务如何从数据走到训练、导出和展示
- 快速复制一个已有任务并改成自己的数据和模型
- 在个人实验里保持统一目录、统一入口和统一检查点习惯
|