Tensorflow 2: ошибка Todo с пользовательскими слоями - PullRequest
0 голосов
/ 18 июня 2020

Я конвертирую 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'

Я заметил message [# TODO (b / 130381733): Сделайте это атрибутом в base_layer.Layer.], но я не могу понять, где исправить код.

...