Migrating code to TF2 and not getting the ModuleNotFoundError: No module named 'tensorflow.contrib.framework'

Migrating code to TF2 and not getting the ModuleNotFoundError: No module named 'tensorflow.contrib.framework'

我从 https://github.com/skokec/DAU-ConvNet, which is based on this paper https://arxiv.org/abs/1902.07474 那里获得了这段代码,它用自适应滤波器版本替换了卷积块中基于网格的标准滤波器。当我尝试导入包时出现此错误:

ModuleNotFoundError: No module named 'tensorflow.contrib.framework'.

我知道 "tensorflow.contrib" 显然在 2.0 版中被删除了,我需要恢复到 <= 1.14 版才能使其正常工作。但我想看看是否有人可以让这段代码在较新的 TF.2 版本中工作,因为这是一篇非常有趣的论文,结果非常好,通过将这段代码迁移到 TF2,它会鼓励其他人尝试和试验与这一层不同 architectures/setups。下面是源代码:

import os
import numpy as np
import tensorflow as tf

from tensorflow.python.layers import base
from tensorflow.python.layers import utils

from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_shape

from tensorflow.python.ops import nn_ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import nn
from tensorflow.python.ops import init_ops

class DAUConv2dTF(base.Layer):
def __init__(self, filters,
             dau_units,
             max_kernel_size,
             strides=1,
             data_format='channels_first',
             activation=None,
             use_bias=True,
             weight_initializer=init_ops.random_normal_initializer(stddev=0.1),
             mu1_initializer=None,
             mu2_initializer=None,
             sigma_initializer=None,
             bias_initializer=init_ops.zeros_initializer(),
             weight_regularizer=None,
             mu1_regularizer=None,
             mu2_regularizer=None,
             sigma_regularizer=None,
             bias_regularizer=None,
             activity_regularizer=None,
             weight_constraint=None,
             mu1_constraint=None,
             mu2_constraint=None,
             sigma_constraint=None,
             bias_constraint=None,
             trainable=True,
             mu_learning_rate_factor=500,
             dau_unit_border_bound=0.01,
             dau_sigma_trainable=False,
             name=None,
             **kwargs):
    super(DAUConv2dTF, self).__init__(trainable=trainable, name=name,
                                activity_regularizer=activity_regularizer,
                                **kwargs)
    self.rank = 2
    self.filters = filters
    self.dau_units = utils.normalize_tuple(dau_units, self.rank, 'dau_components')
    self.max_kernel_size = max_kernel_size
    self.padding = np.floor(self.max_kernel_size/2.0)
    self.strides = strides
    self.data_format = utils.normalize_data_format(data_format)
    self.activation = activation
    self.use_bias = use_bias
    self.bias_initializer = bias_initializer
    self.bias_regularizer = bias_regularizer
    self.bias_constraint = bias_constraint

    self.weight_initializer = weight_initializer
    self.weight_regularizer = weight_regularizer
    self.weight_constraint = weight_constraint

    self.mu1_initializer = mu1_initializer
    self.mu1_regularizer = mu1_regularizer
    self.mu1_constraint = mu1_constraint

    self.mu2_initializer = mu2_initializer
    self.mu2_regularizer = mu2_regularizer
    self.mu2_constraint = mu2_constraint

    self.sigma_initializer = sigma_initializer
    self.sigma_regularizer = sigma_regularizer
    self.sigma_constraint = sigma_constraint

    if self.mu1_initializer is None:
        raise Exception("Must initialize MU1")
    if self.mu2_initializer is None:
        raise Exception("Must initialize MU2")

    if self.sigma_initializer is None:
        self.sigma_initializer=init_ops.constant_initializer(0.5)

    self.mu_learning_rate_factor = mu_learning_rate_factor

    self.input_spec = base.InputSpec(ndim=self.rank + 2)

    self.dau_unit_border_bound = dau_unit_border_bound
    self.num_dau_units_all = np.int32(np.prod(self.dau_units))

    self.dau_weights = None
    self.dau_mu1 = None
    self.dau_mu2 = None
    self.dau_sigma = None

    self.dau_sigma_trainable = dau_sigma_trainable

