tensorflow2.0 keras SavedModel模型特征预处理

神经网络和xgboost有一个很大的区别,就是xgboost树模型对每个特征的数值范围不敏感,因此基本不需要做特征预处理就可以达到不错的效果。

而神经网络对特征的数值范围敏感,如果不进行特征预处理,模型效果可能还不如xgboost。

神经网络的特征预处理

为了让神经网络正常工作,特征预处理主要是2类:

  • one-hot
  • 标准化(让每个特征均值0、方差1)

在scikit-learn里面,我们一般是先对全量训练数据进行预处理完成标准化,然后再输入到模型。

在tensorflow神经网络模型里并不是这样,我们的标准化动作属于模型中的一层(标准化层),它是随着batch训练自学习的,并不需要我们先把全部训练数据过一遍,只需要直接投入到1个batch接着1个batch的训练过程中即可。

这样非常方便,因为我们训练完成后可以直接把模型保存为SavedModel放到tensorflow serving中,在线服务只需要直接把原始特征传给tensorflow serving,由模型预测过程中自动帮我们完成标准化,这样在线服务代码就不需要重复去实现特征预处理的复杂过程了。

one-hot或者其他简单的线性变化原理都一样,就是作为一层写到模型里即可。

举个例子

这是来自我的视频教程《简单粗暴的tensorflow2.0》中的部分代码,对其略作改动,以便给大家演示如何在神经网络模型中引入一些数据预处理逻辑。

数据loader

注意,这里我刻意没有对输入的训练图片进行/255的缩放,目的就是把这一步实现在模型的层中,以便可以让特征预处理+模型融为一体。

自定义预处理层

在模型的第一层就是我们的预处理层,我这里自定义Layer,给大家演示2个动作:

  • 所有通道值除以255。
  • 再对所有通道值做标准化。

这里使用tf.match.divide方法对tensor的所有列除以255,然后使用BatchNormalization层做标准化(其实它就是根据1个batch内的数据进行归一化,在batch之间不停的调整)。

注意,在tf模型中的所有对tensor的变换都需要用tf提供的方法,否则无法被编译为计算图,也就无法导出为SavedModel,同时也无法得到最优的执行速度。

另外,call方法的training参数是tf框架传入的,我们要把它透传给BatchNormalization,否则模型做预测的时候也会调整内部的权重。

构造模型

有了预处理层,我们就可以构造整个网络结构了:

为了方便,我使用函数式构造方法,在Input层后紧跟着预处理层。

编译模型

常规操作,给模型配置损失函数、优化函数、还有评估函数。

训练模型

训练样本未经处理,直接丢入模型,在模型计算过程中完成预处理:

观察batchNormalization层学习到的参数

在输出头部可以看见几个相关参数:

模型预测

现在,我们拿着test数据直接丢入模型,完全不需要对其进行预处理,全部交给模型完成:

得到精度97.33%:

最后

采用继承Model实现模型是一样的道理,只需要在模型计算过程中调用batchNormalization层或者普通的tf.math运算即可,但要记得调用batchNormalization时候也要透传traning参数。

模型正常导出即可用于tf serving,这样工程代码也就不需做特征预处理了,多么方便。

美团有一篇博客大概提到了特征预处理进模型的思路:https://tech.meituan.com/2018/10/11/tfserving-improve.html

有任何问题欢迎留言交流。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~