網站首頁 編程語言 正文
NCL:Improving Graph Collaborative Filtering with Neighborhood-enriched Contrastive Learning,代碼解讀
作者:只想做個咸魚 更新時間: 2022-09-22 編程語言一、前言
1、背景
(1)用戶-項目交互數據通常是稀疏或嘈雜的,并且它可能無法學習可靠的表示,因為基于圖的方法可能更容易受到數據稀疏性的影響
(2)現有的基于 GNN 的 CF 方法依賴于顯式交互鏈接來學習節點表示,而不能顯式利用高階關系或約束(例如,用戶或項目相似性)來豐富圖信息,盡管最近的幾項研究利用對比學習來緩解交互數據的稀疏性,但它們通過隨機抽樣節點或損壞子圖來構建對比對,缺乏構建針對推薦任務更有意義的對比學習任務的思考。
2、做出的貢獻
提出NCL方法,主要從兩方面考慮對比關系,
(1)結構鄰居?: 通過高階路徑在結構上連接的節點
考慮圖結構上的用戶-用戶鄰居,商品-商品鄰居的對比關系
(2)語義鄰居?: 語義上相似的鄰居,在圖上可能不直接相鄰。
從節點表征出發,聚類后,節點與聚類中心構成對比關系
二、模型構建
1、圖協同過濾
這里其實就是lightGCN的傳播機制,簡單過一下:
GCN的消息傳遞
將每層的輸出組合起來,形成結點的最終表示
?然后就是預測,和BPR的損失函數
?這一部分是基礎,如果不熟悉的話可以回看往期的lightGCN介紹
2、結構鄰居的對比學習
提出將每個用戶(或項目)與他/她的結構鄰居進行對比,這些鄰居的表示通過GNN的層傳播進行聚合。
?交互圖 G 是一個二分圖,基于 GNN 的模型在圖上的偶數次信息傳播自然地聚合了同構結構鄰居的信息,就可以從GNN模型的偶數層(如2,4,6)輸出中得到同類鄰居的表示,我們將用戶自身的嵌入和偶數層GNN的相應輸出的嵌入視為正對。基于InfoNCE[20],我們提出了結構對比學習目標來最小化它們之間的距離:
?其中?為GNN中?層的歸一化輸出,?為偶數。?是softmax的溫度超參數,同理。item的一樣
?完整的結構對比目標函數是上述兩個損失的加權之和:
?其中?是一個超參數,以平衡結構對比學習中兩個損失的權重。
?3、語義鄰居的對比學習
語義鄰居是指圖上無法到達但具有相似特征(商品節點)或偏好(用戶節點)的節點。這部分通過聚類,將相似embedding對應的節點劃分的相同的簇,用簇中心代表這個簇,這個中心稱為原型。由于該過程無法進行端到端優化,使用 EM 算法學習提出的原型對比目標。聚類中GNN模型的目標是最大化下式(用戶相關),簡單理解就是讓用戶embedding劃分到某個簇,其中θ為可學習參數,R為交互矩陣,c是用戶u的潛在原型。同理也可以得到商品相關的目標式。
?提出的原型對比學習目標基于InfoNCE來最小化以下函數:
?最終的原型對比目標是用戶目標和項目目標的加權和:
?4、優化器
將提出的兩個對比學習損失作為補充,并利用多任務學習策略來聯合訓練傳統的排序損失和提出的對比損失,公式如下,
?實驗效果:
?三、pytoch代碼實現
1、GNN傳播部分
本質就是lightGCN
def forward(self):
ego_embeddings = torch.cat([self.embedding_dict['user_emb'], self.embedding_dict['item_emb']], 0)
all_embeddings = [ego_embeddings]
for k in range(self.layers):
ego_embeddings = torch.sparse.mm(self.sparse_norm_adj, ego_embeddings)
all_embeddings += [ego_embeddings]
lgcn_all_embeddings = torch.stack(all_embeddings, dim=1)
lgcn_all_embeddings = torch.mean(lgcn_all_embeddings, dim=1)
user_all_embeddings = lgcn_all_embeddings[:self.data.user_num]
item_all_embeddings = lgcn_all_embeddings[self.data.user_num:]
return user_all_embeddings, item_all_embeddings, all_embeddings
輸出user_embedding、item_embedding、all_embedding (這個是存儲每層聚合的嵌入)
所對應的是BPR_loss,如下:
rec_loss = bpr_loss(user_emb, pos_item_emb, neg_item_emb)
2、結構鄰居的對比學習
initial_emb = emb_list[0] #初始embedding
context_emb = emb_list[self.hyper_layers*2] #對比偶數層
ssl_loss = self.ssl_layer_loss(context_emb,initial_emb,user_idx,pos_idx) #loss
看一下loss
def ssl_layer_loss(self, context_emb, initial_emb, user, item):
context_user_emb_all, context_item_emb_all = torch.split(context_emb, [self.data.user_num, self.data.item_num]) #拆分偶數層的嵌入 U+I
initial_user_emb_all, initial_item_emb_all = torch.split(initial_emb, [self.data.user_num, self.data.item_num]) #拆分初始的嵌入 U+I
context_user_emb = context_user_emb_all[user] #獲取當前批次的嵌入
initial_user_emb = initial_user_emb_all[user]
# 對輸入數據進行標準化使得輸入數據滿足正態分布
norm_user_emb1 = F.normalize(context_user_emb) #當前偶數層批次
norm_user_emb2 = F.normalize(initial_user_emb) #當前初始化批次
norm_all_user_emb = F.normalize(initial_user_emb_all)# 全部用戶
pos_score_user = torch.mul(norm_user_emb1, norm_user_emb2).sum(dim=1) # Zk * z0
ttl_score_user = torch.matmul(norm_user_emb1, norm_all_user_emb.transpose(0, 1))
pos_score_user = torch.exp(pos_score_user / self.ssl_temp) #分子
ttl_score_user = torch.exp(ttl_score_user / self.ssl_temp).sum(dim=1)#分母
ssl_loss_user = -torch.log(pos_score_user / ttl_score_user).sum()
#item同理
context_item_emb = context_item_emb_all[item]
initial_item_emb = initial_item_emb_all[item]
norm_item_emb1 = F.normalize(context_item_emb)
norm_item_emb2 = F.normalize(initial_item_emb)
norm_all_item_emb = F.normalize(initial_item_emb_all)
pos_score_item = torch.mul(norm_item_emb1, norm_item_emb2).sum(dim=1)
ttl_score_item = torch.matmul(norm_item_emb1, norm_all_item_emb.transpose(0, 1))
pos_score_item = torch.exp(pos_score_item / self.ssl_temp)
ttl_score_item = torch.exp(ttl_score_item / self.ssl_temp).sum(dim=1)
ssl_loss_item = -torch.log(pos_score_item / ttl_score_item).sum()
ssl_loss = self.ssl_reg * (ssl_loss_user + self.alpha * ssl_loss_item)
return ssl_loss
3、語義鄰居的對比學習
proto_loss = self.ProtoNCE_loss(initial_emb, user_idx, pos_idx)
def ProtoNCE_loss(self, initial_emb, user_idx, item_idx):
user_emb, item_emb = torch.split(initial_emb, [self.data.user_num, self.data.item_num])#拆分初始的嵌入 U+I
user2cluster = self.user_2cluster[user_idx]
user2centroids = self.user_centroids[user2cluster]
proto_nce_loss_user = InfoNCE(user_emb[user_idx],user2centroids,self.ssl_temp) * self.batch_size
item2cluster = self.item_2cluster[item_idx]
item2centroids = self.item_centroids[item2cluster]
proto_nce_loss_item = InfoNCE(item_emb[item_idx],item2centroids,self.ssl_temp) * self.batch_size
proto_nce_loss = self.proto_reg * (proto_nce_loss_user + proto_nce_loss_item)
return proto_nce_loss
總結:
在這項工作中,提出了一種新的對比學習范式,稱為鄰域豐富的對比學習(NCL),以明確地將潛在的節點相關性捕獲到對比學習中,用于圖形協同過濾。分別從圖結構和語義空間兩個方面考慮用戶(或項目)的鄰居。
首先,為了利用交互圖上的結構鄰居,開發了一個新的結構對比目標,該目標可以與基于GNN的協同過濾方法相結合。
其次,為了利用語義鄰域,通過對嵌入內容進行聚類,并將語義鄰域合并到原型對比目標中,從而獲得用戶/項目的原型。對五個公共數據集的大量實驗證明了所提出的NCL的有效性。
作為未來的工作,將把我們的框架擴展到其他推薦任務,例如順序推薦。此外,我們還將考慮制定一個更統一的方案,以利用和利用不同種類的鄰居。
原文鏈接:https://blog.csdn.net/zhao254014/article/details/126966039
相關推薦
- 2022-05-16 解析Sentry?Relay?二次開發調試_python
- 2024-03-13 微信小程序登錄接口 偶發性 解密錯誤
- 2022-10-12 docker配置阿里云鏡像倉庫的實現_docker
- 2022-02-10 Error: Cannot find module ‘webpack/lib/RuleSet‘ 解決
- 2022-11-22 Golang自旋鎖的相關介紹_Golang
- 2022-06-12 Python利用subplots_adjust方法解決圖表與畫布的間距問題_python
- 2022-03-06 C#中List用法介紹詳解_C#教程
- 2022-12-23 Android?Activity被回收的情況分析_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支