2019-09-11 20:50:28 +02:00
/*******************************************************************************
* Copyright ( c ) 2015 - 2018 Skymind , Inc .
*
* This program and the accompanying materials are made available under the
* terms of the Apache License , Version 2.0 which is available at
* https : //www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS , WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied . See the
* License for the specific language governing permissions and limitations
* under the License .
*
* SPDX - License - Identifier : Apache - 2.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//
// @author saudet
// @author raver119@gmail.com
//
# include <ops/declarable/PlatformHelper.h>
# include <ops/declarable/OpRegistrator.h>
# include <platform_boilerplate.h>
# include <helpers/MKLDNNStream.h>
# include "mkldnnUtils.h"
# include <ops/declarable/helpers/convolutions.h>
2019-11-20 11:23:08 +01:00
using namespace dnnl ;
2019-09-11 20:50:28 +02:00
2019-11-03 11:37:19 +01:00
namespace nd4j {
namespace ops {
namespace platforms {
//////////////////////////////////////////////////////////////////////
2020-01-28 16:23:07 +01:00
static void conv2dMKLDNN ( nd4j : : graph : : Context & block , const NDArray * input , const NDArray * weights ,
2019-11-03 11:37:19 +01:00
const NDArray * bias , NDArray * output , const int kH , const int kW , const int sH ,
2019-12-03 07:40:45 +01:00
const int sW , int pH , int pW , const int dH , const int dW , const int paddingMode ,
2019-11-03 11:37:19 +01:00
const int isNCHW ) {
int bS , iC , iH , iW , oC , oH , oW ; // batch size, input channels, input height/width, output channels, output height/width;
int indIOioC , indIiH , indWoC , indWiC , indWkH , indOoH ; // corresponding indexes
2020-01-28 16:23:07 +01:00
ConvolutionUtils : : getSizesAndIndexesConv2d ( isNCHW , * input , * output , bS , iC , iH , iW , oC , oH , oW , indIOioC , indIiH , indWiC , indWoC , indWkH , indOoH ) ;
2019-11-03 11:37:19 +01:00
2019-12-03 07:40:45 +01:00
ConvolutionUtils : : calcPadding2D ( pH , pW , oH , oW , iH , iW , kH , kW , sH , sW , dH , dW , paddingMode ) ;
2019-11-03 11:37:19 +01:00
2019-11-20 11:23:08 +01:00
dnnl_memory_desc_t empty ;
2020-01-28 16:23:07 +01:00
dnnl : : memory : : desc conv_src_md ( empty ) , conv_weights_md ( empty ) , conv_bias_md ( empty ) , conv_dst_md ( empty ) ;
dnnl : : memory : : desc user_src_md ( empty ) , user_weights_md ( empty ) , user_bias_md ( empty ) , user_dst_md ( empty ) ;
2019-11-20 11:23:08 +01:00
dnnl : : memory : : dims conv_strides , conv_padding , conv_padding_r , conv_dilation ;
2020-01-28 16:23:07 +01:00
2019-12-03 07:40:45 +01:00
mkldnnUtils : : getMKLDNNMemoryDescConv2d ( kH , kW , sH , sW , pH , pW , dH , dW , paddingMode , isNCHW ,
2019-11-03 11:37:19 +01:00
bS , iC , iH , iW , oC , oH , oW , input , nullptr , weights , nullptr ,
bias , output ,
& conv_src_md , nullptr , & conv_weights_md , nullptr ,
& conv_bias_md , & conv_dst_md ,
& user_src_md , nullptr , & user_weights_md , nullptr ,
& user_bias_md , & user_dst_md ,
conv_strides , conv_padding , conv_padding_r , conv_dilation ) ;
2020-01-28 16:23:07 +01:00
auto conv_desc = bias ! = nullptr ? convolution_forward : : desc ( prop_kind : : forward ,
2019-11-03 11:37:19 +01:00
algorithm : : convolution_auto , conv_src_md ,
conv_weights_md , conv_bias_md ,
conv_dst_md , conv_strides , conv_dilation , conv_padding ,
conv_padding_r )
2020-01-28 16:23:07 +01:00
: convolution_forward : : desc ( prop_kind : : forward ,
2019-11-03 11:37:19 +01:00
algorithm : : convolution_auto , conv_src_md ,
conv_weights_md ,
conv_dst_md , conv_strides , conv_dilation , conv_padding ,
conv_padding_r ) ;
auto engine = mkldnnUtils : : getEngine ( LaunchContext : : defaultContext ( ) - > engine ( ) ) ;
2019-11-20 11:23:08 +01:00
dnnl : : stream stream ( engine ) ;
2019-11-03 11:37:19 +01:00
auto conv_prim_desc = convolution_forward : : primitive_desc ( conv_desc , engine ) ;
2019-11-20 11:23:08 +01:00
auto user_src_memory = dnnl : : memory ( user_src_md , engine , const_cast < NDArray * > ( input ) - > buffer ( ) ) ;
auto user_weights_memory = dnnl : : memory ( user_weights_md , engine ,
2019-11-03 11:37:19 +01:00
const_cast < NDArray * > ( weights ) - > buffer ( ) ) ;
2019-11-20 11:23:08 +01:00
auto user_dst_memory = dnnl : : memory ( user_dst_md , engine , output - > buffer ( ) ) ;
2019-11-03 11:37:19 +01:00
auto conv_src_memory = user_src_memory ;
if ( conv_prim_desc . src_desc ( ) ! = user_src_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
conv_src_memory = dnnl : : memory ( conv_prim_desc . src_desc ( ) , engine ) ;
2019-11-03 11:37:19 +01:00
reorder ( user_src_memory , conv_src_memory ) . execute ( stream , user_src_memory , conv_src_memory ) ;
}
auto conv_weights_memory = user_weights_memory ;
if ( conv_prim_desc . weights_desc ( ) ! = user_weights_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
conv_weights_memory = dnnl : : memory ( conv_prim_desc . weights_desc ( ) , engine ) ;
2019-11-03 11:37:19 +01:00
reorder ( user_weights_memory , conv_weights_memory ) . execute ( stream , user_weights_memory ,
conv_weights_memory ) ;
}
auto conv_dst_memory = user_dst_memory ;
if ( conv_prim_desc . dst_desc ( ) ! = user_dst_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
conv_dst_memory = dnnl : : memory ( conv_prim_desc . dst_desc ( ) , engine ) ;
2019-11-03 11:37:19 +01:00
}
if ( bias ! = nullptr ) {
2019-11-20 11:23:08 +01:00
auto conv_bias_memory = dnnl : : memory ( conv_prim_desc . bias_desc ( ) , engine ,
2019-11-03 11:37:19 +01:00
const_cast < NDArray * > ( bias ) - > buffer ( ) ) ;
2019-11-20 11:23:08 +01:00
convolution_forward ( conv_prim_desc ) . execute ( stream , { { DNNL_ARG_SRC , conv_src_memory } ,
{ DNNL_ARG_WEIGHTS , conv_weights_memory } ,
{ DNNL_ARG_BIAS , conv_bias_memory } ,
{ DNNL_ARG_DST , conv_dst_memory } } ) ;
2019-11-03 11:37:19 +01:00
} else {
2019-11-20 11:23:08 +01:00
convolution_forward ( conv_prim_desc ) . execute ( stream , { { DNNL_ARG_SRC , conv_src_memory } ,
{ DNNL_ARG_WEIGHTS , conv_weights_memory } ,
{ DNNL_ARG_DST , conv_dst_memory } } ) ;
2019-11-03 11:37:19 +01:00
}
if ( conv_prim_desc . dst_desc ( ) ! = user_dst_memory . get_desc ( ) ) {
reorder ( conv_dst_memory , user_dst_memory ) . execute ( stream , conv_dst_memory , user_dst_memory ) ;
}
stream . wait ( ) ;
}
//////////////////////////////////////////////////////////////////////
2020-01-28 16:23:07 +01:00
static void conv2dBpMKLDNN ( nd4j : : graph : : Context & block ,
const NDArray * input , const NDArray * weights , const NDArray * bias , const NDArray * gradO ,
NDArray * gradI , NDArray * gradW , NDArray * gradB ,
const int kH , const int kW , const int sH , const int sW , int pH , int pW , const int dH , const int dW ,
const int paddingMode , const int isNCHW ) {
2019-11-03 11:37:19 +01:00
int bS , iC , iH , iW , oC , oH , oW ; // batch size, input channels, input height/width, output channels, output height/width;
int indIOioC , indIiH , indWoC , indWiC , indWkH , indOoH ; // corresponding indexes
2020-01-28 16:23:07 +01:00
ConvolutionUtils : : getSizesAndIndexesConv2d ( isNCHW , * input , * gradO , bS , iC , iH , iW , oC , oH , oW , indIOioC , indIiH , indWiC , indWoC , indWkH , indOoH ) ;
2019-11-03 11:37:19 +01:00
2019-12-03 07:40:45 +01:00
ConvolutionUtils : : calcPadding2D ( pH , pW , oH , oW , iH , iW , kH , kW , sH , sW , dH , dW , paddingMode ) ;
2019-11-03 11:37:19 +01:00
2019-11-20 11:23:08 +01:00
dnnl_memory_desc_t empty ;
2020-01-28 16:23:07 +01:00
dnnl : : memory : : desc conv_src_md ( empty ) , conv_diff_src_md ( empty ) , conv_weights_md ( empty ) , conv_diff_weights_md ( empty ) , conv_bias_md ( empty ) , conv_dst_md ( empty ) ;
dnnl : : memory : : desc user_src_md ( empty ) , user_diff_src_md ( empty ) , user_weights_md ( empty ) , user_diff_weights_md ( empty ) , user_bias_md ( empty ) , user_dst_md ( empty ) ;
2019-11-20 11:23:08 +01:00
dnnl : : memory : : dims conv_strides , conv_padding , conv_padding_r , conv_dilation ;
2020-01-28 16:23:07 +01:00
2019-12-03 07:40:45 +01:00
mkldnnUtils : : getMKLDNNMemoryDescConv2d ( kH , kW , sH , sW , pH , pW , dH , dW , paddingMode , isNCHW ,
2019-11-03 11:37:19 +01:00
bS , iC , iH , iW , oC , oH , oW , input , gradI , weights , gradW ,
gradB , gradO ,
& conv_src_md , & conv_diff_src_md , & conv_weights_md ,
& conv_diff_weights_md , & conv_bias_md , & conv_dst_md ,
& user_src_md , & user_diff_src_md , & user_weights_md ,
& user_diff_weights_md , & user_bias_md , & user_dst_md ,
conv_strides , conv_padding , conv_padding_r , conv_dilation ) ;
auto conv_desc = gradB ! = nullptr
2020-01-28 16:23:07 +01:00
? convolution_forward : : desc ( prop_kind : : forward , algorithm : : convolution_auto , conv_src_md , conv_weights_md , conv_bias_md , conv_dst_md , conv_strides , conv_dilation , conv_padding , conv_padding_r )
: convolution_forward : : desc ( prop_kind : : forward , algorithm : : convolution_auto , conv_src_md , conv_weights_md , conv_dst_md , conv_strides , conv_dilation , conv_padding , conv_padding_r ) ;
auto conv_prim_desc = convolution_forward : : primitive_desc ( conv_desc , mkldnnUtils : : getEngine ( LaunchContext : : defaultContext ( ) - > engine ( ) ) ) ;
auto engine = mkldnnUtils : : getEngine ( LaunchContext : : defaultContext ( ) - > engine ( ) ) ;
dnnl : : stream stream ( engine ) ;
2019-11-03 11:37:19 +01:00
if ( gradW ! = nullptr ) {
2020-01-28 16:23:07 +01:00
auto convW_desc = gradB ! = nullptr ? convolution_backward_weights : : desc ( algorithm : : convolution_auto , conv_src_md , conv_diff_weights_md , conv_bias_md , conv_dst_md , conv_strides , conv_dilation , conv_padding , conv_padding_r )
: convolution_backward_weights : : desc ( algorithm : : convolution_auto , conv_src_md , conv_diff_weights_md , conv_dst_md , conv_strides , conv_dilation , conv_padding , conv_padding_r ) ;
auto convW_prim_desc = convolution_backward_weights : : primitive_desc ( convW_desc , engine , conv_prim_desc ) ;
auto userW_src_memory = dnnl : : memory ( user_src_md , engine , const_cast < NDArray * > ( input ) - > buffer ( ) ) ;
2019-11-20 11:23:08 +01:00
auto userW_weights_memory = dnnl : : memory ( user_diff_weights_md , engine , gradW - > buffer ( ) ) ;
2020-01-28 16:23:07 +01:00
auto userW_dst_memory = dnnl : : memory ( user_dst_md , engine , const_cast < NDArray * > ( gradO ) - > buffer ( ) ) ;
2019-11-03 11:37:19 +01:00
auto convW_src_memory = userW_src_memory ;
2020-01-28 16:23:07 +01:00
2019-11-03 11:37:19 +01:00
if ( convW_prim_desc . src_desc ( ) ! = userW_src_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convW_src_memory = dnnl : : memory ( convW_prim_desc . src_desc ( ) , engine ) ;
2020-01-28 16:23:07 +01:00
reorder ( userW_src_memory , convW_src_memory ) . execute ( stream , userW_src_memory , convW_src_memory ) ;
2019-11-03 11:37:19 +01:00
}
auto convW_weights_memory = userW_weights_memory ;
if ( convW_prim_desc . diff_weights_desc ( ) ! = userW_weights_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convW_weights_memory = dnnl : : memory ( convW_prim_desc . diff_weights_desc ( ) , engine ) ;
2019-09-11 20:50:28 +02:00
}
2019-11-03 11:37:19 +01:00
auto convW_dst_memory = userW_dst_memory ;
if ( convW_prim_desc . diff_dst_desc ( ) ! = userW_dst_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convW_dst_memory = dnnl : : memory ( convW_prim_desc . diff_dst_desc ( ) , engine ) ;
2020-01-28 16:23:07 +01:00
reorder ( userW_dst_memory , convW_dst_memory ) . execute ( stream , userW_dst_memory , convW_dst_memory ) ;
2019-11-03 11:37:19 +01:00
}
if ( gradB ! = nullptr ) {
2020-01-28 16:23:07 +01:00
auto convW_bias_memory = dnnl : : memory ( convW_prim_desc . diff_bias_desc ( ) , engine , gradB - > buffer ( ) ) ;
2019-11-03 11:37:19 +01:00
convolution_backward_weights ( convW_prim_desc ) . execute ( stream ,
2019-11-20 11:23:08 +01:00
{ { DNNL_ARG_SRC , convW_src_memory } ,
{ DNNL_ARG_DIFF_DST , convW_dst_memory } ,
{ DNNL_ARG_DIFF_WEIGHTS , convW_weights_memory } ,
{ DNNL_ARG_DIFF_BIAS , convW_bias_memory } } ) ;
2020-01-28 16:23:07 +01:00
}
else {
2019-11-03 11:37:19 +01:00
convolution_backward_weights ( convW_prim_desc ) . execute ( stream ,
2019-11-20 11:23:08 +01:00
{ { DNNL_ARG_SRC , convW_src_memory } ,
{ DNNL_ARG_DIFF_DST , convW_dst_memory } ,
{ DNNL_ARG_DIFF_WEIGHTS , convW_weights_memory } } ) ;
2019-11-03 11:37:19 +01:00
}
if ( convW_prim_desc . diff_weights_desc ( ) ! = userW_weights_memory . get_desc ( ) ) {
reorder ( convW_weights_memory , userW_weights_memory ) . execute ( stream , convW_weights_memory ,
userW_weights_memory ) ;
}
stream . wait ( ) ;
2019-09-11 20:50:28 +02:00
}
2019-11-03 11:37:19 +01:00
if ( gradI ! = nullptr ) {
2020-01-28 16:23:07 +01:00
auto convI_desc = convolution_backward_data : : desc ( algorithm : : convolution_auto , conv_diff_src_md , conv_weights_md , conv_dst_md , conv_strides , conv_dilation , conv_padding , conv_padding_r ) ;
auto convI_prim_desc = convolution_backward_data : : primitive_desc ( convI_desc , engine , conv_prim_desc ) ;
2019-11-20 11:23:08 +01:00
auto userI_src_memory = dnnl : : memory ( user_diff_src_md , engine , gradI - > buffer ( ) ) ;
2020-01-28 16:23:07 +01:00
auto userI_weights_memory = dnnl : : memory ( user_weights_md , engine , const_cast < NDArray * > ( weights ) - > buffer ( ) ) ;
auto userI_dst_memory = dnnl : : memory ( user_dst_md , engine , const_cast < NDArray * > ( gradO ) - > buffer ( ) ) ;
2019-11-03 11:37:19 +01:00
auto convI_src_memory = userI_src_memory ;
if ( convI_prim_desc . diff_src_desc ( ) ! = userI_src_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convI_src_memory = dnnl : : memory ( convI_prim_desc . diff_src_desc ( ) , engine ) ;
2019-11-03 11:37:19 +01:00
}
auto convI_weights_memory = userI_weights_memory ;
if ( convI_prim_desc . weights_desc ( ) ! = userI_weights_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convI_weights_memory = dnnl : : memory ( convI_prim_desc . weights_desc ( ) , engine ) ;
2020-01-28 16:23:07 +01:00
reorder ( userI_weights_memory , convI_weights_memory ) . execute ( stream , userI_weights_memory , convI_weights_memory ) ;
2019-11-03 11:37:19 +01:00
}
auto convI_dst_memory = userI_dst_memory ;
if ( convI_prim_desc . diff_dst_desc ( ) ! = userI_dst_memory . get_desc ( ) ) {
2019-11-20 11:23:08 +01:00
convI_dst_memory = dnnl : : memory ( convI_prim_desc . diff_dst_desc ( ) , engine ) ;
2020-01-28 16:23:07 +01:00
reorder ( userI_dst_memory , convI_dst_memory ) . execute ( stream , userI_dst_memory , convI_dst_memory ) ;
2019-11-03 11:37:19 +01:00
}
convolution_backward_data ( convI_prim_desc ) . execute ( stream ,
2019-11-20 11:23:08 +01:00
{ { DNNL_ARG_DIFF_DST , convI_dst_memory } ,
{ DNNL_ARG_WEIGHTS , convI_weights_memory } ,
{ DNNL_ARG_DIFF_SRC , convI_src_memory } } ) ;
2019-11-03 11:37:19 +01:00
if ( convI_prim_desc . diff_src_desc ( ) ! = userI_src_memory . get_desc ( ) ) {
2020-01-28 16:23:07 +01:00
reorder ( convI_src_memory , userI_src_memory ) . execute ( stream , convI_src_memory , userI_src_memory ) ;
2019-11-03 11:37:19 +01:00
}
stream . wait ( ) ;
2020-01-28 16:23:07 +01:00
}
}
//////////////////////////////////////////////////////////////////////
PLATFORM_IMPL ( conv2d , ENGINE_CPU ) {
auto input = INPUT_VARIABLE ( 0 ) ; // [bS, iH, iW, iC] (NHWC) or [bS, iC, iH, iW] (NCHW)
auto weights = INPUT_VARIABLE ( 1 ) ; // [kH, kW, iC, oC] always
auto bias = block . width ( ) > 2 ? INPUT_VARIABLE ( 2 ) : nullptr ; // [oC]
auto output = OUTPUT_VARIABLE ( 0 ) ; // [bS, oH, oW, oC] (NHWC) or [bS, oC, oH, oW] (NCHW)
int sH = INT_ARG ( 2 ) ; // strides height
int sW = INT_ARG ( 3 ) ; // strides width
int pH = INT_ARG ( 4 ) ; // paddings height
int pW = INT_ARG ( 5 ) ; // paddings width
int dH = INT_ARG ( 6 ) ; // dilations height
int dW = INT_ARG ( 7 ) ; // dilations width
int paddingMode = INT_ARG ( 8 ) ; // 0-VALID, 1-SAME
bool isNCHW = block . getIArguments ( ) - > size ( ) > 9 ? ! INT_ARG ( 9 ) : 1 ; // INT_ARG(9): 0-NCHW, 1-NHWC
int kH = INT_ARG ( 0 ) > 0 ? INT_ARG ( 0 ) : static_cast < int > ( weights - > sizeAt ( 0 ) ) ; // filter(kernel) height
int kW = INT_ARG ( 1 ) > 0 ? INT_ARG ( 1 ) : static_cast < int > ( weights - > sizeAt ( 1 ) ) ; // filter(kernel) width
conv2dMKLDNN ( block , input , weights , bias , output , kH , kW , sH , sW , pH , pW , dH , dW , paddingMode , isNCHW ) ;
return Status : : OK ( ) ;
}
PLATFORM_CHECK ( conv2d , ENGINE_CPU ) {
// we don't want to use mkldnn if cpu doesn't support avx/avx2
if ( : : optimalLevel ( ) < 2 )
return false ;
auto input = INPUT_VARIABLE ( 0 ) ;
auto weights = INPUT_VARIABLE ( 1 ) ;
// conv2d is only available for float32 dtype
return block . isUseMKLDNN ( ) & & input - > dataType ( ) = = nd4j : : DataType : : FLOAT32 & &
weights - > dataType ( ) = = nd4j : : DataType : : FLOAT32 ;
}
//////////////////////////////////////////////////////////////////////
PLATFORM_IMPL ( conv2d_bp , ENGINE_CPU ) {
auto input = INPUT_VARIABLE ( 0 ) ; // [bS, iH, iW, iC] (NHWC) or [bS, iC, iH, iW] (NCHW)
auto weights = INPUT_VARIABLE ( 1 ) ; // [kH, kW, iC, oC] always
auto bias = block . width ( ) > 3 ? INPUT_VARIABLE ( 2 ) : nullptr ; // [oC]
auto gradO = block . width ( ) > 3 ? INPUT_VARIABLE ( 3 ) : INPUT_VARIABLE ( 2 ) ; // [bS, oH, oW, oC] (NHWC) or [bS, oC, oH, oW] (NCHW), epsilon_next
auto gradI = OUTPUT_VARIABLE ( 0 ) ; // [bS, iH, iW, iC] (NHWC) or [bS, iC, iH, iW] (NCHW), epsilon
auto gradW = OUTPUT_VARIABLE ( 1 ) ; // [kH, kW, iC, oC] always
auto gradB = block . width ( ) > 3 ? OUTPUT_VARIABLE ( 2 ) : nullptr ; // [oC]
int kH = INT_ARG ( 0 ) ; // filter(kernel) height
int kW = INT_ARG ( 1 ) ; // filter(kernel) width
int sH = INT_ARG ( 2 ) ; // strides height
int sW = INT_ARG ( 3 ) ; // strides width
int pH = INT_ARG ( 4 ) ; // paddings height
int pW = INT_ARG ( 5 ) ; // paddings width
int dH = INT_ARG ( 6 ) ; // dilations height
int dW = INT_ARG ( 7 ) ; // dilations width
int paddingMode = INT_ARG ( 8 ) ; // 0-VALID, 1-SAME
int isNCHW = block . getIArguments ( ) - > size ( ) > 9 ? ! INT_ARG ( 9 ) : 1 ; // INT_ARG(9): 0-NCHW, 1-NHWC
REQUIRE_TRUE ( input - > rankOf ( ) = = 4 , 0 , " CUSTOM CONV2D_BP OP: rank of input array must be equal to 4, but got %i instead ! " , input - > rankOf ( ) ) ;
REQUIRE_TRUE ( weights - > rankOf ( ) = = 4 , 0 , " CUSTOM CONV2D_BP OP: rank of weights array must be equal to 4, but got %i instead ! " , weights - > rankOf ( ) ) ;
REQUIRE_TRUE ( gradO - > rankOf ( ) = = 4 , 0 , " CUSTOM CONV2D_BP OP: rank of output's gradients (next epsilon) array must be equal to 4, but got %i instead ! " , gradO - > rankOf ( ) ) ;
conv2dBpMKLDNN ( block , input , weights , bias , gradO , gradI , gradW , gradB , kH , kW , sH , sW , pH , pW , dH , dW , paddingMode , isNCHW ) ;
2019-11-03 11:37:19 +01:00
return Status : : OK ( ) ;
}
2020-01-20 19:32:46 +01:00
PLATFORM_CHECK ( conv2d_bp , ENGINE_CPU ) {
2019-12-03 07:40:45 +01:00
auto input = INPUT_VARIABLE ( 0 ) ; // [bS, iH, iW, iC] (NHWC) or [bS, iC, iH, iW] (NCHW)
auto weights = INPUT_VARIABLE ( 1 ) ; // [kH, kW, iC, oC] always
2019-11-03 11:37:19 +01:00
auto bias = block . width ( ) > 3 ? INPUT_VARIABLE ( 2 ) : nullptr ; // [oC]
2019-12-03 07:40:45 +01:00
auto gradO = block . width ( ) > 3 ? INPUT_VARIABLE ( 3 ) : INPUT_VARIABLE ( 2 ) ; // [bS, oH, oW, oC] (NHWC) or [bS, oC, oH, oW] (NCHW), epsilon_next
2019-11-03 11:37:19 +01:00
2019-12-03 07:40:45 +01:00
auto gradI = OUTPUT_VARIABLE ( 0 ) ; // [bS, iH, iW, iC] (NHWC) or [bS, iC, iH, iW] (NCHW), epsilon
auto gradW = OUTPUT_VARIABLE ( 1 ) ; // [kH, kW, iC, oC] always
2019-11-03 11:37:19 +01:00
auto gradB = block . width ( ) > 3 ? OUTPUT_VARIABLE ( 2 ) : nullptr ; // [oC]
return block . isUseMKLDNN ( ) & &
nd4j : : MKLDNNStream : : isSupported ( { input , weights , bias , gradO , gradI , gradW , gradB } ) ;
}
}
}
2019-09-11 20:50:28 +02:00
}