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 任务如何从数据走到训练、导出和展示
- 快速复制一个已有任务并改成自己的数据和模型
- 在个人实验里保持统一目录、统一入口和统一检查点习惯