【推薦演算法】邏輯迴歸(Logistic Regression,LR)
阿新 • • 發佈:2021-06-30
邏輯迴歸(Logistic Regression,LR)在推薦系統發展歷史中佔非常重要的地位。其優勢主要體現在三個方面:
- 數學含義的支撐:LR是一個廣義線性模型(可以簡單理解為加了啟用函式的線性模型),其假設為因變數服從伯努利分佈,而CTR事件可以類比為擲偏心硬幣的問題,所以使用LR作為CTR預估模型是滿足其物理意義的;
- 可解釋性強:在LR中,每一個特徵對應一個權重,權重絕對值的大小可以作為評估該特徵重要性的指標。每一個權重都可解釋,這是任何深度模型都不具備的;
- 工程化需要:LR有易於並行化(不同特徵在不同機器上運算)、訓練開銷小(新增或刪減特徵時只需要fine-tune,而樹模型需要re-train)的特點。
掌握LR的每個細節(如模型具體的輸入輸出),是理解後續模型(如GBDT-LR、FM)的基礎。
模型輸入
LR模型對one-hot型別的輸入非常友好(為什麼?並且為什麼樹模型不適合one-hot輸入)。在pytorch中,我們可以將特徵轉化為one-hot特徵後,使用nn.Linear
構建LR,這是最直觀的解決方法。為了簡化輸入,以及充分利用對sparse input的優化(怎麼優化的?),我們使用nn.Embedding
代替。
nn.Embedding
是一個查詢表(look-up table),輸入為one-hot中為1的特徵的index。因此,我們只需要將所有特徵域拼接起來,輸入為1的特徵對應的index即可。具體拼接方法為:
- 獲取每個特徵域包含的特徵個數,根據特徵個數獲取對應offset;
class MovieLens_100K_Dataset(Dataset): def __init__(self, df): self.token_col = ["user_id", "item_id", "age", "gender", "occupation", "release_year"] # 所用特徵列 self.df = df[self.token_col] self.offset = self.df.nunique().values # 對應步驟1 self.df = self.df.values self.label = df["label"].values def __len__(self): return self.label.shape[0] def __getitem__(self, idx): return self.df[idx], self.label[idx] # 使用全量資料集df來計算每個特徵域包含的特徵個數(field_dims),不能使用split後的資料,否則訓練測試集會不一致 field_dims = MovieLens_100K_Dataset(df).offset
- 每個特徵域中的one-hot為1的index加上offset,獲得在拼接向量中one-hot為1的index;
- 每個特徵域分別送入
nn.Embedding
,對結果sum_pooling得到輸出。
class FeaturesLinear(torch.nn.Module):
def __init__(self, field_dims, output_dim=1):
super().__init__()
self.fc = torch.nn.Embedding(sum(field_dims), output_dim)
self.bias = torch.nn.Parameter(torch.zeros((output_dim,)))
self.offsets = np.array((0, *np.cumsum(field_dims)[:-1]), dtype=np.long)
torch.nn.init.xavier_uniform_(self.fc.weight.data)
def forward(self, x):
"""
:param x: Long tensor of size ``(batch_size, num_fields)``
"""
x = x + x.new_tensor(self.offsets).unsqueeze(0) # 對應步驟2
return torch.sum(self.fc(x), dim=1) + self.bias # 對應步驟3
class LogisticRegressionModel(torch.nn.Module):
def __init__(self, field_dims):
super().__init__()
self.linear = FeaturesLinear(field_dims)
def forward(self, x):
return torch.sigmoid(self.linear(x).squeeze(1))
模型效果
設定:
資料集:ml-100k
優化方法:Adam
學習率:0.003
效果:
收斂epoch:92
train logloss: 0.54183
val auc: 0.78256
test auc: 0.78876