【隐私计算篇】替换半同态使用全同态加速计算联邦机器学习算法的实证分析

news2025/1/15 8:39:11

1. 背景介绍

        联邦学习(Federated Learning,FL)是隐私计算中常见的一种技术范式,其本质是一种面向可信数据流通的分布式机器学习框架,允许多个参与方在不共享其本地数据的前提下,协同训练机器学习模型。与传统的集中式学习方法相比,联邦学习通过分布式以及加密算法等方式保护数据隐私和安全,避免了数据的集中存储与传输。

        关于联邦学习的知识,我们在之前的文章《使用GPU加速计算联邦学习XGBOOST算法》、《大模型的安全由隐私计算来保护》、《基于横纵向的混合联邦学习原理分析》、《SGB、SS-XGB算法原理》、《逻辑回归LR与广义线性模型GLM》中,或多或少都有涉及。本文主要面向联邦学习的性能提升问题,制约联邦学习的因素归根到底主要是两类:计算以及通信,而其中计算又以密文计算耗时占据整体联邦学习的大头,因此在本文中,我们将更多的关注在密文计算上的加速。

        说到密文计算的加速,通常有多种优化的方向:

        (1)软硬件加速(如提升并行度);

        (2)一次密文计算完成多个密文数据处理;

        (3)最小化密文计算(既然密文计算耗时,那采用优化算法机制等手段尽量减少密文的处理场景);

        (4)同态加密算法本身的改进,比如采用中国剩余定理来加速,参考《中国剩余定理解释以及Paillier解密加速应用》。

        (5)同态算法的选型(全同态、半同态) 

        (6)其他还有调度策略、采用其他隐私计算技术来替代同态加密等手段,就不一一列出。   

2. 全同态加密与半同态加密在联邦机器学习中的实证对比

2.1 实验设置

        本文主要关注第(5)点中提到的同态算法选型方向。我们会对比半同态加密、全同态加密的密文计算性能,在联邦逻辑回归算法中的实证结果。注意:这里联邦逻辑回归算法我们会做简化处理,不对原始机器学习算法做节点区分(比如划分成host、guest的计算逻辑),而是简单的对梯度因子(即误差项)做加密,然后密文计算梯度。实际的联邦学习算法中,基本流程类似,guest方会解密host方混淆后的梯度值,然后发回给host方进行模型权重参数的更新。

        密文的操作包括加密(误差)、密文@明文(梯度)、解密(梯度)。

        我们选择的加密算法参照对象分别为:

半同态加密:隐语的Zpaillier【1】;

几种半同态加密算法性能对比数据【1】:

全同态加密:OpenMined的TenSeal【2,3】提供的CKKS  (基于微软的SEAL)【4】。

        CKKS(全称 Cheon-Kim-Kim-Song)是2017年提出的同态加密方案。它支持浮点向量在密文空间的加减乘运算并保持同态,但是只支持有限次乘法的运算。以下是CKKS的计算流程图。先对消息(向量)进行编码,然后再加密,在密文空间进行一些运算后再解密,最后解码成运算后的消息(向量)。这里的编码指的是将复数向量映射成为多项式,是为了方便下面进一步的加密【5】。对于全同态加密算法感兴趣的话,可以参考下这篇文章的分析【6】。

2.2 实验数据及代码

        我们选用的模型是逻辑回归模型,做梯度部分做密文处理,实验数据使用的是风控数据,共有43个特征,样本量10万。

2.2.1 zpaillier(gpaillier)版本模型

        事实上,后续的性能比较采用了gpaillier(gpu版本),gpaillier与zpaillier的接口一致,略微修改就可以切换,gpaillier的性能要优于zpaillier。

        gpaillier与zpaillier的对比见【7】:

import numpy as np
import pandas as pd
import copy
from sklearn.metrics import auc, roc_curve
from heu import numpy as hnp
from heu import phe

# 初始化 Paillier 加密系统
encryption_kit = hnp.setup(phe.SchemaType.ZPaillier, 2048)
encryptor = encryption_kit.encryptor()
decryptor = encryption_kit.decryptor()
evaluator = encryption_kit.evaluator()