def set_dau_variables_manually(self, w = None, mu1 = None, mu2 = None, sigma = None):
    """ Manually set w,mu1,mu2 and/or sigma variables with custom tensor. Call before build() or __call__().
    The shape must match the expecated shape as returned by the get_dau_variable_shape(input_shape)
    otherwise the build() function will fail."""

    if w is not None:
        self.dau_weights = w

    if mu1 is not None:
        self.dau_mu1 = mu1

    if mu2 is not None:
        self.dau_mu2 = mu2

    if sigma is not None:
        self.dau_sigma = sigma

def _get_input_channel_axis(self):
    if self.data_format == 'channels_first':
        channel_axis = 1
    else:
        channel_axis = -1

    return channel_axis

def _get_input_channels(self, input_shape):
    channel_axis = self._get_input_channel_axis()

    if input_shape[channel_axis].value is None:
        raise ValueError('The channel dimension of the inputs '
                         'should be defined. Found `None`.')

    return input_shape[channel_axis].value

def get_dau_variable_shape(self, input_shape):
    # get input
    num_input_channels = self._get_input_channels(input_shape)

    dau_params_shape_ = (num_input_channels, self.dau_units[0], self.dau_units[1], self.filters)
    dau_params_shape = (1, num_input_channels, self.num_dau_units_all, self.filters)

    return dau_params_shape

def add_dau_weights_var(self, input_shape):
    dau_params_shape = self.get_dau_variable_shape(input_shape)
    return self.add_variable(name='weights',
                             shape=dau_params_shape,
                             initializer=self.weight_initializer,
                             regularizer=self.weight_regularizer,
                             constraint=self.weight_constraint,
                             trainable=True,
                             dtype=self.dtype)

def add_dau_mu1_var(self, input_shape):
    dau_params_shape = self.get_dau_variable_shape(input_shape)
    mu1_var = self.add_variable(name='mu1',
                             shape=dau_params_shape,
                             initializer=self.mu1_initializer,
                             regularizer=self.mu1_regularizer,
                             constraint=self.mu1_constraint,
                             trainable=True,
                             dtype=self.dtype)

    # limit max offset based on self.dau_unit_border_bound and kernel size
    mu1_var = tf.minimum(tf.maximum(mu1_var,
                                    -(self.max_kernel_size - self.dau_unit_border_bound)),
                         self.max_kernel_size - self.dau_unit_border_bound)

    return mu1_var



def add_dau_mu2_var(self, input_shape):
    dau_params_shape = self.get_dau_variable_shape(input_shape)
    mu2_var = self.add_variable(name='mu2',
                               shape=dau_params_shape,
                               initializer=self.mu2_initializer,
                               regularizer=self.mu2_regularizer,
                               constraint=self.mu2_constraint,
                               trainable=True,
                               dtype=self.dtype)


    # limit max offset based on self.dau_unit_border_bound and kernel size
    mu2_var = tf.minimum(tf.maximum(mu2_var,
                                    -(self.max_kernel_size - self.dau_unit_border_bound)),
                         self.max_kernel_size - self.dau_unit_border_bound)

    return mu2_var
def add_dau_sigma_var(self, input_shape, trainable=False):
    dau_params_shape = self.get_dau_variable_shape(input_shape)

    # create single sigma variable
    sigma_var = self.add_variable(name='sigma',
                                  shape=dau_params_shape,
                                  initializer=self.sigma_initializer,
                                  regularizer=self.sigma_regularizer,
                                  constraint=self.sigma_constraint,
                                  trainable=self.dau_sigma_trainable,
                                  dtype=self.dtype)

    # but make variable shared across all channels as required for the efficient DAU implementation
    return sigma_var


def add_bias_var(self):
    return self.add_variable(name='bias',
                             shape=(self.filters,),
                             initializer=self.bias_initializer,
                             regularizer=self.bias_regularizer,
                             constraint=self.bias_constraint,
                             trainable=True,
                             dtype=self.dtype)

