Skip to content

Commit 66f8d43

Browse files
author
Jonathan DEKHTIAR
authored
Layer API Refactoring (#692)
* Layer API Refactoring * Conv Layers refactored * dense layers refactored * Error fix in ElementwiseLayer * Various cleaning * docstring cleaning * Documentation print clean * Changelog updated * @zsdonghao corrections added * Import Bug Fix
1 parent 58f4620 commit 66f8d43

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4537
-4063
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,14 @@ To release a new version, please update the changelog as followed:
239239
- Input Layers have been removed from `tl.layers.core` and added to `tl.layers.inputs` (by @DEKHTIARJonathan in #675)
240240
- Input Layers are now considered as true layers in the graph (they represent a placeholder), unittests have been updated (by @DEKHTIARJonathan in #675)
241241
- Layer API is simplified, with automatic feeding `prev_layer` into `self.inputs` (by @DEKHTIARJonathan in #675)
242+
- Convolution Layers have been refactored under the folder `tensorlayer/layers/convolution` (by @DEKHTIARJonathan in #692)
243+
- Dense Layers have been refactored under the folder `tensorlayer/layers/dense` (by @DEKHTIARJonathan in #692)
244+
- Numerous Layer utility functions have been refactored in the file `tensorlayer/layers/utils.py` (by @DEKHTIARJonathan in #692)
242245

243246
### Deprecated
244247
- `tl.layers.TimeDistributedLayer` argurment `args` is deprecated in favor of `layer_args` (by @DEKHTIARJonathan in #667)
245-
- `tl.act.leaky_relu` have been deprecated in favor of `tf.nn.leaky_relu` (by @DEKHTIARJonathan in #686)
248+
- `tl.act.leaky_relu` has been deprecated in favor of `tf.nn.leaky_relu` (by @DEKHTIARJonathan in #686)
249+
- `tl.layers.initialize_global_variables` has been deprecated in favor of `tf.global_variables_initializer` (by @DEKHTIARJonathan in #692)
246250

247251
### Removed
248252
- `assert()` calls remove and replaced by `raise AssertionError()` (by @DEKHTIARJonathan in #667)

example/tutorial_imagenet_inceptionV3_distributed.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -408,12 +408,12 @@ def run_worker(task_spec, checkpoints_path, batch_size=32, epochs=10):
408408
logging.basicConfig(level=logging.INFO, format='%(asctime)-15s %(message)s')
409409

410410
if not tf.gfile.Exists(ILSVRC_DIR):
411-
logging.error('We couldn\'t find the directory "{}"'.format(ILSVRC_DIR))
412-
logging.error('You need to modify the variable BASE_DIR with the path where the dataset is.')
413-
logging.error(
414-
'The dataset can be downloaded from http://www.image-net.org/ or from the Kaggle competition: https://www.kaggle.com/c/imagenet-object-localization-challenge/data'
411+
raise FileNotFoundError(
412+
'We cannot find the directory "{}"\n'
413+
'You need to modify the variable BASE_DIR with the path where the dataset is.\n'
414+
'The dataset can be downloaded from http://www.image-net.org/ or from the Kaggle competition:\n'
415+
'https://www.kaggle.com/c/imagenet-object-localization-challenge/data'.format(ILSVRC_DIR)
415416
)
416-
exit(-1)
417417

418418
# args
419419
parser = argparse.ArgumentParser()

tensorlayer/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from . import decorators
3333
from . import distributed
3434
from . import files
35+
from . import initializers
3536
from . import iterate
3637
from . import layers
3738
from . import lazy_imports

tensorlayer/cost.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def cross_entropy_seq(logits, target_seqs, batch_size=None): #, batch_size=1, n
390390
>>> targets = tf.placeholder(tf.int32, [batch_size, n_steps])
391391
>>> # build the network
392392
>>> print(net.outputs)
393-
... (batch_size * n_steps, n_classes)
393+
(batch_size * n_steps, n_classes)
394394
>>> cost = tl.cost.cross_entropy_seq(network.outputs, targets)
395395
396396
"""
@@ -445,10 +445,10 @@ def cross_entropy_seq_with_mask(logits, target_seqs, input_mask, return_details=
445445
... return_seq_2d = True,
446446
... name = 'dynamicrnn')
447447
>>> print(net.outputs)
448-
... (?, 256)
448+
(?, 256)
449449
>>> net = tl.layers.DenseLayer(net, n_units=vocab_size, name="output")
450450
>>> print(net.outputs)
451-
... (?, 10000)
451+
(?, 10000)
452452
>>> loss = tl.cost.cross_entropy_seq_with_mask(net.outputs, target_seqs, input_mask)
453453
454454
"""

tensorlayer/db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,9 @@ def save_job(self, script=None, args=None):
367367
>>> # Run your job
368368
>>> temp = db.find_one_job(args={'job_id': 1})
369369
>>> print(temp['learning_rate'])
370-
... 0.01
370+
0.01
371371
>>> import _your_script
372-
... running your script
372+
running your script
373373
"""
374374

375375
if args is None:

tensorlayer/files/dataset_loaders/imdb_dataset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ def load_imdb_dataset(
4040
>>> X_train, y_train, X_test, y_test = tl.files.load_imdb_dataset(
4141
... nb_words=20000, test_split=0.2)
4242
>>> print('X_train.shape', X_train.shape)
43-
... (20000,) [[1, 62, 74, ... 1033, 507, 27],[1, 60, 33, ... 13, 1053, 7]..]
43+
(20000,) [[1, 62, 74, ... 1033, 507, 27],[1, 60, 33, ... 13, 1053, 7]..]
4444
>>> print('y_train.shape', y_train.shape)
45-
... (20000,) [1 0 0 ..., 1 0 1]
45+
(20000,) [1 0 0 ..., 1 0 1]
4646
4747
References
4848
-----------

tensorlayer/files/dataset_loaders/voc_dataset.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,24 @@ def load_voc_dataset(path='data', dataset='2012', contain_classes_in_person=Fals
6767
>>> n_objs_list, objs_info_list, objs_info_dicts = tl.files.load_voc_dataset(dataset="2012", contain_classes_in_person=False)
6868
>>> idx = 26
6969
>>> print(classes)
70-
... ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
70+
['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
7171
>>> print(classes_dict)
72-
... {'sheep': 16, 'horse': 12, 'bicycle': 1, 'bottle': 4, 'cow': 9, 'sofa': 17, 'car': 6, 'dog': 11, 'cat': 7, 'person': 14, 'train': 18, 'diningtable': 10, 'aeroplane': 0, 'bus': 5, 'pottedplant': 15, 'tvmonitor': 19, 'chair': 8, 'bird': 2, 'boat': 3, 'motorbike': 13}
72+
{'sheep': 16, 'horse': 12, 'bicycle': 1, 'bottle': 4, 'cow': 9, 'sofa': 17, 'car': 6, 'dog': 11, 'cat': 7, 'person': 14, 'train': 18, 'diningtable': 10, 'aeroplane': 0, 'bus': 5, 'pottedplant': 15, 'tvmonitor': 19, 'chair': 8, 'bird': 2, 'boat': 3, 'motorbike': 13}
7373
>>> print(imgs_file_list[idx])
74-
... data/VOC/VOC2012/JPEGImages/2007_000423.jpg
74+
data/VOC/VOC2012/JPEGImages/2007_000423.jpg
7575
>>> print(n_objs_list[idx])
76-
... 2
76+
2
7777
>>> print(imgs_ann_file_list[idx])
78-
... data/VOC/VOC2012/Annotations/2007_000423.xml
78+
data/VOC/VOC2012/Annotations/2007_000423.xml
7979
>>> print(objs_info_list[idx])
80-
... 14 0.173 0.461333333333 0.142 0.496
81-
... 14 0.828 0.542666666667 0.188 0.594666666667
80+
14 0.173 0.461333333333 0.142 0.496
81+
14 0.828 0.542666666667 0.188 0.594666666667
8282
>>> ann = tl.prepro.parse_darknet_ann_str_to_list(objs_info_list[idx])
8383
>>> print(ann)
84-
... [[14, 0.173, 0.461333333333, 0.142, 0.496], [14, 0.828, 0.542666666667, 0.188, 0.594666666667]]
84+
[[14, 0.173, 0.461333333333, 0.142, 0.496], [14, 0.828, 0.542666666667, 0.188, 0.594666666667]]
8585
>>> c, b = tl.prepro.parse_darknet_ann_list_to_cls_box(ann)
8686
>>> print(c, b)
87-
... [14, 14] [[0.173, 0.461333333333, 0.142, 0.496], [0.828, 0.542666666667, 0.188, 0.594666666667]]
87+
[14, 14] [[0.173, 0.461333333333, 0.142, 0.496], [0.828, 0.542666666667, 0.188, 0.594666666667]]
8888
8989
References
9090
-------------

tensorlayer/files/utils.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -532,9 +532,9 @@ def load_imdb_dataset(
532532
>>> X_train, y_train, X_test, y_test = tl.files.load_imdb_dataset(
533533
... nb_words=20000, test_split=0.2)
534534
>>> print('X_train.shape', X_train.shape)
535-
... (20000,) [[1, 62, 74, ... 1033, 507, 27],[1, 60, 33, ... 13, 1053, 7]..]
535+
(20000,) [[1, 62, 74, ... 1033, 507, 27],[1, 60, 33, ... 13, 1053, 7]..]
536536
>>> print('y_train.shape', y_train.shape)
537-
... (20000,) [1 0 0 ..., 1 0 1]
537+
(20000,) [1 0 0 ..., 1 0 1]
538538
539539
References
540540
-----------
@@ -1046,24 +1046,24 @@ def load_voc_dataset(path='data', dataset='2012', contain_classes_in_person=Fals
10461046
>>> n_objs_list, objs_info_list, objs_info_dicts = tl.files.load_voc_dataset(dataset="2012", contain_classes_in_person=False)
10471047
>>> idx = 26
10481048
>>> print(classes)
1049-
... ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
1049+
['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
10501050
>>> print(classes_dict)
1051-
... {'sheep': 16, 'horse': 12, 'bicycle': 1, 'bottle': 4, 'cow': 9, 'sofa': 17, 'car': 6, 'dog': 11, 'cat': 7, 'person': 14, 'train': 18, 'diningtable': 10, 'aeroplane': 0, 'bus': 5, 'pottedplant': 15, 'tvmonitor': 19, 'chair': 8, 'bird': 2, 'boat': 3, 'motorbike': 13}
1051+
{'sheep': 16, 'horse': 12, 'bicycle': 1, 'bottle': 4, 'cow': 9, 'sofa': 17, 'car': 6, 'dog': 11, 'cat': 7, 'person': 14, 'train': 18, 'diningtable': 10, 'aeroplane': 0, 'bus': 5, 'pottedplant': 15, 'tvmonitor': 19, 'chair': 8, 'bird': 2, 'boat': 3, 'motorbike': 13}
10521052
>>> print(imgs_file_list[idx])
1053-
... data/VOC/VOC2012/JPEGImages/2007_000423.jpg
1053+
data/VOC/VOC2012/JPEGImages/2007_000423.jpg
10541054
>>> print(n_objs_list[idx])
1055-
... 2
1055+
2
10561056
>>> print(imgs_ann_file_list[idx])
1057-
... data/VOC/VOC2012/Annotations/2007_000423.xml
1057+
data/VOC/VOC2012/Annotations/2007_000423.xml
10581058
>>> print(objs_info_list[idx])
1059-
... 14 0.173 0.461333333333 0.142 0.496
1060-
... 14 0.828 0.542666666667 0.188 0.594666666667
1059+
14 0.173 0.461333333333 0.142 0.496
1060+
14 0.828 0.542666666667 0.188 0.594666666667
10611061
>>> ann = tl.prepro.parse_darknet_ann_str_to_list(objs_info_list[idx])
10621062
>>> print(ann)
1063-
... [[14, 0.173, 0.461333333333, 0.142, 0.496], [14, 0.828, 0.542666666667, 0.188, 0.594666666667]]
1063+
[[14, 0.173, 0.461333333333, 0.142, 0.496], [14, 0.828, 0.542666666667, 0.188, 0.594666666667]]
10641064
>>> c, b = tl.prepro.parse_darknet_ann_list_to_cls_box(ann)
10651065
>>> print(c, b)
1066-
... [14, 14] [[0.173, 0.461333333333, 0.142, 0.496], [0.828, 0.542666666667, 0.188, 0.594666666667]]
1066+
[14, 14] [[0.173, 0.461333333333, 0.142, 0.496], [0.828, 0.542666666667, 0.188, 0.594666666667]]
10671067
10681068
References
10691069
-------------
@@ -1901,7 +1901,7 @@ def save_any_to_npy(save_dict=None, name='file.npy'):
19011901
>>> tl.files.save_any_to_npy(save_dict={'data': ['a','b']}, name='test.npy')
19021902
>>> data = tl.files.load_npy_to_any(name='test.npy')
19031903
>>> print(data)
1904-
... {'data': ['a','b']}
1904+
{'data': ['a','b']}
19051905
19061906
"""
19071907
if save_dict is None:
@@ -2124,9 +2124,9 @@ def natural_keys(text):
21242124
----------
21252125
>>> l = ['im1.jpg', 'im31.jpg', 'im11.jpg', 'im21.jpg', 'im03.jpg', 'im05.jpg']
21262126
>>> l.sort(key=tl.files.natural_keys)
2127-
... ['im1.jpg', 'im03.jpg', 'im05', 'im11.jpg', 'im21.jpg', 'im31.jpg']
2127+
['im1.jpg', 'im03.jpg', 'im05', 'im11.jpg', 'im21.jpg', 'im31.jpg']
21282128
>>> l.sort() # that is what we dont want
2129-
... ['im03.jpg', 'im05', 'im1.jpg', 'im11.jpg', 'im21.jpg', 'im31.jpg']
2129+
['im03.jpg', 'im05', 'im1.jpg', 'im11.jpg', 'im21.jpg', 'im31.jpg']
21302130
21312131
References
21322132
----------

tensorlayer/initializers.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#! /usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
import numpy as np
5+
import tensorflow as tf
6+
7+
from tensorlayer.layers.core import LayersConfig
8+
9+
__all__ = ['deconv2d_bilinear_upsampling_initializer']
10+
11+
12+
def deconv2d_bilinear_upsampling_initializer(shape):
13+
"""Returns the initializer that can be passed to DeConv2dLayer for initializing the
14+
weights in correspondence to channel-wise bilinear up-sampling.
15+
Used in segmentation approaches such as [FCN](https://arxiv.org/abs/1605.06211)
16+
17+
Parameters
18+
----------
19+
shape : tuple of int
20+
The shape of the filters, [height, width, output_channels, in_channels].
21+
It must match the shape passed to DeConv2dLayer.
22+
23+
Returns
24+
-------
25+
``tf.constant_initializer``
26+
A constant initializer with weights set to correspond to per channel bilinear upsampling
27+
when passed as W_int in DeConv2dLayer
28+
29+
Examples
30+
--------
31+
- Upsampling by a factor of 2, ie e.g 100->200
32+
>>> import tensorflow as tf
33+
>>> import tensorlayer as tl
34+
>>> rescale_factor = 2
35+
>>> imsize = 128
36+
>>> num_channels = 3
37+
>>> filter_shape = (5, 5)
38+
>>> filter_size = (2 * rescale_factor - rescale_factor % 2) #Corresponding bilinear filter size
39+
>>> num_in_channels = 3
40+
>>> num_out_channels = 3
41+
>>> deconv_filter_shape = (filter_size, filter_size, num_out_channels, num_in_channels)
42+
>>> x = tf.placeholder(tf.float32, (1, imsize, imsize, num_channels))
43+
>>> net = tl.layers.InputLayer(x, name='input_layer')
44+
>>> bilinear_init = deconv2d_bilinear_upsampling_initializer(shape=filter_shape)
45+
>>> net = tl.layers.DeConv2dLayer(net,
46+
... shape=filter_shape,
47+
... output_shape=(1, imsize*rescale_factor, imsize*rescale_factor, num_out_channels),
48+
... strides=(1, rescale_factor, rescale_factor, 1),
49+
... W_init=bilinear_init,
50+
... padding='SAME',
51+
... act=None, name='g/h1/decon2d')
52+
53+
"""
54+
if shape[0] != shape[1]:
55+
raise Exception('deconv2d_bilinear_upsampling_initializer only supports symmetrical filter sizes')
56+
57+
if shape[3] < shape[2]:
58+
raise Exception(
59+
'deconv2d_bilinear_upsampling_initializer behaviour is not defined for num_in_channels < num_out_channels '
60+
)
61+
62+
filter_size = shape[0]
63+
num_out_channels = shape[2]
64+
num_in_channels = shape[3]
65+
66+
# Create bilinear filter kernel as numpy array
67+
bilinear_kernel = np.zeros([filter_size, filter_size], dtype=np.float32)
68+
scale_factor = (filter_size + 1) // 2
69+
if filter_size % 2 == 1:
70+
center = scale_factor - 1
71+
else:
72+
center = scale_factor - 0.5
73+
for x in range(filter_size):
74+
for y in range(filter_size):
75+
bilinear_kernel[x, y] = (1 - abs(x - center) / scale_factor) * (1 - abs(y - center) / scale_factor)
76+
weights = np.zeros((filter_size, filter_size, num_out_channels, num_in_channels))
77+
for i in range(num_out_channels):
78+
weights[:, :, i, i] = bilinear_kernel
79+
80+
# assign numpy array to constant_initalizer and pass to get_variable
81+
return tf.constant_initializer(value=weights, dtype=LayersConfig.tf_dtype)

0 commit comments

Comments
 (0)