-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Dear friends,
I will try to write and summarize a few thoughts regarding the upcoming changes in TensorLayer, namely for version 2.0 🎉🎉🎉.
Main features that will be released.
I may forget some, if so I will update my post.
- Logging contrib Hyperdash module
- Graph Architecture saving
- Distributed training with Horovod
- Network API and features inspired by Keras and PyTorch.
- Database for data and model life-cycle management
TensorLayer 1.x recurring issues.
TensorLayer has always been a quite fuzzy and messy (and it's really improving 👍). The results have been an incredible number of bugs in the different Layers. Implementing one single feature oftenly assume that you partly rewrite the code for absolutely each Layer (I did it already 2 times, and I'm doing it for the 3rd time with the Network API). This is extremely dangerous with a high risk of introducing an incredible number of bugs (I remind you that we had to release a very large number of release candidate to fix all the bugs 1.8.6rc0, 1.8.6rc1, 1.8.6rc2, 1.8.6rc3, 1.8.6rc4, 1.8.6rc5 1.8.6rc6).
Every so often we find new bugs, just by reading at the code:
- Issue Error caused by using tl.layers.DeformableConv2d function #572 with
tl.layers.DeformableConv2d
fixed (PR Unittest for Deformable Convolution Added + Issue Fix #572 #573) - Issue AttributeError: 'ConvLSTMLayer' object has no attribute 'initial_state'? #664 with
tl.layers.ConvLSTMLayer
fixed (PR Update recurrent.py #676) - Error in
tl.layers.TernaryConv2d
fixed - self.inputs not defined (PR Test with Python 3.7 - Dev Branch #658) - etc ...
Additionally, the current Layer API is slightly counter intuitive:
- why
layer.all_params
returns the params of a network and not a layer - same
layer.all_layers
is quite ironic right ? - with the Graph API newly introduced, when you save a Layer, you actually save the whole network.
layer.count_params()
send you the number of params in the graph, not inside the layer- etc.
Proposition: Breaking the breaking the backward compatibility with the Network API
As TensorFlow did when releasing TF 1.0 or Django (with Django 2.0) in a non deep learning context. Very big libraries oftenly decide to let the good old times behind them and clean the code base. I believe that it is not a problem to break backward compibility if it is for the better and done very rarely.
What are the changes, I believe would highly improve TL maintainability and clarity for TL 2.0:
- a huge cleanup in the features of the Layer API, absolutely every features which is a Network feature should move to the newly created Network API.
- keep Layer features at the Layer level.
- add feature Layer-related in a Layer API (e.g. how many params in this Layer ?)
A few words on the Network API
I believe the network API should NOT be mandatory in TL. It should bring additional, non essential features.
The following should be possible
import tensorflow as tf
import tensorlayer as tl
tf.logging.set_verbosity(tf.logging.DEBUG)
tl.logging.set_verbosity(tl.logging.DEBUG)
x = tf.placeholder(tf.float32, shape=[None, 30])
net = tl.layers.InputLayer(x, name='input')
net = tl.layers.DenseLayer(net, n_units=10, name='dense1')
However, the following functionalities should be removed from Layer and move to Network API:
# Graph API
net.load()
net.save()
net.print_layers()
net.print_params(False)
print(net.all_drop)
print(net.all_params)
print(net.all_layers)
print(net.all_graphs)
The list above is not exhaustive. In the same time, new functionalities can be added:
layer.count_params() # returns the number of params in this Layer
layer._local_vars # returns a list of tf.Variable inside this Layer
The list above is not exhaustive
Presentation of the current Network API
It is not finialized, is subject to changes. I plan on releasing two Network Classes:
Sequential (similar idea than Keras)
For easy and sequential models, the Sequential Network API is here for rapid prototyping.
# Model Definition
model = tl.networks.Sequential(name="My_Sequential_1D_Network") # Automatically adds the InputLayer, no need to do it
model.add(tl.layers.DenseLayer(n_units=10, act=tf.nn.relu, name="seq_layer_1"))
model.add(tl.layers.DenseLayer(n_units=20, act=None, name="seq_layer_2"))
model.add(tl.layers.PReluLayer(channel_shared=True, name="prelu_layer_2"))
model.add(tl.layers.DenseLayer(n_units=50, act=None, name="seq_layer_3"))
model.add(tl.layers.PRelu6Layer(channel_shared=False, name="prelu6_layer_3"))
model.add(tl.layers.DenseLayer(n_units=40, act=None, name="seq_layer_4"))
model.add(tl.layers.PTRelu6Layer(channel_shared=True, name="ptrelu6_layer_4"))
model.add(tl.layers.DenseLayer(n_units=40, act=tf.nn.relu, name="seq_layer_5"))
model.add(tl.layers.DropoutLayer(keep=0.5, is_fix=True, name="dropout_layer_5"))
# TF Graph Creation
plh = tf.placeholder(tf.float16, (100, 32))
train_model_output = model.compile(plh, reuse=False, is_train=True) # returns a TF Tensor
test_model_output = model.compile(plh, reuse=True, is_train=False) # returns a TF Tensor
# PyTorch-Like Layer Access
layer_1 = model["seq_layer_1"]
Custom Model API
CustomModel/CustomNetwork/Model/Network: I haven't really decide on the name yet.
This Class haven't been created yet, it is subject to change.
# Model Definition
class MyCustomNetwork(CustomNetwork):
def define_network(self): # abstract function that needs to be overwritten
net_in = tl.layers.InputLayer(name="input_layer")
net = tl.layers.DenseLayer(n_units=10, act=tf.nn.relu, name="seq_layer_1")
net1 = tl.layers.DenseLayer(n_units=20, act=None, name="seq_layer_2")(net)
net1 = tl.layers.PReluLayer(channel_shared=True, name="prelu_layer_2")(net)
net2 = tl.layers.DenseLayer(n_units=50, act=None, name="seq_layer_3")(net)
net2 = tl.layers.PRelu6Layer(channel_shared=False, name="prelu6_layer_3")(net)
net3 = tl.layers.DenseLayer(n_units=40, act=None, name="seq_layer_4")(net)
net3 = tl.layers.PTRelu6Layer(channel_shared=True, name="ptrelu6_layer_4")(net)
net4 = tl.layers.DenseLayer(n_units=40, act=tf.nn.relu, name="seq_layer_5")(net)
net4 = tl.layers.DropoutLayer(keep=0.5, is_fix=True, name="dropout_layer_5")(net)
net_stack = tl.layers.StackLayer(axis=1, name='stack')([net1, net2, net3, net4])
return net_stack
model = MyCustomNetwork(name="My_Custom_Network")
# TF Graph Creation
plh = tf.placeholder(tf.float16, (100, 32))
train_model_output = model.compile(plh, reuse=False, is_train=True) # returns a TF Tensor
test_model_output = model.compile(plh, reuse=True, is_train=False) # returns a TF Tensor
# PyTorch-Like Layer Access
layer_1 = model["seq_layer_1"]