Skip to content

Commit 8b47d90

Browse files
committed
add 'actual_shape' attribute. test=develop
1 parent fef2faa commit 8b47d90

File tree

4 files changed

+148
-28
lines changed

4 files changed

+148
-28
lines changed

paddle/fluid/API.spec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ paddle.fluid.layers.label_smooth ArgSpec(args=['label', 'prior_dist', 'epsilon',
118118
paddle.fluid.layers.roi_pool ArgSpec(args=['input', 'rois', 'pooled_height', 'pooled_width', 'spatial_scale'], varargs=None, keywords=None, defaults=(1, 1, 1.0))
119119
paddle.fluid.layers.roi_align ArgSpec(args=['input', 'rois', 'pooled_height', 'pooled_width', 'spatial_scale', 'sampling_ratio', 'name'], varargs=None, keywords=None, defaults=(1, 1, 1.0, -1, None))
120120
paddle.fluid.layers.dice_loss ArgSpec(args=['input', 'label', 'epsilon'], varargs=None, keywords=None, defaults=(1e-05,))
121-
paddle.fluid.layers.image_resize ArgSpec(args=['input', 'out_shape', 'scale', 'name', 'resample'], varargs=None, keywords=None, defaults=(None, None, None, 'BILINEAR'))
121+
paddle.fluid.layers.image_resize ArgSpec(args=['input', 'out_shape', 'scale', 'name', 'resample', 'actual_shape'], varargs=None, keywords=None, defaults=(None, None, None, 'BILINEAR', None))
122122
paddle.fluid.layers.image_resize_short ArgSpec(args=['input', 'out_short_len', 'resample'], varargs=None, keywords=None, defaults=('BILINEAR',))
123-
paddle.fluid.layers.resize_bilinear ArgSpec(args=['input', 'out_shape', 'scale', 'name'], varargs=None, keywords=None, defaults=(None, None, None))
124-
paddle.fluid.layers.resize_nearest ArgSpec(args=['input', 'out_shape', 'scale', 'name'], varargs=None, keywords=None, defaults=(None, None, None))
123+
paddle.fluid.layers.resize_bilinear ArgSpec(args=['input', 'out_shape', 'scale', 'name', 'actual_shape'], varargs=None, keywords=None, defaults=(None, None, None, None))
124+
paddle.fluid.layers.resize_nearest ArgSpec(args=['input', 'out_shape', 'scale', 'name', 'actual_shape'], varargs=None, keywords=None, defaults=(None, None, None, None))
125125
paddle.fluid.layers.gather ArgSpec(args=['input', 'index'], varargs=None, keywords=None, defaults=None)
126126
paddle.fluid.layers.scatter ArgSpec(args=['input', 'index', 'updates', 'name'], varargs=None, keywords=None, defaults=(None,))
127127
paddle.fluid.layers.sequence_scatter ArgSpec(args=['input', 'index', 'updates', 'name'], varargs=None, keywords=None, defaults=(None,))

paddle/fluid/operators/interpolate_op.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ class InterpolateOp : public framework::OperatorWithKernel {
4040
int out_w = ctx->Attrs().Get<int>("out_w");
4141
PADDLE_ENFORCE_EQ(dim_x.size(), 4, "X's dimension must be 4");
4242

43-
if (ctx->HasInput("OutSize")) {
43+
if (ctx->HasInput("OutSize") && ctx->IsRuntime()) {
4444
auto out_size_dim = ctx->GetInputDim("OutSize");
4545
PADDLE_ENFORCE_EQ(out_size_dim.size(), 1,
4646
"OutSize's dimension size must be 1");
4747
PADDLE_ENFORCE_EQ(out_size_dim[0], 2, "OutSize's dim[0] must be 2");
48+
ctx->ShareLoD("X", "Out");
49+
return;
4850
}
4951
std::vector<int64_t> dim_out({dim_x[0], dim_x[1], out_h, out_w});
5052
ctx->SetOutputDim("Out", framework::make_ddim(dim_out));
@@ -86,7 +88,7 @@ class InterpolateOpMaker : public framework::OpProtoAndCheckerMaker {
8688
interpolation.
8789
8890
Nearest neighbor interpolation is to perform nearest neighbor interpolation
89-
in bot the 3rd dimention(in height direction) and the 4th dimention(in width
91+
in both the 3rd dimention(in height direction) and the 4th dimention(in width
9092
direction) on input tensor.
9193
9294
Bilinear interpolation is an extension of linear interpolation for

python/paddle/fluid/layers/nn.py

Lines changed: 105 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5575,7 +5575,8 @@ def image_resize(input,
55755575
out_shape=None,
55765576
scale=None,
55775577
name=None,
5578-
resample='BILINEAR'):
5578+
resample='BILINEAR',
5579+
actual_shape=None):
55795580
"""
55805581
**Resize a Batch of Images**
55815582
@@ -5600,25 +5601,50 @@ def image_resize(input,
56005601
Default: None
56015602
name(str|None): A name for this layer(optional). If set None, the layer
56025603
will be named automatically.
5603-
resample(str): The resample method. It can only be 'BILINEAR' currently.
5604+
resample(str): The resample method. It supports 'BILINEAR' and 'NEAREST'
5605+
currently.
56045606
Default: 'BILINEAR'
5607+
actual_shape(Variable): An optional input to specify output shape
5608+
dynamically. If provided, image resize
5609+
according to this given shape rather than
5610+
:attr:`out_shape` and :attr:`scale` specifying
5611+
shape. That is to say actual_shape has the
5612+
highest priority. It is recommended to use
5613+
actual_shape instead of :attr:`out_shape` if you
5614+
want to specify output shape dynamically. When
5615+
using actual_shape to specify output shape, one of
5616+
:attr:`out_shape` and :attr:`scale` should also be
5617+
set, otherwise errors would be occured in graph
5618+
constructing stage.
5619+
Default: None
56055620
56065621
Returns:
56075622
Variable: The output is a 4-D tensor of the shape
56085623
(num_batches, channls, out_h, out_w).
56095624
5625+
Raises:
5626+
TypeError: out_shape should be a list or tuple or Variable.
5627+
TypeError: actual_shape should either be Variable or None.
5628+
ValueError: The 'resample' of image_resize can only be 'BILINEAR'
5629+
or 'NEAREST' currently.
5630+
ValueError: One of out_shape and scale must not be None.
5631+
ValueError: out_shape length should be 2.
5632+
56105633
Examples:
56115634
.. code-block:: python
56125635
56135636
out = fluid.layers.image_resize(input, out_shape=[12, 12])
56145637
"""
5615-
resample_methods = {'BILINEAR': 'bilinear', 'NEAREST': 'nearest'}
5638+
resample_methods = {
5639+
'BILINEAR': 'bilinear',
5640+
'NEAREST': 'nearest',
5641+
}
56165642
if resample not in resample_methods:
56175643
raise ValueError(
5618-
"The 'resample' of image_resize can only be 'BILINEAR' and 'NEAREST' currently."
5644+
"The 'resample' of image_resize can only be 'BILINEAR' or 'NEAREST' currently."
56195645
)
56205646
if out_shape is None and scale is None:
5621-
raise ValueError("One of out_shape and scale must not be None")
5647+
raise ValueError("One of out_shape and scale must not be None.")
56225648
helper = LayerHelper('interpolate', **locals())
56235649
dtype = helper.input_dtype()
56245650

@@ -5629,19 +5655,28 @@ def _is_list_or_turple_(data):
56295655
out_w = 0
56305656
inputs = {"X": input}
56315657
if out_shape is not None:
5632-
if not (_is_list_or_turple_(out_shape) and
5633-
len(out_shape) == 2) and not isinstance(out_shape, Variable):
5634-
raise ValueError('out_shape should be a list or tuple or variable')
5635-
if _is_list_or_turple_(out_shape):
5636-
out_shape = list(map(int, out_shape))
5637-
out_h = out_shape[0]
5638-
out_w = out_shape[1]
5639-
else:
5658+
if isinstance(out_shape, Variable):
5659+
warnings.warn("out_shape as Variable type is deprecated, \
5660+
it is recommended to use actual_shape instead of \
5661+
out_shape to specify output shape dynamically.")
56405662
inputs['OutSize'] = out_shape
5663+
elif not (_is_list_or_turple_(out_shape)):
5664+
raise TypeError("out_shape should be a list or tuple or Variable.")
5665+
elif len(out_shape) != 2:
5666+
raise ValueError("out_shape length should be 2.")
5667+
5668+
out_shape = list(map(int, out_shape))
5669+
out_h = out_shape[0]
5670+
out_w = out_shape[1]
56415671
else:
56425672
out_h = int(input.shape[2] * scale)
56435673
out_w = int(input.shape[3] * scale)
56445674

5675+
if isinstance(actual_shape, Variable):
5676+
inputs["OutSize"] = actual_shape
5677+
elif actual_shape is not None:
5678+
raise TypeError("actual_shape should either be Variable or None.")
5679+
56455680
out = helper.create_variable_for_type_inference(dtype)
56465681
helper.append_op(
56475682
type='interpolate',
@@ -5656,9 +5691,24 @@ def _is_list_or_turple_(data):
56565691

56575692

56585693
@templatedoc(op_type="interpolate")
5659-
def resize_bilinear(input, out_shape=None, scale=None, name=None):
5694+
def resize_bilinear(input,
5695+
out_shape=None,
5696+
scale=None,
5697+
name=None,
5698+
actual_shape=None):
56605699
"""
5661-
${comment}
5700+
Resize input by performing bilinear interpolation based on given
5701+
output shape which specified by actual_shape, out_shape and scale
5702+
in priority order.
5703+
5704+
Bilinear interpolation is an extension of linear interpolation for
5705+
interpolating functions of two variables (e.g. H-direction and
5706+
W-direction in this op) on a rectilinear 2D grid. The key idea is
5707+
to perform linear interpolation first in one direction, and then
5708+
again in the other direction.
5709+
5710+
For details of bilinear interpolation, please refer to Wikipedia:
5711+
https://en.wikipedia.org/wiki/Bilinear_interpolation
56625712
56635713
Args:
56645714
input(${x_type}): ${x_comment}.
@@ -5670,18 +5720,41 @@ def resize_bilinear(input, out_shape=None, scale=None, name=None):
56705720
a higher priority than scale. Default: None.
56715721
56725722
name(str|None): The output variable name.
5723+
actual_shape(Variable): An optional input to specify output shape
5724+
dynamically. If provided, image resize
5725+
according to this given shape rather than
5726+
:attr:`out_shape` and :attr:`scale` specifying
5727+
shape. That is to say actual_shape has the
5728+
highest priority. It is recommended to use
5729+
actual_shape instead of :attr:`out_shape` if you
5730+
want to specify output shape dynamically. When
5731+
using actual_shape to specify output shape, one of
5732+
:attr:`out_shape` and :attr:`scale` should also be
5733+
set, otherwise errors would be occured in graph
5734+
constructing stage.
5735+
Default: None
56735736
56745737
Returns:
56755738
${out_comment}.
56765739
"""
56775740

5678-
return image_resize(input, out_shape, scale, name, 'BILINEAR')
5741+
return image_resize(input, out_shape, scale, name, 'BILINEAR', actual_shape)
56795742

56805743

56815744
@templatedoc(op_type="interpolate")
5682-
def resize_nearest(input, out_shape=None, scale=None, name=None):
5745+
def resize_nearest(input,
5746+
out_shape=None,
5747+
scale=None,
5748+
name=None,
5749+
actual_shape=None):
56835750
"""
5684-
${comment}
5751+
Resize input by performing nearest neighbor interpolation in both the
5752+
3rd dimention(in height direction) and the 4th dimention(in width
5753+
direction) based on given output shape which specified by actual_shape,
5754+
out_shape and scale in priority order.
5755+
5756+
For details of nearest neighbor interpolation, please refer to Wikipedia:
5757+
https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation
56855758
56865759
Args:
56875760
input(${x_type}): ${x_comment}.
@@ -5693,12 +5766,25 @@ def resize_nearest(input, out_shape=None, scale=None, name=None):
56935766
a higher priority than scale. Default: None.
56945767
56955768
name(str|None): The output variable name.
5769+
actual_shape(Variable): An optional input to specify output shape
5770+
dynamically. If provided, image resize
5771+
according to this given shape rather than
5772+
:attr:`out_shape` and :attr:`scale` specifying
5773+
shape. That is to say actual_shape has the
5774+
highest priority. It is recommended to use
5775+
actual_shape instead of :attr:`out_shape` if you
5776+
want to specify output shape dynamically. When
5777+
using actual_shape to specify output shape, one of
5778+
:attr:`out_shape` and :attr:`scale` should also be
5779+
set, otherwise errors would be occured in graph
5780+
constructing stage.
5781+
Default: None
56965782
56975783
Returns:
56985784
${out_comment}.
56995785
"""
57005786

5701-
return image_resize(input, out_shape, scale, name, 'NEAREST')
5787+
return image_resize(input, out_shape, scale, name, 'NEAREST', actual_shape)
57025788

57035789

57045790
def image_resize_short(input, out_short_len, resample='BILINEAR'):

python/paddle/fluid/tests/unittests/test_interpolate_op.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@
2020
import paddle.fluid.core as core
2121

2222

23-
def nearest_neighbor_interp_np(X, out_h, out_w, out_size=None):
23+
def nearest_neighbor_interp_np(X,
24+
out_h,
25+
out_w,
26+
out_size=None,
27+
actual_shape=None):
2428
"""nearest neighbor interpolation implement in shape [N, C, H, W]"""
2529
if out_size is not None:
2630
out_h = out_size[0]
2731
out_w = out_size[1]
32+
if actual_shape is not None:
33+
out_h = actual_shape[0]
34+
out_w = actual_shape[1]
2835
n, c, in_h, in_w = X.shape
2936

3037
ratio_h = ratio_w = 0.0
@@ -43,11 +50,14 @@ def nearest_neighbor_interp_np(X, out_h, out_w, out_size=None):
4350
return out.astype(X.dtype)
4451

4552

46-
def bilinear_interp_np(input, out_h, out_w, out_size):
53+
def bilinear_interp_np(input, out_h, out_w, out_size=None, actual_shape=None):
4754
"""bilinear interpolation implement in shape [N, C, H, W]"""
4855
if out_size is not None:
4956
out_h = out_size[0]
5057
out_w = out_size[1]
58+
if actual_shape is not None:
59+
out_h = actual_shape[0]
60+
out_w = actual_shape[1]
5161
batch_size, channel, in_h, in_w = input.shape
5262
if out_h > 1:
5363
ratio_h = (in_h - 1.0) / (out_h - 1.0)
@@ -86,15 +96,18 @@ def bilinear_interp_np(input, out_h, out_w, out_size):
8696
class TestInterpolateOp(OpTest):
8797
def setUp(self):
8898
self.out_size = None
99+
self.actual_shape = None
89100
self.init_test_case()
90101
self.op_type = "interpolate"
91102
input_np = np.random.random(self.input_shape).astype("float32")
92103

93104
output_np = INTERPOLATE_FUNCS[self.interp_method](
94-
input_np, self.out_h, self.out_w, self.out_size)
105+
input_np, self.out_h, self.out_w, self.out_size, self.actual_shape)
95106
self.inputs = {'X': input_np}
96107
if self.out_size is not None:
97108
self.inputs['OutSize'] = self.out_size
109+
if self.actual_shape is not None:
110+
self.inputs['OutSize'] = self.actual_shape
98111
self.attrs = {
99112
'out_h': self.out_h,
100113
'out_w': self.out_w,
@@ -167,6 +180,15 @@ def init_test_case(self):
167180
self.out_size = np.array([65, 129]).astype("int32")
168181

169182

183+
class TestBilinearInterpActualShape(TestInterpolateOp):
184+
def init_test_case(self):
185+
self.interp_method = 'bilinear'
186+
self.input_shape = [3, 2, 32, 16]
187+
self.out_h = 64
188+
self.out_w = 32
189+
self.out_size = np.array([66, 40]).astype("int32")
190+
191+
170192
class TestBilinearInterpBigScale(TestInterpolateOp):
171193
def init_test_case(self):
172194
self.interp_method = 'bilinear'
@@ -179,12 +201,13 @@ def init_test_case(self):
179201
class TestInterpolateOpUint8(OpTest):
180202
def setUp(self):
181203
self.out_size = None
204+
self.actual_shape = None
182205
self.init_test_case()
183206
self.op_type = "interpolate"
184207
input_np = np.random.randint(
185208
low=0, high=256, size=self.input_shape).astype("uint8")
186209
output_np = INTERPOLATE_FUNCS[self.interp_method](
187-
input_np, self.out_h, self.out_w, self.out_size)
210+
input_np, self.out_h, self.out_w, self.out_size, self.actual_shape)
188211
self.inputs = {'X': input_np}
189212
if self.out_size is not None:
190213
self.inputs['OutSize'] = self.out_size
@@ -273,6 +296,15 @@ def init_test_case(self):
273296
self.out_size = np.array([65, 129]).astype("int32")
274297

275298

299+
class TestNearestNeighborInterpActualShape(TestInterpolateOp):
300+
def init_test_case(self):
301+
self.interp_method = 'nearest'
302+
self.input_shape = [3, 2, 32, 16]
303+
self.out_h = 64
304+
self.out_w = 32
305+
self.out_size = np.array([66, 40]).astype("int32")
306+
307+
276308
class TestNearestNeighborInterpBigScale(TestInterpolateOp):
277309
def init_test_case(self):
278310
self.interp_method = 'nearest'

0 commit comments

Comments
 (0)