【Tensorflow2】Estimator使用流程——以Titanic预测任务为例
Estimator是Tensorflow完整模型的高级表示,它被设计用于轻松扩展和异步训练。
这句话是官方文档上的描述,我觉得说的挺对的。为了更直观的体会这句话,这里我以Kaggle经典的入门练习Titanic为例,为大家呈现Estimator的完整使用流程。
Titanic任务与数据说明
当完成Kaggle的注册之后,你需要完成的第一个入门级任务就是Titanic。
这个任务的目的是预测乘客是否会存活。数据集中会提供乘客的一些基础特征,用于构建模型输入数据。这些特征包括了:
- PassengerId: 乘客的ID
- Survived: 乘客是否存活。0表示没有存活,1表示存活
- Pclass: 乘客的船票等级。包含1、2、3级。
- Name: 乘客姓名。
- Sex: 乘客性别。包括male和female。
- Age: 乘客年龄。
- SibSp: 和乘客一起在船上的亲人数(包括兄弟姐妹配偶)。
- Parch: 和乘客一起在船上的亲人数(包括父母和子女)。
- Ticket: 乘客的船票编号。
- Fare: 乘客的船票价格。
- Cabin: 乘客的船舱编号。
- Embarked: 乘客的上船港口。包括C(瑟堡)、Q(皇后镇)、S(南安普顿)
上面的PassengerId作为索引列,不参与到模型特征构建。Survived为模型预测的标签列。很明显这是个二分类问题。话不多说,接下来我将对数据进行简单的预处理,以方便后面的模型训练。
数据预处理
由于我后面会使用FeatureColumn来对特征进行编码,这里的预处理只是进行简单的缺失值填充。通过对每个特征列取值的统计,发现Age
、Fare
、Cabin
、Embarked
这四个特征列中存在取值缺失的情况。这里我直接采用给缺失记录统一填充相同缺失标志符的方法来处理。
1 | import pandas as pd |
缺失值处理的方法有很多,这里我只是为了呈现Estimator的完整使用流程,对于模型的准确率并不是本篇文章的关注点。
input_fn
这里用来构建模型训练和评估时的输入函数。由于是包含了训练和评估两部分,就需要对数据集进行分隔。
Titanic的数据集下载地址在这里
我会按照8:2的比例来获得训练数据集和测试数据集。
1 | import pandas as pd |
上面这种划分还是比较傻的,sklearn中提供了很多更好的方法,有兴趣的朋友可以去研究一下。
接下来,就可以定义模型的输入函数了。我将根据具体的代码实现来说明一下构建逻辑:
1 | def input_fn(data, batch_size, is_training, num_epochs=1): |
这里的输入包括了上面切割好的训练数据和测试数据,就是参数data。
还需要定义数据的批次大小(batch_size),Estimator采用小批量梯度下降的方法来进行模型训练。
is_training用来区分任务类型,以此来决定是否需要对数据进行shuffle操作。训练过程中对数据进行shuffle,可以在一定程度上加快模型收敛速度。
训练任务一般会对数据进行多轮迭代,通过num_epochs可以设置迭代次数。
这一部分主要使用tf.data的API,更多内容可以参考Dataset简明教程
feature_column
原始的输入数据中既有连续特征也有离散特征,这就需要我给每个特征的定义处理逻辑,来完成原始数据向模型真正用于计算的输入数据的数值化转换。
我这里并不打算使用所有的特征列,只用其中的几个进行举例即可。
- 可以穷举的标称特征
Sex、Pclass、Embarked这三个特征的取值不多,可以使用list进行可能取值的管理。
1 | sex = tf.feature_column.categorical_column_with_vocabulary_list( |
- 无法穷举的标称特征
Ticket、Cabin这两个特征的取值比较多,无法使用list来进行可能取值的管理。
1 | ticket = tf.feature_column.categorical_column_with_hash_bucket( |
- 连续特征
SibSp、Parch都是数值类型,可以直接用到模型中。
1 | sibsp = tf.feature_column.numeric_column(key='SibSp') |
- 数值类型特征的离散化处理
Age、Fare也是数值类型,但是Age特征不具有计算意义,Fare特征的取值差异性较大。针对这两个特征我进行分桶处理。
1 | raw_age = tf.feature_column.numeric_column(key='Age') |
这里我暂时只使用上面这些特征,完整的处理逻辑如下:
1 | def feature_column(): |
在最后的返回特征列表中,我对所有的离散化特征列进行了Embedding处理,从而将最终的所有特征列都进行了数值化转换。
Estimator模型
Tensorflow官方提供了一些开箱即用的Estimator模型,这里我使用其中的DNNClassifier模型来进行此次任务的预测。关于如何实现自定义Estimator模型,后续我还会再分享。
1 | model = tf.estimator.DNNClassifier(feature_columns=feature_column(), |
这样就定义好了一个DNN二分类模型,里面的很多参数都可以调整。关于模型调优的这里就不说了。
训练与评估
Estimator设计了一套非常方便的模型训练和评估架构,能够实现一套模型代码无缝地在单机和分布式环境下任意切换。人性化的方法设计也让模型训练和评估变得更加直观简单。
1 | train_spec = tf.estimator.TrainSpec( |
通过定义TrainSpec和EvalSpec来配置模型训练和评估的参数。这里主要用到的就是input_fn和最大训练或评估步数。
触发模型的训练和评估,使用下面的方法实现:
1 | tf.estimator.train_and_evaluate( |
使用到的参数都是上面已经定义好的,只需要把它们捆绑到一起即可。
完整代码和日志
1 | import tensorflow as tf |
1 | INFO:tensorflow:Using default config. |
模型预测
完成了上面的操作,就可以在./model
目录下得到最终的模型文件。关于模型文件的格式、导出等更多内容,我后续也会力争给大家分享。
Titanic的预测数据集下载地址在这里
由于预测数据集并不包含Survived
列,所以我重新写了个input_fn方法,只包含了批次设置。
预测的时候,直接使用上面定义的model
变量,调用predict方法就可以了,不能再简单。
1 | predict_input = data_process(pd.read_csv('./test.csv')) |