神經(jīng)網(wǎng)絡(luò)如何更有效地實(shí)現(xiàn)傳統(tǒng)機(jī)器學(xué)習(xí)任務(wù)?

在《XGBoost與神經(jīng)網(wǎng)絡(luò)誰更牛?》文章,基于相同數(shù)據(jù),對(duì)XGBoost和神經(jīng)網(wǎng)絡(luò)(NN)兩種方法進(jìn)行橫行比較。XGBoost是屬于Tree Model,只把分類特征進(jìn)行數(shù)字化。對(duì)神經(jīng)網(wǎng)絡(luò)(NN)先把分類特征數(shù)值化,然后轉(zhuǎn)換為One-hot。結(jié)果兩個(gè)算法的測(cè)試結(jié)果(損失值)如下:

表3-1兩種不同算法測(cè)試結(jié)果

《XGBoost與神經(jīng)網(wǎng)絡(luò)誰更牛?》基于相同數(shù)據(jù)集用不同算法進(jìn)行比較,本章將從縱向進(jìn)行比較,即基于相同數(shù)據(jù)集,相同算法(都是神經(jīng)網(wǎng)絡(luò)NN),但特征處理方式不同。一種是《XGBoost與神經(jīng)網(wǎng)絡(luò)誰更牛?》的方法,另外一種對(duì)分類特征采用Embedding方法,把分類特征轉(zhuǎn)換為向量,并且這些向量的值會(huì)隨著模型的迭代而自動(dòng)更新。這兩種方法比較的結(jié)果如表3-2所示:

表3-2 同一算法不同特征處理方式的測(cè)試結(jié)果

訓(xùn)練及測(cè)試數(shù)據(jù)沒有打亂,其中測(cè)試數(shù)據(jù)是最新原數(shù)據(jù)的10%。

從表3-2可以看出,使用EE處理分類特征的方法性能遠(yuǎn)好于不使用EE的神經(jīng)網(wǎng)絡(luò),使用EE有利于充分發(fā)揮NN的潛能,提升NN在實(shí)現(xiàn)傳統(tǒng)機(jī)器學(xué)習(xí)任務(wù)的性能。

EE處理方法為何能大大提升模型的性能?使用EE處理特征有哪些優(yōu)勢(shì),Embedding方法是否還適合于處理其它特征?如連續(xù)特征、時(shí)許特征、圖(graph)特征等。這些問題后續(xù)將陸續(xù)進(jìn)行說明。接下來我們將用Keras或TensorFlow的Embeding層處理分類特征。

3.1 Embedding簡(jiǎn)介

神經(jīng)網(wǎng)絡(luò)、深度學(xué)習(xí)的應(yīng)用越來越廣泛,從計(jì)算機(jī)視覺到自然語言處理和時(shí)間序列預(yù)測(cè)。在這些領(lǐng)域都取得不錯(cuò)成績(jī),有很多落地項(xiàng)目性能已超過人的平均水平。不但有較好的性能,特征工程方面更是實(shí)現(xiàn)了特征工程的自動(dòng)化。

特征工程是傳統(tǒng)機(jī)器學(xué)習(xí)的核心任務(wù),模型性能如何很大程度取決特征工程處理方法,由此,要得到理想的特征工程往往需要很多業(yè)務(wù)和技術(shù)方面的技巧,因此有“特征工程是一門藝術(shù)”的說法,這也從一個(gè)側(cè)面說明特征工程的門檻比較高,不利于普及和推廣。不過這種情況,近些年正在改變。為了解決這一大瓶頸,人們開始使用神經(jīng)網(wǎng)絡(luò)或深度學(xué)習(xí)方法處理傳統(tǒng)機(jī)器學(xué)習(xí)任務(wù),特征工程方法使用Embedding 方法,把離散變量轉(zhuǎn)變?yōu)檩^低維的向量,通過這種方式,我們可以將神經(jīng)網(wǎng)絡(luò),深度學(xué)習(xí)用于更廣泛的領(lǐng)域。

