Commit 4893411b authored by Louis Feng's avatar Louis Feng

added conv+bias backprop mkldnn and op.

parent dc4acb4e
......@@ -104,6 +104,7 @@
#include "ngraph/runtime/cpu/cpu_tensor_view.hpp"
#include "ngraph/runtime/cpu/cpu_tracing.hpp"
#include "ngraph/runtime/cpu/mkldnn_utils.hpp"
#include "ngraph/runtime/cpu/ops/conv_bias.hpp"
#include "ngraph/runtime/cpu/ops/matmul_bias.hpp"
#include "ngraph/runtime/cpu/pass/cpu_fusion.hpp"
#include "ngraph/runtime/cpu/pass/cpu_layout.hpp"
......@@ -216,6 +217,12 @@ static const runtime::cpu::OpMap dispatcher{
&runtime::cpu::CPU_Emitter::emit<op::ConvolutionBackpropFilters>},
{TI(ngraph::op::ConvolutionBackpropData),
&runtime::cpu::CPU_Emitter::emit<op::ConvolutionBackpropData>},
{TI(ngraph::op::ConvolutionBias), &runtime::cpu::CPU_Emitter::emit<op::ConvolutionBias>},
{TI(ngraph::op::ConvolutionBiasBackpropFiltersBias),
&runtime::cpu::CPU_Emitter::emit<op::ConvolutionBiasBackpropFiltersBias>},
// conv+bias backprop for data share the same implementation as conv backprop data
{TI(ngraph::op::ConvolutionBiasBackpropData),
&runtime::cpu::CPU_Emitter::emit<op::ConvolutionBackpropData>},
{TI(ngraph::op::Not), &runtime::cpu::CPU_Emitter::emit<op::Not>},
{TI(ngraph::op::MaxPool), &runtime::cpu::CPU_Emitter::emit<op::MaxPool>},
{TI(ngraph::op::Reverse), &runtime::cpu::CPU_Emitter::emit<op::Reverse>},
......
......@@ -141,3 +141,108 @@ size_t MKLDNNEmitter::build_convolution_forward(const mkldnn::memory::desc& inpu
primitive_deps[conv_index] = {input_data_index, weights_index, bias_index, result_index};
return conv_index;
}
size_t MKLDNNEmitter::build_convolution_backward_data(const mkldnn::memory::desc &in_weights_desc,
const mkldnn::memory::desc &in_delta_desc,
const mkldnn::memory::desc &out_data_delta_desc,
const ngraph::Strides &ng_strides,
const ngraph::Strides &ng_dilation_strides,
const ngraph::CoordinateDiff &ng_padding_below,
const ngraph::CoordinateDiff &ng_padding_above)
{
const size_t in_weights_index = build_memory_primitive(in_weights_desc);
const size_t in_delta_index = build_memory_primitive(in_delta_desc);
const size_t out_data_delta_index = build_memory_primitive(out_data_delta_desc);
mkldnn::memory::dims strides(ng_strides.begin(), ng_strides.end());
mkldnn::memory::dims dilation(ng_dilation_strides.begin(), ng_dilation_strides.end());
mkldnn::memory::dims padding_l(ng_padding_below.begin(), ng_padding_below.end());
mkldnn::memory::dims padding_r(ng_padding_above.begin(), ng_padding_above.end());
mkldnn::convolution_forward::primitive_desc fwd_pd{{mkldnn::prop_kind::forward,
mkldnn::algorithm::convolution_direct,
out_data_delta_desc,
in_weights_desc,
in_delta_desc,
strides,
dilation,
padding_l,
padding_r,
mkldnn::padding_kind::zero},
mkldnn_utils::global_cpu_engine};
mkldnn::convolution_backward_data::primitive_desc bwd_pd{{mkldnn::algorithm::convolution_direct,
out_data_delta_desc,
in_weights_desc,
in_delta_desc,
strides,
dilation,
padding_l,
padding_r,
mkldnn::padding_kind::zero},
mkldnn_utils::global_cpu_engine,
fwd_pd};
const size_t conv_index = insert_primitive(new mkldnn::convolution_backward_data(bwd_pd,
*mkldnn_primitives[in_delta_index],
*mkldnn_primitives[in_weights_index],
*mkldnn_primitives[out_data_delta_index]));
primitive_deps[conv_index] = {in_weights_index, in_delta_index, out_data_delta_index};
return conv_index;
}
size_t MKLDNNEmitter::build_convolution_backward_filters_bias(const mkldnn::memory::desc &in_data_desc,
const mkldnn::memory::desc &in_delta_desc,
const mkldnn::memory::desc &out_weights_delta_desc,
const mkldnn::memory::desc &out_bias_delta_desc,
const ngraph::Strides &ng_strides,
const ngraph::Strides &ng_dilation_strides,
const ngraph::CoordinateDiff &ng_padding_below,
const ngraph::CoordinateDiff &ng_padding_above)
{
const size_t in_data_index = build_memory_primitive(in_data_desc);
const size_t in_delta_index = build_memory_primitive(in_delta_desc);
const size_t out_weights_delta_index = build_memory_primitive(out_weights_delta_desc);
const size_t out_bias_delta_index = build_memory_primitive(out_bias_delta_desc);
mkldnn::memory::dims strides(ng_strides.begin(), ng_strides.end());
mkldnn::memory::dims dilation(ng_dilation_strides.begin(), ng_dilation_strides.end());
mkldnn::memory::dims padding_l(ng_padding_below.begin(), ng_padding_below.end());
mkldnn::memory::dims padding_r(ng_padding_above.begin(), ng_padding_above.end());
mkldnn::convolution_forward::primitive_desc fwd_pd{{mkldnn::prop_kind::forward,
mkldnn::algorithm::convolution_direct,
in_data_desc,
out_weights_delta_desc,
out_bias_delta_desc,
in_delta_desc,
strides,
dilation,
padding_l,
padding_r,
mkldnn::padding_kind::zero},
mkldnn_utils::global_cpu_engine};
mkldnn::convolution_backward_weights::primitive_desc bwd_pd{{mkldnn::algorithm::convolution_direct,
in_data_desc,
out_weights_delta_desc,
out_bias_delta_desc,
in_delta_desc,
strides,
dilation,
padding_l,
padding_r,
mkldnn::padding_kind::zero},
mkldnn_utils::global_cpu_engine,
fwd_pd};
const size_t conv_index = insert_primitive(new mkldnn::convolution_backward_weights(bwd_pd,
*mkldnn_primitives[in_data_index],
*mkldnn_primitives[in_delta_index],
*mkldnn_primitives[out_weights_delta_index],
*mkldnn_primitives[out_bias_delta_index]);
primitive_deps[conv_index] = {in_data_index, in_delta_index, out_weights_delta_index, out_bias_delta_index};
return conv_index;
}
\ No newline at end of file
......@@ -61,6 +61,9 @@ namespace ngraph
const ngraph::CoordinateDiff& padding_below,
const ngraph::CoordinateDiff& padding_above);
/**
* Convolution + bias forward
*/
size_t build_convolution_forward(const mkldnn::memory::desc& input_data_desc,
const mkldnn::memory::desc& weights_desc,
const mkldnn::memory::desc& bias_desc,
......@@ -69,6 +72,28 @@ namespace ngraph
const ngraph::Strides& dilation_strides,
const ngraph::CoordinateDiff& padding_below,
const ngraph::CoordinateDiff& padding_above);
/**
* Convolution backprop for data
*/
size_t build_convolution_backward_data(const mkldnn::memory::desc &in_weights_desc,
const mkldnn::memory::desc &in_delta_desc,
const mkldnn::memory::desc &out_data_delta_desc,
const ngraph::Strides &ng_strides,
const ngraph::Strides &ng_dilation_strides,
const ngraph::CoordinateDiff &ng_padding_below,
const ngraph::CoordinateDiff &ng_padding_above);
/**
* Convolution + bias backprop for filters and bias
*/
size_t build_convolution_backward_filters_bias(const mkldnn::memory::desc& input_data_desc,
const mkldnn::memory::desc& weights_desc,
const mkldnn::memory::desc& out_weights_delta_desc,
const mkldnn::memory::desc& result_desc,
const ngraph::Strides& strides,
const ngraph::Strides& dilation_strides,
const ngraph::CoordinateDiff& padding_below,
const ngraph::CoordinateDiff& padding_above);
private:
std::shared_ptr<CPU_ExternalFunction> external_function;
std::vector<mkldnn::primitive*> mkldnn_primitives;
......
......@@ -17,6 +17,7 @@
#include <numeric>
#include "ngraph/runtime/cpu/ops/conv_bias.hpp"
#include "ngraph/ops/get_output_element.hpp"
#include "ngraph/util.hpp"
using namespace std;
......@@ -78,5 +79,239 @@ std::shared_ptr<Node> op::ConvolutionBias::copy_with_new_args(
void op::ConvolutionBias::generate_adjoints(autodiff::Adjoints& adjoints,
const std::shared_ptr<Node>& delta)
{
throw ngraph_error("Not implemented!");
auto data = get_input_op(0);
const auto data_shape = data->get_shape();
auto filter = get_input_op(1);
const auto filter_shape = filter->get_shape();
auto bias = get_input_op(2);
const auto bias_shape = bias->get_shape();
adjoints.add_delta(data,
std::make_shared<op::ConvolutionBiasBackpropData>(data_shape,
filter,
delta,
m_window_movement_strides,
m_window_dilation_strides,
m_padding_below,
m_padding_above,
m_data_dilation_strides));
auto filter_bias_backprop = std::make_shared<op::ConvolutionBiasBackpropFiltersBias>(data,
filter_shape,
bias_shape,
delta,
m_window_movement_strides,
m_window_dilation_strides,
m_padding_below,
m_padding_above,
m_data_dilation_strides);
auto filter_delta = std::make_shared<op::GetOutputElement>(filter_bias_backprop, 0);
auto bias_delta = std::make_shared<op::GetOutputElement>(filter_bias_backprop, 1);
adjoints.add_delta(filter, filter_delta);
adjoints.add_delta(bias, bias_delta);
}
op::ConvolutionBiasBackpropData::ConvolutionBiasBackpropData(const Shape& data_batch_shape,
const std::shared_ptr<Node>& filters,
const std::shared_ptr<Node>& output_delta,
const Strides& window_movement_strides_forward,
const Strides& window_dilation_strides_forward,
const CoordinateDiff& padding_below_forward,
const CoordinateDiff& padding_above_forward,
const Strides& data_dilation_strides_forward)
: RequiresTensorViewArgs("ConvolutionBackpropData", {filters, output_delta})
, m_data_batch_shape(data_batch_shape)
, m_window_movement_strides_forward(window_movement_strides_forward)
, m_window_dilation_strides_forward(window_dilation_strides_forward)
, m_padding_below_forward(padding_below_forward)
, m_padding_above_forward(padding_above_forward)
, m_data_dilation_strides_forward(data_dilation_strides_forward)
{
auto& filters_shape = get_input_shape(0);
auto& filters_et = get_input_element_type(0);
auto& output_delta_shape = get_input_shape(0);
auto& output_delta_et = get_input_element_type(1);
//
// Make sure filter and output delta element types match.
//
if (filters_et != output_delta_et)
{
throw ngraph_error(
"Convolution data batch backprop filter and output delta element types do not match");
}
// Forward Backward
// Window movement strides q p_x
// Window dilation strides p_f p_f
// Padding below a_x (S_F - 1)p_f - a_x
// Padding above b_x (S_f - 1)p_f + ((a_x + (S_x - 1)p_x + b_x - (S_f - 1)p_f) % q) - b_x
// Data dilation strides p_x q
for (size_t i = 0; i < data_batch_shape.size() - 2; i++)
{
m_window_movement_strides_backward.push_back(data_dilation_strides_forward[i]);
m_window_dilation_strides_backward.push_back(window_dilation_strides_forward[i]);
m_padding_below_backward.push_back((filters_shape[i + 2] - 1) *
window_dilation_strides_forward[i] -
padding_below_forward[i]);
m_padding_above_backward.push_back(
(filters_shape[i + 2] - 1) * window_dilation_strides_forward[i] +
((padding_below_forward[i] +
(data_batch_shape[i + 2] - 1) * data_dilation_strides_forward[i] +
padding_above_forward[i] -
(filters_shape[i + 2] - 1) * window_dilation_strides_forward[i]) %
window_movement_strides_forward[i]) -
padding_above_forward[i]);
m_data_dilation_strides_backward.push_back(window_movement_strides_forward[i]);
}
// Shape inferred_convolution_output_shape =
// infer_convolution_output_shape(output_delta_shape,
// filters_shape,
// m_window_movement_strides_backward,
// m_window_dilation_strides_backward,
// m_padding_below_backward,
// m_padding_above_backward,
// m_data_dilation_strides_backward,
// 0,
// 1,
// 0,
// 1,
// 0,
// 1,
// "In ConvolutionBiasBackpropData: ");
//
// // Not sure if this can ever actually happen (i.e., I think it will trip on something else
// // inside infer_convolution_output_shape before we get here) but it seems worth checking.
// if (inferred_convolution_output_shape != data_batch_shape)
// {
// throw ngraph_error(
// "Convolution data batch backprop inferred output shape does not match "
// "specified data batch shape");
// }
set_value_type_checked(filters_et, data_batch_shape);
}
std::shared_ptr<Node> op::ConvolutionBiasBackpropData::copy_with_new_args(
const std::vector<std::shared_ptr<Node>>& new_args) const
{
if (new_args.size() != 2)
{
throw ngraph_error("Incorrect number of new arguments");
}
return std::make_shared<ConvolutionBiasBackpropData>(m_data_batch_shape,
new_args.at(0),
new_args.at(1),
m_window_movement_strides_forward,
m_window_dilation_strides_forward,
m_padding_below_forward,
m_padding_above_forward,
m_data_dilation_strides_forward);
}
op::ConvolutionBiasBackpropFiltersBias::ConvolutionBiasBackpropFiltersBias(
const std::shared_ptr<Node>& data_batch,
const Shape& filters_shape,
const Shape& bias_shape,
const std::shared_ptr<Node>& output_delta,
const Strides& window_movement_strides_forward,
const Strides& window_dilation_strides_forward,
const CoordinateDiff& padding_below_forward,
const CoordinateDiff& padding_above_forward,
const Strides& data_dilation_strides_forward)
: RequiresTensorViewArgs("ConvolutionBackpropFilters", {data_batch, output_delta})
, m_filters_shape(filters_shape)
, m_window_movement_strides_forward(window_movement_strides_forward)
, m_window_dilation_strides_forward(window_dilation_strides_forward)
, m_padding_below_forward(padding_below_forward)
, m_padding_above_forward(padding_above_forward)
, m_data_dilation_strides_forward(data_dilation_strides_forward)
{
auto& data_batch_shape = get_input_shape(0);
auto& data_batch_et = get_input_element_type(0);
auto& output_delta_shape = get_input_shape(1);
auto& output_delta_et = get_input_element_type(1);
//
// Make sure data batch and output delta element types match.
//
if (data_batch_et != output_delta_et)
{
throw ngraph_error(
"ConvolutionBias filter backprop data batch and output delta element types do not match");
}
// Forward Backward
// Window movement strides q p_f
// Window dilation strides p_f q
// Padding below a_x a_x
// Padding above b_x b_x - (a_x + (S_x - 1)p_x + b_x - (S_f - 1)p_f) % q
// Data dilation strides p_x p_x
for (size_t i = 0; i < filters_shape.size() - 2; i++)
{
m_window_movement_strides_backward.push_back(window_dilation_strides_forward[i]);
m_window_dilation_strides_backward.push_back(window_movement_strides_forward[i]);
m_padding_below_backward.push_back(padding_below_forward[i]);
m_padding_above_backward.push_back(
padding_above_forward[i] -
(padding_below_forward[i] +
(data_batch_shape[i + 2] - 1) * data_dilation_strides_forward[i] +
padding_above_forward[i] -
(filters_shape[i + 2] - 1) * window_dilation_strides_forward[i]) %
window_movement_strides_forward[i]);
m_data_dilation_strides_backward.push_back(data_dilation_strides_forward[i]);
}
// Shape inferred_convolution_filters_shape =
// infer_convolution_output_shape(data_batch_shape,
// filters_delta_shape,
// m_window_movement_strides_backward,
// m_window_dilation_strides_backward,
// m_padding_below_backward,
// m_padding_above_backward,
// m_data_dilation_strides_backward,
// 1,
// 0,
// 0,
// 1,
// 1,
// 0,
// "In ConvolutionBiasBackpropFiltersBias: ");
//
// // Not sure if this can ever actually happen (i.e., I think it will trip on something else
// // inside infer_convolution_output_shape before we get here) but it seems worth checking.
// if (inferred_convolution_filters_shape != filters_shape)
// {
// throw ngraph_error(
// "ConvolutionBias filter bias backprop inferred output shape does not match "
// "specified filter shape");
// }
add_output(data_batch_et, filters_shape);
add_output(data_batch_et, bias_shape);
}
std::shared_ptr<Node> op::ConvolutionBiasBackpropFiltersBias::copy_with_new_args(
const std::vector<std::shared_ptr<Node>>& new_args) const
{
if (new_args.size() != 2)
{
throw ngraph_error("Incorrect number of new arguments");
}
return std::make_shared<ConvolutionBiasBackpropFiltersBias>(new_args.at(0),
m_filters_shape,
m_bias_shape,
new_args.at(1),
m_window_movement_strides_forward,
m_window_dilation_strides_forward,
m_padding_below_forward,
m_padding_above_forward,
m_data_dilation_strides_forward);
}
......@@ -60,5 +60,197 @@ namespace ngraph
const CoordinateDiff& padding_above,
const Strides& data_dilation_strides);
};
/// \brief Data batch backprop for batched convolution + bias operation.
class ConvolutionBiasBackpropData : public util::RequiresTensorViewArgs
{
public:
/// \brief Constructs a batched-convolution data batch-backprop operation.
///
/// \param data_batch_shape The shape of the data batch from forward-prop.
/// \param filters The node producing the filters from forward-prop.
/// \param output_delta The node producing output delta.
/// \param window_movement_strides_forward The window movement strides from forward-prop.
/// \param window_dilation_strides_forward The window dilation strides from forward-prop.
/// \param padding_below_forward The padding-below sizes from forward-prop.
/// \param padding_above_forward The padding-above sizes from forward-prop.
/// \param data_dilation_strides_forward The data dilation strides from forward-prop.
ConvolutionBiasBackpropData(const Shape& data_batch_shape,
const std::shared_ptr<Node>& filters,
const std::shared_ptr<Node>& output_delta,
const Strides& window_movement_strides_forward,
const Strides& window_dilation_strides_forward,
const CoordinateDiff& padding_below_forward,
const CoordinateDiff& padding_above_forward,
const Strides& data_dilation_strides_forward);
virtual std::shared_ptr<Node> copy_with_new_args(
const std::vector<std::shared_ptr<Node>>& new_args) const override;
/// \return The data batch shape.
const Shape& get_data_batch_shape() const { return m_data_batch_shape; }
/// \return The window movement strides from the forward prop.
const Strides& get_window_movement_strides_forward() const
{
return m_window_movement_strides_forward;
}
/// \return The window dilation strides from the forward prop.
const Strides& get_window_dilation_strides_forward() const
{
return m_window_dilation_strides_forward;
}
/// \return The padding-below sizes (possibly negative) from the forward prop.
const CoordinateDiff& get_padding_below_forward() const
{
return m_padding_below_forward;
}
/// \return The padding-above sizes (possibly negative) from the forward prop.
const CoordinateDiff& get_padding_above_forward() const
{
return m_padding_above_forward;
}
/// \return The input data dilation strides from the forward prop.
const Strides& get_data_dilation_strides_forward() const
{
return m_data_dilation_strides_forward;
}
/// \return The window movement strides for the backward prop.
const Strides& get_window_movement_strides_backward() const
{
return m_window_movement_strides_backward;
}
/// \return The window dilation strides for the backward prop.
const Strides& get_window_dilation_strides_backward() const
{
return m_window_dilation_strides_backward;
}
/// \return The padding-below sizes (possibly negative) for the backward prop.
const CoordinateDiff& get_padding_below_backward() const
{
return m_padding_below_backward;
}
/// \return The padding-above sizes (possibly negative) for the backward prop.
const CoordinateDiff& get_padding_above_backward() const
{
return m_padding_above_backward;
}
/// \return The input data dilation strides for the backward prop.
const Strides& get_data_dilation_strides_backward() const
{
return m_data_dilation_strides_backward;
}
protected:
Shape m_data_batch_shape;
Strides m_window_movement_strides_forward;
Strides m_window_dilation_strides_forward;
CoordinateDiff m_padding_below_forward;
CoordinateDiff m_padding_above_forward;
Strides m_data_dilation_strides_forward;
Strides m_window_movement_strides_backward;
Strides m_window_dilation_strides_backward;
CoordinateDiff m_padding_below_backward;
CoordinateDiff m_padding_above_backward;
Strides m_data_dilation_strides_backward;
};
/// \brief Filters and bias backprop for batched convolution operation.
class ConvolutionBiasBackpropFiltersBias : public util::RequiresTensorViewArgs
{
public:
/// \brief Constructs a batched-convolution filter-backprop operation.
///
/// \param data_batch The tensor producing the data batch from forward-prop.
/// \param filters_shape The shape of the filters from forward-prop.
/// \param output_delta The node producing output delta.
/// \param window_movement_strides_forward The window movement strides from forward-prop.
/// \param window_dilation_strides_forward The window dilation strides from forward-prop.
/// \param padding_below_forward The padding-below sizes from forward-prop.
/// \param padding_above_forward The padding-above sizes from forward-prop.
/// \param data_dilation_strides_forward The data dilation strides from forward-prop.
ConvolutionBiasBackpropFiltersBias(const std::shared_ptr<Node>& data_batch,
const Shape& filters_shape,
const Shape& bias_shape,
const std::shared_ptr<Node>& output_delta,
const Strides& window_movement_strides_forward,
const Strides& window_dilation_strides_forward,
const CoordinateDiff& padding_below_forward,
const CoordinateDiff& padding_above_forward,
const Strides& data_dilation_strides_forward);
virtual std::shared_ptr<Node> copy_with_new_args(
const std::vector<std::shared_ptr<Node>>& new_args) const override;
/// \return The filters tensor shape.
const Shape& get_filters_shape() const { return m_filters_shape; }
/// \return The window movement strides from the forward prop.
const Strides& get_window_movement_strides_forward() const
{
return m_window_movement_strides_forward;
}
/// \return The window dilation strides from the forward prop.
const Strides& get_window_dilation_strides_forward() const
{
return m_window_dilation_strides_forward;
}
/// \return The padding-below sizes (possibly negative) from the forward prop.
const CoordinateDiff& get_padding_below_forward() const
{
return m_padding_below_forward;
}
/// \return The padding-above sizes (possibly negative) from the forward prop.
const CoordinateDiff& get_padding_above_forward() const
{
return m_padding_above_forward;
}
/// \return The data dilation strides from the forward prop.
const Strides& get_data_dilation_strides_forward() const
{
return m_data_dilation_strides_forward;
}
/// \return The window movement strides for the backward prop.
const Strides& get_window_movement_strides_backward() const
{
return m_window_movement_strides_backward;
}
/// \return The window dilation strides for the backward prop.
const Strides& get_window_dilation_strides_backward() const
{
return m_window_dilation_strides_backward;
}
/// \return The padding-below sizes (possibly negative) for the backward prop.
const CoordinateDiff& get_padding_below_backward() const
{
return m_padding_below_backward;
}
/// \return The padding-above sizes (possibly negative) for the backward prop.
const CoordinateDiff& get_padding_above_backward() const
{
return m_padding_above_backward;
}
/// \return The data dilation strides for the backward prop.
const Strides& get_data_dilation_strides_backward() const
{
return m_data_dilation_strides_backward;
}
protected:
Shape m_filters_shape;
Shape m_bias_shape;
Strides m_window_movement_strides_forward;
Strides m_window_dilation_strides_forward;
CoordinateDiff m_padding_below_forward;
CoordinateDiff m_padding_above_forward;
Strides m_data_dilation_strides_forward;
Strides m_window_movement_strides_backward;
Strides m_window_dilation_strides_backward;
CoordinateDiff m_padding_below_backward;
CoordinateDiff m_padding_above_backward;
Strides m_data_dilation_strides_backward;
};
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment