Как манипулировать (ограничивать) весами ядра фильтра в Conv2D в Керасе? - PullRequest
0 голосов
/ 24 мая 2018

Я понимаю, что есть несколько опций для kernel_constraint в Conv2D в Keras: max_norm, non_neg или unit_norm ..

Но мне нужно было установить нулевую позицию (центр) в ядрах фильтра на ноль,Например, если у нас есть ядро ​​фильтра с его размером (ширина, высота) = (5, 5) и что у нас есть 3 канала на входе.Мне нужно ограничить опорную (центральную) точку этого ядра для каждого канала равным 0, например, w (2,2,:) = 0, предполагая, что мы помещаем измерение канала в 3-е измерение.Если имеется несколько фильтров, позиция привязки каждого фильтра должна быть с нулем.Как я могу это реализовать?

Я предполагаю, что необходимо специальное ограничение ядра.Эта ссылка дает подсказку, как создать один класс, наследующий от Ограничения: https://github.com/keras-team/keras/issues/8196. Это показывает, как реализованы встроенные ограничения: https://github.com/keras-team/keras/blob/master/keras/constraints.py

Но, тем не менее, я не знаю, как измеряются размеры wманипулировать, и как установить желаемое положение равным нулю.Любая помощь приветствуется.Спасибо.

Обновление: ответ Даниэля Меллера был опробован.Сообщение об ошибке выглядит следующим образом:
повышение ValueError («Операция имеет None для градиента.» ValueError: Операция имеет None для градиента. Пожалуйста, убедитесь, что все ваши операции имеют определенный градиент (т.е.дифференцируемый). Обычные операции без градиента: K.argmax, K.round, K.eval.

Поскольку Даниэль может без проблем выполнить его на своей стороне, чтобы проверить, что идет не так в моей программе, я выкладываю свою упрощенную версиюкод здесь. Мои данные имеют 8 каналов, но не имеет значения, сколько у вас есть.

from keras.layers import Input, Conv2D
from keras.models import Model, optimizers
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.callbacks import ModelCheckpoint


class ZeroCenterConv2D(Conv2D):
    def __init__(self, filters, kernel_size, **kwargs):
        super(ZeroCenterConv2D, self).__init__(filters, kernel_size, **kwargs)

    def call(self, inputs):
        assert self.kernel_size[0] % 2 == 1, "Error: the kernel size is an even number"
        assert self.kernel_size[1] % 2 == 1, "Error: the kernel size is an even number"

        centerX = (self.kernel_size[0] - 1) // 2
        centerY = (self.kernel_size[1] - 1) // 2

        kernel_mask = np.ones(self.kernel_size + (1, 1))
        kernel_mask[centerX, centerY] = 0
        kernel_mask = K.constant(kernel_mask)

        customKernel = self.kernel * kernel_mask

        outputs = K.conv2d(
            inputs,
            customKernel,
            strides=self.strides,
            padding=self.padding,
            data_format=self.data_format,
            dilation_rate=self.dilation_rate)

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

        return outputs


size1 = 256
size2 = 256
input_img = Input(shape=(size1, size2, 8))
conv1 = ZeroCenterConv2D(8, (5, 5), padding='same', activation='relu')(input_img)
autoencoder = Model(input_img, conv1)
adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8)
autoencoder.compile(optimizer=adam, loss='mean_squared_error')


import scipy.io
A = scipy.io.loadmat('data_train')
x_train = A['data']
x_train = np.reshape(x_train, (1, 256, 256, 8))


from keras.callbacks import TensorBoard

autoencoder.fit(x_train, x_train,
                epochs=5,
                batch_size=1,
                shuffle=False,
                validation_data=(x_train, x_train),
                callbacks=[TensorBoard(log_dir='/tmp/autoencoder')])


decoded_imgs = autoencoder.predict(x_train)

Когда conv1 = ZeroCenterConv2D ... был заменен обычным conv1 = Conv2D ..., все работает.

Полное сообщение об ошибке:

Connected to pydev debugger (build 181.4668.75)
/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.
Traceback (most recent call last):
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1664, in <module>
    main()
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1658, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1068, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/home/allen/autotion/temptest", line 62, in <module>
    callbacks=[TensorBoard(log_dir='/tmp/autoencoder')])
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/engine/training.py", line 1682, in fit
    self._make_train_function()
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/engine/training.py", line 992, in _make_train_function
    loss=self.total_loss)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/legacy/interfaces.py", line 91, in wrapper
    return func(*args, **kwargs)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/optimizers.py", line 445, in get_updates
    grads = self.get_gradients(loss, params)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/optimizers.py", line 80, in get_gradients
    raise ValueError('An operation has `None` for gradient. '
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.

Process finished with exit code 1

Дальнейшее обновление: добавление части смещения в код в ответ Даниэля (уже сделано), проблемы решены!

1 Ответ

0 голосов
/ 24 мая 2018

Для этого вам понадобится специальный слой Conv2D, в котором вы измените метод вызова, чтобы применить ноль в центре.

class ZeroCenterConv2D(Conv2D):
    def __init__(self, filters, kernel_size, **kwargs):
        super(ZeroCenterConv2D, self).__init__(filters, kernel_size, **kwargs)

    def call(self, inputs):
        assert self.kernel_size[0] % 2 == 1, "Error: the kernel size is an even number"
        assert self.kernel_size[1] % 2 == 1, "Error: the kernel size is an even number"

        centerX = (self.kernel_size[0] - 1) // 2
        centerY = (self.kernel_size[1] - 1) // 2

        kernel_mask = np.ones(self.kernel_size + (1, 1))
        kernel_mask[centerX, centerY] = 0
        kernel_mask = K.variable(kernel_mask)

        customKernel = self.kernel * kernel_mask

        outputs = K.conv2d(
            inputs,
            customKernel,
            strides=self.strides,
            padding=self.padding,
            data_format=self.data_format,
            dilation_rate=self.dilation_rate)

        if self.use_bias:
            outputs = K.bias_add(
                outputs,
                self.bias,
                data_format=self.data_format)

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

        return outputs

Это не заменит фактические веса, но центральные никогда не будут использоваться.

Когда вы используете layer.get_weights() из model.get_weights(), вы увидите центральные веса, как они были инициализированы (не как нули).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...