目前Embedding已廣泛使用在自然語言處理(NLP)、結(jié)構(gòu)化數(shù)據(jù)、圖形數(shù)據(jù)等處理方面。在NLP 中常用的 Word Embedding ,對(duì)結(jié)構(gòu)化數(shù)據(jù)使用 Entity Embedding,對(duì)圖形數(shù)據(jù)采用Graph Embedding。這些內(nèi)容后續(xù)我們將陸續(xù)介紹。這里先介紹如何用keras或TensorFlow實(shí)現(xiàn)分類特征的Embedding。

3.1.1 Keras.Embedding格式

keras的Embedding層格式如下:

keras.layers.Embedding(input_dim, output_dim, embeddings_initializer='uniform', embeddings_regularizer=None, activity_regularizer=None, embeddings_constraint=None, mask_zero=False, input_length=None)

Keras提供了一個(gè)嵌入層(Embedding layer),可用于處理文本數(shù)據(jù)、分類數(shù)據(jù)等的神經(jīng)網(wǎng)絡(luò)。它要求輸入數(shù)據(jù)進(jìn)行整數(shù)編碼,以便每個(gè)單詞或類別由唯一的整數(shù)表示。嵌入層使用隨機(jī)權(quán)重初始化,并將學(xué)習(xí)所有數(shù)據(jù)集中詞或類別的表示。這層只能作為模型的第1層。

【參數(shù)說明】

? input_dim: int > 0。詞匯表大小或類別總數(shù), 即,最大整數(shù)索引(index) + 1。

? output_dim: int >= 0。詞向量的維度。

