Фиксировать сумму весов в фильтре свертки Keras / TensorFlow - PullRequest
0 голосов
/ 27 января 2019

У меня есть слой фильтра свертки 2D (назовите его 7x7) в нейронной сети. Я хочу ограничить фильтр, чтобы его веса добавлялись к 0. (Это общее требование к сверточным фильтрам при обработке изображений - идея состоит в том, что фильтр чувствителен к локальным изменениям яркости, но не к абсолютному уровню яркость.) Это более или менее эквивалентно наличию слоя с 48 весами, чьи входы составляют x [-3, -3] -x [0,0], x [-3, -2] -x [0,0] , ... x [3,3] -x [0,0].

По какой-то причине я не вижу никакой нативной функциональности для наложения этого ограничения.

То, что я пробовал до сих пор:

  • Не навязывайте ограничения. Очень плохо для конвергенции (изменяющиеся общие уровни яркости действуют как массивный источник шума, который препятствует конвергенции сети.)

  • Код пользовательского регуляризатора для слоя:

например.

class FixSum(Regularizer):      
def call(self, x):
    reg=0.01*math_ops.reduce_sum(math_ops.abs(math_ops.reduce_sum(x,axis=(0,1))))
    return reg

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

  • Код пользовательского ограничения для слоя:

, например

class TestConstraint(Constraint):
      def __init__(self, N, target_sum):
        self.target_sum = tf.keras.backend.variable(target_sum,dtype="float32")
        self.N = N
      def __call__(self, w):
        t = math_ops.reduce_sum(x,axis=(0,1),keepdims=True) - self.target_sum
        t /= self.N
        return w - tf.keras.backend.repeat_elements(tf.keras.backend.repeat_elements(t, w.shape[0], 0), w.shape[1], 1)

Вроде работает, но скорость сходимости оставляет желать лучшего

  • Вручную построить все различия. Вместо простого

    Conv2D (n, (7,7), ...)

Я бы сделал

Conv2D(48, (7,7), trainable=False, ...)
Conv2D(n, (1,1), ...)

, где первый Conv2D имеет веса, установленные в самом начале для получения x [-3, -3] -x [0,0] и т. Д.

Скорость сходимости хорошая, но производительность не такая хорошая. И он не слишком хорошо масштабируется (если я увеличу ядро ​​с 7x7 до 15x15, это увеличит вычислительную сложность этого «поддельного слоя» примерно в 20 раз.)

Есть что-нибудь еще, что я должен попробовать?

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