- 原文作者:Camron Godbout
- 譯者:edvardhua
- 校對者:marcmoore, futureshine
確保你已經閱讀了第一部分
在本文中,我們將演示一個寬 N 深度網絡,它使用廣泛的線性模型與前饋網絡同時訓練,以證明它比一些傳統的機器學習技術能提供精度更高的預測結果。下面我們將使用混合學習方法預測泰坦尼克號乘客的生存概率。
混合學習技術已被 Google 應用在 Play 商店中提供應用推薦。Youtube 也在使用類似的混合學習技術來推薦視頻。
本文的代碼可以在這里找到。
廣泛深度網絡
寬和深網絡將線性模型與前饋神經網絡結合,使得我們的預測將具有記憶和通用化。 這種類型的模型可以用于分類和回歸問題。 這種方法能夠在減少特征工程的同時擁有相對精確的預測結果,可謂一箭雙雕。
數據
我們將使用泰坦尼克號 Kaggle 數據來預測乘客的生存率是否和某些屬性有關,如姓名,性別,船票,船艙的類型等。有關此數據的更多信息請點擊這里。
首先,我們要將所有列定義為連續或分類。
連續的列 - 連續范圍內的任何數值。 像錢或年齡。
**分類列 - **有限集的一部分。 像男性或女性,或著乘客的國籍。
CATEGORICAL_COLUMNS = ["Name", "Sex", "Embarked", "Cabin"]
CONTINUOUS_COLUMNS = ["Age", "SibSp", "Parch", "Fare", "PassengerId", "Pclass"]
因為我們只是想看看一個人是否幸存下來,這是一個二元分類問題。 所以預測結果 1 表示該乘客幸存下來,而結果 0 表示沒有幸存。(也即創建一列來儲存預測結果)
SURVIVED_COLUMN = "Survived"
網絡
現在我們可以創建列和添加嵌入層。 當我們構建我們的模型時,我們想要將我們的分類列變成稀疏列。 對于沒有那么多類別(例如 Sex 或 Embarked(S,Q 或 C))的列,我們根據類名將它們轉換為稀疏列。(sparse_column_with_keys)
sex = tf.contrib.layers.sparse_column_with_keys(column_name="Sex",
keys=["female",
"male"])
embarked = tf.contrib.layers.sparse_column_with_keys(column_name="Embarked",
keys=["C",
"S",
"Q"])
對于類別較多的分類列,由于我們沒有一個詞匯表文件(vocab file)將所有可能的類別映射為一個整數,所以我們使用哈希值作為鍵值。(sparse_column_with_hash_bucket)
cabin = tf.contrib.layers.sparse_column_with_hash_bucket(
"Cabin", hash_bucket_size=1000)
name = tf.contrib.layers.sparse_column_with_hash_bucket(
"Name", hash_bucket_size=1000)
我們的連續列使用的是真實的值。 因為 passengerId 是連續的而不是分類的,并且他們已經是整數的 ID 而不是字符串。
age = tf.contrib.layers.real_valued_column("Age")
passenger_id = tf.contrib.layers.real_valued_column("PassengerId")
sib_sp = tf.contrib.layers.real_valued_column("SibSp")
parch = tf.contrib.layers.real_valued_column("Parch")
fare = tf.contrib.layers.real_valued_column("Fare")
p_class = tf.contrib.layers.real_valued_column("Pclass")
我們需要根據年齡對乘客進行分類。 桶化(Bucketization )允許我們找到乘客對應年齡組的生存相關性,而不是將所有年齡作為一個大整體,從而提高我們的準確性。
age_buckets = tf.contrib.layers.bucketized_column(age,
boundaries=[
5, 18, 25,
30, 35, 40,
45, 50, 55,
65
])
最后,我們將定義我們的廣度列和深度列。 我們的寬列將有效地記住我們與特征之間的交互。 我們的寬列不會將我們的特征通用化,這是深度列的用處。
wide_columns = [sex, embarked, p_class, cabin, name, age_buckets,
tf.contrib.layers.crossed_column([p_class, cabin],
hash_bucket_size=int(1e4)),
tf.contrib.layers.crossed_column(
[age_buckets, sex],
hash_bucket_size=int(1e6)),
tf.contrib.layers.crossed_column([embarked, name],
hash_bucket_size=int(1e4))]
擁有這些深度列的好處是,它會將我們提供的高維度稀疏的特征進行降維來計算。
deep_columns = [
tf.contrib.layers.embedding_column(sex, dimension=8),
tf.contrib.layers.embedding_column(embarked, dimension=8),
tf.contrib.layers.embedding_column(p_class,
dimension=8),
tf.contrib.layers.embedding_column(cabin, dimension=8),
tf.contrib.layers.embedding_column(name, dimension=8),
age,
passenger_id,
sib_sp,
parch,
fare,
]
我們通過使用深度列和廣度列來創建分類器,以完成我們的函數。
return tf.contrib.learn.DNNLinearCombinedClassifier(
linear_feature_columns=wide_columns,
dnn_feature_columns=deep_columns,
dnn_hidden_units=[100, 50])
我們在運行網絡之前要做的最后一件事是為我們的連續和分類列創建映射。 我們先創建一個輸入函數給我們的數據框,它能將我們的數據框轉換為 Tensorflow 可以操作的對象。 這樣做的好處是,我們可以改變和調整我們的 tensors 創建過程。 例如說我們可以將特征列傳遞到.fit .feature .predict作為一個單獨創建的列,就像我們上面所描述的一樣,但這個是一個更加簡潔的方案。
def input_fn(df, train=False):
"""Input builder function."""
# Creates a dictionary mapping from each continuous feature column name (k) to
# the values of that column stored in a constant Tensor.
continuous_cols = {k: tf.constant(df[k].values) for k in CONTINUOUS_COLUMNS}
# Creates a dictionary mapping from each categorical feature column name (k)
# to the values of that column stored in a tf.SparseTensor.
categorical_cols = {k: tf.SparseTensor(
indices=[[i, 0] for i in range(df[k].size)],
values=df[k].values,
shape=[df[k].size, 1])
for k in CATEGORICAL_COLUMNS}
# Merges the two dictionaries into one.
feature_cols = dict(continuous_cols)
feature_cols.update(categorical_cols)
# Converts the label column into a constant Tensor.
if train:
label = tf.constant(df[SURVIVED_COLUMN].values)
# Returns the feature columns and the label.
return feature_cols, label
else:
# so we can predict our results that don't exist in the csv
return feature_cols
現在,做完了以上工作,我們就可以開始編寫訓練功能了
def train_and_eval():
"""Train and evaluate the model."""
df_train = pd.read_csv(
tf.gfile.Open("./train.csv"),
skipinitialspace=True)
df_test = pd.read_csv(
tf.gfile.Open("./test.csv"),
skipinitialspace=True)
model_dir = "./models"
print("model directory = %s" % model_dir)
m = build_estimator(model_dir)
m.fit(input_fn=lambda: input_fn(df_train, True), steps=200)
print m.predict(input_fn=lambda: input_fn(df_test))
results = m.evaluate(input_fn=lambda: input_fn(df_train, True), steps=1)
for key in sorted(results):
print("%s: %s" % (key, results[key]))
我們讀取預處理后的 csv 文件,像處理缺失值等。為了讓文章保持簡潔,更多有關預處理的代碼和內容可以在代碼倉庫中找到。
這些 csv 文件將通過調用 input_fn 函數轉換為 tensors 。 我們先構建評價指標,然后打印我們的預測和評估結果。
結果
運行我們的代碼為我們提供了相當好的結果,不需要添加任何額外的列或做任何特征工程。 而且只要很少的微調這個模型可以得到相對較好的結果。
與傳統廣度線性模型一起添加嵌入層的能力,允許通過將稀疏維度降低到低維度來進行準確的預測。
結論
這部分偏離了傳統的深度學習,說明 Tensorflow 還有許多其他用途和應用。 本文主要根據 Google 提供的論文和代碼進行廣泛深入的學習。 研究論文可以在這里找到。 Google 將此模型用作 Google Play 商店的產品推薦引擎,并幫助他們在提高應用銷量上給出了建議。 YouTube 也發布了一篇關于他們使用混合模型做推薦系統的文章。 這些模型開始更多地被各種公司推薦,并且會因為優秀的嵌入能力越來越流行。