资讯动态

TensorFlow 2模型工程化实践:从Keras构建到SavedModel/TFLite部署全攻略

发布时间:2026/10/14 8:39:14 来源:尧图企业网站定制
1. 从模型到手艺为什么你需要一份“便携参考”如果你是做机器学习应用开发的一定有过这样的经历模型在 Notebook 里跑得挺好一到工程化就手忙脚乱。训练完的模型怎么保存保存完怎么转格式转完格式为什么在端侧推理结果对不上还有那些五花八门的部署方式到底选哪个才合适我之前带过好几个项目发现团队里普遍存在一个问题大家都熟悉模型构建的基本操作但一进入“模型要怎么落地”这个环节就开始各查各的文档。TensorFlow 2 官方文档内容确实全但信息太散往往为了查一个模型导出参数要在好几篇页面之间来回跳。所以后来我做了一套自己的便携参考笔记把模型构建到部署这条链路的关键操作按模块整理好随时翻、随时用。这篇文章是这个系列的第二篇重点放在模型构建的工程化实践、训练流程的标准化以及从 SavedModel 到移动端、服务端部署的全链路操作。这套笔记适合什么人如果你已经会用 Keras 搭个简单的序列模型但还没系统梳理过“从训练到部署”的标准流程那这份参考对你应该很有价值。当然如果你已经在做模型上线也可以对照着查漏补缺看看自己在哪个环节还缺一些关键配置。先说清楚这篇内容的定位不是入门教程不讲 TensorFlow 基础语法而是把“从模型设计到部署上线”这条路上最容易踩坑、最容易绕弯的操作环节拆开讲配合可以直接抄走的代码片段和参数配置。这样你在自己项目里遇到类似场景就能快速对应上解决方案。2. 模型构建的工程化设计三种 API 的选型逻辑很多人写模型喜欢从头到尾只用Sequential方便是方便但到了真实项目里模型结构稍微复杂一点就捉襟见肘。TensorFlow 2 真正适合工程化的是三套 API 配合使用。2.1 Functional API工作中最常用的主力方案Functional API是我个人在日常项目里用得最多的方式。它不是像Sequential那样一层层往上摞而是通过“层即函数、输出即调用结果”的思路构建计算图。好处是你可以自由定义分支结构、多输入、多输出而且模型结构一目了然。举个典型例子一个同时接收文本和数值特征的输入模型。import tensorflow as tf from tensorflow.keras import layers # 文本分支 text_input layers.Input(shape(None,), nametext) embedding layers.Embedding(10000, 128)(text_input) lstm_out layers.LSTM(64, return_sequencesFalse)(embedding) # 数值分支 numeric_input layers.Input(shape(10,), namenumeric) dense_out layers.Dense(32, activationrelu)(numeric_input) # 合并 concatenated layers.Concatenate()([lstm_out, dense_out]) output layers.Dense(1, activationsigmoid, nameoutput)(concatenated) model tf.keras.Model(inputs[text_input, numeric_input], outputsoutput)这段代码展示了一个关键操作Concatenate层把两个分支的特征向量拼接在一起。为什么用拼接而不是相加因为两个分支的特征分布差异较大文本向量经过 LSTM 产出的是高维语义表示数值特征是低维统计量相加会互相干扰拼接保留了各自的信息空间让后面的全连接层自己学习组合方式。实际项目中我用 Functional API 处理过多模态输入、共享层权重的孪生网络、甚至带辅助输出的多任务模型。这个 API 最大的优势是“结构显式化”——模型结构直接体现在代码里review 的时候不需要靠想象新人接手也容易理解。2.2 子类化 API研究原型时的利器如果你需要实现一个带有自定义训练逻辑的模型Model子类化是更灵活的方案。它让你完全掌控前向传播过程。class MyModel(tf.keras.Model): def __init__(self): super().__init__() self.conv1 layers.Conv2D(32, 3, activationrelu) self.flatten layers.Flatten() self.dense1 layers.Dense(128, activationrelu) self.dropout layers.Dropout(0.5) self.dense2 layers.Dense(10, activationsoftmax) def call(self, inputs, trainingFalse): x self.conv1(inputs) x self.flatten(x) x self.dense1(x) if training: x self.dropout(x) return self.dense2(x)注意这里training参数的处理Dropout 只在训练阶段生效。如果省略这个判断模型在推理时也会随机丢弃神经元直接导致预测结果不稳定。这个问题我见过不止一次都是因为子类化时没把training标志传对。但子类化也有代价。它不像 Functional API 那样自带完整的层拓扑信息某些依赖图结构的工具比如plot_model画结构图就没法用了。另外子类化模型的保存和加载在一些旧版本里也容易出问题。我的经验是能用 Functional API 解决的问题优先用 Functional API子类化只用于实现自定义层逻辑或者研究性质的原型验证。2.3 一个容易被忽略的点动态图与静态图的选择TensorFlow 2 默认开启动态图模式Eager Execution这对调试非常友好可以随时打印中间张量的值。但动态图在性能上有额外开销尤其是大规模数据训练时。你不需要手动切换到静态图。TensorFlow 2 的tf.function装饰器会自动把 Python 函数编译成计算图在保留调试便利性的同时提升执行效率。tf.function def train_step(x, y): with tf.GradientTape() as tape: predictions model(x, trainingTrue) loss loss_fn(y, predictions) gradients tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables))这里有个实践要点tf.function对 Python 原生数据结构比如字典、列表的处理比较敏感最好保持输入是张量或者能被追踪的结构。我第一次在项目里用它时因为传入的training参数是 Python 布尔值导致每次调用都重新编译训练慢得离谱。后来改成tf.Variable或者直接传张量才解决。这个坑在 TensorFlow 官方文档里写得不明显实际碰到的人却不少。3. 训练流程的标准化从数据管道到回调机制模型架构确定之后训练环节是否规范直接决定了模型质量的上限。很多人在这一步只写个model.fit()就完事但对于工程化项目来说数据输入、训练策略、日志监控都是需要精细化配置的。3.1 tf.data 管道不要再用 NumPy 数组硬扛大数据用model.fit(x_train, y_train)这种写法处理小数据集没问题但真实项目里数据量一上来内存先爆炸。正确做法是用tf.data.Dataset构建高效的数据管道。dataset tf.data.Dataset.from_tensor_slices((x_train, y_train)) dataset dataset.shuffle(buffer_size10000) dataset dataset.batch(64) dataset dataset.prefetch(tf.data.AUTOTUNE)这段配置里shuffle的buffer_size决定了数据随机化的程度。这个值太小数据洗牌不充分模型容易学到样本顺序里的虚假模式值太大又会增加内存开销。经验值是设置为数据集大小的 10% 左右最多不超过 10000 条具体看数据量级。prefetch(tf.data.AUTOTUNE)是我特别想强调的。它让数据加载和模型训练并行执行模型在算当前 batch 的时候数据管道已经在后台准备下一个 batch 了。实测下来这个配置在大多数场景下能把训练吞吐量提升 20% 到 50%而且是零成本优化。另外如果你的数据是图像在管道里顺手做数据增强会非常高效——它利用了 CPU 并行能力不用额外占内存。很多人先加载全部图像再慢慢增强那是传统做法在 TensorFlow 2 里已经过时了。3.2 回调函数训练监控的标配组合回调函数是 TensorFlow 2 里被低估的功能。它能在训练过程中的特定时机自动执行操作。我的标准配置是这样callbacks [ tf.keras.callbacks.EarlyStopping( monitorval_loss, patience5, restore_best_weightsTrue ), tf.keras.callbacks.ModelCheckpoint( filepathbest_model.keras, monitorval_loss, save_best_onlyTrue ), tf.keras.callbacks.ReduceLROnPlateau( monitorval_loss, factor0.5, patience3, min_lr1e-6 ), tf.keras.callbacks.TensorBoard(log_dirlogs) ]EarlyStopping的restore_best_weightsTrue很关键它会在训练停止时自动恢复验证集上表现最好的参数。如果不设置这个参数你得到的模型可能是最后一步的权重而最后一步往往不是最优的。ReduceLROnPlateau则是当验证损失连续几个 epoch 不下降时自动把学习率减半这比手动调整学习率要科学得多。我见过不少人训练到一半发现 loss 不降了亲手去改学习率重新训练——完全没必要回调函数已经帮你做了这件事。ModelCheckpoint保存格式要注意后缀用.keras是 TensorFlow 2 新版的推荐格式完整保留模型结构和权重如果你用旧版的.h5格式某些自定义层会出现兼容问题尤其当你升级 TensorFlow 版本之后旧模型可能加载不了。3.3 混合精度训练用更少显存跑更大模型如果你的显卡支持NVIDIA 的 Turing 架构及以上混合精度训练是一个值得开的功能。它让模型用 FP16 计算用 FP32 做精度补偿理论上显存占用几乎减半训练速度可提升 2 到 3 倍。from tensorflow.keras import mixed_precision mixed_precision.set_global_policy(mixed_float16) # 对于任何自定义的损失函数需要额外做一步 # 在计算 loss 时手动转为 float32避免精度溢出开混合精度有一个容易忽略的细节损失计算和 Softmax 这类操作通常必须在 FP32 下进行否则数值不稳定。Keras 的某些内置层已经自动处理了但如果你有自定义层就得检查有没有数值溢出风险。我在一个语义分割模型上踩过这个坑开了混合精度后 loss 出现 NaN排查了整整一个下午最后发现是自定义损失函数里求均值时精度不够加了一个tf.cast(x, tf.float32)就解决了。3.4 学习率与优化器的配合从 Adam 到 AdamWAdam 是当前最常用的优化器但它有一个被很多人忽略的问题权重衰减的实现方式。标准 Adam 把 L2 正则直接加到梯度里这与权重衰减在数学上并不等价。TensorFlow 2 提供了AdamW修正了这个问题optimizer tf.keras.optimizers.AdamW( learning_rate1e-3, weight_decay1e-4 )从实际操作看对于 Transformer 类模型和 CV 领域的很多模型换成 AdamW 后收敛更稳定最终精度也普遍略高于标准 Adam。尤其是当你训练较大模型、需要较长训练时间时差异会更加明显。学习率的具体数值没有万能答案但有一个可复用的经验先从一个较大的值开始比如 1e-3如果 loss 震荡剧烈或者直接发散就降一个量级。使用ReduceLROnPlateau的情况下初始学习率稍微设大一点也没关系回调函数会自动帮你降下来。4. 模型导出的规范化从 SavedModel 到多端部署模型训练完只是第一步真正让模型产生价值的是部署环节。TensorFlow 2 的部署生态非常丰富但要搞清楚各种导出格式和工具的适配关系否则很容易在格式转换上卡壳。4.1 SavedModel工程部署的统一格式SavedModel是 TensorFlow 官方推荐的部署格式。它不只是保存权重而是把完整的计算图、参数、签名函数都打包在一个目录里。最简洁的导出方式model.save(my_model_dir)导出的目录结构长这样my_model_dir/ ├── assets/ ├── variables/ │ ├── variables.data-00000-of-00001 │ └── variables.index ├── saved_model.pb └── fingerprint.pbsaved_model.pb是计算图定义variables目录存参数。这种格式可以被很多下游工具直接消费TensorFlow Serving 可以直接加载、TF.js 转换器可以把它转给前端、TFLite 转换器也能读取它再压缩成移动端格式。保存时有一个参数值得注意如果你计划后续用 TensorFlow Serving 部署建议在保存前用tf.saved_model.SaveOptions指定签名函数。tf.function(input_signature[tf.TensorSpec(shape[None, 224, 224, 3], dtypetf.float32)]) def serving_fn(inputs): return {output: model(inputs)} tf.saved_model.save(model, saved_model_dir, signatures{serving_default: serving_fn})指定input_signature后模型在 Serving 端接收请求时就有了明确的输入格式约束避免因输入尺寸不一致导致推理报错。如果不指定Serving 可能会因为看不到输入的具体形状而在线上报错。4.2 TFLite 转换移动端与嵌入式部署的必经之路移动端部署的核心工具是TFLiteConverter。它的核心优势在于模型体积小、推理速度快特别适合手机和物联网设备。converter tf.lite.TFLiteConverter.from_saved_model(my_model_dir) # 设置优化策略 converter.optimizations [tf.lite.Optimize.DEFAULT] # 设置代表数据集用于量化校准 def representative_dataset(): for data in calibration_data: yield [data.reshape(1, 224, 224, 3)] converter.representative_dataset representative_dataset converter.target_spec.supported_ops [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] tflite_model converter.convert() with open(model.tflite, wb) as f: f.write(tflite_model)这里的量化逻辑值得展开讲一下Optimize.DEFAULT会自动把权重从 FP32 转为 FP16 或者 INT8具体取决于兼容性。representative_dataset是量化校准用的数据样本它让转换器统计激活值的分布范围从而把激活也量化到 INT8。很多人在这一步翻车没提供representative_dataset就想做 INT8 全整数量化结果转换报错或者精度暴跌。提供几百到一千条有代表性的样本就够了不需要太多关键是要覆盖模型在实际应用中会遇到的数据分布。转换完之后在 Python 端可以用tflite.Interpreter做推理验证确保量化后的模型输出没有显著偏差interpreter tf.lite.Interpreter(model_pathmodel.tflite) interpreter.allocate_tensors() input_details interpreter.get_input_details() output_details interpreter.get_output_details() # 注意量化模型的输入输出是 int8需要做归一化到 [-128, 127] 的映射4.3 TensorFlow Serving生产环境的稳定选择如果需要部署到服务器接受 HTTP/gRPC 请求TensorFlow Serving 是经验成熟的选择。它最大的特点是模型热加载、多版本管理、高并发支持。部署流程非常直接把 SavedModel 按版本目录放好启动服务即可。tensorflow_model_server \ --rest_api_port8501 \ --model_namemy_model \ --model_base_path/models/my_model目录结构要求如下/models/ └── my_model/ ├── 1/ │ ├── saved_model.pb │ └── variables/ ├── 2/ │ ├── saved_model.pb │ └── variables/ └── 3/ ├── saved_model.pb └── variables/这里/models/my_model下每个数字文件夹代表一个版本。TFServing 会自动加载数字最大的版本作为默认版本同时支持通过 API 指定版本号来访问旧版本。少了这个目录结构它会直接报“找不到可加载的模型”。客户端请求示例import requests url http://localhost:8501/v1/models/my_model:predict data {instances: [image_array.tolist()]} response requests.post(url, jsondata) result response.json()这里有一个性能细节instances里的数据是 JSON 数组如果数据量大序列化和反序列化开销不可忽视。对性能要求高的场景优先用 gRPC 接口它基于 Protobuf 序列化传输效率远高于 REST。官方测试里gRPC 的吞吐量一般是 REST 的数倍。4.4 TF.js 与边缘部署浏览器里的推理如果你的模型需要跑在浏览器端TensorFlow.js 是适配工具。转换流程同样基于 SavedModeltensorflowjs_converter \ --input_formattf_saved_model \ --output_formattfjs_graph_model \ /path/to/saved_model_dir \ /path/to/web_model输出目录里会有model.json加一组权重分片文件。前端加载时只需const model await tf.loadGraphModel( https://your-cdn/model.json ); const prediction await model.predict(tensor);需要特别留意的是浏览器环境和 Python 环境的算子支持有差异。你训练模型时用了太多自定义算子转换到 TF.js 时很可能缺算子报错。实际项目中我通常建议如果是新模型且目标平台包含 Web 端从一开始就避免依赖自定义层和冷门算子尽量用标准 Keras 层搭建这样能省去大量兼容性排查时间。5. 一个端到端案例图像分类模型从训练到多端部署前面讲了不少模块化的内容可能有点散。这一节把它们串起来走一遍完整的流程。5.1 场景设定与模型选型模拟项目场景某公司要做工业质检需要把“产品表面缺陷图像分类”模型部署到产线边缘设备和服务器端。模型输入是 224x224 的 RGB 图像分类目标是 10 类缺陷。这个场景对模型有两个核心要求一是准确率要高二是推理延迟要低。模型选用 EfficientNet 作为主干但小数据集上直接从头训练效果容易不理想所以加载了预训练权重做迁移学习。base_model tf.keras.applications.EfficientNetB0( weightsimagenet, include_topFalse, input_shape(224, 224, 3) ) base_model.trainable False inputs tf.keras.Input(shape(224, 224, 3)) x base_model(inputs, trainingFalse) x layers.GlobalAveragePooling2D()(x) x layers.Dropout(0.2)(x) outputs layers.Dense(10, activationsoftmax)(x) model tf.keras.Model(inputs, outputs)5.2 迁移学习的训练策略迁移学习的关键在于“分阶段解冻”。先冻结主干只训练新增的分类头等损失下降到一定程度再解冻部分后面的层用更小的学习率微调。# 阶段一只训练分类头 model.compile( optimizertf.keras.optimizers.Adam(1e-3), losssparse_categorical_crossentropy, metrics[accuracy] ) history model.fit(train_ds, validation_dataval_ds, epochs15, callbackscallbacks) # 阶段二解冻主干后半段微调 base_model.trainable True for layer in base_model.layers[:100]: layer.trainable False model.compile( optimizertf.keras.optimizers.Adam(1e-5), losssparse_categorical_crossentropy, metrics[accuracy] ) history model.fit(train_ds, validation_dataval_ds, epochs10, callbackscallbacks)这里有个要点解冻主干后学习率必须调低。预训练权重已经很好了如果还按 1e-3 来微调很容易破坏原有特征表示导致损失发散。很多人的迁移学习效果不佳就是因为解冻后没把学习率降下来。另外不同部分的可训练属性会影响 BatchNormalization 层的行为。解冻后BatchNormalization 层会利用当前 batch 的均值和方差更新自身的统计量如果 batch size 太小比如 8 或 16统计噪声会很大。这种情况下要么冻结 BN 层要么增大 batch size。我在实际项目中通常把 batch size 设置在 32 到 64 之间。5.3 模型评估与迭代决策训练完成后不能只看准确率。对于工业质检场景误检率假阳性和漏检率假阴性的成本完全不同漏检意味着缺陷产品流出误检意味着把良品当缺陷品会产生额外人工复检成本。所以需要看混淆矩阵分析每个类别的精确率和召回率。from sklearn.metrics import classification_report, confusion_matrix y_true [] y_pred [] for images, labels in val_ds: preds model.predict(images) y_pred.extend(tf.argmax(preds, axis1).numpy()) y_true.extend(labels.numpy()) print(classification_report(y_true, y_pred, target_namesclass_names))如果发现某个类别的召回率明显偏低不要盲目增加数据量。先可视化这个类别的被错分样本看是标注质量问题、数据分布不均还是模型容量不足。我之前遇到过一个“划痕”类缺陷老是跟“正常纹理”混淆把样本图打出来才发现有大量弱划痕本身标注就不一致后来重新清洗标注数据召回率一下就上来了。5.4 部署落地的完整流水线模型确认没问题后开始走部署流程。同时输出三种目标格式# 1. SavedModel 用于 Serving model.save(deploy/saved_model) # 2. TFLite 用于边缘设备 converter tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations [tf.lite.Optimize.DEFAULT] converter.representative_dataset representative_dataset tflite_model converter.convert() # 3. TF.js 用于 Web 端演示 # 转 TF.js 前通常需要先保存为 SavedModel再命令行转换这个流程里每一步导出的模型都需要用对应的推理环境重新验证一遍不能只测 TensorFlow 原生模型。TFLite 量化模型在 IO 边缘设备和 Web 端推理结果和原始模型会有微小差异必须在目标环境上跑一遍验证集数据确认指标下降在可接受范围内通常是 1% 以内具体看任务敏感度。现在很多模型压缩量化版本精度掉得厉害就是因为只跑了 TensorFlow 原生精度验证没跑部署后的验证。6. 我踩过的部署坑与排查心得这一部分算是我自己真金白银换来的经验。每次项目遇到奇怪的问题我都会把问题、现象、原因、解法整理成速查表方便后续遇到同类型问题时快速对照。6.1 常见问题速查表问题现象可能原因排查方向与解法训练 loss 为 NaN学习率过大、数据含有 NaN、混合精度溢出降低学习率、检查数据预处理、在 loss 计算处加tf.cast(x, tf.float32)保存的模型加载报错自定义层缺少get_config()、使用旧版.h5格式用.keras格式、为自定义层补全配置方法TF Serving 找不到模型目录结构不规范、版本目录缺失确保/models/模型名/正整数/层级完整TFLite 转换 INT8 失败缺少代表数据集、存在不支持算子补代表数据集、查看具体不支持算子并替换TF.js 加载模型报算子缺失模型使用了冷门算子或自定义层改用标准层、查看官方算子支持列表量化后精度大幅下降代表数据集分布偏差、量化粒度选择不当重新采样代表数据、试试仅量化权重保留 FP32 激活6.2 一个典型的定位过程有次在某个项目里TFLite 转换后的模型在 Android 端推理结果全是乱码输出概率分布完全不对。当时第一反应是量化精度问题花了大量时间调代表数据集精调之后还是不对。后来冷静下来直接把原始 Keras 模型也在同样的测试图片上跑了一遍结果发现原始模型的输出本身就有问题。最后定位到是训练阶段的数据预处理方式和推理阶段不一致。训练时图像是归一化到 0~1但 Android 端加载图片后直接作为 0~255 的整数喂给模型输入分布完全偏了模型输出的 logits 当然不对。这个问题的教训是部署问题先排除输入输出预处理的一致性再怀疑模型格式和量化。大多数所谓“部署后精度下降”根源其实是预处理步骤没有对齐而不是模型本身出了问题。6.3 给入门者的几条实用建议第一保存模型时尽量用带签名的 SavedModel 格式。虽然看起来多写了几个参数但它让模型自描述后续接任何部署工具都省心。第二每次转换模型格式后写一个自动化验证脚本加载转换后的模型在同一组测试数据上跑一遍对比输出偏差。这个脚本值得在项目初期就写好避免每次手忙脚乱地临时想验证方案。第三TensorFlow 版本不一致是很多兼容性问题的根源。团队内部一定要统一 TensorFlow 版本用requirements.txt或者 Docker 镜像锁定环境。不同 Python 版本搭配不同 TensorFlow 版本行为也会略有差异工程化项目在这上面吃过亏的人不在少数。第四常看官方发布说明。TensorFlow 每个版本都有弃用警告和 API 调整但很多人习惯了“写完就不升级”等出了问题再升级迁移成本就很高了。与其被动升级不如隔一段时间主动检查一下自己项目里用的 API 是否有新的推荐替代方式。7. 一个容易忽略的细节Keras 3 带来的变化如果你使用的是 TensorFlow 2.12 以上版本Keras 3 已经以默认形式存在了。这带来了一个重要变化Keras 成为了独立于 TensorFlow 的多后端框架除了 TensorFlow你还可以选择 JAX 或 PyTorch 作为后端。对实际项目的影响有两点。第一model.save()的默认格式变成了.keras这是 Keras 3 的专有格式兼容性更好。第二如果你之前一直用 TensorFlow 特定的 API比如tf.distribute在 Keras 3 里的写法略有变化需要留意。# Keras 3 中设置后端 os.environ[KERAS_BACKEND] tensorflow切换后端听起来很诱人但我想提醒一句不要为了用新功能而用新功能。如果你当前项目跑在 TensorFlow 2 的旧版本上且稳定运行没有强需求就别动。如果你在开新项目用 Keras 3 是值得的它的 API 更统一模型构建和部署链路也更顺畅。但从 TensorFlow 2 老版本迁移过来时建议先在虚拟环境里做好完整回归测试别在生产环境直接换版本。我个人在迁移过程中遇到的主要问题是一些第三方层和自定义训练循环的代码在 Keras 3 里有细微差别比如add_loss的传参方式变了。把这些整理清楚迁移成本其实不大但收益明显后续模型转换工具链的支持也更及时。8. 最后的工程习惯建议这一路梳理下来内容确实不少。如果只留一条建议那就是把模型构建和部署的流程沉淀成一套可复用的模板。每次新项目都在这个模板上做增量而不是从零开始摸索。我现在自己项目里的做法是维护一个内部工具库其中封装了标准的数据管道构建、训练配置、模型导出三个模块。新项目进来只需要改数据路径和模型结构训练和部署链路直接复用省下来的时间相当可观。比如数据管道我封装了一个统一的函数def create_dataset(image_paths, labels, batch_size32, augmentFalse): dataset tf.data.Dataset.from_tensor_slices((image_paths, labels)) def _parse(image_path, label): image tf.io.read_file(image_path) image tf.image.decode_jpeg(image, channels3) image tf.image.resize(image, [224, 224]) image tf.image.convert_image_dtype(image, tf.float32) return image, label dataset dataset.map(_parse, num_parallel_callstf.data.AUTOTUNE) if augment: dataset dataset.map(augment_fn, num_parallel_callstf.data.AUTOTUNE) dataset dataset.shuffle(1024).batch(batch_size).prefetch(tf.data.AUTOTUNE) return dataset这个函数可以被图像分类、目标检测、图像分割等各类视觉任务复用只改解析逻辑就行。文本任务就另外写一个_parse_text其余结构不变。模型导出也是一样封装成脚本后每次训练完直接命令行调用输入模型路径和部署目标自动输出对应的部署格式。省去每次手动输入一长串参数的烦恼。这类“模板化”思维我觉得是工程效率的最大杠杆。你在单个模型上花的时间再省也就是几十分钟但如果你能在每个项目上复用一套成熟流程省下的时间就是按天计算的。这也是我做这份便携参考的真正目的——把踩过的坑、验证过的方式固化下来让后面的项目不再重复走弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