@@ -33,9 +33,13 @@ public static Tensor[] _AbsGrad(Operation op, Tensor[] grads)
3333 var x = op . inputs [ 0 ] ;
3434 var grad = grads [ 0 ] ;
3535
36- return new Tensor [ ] { gen_ops . mul ( grad , gen_math_ops . sign ( x ) ) } ;
36+ return new Tensor [ ] { grad * math_ops . sign ( x ) } ;
3737 }
3838
39+ [ RegisterGradient ( "AddV2" ) ]
40+ public static Tensor [ ] _AddV2Grad ( Operation op , Tensor [ ] grads )
41+ => _AddGrad ( op , grads ) ;
42+
3943 [ RegisterGradient ( "Add" ) ]
4044 public static Tensor [ ] _AddGrad ( Operation op , Tensor [ ] grads )
4145 {
@@ -107,7 +111,9 @@ public static Tensor[] _ExpGrad(Operation op, Tensor[] grads)
107111 var y = op . outputs [ 0 ] ; // y = e^x
108112 return tf_with ( ops . control_dependencies ( new Operation [ ] { grad } ) , dp => {
109113 y = math_ops . conj ( y ) ;
110- return new Tensor [ ] { math_ops . mul_no_nan ( y , grad ) } ;
114+ // forward_compatible(2019, 9, 14)
115+ // return new Tensor[] { math_ops.mul_no_nan(y, grad) };
116+ return new Tensor [ ] { grad * y } ;
111117 } ) ;
112118 }
113119
@@ -167,8 +173,7 @@ public static Tensor[] _MulGrad(Operation op, Tensor[] grads)
167173 new TF_DataType [ ] { tf . int32 , tf . float32 } . Contains ( grad . dtype ) )
168174 return new Tensor [ ] { gen_math_ops . mul ( grad , y ) , gen_math_ops . mul ( grad , x ) } ;
169175
170- var sx = array_ops . shape ( x ) ;
171- var sy = array_ops . shape ( y ) ;
176+ var ( sx , sy ) = SmartBroadcastGradientArgs ( x , y ) ;
172177 var ( rx , ry ) = gen_array_ops . broadcast_gradient_args ( sx , sy ) ;
173178
174179 x = math_ops . conj ( x ) ;
@@ -355,8 +360,8 @@ private static Tensor[] _MaximumMinimumGrad(bool isMaximum, Operation op, Tensor
355360 : gen_math_ops . less_equal ( x , y ) ;
356361 var ( rx , ry ) = gen_array_ops . broadcast_gradient_args ( sx , sy ) ;
357362 var xgrad = array_ops . where ( xmask , grad , zeros ) ;
358- var ygrad = array_ops . where ( xmask , zeros , grad ) ;
359363 var gx = array_ops . reshape ( math_ops . reduce_sum ( xgrad , rx ) , sx ) ;
364+ var ygrad = array_ops . where ( xmask , zeros , grad ) ;
360365 var gy = array_ops . reshape ( math_ops . reduce_sum ( ygrad , ry ) , sy ) ;
361366 return new Tensor [ ] { gx , gy } ;
362367 }
@@ -397,14 +402,13 @@ public static Tensor[] _SubGrad(Operation op, Tensor[] grads)
397402 _ShapesFullySpecifiedAndEqual ( x , y , grad ) )
398403 return new Tensor [ ] { grad , - grad } ;
399404
400- var sx = array_ops . shape ( x ) ;
401- var sy = array_ops . shape ( y ) ;
405+ var ( sx , sy ) = SmartBroadcastGradientArgs ( x , y ) ;
402406 var ( rx , ry ) = gen_array_ops . broadcast_gradient_args ( sx , sy ) ;
403407
404- var r1 = gen_array_ops . reshape ( math_ops . reduce_sum ( grad , rx ) , sx ) ;
405- var r2 = gen_array_ops . reshape ( - math_ops . reduce_sum ( grad , ry ) , sy ) ;
408+ var gx = array_ops . reshape ( math_ops . reduce_sum ( grad , rx ) , sx ) ;
409+ var gy = array_ops . reshape ( math_ops . reduce_sum ( - grad , ry ) , sy ) ;
406410
407- return new Tensor [ ] { r1 , r2 } ;
411+ return new Tensor [ ] { gx , gy } ;
408412 }
409413
410414 public static bool _ShapesFullySpecifiedAndEqual ( Tensor x , Tensor y , Tensor grad )
@@ -468,15 +472,16 @@ public static Tensor[] _RealDivGrad(Operation op, Tensor[] grads)
468472 x = math_ops . conj ( x ) ;
469473 y = math_ops . conj ( y ) ;
470474
471- var realdiv1 = gen_math_ops . real_div ( - x , y ) ;
472- var realdiv2 = gen_math_ops . real_div ( realdiv1 , y ) ;
473- var reduce_sum1 = math_ops . reduce_sum ( grad * realdiv2 , ry ) ;
474- var reshape1 = gen_array_ops . reshape ( reduce_sum1 , sy ) ;
475- var realdiv3 = gen_math_ops . real_div ( grad , y ) ;
476- var reduce_sum2 = math_ops . reduce_sum ( realdiv3 , rx ) ;
477- var reshape2 = gen_array_ops . reshape ( reduce_sum2 , sx ) ;
475+ var reshape1 = array_ops . reshape (
476+ math_ops . reduce_sum (
477+ math_ops . realdiv ( grad , y ) , rx ) ,
478+ sx ) ;
479+ var reshape2 = array_ops . reshape (
480+ math_ops . reduce_sum (
481+ grad * math_ops . realdiv ( math_ops . realdiv ( - x , y ) , y ) , ry ) ,
482+ sy ) ;
478483
479- return new Tensor [ ] { reshape2 , reshape1 } ;
484+ return new Tensor [ ] { reshape1 , reshape2 } ;
480485 }
481486
482487 [ RegisterGradient ( "Sigmoid" ) ]
@@ -602,14 +607,12 @@ public static Tensor[] _PowGrad(Operation op, Tensor[] grads)
602607 var y = op . inputs [ 1 ] ;
603608 var z = op . outputs [ 0 ] ;
604609
605- var sx = array_ops . shape ( x ) ;
606- var sy = array_ops . shape ( y ) ;
610+ var ( sx , sy ) = SmartBroadcastGradientArgs ( x , y ) ;
607611 var ( rx , ry ) = gen_array_ops . broadcast_gradient_args ( sx , sy ) ;
608612 x = math_ops . conj ( x ) ;
609613 y = math_ops . conj ( y ) ;
610614 z = math_ops . conj ( z ) ;
611- var pow = gen_math_ops . pow ( x , y - 1.0f ) ;
612- var mul = grad * y * pow ;
615+ var mul = grad * y * math_ops . pow ( x , y - 1.0f ) ;
613616 var reduce_sum = math_ops . reduce_sum ( mul , rx ) ;
614617 var gx = gen_array_ops . reshape ( reduce_sum , sx ) ;
615618
@@ -630,5 +633,29 @@ public static Tensor[] _PowGrad(Operation op, Tensor[] grads)
630633
631634 return new Tensor [ ] { gx , gy } ;
632635 }
636+
637+ /// <summary>
638+ /// Optimized version of `broadcast_gradient_args` that caches results.
639+ /// </summary>
640+ /// <param name="x"></param>
641+ /// <param name="y"></param>
642+ /// <returns></returns>
643+ private static ( Tensor , Tensor ) SmartBroadcastGradientArgs ( Tensor x , Tensor y )
644+ {
645+ Tensor sx , sy ;
646+ if ( x . TensorShape . is_fully_defined ( ) &&
647+ y . TensorShape . is_fully_defined ( ) )
648+ {
649+ sx = array_ops . shape ( x ) ;
650+ sy = array_ops . shape ( y ) ;
651+ }
652+ else
653+ {
654+ sx = array_ops . shape_internal ( x , optimize : false ) ;
655+ sy = array_ops . shape_internal ( y , optimize : false ) ;
656+ }
657+
658+ return ( sx , sy ) ;
659+ }
633660 }
634661}
0 commit comments