def update(self, learning_rate): #반복문 개선 버전 (최적화) def update_(x, delta_x): return x - learning_rate.array[0] * delta_x #learning_rate는 캡쳐됨. tensor.function_elment_wise(self.gamma, self.dgamma, update_, self.gamma) tensor.function_elment_wise(self.beta, self.dbeta, update_, self.beta)
def accuracy(self, table): """forward를 반드시 해야 하고, backward 이전에 사용해야 합니다.""" out = self.layers[-1].out out_argmax = tensor.argmax(out, -1, tensor.create_sum(out, -1)) table_argmax = tensor.argmax(table, -1, tensor.create_sum(table, -1)) eq = tensor.function_elment_wise( out_argmax, table_argmax, Layers._equal, tensor.create_element_wise_product(out_argmax, table_argmax, int)) reduce_sum = tensor.sum_axis(eq, 0, tensor.Tensor([1], [1])) return reduce_sum.array[0] / len(out_argmax.array)
def backward(self, dout): #반복문 최소화하기 위한 함수 def comput_new_dxc(dxc, xc_dvar): return dxc + (2.0 / self.batch_size) * xc_dvar def comput_dx(dxc, dmu): return dxc - dmu / self.batch_size tensor.mul(self.gamma, dout, self.out) # out를 dxn으로 사용(기존 forward out 손실) tensor.mul(self.out, self.xc, self.tmp_out_shape) #dstd를 구하기 전단계 #반복문 최소화 기능. tensor.function_elment_wise( self.tmp_out_shape, self.std, BatchNormalization.comput_dstd, self.tmp_out_shape) #tmp_out_shape은 dstd(np.sum하기 전)로 사용 tensor.function_elment_wise( self.tmp_out_shape, self.std, BatchNormalization.comput_dvar, self.tmp_out_shape) #tmp_out_shape는 dvar(np.sum하기 전)로 사용 tensor.sum_axis(self.tmp_out_shape, 0, self.dbeta) #self.dbeta는 dvar로 사용(기존 dbeta값 손실) tensor.mul(self.xc, self.dbeta, self.xc) #xc를 xc와 dvar의 곱으로 사용(기존 xc값 손실) (dvar의 역할 끝) tensor.div(self.out, self.std, self.out) # out을 dxc로 사용 (dxn값 손실) (dxn 역할 끝) tensor.function_elment_wise(self.out, self.xc, comput_new_dxc, self.out) tensor.sum_axis(self.out, 0, self.dbeta) #dmu를 dbeta로 사용(기존 dvar값 손실) tensor.function_elment_wise(self.out, self.dbeta, comput_dx, self.out) #최종 backward값(dxn값 손실) tensor.sum_axis(dout, 0, self.dbeta) tensor.mul( self.xn, dout, self.tmp_out_shape ) #tmp_out_shape는 dgamma를 구하기 위한 임시 객체로 재활용 (기존 dvar(np.sum하기 전)값 손실) tensor.sum_axis(self.tmp_out_shape, 0, self.dgamma) return self.out
def forward(self, x): #최적화 기법 def multiply_momentum_and_add(left, right): return left * self.momentum + (1 - self.momentum) * right #momentum 캡쳐 if (self.out.shape[0] != x.shape[0]): self.xc = x.copy() self.xn = x.copy() self.out = x.copy() self.tmp_out_shape = x.copy() self.batch_size = x.shape[0] if self.running_mean is None: D = len(x.array) // x.shape[0] self.running_mean = tensor.create_zeros([D]) self.running_var = tensor.create_zeros([D]) self.std = self.running_mean.copy() #self.tmp_sum_axis = self.running_mean.copy() self.dbeta = self.running_mean.copy() self.dgamma = self.running_mean.copy() if self.train_flg: #tmp_sum_axis가 나중에 추가되서 값이 이상하게 나오면 바꾸자. tensor.mean_axis(x, 0, self.std) #std가 임시 객체로 활용. (mu에 해당) #self.running_mean = self.momentum * self.running_mean + (1-self.momentum) * mu #(넘파이 버전) tensor.function_elment_wise(self.running_mean, self.std, multiply_momentum_and_add, self.running_mean) tensor.sub(x, self.std, self.xc) tensor.function(self.xc, BatchNormalization.jegop, self.xn) #xn도 계산에 필요한 임시 객체로 사용 tensor.mean_axis(self.xn, 0, self.std) #std가 임시 객체로 활용(var에 해당) #self.running_var = self.momentum * self.running_var + (1-self.momentum) * var #넘파이 버전 알고리즘 tensor.function_elment_wise(self.running_var, self.std, multiply_momentum_and_add, self.running_var) tensor.function(self.std, BatchNormalization.sqrt, self.std) # std가 가져야 할 값 tensor.div(self.xc, self.std, self.xn) #xn이 가져야 할 값 else: tensor.sub(x, self.running_mean, self.xc) tensor.function_elment_wise(self.xc, self.running_var, BatchNormalization.sqrt_and_div, self.xn) tensor.mul(self.gamma, self.xn, self.out) tensor.add(self.out, self.beta, self.out) return self.out
def update(self, learning_rate): def update_(x, delta_x): return x - learning_rate.array[0] * delta_x #learning_rate는 캡쳐됨. tensor.function_elment_wise(self.W, self.dW, update_, self.W) tensor.function_elment_wise(self.b, self.db, update_, self.b)
def backward(self, dout): tensor.function_elment_wise(dout, self.out, Relu.relu_dfunc, self.out) # 기존 out값이 손실 됨. return self.out