Керас с лямбда-слоем - PullRequest
       8

Керас с лямбда-слоем

0 голосов
/ 22 ноября 2018

Я относительно новичок в Keras и собираюсь построить Dueling Q-Network для обучения KI.Я нашел фрагмент кода для построения модели, которая на удивление работает.Я просто понятия не имею почему, потому что я не слишком знаком с лямбда-выражениями в Keras.Кто-нибудь может объяснить, как именно работает создание лямбда-слоя в следующей модели?Большое спасибо за преимущество!

def build_model():

    model = Sequential()
    model.add(Dense(units=16, activation='relu', input_dim = 2))
    model.add(Dense(units=32, activation='relu'))
    model.add(Dense(units=9, activation='relu'))

    #I definitely don't understand how the following layer works:
    model.add(Lambda(lambda i: K.expand_dims(i[:,0],-1) + i[:,1:] - K.mean(i[:,1:], keepdims=True), output_shape=(8,)))

    model.add(Dense(units=8, activation='linear'))
    model.compile(loss='mse',
    optimizer = RMSprop(lr=0.001) )
    return model

1 Ответ

0 голосов
/ 23 ноября 2018

Я не знаком с вашей конкретной областью исследований, но я могу рассказать вам, что делает этот слой.Слой Lambda - это когда вы хотите определить пользовательскую операцию для входов, которые не исходят из чего-либо, что предопределено из Keras.В частности, вы хотите применить некоторую пользовательскую операцию к тензорному элементу, входящему в слой, который Keras еще не обрабатывает.

Вход в слой Lambda представляет собой анонимную функцию , гдевход - тензор, который входит в этот слой.Однако обратите внимание, что вы также можете указать любую функцию или операцию в этом слое, и она не должна быть анонимной функцией ... при условии, что она работает с входным тензором и создает выходной.Затем вы определяете операцию, которую хотите выполнить с этим входным тензором, и он создает соответствующий выходной тензор, который будет подан на следующий слой.Такое поведение, конечно, предполагает наличие сети прямой связи, что я и вижу здесь.Вы можете думать об анонимной функции как о единовременной функции, которая будет использоваться для выполнения операций, но вы не хотите, чтобы они задерживались позже, так как они вам больше не нужны после того, как вы указали, что делать с входным тензором.

lambda i означает, что вы создаете анонимную функцию, которую слой Lambda будет работать с входным тензором, определенным как i.K.expand_dims гарантирует, что вы добавите одноэлементные измерения для широковещания .В этом случае мы хотим взять первый столбец входного тензора i[:,0], который становится одномерным массивом, и убедиться, что входной тензор является двумерным массивом с одним столбцом (т. Е. Перейти от массива N, к N x 1 массив).Аргумент -1 - это ось, по которой вы хотите расширить.Установка этого значения в -1 просто расширяет самое последнее измерение, которое в этом случае последнее измерение является первым (и единственным) измерением.

Если вы не привыкли к широковещанию, операция добавления к этому расширенномуМассив немного сложен для понимания, но как только вы освоите его, он станет одним из самых мощных механизмов в вычислительной технике.i[:,1:] разрезает входной тензор так, чтобы мы рассматривали тензор от второго столбца до конца.Под капотом добавление этого нарезанного тензора с расширенным одиночным столбцом i[:,0] означает, что этот столбец получает реплицированных и добавляется к каждому отдельному столбцу в i[:,1:] индивидуально.

Например, еслиi[:,0] было [1, 2, 3, 4] и i[:,1:] было [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6], выполнение K.expand_dims(i[:,0], -1) + i[:,1:] приводит к [[5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10]].

Последний фрагмент головоломки такой: K.mean(i[:,1:], keepdims=True).Мы берем K.expand_dims(i[:,0], -1) + i[:,1:], затем вычитаем это с K.mean(i[:,1:], keepdims=True).K.mean в этом контексте найдет среднее значение всех значений в тензоре для всех строк, начиная со второго столбца и далее.Это стандартное поведение операции.В зависимости от того, как вы используете K.mean, одно или несколько измерений могут упасть.Дополнительным входом в K.mean является axis, который позволяет вам указать, какие измерения вы хотите проанализировать в среднем в тензоре.Например, если вы сделали axis=0, это находит среднее значение для каждого столбца в отдельности.Это уменьшило бы до 1D тензор значений.С ключевым словом keepdims, если вы указали keepdims=True, это гарантирует, что тензор будет по-прежнему двумерным с числом столбцов, равным 1 (т. Е. Тензор N x 1 вместо тензора N,).Поведение по умолчанию - false.

Поэтому, выполняя операцию K.mean, мы гарантируем, что конечный результат равен 1 x 1, и это значение вычитается из каждого значения результата K.expand_dims(i[:,0],-1) + i[:,1:].Это опять-таки возможно из-за широковещания.

Наконец, мы убедимся, что форма вывода этой операции дает одномерный тензор размера 8.

tl;dr

Эта операция является пользовательской, в которой мы берем первый столбец входного тензора, добавляем его во все остальные столбцы, начиная со второго столбца, и вычитаем каждое значение этого результата из среднего значения всех других столбцов извторой столбец вперед.Кроме того, мы ограничиваем выходной размер тензора так, чтобы он был 1D с размером 8.

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