def build(self, input_shape):
    input_shape = tensor_shape.TensorShape(input_shape)

    dau_params_shape = self.get_dau_variable_shape(input_shape)
    if self.dau_weights is None:
        self.dau_weights = self.add_dau_weights_var(input_shape)
    elif np.any(self.dau_weights.shape != dau_params_shape):
        raise ValueError('Shape mismatch for variable `dau_weights`')
    if self.dau_mu1 is None:
        self.dau_mu1 = self.add_dau_mu1_var(input_shape)
    elif np.any(self.dau_mu1.shape != dau_params_shape):
        raise ValueError('Shape mismatch for variable `dau_mu1`')

    if self.dau_mu2 is None:
        self.dau_mu2 = self.add_dau_mu2_var(input_shape)
    elif np.any(self.dau_mu2.shape != dau_params_shape):
        raise ValueError('Shape mismatch for variable `dau_mu2`')
    if self.dau_sigma is None:
        self.dau_sigma = self.add_dau_sigma_var(input_shape, trainable=self.dau_sigma_trainable)
    elif np.any(self.dau_sigma.shape != dau_params_shape):
        raise ValueError('Shape mismatch for variable `dau_sigma`')

    if self.use_bias:
        self.bias = self.add_bias_var()
    else:
        self.bias = None

    input_channel_axis = self._get_input_channel_axis()
    num_input_channels = self._get_input_channels(input_shape)

    self.input_spec = base.InputSpec(ndim=self.rank + 2,
                                     axes={input_channel_axis: num_input_channels})

    kernel_shape = tf.TensorShape((self.max_kernel_size, self.max_kernel_size, num_input_channels, self.filters))

    self._convolution_op = nn_ops.Convolution(
        input_shape,
        filter_shape=kernel_shape,
        dilation_rate=(1,1),
        strides=(self.strides,self.strides),
        padding="SAME",
        data_format=utils.convert_data_format(self.data_format,
                                              self.rank + 2))
    self.built = True

def call(self, inputs):

    def get_kernel_fn(dau_w, dau_mu1, dau_mu2, dau_sigma, max_kernel_size, mu_learning_rate_factor=1):

        # add mu1/mu2 gradient multiplyer
        if mu_learning_rate_factor != 1:
            dau_mu1 = mu_learning_rate_factor * dau_mu1 + (1 - mu_learning_rate_factor) * tf.stop_gradient(dau_mu1)
            dau_mu2 = mu_learning_rate_factor * dau_mu2 + (1 - mu_learning_rate_factor) * tf.stop_gradient(dau_mu2)

        [X,Y] = np.meshgrid(np.arange(max_kernel_size),np.arange(max_kernel_size))

        X = np.reshape(X,(max_kernel_size*max_kernel_size,1,1,1)) - int(max_kernel_size/2)
        Y = np.reshape(Y,(max_kernel_size*max_kernel_size,1,1,1)) - int(max_kernel_size/2)

        X = X.astype(np.float32)
        Y = Y.astype(np.float32)

        # Gaussian kernel
        X = tf.convert_to_tensor(X,name='X',dtype=tf.float32)
        Y = tf.convert_to_tensor(Y,name='Y',dtype=tf.float32)

        gauss_kernel = tf.exp(-1* (tf.pow(X - dau_mu1,2.0) + tf.pow(Y - dau_mu2,2.0)) / (2.0*tf.pow(dau_sigma,2.0)),name='gauss_kernel')

        gauss_kernel_sum = tf.reduce_sum(gauss_kernel,axis=0, keep_dims=True,name='guass_kernel_sum')

        gauss_kernel_norm = tf.divide(gauss_kernel, gauss_kernel_sum ,name='gauss_kernel_norm')

        # normalize to sum of 1 and add weight
        gauss_kernel_norm = tf.multiply(dau_w, gauss_kernel_norm,name='gauss_kernel_weight')

        # sum over Gaussian units
        gauss_kernel_norm = tf.reduce_sum(gauss_kernel_norm, axis=2, keep_dims=True,name='gauss_kernel_sum_units')

        # convert to [Kw,Kh,S,F] shape
        gauss_kernel_norm = tf.reshape(gauss_kernel_norm, (max_kernel_size, max_kernel_size, gauss_kernel_norm.shape[1], gauss_kernel_norm.shape[3]),name='gauss_kernel_reshape')

        return gauss_kernel_norm

    try:
        # try with XLA if exists
        from tensorflow.contrib.compiler import xla

        gauss_kernel_norm = xla.compile(computation=get_kernel_fn, inputs=(self.dau_weights, self.dau_mu1, self.dau_mu2, self.dau_sigma, self.max_kernel_size, self.mu_learning_rate_factor))[0]

    except:
        # otherwise revert to direct method call
        gauss_kernel_norm = get_kernel_fn(self.dau_weights, self.dau_mu1, self.dau_mu2, self.dau_sigma, self.max_kernel_size, self.mu_learning_rate_factor)

    outputs = self._convolution_op(inputs, gauss_kernel_norm)

    if self.use_bias:
        if self.data_format == 'channels_first':
            if self.rank == 1:
                # nn.bias_add does not accept a 1D input tensor.
                bias = array_ops.reshape(self.bias, (1, self.filters, 1))
                outputs += bias
            if self.rank == 2:
                outputs = nn.bias_add(outputs, self.bias, data_format='NCHW')
            if self.rank == 3:
                # As of Mar 2017, direct addition is significantly slower than
                # bias_add when computing gradients. To use bias_add, we collapse Z
                # and Y into a single dimension to obtain a 4D input tensor.
                outputs_shape = outputs.shape.as_list()
                if outputs_shape[0] is None:
                    outputs_shape[0] = -1
                outputs_4d = array_ops.reshape(outputs,
                                               [outputs_shape[0], outputs_shape[1],
                                                outputs_shape[2] * outputs_shape[3],
                                                outputs_shape[4]])
                outputs_4d = nn.bias_add(outputs_4d, self.bias, data_format='NCHW')
                outputs = array_ops.reshape(outputs_4d, outputs_shape)
        else:
            outputs = nn.bias_add(outputs, self.bias, data_format='NHWC')

    if self.activation is not None:
        return self.activation(outputs)
    return outputs

