#NEWLINE# def bprop( self , error , alpha = 1.0 , beta = 0.0 ) : #NEWLINE# #INDENT# '\n        Backpropagation of errors, output delta for previous layer, and\n        calculate the update on model params\n\n        Arguments:\n            error (list[Tensor]): error tensors for each time step\n                                  of unrolling\n            alpha (float, optional): scale to apply to input for activation\n                                     gradient bprop.  Defaults to 1.0\n            beta (float, optional): scale to apply to output activation\n                                    gradient bprop.  Defaults to 0.0\n\n        Returns:\n            Tensor: Backpropagated errors for each time step of model unrolling\n        ' #NEWLINE# self . dW [ : ] = 0 #NEWLINE# if ( self . in_deltas_f is None ) : #NEWLINE# #INDENT# self . in_deltas_f = get_steps ( error [ : self . o_shape [ 0 ] ] , self . o_shape ) #NEWLINE# self . prev_in_deltas = ( self . in_deltas_f [ ( - 1 ) : ] + self . in_deltas_f [ : ( - 1 ) ] ) #NEWLINE# self . ifog_delta_last_steps = self . ifog_delta_buffer [ : , self . be . bsz : ] #NEWLINE# self . h_first_steps = self . h_buffer_f [ : , : ( - self . be . bsz ) ] #NEWLINE# #UNINDENT# if ( self . in_deltas_b is None ) : #NEWLINE# #INDENT# self . in_deltas_b = get_steps ( error [ self . o_shape [ 0 ] : ] , self . o_shape ) #NEWLINE# self . next_in_deltas = ( self . in_deltas_b [ 1 : ] + self . in_deltas_b [ : 1 ] ) #NEWLINE# self . ifog_delta_first_steps = self . ifog_delta_buffer [ : , : ( - self . be . bsz ) ] #NEWLINE# self . h_last_steps = self . h_buffer_b [ : , self . be . bsz : ] #NEWLINE# #UNINDENT# params_f = ( self . in_deltas_f , self . prev_in_deltas , self . i_f , self . f_f , self . o_f , self . g_f , self . ifog_delta , self . i_delta , self . f_delta , self . o_delta , self . g_delta , self . c_delta , self . c_delta_prev , self . c_prev_bprop , self . c_act_f ) #NEWLINE# params_b = ( f . in_deltas_b , self . next_in_deltas , self . i_b , self . f_b , self . o_b , self . g_b , self . ifog_delta , self . i_delta , self . f_delta , self . o_delta , self . g_delta , self . c_delta , self . c_delta_next , self . c_next_bprop , self . c_act_b ) #NEWLINE# self . c_delta_buffer [ : ] = 0 #NEWLINE# self . ifog_delta_buffer [ : ] = 0 #NEWLINE# self . ifog_delta_f = None #NEWLINE# self . ifog_delta_b = None #NEWLINE# for ( in_deltas , prev_in_deltas , i , f , o , g , ifog_delta , i_delta , f_delta , o_delta , g_delta , c_delta , c_delta_prev , c_prev , c_act ) in reversed ( zip ( * params_f ) ) : #NEWLINE# #INDENT# c_delta [ : ] = ( c_delta + ( self . activation . bprop ( c_act ) * ( o * in_deltas ) ) ) #NEWLINE# i_delta [ : ] = ( ( self . gate_activation . bprop ( i ) * c_delta ) * g ) #NEWLINE# f_delta [ : ] = ( ( self . gate_activation . bprop ( f ) * c_delta ) * c_prev ) #NEWLINE# o_delta [ : ] = ( ( self . gate_activation . bprop ( o ) * in_deltas ) * c_act ) #NEWLINE# g_delta [ : ] = ( ( self . activation . bprop ( g ) * c_delta ) * i ) #NEWLINE# self . be . compound_dot ( self . W_recur_f . T , ifog_delta , prev_in_deltas , beta = 1.0 ) #NEWLINE# if ( c_delta_prev is not None ) : #NEWLINE# #INDENT# c_delta_prev [ : ] = ( c_delta * f ) #NEWLINE# #UNINDENT# #UNINDENT# self . be . compound_dot ( self . ifog_delta_last_steps , self . h_first_steps . T , self . dW_recur_f ) #NEWLINE# self . be . compound_dot ( self . ifog_delta_buffer , self . x_f . T , self . dW_input_f ) #NEWLINE# self . db_f [ : ] = self . be . sum ( self . ifog_delta_buffer , axis = 1 ) #NEWLINE# if self . out_deltas_buffer : #NEWLINE# #INDENT# self . be . compound_dot ( self . W_input_f . T , self . ifog_delta_buffer , self . out_deltas_buffer_f , alpha = alpha , beta = beta ) #NEWLINE# #UNINDENT# self . c_delta_buffer [ : ] = 0 #NEWLINE# self . ifog_delta_buffer [ : ] = 0 #NEWLINE# for ( in_deltas , next_in_deltas , i , f , o , g , ifog_delta , i_delta , f_delta , o_delta , g_delta , c_delta , c_delta_next , c_next , c_act ) in zip ( * params_b ) : #NEWLINE# #INDENT# c_delta [ : ] = ( c_delta [ : ] + ( self . activation . bprop ( c_act ) * ( o * in_deltas ) ) ) #NEWLINE# i_delta [ : ] = ( ( self . gate_activation . bprop ( i ) * c_delta ) * g ) #NEWLINE# f_delta [ : ] = ( ( self . gate_activation . bprop ( f ) * c_delta ) * c_next ) #NEWLINE# o_delta [ : ] = ( ( self . gate_activation . bprop ( o ) * in_deltas ) * c_act ) #NEWLINE# g_delta [ : ] = ( ( self . activation . bprop ( g ) * c_delta ) * i ) #NEWLINE# self . be . compound_dot ( self . W_recur_b . T , ifog_delta , next_in_deltas , beta = 1.0 ) #NEWLINE# if ( c_delta_next is not None ) : #NEWLINE# #INDENT# c_delta_next [ : ] = ( c_delta * f ) #NEWLINE# #UNINDENT# #UNINDENT# self . be . compound_dot ( self . ifog_delta_first_steps , self . h_last_steps . T , self . dW_recur_b ) #NEWLINE# self . be . compound_dot ( self . ifog_delta_buffer , self . x_b . T , self . dW_input_b ) #NEWLINE# self . db_b [ : ] = self . be . sum ( self . ifog_delta_buffer , axis = 1 ) #NEWLINE# if self . out_deltas_buffer : #NEWLINE# #INDENT# self . be . compound_dot ( self . W_input_b . T , self . ifog_delta_buffer , self . out_deltas_buffer_b , alpha = alpha , beta = ( beta if self . inputs else 1.0 ) ) #NEWLINE# #UNINDENT# return self . out_deltas_buffer