Unverified Commit c5144d48 authored by Adam Procter's avatar Adam Procter Committed by GitHub

Negative convolution padding (#396)

parent 68ef3faa
# API Changes # API Changes
`Parameter` and `Function` no longer take a type argument.
## Negative convolution padding
`Convolution` now allows negative padding. This means that the `padding_below` and `padding_above`
arguments now take type `CoordinateDiff` instead of `Shape`. `CoordinateDiff` is an alias for
`std::vector<std::ptrdiff_t>`, which "is like `size_t` but is allowed to be negative". Callers may
need to be adapted.
## `Parameter` and `Function` no longer take a type argument.
To update, remove the passed argument. For example, To update, remove the passed argument. For example,
```C++ ```C++
// Old // Old
......
...@@ -53,6 +53,13 @@ namespace ngraph ...@@ -53,6 +53,13 @@ namespace ngraph
/// @brief Strides of a tensor /// @brief Strides of a tensor
using Strides = std::vector<size_t>; using Strides = std::vector<size_t>;
/// @brief A coordinate-like type whose elements are allowed to be
/// negative.
///
/// Currently used only to express negative padding; in the future,
/// could conceivably be used to express
using CoordinateDiff = std::vector<std::ptrdiff_t>;
Coordinate project_coordinate(const Coordinate& coord, const AxisSet& deleted_axes); Coordinate project_coordinate(const Coordinate& coord, const AxisSet& deleted_axes);
Shape project_shape(const Shape& shape, const AxisSet& deleted_axes); Shape project_shape(const Shape& shape, const AxisSet& deleted_axes);
......
...@@ -30,8 +30,8 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape, ...@@ -30,8 +30,8 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape,
const Coordinate& source_end_corner, const Coordinate& source_end_corner,
const Strides& source_strides, const Strides& source_strides,
const AxisVector& source_axis_order, const AxisVector& source_axis_order,
const Shape& target_padding_below, const CoordinateDiff& target_padding_below,
const Shape& target_padding_above, const CoordinateDiff& target_padding_above,
const Strides& target_dilation_strides) const Strides& target_dilation_strides)
: m_source_shape(source_shape) : m_source_shape(source_shape)
, m_source_start_corner(source_start_corner) , m_source_start_corner(source_start_corner)
...@@ -96,48 +96,61 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape, ...@@ -96,48 +96,61 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape,
for (size_t i = 0; i < m_n_axes; i++) for (size_t i = 0; i < m_n_axes; i++)
{ {
if (source_start_corner[i] >= (source_shape[i] - 1) * target_dilation_strides[i] + 1 + if (target_dilation_strides[i] == 0)
target_padding_below[i] + target_padding_above[i] &&
!(source_start_corner[i] == 0 && source_shape[i] == 0))
{ {
std::stringstream ss; std::stringstream ss;
ss << "The start corner is out of bounds at axis " << i; ss << "The target dilation stride is 0 at axis " << i;
throw std::domain_error(ss.str()); throw std::domain_error(ss.str());
} }
} }
std::vector<std::ptrdiff_t> padded_upper_bounds;
for (size_t i = 0; i < m_n_axes; i++) for (size_t i = 0; i < m_n_axes; i++)
{ {
if (source_end_corner[i] > std::ptrdiff_t padded_upper_bound =
subtract_or_zero(source_shape[i], size_t(1)) * target_dilation_strides[i] + 1 + subtract_or_zero(source_shape[i], size_t(1)) * target_dilation_strides[i] + 1 +
target_padding_below[i] + target_padding_above[i]) target_padding_below[i] + target_padding_above[i];
if (padded_upper_bound < 0)
{ {
std::stringstream ss; std::stringstream ss;
ss << "The end corner is out of bounds at axis " << i; ss << "The end corner is out of bounds at axis " << i;
throw std::domain_error(ss.str()); throw std::domain_error(ss.str());
} }
padded_upper_bounds.push_back(padded_upper_bound);
} }
for (size_t i = 0; i < m_n_axes; i++) for (size_t i = 0; i < m_n_axes; i++)
{ {
if (source_strides[i] == 0) if (source_start_corner[i] >= padded_upper_bounds[i] &&
!(source_start_corner[i] == 0 && source_shape[i] == 0))
{ {
std::stringstream ss; std::stringstream ss;
ss << "The source stride is 0 at axis " << i; ss << "The start corner is out of bounds at axis " << i;
throw std::domain_error(ss.str());
}
if (source_end_corner[i] > padded_upper_bounds[i])
{
std::stringstream ss;
ss << "The end corner is out of bounds at axis " << i;
throw std::domain_error(ss.str()); throw std::domain_error(ss.str());
} }
} }
for (size_t i = 0; i < m_n_axes; i++) for (size_t i = 0; i < m_n_axes; i++)
{ {
if (target_dilation_strides[i] == 0) if (source_strides[i] == 0)
{ {
std::stringstream ss; std::stringstream ss;
ss << "The target dilation stride is 0 at axis " << i; ss << "The source stride is 0 at axis " << i;
throw std::domain_error(ss.str()); throw std::domain_error(ss.str());
} }
} }
...@@ -160,8 +173,8 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape, ...@@ -160,8 +173,8 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape,
const Coordinate& source_end_corner, const Coordinate& source_end_corner,
const Strides& source_strides, const Strides& source_strides,
const AxisVector& source_axis_order, const AxisVector& source_axis_order,
const Shape& target_padding_below, const CoordinateDiff& target_padding_below,
const Shape& target_padding_above) const CoordinateDiff& target_padding_above)
: CoordinateTransform(source_shape, : CoordinateTransform(source_shape,
source_start_corner, source_start_corner,
source_end_corner, source_end_corner,
...@@ -173,9 +186,9 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape, ...@@ -173,9 +186,9 @@ CoordinateTransform::CoordinateTransform(const Shape& source_shape,
{ {
} }
Shape CoordinateTransform::default_padding(size_t n_axes) CoordinateDiff CoordinateTransform::default_padding(size_t n_axes)
{ {
return Shape(n_axes, 0); return CoordinateDiff(n_axes, 0);
} }
CoordinateTransform::CoordinateTransform(const Shape& source_shape, CoordinateTransform::CoordinateTransform(const Shape& source_shape,
...@@ -321,18 +334,18 @@ bool CoordinateTransform::has_source_coordinate(const Coordinate& c_target) cons ...@@ -321,18 +334,18 @@ bool CoordinateTransform::has_source_coordinate(const Coordinate& c_target) cons
// The rest of this is a replay of the corresponding logic in `to_source_coordinate`, with // The rest of this is a replay of the corresponding logic in `to_source_coordinate`, with
// bounds and divisibility checking. // bounds and divisibility checking.
size_t source_axis = m_source_axis_order[target_axis]; std::ptrdiff_t source_axis = m_source_axis_order[target_axis];
size_t target_pos = c_target[target_axis]; std::ptrdiff_t target_pos = c_target[target_axis];
size_t pos_destrided = target_pos * m_source_strides[source_axis]; std::ptrdiff_t pos_destrided = target_pos * m_source_strides[source_axis];
size_t pos_deshifted = pos_destrided + m_source_start_corner[source_axis]; std::ptrdiff_t pos_deshifted = pos_destrided + m_source_start_corner[source_axis];
// If we are in the below-padding or the above-padding. // If we are in the below-padding or the above-padding.
if (pos_deshifted < m_target_padding_below[target_axis]) if (pos_deshifted < m_target_padding_below[target_axis])
{ {
return false; return false;
} }
size_t pos_depadded = pos_deshifted - m_target_padding_below[target_axis]; std::ptrdiff_t pos_depadded = pos_deshifted - m_target_padding_below[target_axis];
// If we are in the above-padding, we have no source coordinate. // If we are in the above-padding, we have no source coordinate.
if (m_source_shape[source_axis] == 0 || if (m_source_shape[source_axis] == 0 ||
......
...@@ -31,8 +31,8 @@ namespace ngraph ...@@ -31,8 +31,8 @@ namespace ngraph
const Coordinate& source_end_corner, const Coordinate& source_end_corner,
const Strides& source_strides, const Strides& source_strides,
const AxisVector& source_axis_order, const AxisVector& source_axis_order,
const Shape& target_padding_below, const CoordinateDiff& target_padding_below,
const Shape& target_padding_above, const CoordinateDiff& target_padding_above,
const Strides& source_dilation_strides); const Strides& source_dilation_strides);
CoordinateTransform(const Shape& source_shape, CoordinateTransform(const Shape& source_shape,
...@@ -40,8 +40,8 @@ namespace ngraph ...@@ -40,8 +40,8 @@ namespace ngraph
const Coordinate& source_end_corner, const Coordinate& source_end_corner,
const Strides& source_strides, const Strides& source_strides,
const AxisVector& source_axis_order, const AxisVector& source_axis_order,
const Shape& target_padding_below, const CoordinateDiff& target_padding_below,
const Shape& target_padding_above); const CoordinateDiff& target_padding_above);
CoordinateTransform(const Shape& source_shape, CoordinateTransform(const Shape& source_shape,
const Coordinate& source_start_corner, const Coordinate& source_start_corner,
...@@ -96,7 +96,7 @@ namespace ngraph ...@@ -96,7 +96,7 @@ namespace ngraph
private: private:
size_t index_source(const Coordinate& c) const; size_t index_source(const Coordinate& c) const;
static Strides default_strides(size_t n_axes); static Strides default_strides(size_t n_axes);
static Shape default_padding(size_t n_axes); static CoordinateDiff default_padding(size_t n_axes);
static AxisVector default_axis_order(size_t n_axes); static AxisVector default_axis_order(size_t n_axes);
static Coordinate default_source_start_corner(size_t n_axes); static Coordinate default_source_start_corner(size_t n_axes);
static Coordinate default_source_end_corner(const Shape& source_shape); static Coordinate default_source_end_corner(const Shape& source_shape);
...@@ -106,8 +106,8 @@ namespace ngraph ...@@ -106,8 +106,8 @@ namespace ngraph
Shape m_source_end_corner; Shape m_source_end_corner;
Strides m_source_strides; Strides m_source_strides;
AxisVector m_source_axis_order; AxisVector m_source_axis_order;
Shape m_target_padding_below; CoordinateDiff m_target_padding_below;
Shape m_target_padding_above; CoordinateDiff m_target_padding_above;
Strides m_target_dilation_strides; Strides m_target_dilation_strides;
Shape m_target_shape; Shape m_target_shape;
......
...@@ -22,8 +22,8 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch, ...@@ -22,8 +22,8 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch,
const std::shared_ptr<Node>& filters, const std::shared_ptr<Node>& filters,
const Strides& window_movement_strides, const Strides& window_movement_strides,
const Strides& window_dilation_strides, const Strides& window_dilation_strides,
const Shape& padding_below, const CoordinateDiff& padding_below,
const Shape& padding_above, const CoordinateDiff& padding_above,
const Strides& image_dilation_strides) const Strides& image_dilation_strides)
: RequiresTensorViewArgs("Convolution", {image_batch, filters}) : RequiresTensorViewArgs("Convolution", {image_batch, filters})
, m_window_movement_strides(window_movement_strides) , m_window_movement_strides(window_movement_strides)
...@@ -128,7 +128,16 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch, ...@@ -128,7 +128,16 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch,
size_t dim_size = image_batch_shape[1 + 1 + i]; size_t dim_size = image_batch_shape[1 + 1 + i];
m_input_image_physical_shape.push_back(dim_size); m_input_image_physical_shape.push_back(dim_size);
size_t dilated_dim_size = (dim_size - 1) * image_dilation_strides[i] + 1; size_t dilated_dim_size = (dim_size - 1) * image_dilation_strides[i] + 1;
size_t padded_dilated_dim_size = padding_below[i] + dilated_dim_size + padding_above[i];
std::ptrdiff_t padded_dilated_dim_size =
padding_below[i] + dilated_dim_size + padding_above[i];
if (padded_dilated_dim_size < 0)
{
throw ngraph_error(
"Convolution input image dimension after padding and dilation is negative.");
}
m_input_image_virtual_shape.push_back(padded_dilated_dim_size); m_input_image_virtual_shape.push_back(padded_dilated_dim_size);
if (m_input_image_virtual_shape[i] == 0) if (m_input_image_virtual_shape[i] == 0)
...@@ -214,8 +223,8 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch, ...@@ -214,8 +223,8 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch,
const std::shared_ptr<Node>& filters, const std::shared_ptr<Node>& filters,
const Strides& window_movement_strides, const Strides& window_movement_strides,
const Strides& window_dilation_strides, const Strides& window_dilation_strides,
const Shape& padding_below, const CoordinateDiff& padding_below,
const Shape& padding_above) const CoordinateDiff& padding_above)
: Convolution(image_batch, : Convolution(image_batch,
filters, filters,
window_movement_strides, window_movement_strides,
...@@ -226,7 +235,7 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch, ...@@ -226,7 +235,7 @@ op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch,
{ {
} }
Shape op::Convolution::default_padding(const std::shared_ptr<Node>& image_batch) CoordinateDiff op::Convolution::default_padding(const std::shared_ptr<Node>& image_batch)
{ {
auto& image_batch_shape = image_batch->get_shape(); auto& image_batch_shape = image_batch->get_shape();
if (image_batch_shape.size() < 3) if (image_batch_shape.size() < 3)
...@@ -236,7 +245,7 @@ Shape op::Convolution::default_padding(const std::shared_ptr<Node>& image_batch) ...@@ -236,7 +245,7 @@ Shape op::Convolution::default_padding(const std::shared_ptr<Node>& image_batch)
"Convolution image batch input must have rank of at least 3 (one batch axis, one " "Convolution image batch input must have rank of at least 3 (one batch axis, one "
"input-channel axis, at least one image dimension)."); "input-channel axis, at least one image dimension).");
} }
return Shape(image_batch_shape.size() - 2, 0); return CoordinateDiff(image_batch_shape.size() - 2, 0);
} }
op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch, op::Convolution::Convolution(const std::shared_ptr<Node>& image_batch,
......
...@@ -34,8 +34,8 @@ namespace ngraph ...@@ -34,8 +34,8 @@ namespace ngraph
/// ///
/// 3. <i>(the window movement strides)</i> a vector of positive integers \f$(s_1,\dots,s_n)\f$ (default is all ones), /// 3. <i>(the window movement strides)</i> a vector of positive integers \f$(s_1,\dots,s_n)\f$ (default is all ones),
/// 4. <i>(the window dilation strides)</i> a vector of positive integers \f$(l_1,\dots,l_n)\f$ (default is all ones), /// 4. <i>(the window dilation strides)</i> a vector of positive integers \f$(l_1,\dots,l_n)\f$ (default is all ones),
/// 5. <i>(the padding below)</i> a vector of non-negative integers \f$(p_1,\dots,p_n)\f$ (default is all zeros), /// 5. <i>(the padding below)</i> a vector of (possibly negative) integers \f$(p_1,\dots,p_n)\f$ (default is all zeros),
/// 6. <i>(the padding above)</i> a vector of non-negative integers \f$(q_1,\dots,q_n)\f$ (default is all zeros), and /// 6. <i>(the padding above)</i> a vector of (possibly negative) integers \f$(q_1,\dots,q_n)\f$ (default is all zeros), and
/// 7. <i>(the image dilation strides)</i> a vector of non-negative integers \f$(q_1,\dots,q_n)\f$ (default is all ones). /// 7. <i>(the image dilation strides)</i> a vector of non-negative integers \f$(q_1,\dots,q_n)\f$ (default is all ones).
/// ///
/// The output has the shape \f$(N,C_\textit{out},d'_1,\dots,d'_n)\f$, where \f$d'_n = \lceil \frac{(d_i - 1) * g_i + 1 + p_i + q_i - l_i(d^f_i - 1)}{s_i} \rceil\f$. /// The output has the shape \f$(N,C_\textit{out},d'_1,\dots,d'_n)\f$, where \f$d'_n = \lceil \frac{(d_i - 1) * g_i + 1 + p_i + q_i - l_i(d^f_i - 1)}{s_i} \rceil\f$.
...@@ -68,8 +68,8 @@ namespace ngraph ...@@ -68,8 +68,8 @@ namespace ngraph
const std::shared_ptr<Node>& filters, const std::shared_ptr<Node>& filters,
const Strides& window_movement_strides, const Strides& window_movement_strides,
const Strides& window_dilation_strides, const Strides& window_dilation_strides,
const Shape& padding_below, const CoordinateDiff& padding_below,
const Shape& padding_above, const CoordinateDiff& padding_above,
const Strides& image_dilation_strides); const Strides& image_dilation_strides);
/// \brief Constructs a batched convolution operation with no image dilation (i.e., all image dilation strides are 1). /// \brief Constructs a batched convolution operation with no image dilation (i.e., all image dilation strides are 1).
...@@ -84,8 +84,8 @@ namespace ngraph ...@@ -84,8 +84,8 @@ namespace ngraph
const std::shared_ptr<Node>& filters, const std::shared_ptr<Node>& filters,
const Strides& window_movement_strides, const Strides& window_movement_strides,
const Strides& window_dilation_strides, const Strides& window_dilation_strides,
const Shape& padding_below, const CoordinateDiff& padding_below,
const Shape& padding_above); const CoordinateDiff& padding_above);
/// \brief Constructs a batched convolution operation with no padding or image dilation (i.e., padding above and below are 0 everywhere, and all image dilation strides are 1). /// \brief Constructs a batched convolution operation with no padding or image dilation (i.e., padding above and below are 0 everywhere, and all image dilation strides are 1).
/// ///
...@@ -121,10 +121,10 @@ namespace ngraph ...@@ -121,10 +121,10 @@ namespace ngraph
const Strides& get_window_movement_strides() const { return m_window_movement_strides; } const Strides& get_window_movement_strides() const { return m_window_movement_strides; }
/// \return The window dilation strides. /// \return The window dilation strides.
const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; } const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; }
/// \return The padding-below sizes. /// \return The padding-below sizes (possibly negative).
const Shape& get_padding_below() const { return m_padding_below; } const CoordinateDiff& get_padding_below() const { return m_padding_below; }
/// \return The padding-above sizes. /// \return The padding-above sizes (possibly negative).
const Shape& get_padding_above() const { return m_padding_above; } const CoordinateDiff& get_padding_above() const { return m_padding_above; }
/// \return The input image dilation strides. /// \return The input image dilation strides.
const Strides& get_image_dilation_strides() const { return m_image_dilation_strides; } const Strides& get_image_dilation_strides() const { return m_image_dilation_strides; }
/// \return The number of input channels. /// \return The number of input channels.
...@@ -156,8 +156,8 @@ namespace ngraph ...@@ -156,8 +156,8 @@ namespace ngraph
protected: protected:
Strides m_window_movement_strides; Strides m_window_movement_strides;
Strides m_window_dilation_strides; Strides m_window_dilation_strides;
Shape m_padding_below; CoordinateDiff m_padding_below;
Shape m_padding_above; CoordinateDiff m_padding_above;
Strides m_image_dilation_strides; Strides m_image_dilation_strides;
// TODO: Some or all of these values should probably be computed dynamically rather than stored here. // TODO: Some or all of these values should probably be computed dynamically rather than stored here.
...@@ -173,7 +173,7 @@ namespace ngraph ...@@ -173,7 +173,7 @@ namespace ngraph
private: private:
static Strides default_strides(const std::shared_ptr<Node>& image_batch); static Strides default_strides(const std::shared_ptr<Node>& image_batch);
static Shape default_padding(const std::shared_ptr<Node>& image_batch); static CoordinateDiff default_padding(const std::shared_ptr<Node>& image_batch);
}; };
} }
} }
...@@ -63,12 +63,12 @@ namespace ngraph ...@@ -63,12 +63,12 @@ namespace ngraph
size_t n_image_dimensions = arg_shape.size() - 2; size_t n_image_dimensions = arg_shape.size() - 2;
Shape input_batch_transform_start(2 + n_image_dimensions); Coordinate input_batch_transform_start(2 + n_image_dimensions);
Shape input_batch_transform_end(2 + n_image_dimensions); Coordinate input_batch_transform_end(2 + n_image_dimensions);
Shape input_batch_transform_source_strides(2 + n_image_dimensions, 1); Strides input_batch_transform_source_strides(2 + n_image_dimensions, 1);
Shape input_batch_transform_source_axis_order(2 + n_image_dimensions); AxisVector input_batch_transform_source_axis_order(2 + n_image_dimensions);
Shape input_batch_transform_padding_below(2 + n_image_dimensions); CoordinateDiff input_batch_transform_padding_below(2 + n_image_dimensions);
Shape input_batch_transform_padding_above(2 + n_image_dimensions); CoordinateDiff input_batch_transform_padding_above(2 + n_image_dimensions);
input_batch_transform_start[0] = img_index; input_batch_transform_start[0] = img_index;
input_batch_transform_end[0] = img_index + 1; input_batch_transform_end[0] = img_index + 1;
......
...@@ -35,8 +35,8 @@ namespace ngraph ...@@ -35,8 +35,8 @@ namespace ngraph
const Shape& out_shape, const Shape& out_shape,
const Strides& window_movement_strides, const Strides& window_movement_strides,
const Strides& window_dilation_strides, const Strides& window_dilation_strides,
const Shape& padding_below, const CoordinateDiff& padding_below,
const Shape& padding_above, const CoordinateDiff& padding_above,
const Strides& image_dilation_strides) const Strides& image_dilation_strides)
{ {
// At the outermost level we will walk over every output coordinate O. // At the outermost level we will walk over every output coordinate O.
...@@ -71,12 +71,12 @@ namespace ngraph ...@@ -71,12 +71,12 @@ namespace ngraph
size_t n_image_dimensions = arg0_shape.size() - 2; size_t n_image_dimensions = arg0_shape.size() - 2;
size_t n_input_channels = arg0_shape[1]; size_t n_input_channels = arg0_shape[1];
Shape input_batch_transform_start(2 + n_image_dimensions); Coordinate input_batch_transform_start(2 + n_image_dimensions);
Shape input_batch_transform_end(2 + n_image_dimensions); Coordinate input_batch_transform_end(2 + n_image_dimensions);
Shape input_batch_transform_movement_strides(2 + n_image_dimensions, 1); Strides input_batch_transform_movement_strides(2 + n_image_dimensions, 1);
Shape input_batch_transform_padding_below(2 + n_image_dimensions, 0); CoordinateDiff input_batch_transform_padding_below(2 + n_image_dimensions, 0);
Shape input_batch_transform_padding_above(2 + n_image_dimensions, 0); CoordinateDiff input_batch_transform_padding_above(2 + n_image_dimensions, 0);
Shape input_batch_transform_dilation_strides(2 + n_image_dimensions, 1); Strides input_batch_transform_dilation_strides(2 + n_image_dimensions, 1);
input_batch_transform_start[0] = img_index; input_batch_transform_start[0] = img_index;
input_batch_transform_end[0] = img_index + 1; input_batch_transform_end[0] = img_index + 1;
...@@ -87,8 +87,8 @@ namespace ngraph ...@@ -87,8 +87,8 @@ namespace ngraph
{ {
size_t window_dilation_stride = window_dilation_strides[i - 2]; size_t window_dilation_stride = window_dilation_strides[i - 2];
size_t window_movement_stride = window_movement_strides[i - 2]; size_t window_movement_stride = window_movement_strides[i - 2];
size_t below_pad = padding_below[i - 2]; std::ptrdiff_t below_pad = padding_below[i - 2];
size_t above_pad = padding_above[i - 2]; std::ptrdiff_t above_pad = padding_above[i - 2];
size_t image_dilation_stride = image_dilation_strides[i - 2]; size_t image_dilation_stride = image_dilation_strides[i - 2];
input_batch_transform_start[i] = window_movement_stride * out_coord[i]; input_batch_transform_start[i] = window_movement_stride * out_coord[i];
......
...@@ -59,8 +59,8 @@ namespace ngraph ...@@ -59,8 +59,8 @@ namespace ngraph
size_t n_image_dimensions = arg_shape.size() - 2; size_t n_image_dimensions = arg_shape.size() - 2;
Shape input_batch_transform_start(2 + n_image_dimensions); Coordinate input_batch_transform_start(2 + n_image_dimensions);
Shape input_batch_transform_end(2 + n_image_dimensions); Coordinate input_batch_transform_end(2 + n_image_dimensions);
input_batch_transform_start[0] = img_index; input_batch_transform_start[0] = img_index;
input_batch_transform_end[0] = img_index + 1; input_batch_transform_end[0] = img_index + 1;
......
...@@ -54,13 +54,23 @@ namespace ngraph ...@@ -54,13 +54,23 @@ namespace ngraph
input_dilation[i] = padding_interior[i] + 1; input_dilation[i] = padding_interior[i] + 1;
} }
// Need to cast these to CoordinateDiff in order to make CoordinateTransform happy.
CoordinateDiff padding_below_signed;
CoordinateDiff padding_above_signed;
for (size_t i = 0; i < padding_below.size(); i++)
{
padding_below_signed.push_back(padding_below[i]);
padding_above_signed.push_back(padding_above[i]);
}
CoordinateTransform input_transform(arg0_shape, CoordinateTransform input_transform(arg0_shape,
input_start, input_start,
input_end, input_end,
input_strides, input_strides,
input_axis_order, input_axis_order,
padding_below, padding_below_signed,
padding_above, padding_above_signed,
input_dilation); input_dilation);
CoordinateTransform output_transform(out_shape); CoordinateTransform output_transform(out_shape);
......
...@@ -369,8 +369,8 @@ static shared_ptr<ngraph::Function> ...@@ -369,8 +369,8 @@ static shared_ptr<ngraph::Function>
node_js.at("window_movement_strides").get<vector<size_t>>(); node_js.at("window_movement_strides").get<vector<size_t>>();
auto window_dilation_strides = auto window_dilation_strides =
node_js.at("window_dilation_strides").get<vector<size_t>>(); node_js.at("window_dilation_strides").get<vector<size_t>>();
auto padding_below = node_js.at("padding_below").get<vector<size_t>>(); auto padding_below = node_js.at("padding_below").get<vector<std::ptrdiff_t>>();
auto padding_above = node_js.at("padding_above").get<vector<size_t>>(); auto padding_above = node_js.at("padding_above").get<vector<std::ptrdiff_t>>();
node = make_shared<op::Convolution>(args[0], node = make_shared<op::Convolution>(args[0],
args[1], args[1],
window_movement_strides, window_movement_strides,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -81,6 +81,7 @@ def tuple_times(t1,t2): ...@@ -81,6 +81,7 @@ def tuple_times(t1,t2):
def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads, above_pads, image_dilation): def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads, above_pads, image_dilation):
assert(len(img_batch.shape) == len(filter.shape)) assert(len(img_batch.shape) == len(filter.shape))
assert(len(img_batch.shape) > 2) assert(len(img_batch.shape) > 2)
assert(len(img_batch.shape) <= 6)
assert(img_batch.shape[1] == filter.shape[1]) assert(img_batch.shape[1] == filter.shape[1])
assert(len(move_strides) == len(img_batch.shape) - 2) assert(len(move_strides) == len(img_batch.shape) - 2)
assert(len(filter_dilation) == len(img_batch.shape) - 2) assert(len(filter_dilation) == len(img_batch.shape) - 2)
...@@ -93,7 +94,9 @@ def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads ...@@ -93,7 +94,9 @@ def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads
for n in range(0, new_img_batch_shape[0]) : for n in range(0, new_img_batch_shape[0]) :
for c in range(0, new_img_batch_shape[1]) : for c in range(0, new_img_batch_shape[1]) :
if new_img_batch.ndim == 4: if new_img_batch.ndim == 3:
new_img_batch[n, c, 0::image_dilation[0]] = img_batch[n][c]
elif new_img_batch.ndim == 4:
new_img_batch[n, c, 0::image_dilation[0], 0::image_dilation[1]] = img_batch[n][c] new_img_batch[n, c, 0::image_dilation[0], 0::image_dilation[1]] = img_batch[n][c]
elif new_img_batch.ndim == 5: elif new_img_batch.ndim == 5:
new_img_batch[n, c, 0::image_dilation[0], 0::image_dilation[1], 0::image_dilation[2]] = img_batch[n][c] new_img_batch[n, c, 0::image_dilation[0], 0::image_dilation[1], 0::image_dilation[2]] = img_batch[n][c]
...@@ -104,10 +107,16 @@ def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads ...@@ -104,10 +107,16 @@ def convolution_ref(img_batch, filter, move_strides, filter_dilation, below_pads
img_batch = new_img_batch img_batch = new_img_batch
# Pad the input batch. # Pad the input batch wherever the pads are positive.
below_pads = (0,0) + below_pads # Have to add values for the image and channel dims. below_pads_pos = (0,0) + tuple(np.clip(below_pads,0,None)) # Have to add values for the image and channel dims.
above_pads = (0,0) + above_pads # Have to add values for the image and channel dims. above_pads_pos = (0,0) + tuple(np.clip(above_pads,0,None)) # Have to add values for the image and channel dims.
img_batch = np.pad(img_batch, zip(below_pads,above_pads), mode='constant', constant_values=0) img_batch = np.pad(img_batch, zip(below_pads_pos,above_pads_pos), mode='constant', constant_values=0)
# Slice the input batch wherever the pads are negative.
slice_bottoms = (0,0) + tuple (-np.clip(below_pads,None,0))
slice_tops = (0,0) + tuple (np.clip(above_pads,None,0))
slices = map(lambda p: slice(p[0],p[1] if p[1] < 0 else None),zip(slice_bottoms,slice_tops))
img_batch = img_batch[slices]
img_count = img_batch.shape[0] # N img_count = img_batch.shape[0] # N
ci_count = img_batch.shape[1] # Ci ci_count = img_batch.shape[1] # Ci
...@@ -198,8 +207,8 @@ TEST (${BACKEND_NAME}, %s) ...@@ -198,8 +207,8 @@ TEST (${BACKEND_NAME}, %s)
make_shared<op::Convolution>(A, B, make_shared<op::Convolution>(A, B,
Strides{%s}, // move_strides Strides{%s}, // move_strides
Strides{%s}, // filter_dilation Strides{%s}, // filter_dilation
Shape{%s}, // below_pads CoordinateDiff{%s}, // below_pads
Shape{%s}, // above_pads CoordinateDiff{%s}, // above_pads
Strides{%s}), // image_dilation Strides{%s}), // image_dilation
op::Parameters{A, B}); op::Parameters{A, B});
...@@ -251,11 +260,14 @@ tests = [ ...@@ -251,11 +260,14 @@ tests = [
("convolution_3d_2images", shaped_linspace((2,1,3,5,8)), shaped_linspace((2,1,2,2,3)), (1,1,1), (1,1,1), (0,0,0), (0,0,0), (1,1,1)), ("convolution_3d_2images", shaped_linspace((2,1,3,5,8)), shaped_linspace((2,1,2,2,3)), (1,1,1), (1,1,1), (0,0,0), (0,0,0), (1,1,1)),
("convolution_4d_2images", shaped_linspace((2,1,3,5,8,7)),shaped_linspace((2,1,2,2,3,1)),(1,1,1,1),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)), ("convolution_4d_2images", shaped_linspace((2,1,3,5,8,7)),shaped_linspace((2,1,2,2,3,1)),(1,1,1,1),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)),
("convolution_4d_4images", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(1,1,1,1),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)), ("convolution_4d_4images", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(1,1,1,1),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)),
("convolution_4d_4images_padded_neg", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(1,1,1,1),(1,1,1,1),(-1,2,-3,2),(1,0,0,-3), (1,1,1,1)),
("convolution_4d_4images_strided", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(2,1,3,2),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)), ("convolution_4d_4images_strided", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(2,1,3,2),(1,1,1,1),(0,0,0,0), (0,0,0,0), (1,1,1,1)),
("convolution_4d_4images_dilated", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(1,1,1,1),(2,1,3,2),(0,0,0,0), (0,0,0,0), (1,1,1,1)), ("convolution_4d_4images_dilated", shaped_linspace((4,3,3,5,8,7)),shaped_linspace((4,3,2,2,3,1)),(1,1,1,1),(2,1,3,2),(0,0,0,0), (0,0,0,0), (1,1,1,1)),
("convolution_4d_4images_strided_dilated",shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(0,0,0,0), (0,0,0,0), (1,1,1,1)), ("convolution_4d_4images_strided_dilated",shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(0,0,0,0), (0,0,0,0), (1,1,1,1)),
("convolution_4d_4images_strided_dilated_padded", ("convolution_4d_4images_strided_dilated_padded",
shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(2,4,6,8), (1,3,5,7), (1,1,1,1)), shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(2,4,6,8), (1,3,5,7), (1,1,1,1)),
("convolution_4d_4images_strided_dilated_padded_neg",
shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(-2,4,0,5), (1,3,-1,-4),(1,1,1,1)),
("convolution_4d_4images_strided_dilated_padded_same", ("convolution_4d_4images_strided_dilated_padded_same",
shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(3,3,3,3), (3,3,3,3), (1,1,1,1)), shaped_linspace((4,3,8,8,8,8)),shaped_linspace((4,3,2,2,3,1)),(3,2,2,3),(2,1,3,2),(3,3,3,3), (3,3,3,3), (1,1,1,1)),
("convolution_2d_1image_1o1i_img_dilated",shaped_linspace((1,1,3,5)), shaped_linspace((1,1,2,2)), (1,1), (1,1), (0,0), (0,0), (2,2)), ("convolution_2d_1image_1o1i_img_dilated",shaped_linspace((1,1,3,5)), shaped_linspace((1,1,2,2)), (1,1), (1,1), (0,0), (0,0), (2,2)),
...@@ -337,14 +349,16 @@ static bool all_close_d(const std::vector<double>& a, ...@@ -337,14 +349,16 @@ static bool all_close_d(const std::vector<double>& a,
{ {
assert(a.size() == b.size()); assert(a.size() == b.size());
bool rc = true;
for (size_t i = 0; i < a.size(); ++i) for (size_t i = 0; i < a.size(); ++i)
{ {
if (std::abs(a[i] - b[i]) > atol + rtol * std::abs(b[i])) if (std::abs(a[i] - b[i]) > atol + rtol * std::abs(b[i]))
{ {
return false; rc = false;
} }
} }
return true; return rc;
} }
''') ''')
for t in tests: for t in tests:
......
...@@ -1767,8 +1767,8 @@ TEST(type_prop, conv_1d_deduce) ...@@ -1767,8 +1767,8 @@ TEST(type_prop, conv_1d_deduce)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{0}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{0});
EXPECT_EQ(conv->get_padding_above(), Shape{0}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{0});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1791,8 +1791,8 @@ TEST(type_prop, conv_1d_deduce_padded) ...@@ -1791,8 +1791,8 @@ TEST(type_prop, conv_1d_deduce_padded)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10});
auto move_strides = Strides{1}; auto move_strides = Strides{1};
auto dilation_strides = Strides{1}; auto dilation_strides = Strides{1};
auto padding_below = Shape{2}; auto padding_below = CoordinateDiff{2};
auto padding_above = Shape{3}; auto padding_above = CoordinateDiff{3};
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(
param0, param1, move_strides, dilation_strides, padding_below, padding_above); param0, param1, move_strides, dilation_strides, padding_below, padding_above);
EXPECT_EQ(conv->get_element_type(), element::f32); EXPECT_EQ(conv->get_element_type(), element::f32);
...@@ -1802,8 +1802,8 @@ TEST(type_prop, conv_1d_deduce_padded) ...@@ -1802,8 +1802,8 @@ TEST(type_prop, conv_1d_deduce_padded)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{2}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{2});
EXPECT_EQ(conv->get_padding_above(), Shape{3}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{3});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1833,8 +1833,8 @@ TEST(type_prop, conv_1d_deduce_strided) ...@@ -1833,8 +1833,8 @@ TEST(type_prop, conv_1d_deduce_strided)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{0}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{0});
EXPECT_EQ(conv->get_padding_above(), Shape{0}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{0});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1857,8 +1857,8 @@ TEST(type_prop, conv_1d_deduce_strided_padded) ...@@ -1857,8 +1857,8 @@ TEST(type_prop, conv_1d_deduce_strided_padded)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10});
auto move_strides = Strides{2}; auto move_strides = Strides{2};
auto dilation_strides = Strides{1}; auto dilation_strides = Strides{1};
auto padding_below = Shape{2}; auto padding_below = CoordinateDiff{2};
auto padding_above = Shape{3}; auto padding_above = CoordinateDiff{3};
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(
param0, param1, move_strides, dilation_strides, padding_below, padding_above); param0, param1, move_strides, dilation_strides, padding_below, padding_above);
EXPECT_EQ(conv->get_element_type(), element::f32); EXPECT_EQ(conv->get_element_type(), element::f32);
...@@ -1868,8 +1868,8 @@ TEST(type_prop, conv_1d_deduce_strided_padded) ...@@ -1868,8 +1868,8 @@ TEST(type_prop, conv_1d_deduce_strided_padded)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{2}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{2});
EXPECT_EQ(conv->get_padding_above(), Shape{3}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{3});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1899,8 +1899,8 @@ TEST(type_prop, conv_1d_deduce_strided_small_uneven) ...@@ -1899,8 +1899,8 @@ TEST(type_prop, conv_1d_deduce_strided_small_uneven)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{0}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{0});
EXPECT_EQ(conv->get_padding_above(), Shape{0}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{0});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1930,8 +1930,8 @@ TEST(type_prop, conv_1d_deduce_strided_small_even) ...@@ -1930,8 +1930,8 @@ TEST(type_prop, conv_1d_deduce_strided_small_even)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{0}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{0});
EXPECT_EQ(conv->get_padding_above(), Shape{0}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{0});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1962,8 +1962,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated) ...@@ -1962,8 +1962,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{0}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{0});
EXPECT_EQ(conv->get_padding_above(), Shape{0}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{0});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -1986,8 +1986,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_padded) ...@@ -1986,8 +1986,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_padded)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10});
auto move_strides = Strides{1}; auto move_strides = Strides{1};
auto dilate_strides = Strides{2}; auto dilate_strides = Strides{2};
auto padding_below = Shape{2}; auto padding_below = CoordinateDiff{2};
auto padding_above = Shape{3}; auto padding_above = CoordinateDiff{3};
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(
param0, param1, move_strides, dilate_strides, padding_below, padding_above); param0, param1, move_strides, dilate_strides, padding_below, padding_above);
EXPECT_EQ(conv->get_element_type(), element::f32); EXPECT_EQ(conv->get_element_type(), element::f32);
...@@ -1997,8 +1997,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_padded) ...@@ -1997,8 +1997,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_padded)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{1});
EXPECT_EQ(conv->get_padding_below(), Shape{2}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{2});
EXPECT_EQ(conv->get_padding_above(), Shape{3}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{3});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2021,8 +2021,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_images_dilated_padded) ...@@ -2021,8 +2021,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_images_dilated_padded)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10});
auto move_strides = Strides{1}; auto move_strides = Strides{1};
auto dilate_strides = Strides{2}; auto dilate_strides = Strides{2};
auto padding_below = Shape{2}; auto padding_below = CoordinateDiff{2};
auto padding_above = Shape{3}; auto padding_above = CoordinateDiff{3};
auto img_dilate_strides = Strides{3}; auto img_dilate_strides = Strides{3};
auto conv = make_shared<op::Convolution>(param0, auto conv = make_shared<op::Convolution>(param0,
param1, param1,
...@@ -2038,8 +2038,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_images_dilated_padded) ...@@ -2038,8 +2038,8 @@ TEST(type_prop, conv_1d_deduce_window_dilated_images_dilated_padded)
EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2}); EXPECT_EQ(conv->get_window_dilation_strides(), Strides{2});
EXPECT_EQ(conv->get_image_dilation_strides(), Strides{3}); EXPECT_EQ(conv->get_image_dilation_strides(), Strides{3});
EXPECT_EQ(conv->get_padding_below(), Shape{2}); EXPECT_EQ(conv->get_padding_below(), CoordinateDiff{2});
EXPECT_EQ(conv->get_padding_above(), Shape{3}); EXPECT_EQ(conv->get_padding_above(), CoordinateDiff{3});
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2068,8 +2068,8 @@ TEST(type_prop, conv_2d_deduce) ...@@ -2068,8 +2068,8 @@ TEST(type_prop, conv_2d_deduce)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2092,8 +2092,8 @@ TEST(type_prop, conv_2d_deduce_padded) ...@@ -2092,8 +2092,8 @@ TEST(type_prop, conv_2d_deduce_padded)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10, 20}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10, 20});
auto move_strides = Strides{1, 1}; auto move_strides = Strides{1, 1};
auto dilate_strides = Strides{1, 1}; auto dilate_strides = Strides{1, 1};
auto padding_below = Shape{2, 3}; auto padding_below = CoordinateDiff{2, 3};
auto padding_above = Shape{3, 4}; auto padding_above = CoordinateDiff{3, 4};
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(
param0, param1, move_strides, dilate_strides, padding_below, padding_above); param0, param1, move_strides, dilate_strides, padding_below, padding_above);
EXPECT_EQ(conv->get_element_type(), element::f32); EXPECT_EQ(conv->get_element_type(), element::f32);
...@@ -2103,8 +2103,8 @@ TEST(type_prop, conv_2d_deduce_padded) ...@@ -2103,8 +2103,8 @@ TEST(type_prop, conv_2d_deduce_padded)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{2, 3})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{2, 3}));
EXPECT_EQ(conv->get_padding_above(), (Shape{3, 4})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{3, 4}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2120,6 +2120,41 @@ TEST(type_prop, conv_2d_deduce_padded) ...@@ -2120,6 +2120,41 @@ TEST(type_prop, conv_2d_deduce_padded)
EXPECT_EQ(conv->get_image_dimension_count(), 2); EXPECT_EQ(conv->get_image_dimension_count(), 2);
} }
TEST(type_prop, conv_2d_deduce_padded_neg)
{
// Deduce type
auto param0 = make_shared<op::Parameter>(element::f32, Shape{64, 3, 100, 150});
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10, 20});
auto move_strides = Strides{1, 1};
auto dilate_strides = Strides{1, 1};
auto padding_below = CoordinateDiff{2, -3};
auto padding_above = CoordinateDiff{3, -4};
auto conv = make_shared<op::Convolution>(
param0, param1, move_strides, dilate_strides, padding_below, padding_above);
EXPECT_EQ(conv->get_element_type(), element::f32);
EXPECT_EQ(conv->get_shape(), (Shape{64, 128, 96, 124}));
EXPECT_EQ(conv->get_window_movement_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{2, -3}));
EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{3, -4}));
EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128);
EXPECT_EQ(conv->get_input_image_physical_shape(), (Shape{100, 150}));
EXPECT_EQ(conv->get_input_image_virtual_shape(), (Shape{105, 143}));
EXPECT_EQ(conv->get_output_image_shape(), (Shape{96, 124}));
EXPECT_EQ(conv->get_window_physical_shape(), (Shape{10, 20}));
EXPECT_EQ(conv->get_window_virtual_shape(), (Shape{10, 20}));
EXPECT_EQ(conv->get_batch_size(), 64);
EXPECT_EQ(conv->get_image_dimension_count(), 2);
}
TEST(type_prop, conv_2d_deduce_strided) TEST(type_prop, conv_2d_deduce_strided)
{ {
// Deduce type // Deduce type
...@@ -2134,8 +2169,8 @@ TEST(type_prop, conv_2d_deduce_strided) ...@@ -2134,8 +2169,8 @@ TEST(type_prop, conv_2d_deduce_strided)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2166,8 +2201,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated) ...@@ -2166,8 +2201,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2190,8 +2225,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_images_dilated) ...@@ -2190,8 +2225,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_images_dilated)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10, 20}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 10, 20});
auto move_strides = Strides{2, 3}; auto move_strides = Strides{2, 3};
auto dilate_strides = Strides{3, 2}; auto dilate_strides = Strides{3, 2};
auto padding_below = Shape{0, 0}; auto padding_below = CoordinateDiff{0, 0};
auto padding_above = Shape{0, 0}; auto padding_above = CoordinateDiff{0, 0};
auto img_dilate_strides = Strides{2, 3}; auto img_dilate_strides = Strides{2, 3};
auto conv = make_shared<op::Convolution>(param0, auto conv = make_shared<op::Convolution>(param0,
param1, param1,
...@@ -2207,8 +2242,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_images_dilated) ...@@ -2207,8 +2242,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_images_dilated)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{2, 3})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{2, 3}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2239,8 +2274,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_small) ...@@ -2239,8 +2274,8 @@ TEST(type_prop, conv_2d_deduce_strided_window_dilated_small)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2271,8 +2306,8 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_small) ...@@ -2271,8 +2306,8 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_small)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2, 2})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2, 2}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1, 1})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{1, 1, 1}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2295,15 +2330,15 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_image_dilated_small) ...@@ -2295,15 +2330,15 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_image_dilated_small)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 2, 3, 2}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{128, 3, 2, 3, 2});
auto move_strides = Strides{2, 3, 4}; auto move_strides = Strides{2, 3, 4};
auto dilate_strides = Strides{3, 2, 2}; auto dilate_strides = Strides{3, 2, 2};
auto below_padding = Shape{0, 0, 0}; auto padding_below = CoordinateDiff{0, 0, 0};
auto above_padding = Shape{0, 0, 0}; auto padding_above = CoordinateDiff{0, 0, 0};
auto img_dilate_strides = Strides{2, 3, 2}; auto img_dilate_strides = Strides{2, 3, 2};
auto conv = make_shared<op::Convolution>(param0, auto conv = make_shared<op::Convolution>(param0,
param1, param1,
move_strides, move_strides,
dilate_strides, dilate_strides,
below_padding, padding_below,
above_padding, padding_above,
img_dilate_strides); img_dilate_strides);
EXPECT_EQ(conv->get_element_type(), element::f32); EXPECT_EQ(conv->get_element_type(), element::f32);
EXPECT_EQ(conv->get_shape(), (Shape{64, 128, 5, 6, 5})); EXPECT_EQ(conv->get_shape(), (Shape{64, 128, 5, 6, 5}));
...@@ -2312,8 +2347,8 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_image_dilated_small) ...@@ -2312,8 +2347,8 @@ TEST(type_prop, conv_3d_deduce_strided_window_dilated_image_dilated_small)
EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2, 2})); EXPECT_EQ(conv->get_window_dilation_strides(), (Strides{3, 2, 2}));
EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{2, 3, 2})); EXPECT_EQ(conv->get_image_dilation_strides(), (Strides{2, 3, 2}));
EXPECT_EQ(conv->get_padding_below(), (Shape{0, 0, 0})); EXPECT_EQ(conv->get_padding_below(), (CoordinateDiff{0, 0, 0}));
EXPECT_EQ(conv->get_padding_above(), (Shape{0, 0, 0})); EXPECT_EQ(conv->get_padding_above(), (CoordinateDiff{0, 0, 0}));
EXPECT_EQ(conv->get_input_channel_count(), 3); EXPECT_EQ(conv->get_input_channel_count(), 3);
EXPECT_EQ(conv->get_output_channel_count(), 128); EXPECT_EQ(conv->get_output_channel_count(), 128);
...@@ -2601,8 +2636,8 @@ TEST(type_prop, conv_invalid_image_dilation_stride_rank) ...@@ -2601,8 +2636,8 @@ TEST(type_prop, conv_invalid_image_dilation_stride_rank)
param1, param1,
Strides{2, 3}, Strides{2, 3},
Strides{2, 3}, Strides{2, 3},
Shape{0, 0}, CoordinateDiff{0, 0},
Shape{0, 0}, CoordinateDiff{0, 0},
Strides{2, 3, 8}); Strides{2, 3, 8});
// Should have thrown, so fail if it didn't // Should have thrown, so fail if it didn't
...@@ -2627,8 +2662,12 @@ TEST(type_prop, conv_invalid_padding_below_rank) ...@@ -2627,8 +2662,12 @@ TEST(type_prop, conv_invalid_padding_below_rank)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3});
try try
{ {
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(param0,
param0, param1, Strides{2, 3}, Strides{1, 1}, Shape{0, 0, 0}, Shape{0, 0}); param1,
Strides{2, 3},
Strides{1, 1},
CoordinateDiff{0, 0, 0},
CoordinateDiff{0, 0});
// Should have thrown, so fail if it didn't // Should have thrown, so fail if it didn't
FAIL() << "Invalid input with wrong padding-below rank not detected"; FAIL() << "Invalid input with wrong padding-below rank not detected";
...@@ -2652,8 +2691,12 @@ TEST(type_prop, conv_invalid_padding_above_rank) ...@@ -2652,8 +2691,12 @@ TEST(type_prop, conv_invalid_padding_above_rank)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3});
try try
{ {
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(param0,
param0, param1, Strides{2, 3}, Strides{2, 3}, Shape{0, 0}, Shape{0, 0, 0}); param1,
Strides{2, 3},
Strides{2, 3},
CoordinateDiff{0, 0},
CoordinateDiff{0, 0, 0});
// Should have thrown, so fail if it didn't // Should have thrown, so fail if it didn't
FAIL() << "Invalid input with wrong padding-above rank not detected"; FAIL() << "Invalid input with wrong padding-above rank not detected";
...@@ -2670,6 +2713,65 @@ TEST(type_prop, conv_invalid_padding_above_rank) ...@@ -2670,6 +2713,65 @@ TEST(type_prop, conv_invalid_padding_above_rank)
} }
} }
TEST(type_prop, conv_invalid_input_image_size_negative_after_padding)
{
// Deduce type
auto param0 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 10, 10});
auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3});
try
{
auto conv = make_shared<op::Convolution>(param0,
param1,
Strides{0, 0},
Strides{0, 0},
CoordinateDiff{-4, 0},
CoordinateDiff{-7, 0});
// Should have thrown, so fail if it didn't
FAIL() << "Invalid input with negative-length post-padding image axis not detected";
}
catch (const ngraph_error& error)
{
EXPECT_EQ(error.what(),
std::string(
"Convolution input image dimension after padding and dilation is negative."));
}
catch (...)
{
FAIL() << "Deduced type check failed for unexpected reason";
}
}
TEST(type_prop, conv_invalid_input_image_size_zero_after_padding)
{
// Deduce type
auto param0 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 10, 10});
auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3});
try
{
auto conv = make_shared<op::Convolution>(param0,
param1,
Strides{0, 0},
Strides{0, 0},
CoordinateDiff{-4, 0},
CoordinateDiff{-6, 0});
// Should have thrown, so fail if it didn't
FAIL() << "Invalid input with zero-length post-padding image axis not detected";
}
catch (const ngraph_error& error)
{
EXPECT_EQ(
error.what(),
std::string(
"Convolution input image dimension after dilation is zero even with padding."));
}
catch (...)
{
FAIL() << "Deduced type check failed for unexpected reason";
}
}
TEST(type_prop, conv_invalid_input_image_size_0) TEST(type_prop, conv_invalid_input_image_size_0)
{ {
// Deduce type // Deduce type
...@@ -2746,8 +2848,13 @@ TEST(type_prop, conv_invalid_image_dilation_stride_0) ...@@ -2746,8 +2848,13 @@ TEST(type_prop, conv_invalid_image_dilation_stride_0)
auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3}); auto param1 = make_shared<op::Parameter>(element::f32, Shape{6, 2, 3, 3});
try try
{ {
auto conv = make_shared<op::Convolution>( auto conv = make_shared<op::Convolution>(param0,
param0, param1, Strides{2, 3}, Strides{2, 3}, Shape{0, 0}, Shape{0, 0}, Strides{2, 0}); param1,
Strides{2, 3},
Strides{2, 3},
CoordinateDiff{0, 0},
CoordinateDiff{0, 0},
Strides{2, 0});
// Should have thrown, so fail if it didn't // Should have thrown, so fail if it didn't
FAIL() << "Invalid input with wrong 0-length image dilation stride axis not detected"; FAIL() << "Invalid input with wrong 0-length image dilation stride axis not detected";
......
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