def compute_output_shape(self, input_shape):
    input_shape = tensor_shape.TensorShape(input_shape).as_list()
    if self.data_format == 'channels_last':
        space = input_shape[1:-1]
        new_space = []
        for i in range(len(space)):
            new_dim = utils.conv_output_length(
                space[i],
                self.max_kernel_size[i],
                padding=self.padding,
                stride=self.strides[i],
                dilation=1)
            new_space.append(new_dim)
        return tensor_shape.TensorShape([input_shape[0]] + new_space +
                                        [self.filters])
    else:
        space = input_shape[2:]
        new_space = []
        for i in range(len(space)):
            new_dim = utils.conv_output_length(
                space[i],
                self.kernel_size[i],
                padding=self.padding,
                stride=self.strides,
                dilation=1)
            new_space.append(new_dim)
        return tensor_shape.TensorShape([input_shape[0], self.filters] +
                                        new_space)


from tensorflow.contrib.framework.python.ops import add_arg_scope
from tensorflow.python.ops import variable_scope
from tensorflow.contrib.layers.python.layers import layers as layers_contrib
from tensorflow.contrib.layers.python.layers import utils as utils_contrib

@add_arg_scope
def dau_conv2d_tf(inputs,
             filters,
             dau_units,
             max_kernel_size,
             stride=1,
             mu_learning_rate_factor=500,
             data_format=None,
             activation_fn=nn.relu,
             normalizer_fn=None,
             normalizer_params=None,
             weights_initializer=init_ops.random_normal_initializer(stddev=0.1), #init_ops.glorot_uniform_initializer(),
             weights_regularizer=None,
             weights_constraint=None,
             mu1_initializer=None,
             mu1_regularizer=None,
             mu1_constraint=None,
             mu2_initializer=None,
             mu2_regularizer=None,
             mu2_constraint=None,
             sigma_initializer=None,
             sigma_regularizer=None,
             sigma_constraint=None,
             biases_initializer=init_ops.zeros_initializer(),
             biases_regularizer=None,
             biases_constraint=None,
             dau_unit_border_bound=0.01,
             dau_sigma_trainable=False,
             reuse=None,
             variables_collections=None,
             outputs_collections=None,
             trainable=True,
             scope=None):

