EmbeddingVariable
本文中含有需要您注意的重要提示信息,忽略該信息可能對(duì)您的業(yè)務(wù)造成影響,請(qǐng)務(wù)必仔細(xì)閱讀。
使用EmbeddingVariable進(jìn)行超大規(guī)模訓(xùn)練,不僅可以保證模型特征無損,而且可以節(jié)約內(nèi)存資源。
公共云GPU服務(wù)器即將過保下線,您可以繼續(xù)提交CPU版本的TensorFlow任務(wù)。如需使用GPU進(jìn)行模型訓(xùn)練,請(qǐng)前往DLC提交任務(wù),具體操作請(qǐng)參見創(chuàng)建訓(xùn)練任務(wù)。
背景信息
Embedding已成為深度學(xué)習(xí)領(lǐng)域處理Word及ID類特征的有效途徑。作為一種“函數(shù)映射”,Embedding通常將高維稀疏特征映射為低維稠密向量,再進(jìn)行模型端到端訓(xùn)練。在TensorFlow中,使用Variable定義模型或節(jié)點(diǎn)狀態(tài),其實(shí)現(xiàn)依賴于數(shù)據(jù)結(jié)構(gòu)Tensor。Tensor是TensorFlow的抽象數(shù)據(jù)類型,包括標(biāo)量、向量、矩陣及更高維的數(shù)據(jù)結(jié)構(gòu)。Tensor作為數(shù)據(jù)載體在各算子間流通,任何支持Tensor作為輸入和輸出的算子,都可以加入Graph的計(jì)算過程中。因?yàn)?span id="z68uejxpaoma" class="help-letter-space">Tensor采用連續(xù)存儲(chǔ),所以定義Variable時(shí),必須指定類型(Type)和空間大?。⊿hape),且該空間大小不支持修改。
TensorFlow通過Variable的方式實(shí)現(xiàn)Embedding機(jī)制,用于存儲(chǔ)Embedding的Variable空間大小為[vocabulary_size, embedding_dimension]。在大規(guī)模稀疏特征場(chǎng)景下,存在以下弊端:
vocabulary_size通常由ID空間決定,隨著在線學(xué)習(xí)場(chǎng)景的ID不斷增加,會(huì)導(dǎo)致vocabulary_size難以估計(jì)。
ID通常為字符串類型且規(guī)模龐大,進(jìn)行Embedding之前,需要將其Hash到vocabulary_size范圍內(nèi):
如果vocabulary_size過小,則導(dǎo)致Hash沖突率增加,不同特征可能查找到相同的Embedding,即特征減少。
如果vocabulary_size過大,則導(dǎo)致Variable存儲(chǔ)永遠(yuǎn)不會(huì)被查找的Embedding,即內(nèi)存冗余。
Embedding變量過大是導(dǎo)致模型增大的主要原因,即使通過正則手段降低某些特征的Embedding對(duì)整個(gè)模型效果的影響,也無法從模型中去除該Embedding。
為解決上述問題,PAI-TF推出動(dòng)態(tài)Embedding語義的EmbeddingVariable,在特征無損訓(xùn)練的條件下,以經(jīng)濟(jì)的方式使用內(nèi)存資源,從而實(shí)現(xiàn)超大規(guī)模特征的離線訓(xùn)練和模型上線。PAI-TF提供EmbeddingVariable(3.1)及Feature_Column(3.3)API,推薦使用Feature_Column API,它可以自動(dòng)增加字符串的Feature ID化流程。
EmbeddingVariable特性
動(dòng)態(tài)Embedding。
無需指定Vocabulary規(guī)模,只需要指定Embedding Dim,PAI-TF就可以根據(jù)訓(xùn)練,動(dòng)態(tài)地?cái)U(kuò)展或縮減詞典大小。適用于在線學(xué)習(xí)場(chǎng)景,同時(shí)省略了TensorFlow模型的數(shù)據(jù)預(yù)處理流程。
Group Lasso正則。
通常經(jīng)過深度學(xué)習(xí)的Embedding變量規(guī)模超大,如果將其部署為在線服務(wù),則會(huì)造成服務(wù)器壓力。使用Group Lasso正則處理Embedding,可以減少模型部署的壓力。
支持將原始特征值傳入Embedding Lookup,省略了Hash等ID化操作,從而實(shí)現(xiàn)特征的無損訓(xùn)練。
支持Graph的Inference、Back Propagation及變量的導(dǎo)入導(dǎo)出,模型訓(xùn)練中通過Optimizer自動(dòng)更新EmbeddingVariable。
tf.get_embedding_variable接口說明
tf.get_embedding_variable接口返回一個(gè)已有的EmbeddingVariable變量或新建的EmbeddingVariable變量,接口定義如下。
get_embedding_variable(
name,
embedding_dim,
key_dtype=dtypes.int64,
value_dtype=None,
initializer=None,
trainable=True,
collections=None,
partitioner=None,
custom_getter=None,
steps_to_live=None,
filter_options=variables.CounterFilterOptions()
)
name:Embedding Variable的名稱。
embedding_dim:Embedding的維度。例如8或64。
key_dtype:Lookup時(shí)key的類型,默認(rèn)值為int64。
value_dtype: EmbeddingVariable的類型,僅支持float類型。
initializer:EmbeddingVariable的初始值。
trainable:是否被添加到GraphKeys.TRAINABLE_VARIABLES的Collection。
collections:一個(gè)記錄了collection的keys的列表,該Variable會(huì)被加入到列表中的collection,默認(rèn)為[GraphKeys.GLOBAL_VARIABLES]。
partitioner:分區(qū)函數(shù)。
custom_getter:一個(gè)可調(diào)用的對(duì)象,將true getter作為它的第一個(gè)參數(shù)傳入,并且允許覆蓋內(nèi)部的
get_variable
方法。應(yīng)符合def custom_getter(getter,*args,**kwargs)
的形式,也可以通過def custom_getter(getter,name,*args,**kwargs)
的形式直接訪問get_variable
中的所有參數(shù)。steps_to_live:全局步長(zhǎng),用于自動(dòng)淘汰過期特征。系統(tǒng)會(huì)刪除全局步數(shù)超過該參數(shù)值的未更新特征。
filter_options:準(zhǔn)入策略,支持根據(jù)特征頻次進(jìn)行準(zhǔn)入。
EmbeddingVariable
EmbeddingVariable的結(jié)構(gòu)如下。
class EmbeddingVariable(ResourceVariable)
def total_count():
# 返回Embedding當(dāng)前的total_count,[rowCount,EmbeddingDim]。
def read_value():
raise NotImplementedError("...")
def assign():
raise NotImplementedError("...")
def assign_add():
raise NotImplementedError("...")
def assign_sub():
raise NotImplementedError("...")
支持讀取稀疏數(shù)據(jù)的
sparse_read()
方法。如果查詢的key不存在,則返回EmbeddingVariable初始化時(shí),該key對(duì)應(yīng)的initializer。支持查詢EmbeddingVariable詞表總數(shù)的
total_count()
方法,該方法返回EmbeddingVariable的動(dòng)態(tài)Shape值。不支持全量讀取EmbeddingVariable的
read_value()
方法。不支持EmbeddingVariable的賦值方法,包括
assign()
、assign_add()
及assign_sub()
。CounterFilterOptions的結(jié)構(gòu)如下。
@tf_export("CounterFilterOptions") class CounterFilterOptions(object): def __init__(self, filter_freq=0): pass
指定準(zhǔn)入頻次,默認(rèn)值為0。
使用feature_column接口構(gòu)建EmbeddingVariable
def tf.contrib.layers.sparse_column_with_embedding(column_name=column_name,
dtype=tf.string,
partition_num=None,
steps_to_live=None,
# 1120版本不支持以下兩個(gè)參數(shù),僅140lite版本支持。
steps_to_live_l2reg=None,
l2reg_theta=None)
# column_name: column name
# dtype: type, default is tf.string
示例
使用底層tf.get_embedding_variable接口構(gòu)建包含EmbeddingVariable的TensorFlow Graph。
#!/usr/bin/python import tensorflow as tf var = tf.get_embedding_variable("var_0", embedding_dim=3, initializer=tf.ones_initializer(tf.float32), partitioner=tf.fixed_size_partitioner(num_shards=4)) shape = [var1.total_count() for var1 in var] emb = tf.nn.embedding_lookup(var, tf.cast([0,1,2,5,6,7], tf.int64)) fun = tf.multiply(emb, 2.0, name='multiply') loss = tf.reduce_sum(fun, name='reduce_sum') opt = tf.train.FtrlOptimizer(0.1, l1_regularization_strength=2.0, l2_regularization_strength=0.00001) g_v = opt.compute_gradients(loss) train_op = opt.apply_gradients(g_v) init = tf.global_variables_initializer() sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False) with tf.Session(config=sess_config) as sess: sess.run([init]) print(sess.run([emb, train_op, loss])) print(sess.run([emb, train_op, loss])) print(sess.run([emb, train_op, loss])) print(sess.run([shape]))
將EmbeddingVariable保存為Checkpoint。
#!/usr/bin/python import tensorflow as tf var = tf.get_embedding_variable("var_0", embedding_dim=3, initializer=tf.ones_initializer(tf.float32), partitioner=tf.fixed_size_partitioner(num_shards=4)) emb = tf.nn.embedding_lookup(var, tf.cast([0,1,2,5,6,7], tf.int64)) init = tf.global_variables_initializer() saver = tf.train.Saver(sharded=True) print("GLOBAL_VARIABLES: ", tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)) print("SAVEABLE_OBJECTS: ", tf.get_collection(tf.GraphKeys.SAVEABLE_OBJECTS)) checkpointDir = "/tmp/model_dir" sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False) with tf.Session(config=sess_config) as sess: sess.run([init]) print(sess.run([emb])) save_path = saver.save(sess, checkpointDir + "/model.ckpt", global_step=666) tf.train.write_graph(sess.graph_def, checkpointDir, 'train.pbtxt') print("save_path", save_path) print("list_variables", tf.contrib.framework.list_variables(checkpointDir))
從Checkpoint中恢復(fù)EmbeddingVariable變量。
#!/usr/bin/python import tensorflow as tf var = tf.get_embedding_variable("var_0", embedding_dim=3, initializer=tf.ones_initializer(tf.float32), partitioner=tf.fixed_size_partitioner(num_shards=4)) emb = tf.nn.embedding_lookup(var, tf.cast([0,1,2,5,6,7], tf.int64)) init = tf.global_variables_initializer() saver = tf.train.Saver(sharded=True) print("GLOBAL_VARIABLES: ", tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)) print("SAVEABLE_OBJECTS: ", tf.get_collection(tf.GraphKeys.SAVEABLE_OBJECTS)) checkpointDir = "/tmp/model_dir" sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False) with tf.Session(config=sess_config) as sess: print("list_variables", tf.contrib.framework.list_variables(checkpointDir)) saver.restore(sess, checkpointDir + "/model.ckpt-666") print(sess.run([emb]))
使用feature_column接口構(gòu)建包含EmbeddingVariable的TensorFlow Graph。
import tensorflow as tf import os columns_list=[] columns_list.append(tf.contrib.layers.sparse_column_with_embedding(column_name="col_emb", dtype=tf.string)) W = tf.contrib.layers.shared_embedding_columns(sparse_id_columns=columns_list, dimension=3, initializer=tf.ones_initializer(tf.float32), shared_embedding_name="xxxxx_shared") ids={} ids["col_emb"] = tf.SparseTensor(indices=[[0,0],[1,0],[2,0],[3,0],[4,0]], values=["aaaa","bbbbb","ccc","4nn","5b"], dense_shape=[5, 5]) emb = tf.contrib.layers.input_from_feature_columns(columns_to_tensors=ids, feature_columns=W) fun = tf.multiply(emb, 2.0, name='multiply') loss = tf.reduce_sum(fun, name='reduce_sum') opt = tf.train.FtrlOptimizer(0.1, l1_regularization_strength=2.0, l2_regularization_strength=0.00001) g_v = opt.compute_gradients(loss) train_op = opt.apply_gradients(g_v) init = tf.global_variables_initializer() init_local = tf.local_variables_initializer() sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False) with tf.Session(config=sess_config) as sess: sess.run(init) print("init global done") sess.run(init_local) print("init local done") print(sess.run([emb, train_op,loss])) print(sess.run([emb, train_op,loss])) print(sess.run([emb, train_op,loss])) print(sess.run([emb]))
說明EmbeddingVariable僅支持Ftrl Optimizer、Adagrad Optimizer、Adam Optimizer及AdagradDecay Optimizer。