I am examining a tf.keras code and I found out that when inside a custom model.Model instance every list of tf ops assigned to a self variable is automatically converted to ListWrapper object.
An example of this functionality is shown with the code:
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import initializers
class CustomModel(models.Model):
def __init__(self, width, depth, **kwargs):
super(CustomModel, self).__init__(**kwargs)
self.width = width
options = {
'kernel_size': 3,
'strides': 1,
'padding': 'same',
'kernel_initializer': initializers.RandomNormal(mean=0.0, stddev=0.01, seed=None)
}
self.convs = [layers.Conv2D(filters=width, bias_initializer='zeros', name='convs_{}'.format(i), **options)
for i in range(depth)]
self.conv = layers.Conv2D(filters=width, bias_initializer='zeros', name='conv_{}'.format(0), **options)
self.conv2 = [layers.Conv2D(filters=width, bias_initializer='zeros', name='conv_{}'.format(0), **options)]
self.depth = depth
where if checked (in a debugger for example):
type(self.convs)
tensorflow.python.training.tracking.data_structures.ListWrapper
type(self.conv)
tensorflow.python.keras.layers.convolutional.Conv2D
type(self.conv2)
tensorflow.python.training.tracking.data_structures.ListWrapper
where it can be seen that self.convs and self.conv2 are ListWrapper instead of list. On the contrary if the class does not inherit from Model:
class CustomModel2(object):
def __init__(self, width, depth, **kwargs):
# super(CustomModel, self).__init__(**kwargs)
self.width = width
options = {
'kernel_size': 3,
'strides': 1,
'padding': 'same',
'kernel_initializer': initializers.RandomNormal(mean=0.0, stddev=0.01, seed=None)
}
self.convs = [layers.Conv2D(filters=width, bias_initializer='zeros', name='convs_{}'.format(i), **options)
for i in range(depth)]
self.conv = layers.Conv2D(filters=width, bias_initializer='zeros', name='conv_{}'.format(0), **options)
self.conv2 = [layers.Conv2D(filters=width, bias_initializer='zeros', name='conv_{}'.format(0), **options)]
self.depth = depth
the usual lists are created:
type(self.convs)
list
type(self.conv)
tensorflow.python.keras.layers.convolutional.Conv2D
type(self.conv2)
list
So, my question is why is this happening? What's the advantages of using ListWrapper over list? Also, how can I use this type? I know I can access its members via a for loop for example. Are there any other properties I should know about?
There is a similar question here but neither the question nor the answer satisfied me.