Как проверить пользовательский слой Keras в python - PullRequest
0 голосов
/ 02 апреля 2019

Ввиду необходимости, которое я выставил в этом вопросе, я решил создать подкласс слоя Conv2D, чтобы он правильно обернул входной тензор первым.

Но я не мог заставить это работать. В частности, я не смог даже выполнить модульный тест, который инициализирует слой с данным ядром, затем передает ему заданный входной тензор и проверяет, что вычисление, определенное в методе .call(), дает ожидаемый результат .

Итак, я делаю шаг назад, и, чтобы избежать проблем с моим кодом, я концентрируюсь на том, как сначала разобраться с уже существующим родительским уровнем Keras Conv2D.

import unittest

from numpy import asarray, arange

import keras.backend as K
from keras.models import Sequential  #, Model, 
from keras.layers import Conv2D  #, Input, MaxPooling2D
from keras.initializers import Constant
from keras.optimizers import SGD

class Test(unittest.TestCase):

    def testConv2D(self):
        ''' verify that I can initialize, invoke, and test a given Keras layer
        '''
        # kernel to make convolution constant except at borders 
        kern = asarray([[ 1, 0, -1]]).T + asarray([[ 0.5, 1, 0, -1, -0.5 ]]) 
        print(kern)
        kern = Constant(kern)

        input_shape = (10, 10, 3)
        sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)

        base_model = Sequential()
        base_layer = Conv2D(10, (3, 5),
                             input_shape=input_shape,
                             kernel_initializer=kern,
                             use_bias=False)
        base_model.add(base_layer)
        base_model.compile(loss='mean_squared_error', optimizer=sgd)

        x = arange(5 * 10 * 10 * 3).reshape((5, 10, 10, 3))  # 5 samples, 3 channels
        x = K.variable(x)
        # the print() statements to be replaced by asserts of course
        y = base_layer(x)
        print(y)                      # this just prints     Tensor("conv2d_1_1/convolution:0", shape=(5, 8, 6, 10), dtype=float32)
        yp = base_model.predict(x)    # this throws a        ValueError about specifying the `steps` argument
        print(yp)
        pass
        # once this works I'll replace Conv2D with a subclass of it, and 
        # verify that I can preprocess the input tensor; and will be able 
        # to verify that the convolution gives the right result
        pass
        # once also this works, I'll replace partial tests with a single test that verifies only the result
        pass

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

Попытка выполнить это показывает, что я даже не могу вызвать существующий слой Keras для данных. Понятия не имею, как это сделать лучше (может, мне лучше использовать функциональный API?)

Я подозреваю, что я полностью сбился с пути. Если есть какой-нибудь пример или ссылка, где я могу получить вдохновение, или любой намек о правильном способе выполнения вышеизложенного, я был бы очень признателен, чтобы прочитать его

PS. Я также проверил эти вопросы, которые пролили некоторый свет на то, как реализовать то, что мне нужно, но на самом деле сейчас Я сосредоточен на том, как протестировать то, что я реализую :

Обновление 1: два вывода

Прежде чем кто-то еще это укажет, я нашел несколько первых ответов и могу сказать, в каком направлении я следую:

  • y = base_layer(x); Непосредственно не подходит для тестирования , так как не дает никакого значения (в Functional API он просто объявляет, как должна быть преобразована переменная x, чтобы получить выходные данные слоя)
  • Вместо этого yp = base_model.predict(x) является правильным , но x должен быть массивом numpy. Гораздо проще, чем любой Keras variable или Constant вообще (что я считаю более декларативным объектами)
  • явная инициализация ядра с помощью объекта keras.initializers.Constant, созданного из numpy массива , работает, если предоставленное ядро ​​имеет правильный размер! В этом случае Я хотел использовать ядро ​​[3,5], но сделал это очень плохо: если мы работаем с изображениями с C цветными слоями, один фильтр подразумевает ядро ​​[3,5,C]. Наконец, поскольку слой Conv2D имеет F=10 фильтры, правильный инициализатор ядра должен быть из четырехмерного массива с формой [3,5,C,F]. Обратите внимание, что размер фильтра является последним (а не первым).
  • с точки зрения тестирования, я мог бы реализовать это, вызвав метод layer get_weights() и проверив, что форма инициализатора является конгруэнтной (описано здесь ) (может быть специальная проверка и предупреждающие сообщения вставляется в код Keras, когда инициализатор содержит явный массив, чтобы предотвратить эту ошибку).

Так что теперь я знаю, как двигаться дальше. Я буду держать вас в курсе, надеюсь, с полным ответом с рабочим решением.

...