def gradient(self, eta_1, eta_2): # self.eta_next = eta * (1-self.output_array**2) # return self.eta_next sq_1, sq_2 = secp.SecMul_matrix(self.output_array_1, self.output_array_1, self.output_array_2, self.output_array_2, self.bit_length) self.eta_next_1, self.eta_next_2 = secp.SecMul_matrix( eta_1, 1 - sq_1, eta_2, -sq_2, self.bit_length) return self.eta_next_1, self.eta_next_2
def forward(self, input_array_1, input_array_2): eps = 1e-5 # CMP input_shape = input_array_1.shape a_1, a_2, offline_time_1, online_time_1 = secp2.SecCmp_z2( input_array_1, -0.5 * np.ones(input_shape), input_array_2, np.zeros(input_shape), bit_length=self.bit_length) b_1, b_2, offline_time_2, online_time_2 = secp2.SecCmp_z2( input_array_1, 0.5 * np.ones(input_shape), input_array_2, np.zeros(input_shape), bit_length=self.bit_length) start_time = time.time() # XOR, AND alpha_1, alpha_2 = secp3.SecXor_z2(a_1, 1, a_2, 0) beta_x_1, beta_x_2 = secp3.SecXor_z2(b_1, 1, b_2, 0) beta_1, beta_2 = secp3.SecMul_z2(a_1, beta_x_1, a_2, beta_x_2) # FIELD CONVERT alpha_1, alpha_2 = secp2.SecFieldC(alpha_1, alpha_2, bit_length=self.bit_length) beta_1, beta_2 = secp2.SecFieldC(beta_1, beta_2, bit_length=self.bit_length) gamma_1, gamma_2 = secp2.SecFieldC(b_1, b_2, bit_length=self.bit_length) # MUL alpha_1, alpha_2 = secp.SecMul_matrix(alpha_1, eps, alpha_2, 0, bit_length=self.bit_length) beta_1, beta_2 = secp.SecMul_matrix(beta_1, input_array_1 + 0.5, beta_2, input_array_2, bit_length=self.bit_length) gamma_1, gamma_2 = secp.SecMul_matrix(gamma_1, 1 - eps, gamma_2, 0, bit_length=self.bit_length) self.output_array_1 = alpha_1 + beta_1 + gamma_1 self.output_array_2 = alpha_2 + beta_2 + gamma_2 end_time = time.time() self.offline_time = offline_time_1 + offline_time_2 self.online_time = online_time_1 + online_time_2 + (end_time - start_time) * 1000 return self.output_array_1, self.output_array_2
def cal_softmax(self, input_array_1, input_array_2): # 密文 softmax_1 = np.zeros(input_array_1.shape) softmax_2 = np.zeros(input_array_2.shape) # 对每个batch的数据求softmax exp_i_1, exp_i_2 = secp.SecExp( input_array_1 - np.max(input_array_1 + input_array_2), input_array_2, self.bit_length) # print('exp_sec: ', exp_i_1+exp_i_2) sum_exp_1 = np.sum(exp_i_1) sum_exp_2 = np.sum(exp_i_2) # print('sum exp_sec: ', sum_exp_1+sum_exp_2) # exps_i = np.exp(input_array-np.max(input_array)) tau_inv = 10 initial_inv = 1e-2 sum_exp_inv_1, sum_exp_inv_2 = secp.SecInv(sum_exp_1, sum_exp_2, tau_inv, initial=initial_inv, bit_length=self.bit_length) softmax_1, softmax_2 = secp.SecMul_matrix(exp_i_1, sum_exp_inv_1, exp_i_2, sum_exp_inv_2, self.bit_length) # print('inv_sec: ', sum_exp_inv_1+sum_exp_inv_2) # print('softmax_sec: ', softmax_1+softmax_2) # softmax = exps_i/np.sum(exps_i) # softmax[batch, class_num] return softmax_1, softmax_2
def gradient(self, eta_1, eta_2): # index_matrix = (self.f1+self.f2)&(2-1) # self.eta_next_1 = eta_1*self.index_matrix # self.eta_next_2 = eta_2*self.index_matrix self.eta_next_1, self.eta_next_2 = secp.SecMul_matrix( eta_1, self.index_matrix_1, eta_2, self.index_matrix_2, self.bit_length) return self.eta_next_1, self.eta_next_2
def SecFieldC(u1, u2, bit_length=32): # 生成2**bit_length数域上的随机数,r1+r2=0 # low = -2**(bit_length//4) # high = 2**(bit_length//4) low = 0 high = 2 input_shape = u1.shape r1 = np.random.randint(low, high, input_shape) r2 = 0 - r1 m1, m2 = secp.SecMul_matrix(u1, u2, 0, 0, bit_length) f1 = r1 + u1 - 2 * m1 f2 = r2 + u2 - 2 * m2 return f1, f2
def secmul_m_test_fix(): u1 = [[-56503, -56503, -56503, -56503], [-56503, -56503, -56503, -56503]] u2 = [[56504, 56504, 56504, 56504], [56504, 56504, 56504, 56504]] v1 = [[44795, -33891, -16734, 48148], [14328, -29446, 16009, 27700]] v2 = [[-44795, 33891, 16735, -48148], [-14327, 29447, -16008, -27699]] u1 = np.array(u1) u2 = np.array(u2) v1 = np.array(v1) v2 = np.array(v2) f1, f2 = secp.SecMul_matrix(u1, v1, u2, v2) print('f1+f2: \n', (f1 + f2)) print('cal err: \n', (f1 + f2) - (u1 + u2) * (v1 + v2))
def secConvSpeed_test(): a = np.random.randn(5, 5) # a=[3,4] b = np.random.randn(5, 5) # b=[4,3] a1 = np.random.randn(5, 5) b1 = np.random.randn(5, 5) a2 = a - a1 b2 = b - b1 start_time = time.time() for i in range(0, 5): for j in range(0, 169): f1, f2 = secp.SecMul_matrix(a1, b1, a2, b2, bit_length=32) end_time = time.time() print('conv time: ', (end_time - start_time) * 1000)
def forward(self, input_array_1, input_array_2): input_array = input_array_1 + input_array_2 input_array_1 = input_array / 3 input_array_2 = input_array - input_array_1 tau = 10 initial_num = 1e-2 # 训练的时候调整一下 t1 = np.exp(-input_array_1) t2 = np.exp(-input_array_2) u1, u2 = secp.SecMul_matrix(t1, t2, 0, 0, self.bit_length) self.output_array_1, self.output_array_2 = secp.SecInv( 1 + u1, u2, tau, initial=initial_num, bit_length=self.bit_length) # print('1+exp(-1):', 1+np.exp(-(input_array_1+input_array_2))) # print('1+exp(-1)_sec:', 1+u1+u2) return self.output_array_1, self.output_array_2
def forward(self, input_array_1, input_array_2): self.input_array_1 = input_array_1 self.input_array_2 = input_array_2 input_shape = self.input_array_1.shape input_zeros_1 = np.zeros(input_shape).astype(np.int) input_zeros_2 = np.zeros(input_shape).astype(np.int) input_ones = np.ones(input_shape).astype(np.int) '''计算C*x if x>0''' index_matrix_z2_1, index_matrix_z2_2, self.offline_time, self.online_time, self.dfc_time = secp2.SecCmp_z2( self.input_array_1, input_zeros_1, self.input_array_2, input_zeros_2, self.bit_length) # 计时版 self.index_matrix_1, self.index_matrix_2 = secp2.SecFieldC( index_matrix_z2_1, index_matrix_z2_2, self.bit_length) lrelu_out_1, lrelu_out_2 = secp.SecMul_matrix(self.input_array_1, self.index_matrix_1, self.input_array_2, self.index_matrix_2, self.bit_length) '''计算alpha*x if x<=0''' # 对cmp输出与1做异或 index_matrix_z2_alpha_1, index_matrix_z2_alpha_2, xor_online_time = secp2.SecXor_z2( index_matrix_z2_1, input_zeros_1, index_matrix_z2_2, input_ones) # 将异或结果转换域 index_matrix_new_1, index_matrix_new_2 = secp2.SecFieldC( index_matrix_z2_alpha_1, index_matrix_z2_alpha_2, self.bit_length) lrelu_alpha_1, lrelu_alpha_2 = secp.SecMul_matrix( self.alpha1 * self.input_array_1, index_matrix_new_1, self.alpha1 * self.input_array_2, index_matrix_new_2, self.bit_length) lrelu_out_1 += lrelu_alpha_1 lrelu_out_2 += lrelu_alpha_2 return lrelu_out_1, lrelu_out_2, self.dfc_time
def unit_test(): batchsize = 2 u = np.random.randn(batchsize, 4, 3) v = np.random.randn(batchsize, 4, 3) print('u: \n', u) print('v: \n', v) u1 = np.random.randn(batchsize, 4, 3) u2 = u - u1 v1 = np.random.randn(batchsize, 4, 3) v2 = v - v1 start_time = time.time() f1, f2 = secp.SecMul_matrix(u1, v1, u2, v2) end_time = time.time() print('f: ', f1 + f2) print('u*v: ', u * v) print('err: ', (f1 + f2) - u * v)
def forward(self, input_array_1, input_array_2): # self.output_array = 2/(1+np.exp(-2*input_array))-1 # return self.output_array # shares再分配= =策略 input_array = input_array_1 + input_array_2 input_array_1 = input_array / 3 input_array_2 = input_array - input_array_1 tau = 10 initial_num = 1e-2 t1 = np.exp(-2 * input_array_1) t2 = np.exp(-2 * input_array_2) u1, u2 = secp.SecMul_matrix(t1, t2, 0, 0, self.bit_length) output_array_1, output_array_2 = secp.SecInv( 1 + u1, u2, tau, initial=initial_num, bit_length=self.bit_length) self.output_array_1 = 2 * output_array_1 - 1 self.output_array_2 = 2 * output_array_2 return self.output_array_1, self.output_array_2
def secmul_m_test(): batchsize = 512 u = np.random.randn(batchsize, 4, 3) v = np.random.randn(batchsize, 4, 3) # print('u: \n', u) # print('v: \n', v) u1 = np.random.randn(batchsize, 4, 3) u2 = u - u1 v1 = np.random.randn(batchsize, 4, 3) v2 = v - v1 start_time = time.time() f1, f2 = secp.SecMul_matrix(u1, v1, u2, v2) end_time = time.time() # print('u1: \n', u1) # print('u2: \n', u2) # print('v1: \n', v1) # print('v2: \n', v2) # print('cal err: \n', (f1+f2)-u*v) print('mul time: \n', end_time - start_time)
def forward(self, input_array_1, input_array_2): self.input_array_1 = input_array_1 self.input_array_2 = input_array_2 input_shape = self.input_array_1.shape input_zeros_1 = np.zeros(input_shape) input_zeros_2 = np.zeros(input_shape) # 使用0和input_array的元素依次比较 # np.maximum:(X, Y, out=None) X与Y逐位比较取其大者 index_matrix_z2_1, index_matrix_z2_2, self.offline_time, self.online_time, self.dfc_time = secp2.SecCmp_z2( self.input_array_1, input_zeros_1, self.input_array_2, input_zeros_2, self.bit_length) # 计时版 # index_matrix_z2_1, index_matrix_z2_2 = secp3.SecCmp_z2(self.input_array_1, input_zeros_1, self.input_array_2, input_zeros_2, self.bit_length) # 非计时版 # start_time = time.time() ## 将数域从Z2转到Z2**bit_length self.index_matrix_1, self.index_matrix_2 = secp2.SecFieldC( index_matrix_z2_1, index_matrix_z2_2, self.bit_length) # print("f1+f2: ",(self.f1+self.f2)&(2-1)) # index_matrix用于保存input中的数是否大于0的矩阵 # if u_i>0, index_matrix[i]=1 # if u_i<=0, index_matrix[i]=0 # self.index_matrix = (index_matrix_z2_1+index_matrix_z2_2)&(2-1) # print('index_matrix_z2_1: \n', index_matrix_z2_1) # print('index_matrix_z2_2: \n', index_matrix_z2_2) # print('error: \n', self.index_matrix_1+self.index_matrix_2-self.index_matrix) relu_out_1, relu_out_2 = secp.SecMul_matrix(self.input_array_1, self.index_matrix_1, self.input_array_2, self.index_matrix_2, self.bit_length) # end_time = time.time() # print('SFC+Mulmatirx time: ',(end_time-start_time)*1000) # self.online_time += (end_time-start_time)*1000 # print('total relu time: ', self.online_time+self.offline_time) # print('dfc_time: ', self.dfc_time*60*1000) # print('relu_shape: ', self.input_array_1.shape) # print('-----') return relu_out_1, relu_out_2, self.dfc_time
def forward(self, input_array_1, input_array_2, mode="train"): # input_data = [batch,channel_num,h,w] # self.input_data = input_array self.input_data_1 = input_array_1 self.input_data_2 = input_array_2 self.input_shape = self.input_data_1.shape self.batchsize = self.input_shape[0] # 计算均值的数据总量的维度m self.m = self.batchsize if self.input_data_1.ndim == 4: self.m = self.batchsize * self.input_data_1.shape[ 2] * self.input_data_1.shape[3] # 计算均值mean (axis=1对列求平均值,axis=0对行求平均) # keepdims=True可以保证使用np计算均值或者方差的结果保留原始数据的维度大小,可以方便的用于和原输入进行运算 # self.mean = np.mean(self.input_data, axis=(0,2,3), keepdims=True) self.mean_1 = np.mean(self.input_data_1, axis=(0, 2, 3), keepdims=True) self.mean_2 = np.mean(self.input_data_2, axis=(0, 2, 3), keepdims=True) # print('mean.shape: ',self.mean.shape) # 记录一下标准差standard矩阵, 反向传播时使用 # self.standard = self.input_data-self.mean self.standard_1 = self.input_data_1 - self.mean_1 self.standard_2 = self.input_data_2 - self.mean_2 # 计算方差var ## 计算标准差的平方 # print('bn mul_1 shape: ', self.standard_1.shape) std_sq_1, std_sq_2 = secp.SecMul_matrix(self.standard_1, self.standard_1, self.standard_2, self.standard_2, bit_length=self.bit_length) self.var_1 = np.mean(std_sq_1, axis=(0, 2, 3), keepdims=True) self.var_2 = np.mean(std_sq_2, axis=(0, 2, 3), keepdims=True) # self.var = np.var(self.input_data_1+self.input_data_2, axis=(0,2,3), keepdims=True) # 存在多组数据batch的情况下,需要计算方差的无偏估计(b/(b-1)*E(var(x))) [但是pytorch似乎也没这么计算] # if self.batchsize>1: # self.var = self.m/(self.m-1)*self.var # 利用指数加权平均算法计算moving_mean和moving_var,用于测试时作为整体的mean,var的无偏估计 if np.sum(self.moving_mean) == 0 and np.sum(self.moving_var) == 0: self.moving_mean = self.mean_1 + self.mean_2 self.moving_var = self.var_1 + self.var_2 else: self.moving_mean = self.moving_decay * self.moving_mean + ( 1 - self.moving_decay) * (self.mean_1 + self.mean_2) self.moving_var = self.moving_decay * self.moving_var + ( 1 - self.moving_decay) * (self.var_1 + self.var_2) # 计算标准化值normed_x = [batch, bn_shape] if mode == 'train': tua_sqrt = 5 # print('sqrt input_sec: ', self.var_1[0][0]+self.epsilon, self.var_2[0][0]) # print('sqrt shape: ', self.var_1.shape) # self.normed_x = (self.input_data-self.mean)/np.sqrt(self.var+self.epsilon) # print('bn sqrt shape: ', self.var_1.shape) inverse_sq_x_1, inverse_sq_x_2 = secp.SSqrt( self.var_1 + self.epsilon, self.var_2, tua_sqrt, inverse_required=True, bit_length=self.bit_length) # print('error var: ',self.var-(self.var_1+self.var_2)) # print('error inverse sqrt: ',(inverse_sq_x_1+inverse_sq_x_2 - 1/np.sqrt(self.var_1+self.var_2+self.epsilon))[0][0]) # print('bn mul_1 shape: ', self.standard_1.shape) self.normed_x_1, self.normed_x_2 = secp.SecMul_matrix( self.standard_1, inverse_sq_x_1, self.standard_2, inverse_sq_x_2) # self.normed_x = (self.standard_1+self.standard_2)/np.sqrt(self.var+self.epsilon) # print('error inverse normed_x: ',self.normed_x-(self.normed_x_1+self.normed_x_2)) # print(self.normed_x) '''test的先不写了''' if mode == 'test': self.normed_x = (self.input_data - self.moving_mean ) / np.sqrt(self.moving_var + self.epsilon) # 计算BN输出 output_y = [batch, -1] # 对每个输入都进行标准化,所以输出y的size和输入相同 # print('gamma.shape: ',self.gamma.shape) # print('normed_x.shape: ',self.normed_x.shape) # print('type_gamma: ',self.gamma[0]) # print('type_normed_x: ',type(self.normed_x)) # 对每个channel做一次线性变换 output_y_1 = np.zeros(self.input_shape) output_y_2 = np.zeros(self.input_shape) # output_y = np.zeros(self.input_shape) for i in range(self.in_channels): # output_y[:,i,:,:] = self.gamma.data[i]*self.normed_x[:,i,:,:] + self.beta.data[i] # output_y[:,i,:,:] = output_y_i output_y_1[:, i, :, :] = self.gamma.data[ i] * self.normed_x_1[:, i, :, :] + self.beta.data[i] output_y_2[:, i, :, :] = self.gamma.data[i] * self.normed_x_2[:, i, :, :] # output_y = np.array(output_y) # output_y = self.gamma*self.normed_x + self.beta # print('error scale: ',output_y-(output_y_1+output_y_2)) return output_y_1, output_y_2
def gradient(self, eta_1, eta_2): self.eta_next_1, self.eta_next_2 = secp.SecMul_matrix( eta_1, 2 * self.input_array_1, eta_2, 2 * self.input_array_2, self.bit_length) return self.eta_next_1, self.eta_next_2