@ -95,5 +95,206 @@ class TestInplace(unittest.TestCase):
loss . backward ( )
class TestDygraphInplace ( unittest . TestCase ) :
def setUp ( self ) :
self . init_data ( )
def init_data ( self ) :
self . input_var_numpy = np . random . rand ( 2 , 3 , 1 )
self . dtype = " float32 "
def non_inplace_api_processing ( self , var ) :
return paddle . squeeze ( var )
def inplace_api_processing ( self , var ) :
return paddle . squeeze_ ( var )
def test_inplace_api ( self ) :
var = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
inplace_var = self . inplace_api_processing ( var )
self . assertTrue ( id ( var ) == id ( inplace_var ) )
inplace_var [ 0 ] = 2.
self . assertTrue ( np . array_equal ( var . numpy ( ) , inplace_var . numpy ( ) ) )
def test_forward_version ( self ) :
with paddle . fluid . dygraph . guard ( ) :
var = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
self . assertEqual ( var . inplace_version , 0 )
inplace_var = self . inplace_api_processing ( var )
self . assertEqual ( var . inplace_version , 1 )
inplace_var [ 0 ] = 2.
self . assertEqual ( var . inplace_version , 2 )
inplace_var = self . inplace_api_processing ( inplace_var )
self . assertEqual ( var . inplace_version , 3 )
def test_leaf_inplace_var_error ( self ) :
with paddle . fluid . dygraph . guard ( ) :
var = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var . stop_gradient = False
def leaf_inplace_error ( ) :
self . inplace_api_processing ( var )
self . assertRaises ( ValueError , leaf_inplace_error )
def test_backward_error ( self ) :
# It raises an error because the inplace operator will result
# in incorrect gradient computation.
with paddle . fluid . dygraph . guard ( ) :
var_a = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var_a . stop_gradient = False
var_b = var_a * * 2
# Here, the gradient computation will use the value of var_b
var_c = var_b * * 2
self . inplace_api_processing ( var_b )
loss = paddle . nn . functional . relu ( var_c )
with self . assertRaisesRegexp (
RuntimeError ,
" received tensor_version: {} != wrapper_version_snapshot: {} " .
format ( 1 , 0 ) ) :
loss . backward ( )
def test_backward_success_1 ( self ) :
# var_b is modified inplace before using it, the inplace operator doesn't result
# in incorrect gradient computation.
grad_var_a , grad_var_a_inplace = 0 , 1
with paddle . fluid . dygraph . guard ( ) :
var_a = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var_a . stop_gradient = False
var_b = var_a * * 2
var_c = self . inplace_api_processing (
var_b ) # var_b is modified inplace before using it
# Here, the gradient computation will use the value of var_b
var_d = var_c * * 2
loss = var_d . sum ( )
loss . backward ( )
grad_var_a_inplace = var_a . grad
with paddle . fluid . dygraph . guard ( ) :
var_a = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var_a . stop_gradient = False
var_b = var_a * * 2
var_c = self . non_inplace_api_processing ( var_b )
var_d = var_c * * 2
loss = var_d . sum ( )
loss . backward ( )
grad_var_a = var_a . grad
self . assertTrue ( np . array_equal ( grad_var_a_inplace , grad_var_a ) )
def test_backward_success_2 ( self ) :
# Although var_b is modified inplace after using it, it does not used in gradient computation.
# The inplace operator doesn't result in incorrect gradient computation.
grad_var_a , grad_var_a_inplace = 0 , 1
with paddle . fluid . dygraph . guard ( ) :
var_a = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var_a . stop_gradient = False
var_b = var_a * * 2
var_c = self . inplace_api_processing (
var_b ) # var_b is modified inplace before using it
var_d = var_c + var_c # Here, the grad op of sum doesn't use the value of var_b
loss = var_d . sum ( )
loss . backward ( )
grad_var_a_inplace = var_a . grad
with paddle . fluid . dygraph . guard ( ) :
var_a = paddle . to_tensor ( self . input_var_numpy ) . astype ( self . dtype )
var_a . stop_gradient = False
var_b = var_a * * 2
var_c = self . non_inplace_api_processing (
var_b ) # var_b is modified inplace before using it
var_d = var_c + var_c # Here, the grad op of sum doesn't use the value of var_b
loss = var_d . sum ( )
loss . backward ( )
grad_var_a = var_a . grad
self . assertTrue ( np . array_equal ( grad_var_a_inplace , grad_var_a ) )
class TestDygraphInplaceUnsqueeze ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . unsqueeze ( var , - 1 )
def inplace_api_processing ( self , var ) :
return paddle . unsqueeze_ ( var , - 1 )
class TestDygraphInplaceReshape ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . reshape ( var , [ - 1 ] )
def inplace_api_processing ( self , var ) :
return paddle . reshape_ ( var , [ - 1 ] )
class TestDygraphInplaceScatter ( TestDygraphInplace ) :
def init_data ( self ) :
self . input_var_numpy = np . array ( [ [ 1 , 1 ] , [ 2 , 2 ] , [ 3 , 3 ] ] )
self . dtype = " float32 "
def non_inplace_api_processing ( self , var ) :
index = paddle . to_tensor ( [ 2 , 1 , 0 , 1 ] , dtype = ' int64 ' )
updates = paddle . to_tensor (
[ [ 1 , 1 ] , [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] ] , dtype = ' float32 ' )
return paddle . scatter ( var , index , updates , overwrite = False )
def inplace_api_processing ( self , var ) :
index = paddle . to_tensor ( [ 2 , 1 , 0 , 1 ] , dtype = ' int64 ' )
updates = paddle . to_tensor (
[ [ 1 , 1 ] , [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] ] , dtype = ' float32 ' )
return paddle . scatter_ ( var , index , updates , overwrite = False )
class TestDygraphInplaceElu ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . nn . functional . elu ( var )
def inplace_api_processing ( self , var ) :
return paddle . nn . functional . elu_ ( var )
class TestDygraphInplaceRelu ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . nn . functional . relu ( var )
def inplace_api_processing ( self , var ) :
return paddle . nn . functional . relu_ ( var )
class TestDygraphInplaceSoftmax ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . nn . functional . softmax ( var )
def inplace_api_processing ( self , var ) :
return paddle . nn . functional . softmax_ ( var )
class TestDygraphInplaceTanh ( TestDygraphInplace ) :
def non_inplace_api_processing ( self , var ) :
return paddle . tanh ( var )
def inplace_api_processing ( self , var ) :
return paddle . tanh_ ( var )
if __name__ == ' __main__ ' :
unittest . main ( )