if data_format not in [None, 'NWC', 'NCW', 'NHWC', 'NCHW', 'NDHWC', 'NCDHW']:
    raise ValueError('Invalid data_format: %r' % (data_format,))

layer_variable_getter = layers_contrib._build_variable_getter({
    'bias': 'biases',
    'weight': 'weights',
    'mu1': 'mu1',
    'mu2': 'mu2',
    'sigma': 'sigma'
})

with variable_scope.variable_scope(
        scope, 'DAUConv', [inputs], reuse=reuse,
        custom_getter=layer_variable_getter) as sc:
    inputs = ops.convert_to_tensor(inputs)
    input_rank = inputs.get_shape().ndims

    if input_rank != 4:
        raise ValueError('DAU convolution not supported for input with rank',
                         input_rank)

    df = ('channels_first'
          if data_format and data_format.startswith('NC') else 'channels_last')

    layer = DAUConv2dTF(filters,
                      dau_units,
                      max_kernel_size,
                      strides=stride,
                      data_format=df,
                      activation=None,
                      use_bias=not normalizer_fn and biases_initializer,
                      mu_learning_rate_factor=mu_learning_rate_factor,
                      weight_initializer=weights_initializer,
                      mu1_initializer=mu1_initializer,
                      mu2_initializer=mu2_initializer,
                      sigma_initializer=sigma_initializer,
                      bias_initializer=biases_initializer,
                      weight_regularizer=weights_regularizer,
                      mu1_regularizer=mu1_regularizer,
                      mu2_regularizer=mu2_regularizer,
                      sigma_regularizer=sigma_regularizer,
                      bias_regularizer=biases_regularizer,
                      activity_regularizer=None,
                      weight_constraint=weights_constraint,
                      mu1_constraint=mu1_constraint,
                      mu2_constraint=mu2_constraint,
                      sigma_constraint=sigma_constraint,
                      bias_constraint=biases_constraint,
                      dau_unit_border_bound=dau_unit_border_bound,
                      dau_sigma_trainable=dau_sigma_trainable,
                      trainable=trainable,
                      name=sc.name,
                      _scope=sc,
                      _reuse=reuse)

    outputs = layer.apply(inputs)

    # Add variables to collections.
    layers_contrib._add_variable_to_collections(layer.dau_weights, variables_collections, 'weights')
    layers_contrib._add_variable_to_collections(layer.dau_mu1, variables_collections, 'mu1')
    layers_contrib._add_variable_to_collections(layer.dau_mu2, variables_collections, 'mu2')
    layers_contrib._add_variable_to_collections(layer.dau_sigma, variables_collections, 'sigma')

    if layer.use_bias:
        layers_contrib._add_variable_to_collections(layer.bias, variables_collections, 'biases')

    if normalizer_fn is not None:
        normalizer_params = normalizer_params or {}
        outputs = normalizer_fn(outputs, **normalizer_params)

    if activation_fn is not None:
        outputs = activation_fn(outputs)
    return utils_contrib.collect_named_outputs(outputs_collections, sc.name, outputs)

如有任何帮助,我们将不胜感激。 干杯, H

在 TensorFlow 2.x 中,创建可重用神经网络层的推荐方法是创建一个新的 tf.keras.layers.Layer subclass。 TensorFlow 提供了 great tutorial on this。您可以在 tf.keras 层 class 中重用您发布的示例中的绝大部分代码。您也许还可以从 tensorflow.python.keras.layers.convolutional.Conv 继承以减少样板代码的数量。

至于有些模块找不到,你应该使用TensorFlow暴露的别名。这是一个不完整的列表:

  • array_ops.reshape -> tf.reshape
  • init_ops.constant_initializer -> tf.initializers.constant
  • tensor_shape -> tf.TensorShape
  • nn_ops.Convolution -> tf.nn.convolutiontf.keras.layers.Conv?D