-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CSpaceToDepthLayer and CDepthToSpaceLayer (#169)
* Add SpaceToDepth and DepthToSpace functions to MathEngine Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Fix Metal kernels Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Remove unused variable from CPU SpaceToDepthFunc Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Delete unused test parts Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Add CSpaceToDepthLayer and CDepthToSpaceLayer Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Update version of NeoMLTest Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Clarify docs Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Fix checks in CDepthToSpaceLayer and CSpaceToDepthLayer Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> * Add SpaceToDepth and DepthToSpace layers to Python library Signed-off-by: Valeriy Fedyunin <valery.fedyunin@abbyy.com> Co-authored-by: Stanislav Angeliuk <59917951+SAngeliuk@users.noreply.github.com>
- Loading branch information
Showing
42 changed files
with
1,820 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
""" Copyright (c) 2017-2020 ABBYY Production LLC | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://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. | ||
--------------------------------------------------------------------------------------------------------------*/ | ||
""" | ||
|
||
import neoml.PythonWrapper as PythonWrapper | ||
from .Dnn import Layer | ||
from neoml.Utils import check_input_layers | ||
import neoml.Blob as Blob | ||
|
||
|
||
class SpaceToDepth(Layer): | ||
"""The layer that splits images into square blocks of size `k x k x Ch` and | ||
writes the contents of these blocks to the corresponding pixels (`1 x 1 x Ch*k*k`) of the | ||
output images in channel-last ordering. | ||
As a result image of size `H x W x Ch` is transformed into images of size `H/k x W/k x Ch*k*k`. | ||
This operation is the inverse function of DepthToSpace. | ||
:param input_layers: The input layers to be connected. | ||
The integer in each tuple specifies the number of the output. | ||
If not set, the first output will be used. | ||
:type input_layers: object, tuple(object, int) or list of them | ||
:param block_size: The size of the block (`k` from the formula). | ||
:type block_size: int, default=1 | ||
:param name: The layer name. | ||
:type name: str, default=None | ||
.. rubric:: Layer inputs: | ||
Has single input, of the dimensions: | ||
- **BatchLength** * **BatchWidth** * **ListSize** is equal to the number of images | ||
- **Height** is the image height; should be a multiple of `block_size` | ||
- **Width** is the image width; should be a multiple of `block_size` | ||
- **Depth** is equal to `1` | ||
- **Channels** is the number of channels in the image format | ||
.. rubric:: Layer outputs: | ||
The layer has single output, of the dimensions: | ||
- **BatchLength** is equal to the input `BatchLength` | ||
- **BatchWidth** is equal to the input `BatchWidth` | ||
- **ListSize** is equal to the input `ListSize` | ||
- **Height** is equal to the input `Height / block_size` | ||
- **Width** is equal to the input `Width / block_size` | ||
- **Depth** is equal to `1` | ||
- **Channels** is equal to the input `Channels * block_size * block_size` | ||
""" | ||
|
||
def __init__(self, input_layer, block_size=1, name=None): | ||
if type(input_layer) is PythonWrapper.SpaceToDepth: | ||
super().__init__(input_layer) | ||
return | ||
|
||
layers, outputs = check_input_layers(input_layer, 1) | ||
|
||
if block_size < 1: | ||
raise ValueError('`block_size` must be < 0.') | ||
|
||
internal = PythonWrapper.SpaceToDepth(str(name), layers[0], int(outputs[0]), block_size) | ||
super().__init__(internal) | ||
|
||
@property | ||
def block_size(self): | ||
"""Gets the block size. | ||
""" | ||
return self._internal.get_block_size() | ||
|
||
@block_size.setter | ||
def block_size(self, new_block_size): | ||
"""Sets the block size. | ||
""" | ||
if new_block_size < 1: | ||
raise ValueError('`block_size` must be < 0.') | ||
self._internal.set_block_size(int(new_block_size)) | ||
|
||
# ---------------------------------------------------------------------------------------------------------------------- | ||
|
||
|
||
class DepthToSpace(Layer): | ||
"""The layer that transforms each pixel (`1 x 1 x Ch`) of 2-dimensional | ||
images into square blocks of size `k x k x Ch/(k*k)`. | ||
The elements of pixel are interpreted as an image of size `k x k x Ch/(k*k)` in channel-last ordering. | ||
As a result `H x W x Ch` image is transformed into `H*k x W*k x Ch/(k*k)` image. | ||
This operation is the inverse function of SpaceToDepth. | ||
:param input_layers: The input layers to be connected. | ||
The integer in each tuple specifies the number of the output. | ||
If not set, the first output will be used. | ||
:type input_layers: object, tuple(object, int) or list of them | ||
:param block_size: The size of the block (`k` from the formula). | ||
:type block_size: int, default=1 | ||
:param name: The layer name. | ||
:type name: str, default=None | ||
.. rubric:: Layer inputs: | ||
Has single input, of the dimensions: | ||
- **BatchLength** * **BatchWidth** * **ListSize** is equal to the number of images | ||
- **Height** is the image height | ||
- **Width** is the image width | ||
- **Depth** is equal to `1` | ||
- **Channels** is the number of channels in the image format; should be a multiple of `block_size * block_size` | ||
.. rubric:: Layer outputs: | ||
The layer has single output, of the dimensions: | ||
- **BatchLength** is equal to the input `BatchLength` | ||
- **BatchWidth** is equal to the input `BatchWidth` | ||
- **ListSize** is equal to the input `ListSize` | ||
- **Height** is equal to the input `Height * block_size` | ||
- **Width** is equal to the input `Width * block_size` | ||
- **Depth** is equal to `1` | ||
- **Channels** is equal to the input `Channels / ( block_size * block_size )` | ||
""" | ||
|
||
def __init__(self, input_layer, block_size=1, name=None): | ||
if type(input_layer) is PythonWrapper.DepthToSpace: | ||
super().__init__(input_layer) | ||
return | ||
|
||
layers, outputs = check_input_layers(input_layer, 1) | ||
|
||
if block_size < 1: | ||
raise ValueError('`block_size` must be < 0.') | ||
|
||
internal = PythonWrapper.DepthToSpace(str(name), layers[0], int(outputs[0]), block_size) | ||
super().__init__(internal) | ||
|
||
@property | ||
def block_size(self): | ||
"""Gets the block size. | ||
""" | ||
return self._internal.get_block_size() | ||
|
||
@block_size.setter | ||
def block_size(self, new_block_size): | ||
"""Sets the block size. | ||
""" | ||
if new_block_size < 1: | ||
raise ValueError('`block_size` must be < 0.') | ||
self._internal.set_block_size(int(new_block_size)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* Copyright © 2017-2021 ABBYY Production LLC | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://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. | ||
--------------------------------------------------------------------------------------------------------------*/ | ||
|
||
#include <common.h> | ||
#pragma hdrstop | ||
|
||
#include "PySpaceAndDepthLayer.h" | ||
|
||
class CPySpaceToDepthLayer : public CPyLayer { | ||
public: | ||
explicit CPySpaceToDepthLayer( CSpaceToDepthLayer& layer, CPyMathEngineOwner& mathEngineOwner ) : CPyLayer( layer, mathEngineOwner ) {} | ||
|
||
void SetBlockSize( int value ) { Layer<CSpaceToDepthLayer>()->SetBlockSize( value ); } | ||
int GetBlockSize() const { return Layer<CSpaceToDepthLayer>()->GetBlockSize(); } | ||
|
||
py::object CreatePythonObject() const | ||
{ | ||
py::object pyModule = py::module::import( "neoml.Dnn" ); | ||
py::object pyConstructor = pyModule.attr( "SpaceToDepth" ); | ||
return pyConstructor( py::cast( this ) ); | ||
} | ||
}; | ||
|
||
class CPyDepthToSpaceLayer : public CPyLayer { | ||
public: | ||
explicit CPyDepthToSpaceLayer( CDepthToSpaceLayer& layer, CPyMathEngineOwner& mathEngineOwner ) : CPyLayer( layer, mathEngineOwner ) {} | ||
|
||
void SetBlockSize( int value ) { Layer<CDepthToSpaceLayer>()->SetBlockSize( value ); } | ||
int GetBlockSize() const { return Layer<CDepthToSpaceLayer>()->GetBlockSize(); } | ||
|
||
py::object CreatePythonObject() const | ||
{ | ||
py::object pyModule = py::module::import( "neoml.Dnn" ); | ||
py::object pyConstructor = pyModule.attr( "DepthToSpace" ); | ||
return pyConstructor( py::cast( this ) ); | ||
} | ||
}; | ||
|
||
void InitializeSpaceAndDepthLayer( py::module& m ) | ||
{ | ||
py::class_<CPySpaceToDepthLayer, CPyLayer>( m, "SpaceToDepth" ) | ||
.def( py::init([]( const CPyLayer& layer ) | ||
{ | ||
return new CPySpaceToDepthLayer( *layer.Layer<CSpaceToDepthLayer>(), layer.MathEngineOwner() ); | ||
})) | ||
.def( py::init([]( const std::string& name, const CPyLayer& inputLayer, int outputNumber, int blockSize ) | ||
{ | ||
CDnn& dnn = inputLayer.Dnn(); | ||
IMathEngine& mathEngine = dnn.GetMathEngine(); | ||
|
||
CPtr<CSpaceToDepthLayer> spaceToDepth = new CSpaceToDepthLayer( mathEngine ); | ||
spaceToDepth->SetName( FindFreeLayerName( dnn, "SpaceToDepth", name ).c_str() ); | ||
dnn.AddLayer( *spaceToDepth ); | ||
spaceToDepth->Connect( 0, inputLayer.BaseLayer(), outputNumber ); | ||
CPySpaceToDepthLayer* result = new CPySpaceToDepthLayer( *spaceToDepth, inputLayer.MathEngineOwner() ); | ||
result->SetBlockSize( blockSize ); | ||
return result; | ||
})) | ||
.def( "set_block_size", &CPySpaceToDepthLayer::SetBlockSize, py::return_value_policy::reference ) | ||
.def( "get_block_size", &CPySpaceToDepthLayer::GetBlockSize, py::return_value_policy::reference ) | ||
; | ||
|
||
py::class_<CPyDepthToSpaceLayer, CPyLayer>( m, "DepthToSpace" ) | ||
.def( py::init([]( const CPyLayer& layer ) | ||
{ | ||
return new CPyDepthToSpaceLayer( *layer.Layer<CDepthToSpaceLayer>(), layer.MathEngineOwner() ); | ||
})) | ||
.def( py::init([]( const std::string& name, const CPyLayer& inputLayer, int outputNumber, int blockSize ) | ||
{ | ||
CDnn& dnn = inputLayer.Dnn(); | ||
IMathEngine& mathEngine = dnn.GetMathEngine(); | ||
|
||
CPtr<CDepthToSpaceLayer> depthToSpace = new CDepthToSpaceLayer( mathEngine ); | ||
depthToSpace->SetName( FindFreeLayerName( dnn, "DepthToSpace", name ).c_str() ); | ||
dnn.AddLayer( *depthToSpace ); | ||
depthToSpace->Connect( 0, inputLayer.BaseLayer(), outputNumber ); | ||
CPyDepthToSpaceLayer* result = new CPyDepthToSpaceLayer( *depthToSpace, inputLayer.MathEngineOwner() ); | ||
result->SetBlockSize( blockSize ); | ||
return result; | ||
})) | ||
.def( "set_block_size", &CPyDepthToSpaceLayer::SetBlockSize, py::return_value_policy::reference ) | ||
.def( "get_block_size", &CPyDepthToSpaceLayer::GetBlockSize, py::return_value_policy::reference ) | ||
; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* Copyright © 2017-2021 ABBYY Production LLC | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://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. | ||
--------------------------------------------------------------------------------------------------------------*/ | ||
|
||
#pragma once | ||
|
||
#include "PyLayer.h" | ||
|
||
void InitializeSpaceAndDepthLayer( py::module& m ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.