? embeddings_initializer: embeddings 矩陣的初始化方法 (詳見 https://keras.io/initializers/)。

? embeddings_regularizer: embeddings matrix 的正則化方法

(詳見https://keras.io/regularizers/)。

? embeddings_constraint: embeddings matrix 的約束函數(shù) (詳見 https://keras.io/constraints/)。

? mask_zero: 是否把 0 看作為一個(gè)應(yīng)該被遮蔽的特殊的 "padding" 值。這對(duì)于可變長(zhǎng)的循環(huán)神經(jīng)網(wǎng)絡(luò)層十分有用。 如果設(shè)定為 True,那么接下來的所有層都必須支持 masking,否則就會(huì)拋出異常。 如果 mask_zero 為 True,作為結(jié)果,索引 0 就不能被用于詞匯表中 (input_dim 應(yīng)該與 vocabulary + 1 大小相同)。

? input_length: 輸入序列的長(zhǎng)度,當(dāng)它是固定的時(shí)。 如果你需要連接 Flatten 和 Dense 層,則這個(gè)參數(shù)是必須的 (沒有它,dense 層的輸出尺寸就無法計(jì)算)。

? 輸入尺寸

尺寸為 (batch_size, sequence_length) 的 2D 張量。

? 輸出尺寸

尺寸為 (batch_size, sequence_length, output_dim) 的 3D 張量。

更多信息可參考官網(wǎng):

https://keras.io/layers/embeddings/

https://keras.io/zh/layers/embeddings/(中文)

假設(shè)定義一個(gè)詞匯量為200的嵌入層的整數(shù)編碼單詞,將詞嵌入到32維的向量空間,每次輸入50個(gè)單詞的輸入文檔,那么對(duì)應(yīng)的embedding可寫成如下格式:

em=Embedding(200,32,input_length=50)

為更好理解Keras的Embedding層的使用,下面列舉幾個(gè)具體實(shí)例。

(1)簡(jiǎn)單實(shí)例代碼:


model = Sequential()

model.add(Embedding(1000, 64, input_length=10))

# 模型將輸入一個(gè)大小為 (batch, input_length) 的整數(shù)矩陣。

# 輸入中最大的整數(shù)(即詞索引)不應(yīng)該大于 999 (詞匯表大小)

#生成輸入矩陣,batch=32,input_length=10

input_array = np.random.randint(1000, size=(32, 10))

#編譯模型

model.compile('rmsprop', 'mse')

#進(jìn)行預(yù)測(cè)

output_array = model.predict(input_array)

# 現(xiàn)在 model.output_shape == (None, 10, 64),其中 None 是 batch 的維度。

print(output_array.shape) ###(32, 10, 64)


(2)用Embedding學(xué)習(xí)文本表示實(shí)例

假設(shè)有10個(gè)文本文檔,每個(gè)文檔都有一個(gè)學(xué)生提交的工作評(píng)論。每個(gè)文本文檔被分類為正的“1”或負(fù)的“0”。這是一個(gè)簡(jiǎn)單的情感分析問題。用Keras的Embedding學(xué)習(xí)這10個(gè)文本的表示,具體實(shí)現(xiàn)代碼如下;

#導(dǎo)入需要的模塊


import numpy as np

from tensorflow.keras.preprocessing.text import one_hot

from tensorflow.keras.preprocessing.sequence import pad_sequences

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dense

from tensorflow.keras.layers import Flatten

from tensorflow.keras.layers import Embedding

#定義一個(gè)文檔,這個(gè)文檔有10句語句

docs = ['Well done!',

? ? ? ? 'Good work',

? ? ? ? 'Great effort',

? ? ? ? 'nice work',

? ? ? ? 'Excellent!',

? ? ? ? 'Weak',

? ? ? ? 'Poor effort!',

? ? ? ? 'not good',

? ? ? ? 'poor work',

? ? ? ? 'Could have done better.']

#定義對(duì)應(yīng)的類標(biāo)簽

labels = np.array([1,1,1,1,1,0,0,0,0,0])

vocab_size = 50

# 用one-hot函數(shù)將文本編碼為大小為vocab_size的單詞索引列表

encoded_docs = [one_hot(d, vocab_size) for d in docs]

print("把文本轉(zhuǎn)換為整數(shù)")

print(encoded_docs)

# 將序列填充到相同的長(zhǎng)度(長(zhǎng)度為4)

max_length = 4

padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')

print("填充向量")

print(padded_docs)

#定義模型

model = Sequential()

model.add(Embedding(vocab_size,8,input_length=max_length,name='word_embedding'))

model.add(Flatten())

model.add(Dense(1, activation='sigmoid'))

#編譯模型

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])

#查看模型結(jié)構(gòu)

print("查看模型結(jié)構(gòu)")

print(model.summary())

#擬合模型

model.fit(padded_docs, labels, epochs=50, verbose=0)

#評(píng)估模型

loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)

print("查看模型精度")

print('Accuracy: %f' % (accuracy*100))


運(yùn)行結(jié)果如下:

把文本轉(zhuǎn)換為整數(shù)

[[49, 28], [33, 36], [21, 41], [18, 36], [32], [29], [18, 41], [30, 33], [18, 36], [43, 17, 28, 34]]

填充向量

[[49 28 0 0]

[33 36 0 0]

[21 41 0 0]

[18 36 0 0]

[32 0 0 0]

[29 0 0 0]

[18 41 0 0]

[30 33 0 0]

[18 36 0 0]

[43 17 28 34]]

查看模型結(jié)構(gòu)

Model: "sequential_5"

_________________________________________________________________

Layer (type) Output Shape Param #

=================================================================

embedding_5 (Embedding) (None, 4, 8) 400

_________________________________________________________________

flatten_4 (Flatten) (None, 32) 0

_________________________________________________________________

dense_4 (Dense) (None, 1) 33

=================================================================

Total params: 433

Trainable params: 433

Non-trainable params: 0

_________________________________________________________________

None

查看模型精度

Accuracy: 89.999998

查看通過50次迭代后的Embedding矩陣。

model.get_layer('word_embedding').get_weights()[0].shape ##(50,8)

model.get_layer('word_embedding').get_weights()[0][:3] #查看前3行

