Tensorflow 2: ошибка Todo с пользовательскими слоями
Я конвертирую Face Alignment Network(FAN) в PyTorch в Tensorflow 2. У меня возникла ошибка, но я не знаю, почему она возникает. Оригинальный код здесь.
Код ниже - это мой код.
import tensorflow as tf
import numpy as np
from tensorflow.keras import datasets, layers, models
class ConvBlock(layers.Layer):
def __init__(self, in_planes, out_planes):
super(ConvBlock, self).__init__()
self.bn1 = layers.BatchNormalization()
self.conv1 = layers.Conv2D(int(out_planes / 2), (3, 3), padding='same', strides=(1, 1))
self.bn2 = layers.BatchNormalization()
self.conv2 = layers.Conv2D(int(out_planes / 4), (3, 3), padding='same', strides=(1, 1))
self.bn3 = layers.BatchNormalization()
self.conv3 = layers.Conv2D(int(out_planes / 4), (3, 3), padding='same', strides=(1, 1))
if in_planes != out_planes:
self.downsample = tf.keras.Sequential()
self.downsample.add(layers.BatchNormalization())
self.downsample.add(layers.ReLU())
self.downsample.add(layers.Conv2D(out_planes, (1, 1), padding='same', strides=(1, 1)))
else:
self.downsample = None
def call(self, input_tensor, training=False):
residual = input_tensor
out1 = self.bn1(input_tensor)
out1 = tf.nn.relu(out1)
out1 = self.conv1(out1)
out2 = self.bn2(out1)
out2 = tf.nn.relu(out2)
out2 = self.conv2(out2)
out3 = self.bn3(out2)
out3 = tf.nn.relu(out3)
out3 = self.conv3(out3)
out3 = tf.concat([out1, out2, out3], 3)
if self.downsample is not None:
residual = self.downsample(residual)
out3 += residual
return out3
class Bottleneck(layers.Layer):
expansion = 4
def __init__(self, in_planes, planes, stride=1, downsample=None):
super(Bottleneck, self).__init__()
self.conv1 = layers.Conv2D(planes, (1, 1), padding='valid')
self.bn1 = layers.BatchNormalization()
self.conv2 = layers.Conv2D(planes, (3, 3), padding='same', strides=1)
self.bn2 = layers.BatchNormalization()
self.conv3 = layers.Conv2D(planes * 4 , (1, 1), padding='valid')
self.bn3 = layers.BatchNormalization()
self.downsample = downsample
self.stride = stride
def call(self, input_tensor, training=False):
residual = input_tensor
out = self.conv1(input_tensor)
out = self.bn1(out)
out = tf.nn.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = tf.nn.relu(out)
out = self.conv3(out)
out = self.bn3(out)
out = tf.nn.relu(out)
if self.downsample is not None:
residual = self.downsample(residual)
out += residual
out = tf.nn.relu(out)
return out
class HourGlass(layers.Layer):
def __init__(self, num_modules, depth, num_features):
super(HourGlass, self).__init__()
self.num_modules = num_modules
self.depth = depth
self.features = num_features
self._layers = dict()
self._generate_network(self.depth)
def _generate_network(self, level):
self._layers['b1_' + str(level)] = ConvBlock(self.features, self.features)
self._layers['b2_' + str(level)] = ConvBlock(self.features, self.features)
if level > 1:
self._generate_network(level - 1)
else:
self._layers['b2_plus_' + str(level)] = ConvBlock(self.features, self.features)
self._layers['b3_' + str(level)] = ConvBlock(self.features, self.features)
def _call(self, level, inp):
# Upper branch
up1 = inp
up1 = self._layers['b1_' + str(level)](up1)
# Lower branch
low1 = layers.AveragePooling2D((2, 2), stride=2)(inp)
low1 = self._layers['b2_' + str(level)](low1)
if level > 1:
low2 = self._call(level - 1, low1)
else:
low2 = low1
low2 = self._layers['b2_plus_' + str(level)](low2)
low3 = low2
low3 = self._layers['b3_' + str(level)](low3)
up2 = layers.UpSampling2D(low3, interpolation='nearest') #########
return up1 + up2
def call(self, x):
return self._call(self.depth, x)
class FAN(layers.Layer):
def __init__(self, num_modules=1):
super(FAN, self).__init__()
self.num_modules = num_modules
#base part
self.conv1 = layers.Conv2D(64, (7, 7), padding='same', strides=2)
self.bn1 = layers.BatchNormalization()
self.conv2 = ConvBlock(64, 128)
self.conv3 = ConvBlock(128, 128)
self.conv4 = ConvBlock(128, 128)
self._layers = dict()
# Stacking part
for hg_module in range(self.num_modules):
self._layers['m' + str(hg_module)] = HourGlass(1, 4, 256)
self._layers['top_m_' + str(hg_module)] = ConvBlock(256, 256)
self._layers['conv_last' + str(hg_module)] = layers.Conv2D(256, (1, 1), padding='same', strides=1)
self._layers['bn_end' + str(hg_module)] = layers.BatchNormalization()
self._layers['l' + str(hg_module)] = layers.Conv2D(68, (1, 1), padding='same', strides=1)
if hg_module < self.num_modules -1:
self._layers['bl' + str(hg_module)] = layers.Conv2D(256, (1, 1), padding='same', strides=1)
self._layers['al' + str(hg_module)] = layers.Conv2D(256, (1, 1), padding='same', strides=1)
def call(self, x):
x = tf.nn.relu(self.bn1(self.conv1(x)))
x = layers.AveragePooling2D((7, 7))(x)
x = self.conv3(x)
x = self.conv4(x)
previous = x
outputs = []
for i in range(self.num_modules):
hg = self._layers['m' + str(i)](previous)
ll = hg
ll = self._module['top_m_' + str(i)](ll)
ll = tf.nn.relu(self._layers['bn_end' + str(i)]
(self._layers['conv_last' + str(i)](ll)))
# Predict heatmaps
tmp_out = self._layers['l' + str(i)](ll)
outputs.append(tmp_out)
if i < self.num_modules - 1:
ll = self._layers['bl' + str(i)](ll)
tmp_out_ = self._layers['al' + str(i)](tmp_out)
previous = previous + ll + tmp_out_
return outputs
class ResNetDepth(layers.Layer):
def __init__(self, block=Bottleneck, layers=[3, 8, 36, 3], num_classes=208):
self.inplanes = 208
super(ResNetDepth, self).__init__()
self.conv1 = layers.Conv2D(208, (7, 7), padding='same', stride=2)
self.bn1 = layers.BatchNormalization()
self.relu = layers.ReLu()
self.maxpool = layers.MaxPool2D(pool_size=(3, 3), stride=2, padding='same')
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.avgpool = layers.AveragePooling2D((7, 7))
self.fc = layers.Dense(num_classes)
def _make_layer(sellf, block, planes, blocks, stride=1):
dowmsample = None
if stride != 1 or self.inplanes != planes * block.expansion:
downsample == tf.keras.Sequential(
layers.Conv2D(planes * block.expansion, (1, 1), strides=1, padding='same'), # 확인요망
layers.BatchNormalization()
)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample))
self.inplanes = planes * block.expansion
for i in range(1, blocks):
layers.append(block(self.inplanes, planes))
return tf.keras.Sequential(*layers)
def call(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
model = tf.keras.Sequential()
model.add(FAN())
Это ошибка.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-721cf81b7676> in <module>
----> 1 model.add(FAN())
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\training\tracking\base.py in _method_wrapper(self, *args, **kwargs)
455 self._self_setattr_tracking = False # pylint: disable=protected-access
456 try:
--> 457 result = method(self, *args, **kwargs)
458 finally:
459 self._self_setattr_tracking = previous_value # pylint: disable=protected-access
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\sequential.py in add(self, layer)
219 self._layers.append(layer)
220 if self._layers:
--> 221 self._track_layers(self._layers)
222
223 self._layer_call_argspecs[layer] = tf_inspect.getfullargspec(layer.call)
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\network.py in _track_layers(self, layers)
403 for layer_index, layer in enumerate(layers):
404 try:
--> 405 if layer.weights:
406 # Keep a separate index for layers which have weights. This allows
407 # users to insert Layers without weights anywhere in the network
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in weights(self)
913 A list of variables.
914 """
--> 915 return self.trainable_weights + self.non_trainable_weights
916
917 @property
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in trainable_weights(self)
890 def trainable_weights(self):
891 if self.trainable:
--> 892 nested = self._gather_children_attribute('trainable_weights')
893 return self._dedup_weights(self._trainable_weights + nested)
894 else:
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in _gather_children_attribute(self, attribute)
2319 return list(
2320 itertools.chain.from_iterable(
-> 2321 getattr(layer, attribute) for layer in nested_layers))
2322 return []
2323
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py in <genexpr>(.0)
2319 return list(
2320 itertools.chain.from_iterable(
-> 2321 getattr(layer, attribute) for layer in nested_layers))
2322 return []
2323
~\anaconda3\envs\tf2\lib\site-packages\tensorflow_core\python\training\tracking\layer_utils.py in filter_empty_layer_containers(layer_list)
236 # TODO(b/130381733): Make this an attribute in base_layer.Layer.
237 existing = object_identity.ObjectIdentitySet()
--> 238 to_visit = layer_list[::-1]
239 while to_visit:
240 obj = to_visit.pop()
TypeError: unhashable type: 'slice'
Я заметил сообщение [# TODO(b/130381733): Сделайте это атрибутом в base_layer.Layer.], Но я не могу понять, где исправить код.