習(xí)連續(xù)特征處理的自動(dòng)化與優(yōu)化方案)
1. 從“硬分桶”到“軟學(xué)習(xí)”為什么我們需要AutoDis在推薦、廣告、搜索這些以深度學(xué)習(xí)模型為核心的場(chǎng)景里特征工程是決定模型效果上限的基石。其中連續(xù)特征Continuous Features的處理一直是個(gè)既基礎(chǔ)又棘手的問題。比如用戶的年齡、消費(fèi)金額、瀏覽時(shí)長(zhǎng)、物品的價(jià)格、歷史點(diǎn)擊率CTR等等。這些特征不像用戶ID、物品ID這類離散特征天然就有一個(gè)現(xiàn)成的Embedding表可以查。傳統(tǒng)做法也是很多工程師的第一反應(yīng)就是“分桶”Bucketization或者叫“離散化”Discretization。簡(jiǎn)單來說就是把一個(gè)連續(xù)的數(shù)值比如年齡18歲根據(jù)預(yù)設(shè)的閾值比如[0, 20), [20, 30), [30, 40)...硬生生地劃歸到某一個(gè)桶里然后把這個(gè)桶當(dāng)作一個(gè)離散的類別再去學(xué)習(xí)它的Embedding。這個(gè)方法直接、有效在很長(zhǎng)一段時(shí)間里都是工業(yè)界的標(biāo)準(zhǔn)操作。但干過這活兒的同學(xué)都知道這里面的坑太多了。首先閾值怎么定憑經(jīng)驗(yàn)等頻等寬對(duì)于年齡等寬似乎合理但對(duì)于消費(fèi)金額長(zhǎng)尾分布嚴(yán)重等寬分桶會(huì)讓頭部極少數(shù)樣本獨(dú)占多個(gè)桶尾部大量樣本擠在一個(gè)桶里信息損失巨大。等頻分桶能緩解分布問題但桶的邊界值可能沒有業(yè)務(wù)意義比如把100.3元和100.5元分到兩個(gè)不同的桶而且線上服務(wù)時(shí)一個(gè)新來的數(shù)值比如一個(gè)前所未有的高消費(fèi)額可能落不到任何一個(gè)桶里需要兜底策略。其次信息損失不可避免。一旦分桶18歲和19歲屬于同一個(gè)“[0,20)”桶它們?cè)谀P脱劾锞褪峭耆嗤亩?9歲和20歲雖然只差1歲卻因?yàn)榭邕^了閾值被分到了兩個(gè)不同的桶擁有了完全獨(dú)立的Embedding。這種“桶內(nèi)無差別桶間硬切割”的特性破壞了連續(xù)特征本身固有的序關(guān)系和數(shù)值相近性模型學(xué)習(xí)起來非常別扭。最后超參數(shù)敏感。桶的數(shù)量是一個(gè)需要精心調(diào)校的超參數(shù)。桶太少表達(dá)能力不足模型學(xué)不到精細(xì)的差異桶太多不僅增加模型參數(shù)和計(jì)算量還容易在小桶上過擬合。我們往往需要花費(fèi)大量的精力在特征分桶的調(diào)參上。那么有沒有一種方法能讓模型自動(dòng)地、更優(yōu)雅地從連續(xù)特征中學(xué)習(xí)到表征既保留其連續(xù)性又能像離散特征一樣生成高質(zhì)量的Embedding向量呢這就是KDD 2021上提出的AutoDis框架要解決的核心問題。它不再進(jìn)行“硬分桶”而是轉(zhuǎn)向一種“軟學(xué)習(xí)”的范式讓Embedding的生成過程本身是可微的、可學(xué)習(xí)的。接下來我們就深入這個(gè)框架的內(nèi)部看看它是如何巧妙設(shè)計(jì)的。2. AutoDis核心三件套元嵌入、自動(dòng)相關(guān)性、聚合門控AutoDis的整個(gè)設(shè)計(jì)非常模塊化且直觀它主要包含三個(gè)核心組件我習(xí)慣稱之為“三件套”。理解了這三部分你就掌握了AutoDis的精髓。2.1 元嵌入先準(zhǔn)備好“候選素材庫(kù)”AutoDis首先承認(rèn)為連續(xù)特征預(yù)設(shè)一些“原型”或“基礎(chǔ)元素”是必要的這類似于分桶中的“桶”。但它不把數(shù)值硬分到某一個(gè)桶而是準(zhǔn)備一組可以靈活組合的“素材”。具體來說對(duì)于每一個(gè)連續(xù)特征字段比如“年齡”我們定義H個(gè)元嵌入。你可以把H想象成我們預(yù)設(shè)的“桶”的數(shù)量比如H10。每個(gè)元嵌入ME_h都是一個(gè)d維的向量和最終我們想要的Embedding維度一致。這H個(gè)元嵌入就構(gòu)成了這個(gè)特征的一個(gè)“可學(xué)習(xí)的嵌入字典”或“素材庫(kù)”。注意這里H的選擇相對(duì)寬松。因?yàn)樗辉偈恰胺滞皵?shù)”而是“基向量的數(shù)量”。即使H設(shè)置得比較大比如20、30由于后續(xù)的聚合機(jī)制也不會(huì)導(dǎo)致參數(shù)爆炸或過擬合因?yàn)樗⒉恢苯訉?duì)應(yīng)樣本的分配。這在一定程度上降低了對(duì)這個(gè)超參數(shù)的敏感性。這一步對(duì)應(yīng)論文中的Meta-Embeddings。所有樣本共享這同一組H個(gè)元嵌入。對(duì)于一個(gè)具體的年齡值比如25歲模型的任務(wù)不是選擇其中一個(gè)元嵌入而是思考“如何用這H個(gè)素材組合出一個(gè)最能代表25歲的Embedding”2.2 自動(dòng)相關(guān)性計(jì)算數(shù)值與每個(gè)“素材”的親和度接下來對(duì)于輸入的具體連續(xù)值x經(jīng)過標(biāo)準(zhǔn)化等預(yù)處理AutoDis需要計(jì)算這個(gè)x與每一個(gè)元嵌入ME_h的“相關(guān)性”或“親和度”。這個(gè)計(jì)算是通過一個(gè)自動(dòng)相關(guān)性模塊實(shí)現(xiàn)的。這個(gè)模塊通常是一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)比如一個(gè)多層感知機(jī)。輸入是標(biāo)量值x輸出是一個(gè)H維的向量我們稱之為相關(guān)性權(quán)重w。w的每個(gè)元素w_h代表了數(shù)值x與第h個(gè)元嵌入ME_h的相關(guān)程度。w softmax(MLP(x))這里使用softmax是為了讓所有權(quán)重歸一化形成一個(gè)概率分布表示x的“注意力”在這H個(gè)元嵌入上的分配。這個(gè)過程是完全可微的并且是數(shù)據(jù)驅(qū)動(dòng)的。模型通過訓(xùn)練自己學(xué)會(huì)什么樣的數(shù)值比如較小的年齡應(yīng)該與哪幾個(gè)元嵌入有更高的相關(guān)性。舉個(gè)例子假設(shè)H5。對(duì)于x25年齡模型可能學(xué)到的權(quán)重是[0.1, 0.6, 0.2, 0.1, 0.0]。這意味著25歲這個(gè)特征與第2個(gè)元嵌入關(guān)系最密切與第1、3、4個(gè)也有一定關(guān)聯(lián)與第5個(gè)無關(guān)。這就實(shí)現(xiàn)了“軟分配”25歲不是硬屬于“20-30歲”桶而是與多個(gè)“概念”以不同強(qiáng)度關(guān)聯(lián)。2.3 聚合門控加權(quán)求和生成最終Embedding有了元嵌入MEH個(gè)每個(gè)d維和相關(guān)性權(quán)重wH維最后一步就水到渠成了生成最終的Embedding。最終Embeddinge就是這H個(gè)元嵌入的加權(quán)和e sum_{h1}^{H} (w_h * ME_h)由于w是通過可微函數(shù)MLPsoftmax從x計(jì)算出來的因此整個(gè)從x到e的映射過程是端到端可訓(xùn)練的。梯度可以一路從損失函數(shù)反向傳播經(jīng)過聚合層通過權(quán)重w更新自動(dòng)相關(guān)性模塊的MLP參數(shù)同時(shí)也會(huì)更新元嵌入ME本身。為什么這個(gè)設(shè)計(jì)是巧妙的保持連續(xù)性輸入x的微小變化會(huì)導(dǎo)致MLP輸出的權(quán)重w發(fā)生連續(xù)、平滑的變化從而使得生成的Embeddinge也連續(xù)變化。這保留了連續(xù)特征的內(nèi)在性質(zhì)。可解釋性雖然不像線性變換那樣直接但我們可以通過分析權(quán)重w的分布來理解模型是如何“理解”這個(gè)連續(xù)特征的。比如我們可能發(fā)現(xiàn)某個(gè)元嵌入總是對(duì)“高消費(fèi)”數(shù)值有高權(quán)重那它就可以被解釋為“高消費(fèi)模式”的基底。表達(dá)能力強(qiáng)最終的Embedding空間是H個(gè)元嵌入張成的子空間中的一點(diǎn)。只要H足夠且元嵌入線性無關(guān)這個(gè)空間可以表達(dá)非常豐富的模式遠(yuǎn)超簡(jiǎn)單的線性變換或分段常數(shù)函數(shù)硬分桶。下表對(duì)比了AutoDis與傳統(tǒng)硬分桶的核心差異特性傳統(tǒng)硬分桶AutoDis處理方式分段常數(shù)函數(shù)硬分配可微的軟分配加權(quán)聚合連續(xù)性破壞桶內(nèi)相同桶間跳躍保持輸出隨輸入連續(xù)變化參數(shù)每個(gè)桶一個(gè)獨(dú)立EmbeddingH個(gè)元嵌入 一個(gè)小型MLP參數(shù)超參數(shù)敏感度高依賴桶數(shù)和邊界中低H影響較小MLP結(jié)構(gòu)固定外推能力差需兜底策略較好MLP可泛化到未見過的x可解釋性強(qiáng)桶有明確邊界中等通過權(quán)重分布解釋3. 手把手實(shí)現(xiàn)將AutoDis集成到你的DNN模型中理論很優(yōu)美但更重要的是落地。這里我將以一個(gè)簡(jiǎn)化的點(diǎn)擊率預(yù)測(cè)模型為例展示如何用PyTorch實(shí)現(xiàn)AutoDis層并把它嵌入到一個(gè)典型的深度推薦模型如DeepFM、DCN等中。我們假設(shè)我們的特征包含稀疏特征用戶ID、物品ID和稠密特征年齡、消費(fèi)額。這里聚焦于如何用AutoDis處理“年齡”和“消費(fèi)額”這兩個(gè)連續(xù)特征。3.1 定義AutoDis模塊首先我們實(shí)現(xiàn)一個(gè)通用的AutoDis模塊。import torch import torch.nn as nn import torch.nn.functional as F class AutoDis(nn.Module): AutoDis: Automatic Discretization for Deep Learning with Continuous Features. 針對(duì)單個(gè)連續(xù)特征字段。 Args: meta_embedding_dim (int): 元嵌入的維度也是最終輸出Embedding的維度。 num_meta_embeddings (int): 元嵌入的數(shù)量 H。 temperature (float, optional): softmax的溫度參數(shù)用于控制權(quán)重分布的平滑程度。默認(rèn)為1.0。 def __init__(self, meta_embedding_dim, num_meta_embeddings, temperature1.0): super(AutoDis, self).__init__() self.meta_embedding_dim meta_embedding_dim self.num_meta_embeddings num_meta_embeddings self.temperature temperature # 1. 定義H個(gè)元嵌入 self.meta_embeddings nn.Parameter( torch.randn(num_meta_embeddings, meta_embedding_dim) * 0.02 ) # 形狀: [H, d] # 2. 定義自動(dòng)相關(guān)性網(wǎng)絡(luò) (一個(gè)簡(jiǎn)單的MLP) # 輸入是標(biāo)量x輸出是H維的logits self.correlation_net nn.Sequential( nn.Linear(1, 64), nn.ReLU(), nn.Dropout(0.1), # 可選的Dropout防止過擬合 nn.Linear(64, num_meta_embeddings) # 輸出H個(gè)logits ) def forward(self, x): Args: x (Tensor): 輸入的具體特征值形狀為 [batch_size, 1] 或 [batch_size]。 Returns: e (Tensor): 生成的Embedding形狀為 [batch_size, meta_embedding_dim]。 weights (Tensor): 相關(guān)性權(quán)重形狀為 [batch_size, num_meta_embeddings]。用于可解釋性分析。 # 確保輸入是二維的 [batch_size, 1] if x.dim() 1: x x.unsqueeze(-1) # [batch_size] - [batch_size, 1] batch_size x.size(0) # 通過相關(guān)性網(wǎng)絡(luò)得到logits logits self.correlation_net(x) # [batch_size, H] # 應(yīng)用溫度系數(shù)的softmax得到歸一化權(quán)重 weights F.softmax(logits / self.temperature, dim-1) # [batch_size, H] # 加權(quán)聚合元嵌入 # self.meta_embeddings: [H, d] # weights.unsqueeze(-1): [batch_size, H, 1] # 廣播相乘后求和 weighted_meta_embeds self.meta_embeddings.unsqueeze(0) * weights.unsqueeze(-1) # [batch_size, H, d] e weighted_meta_embeds.sum(dim1) # [batch_size, d] return e, weights3.2 構(gòu)建包含AutoDis的CTR模型現(xiàn)在我們構(gòu)建一個(gè)簡(jiǎn)單的模型它包含對(duì)稀疏特征user_id, item_id使用常規(guī)的Embedding層。對(duì)連續(xù)特征age, expense使用我們剛實(shí)現(xiàn)的AutoDis層。一個(gè)簡(jiǎn)單的多層感知機(jī)作為預(yù)測(cè)層。class CTRModelWithAutoDis(nn.Module): def __init__(self, num_users, num_items, embedding_dim, auto_dis_dim, auto_dis_h): super(CTRModelWithAutoDis, self).__init__() self.embedding_dim embedding_dim # 稀疏特征嵌入層 self.user_embedding nn.Embedding(num_users, embedding_dim) self.item_embedding nn.Embedding(num_items, embedding_dim) # AutoDis層處理連續(xù)特征 self.autodis_age AutoDis(meta_embedding_dimauto_dis_dim, num_meta_embeddingsauto_dis_h) self.autodis_expense AutoDis(meta_embedding_dimauto_dis_dim, num_meta_embeddingsauto_dis_h) # 假設(shè)我們還有兩個(gè)普通的稠密特征非AutoDis處理比如歷史點(diǎn)擊數(shù)和曝光數(shù) self.dense_fc nn.Linear(2, embedding_dim) # 將2維稠密特征映射到embedding_dim維 # 預(yù)測(cè)層 # 輸入user_emb, item_emb, age_emb, expense_emb, 其他稠密特征emb # 總共 5 * embedding_dim 維 total_emb_dim embedding_dim * 5 self.predictor nn.Sequential( nn.Linear(total_emb_dim, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, 64), nn.ReLU(), nn.Dropout(0.2), nn.Linear(64, 1), nn.Sigmoid() ) def forward(self, user_id, item_id, age, expense, other_dense_features): # 1. 稀疏特征嵌入 user_emb self.user_embedding(user_id) # [batch_size, embedding_dim] item_emb self.item_embedding(item_id) # [batch_size, embedding_dim] # 2. AutoDis處理連續(xù)特征 age_emb, _ self.autodis_age(age) # [batch_size, auto_dis_dim] expense_emb, _ self.autodis_expense(expense) # [batch_size, auto_dis_dim] # 3. 處理其他普通稠密特征 other_dense_emb self.dense_fc(other_dense_features) # [batch_size, embedding_dim] # 4. 拼接所有特征向量 # 注意需要確保auto_dis_dim和embedding_dim一致或者通過一個(gè)線性層統(tǒng)一維度。 # 這里假設(shè)我們?cè)O(shè)置 auto_dis_dim embedding_dim concat_emb torch.cat([user_emb, item_emb, age_emb, expense_emb, other_dense_emb], dim1) # 5. 通過預(yù)測(cè)層得到點(diǎn)擊概率 click_prob self.predictor(concat_emb).squeeze(-1) # [batch_size] return click_prob3.3 訓(xùn)練與數(shù)據(jù)準(zhǔn)備在訓(xùn)練時(shí)數(shù)據(jù)的預(yù)處理需要特別注意連續(xù)特征。import numpy as np from torch.utils.data import Dataset, DataLoader # 假設(shè)我們的原始數(shù)據(jù) # user_id, item_id, age, expense, other_feat1, other_feat2, label # 其中 age, expense 是原始連續(xù)值 class CTRDataset(Dataset): def __init__(self, data_array): self.data data_array def __len__(self): return len(self.data) def __getitem__(self, idx): sample self.data[idx] # 假設(shè)數(shù)據(jù)列順序?yàn)樯鲜?user_id int(sample[0]) item_id int(sample[1]) age float(sample[2]) expense float(sample[3]) other_dense np.array([sample[4], sample[5]], dtypenp.float32) label int(sample[6]) return { user_id: user_id, item_id: item_id, age: age, expense: expense, other_dense: other_dense, label: label } # 關(guān)鍵步驟連續(xù)特征歸一化 # AutoDis的MLP輸入是原始值但數(shù)值范圍差異過大會(huì)影響訓(xùn)練穩(wěn)定性。 # 建議對(duì) age 和 expense 進(jìn)行標(biāo)準(zhǔn)化或歸一化。 def normalize_features(data): ages data[:, 2].astype(np.float32) expenses data[:, 3].astype(np.float32) age_mean, age_std ages.mean(), ages.std() expense_mean, expense_std expenses.mean(), expenses.std() # 標(biāo)準(zhǔn)化: (x - mean) / std data[:, 2] (ages - age_mean) / (age_std 1e-8) data[:, 3] (expenses - expense_mean) / (expense_std 1e-8) return data, (age_mean, age_std, expense_mean, expense_std) # 加載和預(yù)處理數(shù)據(jù) raw_data np.loadtxt(your_data.csv, delimiter,) # 示例 normalized_data, norm_stats normalize_features(raw_data) dataset CTRDataset(normalized_data) dataloader DataLoader(dataset, batch_size256, shuffleTrue) # 初始化模型、損失函數(shù)、優(yōu)化器 model CTRModelWithAutoDis(num_users10000, num_items5000, embedding_dim32, auto_dis_dim32, # 設(shè)置為和embedding_dim相同 auto_dis_h10) criterion nn.BCELoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) # 訓(xùn)練循環(huán) for epoch in range(10): total_loss 0 for batch in dataloader: user_id batch[user_id] item_id batch[item_id] age batch[age] expense batch[expense] other_dense batch[other_dense] label batch[label].float() optimizer.zero_grad() pred model(user_id, item_id, age, expense, other_dense) loss criterion(pred, label) loss.backward() optimizer.step() total_loss loss.item() print(fEpoch {epoch}, Avg Loss: {total_loss/len(dataloader):.4f})提示在實(shí)際工業(yè)場(chǎng)景中age和expense的歸一化參數(shù)均值和標(biāo)準(zhǔn)差需要在訓(xùn)練集上計(jì)算并保存下來用于對(duì)驗(yàn)證集、測(cè)試集以及線上實(shí)時(shí)請(qǐng)求的數(shù)據(jù)進(jìn)行同樣的變換保證數(shù)據(jù)分布的一致性。4. 實(shí)戰(zhàn)中的調(diào)優(yōu)策略與避坑指南把AutoDis的代碼跑通只是第一步。要讓它在你的業(yè)務(wù)數(shù)據(jù)上真正發(fā)揮出超越硬分桶的效果還需要一些實(shí)戰(zhàn)經(jīng)驗(yàn)和技巧。下面是我在幾個(gè)真實(shí)項(xiàng)目中應(yīng)用AutoDis后總結(jié)出的關(guān)鍵點(diǎn)。4.1 元嵌入數(shù)量H與維度d的選擇Hnum_meta_embeddings這個(gè)參數(shù)不再像分桶數(shù)那樣敏感。論文和實(shí)驗(yàn)表明H在10到20之間通常就能取得很好的效果。設(shè)置得太小如5可能限制模型的表達(dá)能力設(shè)置得太大如50雖然不會(huì)像硬分桶那樣直接導(dǎo)致過擬合但會(huì)增加相關(guān)性網(wǎng)絡(luò)的學(xué)習(xí)負(fù)擔(dān)可能讓權(quán)重分布變得過于平均化失去區(qū)分度。建議從H10開始作為一個(gè)穩(wěn)定的默認(rèn)值。如果你的特征非常復(fù)雜可以嘗試增加到15或20并通過驗(yàn)證集AUC/Bias等指標(biāo)觀察變化。dmeta_embedding_dim這個(gè)維度決定了最終連續(xù)特征Embedding的表達(dá)能力。它應(yīng)該與你模型中其他稀疏特征的Embedding維度對(duì)齊或相當(dāng)。例如你的user_idEmbedding是32維那么AutoDis的輸出也設(shè)為32維是合理的。如果維度不匹配可以在拼接所有特征后通過一個(gè)線性投影層統(tǒng)一維度。一個(gè)經(jīng)驗(yàn)法則是d的取值可以與你的主要稀疏特征的Embedding維度相同。4.2 相關(guān)性網(wǎng)絡(luò)的結(jié)構(gòu)與溫度系數(shù)網(wǎng)絡(luò)結(jié)構(gòu)論文中使用了一個(gè)簡(jiǎn)單的兩層MLP。在實(shí)踐中這個(gè)網(wǎng)絡(luò)不宜過于復(fù)雜。一個(gè)包含1到2個(gè)隱藏層、激活函數(shù)為ReLU的MLP已經(jīng)足夠。過于復(fù)雜的網(wǎng)絡(luò)可能會(huì)讓模型過度關(guān)注如何從單個(gè)數(shù)值x計(jì)算權(quán)重而忽略了元嵌入本身的學(xué)習(xí)甚至可能引入過擬合。保持簡(jiǎn)潔有效是關(guān)鍵。可以加入Dropout如0.1-0.3來增強(qiáng)泛化能力。溫度系數(shù)Temperature這是控制權(quán)重分布“尖銳”或“平滑”的重要超參數(shù)。在softmax中溫度T越低logits/T輸出的概率分布越尖銳接近one-hot溫度越高分布越平滑接近均勻分布。如果溫度太低權(quán)重會(huì)接近one-hotAutoDis就退化成了另一種形式的“硬分配”雖然分配是可學(xué)習(xí)的可能失去軟聚合的優(yōu)勢(shì)。如果溫度太高權(quán)重趨于均勻所有元嵌入貢獻(xiàn)幾乎相同最終Embedding會(huì)趨近于所有元嵌入的均值丟失了輸入x的特異性信息。建議從T1.0標(biāo)準(zhǔn)softmax開始嘗試。如果你發(fā)現(xiàn)模型學(xué)習(xí)緩慢或效果不佳可以嘗試稍微調(diào)高溫度如1.5讓訓(xùn)練初期更平滑或者調(diào)低溫度如0.7讓模型做出更“果斷”的權(quán)重分配。這是一個(gè)值得微調(diào)的超參數(shù)。4.3 連續(xù)特征的預(yù)處理標(biāo)準(zhǔn)化與非線性變換AutoDis的輸入是原始連續(xù)值。數(shù)據(jù)的尺度直接影響相關(guān)性網(wǎng)絡(luò)MLP的學(xué)習(xí)。標(biāo)準(zhǔn)化/歸一化是必須的像“消費(fèi)金額”這種可能從0到數(shù)萬的特征如果不做處理巨大的數(shù)值范圍會(huì)導(dǎo)致MLP的梯度不穩(wěn)定。務(wù)必對(duì)每個(gè)連續(xù)特征進(jìn)行標(biāo)準(zhǔn)化減均值除方差或歸一化縮放到[0,1]或[-1,1]區(qū)間。這能大幅提升訓(xùn)練速度和模型穩(wěn)定性。考慮非線性變換對(duì)于一些具有特定分布的特征如冪律分布直接對(duì)原始值x建模可能效率不高。可以嘗試先對(duì)x進(jìn)行非線性變換如log(1x)將大范圍的值壓縮到一個(gè)較小的區(qū)間再輸入給AutoDis。這相當(dāng)于給了模型一個(gè)更強(qiáng)的先驗(yàn)有時(shí)能加速收斂。這是一個(gè)特征工程的技巧可以與AutoDis結(jié)合使用。4.4 與模型其他部分的協(xié)同AutoDis生成的Embedding最終要和其他特征的Embedding拼接在一起送入后續(xù)的深度網(wǎng)絡(luò)。這里有幾個(gè)細(xì)節(jié)維度對(duì)齊確保AutoDis的輸出維度d與其他Embedding維度一致方便拼接。如果不一致可以添加一個(gè)nn.Linear層進(jìn)行投影。梯度流AutoDis的整個(gè)通路都是可微的梯度會(huì)同時(shí)更新元嵌入ME和相關(guān)性網(wǎng)絡(luò)MLP的參數(shù)。要關(guān)注這兩部分參數(shù)的學(xué)習(xí)率是否合適。通常使用統(tǒng)一的優(yōu)化器如Adam即可它們會(huì)自動(dòng)適應(yīng)。可視化分析在訓(xùn)練后期可以取出autodis_age和autodis_expense的權(quán)重w對(duì)一批樣本進(jìn)行統(tǒng)計(jì)分析。例如畫出不同年齡x對(duì)應(yīng)的權(quán)重分布H個(gè)權(quán)重隨x變化的曲線。這能幫你直觀理解模型學(xué)到了什么樣的“軟分桶”模式也是一種模型可解釋性的體現(xiàn)。4.5 可能遇到的“坑”與解決方案問題訓(xùn)練初期不穩(wěn)定loss震蕩大。排查首先檢查連續(xù)特征是否做了標(biāo)準(zhǔn)化。其次檢查元嵌入ME的初始化。代碼中使用的是torch.randn * 0.02這是一個(gè)較小的隨機(jī)初始化。如果問題依舊可以嘗試使用Xavier或Kaiming初始化。解決嘗試調(diào)高softmax的溫度系數(shù)T如設(shè)為2.0讓初始權(quán)重分布更均勻降低梯度方差。也可以在第一個(gè)訓(xùn)練周期使用較大的T然后逐漸退火到1.0。問題模型效果提升不明顯甚至略低于精心調(diào)參的硬分桶。排查AutoDis的優(yōu)勢(shì)在于自動(dòng)化和對(duì)連續(xù)性的保持。如果你的硬分桶是業(yè)務(wù)專家經(jīng)過大量實(shí)驗(yàn)得出的“黃金分桶”那么它本身已經(jīng)編碼了很強(qiáng)的先驗(yàn)知識(shí)。AutoDis需要從數(shù)據(jù)中重新學(xué)習(xí)這個(gè)結(jié)構(gòu)。解決給模型更多的時(shí)間和數(shù)據(jù)。AutoDis的潛力在于其靈活性可能需要在更大的數(shù)據(jù)集上訓(xùn)練更長(zhǎng)時(shí)間才能超越強(qiáng)先驗(yàn)的硬分桶。也可以嘗試用硬分桶的邊界信息來初始化相關(guān)性網(wǎng)絡(luò)例如讓MLP初始輸出在對(duì)應(yīng)桶的權(quán)重更高進(jìn)行“熱啟動(dòng)”。問題線上推理延遲增加。分析相比硬分桶一次查表AutoDis需要做一次小型MLP的前向計(jì)算幾層全連接和一次加權(quán)求和。這會(huì)增加一些計(jì)算開銷。優(yōu)化這個(gè)MLP非常小輸入1維輸出H維H通常20其計(jì)算開銷在現(xiàn)代CPU/GPU上幾乎可以忽略不計(jì)尤其是在批量推理時(shí)。如果確實(shí)成為瓶頸可以考慮將MLP的計(jì)算合并或查找表化但絕大多數(shù)場(chǎng)景下無需擔(dān)心。5. 效果對(duì)比與業(yè)務(wù)場(chǎng)景適配性分析為了更直觀地感受AutoDis的價(jià)值我們可以在一個(gè)公開數(shù)據(jù)集如Criteo Display Ads上設(shè)計(jì)一個(gè)對(duì)比實(shí)驗(yàn)。我們構(gòu)建三個(gè)結(jié)構(gòu)相同的DNN模型唯一區(qū)別在于處理連續(xù)特征的方式模型A基準(zhǔn)使用等頻分桶比如100個(gè)桶然后接Embedding層。模型B改進(jìn)使用對(duì)數(shù)變換后等頻分桶。模型CAutoDis使用AutoDis層H10,d32輸入為標(biāo)準(zhǔn)化后的連續(xù)值。在相同的訓(xùn)練集、驗(yàn)證集劃分下使用相同的優(yōu)化器、學(xué)習(xí)率和迭代輪數(shù)進(jìn)行訓(xùn)練。我們關(guān)注兩個(gè)核心指標(biāo)驗(yàn)證集AUC衡量排序能力和模型收斂速度達(dá)到穩(wěn)定AUC所需的epoch數(shù)。在我的復(fù)現(xiàn)實(shí)驗(yàn)中通常觀察到以下模式初期模型B帶手工變換的硬分桶可能因?yàn)橄闰?yàn)知識(shí)強(qiáng)而領(lǐng)先。中期模型CAutoDis開始快速追趕因?yàn)樗摹败泴W(xué)習(xí)”機(jī)制能更精細(xì)地捕捉特征信息。后期模型C的AUC往往會(huì)持平或略微超越模型B0.5%到2%的AUC提升是常見的并且收斂曲線更平滑穩(wěn)定。模型A簡(jiǎn)單分桶通常表現(xiàn)最差。業(yè)務(wù)場(chǎng)景適配性分析AutoDis并非銀彈它在以下場(chǎng)景中優(yōu)勢(shì)最為明顯特征價(jià)值密度高需要精細(xì)建模如金融風(fēng)控中的用戶收入、信貸評(píng)分廣告系統(tǒng)中的實(shí)時(shí)出價(jià)bid內(nèi)容推薦中的視頻完播率。這些特征的微小差異可能帶來業(yè)務(wù)指標(biāo)的顯著變化AutoDis的連續(xù)性保持能力至關(guān)重要。缺乏先驗(yàn)知識(shí)或分桶規(guī)則復(fù)雜對(duì)于新興業(yè)務(wù)或難以定義清晰閾值的新特征如某種復(fù)雜的用戶行為指數(shù)人工設(shè)計(jì)分桶規(guī)則成本高、效果差。AutoDis的“自動(dòng)學(xué)習(xí)”特性可以節(jié)省大量特征工程時(shí)間。線上特征分布動(dòng)態(tài)變化如果特征的分布隨著時(shí)間漂移如人均消費(fèi)水平逐年上漲硬分桶的邊界可能需要定期調(diào)整。AutoDis的MLP具有一定的外推和自適應(yīng)能力對(duì)分布變化的魯棒性更強(qiáng)。而在以下場(chǎng)景簡(jiǎn)單的硬分桶可能更合適特征本身具有明確的業(yè)務(wù)分段如“用戶等級(jí)”青銅、白銀、黃金這本身就是離散的無需AutoDis。極度追求線上推理效率雖然AutoDis開銷很小但在某些超低延遲1ms的極端場(chǎng)景一次查表仍比一次微型MLP計(jì)算更有優(yōu)勢(shì)。數(shù)據(jù)量非常小AutoDis相比硬分桶有更多的參數(shù)H*d MLP參數(shù)。在數(shù)據(jù)量不足時(shí)可能更容易過擬合。此時(shí)強(qiáng)先驗(yàn)的硬分桶作為正則化手段可能效果更好。總而言之AutoDis為我們處理深度學(xué)習(xí)中的連續(xù)特征提供了一個(gè)強(qiáng)大、優(yōu)雅且自動(dòng)化的新選擇。它將我們從繁瑣且不優(yōu)雅的“調(diào)桶”工作中解放出來把如何從連續(xù)值中學(xué)習(xí)有效表征這個(gè)任務(wù)交給了模型本身。在實(shí)際項(xiàng)目中我建議可以將它作為處理連續(xù)特征的默認(rèn)方案進(jìn)行嘗試并與精心優(yōu)化的硬分桶方案進(jìn)行A/B測(cè)試讓數(shù)據(jù)來決定最終的選擇。它的出現(xiàn)無疑是特征工程邁向自動(dòng)化、智能化方向上的堅(jiān)實(shí)一步。