# 设置浮点数编码比例
scale_factor = 10**6
float_encoder = phe.FloatEncoder(phe.SchemaType.ZPaillier, scale_factor)

# 定义 Sigmoid 函数
def sigmoid(x):
    return 1. / (1 + np.exp(-x))

# 数据列名
match_column = "id"
label_column = "isDefault"
feature_file = "risk_train_x.csv"
label_file = "risk_train_y.csv"

# 加载并合并特征和标签数据集
features_df = pd.read_csv(feature_file)
labels_df = pd.read_csv(label_file)
merged_df = pd.merge(features_df, labels_df, how='left', on=match_column)
merged_df = pd.DataFrame(merged_df)

# 获取所有列名并移除匹配列和标签列
all_columns = list(merged_df.columns)
feature_columns = copy.deepcopy(all_columns)
feature_columns.remove(match_column)
feature_columns.remove(label_column)
print(f"特征列名: {feature_columns}")

# 填充缺失值(使用众数填充)
X = merged_df[feature_columns].fillna(merged_df[feature_columns].mode().iloc[0])

# 特征标准化处理
mean_values = np.mean(X, axis=0)
std_values = np.std(X, axis=0)
X_normalized = (X - mean_values) / std_values
X_normalized = X_normalized.to_numpy()

# 获取标签列
Y = merged_df[label_column].to_numpy().reshape((len(merged_df), 1))

# 划分训练集和测试集(比例为 8:2)
train_ratio = 0.8
split_index = int(len(X_normalized) * train_ratio)
X_train, X_test = X_normalized[:split_index], X_normalized[split_index:]
y_train, y_test = Y[:split_index], Y[split_index:]
print(f"训练数据大小: {X_train.shape}, {y_train.shape}, {X_test.shape}, {y_test.shape}")

# 设置逻辑回归模型超参数
num_epochs = 3
batch_size = 4000
learning_rate = 0.01

# 初始化模型权重
num_features = len(feature_columns)
weights = np.zeros((num_features, 1))

# 计算批次数
num_batches = len(y_train) // batch_size
if len(y_train) % batch_size != 0:
    num_batches += 1

# 迭代训练模型
for epoch in range(num_epochs):
    for batch in range(num_batches):
        print(f"Epoch {epoch}, Batch {batch}")
        X_batch = X_train[batch * batch_size: (batch + 1) * batch_size]
        y_batch = y_train[batch * batch_size: (batch + 1) * batch_size]
        y_pred = sigmoid(np.matmul(X_batch, weights))

        # 梯度因子加密
        grad_factor = y_pred - np.array(y_batch)
        grad_factor_encrypted = encryption_kit.array(grad_factor.T, float_encoder)
        encrypted_gradients = encryptor.encrypt(grad_factor_encrypted)

        # 密文梯度计算
        X_batch_encoded = encryption_kit.array(X_batch, float_encoder)
        encrypted_grad_sum = evaluator.matmul(encrypted_gradients, X_batch_encoded)

        # 解密并计算权重更新
        grad_sum = decryptor.decrypt(encrypted_grad_sum).to_numpy(float_encoder)
        grad_sum = grad_sum.T / scale_factor
        gradient = grad_sum / len(y_batch)
        weights -= gradient * learning_rate

# 在测试集上进行预测
y_pred_test = sigmoid(np.matmul(X_test, weights))

# 计算模型评估指标
print("模型评估指标:")
fpr, tpr, _ = roc_curve(y_test, y_pred_test)
ks_value = max(tpr - fpr)
auc_value = auc(fpr, tpr)
print(f"KS值: {ks_value}")
print(f"AUC值: {auc_value}")

2.2.2 tenseal-ckks版本模型

import numpy as np
import pandas as pd
from sklearn.metrics import auc, roc_curve
import tenseal as ts
import sys

