Skip to content

Commit 3a5fa3c

Browse files
authored
Release1.11 (#867)
* support data_format='channels_first' in BatchNormLayer * don't use tf.nn.bias_add * fix typo * rename images * update changelog * add some explaination for affine transformation * fix * update version * update readme * only cache $HOME/.cache/pip/wheels
1 parent f82ea76 commit 3a5fa3c

File tree

8 files changed

+85
-18
lines changed

8 files changed

+85
-18
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
language: python
33

44
# https://docs.travis-ci.com/user/caching/#pip-cache
5-
cache: pip
5+
cache:
6+
directories:
7+
- $HOME/.cache/pip/wheels
68

79
addons:
810
apt:
@@ -59,7 +61,7 @@ matrix:
5961
install:
6062
- |
6163
if [[ -v _DOC_AND_YAPF_TEST ]]; then
62-
pip install tensorflow
64+
pip install tensorflow
6365
pip install yapf
6466
pip install -e .[doc]
6567
else

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ To release a new version, please update the changelog as followed:
8686

8787
### Changed
8888

89+
- BatchNormLayer: support `data_format`
90+
8991
### Dependencies Update
9092
- yapf>=0.22,<0.24 => yapf>=0.22,<0.25 (PR #829)
9193
- sphinx>=1.7,<1.8 => sphinx>=1.7,<1.9 (PR #842)
@@ -132,7 +134,7 @@ To release a new version, please update the changelog as followed:
132134

133135
### Contributors
134136
- @DEKHTIARJonathan: #815 #818 #820 #823
135-
- @ndiy: #819
137+
- @ndiy: #819
136138
- @zsdonghao: #818
137139

138140

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ both English and Chinese. Please click the following icons to find the documents
7979
[![Chinese Documentation](https://img.shields.io/badge/documentation-%E4%B8%AD%E6%96%87-blue.svg)](https://tensorlayercn.readthedocs.io/)
8080
[![Chinese Book](https://img.shields.io/badge/book-%E4%B8%AD%E6%96%87-blue.svg)](http://www.broadview.com.cn/book/5059/)
8181

82+
If you want to try the experimental features on the the master branch, you can find the latest document
83+
[here](https://tensorlayer.readthedocs.io/en/latest/).
84+
8285
# Install
8386

8487
TensorLayer has pre-requisites including TensorFlow, numpy, and others. For GPU support, CUDA and cuDNN are required.
930 Bytes
Loading

docs/images/affine_transform_why.jpg

-930 Bytes
Loading

docs/modules/prepro.rst

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ preserve the content in an image. The following figure illustrates these two ben
215215
:width: 100 %
216216
:align: center
217217

218+
The major reason for combined affine transformation being fast is because it has lower computational complexity.
219+
Assume we have ``k`` affine transformations ``T1, ..., Tk``, where ``Ti`` can be represented by 3x3 matrixes.
220+
The sequential transformation can be represented as ``y = Tk (... T1(x))``,
221+
and the time complexity is ``O(k N)`` where ``N`` is the cost of applying one transformation to image ``x``.
222+
``N`` is linear to the size of ``x``.
223+
For the combined transformation ``y = (Tk ... T1) (x)``
224+
the time complexity is ``O(27(k - 1) + N) = max{O(27k), O(N)} = O(N)`` (assuming 27k << N) where 27 = 3^3 is the cost for combine two transformations.
225+
218226

219227
Get rotation matrix
220228
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,17 +269,13 @@ Apply keypoint transform
261269
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
262270
.. autofunction:: affine_transform_keypoints
263271

264-
Projective transform by points
265-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
266-
.. autofunction:: projective_transform_by_points
267-
268272

269273
Images
270274
-----------
271275

272-
- These functions only apply on a single image, use ``threading_data`` to apply multiple threading see ``tutorial_image_preprocess.py``.
273-
- All functions have argument ``is_random``.
274-
- All functions end with ``*_multi`` process all images together, usually be used for image segmentation i.e. the input and output image should be matched.
276+
Projective transform by points
277+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278+
.. autofunction:: projective_transform_by_points
275279

276280
Rotation
277281
^^^^^^^^^

tensorlayer/layers/normalization.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import tensorflow as tf
55
from tensorflow.python.training import moving_averages
6+
from tensorflow.python.framework import ops
7+
from tensorflow.python.ops import math_ops
68

79
from tensorlayer.layers.core import Layer
810
from tensorlayer.layers.core import LayersConfig
@@ -69,6 +71,52 @@ def __init__(
6971
self._add_layers(self.outputs)
7072

7173

74+
def _to_channel_first_bias(b):
75+
"""Reshape [c] to [c, 1, 1]."""
76+
channel_size = int(b.shape[0])
77+
new_shape = (channel_size, 1, 1)
78+
# new_shape = [-1, 1, 1] # doesn't work with tensorRT
79+
return tf.reshape(b, new_shape)
80+
81+
82+
def _bias_scale(x, b, data_format):
83+
"""The multiplication counter part of tf.nn.bias_add."""
84+
if data_format == 'NHWC':
85+
return x * b
86+
elif data_format == 'NCHW':
87+
return x * _to_channel_first_bias(b)
88+
else:
89+
raise ValueError('invalid data_format: %s' % data_format)
90+
91+
92+
def _bias_add(x, b, data_format):
93+
"""Alternative implementation of tf.nn.bias_add which is compatiable with tensorRT."""
94+
if data_format == 'NHWC':
95+
return tf.add(x, b)
96+
elif data_format == 'NCHW':
97+
return tf.add(x, _to_channel_first_bias(b))
98+
else:
99+
raise ValueError('invalid data_format: %s' % data_format)
100+
101+
102+
def batch_normalization(x, mean, variance, offset, scale, variance_epsilon, data_format, name=None):
103+
"""Data Format aware version of tf.nn.batch_normalization."""
104+
with ops.name_scope(name, 'batchnorm', [x, mean, variance, scale, offset]):
105+
inv = math_ops.rsqrt(variance + variance_epsilon)
106+
if scale is not None:
107+
inv *= scale
108+
109+
a = math_ops.cast(inv, x.dtype)
110+
b = math_ops.cast(offset - mean * inv if offset is not None else -mean * inv, x.dtype)
111+
112+
# Return a * x + b with customized data_format.
113+
# Currently TF doesn't have bias_scale, and tensorRT has bug in converting tf.nn.bias_add
114+
# So we reimplemted them to allow make the model work with tensorRT.
115+
# See https://github.com/tensorlayer/openpose-plus/issues/75 for more details.
116+
df = {'channels_first': 'NCHW', 'channels_last': 'NHWC'}
117+
return _bias_add(_bias_scale(x, a, df[data_format]), b, df[data_format])
118+
119+
72120
class BatchNormLayer(Layer):
73121
"""
74122
The :class:`BatchNormLayer` is a batch normalization layer for both fully-connected and convolution outputs.
@@ -115,6 +163,7 @@ def __init__(
115163
beta_init=tf.zeros_initializer,
116164
gamma_init=tf.random_normal_initializer(mean=1.0, stddev=0.002),
117165
moving_mean_init=tf.zeros_initializer(),
166+
data_format='channels_last',
118167
name='batchnorm_layer',
119168
):
120169
super(BatchNormLayer, self).__init__(prev_layer=prev_layer, act=act, name=name)
@@ -123,14 +172,21 @@ def __init__(
123172
"BatchNormLayer %s: decay: %f epsilon: %f act: %s is_train: %s" %
124173
(self.name, decay, epsilon, self.act.__name__ if self.act is not None else 'No Activation', is_train)
125174
)
126-
if decay > 1:
175+
if decay < 0 or 1 < decay:
127176
raise Exception("decay should be between 0 to 1")
128177

129178
x_shape = self.inputs.get_shape()
130-
params_shape = x_shape[-1:]
179+
if data_format == 'channels_last':
180+
axis = len(x_shape) - 1
181+
elif data_format == 'channels_first':
182+
axis = 1
183+
else:
184+
raise ValueError('data_format should be either %s or %s' % ('channels_last', 'channels_first'))
185+
params_shape = x_shape[axis]
131186

132187
with tf.variable_scope(name):
133-
axis = list(range(len(x_shape) - 1))
188+
axes = [i for i in range(len(x_shape)) if i != axis]
189+
134190
# 1. beta, gamma
135191
variables = []
136192

@@ -176,7 +232,7 @@ def __init__(
176232

177233
# 3.
178234
# These ops will only be preformed when training.
179-
mean, variance = tf.nn.moments(self.inputs, axis)
235+
mean, variance = tf.nn.moments(self.inputs, axes)
180236

181237
update_moving_mean = moving_averages.assign_moving_average(
182238
moving_mean, mean, decay, zero_debias=False
@@ -196,7 +252,7 @@ def mean_var_with_update():
196252
mean, var = moving_mean, moving_variance
197253

198254
self.outputs = self._apply_activation(
199-
tf.nn.batch_normalization(self.inputs, mean, var, beta, gamma, epsilon)
255+
batch_normalization(self.inputs, mean, var, beta, gamma, epsilon, data_format)
200256
)
201257

202258
variables.extend([moving_mean, moving_variance])

tensorlayer/package_info.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
3-
"""Deep learning and Reinforcement learning library for Researchers and Engineers"""
3+
"""Deep learning and Reinforcement learning library for Researchers and Engineers."""
44

55
# Use the following formatting: (major, minor, patch, prerelease)
6-
VERSION = (1, 10, 1, "")
6+
VERSION = (1, 11, 0, 'rc0')
77
__shortversion__ = '.'.join(map(str, VERSION[:3]))
8-
__version__ = '.'.join(map(str, VERSION[:3])) + "".join(VERSION[3:])
8+
__version__ = '.'.join(map(str, VERSION[:3])) + ''.join(VERSION[3:])
99

1010
__package_name__ = 'tensorlayer'
1111
__contact_names__ = 'TensorLayer Contributors'

0 commit comments

Comments
 (0)