運(yùn)行結(jié)果如下:

array([[ 0.03469506, 0.05556902, -0.06460979, 0.04944995, -0.04956526,

-0.01446372, -0.01657126, 0.04287368],

[ 0.04969586, -0.0284451 , -0.03200825, -0.00149088, 0.04212971,

-0.00741715, -0.02147427, -0.02345204],

[ 0.00152697, 0.04381416, 0.01856637, -0.00952369, 0.04007444,

0.00964203, -0.0313913 , -0.04820969]], dtype=float32)

3.1.2 Dense簡(jiǎn)介

keras.layers.Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)

Dense就是常用的的全連接層,它實(shí)現(xiàn)以下操作:

output = activation(dot(input, kernel) + bias)

其中 activation 是按逐個(gè)元素計(jì)算的激活函數(shù),kernel 是由網(wǎng)絡(luò)層創(chuàng)建的權(quán)值矩陣,以及 bias 是其創(chuàng)建的偏置向量 (只在 use_bias 為 True 時(shí)才有用)。

注意: 如果該層的輸入的秩大于2,那么它首先被展平然后 再計(jì)算與 kernel 的點(diǎn)乘。

【參數(shù)說明】

? units: 正整數(shù),輸出空間維度。

? activation: 激活函數(shù) (詳見 activations)。 若不指定,則不使用激活函數(shù) (即,「線性」激活: a(x) = x)。

? use_bias: 布爾值,該層是否使用偏置向量。

