在当今信息爆炸的时代,个性化推荐系统在我们的日常生活中扮演着越来越重要的角色。然而,随着个人数据的广泛收集和利用,隐私保护成为了一个不可忽视的挑战。为了平衡推荐系统的效用与用户隐私的保护,一款轻量级的隐私保护推荐系统应运而生。本文将深入探讨这样一种系统的设计理念、关键技术以及其在实际应用中的潜力和优势。通过探索如何在保证个性化推荐效果的同时,有效保护用户隐私,我们将揭示出一种新兴的技术趋势,为未来智能化应用的发展开辟新的可能性。
本文所涉及所有资源均在传知代码平台可获取
目录
概述
项目设计
核心代码
写在最后
概述
本文的主要内容是介绍了一种名为LightFR的轻量级联邦推荐系统,该系统采用隐私保护的矩阵分解技术。文章首先回顾了矩阵分解、学习哈希和联邦推荐系统等相关领域的研究,然后详细介绍了LightFR的框架和算法,并从存储/通信效率、推荐效率和隐私保护等多个方面论证了其优越性。接下来,文章通过实验验证了LightFR的有效性和效率,并讨论了其对用户隐私的保护能力,主要创新点如下所示:
1)提出了一种轻量级、隐私保护的联邦推荐系统(FRS),名为LightFR,以解决现有工作中的效率和隐私问题。
2)通过学习哈希技术获得用户和项目的二进制表示,以有效解决联邦设置中的离散优化问题。
3)设计了一种高效的联邦离散算法,以在服务器和客户端之间嵌入用户偏好,同时减少资源消耗和保护隐私。
4)解释了为什么现有的方法没有考虑效率和隐私问题,以及它们在实际FRS中的主要挑战。
解决的主要问题:
现有问题:
1)现有的联邦推荐系统(FRS)在资源效率和隐私保护方面存在挑战。
2)高成本的资源消耗和通信开销限制了现有方法在大规模推荐场景中的应用。
3)提高用户隐私保护的能力对于现实世界的FRS至关重要,但现有方法在这方面的考虑不足。
解决问题:
1)开发一种轻量级且隐私保护的联邦推荐系统(FRS),以降低资源成本并提高隐私保护能力。
2)通过学习哈希技术获得用户和项目的二进制表示,从而有效解决效率和隐私问题。
3)设计一种在服务器和客户端之间高效的联邦离散算法,以嵌入用户偏好到离散汉明空间,同时降低服务器和客户端的资源利用,保护用户隐私。
论文提出了一种名为LightFR的轻量级联邦推荐方法,它通过矩阵分解和隐私保护的学习哈希技术实现轻量级、高效且安全的推荐。
项目设计
实验设计包括以下几个方面:
1)数据集:使用四个不同规模的公开数据集(MovieLens-1M、Filmtrust、Douban-Movie 和 Ciao)进行实验分析,以全面反映模型性能。
2)评估指标:使用两个常用的评估指标,即 Hit Ratio(HR)和 Normalized Discounted Cumulative Gain(NDCG),以评估模型性能和验证其有效性。
3)实验方法:对比中心化经典矩阵分解模型(如PMF、SVD++和DDL)和联邦矩阵分解基线(如FederatedMF)与提出的 LightFR 模型。分析不同超参数(如二进制编码长度 f、权衡参数 λ 和选定客户比例 p)对性能的影响。
本文的最核心创新点包括以下几点:
1)提出了一种轻量级的联邦推荐系统(LightFR),它通过学习哈希技术获得用户和项目的二进制表示,从而有效解决资源效率和隐私保护问题。
2)设计了一种高效的联邦离散算法,用于在服务器和客户端之间进行训练离散参数,实现了在保护隐私的方式下提高资源效率。
3)从理论角度证明了LightFR在存储/通信效率、推理效率和隐私保护方面的优越性。
4)通过大量实验证明,LightFR在推荐准确性、资源节约和数据隐私方面明显优于现有的联邦推荐方法。
核心代码
下面这个 Client 类体现了联邦学习在推荐系统中的应用,其中每个客户端独立地更新其模型(哈希表示),并可以在本地进行模型性能评估。整个过程旨在优化用户的哈希表示,使其能够更好地捕捉用户的偏好和行为模式,同时在联邦学习的框架下保持用户数据的隐私性:
import numpy as np
from Metrics import Metrics
class Client:
def __init__(self, configs):
self.bu = None #客户端的哈希表示
self.D = None # 与项目相关的全局参数
self.data_u = None #特定客户端的用户数据
self.data_bin_u = None #特定客户端的用户数据的二进制表示
self.data_len_u = None #特定客户端的用户数据的长度
self.configs = configs
def client_update(self, client, master_flag):
'''
client process, could be implemented in parallel
:param master_flag:
:param bu:
:param D:
:param data_u:
:param data_bin_u:
:param l:
:return:
'''
while True:
flag = 0
for k in range(self.configs.code_len):
dk = client.D[:, k]
buk_hat = np.sum(
( client.data_u - np.dot(client.D, client.bu.T)) * dk * client.data_bin_u) + 2 * self.configs.lambdaa * client.data_len_u * client.bu[k]
buk_new = np.sign(self.K(buk_hat, client.bu[k]))
if (client.bu[k] != buk_new):
flag = 1
client.bu[k] = buk_new
if (flag == 0):
break
master_flag = 1
return client.bu, master_flag
def get_inter_params(self, i, k):
di = self.D[i, :]
grads = (self.data_u[i] - np.dot(self.bu, di.T)) * self.bu[k] * self.data_bin_u[i]
grads_len = self.data_bin_u[i]
return grads, grads_len
def K(self, x, y):
return x if x != 0 else y
def calculate_loss(self):
local_loss = np.sum((self.data_u - np.dot(self.D, self.bu)) ** 2 * self.data_bin_u)
return local_loss
def evaluate_local(self, items, val_data):
configs = {'top_k': 10, 'num_negative_test': 49, }
metric = Metrics(configs)
bus = self.bu
dis = self.D[items]
rating_pred = np.multiply(bus, dis)
preds = np.sum(rating_pred, axis=1)
val_data['pred'] = preds.tolist()
hr = metric.get_hit_ratio(val_data)
ndcg = metric.get_ndcg(val_data)
return hr, ndcg
下面 Base 类提供了一个推荐系统基本框架,包括数据处理、模型初始化和评估。这个类能够处理用户和项目的交互数据,生成评分矩阵,并对推荐模型的性能进行评估。通过这种方式,它为构建更复杂的推荐系统模型提供了基础:
# -*- coding: utf-8 -*-
import numpy as np
import scipy.linalg as la
from collections import defaultdict
from math import log
import pandas as pd
import torch
from DataLoader import DataLoaderCenter
from Metrics import Metrics
class Base:
def __init__(self):
self.user = {}
self.item = {}
self.id2user = {}
self.id2item = {}
self.u_i_r = defaultdict(dict)
self.i_u_r = defaultdict(dict)
self.minVal = 0.5
self.maxVal = 4
self.dataset_name = 'filmtrust'
self.federated_train_data_path = 'data/' + self.dataset_name + '/' + self.dataset_name + '_train.csv'
self.federated_valid_data_path = 'data/' + self.dataset_name + '/' + self.dataset_name + '_val.csv'
self.federated_test_data_path = 'data/' + self.dataset_name + '/' + self.dataset_name + '_test.csv'
pass
def init_model(self):
self.generate_vocabulary()
self.rating_matrix, self.rating_matrix_bin, self.globalmean = self.get_rating_matrix()
self.B = np.sign(np.array(np.random.randn(len(self.user), self.configs.code_len) / (self.configs.code_len ** 0.5)))
self.D = np.sign(np.array(np.random.randn(len(self.item), self.configs.code_len) / (self.configs.code_len ** 0.5)))
self.loss, self.last_delta_loss = 0.0, 0.0
def trainSet(self):
with open(self.federated_train_data_path, 'r') as f:
for index, line in enumerate(f):
if index != 0: # 去除headers
u, i, r = line.strip('\r\n').split(',')
r = 2 * self.configs.code_len * (float(r)) - self.configs.code_len
yield (int(u), int(i), float(r))
def containUser(self, user_id):
if user_id in self.user:
return True
else:
return False
def containItem(self, item_id):
if item_id in self.item:
return True
else:
return False
def valid_test_Set(self, path):
with open(path, 'r') as f:
for index, line in enumerate(f):
if index != 0: # 去除headers
u, i, r = line.strip('\r\n').split(',')
# r = 2 * self.code_len * (float(int(r) - self.minVal) / (self.maxVal - self.minVal) + 0.01) - self.code_len
yield (int(u), int(i), float(r))
def read_federated_valid_dataset(self, path):
data_val = pd.read_csv(path)
return data_val
def generate_vocabulary(self):
for index, line in enumerate(self.trainSet()):
user_id, item_id, rating = line
self.u_i_r[user_id][item_id] = rating
self.i_u_r[item_id][user_id] = rating
if user_id not in self.user:
self.user[user_id] = len(self.user)
self.id2user[self.user[user_id]] = user_id
if item_id not in self.item:
self.item[item_id] = len(self.item)
self.id2item[self.item[item_id]] = item_id
for index, line in enumerate(self.valid_test_Set(self.federated_valid_data_path)):
user_id, item_id, rating = line
self.u_i_r[user_id][item_id] = rating
self.i_u_r[item_id][user_id] = rating
if user_id not in self.user:
self.user[user_id] = len(self.user)
self.id2user[self.user[user_id]] = user_id
if item_id not in self.item:
self.item[item_id] = len(self.item)
self.id2item[self.item[item_id]] = item_id
for index, line in enumerate(self.valid_test_Set(self.federated_test_data_path)):
user_id, item_id, rating = line
self.u_i_r[user_id][item_id] = rating
self.i_u_r[item_id][user_id] = rating
if user_id not in self.user:
self.user[user_id] = len(self.user)
self.id2user[self.user[user_id]] = user_id
if item_id not in self.item:
self.item[item_id] = len(self.item)
self.id2item[self.item[item_id]] = item_id
def get_rating_matrix(self):
rating_matrix = np.zeros((len(self.user), len(self.item))) # (943, 1596)
globalmean = 0.0
lens = 0
for index, line in enumerate(self.trainSet()):
lens += 1
user_id, item_id, rating = line
globalmean += rating
rating_matrix[self.user[user_id]][self.item[item_id]] = int(rating)
rating_matrix_bin = (rating_matrix > 0).astype('int')
globalmean = globalmean / (lens)
return rating_matrix, rating_matrix_bin, globalmean
def K(self, x, y):
return x if x != 0 else y
def valid_test_model(self, path):
pre_true_dict = defaultdict(list)
for index, line in enumerate(self.valid_test_Set(path)):
user_id, item_id, rating = line
if (self.containUser(user_id) and self.containItem(item_id)):
bu = self.B[self.user[user_id], :]
di = self.D[self.item[item_id], :]
pre = np.dot(bu, di)
elif (self.containUser(user_id) and not self.containItem(item_id)):
pre = sum(self.u_i_r[user_id].values()) / float(len(self.u_i_r[user_id]))
elif (not self.containUser(user_id) and self.containItem(item_id)):
pre = sum(self.i_u_r[item_id].values()) / float(len(self.i_u_r[item_id]))
else:
pre = self.globalmean
pre_true_dict[user_id].append([pre, rating])
metrics = Metrics()
ndcg_10 = metrics.calDCG_k(pre_true_dict, 10)
return ndcg_10
写在最后
本文详细探讨了一款轻量级的隐私保护推荐系统的设计与实施。通过介绍其核心理念和关键技术,我们深入理解了如何在个性化推荐和用户隐私保护之间取得平衡。这种系统通过采用匿名化数据处理、去标识化技术和分布式计算等手段,有效降低了数据泄露的风险,同时保证了推荐的个性化和准确性。随着隐私问题日益成为社会关注的焦点,这样的技术创新不仅提升了用户的信任和满意度,也为未来智能化应用的发展指明了方向。未来,随着技术的进一步进化和隐私法规的完善,这种轻量级的隐私保护推荐系统有望在更广泛的应用场景中发挥重要作用,推动数字化社会的可持续发展。
详细复现过程的项目源码、数据和预训练好的模型可从该文章下方附件获取。