# 设置 TenSEAL 加密上下文,指定多项式模数度数和系数位大小
context = ts.context(
    ts.SCHEME_TYPE.CKKS,
    poly_modulus_degree=8192,
    coeff_mod_bit_sizes=[60, 40, 40, 60]
)
# 生成 Galois 密钥,用于加密操作
context.generate_galois_keys()
context.global_scale = 2**40  # 设置全局加密比例


def sigmoid(x):
    return 1. / (1 + np.exp(-x))


match_column = "id"  # 匹配列名
label_column = "isDefault"  # 标签列名
feature_data_file = "risk_train_x.csv"  # 特征数据文件
label_data_file = "risk_train_y.csv"  # 标签数据文件

# 加载并合并特征与标签数据集
features_df = pd.read_csv(feature_data_file)
labels_df = pd.read_csv(label_data_file)
merged_df = pd.merge(features_df, labels_df, how='left', on=match_column)

# 获取特征列名,排除匹配列和标签列
feature_columns = [col for col in merged_df.columns if col not in [match_column, label_column]]

# 填充缺失值(使用众数),并对特征进行标准化
X = merged_df[feature_columns].fillna(merged_df.mode().iloc[0])
X = (X - X.mean()) / X.std()
X = X.to_numpy()

# 获取标签列数据
Y = merged_df[label_column].to_numpy().reshape(-1, 1)

# 将数据集按 80/20 划分为训练集和测试集
train_ratio = 0.8
train_size = int(len(X) * train_ratio)
X_train, X_test = X[:train_size], X[train_size:]  # 训练集和测试集的特征
y_train, y_test = Y[:train_size], Y[train_size:]  # 训练集和测试集的标签

# 逻辑回归的超参数配置
num_epochs = 3  # 迭代次数
batch_size = 4000  # 批量大小
learning_rate = 0.01  # 学习率

# 初始化模型权重
num_features = X_train.shape[1]  # 特征数目
weights = np.zeros((num_features, 1))  # 权重初始化为全零向量

# 计算批次数量
num_batches = int(np.ceil(len(y_train) / batch_size))

# 使用批量梯度下降训练逻辑回归模型
for epoch in range(num_epochs):
    for batch in range(num_batches):
        print(f"Epoch {epoch}, Batch {batch}")
        # 获取当前批次的训练数据
        X_batch = X_train[batch * batch_size: (batch + 1) * batch_size]
        y_batch = y_train[batch * batch_size: (batch + 1) * batch_size]
        # 预测当前批次的结果
        y_pred = sigmoid(np.matmul(X_batch, weights))

        # 计算梯度误差,并进行加密
        gradient_error = y_pred - y_batch
        encrypted_gradient = ts.ckks_vector(context, gradient_error.T.flatten().tolist())

        # 内存占用
        print("内存占用", sys.getsizeof(encrypted_gradient))

        # 加密矩阵乘法,计算加密后的梯度
        gradient_sum_encrypted = encrypted_gradient.matmul(X_batch.tolist())

        # 解密梯度
        gradient_sum = np.array(gradient_sum_encrypted.decrypt()).reshape(-1, 1)

        # 更新权重,按照梯度下降规则
        weights -= learning_rate * gradient_sum / len(y_batch)

# 在测试集上进行预测
y_pred_test = sigmoid(np.matmul(X_test, weights))

# 评估模型性能,计算 AUC 和 KS 指标
fpr, tpr, _ = roc_curve(y_test, y_pred_test)
ks_stat = max(tpr - fpr)  # KS 统计量
auc_score = auc(fpr, tpr)  # AUC 值
print(f'KS: {ks_stat}') 
print(f'AUC: {auc_score}')

2.3 实验结果

        实验迭代3个epoch,batchsize设置4000。

        左边是ckks版本的耗时 407s,右边是gpaillier版本的耗时 1167s。结果显示,采用全同态ckks,在计算性能上明显优于gpaillier版本,更优于zpaillier。

3. 参考材料

【1】HEU 多种 PHE 算法选择

【2】TenSeal代码仓库

【3】TENSEAL: A LIBRARY FOR ENCRYPTED TENSOR OPERATIONS USING HOMOMORPHIC ENCRYPTION

