From a16b390b5dec921865ccf0f3307626e43d446838 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Dmitry=20Mozolev/AI=20Tools=20Lab=20/SRR/Engineer/=EC=82=BC?= =?utf8?q?=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Sun, 15 Jul 2018 09:34:05 +0300 Subject: [PATCH] Add implementation of Caffe to Model IR converter (#640) Add Caffe layer to Model IR converter skeleton Added a class for converting Caffe layers to Model IR operations. Signed-off-by: Dmitry Mozolev --- .../libs/frontend/caffe/src/caffe_op_creator.cpp | 121 +++++++++++++++++---- 1 file changed, 98 insertions(+), 23 deletions(-) diff --git a/contrib/nnc/libs/frontend/caffe/src/caffe_op_creator.cpp b/contrib/nnc/libs/frontend/caffe/src/caffe_op_creator.cpp index 35f7556..caf9040 100644 --- a/contrib/nnc/libs/frontend/caffe/src/caffe_op_creator.cpp +++ b/contrib/nnc/libs/frontend/caffe/src/caffe_op_creator.cpp @@ -260,64 +260,139 @@ __attribute__ ((unused)) static int getAxisValue(const OptsType& opts) std::vector OpCreator::createConv2D(InputOps inputs, InputParams params, const caffe::ConvolutionParameter& opts) { - (void)inputs; - (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + assert(opts.pad_size() <= 2); + assert(opts.stride_size() <= 2); + + ops::PaddingType padType = util::getConvPadType(opts); + Shape strideShape = util::getConvStride(opts); + + auto outputs = createOp(inputs, std::move(*params[0]), + strideShape, padType); + + // bias_term is optional (so might not be present) and defaults to true + if (!opts.has_bias_term() || opts.bias_term()) + return createOp(outputs, std::move(*params[1])); + else + return outputs; } +/** + * @brief Converts Caffe InnerProduct layer to Model IR FullyConnected operation. + * @todo InnerProduct layer take NCHW input and flattens the CHW part. We insert the + * Model IR Reshape operation here to account for that, but its result may not be + * equivalent to how Caffe flattens inputs. Need to check how Caffe does this and + * implement it correctly. + * @todo Support axis and transpose parameters as needed. + */ std::vector OpCreator::createFullyConnected(InputOps &inputs, InputParams ¶ms, const caffe::InnerProductParameter &opts) { - (void)inputs; - (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + if (opts.has_axis() && opts.axis() != 1) + { + throw PluginException("InnerProduct layer axis param is not supported yet"); + } + + if (opts.has_transpose() && opts.transpose()) + { + throw PluginException("InnerProduct layer transpose param is not supported yet"); + } + + // Add Reshape operation to make sure the input for FC operation has shape [1, fcInputSize] + // It is needed because Caffe InnerProduct layer takes NCHW input and flattens the CHW part. + auto outputs = createOp(inputs); + uint32_t fcInputSize = static_cast( + num_elements(params[0]->getShape())) / opts.num_output(); + outputs[0]->getOperation()->setOutputShape(0, {1, fcInputSize}); + + auto fcOutputs = createOp(outputs, std::move(*params[0])); + + // bias_term is optional (so might not be present) and defaults to true + if (!opts.has_bias_term() || opts.bias_term()) + return createOp(fcOutputs, std::move(*params[1])); + else + return outputs; } std::vector OpCreator::createConcat(InputOps inputs, InputParams params, const caffe::ConcatParameter& opts) { - (void)inputs; (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + + return createOp(inputs, inputs.size(), util::getAxisValue(opts)); } std::vector OpCreator::createPool(InputOps inputs, InputParams params, const caffe::PoolingParameter& opts) { - (void)inputs; (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + + if (opts.has_global_pooling() && opts.global_pooling()) + { + throw PluginException("Pooling layer global_pooling param is not supported yet"); + } + + Shape windowShape = util::getPoolWindowShape(opts); + ops::PoolOp::PoolingType poolType = util::getPoolingType(opts); + ops::PaddingType padType = util::getPoolPadType(opts); + Shape stride = util::getPoolStride(opts); + + return createOp(inputs, windowShape, stride, poolType, padType); } std::vector OpCreator::createSoftmax(InputOps inputs, InputParams params, const caffe::SoftmaxParameter& opts) { - (void)inputs; (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + + return createOp(inputs, util::getAxisValue(opts)); } +/** + * @brief Converts Caffe Reshape layer to Model IR Reshape operation. + * @todo Support "axis" and "num_axes" parameters as needed. + * @todo Decide how to react to the absence of "shape" parameter. + * @todo Support zero values in "shape" parameter. + */ std::vector OpCreator::createReshape(InputOps inputs, InputParams params, const caffe::ReshapeParameter& opts) { - (void)inputs; (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + + auto outputs = createOp(inputs); + + if (opts.has_axis() || opts.has_num_axes()) + { + throw PluginException("Reshape layer axis and num_axes params are not supported yet"); + } + + if (!opts.has_shape()) + { + throw PluginException("Reshape layer doesn't have shape parameter"); + } + + Shape newShape = common::ShapeHelper::createShape(opts.shape().dim(), opts.shape().dim_size()); + + for (unsigned int i = 0; i < newShape.rank(); ++i) + { + if (newShape.dim(i) == 0) + throw PluginException("Reshape layer zero shape values are not supported yet"); + } + + outputs[0]->getOperation()->setOutputShape(0, newShape); + return outputs; } std::vector OpCreator::createRelu(InputOps inputs, InputParams params, const caffe::ReLUParameter& opts) { - (void)inputs; (void)params; - (void)opts; - throw std::runtime_error("Not yet implemented"); + + if (opts.has_negative_slope()) + { + throw PluginException("ReLU layer negative_slope param is not supported yet."); + } + + return createOp(inputs); } void OpCreator::connectInputs(INode::Ref op, InputOps inputs) -- 2.7.4