? kernel_initializer: kernel 權(quán)值矩陣的初始化器 (詳見https://keras.io/zh/initializers/)。

? bias_initializer: 偏置向量的初始化器 (詳見https://keras.io/zh/initializers/).

? kernel_regularizer: 運(yùn)用到 kernel 權(quán)值矩陣的正則化函數(shù) (詳見 https://keras.io/zh/regularizers/)。

? bias_regularizer: 運(yùn)用到偏置向的的正則化函數(shù) (詳見 https://keras.io/zh/regularizers/)。

? activity_regularizer: 運(yùn)用到層的輸出的正則化函數(shù) (它的 "activation")。 (詳見 https://keras.io/zh/regularizers/)。

? kernel_constraint: 運(yùn)用到 kernel 權(quán)值矩陣的約束函數(shù) (詳見https://keras.io/zh/constraints/)。

? bias_constraint: 運(yùn)用到偏置向量的約束函數(shù) (詳見https://keras.io/zh/constraints/)。

? 輸入尺寸

nD張量,尺寸: (batch_size, ..., input_dim)。 最常見的情況是一個(gè)尺寸為 (batch_size, input_dim) 的2D輸入。

? 輸出尺寸

nD張量,尺寸: (batch_size, ..., units)。 例如,對(duì)于尺寸為 (batch_size, input_dim)的2D輸入, 輸出的尺寸為 (batch_size, units)。

簡(jiǎn)單示例代碼:


# 作為 Sequential 模型的第一層

model = Sequential()

model.add(Dense(32, input_shape=(16,)))

# 現(xiàn)在模型就會(huì)以尺寸為 (*, 16) 的數(shù)組作為輸入,

# 其輸出數(shù)組的尺寸為 (*, 32)

# 在第一層之后,就不再需要指定輸入的尺寸了:

model.add(Dense(32))


3.2 NN架構(gòu)


圖3-2 NN架構(gòu)圖

從圖3-2可知,NN共處理7個(gè)特征,其中promo特征因只有2個(gè)值(0或1),無需轉(zhuǎn)換為Embedding向量,其它6個(gè)特征,根據(jù)類別數(shù),分別做了Embedding處理。處理后合并這7個(gè)特征,再通過3個(gè)全連接層。

3.3 分類特征處理

基于第2章(《XGBoost與NN誰更牛?》)處理保存的feature_train_data.pickle文件,做如下處理:

3.3.1 數(shù)據(jù)預(yù)處理

(1)定義對(duì)特征進(jìn)行Embedding處理函數(shù)


#從訓(xùn)練結(jié)果讀取各特征的embedding向量,并用這些向量作為輸入值

def embed_features(X, saved_embeddings_fname):

? ? # f_embeddings = open("embeddings_shuffled.pickle", "rb")

? ? f_embeddings = open(saved_embeddings_fname, "rb")

? ? embeddings = pickle.load(f_embeddings)


? ? #因store_open,promo這兩列(索引分別為0、3),至多只有兩個(gè)值,沒有進(jìn)行embedding,故需排除在外

? ? index_embedding_mapping = {1: 0, 2: 1, 4: 2, 5: 3, 6: 4, 7: 5}

? ? X_embedded = []

? ? (num_records, num_features) = X.shape

? ? for record in X:

? ? ? ? embedded_features = []

? ? ? ? for i, feat in enumerate(record):

? ? ? ? ? ? feat = int(feat)

? ? ? ? ? ? if i not in index_embedding_mapping.keys():

? ? ? ? ? ? ? ? embedded_features += [feat]

? ? ? ? ? ? else:

? ? ? ? ? ? ? ? embedding_index = index_embedding_mapping[i]

? ? ? ? ? ? ? ? embedded_features += embeddings[embedding_index][feat].tolist()

? ? ? ? X_embedded.append(embedded_features)

? ? return numpy.array(X_embedded)

#分別取出各特征,因第1列只有1個(gè)值,不用第1列(即索引為0的列)

def split_features(X):

? ? X_list = []

? ? #獲取X第2列數(shù)據(jù)

? ? store_index = X[..., [1]]

? ? X_list.append(store_index)

? ? #獲取X第3列數(shù)據(jù),以下類推

? ? day_of_week = X[..., [2]]

? ? X_list.append(day_of_week)

? ? promo = X[..., [3]]

? ? X_list.append(promo)

? ? year = X[..., [4]]

? ? X_list.append(year)

? ? month = X[..., [5]]

? ? X_list.append(month)

? ? day = X[..., [6]]

? ? X_list.append(day)

? ? State = X[..., [7]]

? ? X_list.append(State)

? ? return X_list


(2)導(dǎo)入模塊


import pickle

import numpy

numpy.random.seed(123)

from tensorflow.keras.models import Sequential

from tensorflow.keras.models import Model as KerasModel

from tensorflow.keras.layers import Input, Dense, Activation, Reshape,Flatten

from tensorflow.keras.layers import Concatenate

from tensorflow.keras.layers import Embedding

from tensorflow.keras.callbacks import ModelCheckpoint

import sys

sys.setrecursionlimit(10000)

train_ratio = 0.9

shuffle_data = False

one_hot_as_input = False

embeddings_as_input = False

save_embeddings = True

saved_embeddings_fname = "embeddings.pickle"? # set save_embeddings to True to create this file


(3)讀取數(shù)據(jù)


f = open('feature_train_data.pickle', 'rb')

(X, y) = pickle.load(f)

num_records = len(X)

train_size = int(train_ratio * num_records)


(4)生成訓(xùn)練、測(cè)試數(shù)據(jù)


X_train = X[:train_size]

X_val = X[train_size:]

y_train = y[:train_size]

y_val = y[train_size:]


(5)定義采樣函數(shù)


def sample(X, y, n):

? ? '''random samples'''

? ? num_row = X.shape[0]

? ? indices = numpy.random.randint(num_row, size=n)

? ? return X[indices, :], y[indices]


(6)采樣生成訓(xùn)練數(shù)據(jù)


X_train, y_train = sample(X_train, y_train, 200000) # Simulate data sparsity

print("Number of samples used for training: " + str(y_train.shape[0]))


3.3.2 構(gòu)建模型

(1)定義Model類


class Model(object):

? ? def evaluate(self, X_val, y_val):

? ? ? ? assert(min(y_val) > 0)

? ? ? ? guessed_sales = self.guess(X_val)

? ? ? ? relative_err = numpy.absolute((y_val - guessed_sales) / y_val)

? ? ? ? result = numpy.sum(relative_err) / len(y_val)

? ? ? ? return result


(2)構(gòu)建模型


class NN_with_EntityEmbedding(Model):

? ? def __init__(self, X_train, y_train, X_val, y_val):

? ? ? ? super().__init__()

? ? ? ? self.epochs = 10

? ? ? ? self.checkpointer = ModelCheckpoint(filepath="best_model_weights.hdf5", verbose=1, save_best_only=True)

? ? ? ? self.max_log_y = max(numpy.max(numpy.log(y_train)), numpy.max(numpy.log(y_val)))

? ? ? ? self.__build_keras_model()

? ? ? ? self.fit(X_train, y_train, X_val, y_val)

? ? def preprocessing(self, X):

? ? ? ? X_list = split_features(X)

? ? ? ? return X_list

? ? def __build_keras_model(self):

? ? ? ? input_store = Input(shape=(1,))

? ? ? ? output_store = Embedding(1115, 10, name='store_embedding')(input_store)

? ? ? ? output_store = Reshape(target_shape=(10,))(output_store)

? ? ? ? input_dow = Input(shape=(1,))

? ? ? ? output_dow = Embedding(7, 6, name='dow_embedding')(input_dow)

? ? ? ? output_dow = Reshape(target_shape=(6,))(output_dow)


? ? ? ? #promo只有0、1兩個(gè)值,無需進(jìn)行Embedding

? ? ? ? input_promo = Input(shape=(1,))

? ? ? ? output_promo = Dense(1)(input_promo)

? ? ? ? input_year = Input(shape=(1,))

? ? ? ? output_year = Embedding(3, 2, name='year_embedding')(input_year)

? ? ? ? output_year = Reshape(target_shape=(2,))(output_year)

? ? ? ? input_month = Input(shape=(1,))

? ? ? ? output_month = Embedding(12, 6, name='month_embedding')(input_month)

? ? ? ? output_month = Reshape(target_shape=(6,))(output_month)

? ? ? ? input_day = Input(shape=(1,))

? ? ? ? output_day = Embedding(31, 10, name='day_embedding')(input_day)

? ? ? ? output_day = Reshape(target_shape=(10,))(output_day)

? ? ? ? input_germanstate = Input(shape=(1,))

? ? ? ? output_germanstate = Embedding(12, 6, name='state_embedding')(input_germanstate)

? ? ? ? output_germanstate = Reshape(target_shape=(6,))(output_germanstate)

? ? ? ? input_model = [input_store, input_dow, input_promo,

? ? ? ? ? ? ? ? ? ? ? input_year, input_month, input_day, input_germanstate]

? ? ? ? output_embeddings = [output_store, output_dow, output_promo,

? ? ? ? ? ? ? ? ? ? ? ? ? ? output_year, output_month, output_day, output_germanstate]

? ? ? ? output_model = Concatenate()(output_embeddings)

? ? ? ? output_model = Dense(1000, kernel_initializer="uniform")(output_model)

? ? ? ? output_model = Activation('relu')(output_model)

? ? ? ? output_model = Dense(500, kernel_initializer="uniform")(output_model)

? ? ? ? output_model = Activation('relu')(output_model)

? ? ? ? output_model = Dense(1)(output_model)

? ? ? ? output_model = Activation('sigmoid')(output_model)

? ? ? ? self.model = KerasModel(inputs=input_model, outputs=output_model)

? ? ? ? self.model.compile(loss='mean_absolute_error', optimizer='adam')

? ? def _val_for_fit(self, val):

? ? ? ? val = numpy.log(val) / self.max_log_y

? ? ? ? return val

? ? def _val_for_pred(self, val):

? ? ? ? return numpy.exp(val * self.max_log_y)

? ? def fit(self, X_train, y_train, X_val, y_val):

? ? ? ? self.model.fit(self.preprocessing(X_train), self._val_for_fit(y_train),

? ? ? ? ? ? ? ? ? ? ? validation_data=(self.preprocessing(X_val), self._val_for_fit(y_val)),

? ? ? ? ? ? ? ? ? ? ? epochs=self.epochs, batch_size=128,

? ? ? ? ? ? ? ? ? ? ? # callbacks=[self.checkpointer],

? ? ? ? ? ? ? ? ? ? ? )

? ? ? ? # self.model.load_weights('best_model_weights.hdf5')

? ? ? ? print("Result on validation data: ", self.evaluate(X_val, y_val))

? ? def guess(self, features):

? ? ? ? features = self.preprocessing(features)

? ? ? ? result = self.model.predict(features).flatten()

? ? ? ? return self._val_for_pred(result)


(3)訓(xùn)練模型


models = []

print("Fitting NN_with_EntityEmbedding...")

for i in range(5):

? ? models.append(NN_with_EntityEmbedding(X_train, y_train, X_val, y_val))


運(yùn)行部分結(jié)果

Fitting NN_with_EntityEmbedding...

Train on 200000 samples, validate on 84434 samples

Epoch 1/10

200000/200000 [==============================] - 37s 185us/sample - loss: 0.0140 - val_loss: 0.0113

Epoch 2/10

200000/200000 [==============================] - 33s 165us/sample - loss: 0.0093 - val_loss: 0.0110

Epoch 3/10

200000/200000 [==============================] - 34s 168us/sample - loss: 0.0085 - val_loss: 0.0104

Epoch 4/10

200000/200000 [==============================] - 35s 173us/sample - loss: 0.0079 - val_loss: 0.0107

Epoch 5/10

200000/200000 [==============================] - 37s 184us/sample - loss: 0.0076 - val_loss: 0.0100

Epoch 6/10

200000/200000 [==============================] - 38s 191us/sample - loss: 0.0074 - val_loss: 0.0095

Epoch 7/10

200000/200000 [==============================] - 31s 154us/sample - loss: 0.0072 - val_loss: 0.0097

Epoch 8/10

200000/200000 [==============================] - 33s 167us/sample - loss: 0.0071 - val_loss: 0.0091

Epoch 9/10

200000/200000 [==============================] - 36s 181us/sample - loss: 0.0069 - val_loss: 0.0090

Epoch 10/10

200000/200000 [==============================] - 40s 201us/sample - loss: 0.0068 - val_loss: 0.0089

Result on validation data: 0.09481584162850512

Train on 200000 samples, validate on 84434 samples

Epoch 1/10

200000/200000 [==============================] - 38s 191us/sample - loss: 0.0143 - val_loss: 0.0125

Epoch 2/10

200000/200000 [==============================] - 41s 206us/sample - loss: 0.0096 - val_loss: 0.0107

Epoch 3/10

200000/200000 [==============================] - 46s 232us/sample - loss: 0.0089 - val_loss: 0.0105

Epoch 4/10

200000/200000 [==============================] - 39s 197us/sample - loss: 0.0082 - val_loss: 0.0099

Epoch 5/10

200000/200000 [==============================] - 39s 197us/sample - loss: 0.0077 - val_loss: 0.0095

Epoch 6/10

200000/200000 [==============================] - 41s 207us/sample - loss: 0.0075 - val_loss: 0.0111

Epoch 7/10

200000/200000 [==============================] - 39s 193us/sample - loss: 0.0073 - val_loss: 0.0092

Epoch 8/10

200000/200000 [==============================] - 50s 248us/sample - loss: 0.0071 - val_loss: 0.0092

Epoch 9/10

200000/200000 [==============================] - 46s 228us/sample - loss: 0.0070 - val_loss: 0.0094

Epoch 10/10

200000/200000 [==============================] - 44s 221us/sample - loss: 0.0069 - val_loss: 0.0091

Result on validation data: 0.09585602861091462

3.3.3 驗(yàn)證模型


#求多個(gè)模型的集成精度

def evaluate_models(models, X, y):

? ? assert(min(y) > 0)

? ? guessed_sales = numpy.array([model.guess(X) for model in models])

? ? mean_sales = guessed_sales.mean(axis=0)

? ? relative_err = numpy.absolute((y - mean_sales) / y)

? ? result = numpy.sum(relative_err) / len(y)

? ? return result

print("Evaluate combined models...")

print("Training error...")

r_train = evaluate_models(models, X_train, y_train)

print(r_train)

print("Validation error...")

r_val = evaluate_models(models, X_val, y_val)

print(r_val)


運(yùn)行結(jié)果如下:

Evaluate combined models...

Training error...

0.06760082089742254

Validation error...

0.09348419043167332

3.4 可視化Entity Embedding

把特征轉(zhuǎn)換為Entity Embedding之后,可以利用t-SNE進(jìn)行可視化,如對(duì)store特征的Embedding降維后進(jìn)行可視化,從可視化結(jié)果揭示出一些重要信息,彼此相似的類別比較接近。

3.4.1 保存Embedding


#保存各特征的embedding值

if save_embeddings:

? ? model = models[3].model

? ? store_embedding = model.get_layer('store_embedding').get_weights()[0]

? ? dow_embedding = model.get_layer('dow_embedding').get_weights()[0]

? ? year_embedding = model.get_layer('year_embedding').get_weights()[0]

? ? month_embedding = model.get_layer('month_embedding').get_weights()[0]

? ? day_embedding = model.get_layer('day_embedding').get_weights()[0]

? ? german_states_embedding = model.get_layer('state_embedding').get_weights()[0]

? ? with open(saved_embeddings_fname, 'wb') as f:

? ? ? ? pickle.dump([store_embedding, dow_embedding, year_embedding,

? ? ? ? ? ? ? ? ? ? month_embedding, day_embedding, german_states_embedding], f, -1)


3.4.2 可視化Embedding特征

(1)導(dǎo)入模塊


import pickle

from sklearn import manifold

import matplotlib.pyplot as plt

import numpy as np

%matplotlib inline

#屏蔽警告信息

import warnings

warnings.filterwarnings('ignore')


(2)讀取保存的embedding文件


with open("embeddings.pickle", 'rb') as f:

? ? [store_embedding, dow_embedding, year_embedding,

? ? month_embedding, day_embedding, german_states_embedding] = pickle.load(f)


(3)定義對(duì)應(yīng)各州的名稱


states_names = ["柏林","巴登?符騰堡","拜仁","下薩克森","黑森","漢堡","北萊茵?威斯特法倫州","萊茵蘭?普法爾茨州","石勒蘇益格荷爾斯泰因州","薩克森州","薩克森安哈爾特州","圖林根州"]


(4)可視化german_states_embedding


plt.rcParams['font.sans-serif']=['SimHei'] ##顯示中文

plt.rcParams['axes.unicode_minus']=False? ##防止坐標(biāo)軸上的-號(hào)變?yōu)榉綁K

tsne = manifold.TSNE(init='pca', random_state=0, method='exact')

Y = tsne.fit_transform(german_states_embedding)

plt.figure(figsize=(8,8))

plt.scatter(-Y[:, 0], -Y[:, 1])

for i, txt in enumerate(states_names):

? ? plt.annotate(txt, (-Y[i, 0],-Y[i, 1]), xytext = (-20, 8), textcoords = 'offset points')

plt.savefig('state_embedding.pdf')


可視化結(jié)果如下:


圖3-4 可視化german_states_embedding

從圖3-2 可知,德國(guó)的原屬于東德的幾個(gè)州:薩克森州、薩克森安哈爾特州、圖林根州彼此比較接近。其它各州也有類似屬性,這就是Embedding通過多次迭代,從數(shù)據(jù)中學(xué)習(xí)到一些規(guī)則。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容