【4】微软SEAL

【5】CKKS explained series

【6】全同态加密算法概览

【7】隐语HEU同态加密算法解读

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214951.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python | Leetcode Python题解之第479题最大回文数乘积

题目: 题解: class Solution:def largestPalindrome(self, n: int) -> int:if n 1:return 9upper 10 ** n - 1for left in range(upper, upper // 10, -1): # 枚举回文数的左半部分p, x left, leftwhile x:p p * 10 x % 10 # 翻转左半部分到其…

【C语言刷力扣】1748.唯一元素的和

题目: 法一 解题思路: 由于 nums.length 小于100,新建数组 num[101],用来遍历存放 nums[i]出现的次数。 int sumOfUnique(int* nums, int numsSize) {int result 0;int num[101] {0}; // memset(num, 0, sizof(num));for (int…

写一个菜谱网站,数据库应该怎么设计?AI回答我动手!

大部分问题使用chatglm4-9b进行回答,总体效果不错,大家可以来试试。关于如何使用ChatGLM4-9b模型,可以参考:在启智AI平台实践ChatGLM4-9B聊天机器人MindSpore-CSDN博客 设计数据库 问题 写一个菜谱网站,数据库应该怎…

mongodb-7.0.14分片副本集超详细部署

mongodb介绍: 是最常用的nosql数据库,在数据库排名中已经上升到了前六。这篇文章介绍如何搭建高可用的mongodb(分片副本)集群。 环境准备 系统系统 BC 21.10 三台服务器:192.168.123.247/248/249 安装包&#xff1a…

STM32L010F4 最小系统设计

画一个 STM32L010F4 的测试板子...... by 矜辰所致前言 最近需要用到一个新的 MCU: STM32L010F4 ,上次测试的 VL53L0X 需要移植到这个芯片上,网上一搜 STM32L010F4,都是介绍资料,没有最小系统,使用说明等。…

element plus的el-select分页

摘要&#xff1a; el-select的数据比较多的时候&#xff0c;必须要分页&#xff0c;处理方案有全部数据回来&#xff0c;或者添加搜索功能&#xff0c;但是就有个问题就是编辑的时候回显问题&#xff0c;必须要保证select的数据有对应的id与name匹配回显&#xff01; <el-fo…

Pytest基于fixture的参数化及解决乱码问题

我们知道&#xff0c;Pytest是Python技术栈下进行自动化测试的主流测试框架。支持灵活的测试发现、执行策略&#xff0c;强大的Fixture夹具和丰富的插件支持。 除了通过pytest的parametrize标签进行参数化外&#xff0c;我们通过fixture的param参数也可以比较方便地实现参数化…

Android从上帝视角来看PackageManagerService

戳蓝字“牛晓伟”关注我哦&#xff01; 用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章&#xff0c;技术文章也可以有温度。 前言 阅读该篇之前&#xff0c;建议先阅读下面的系列文章&#xff1a; Android深入理解包管理–PackageManagerService和它的“小伙伴…

SPI

Flash-W25Q64 -- 这一章的重点是重点是知道标准SPI通信&#xff0c;地址会算&#xff0c;FLASH时序要会看 目录 Flash-W25Q64 回顾 FLASH SPI简介 单片机&#xff08;32&#xff09;上的SPI W25Q64 模块之间应该怎么通信呢&#xff1f;-- 看时序图 代码编写 更改代码…

Vue Data UI——Vue 3 数据可视化组件库

文章目录 1、Vue Data UI2、核心特点2.1.Vue 3 的深度集成2.2 丰富的可视化组件2.3 灵活的定制性2.4 易于集成2.5 文件导出功能2.6 多主题支持3、如何在项目中使用 Vue Data UI?3.1 安装 Vue Data UI3.2 全局注册组件3.3 局部引入组件3.4 使用通用组件3.5 TypeScript 集成4、总…

城市交通系统优化策略:透视拥堵之困,探索流畅之道

在快速城市化的今天&#xff0c;交通拥堵已成为众多大中型城市的“城市病”&#xff0c;严重影响居民生活质量、经济运行效率及环境质量。本文旨在深度剖析城市交通拥堵的根源&#xff0c;并提出一系列行之有效的优化策略&#xff0c;旨在构建更加顺畅、高效、绿色的城市交通系…

R语言实现logistic回归曲线绘制

方式一&#xff1a;编制函数 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码快 f <- function(x){y 1/(1 exp(-x))plot(x,y)}#sigmoid函数 f(x)​ 方式二&#xff1a;Sigmoid函数代码 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码块 #y<-1/(1exp(-x)) y&…

【NOIP1997 普及组第一题】棋盘问题

题目背景 NOIP1997 普及组第一题 题目描述 设有一个NM 方格的棋盘 (1≤N≤100,1≤M≤100) 求出该棋盘中包含有多少个正方形、多少个长方形&#xff08;不包括正方形&#xff09;。 例如&#xff1a;当 N2,M3时&#xff1a; 正方形的个数有 8 个&#xff1a;即边长为 1 的正…

北斗短报文平板终端|军用三防平板|国产加固平板|防爆工业平板

在当今数字化浪潮的推动下&#xff0c;各行各业对智能终端设备的需求日益多样化与专业化&#xff0c;特别是在工业领域&#xff0c;一款集通信、定位、导航及耐用性于一身的设备显得尤为重要。北斗三代短报文工业平板电脑正是应此需求而生&#xff0c;它不仅是一款普通的平板电…

睿赛德科技正式推出RT-Thread开源 4+服务,助力企业用户发展

RT-Thread始于2006 年&#xff0c;是100%由中国开发者编写的开源嵌入式操作系统。经过10多年的发展&#xff0c;已经成为国内最流行的嵌入式操作系统&#xff0c;广泛应用于工业、 电力、轨道交通、智慧城市、智能家居、穿戴、车载、甚至航空航天等领域。 RT-Thread的成功基于对…

基金好书入门阅读笔记《基金作战笔记:从投基新手到配置高手的进阶之路》笔记3

公募基金的分类方式按投资范围分 80%以上资产投资于股票的&#xff0c;叫股票基金&#xff1b;80%以上资产投资于债券的&#xff0c;叫债券基金&#xff1b;80% 以上资产投资于其他基金的&#xff0c;叫FOF; 80%以上资产投资于货币市场的&#xff0c;叫货币基金&#xff1b;以上…

【AI绘画】Midjourney进阶:中心点构图详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;什么是构图为什么Midjourney要使用构图 &#x1f4af;中心点构图中心点构图的特点使用场景提示词书写技巧测试 &#x1f4af;小结 &#x1f4af;前言 【AI绘画】Midj…

freertos的任务管理

任务函数 任务被实现为C函数。它们唯一特别的地方是它们的原型&#xff0c;它必须返回void并接受void指针参数。以下是函数原型。 void ATaskFunction( void *pvParameters );每个任务本身都是一个小程序。它有一个入口点&#xff0c;通常会在无限循环中永远运行&#xff0c;…

MWD天气图像多分类数据集,用于图像分类-共6个类别,共60000张图像数据 ,含有模型

MWD天气图像多分类数据集&#xff0c;用于图像分类- MWD天气图像多分类数据集&#xff0c;用于图像分类-共6个类别&#xff0c;共60000张图像数据 &#xff0c;含有模型 MWD天气图像多分类数据集及模型介绍 数据集概述 名称&#xff1a;MWD天气图像多分类数据集图像数量&…

大规模多传感器滑坡检测数据集,利用landsat,哨兵2,planet,无人机图像等多种传感器采集数据共2w余副图像,mask准确标注滑坡位置

大规模多传感器滑坡检测数据集&#xff0c;利用landsat&#xff0c;哨兵2&#xff0c;planet&#xff0c;无人机图像等多种传感器采集数据共2w余副图像&#xff0c;mask准确标注滑坡位置 大规模多传感器滑坡检测数据集介绍 数据集概述 名称&#xff1a;大规模多传感器滑坡检测…