使用預(yù)設(shè)的 Estimator 模型
在之前的學(xué)習(xí)中,我們學(xué)習(xí)到了如何使用 Keras 來(lái)快速、簡(jiǎn)潔地構(gòu)建網(wǎng)絡(luò)模型,我們也認(rèn)識(shí)到了使用 tf.keras 構(gòu)建模型的優(yōu)點(diǎn)。但是在 TensorFlow 之中構(gòu)建網(wǎng)絡(luò)模型的方式遠(yuǎn)遠(yuǎn)不止 Keras 一種方式,那么這節(jié)課開始我們便開始學(xué)習(xí)如何使用 Estimator 來(lái)構(gòu)建模型。
1. 什么是 Estimator
Estimator 是 TensorFlow 之中模型的一種高級(jí)表示,也就是說(shuō),我們可以像使用 Keras 一樣來(lái)創(chuàng)建自己的模型,并進(jìn)行訓(xùn)練、評(píng)估等操作。Estimator 主要可以提供的功能包括:
- 模型的訓(xùn)練;
- 模型的評(píng)估;
- 使用模型進(jìn)行預(yù)測(cè)。
在 TensorFlow 之中,Estimator 的大部分 API 都集中在 tf.estimator 之中。
在 API 層面上,Keras 與 Estimator 處于相同的層面,與 Keras 相似,Estimator 也是一種模型層面的高階 API,因此也可以和 Keras 一樣快捷、方便地使用。
但是與 Keras 不同的是,Estimator 在 TensorFlow1.1 版本的時(shí)候就已經(jīng)被引入了 TensorFlow,也正因如此,TensorFlow 對(duì)于 Estimator 的支持也較好一些。
2. 使用 Estimator 構(gòu)建模型的一般步驟
在 TensorFlow 之中,使用 Estimator 進(jìn)行模型訓(xùn)練大致需要經(jīng)過(guò)四個(gè)步驟,它們分別是:
- 定義特征列;
- 定義輸入函數(shù);
- 創(chuàng)建(實(shí)例化)一個(gè) Estimator 模型;
- 訓(xùn)練并進(jìn)行相應(yīng)的評(píng)估等操作。
對(duì)于這四個(gè)步驟,相信特征列和輸入函數(shù)這兩個(gè)名詞對(duì)于大家都很陌生,那么我們便來(lái)進(jìn)行相應(yīng)解釋:
-
特征列:
“特征列(feature columns)是一個(gè)對(duì)象,用于描述模型應(yīng)該如何使用特征字典中的原始輸入數(shù)據(jù)”——官方定義
簡(jiǎn)單來(lái)說(shuō),特征列就是來(lái)告訴模型你要使用數(shù)據(jù)中的哪些數(shù)據(jù)列,其中哪些數(shù)據(jù)列為離散值,哪些數(shù)據(jù)列為連續(xù)值。
-
輸入函數(shù):簡(jiǎn)單來(lái)說(shuō),輸入函數(shù)是一個(gè)函數(shù),它返回的是一個(gè)數(shù)據(jù)集,其中的每條數(shù)據(jù)都是(特征,標(biāo)簽)的形式。我們可以將輸入函數(shù)理解為“模型用來(lái)取數(shù)據(jù)的地方,通過(guò)輸入函數(shù),模型可以不斷取得新的數(shù)據(jù)”。
因?yàn)?TensorFlow 內(nèi)部提供了很多內(nèi)置的 Estimator 模型,因此這節(jié)課我們會(huì)采用其預(yù)設(shè)的模型來(lái)進(jìn)行分類學(xué)習(xí)。
對(duì)于這四步的具體細(xì)節(jié),我們會(huì)在接下來(lái)的示例過(guò)程中具體演示。
3. 實(shí)例-使用 Estimator 進(jìn)行泰坦尼克生存預(yù)測(cè)
首先我們需要先獲取數(shù)據(jù)集,也就是泰塔尼克數(shù)據(jù)集,我們采用之前相同的方式來(lái)獲取數(shù)據(jù)集:
import pandas as pd
import tensorflow as tf
train_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
columns = ['survived', 'sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']
categorical = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck', 'embark_town', 'alone']
numeric = ['age', 'fare']
train_df = pd.read_csv(train_file, names=columns)
其中我們 columns 變量定義了全部的列,同時(shí)我們定義了 categorical 和 numeric 兩個(gè)數(shù)據(jù)列,分別代表離散值以及連續(xù)值,這便于我們后面的編碼處理。
然后我們進(jìn)行測(cè)試集與訓(xùn)練集的劃分:
test_df = train_df.sample(frac=0.2)
train_df = train_df[~train_df.index.isin(test_df.index)]
train_df_y = train_df.pop('survived')
test_df_y = test_df.pop('survived')
print(len(train_df), len(test_df))
在這里,我們使用 train_df.sample() 方法來(lái)按照 0.2 的采樣率進(jìn)行隨機(jī)采樣,從來(lái)獲取我們的測(cè)試集,然后我們將原來(lái)集合中的測(cè)試集去掉,得到剩下的訓(xùn)練集。然后我們又采用 pop 的方式來(lái)獲取到標(biāo)簽值。這里我們按照傳統(tǒng)的8:2的比例進(jìn)行分割。
我們可以得到輸出:
502, 125
然后我們就進(jìn)行特征列的構(gòu)造,在這里我們將特征列分為連續(xù)值與離散值,對(duì)于離散值,我們進(jìn)行了獨(dú)熱編碼的處理,因?yàn)楠?dú)熱編碼在訓(xùn)練的過(guò)程中較大的優(yōu)勢(shì):
def transfer2one_hot(feature, feature_vocab):
return tf.feature_column.indicator_column(tf.feature_column.categorical_column_with_vocabulary_list(feature, feature_vocab))
features = []
for feature in categorical:
features.append(
transfer2one_hot(feature, train_df[feature].unique())
)
for feature in numeric:
features.append(
tf.feature_column.numeric_column(feature, dtype=tf.float32)
)
在這里我們使用到了三個(gè)非常重要的函數(shù):
- tf.feature_column.numeric_column,將某一列作為連續(xù)值視作數(shù)據(jù)特征;
- tf.feature_column.indicator_column,將某一離散列作為獨(dú)熱編碼視作數(shù)據(jù)列;
- tf.feature_column.categorical_column_with_vocabulary_list,接收第一個(gè)參數(shù)為某一離散特征列,第二個(gè)參數(shù)為該離散特征列的所有取值情況,將一個(gè)普通列視作離散數(shù)據(jù)列(未經(jīng)過(guò)獨(dú)熱編碼)。
然后我們便可以定義我們的輸入函數(shù),在這里我們將輸入函數(shù)分為訓(xùn)練時(shí)的輸入函數(shù)以及測(cè)試時(shí)的輸入函數(shù),具體來(lái)說(shuō):
def train_input_fn(features, labels, batch_size=8):
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
dataset = dataset.shuffle(len(train_df))
dataset = dataset.repeat(30000)
return dataset.batch(batch_size)
def test_input_fn(features, labels, batch_size=8):
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
return dataset.batch(batch_size)
train_fn = lambda: train_input_fn(train_df, train_df_y)
test_fn = lambda: test_input_fn(test_df, test_df_y)
在輸入函數(shù)之中,我們使用參數(shù)中的 features 和 labels 創(chuàng)建了一個(gè)數(shù)據(jù)集,并且將其返回。并且對(duì)于訓(xùn)練集,我們采用了數(shù)據(jù)增強(qiáng),也就是隨機(jī)化以及重復(fù)操作,在這里,30000 就是我們要訓(xùn)練的 Steps 數(shù)量(我們所使用的 batch_size 的數(shù)量,這里是8)。
最后因?yàn)檩斎牒瘮?shù)是一個(gè)函數(shù),因此我們需要定義一個(gè) lambda 函數(shù)來(lái)返回一個(gè)輸入函數(shù),否則輸入函數(shù)將直接返回一個(gè)數(shù)據(jù)集,這是我們不希望看到的。
再者我們就可以載入一個(gè)內(nèi)置的模型:
classifier = tf.estimator.DNNClassifier(
feature_columns=feature_columns,
hidden_units=[50, 30, 20],
n_classes=2)
在這里我們定義了一個(gè) Estimator 內(nèi)置的分類器,它的三個(gè)參數(shù)如下:
- feature_columns,特征列,就是我們剛剛處理過(guò)的特征列,包含連序列與離散列;
- hidden_units,隱藏單元的數(shù)量,在這里我們定義了三層;
- n_classes,輸出的種類,這里我們只有生存和不能生存兩類。
最后我們便可以進(jìn)行模型的訓(xùn)練與測(cè)試,具體的實(shí)現(xiàn)細(xì)節(jié)非常簡(jiǎn)單:
classifier.train(input_fn=train_fn, steps=30000)
test_result = classifier.evaluate(input_fn=test_fn)
print(test_result)
我們首先進(jìn)行了訓(xùn)練,輸入函數(shù)為我們之前定義的訓(xùn)練的輸入函數(shù),然后訓(xùn)練 Steps 為 30000 ,然后我們便進(jìn)行了測(cè)試,此時(shí)的輸入函數(shù)為我們?yōu)闇y(cè)試專門定制的輸入函數(shù)。我們可以得到結(jié)果:
......
INFO:tensorflow:global_step/sec: 861.581
INFO:tensorflow:loss = 0.4950667, step = 47500 (0.114 sec)
INFO:tensorflow:global_step/sec: 885.82
INFO:tensorflow:loss = 0.30664578, step = 47600 (0.113 sec)
INFO:tensorflow:global_step/sec: 879.637
INFO:tensorflow:loss = 0.82413065, step = 47700 (0.116 sec)
INFO:tensorflow:global_step/sec: 814.178
INFO:tensorflow:loss = 0.5236651, step = 47800 (0.123 sec)
INFO:tensorflow:global_step/sec: 829.556
INFO:tensorflow:loss = 0.4500552, step = 47900 (0.118 sec)
......
{'accuracy': 0.724, 'accuracy_baseline': 0.7624, 'auc': 0.5004091, 'auc_precision_recall': 0.43117255, 'average_loss': 1.7417283, 'label/mean': 0.376, 'loss': 2.7342584, 'precision': 0.0, 'prediction/mean': 0.025458882, 'recall': 0.0, 'global_step': 0}
我們可以看到,最后我們?cè)跍y(cè)試集上的準(zhǔn)確率為 0.72 ,也是一個(gè)不錯(cuò)的結(jié)果。
4. 小結(jié)
在這節(jié)課之中,我們學(xué)習(xí)了什么是 Estimator,同時(shí)也了解了使用 Estimator 進(jìn)行訓(xùn)練的一般步驟,最后我們也學(xué)習(xí)了如何在實(shí)戰(zhàn)中使用 Estimator 模型。