Page 258 - 《软件学报》2026年第2期
P. 258

余欢 等: Antelope: 基于  GPU  的三方隐私保护机器学习框架                                           737


                    ● 非线性函数: 如文献 [21,23] 所指出, 文献      [14,20] 所使用的数值算法精度难以达到实际应用需求, 并且不具
                 有良好的数值稳定性, 因而我们首先设计了更好的 MSB 协议从而高效地实现比较运算, 然后针对我们                               MSB 低通
                 信的优势设计了平方根倒数、指数以及 Softmax 函数的多方计算协议, 具体内容见 第                      3.3–3.5  节.
                  3.2   线性层实现
                    由于乘法可以通过        3  次本地乘法连同一次截断操作实现, 矩阵乘法的最大计算负载也只是                      3  次本地矩阵乘
                 法. 为了减少计算开销, 我们将截断协议延迟到所有乘法与求和都计算完毕之后再执行, 这样仅需一次截断操作.
                             A, B ∈ R n×n , 我们计算:
                 这就是说, 假设

                                                                                
                                                                      n
                                                                    ∑           
                                       [[  ]]  [[  ]]  [[  ]]          [[      ]]
                                                                                
                                                                                 
                                                                       A j,q B q,k ;2 f .
                                        AB; f = C; f ↠ C j,k ; f = Truncate
                                                                                
                                                                                
                                                                     q=1
                    cuBLAS 库没有提供针对       64  位整数的矩阵乘法和卷积运算, 因此无法直接调用               cuBLAS  库完成各参与方本
                 地的线性计算. 为了利用       GPU  的并行计算能力, CryptGPU    将  64  位整数分解成为   4  个独立的   64  位浮点数, 进而直
                 接调用   cuBLAS 库中的矩阵相乘和卷积运算接口, 再将计算结果进行无损整合得到最终结果. 不过, 这种方法会带
                 来额外计算开销, 同时会显著增加存储需求. Piranha 针对线性层计算任务手动编写了                      GPU  核函数, 并仔细设计了
                 数据在   GPU  上的存储布局, 但是并没有充分发掘          GPU  的访存特性.
                    我们利用    CUDA  程序执行涉及     64  位整数的矩阵乘法计算. 为最大限度地提高计算速度, 受单精度矩阵乘法
                 (SGEMM) 启发, 我们的算法策略以减少内存访问延迟和提高计算与内存访问比为主. 具体来说, 为了降低内存访
                 问延迟, 我们将矩阵分块相乘, 每个         GPU  线程分块用于计算积矩阵中的一个分块矩阵. 此外, 读取分块矩阵时不直
                 接从  GPU  全局内存中读取, 而是先将需要计算的分块矩阵搬运到                 GPU  共享内存, 再从共享内存中读取分块矩阵
                 中的元素到寄存器空间.
                    具体的   GPU  上矩阵乘法算子实现见算法         1, 其中块内线程同步 syncthreads() 使得    b x , b y 相同的线程在执行到
                 这步时阻塞, 等待块内所有的线程都到达这步以后再继续运行后面的语句. 为了介绍方便, 算法                              1  中假设矩阵   A,
                 B  都是方阵并且阶数恰好是        2  的幂次, 很明显非该种情形的矩阵乘法通过填             0  可以在矩阵规模扩大不超过        4  倍的
                 情况下适用这种算法, 而实际实现时并不需要显式地补                  0, 直接忽略超出矩阵范围的计算就能自然地将这算法扩
                 展到一般情形而不引入额外开销.

                 算法  1. MatMul(A, B, C; (b x , b y ), (t x , t y )).
                                           m
                                                                                                    b
                                  64
                 输入: 矩阵  A, B ∈ (Z/2 Z) n×n  ( n = 2 ), 这些数据都存放在 GPU 的全局内存上. 固定的全局参数 blockSize =   2  表示
                                                                              b
                                                       .
                 GPU 上每个线程分块的行数或者列数, 这里            b ⩽ m 0 ⩽ b x , b y < 2 m−b , 0 ⩽ t x , t y < 2  是每个 GPU 线程的内置变量, 表
                 示线程所在线程分块的行列编号和在线程分块中的行列编号;
                               b x , b y , t x , t y , 相应核函数都已经在实际 GPU 的物理 SM 上运行完毕, 那么 GPU 全局内存上的矩
                 输出: 如果对每个
                 阵 C 的子矩阵将会被正确置为         A· B.
                                                               b
                 1. 申请块内共享内存 shareA 和 shareB, 并假定其布局均为        2 ×2  的二维数组
                                                                  b
                 2. 执行块内线程同步 syncthreads()
                 3. 置  t ← 0
                 4. For   j = 0,...,2 m−b  −1 do
                                                                     b
                 5.  拷贝 shareA[t x ][t y ]  ← A[b x 2 +t x ][ j2 +t y ] 和 shareB[t x ][t y ]  ← B[ j2 +t x ][b y 2 +t y ]
                                                                            b
                                         b
                                               b
                 6.  执行块内线程同步 syncthreads()
                              2 b −1
                              ∑
                 7.  计算  t ← t +  shareA[t x ][k]· shareB[k][t y ]
                              k=0
                 8.  执行块内线程同步 syncthreads()
                         b
                                b
                 9. 置  C[b x 2 +t x ][b y 2 +t y ] ← t
   253   254   255   256   257   258   259   260   261   262   263