Как внедрить серию Маклорин в Керасе?

Я пытаюсь реализовать расширяемую CNN, используя серию maclaurin. Основная идея заключается в том, что первый входной узел можно разложить на несколько узлов с разными порядками и коэффициентами. Разложение отдельных узлов на несколько может генерировать различные нелинейные линейные соединения, которые генерируются сериями Маклорена. Может ли кто-нибудь дать мне возможную идею о том, как расширить CNN с помощью нелинейного расширения серии Маклорена? любая мысль?

Я не совсем понимаю, как разложить входной узел на несколько с разными нелинейными связями линий, которые генерируются сериями Маклорена. насколько я знаю, ряд Маклорена является аппроксимационной функцией, но разлагающий узел не совсем интуитивно понятен мне с точки зрения реализации. Как реализовать разложение входного узла на несколько в python? Как сделать так, чтобы это произошло легко? Есть идеи?

моя попытка:

import tensorflow as tf
import numpy as np
import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Dropout, Flatten
from keras.datasets import cifar10
from keras.utils import to_categorical

(train_imgs, train_label), (test_imgs, test_label)= cifar10.load_data()
output_class = np.unique(train_label)
n_class = len(output_class)

nrows_tr, ncols_tr, ndims_tr = train_imgs.shape[1:]
nrows_ts, ncols_ts, ndims_ts = test_imgs.shape[1:]
train_data = train_imgs.reshape(train_imgs.shape[0], nrows_tr, ncols_tr, ndims_tr)

test_data = test_imgs.reshape(test_imgs.shape[0], nrows_ts, ncols_ts, ndims_ts)
input_shape = (nrows_tr, ncols_tr, ndims_tr)
train_data = train_data.astype('float32')
trast_data = test_data.astype('float32')
train_data //= 255
test_data //= 255
train_label_one_hot = to_categorical(train_label)
test_label_one_hot = to_categorical(test_label)

def pown(x,n):
    return(x**n)

def expandable_cnn(input_shape, output_shape, approx_order):
    inputs=Input(shape=(input_shape))
    x= Dense(input_shape)(inputs)
    y= Dense(output_shape)(x)
    model = Sequential()
    model.add(Conv2D(filters=32, kernel_size=(3,3), padding='same', activation="relu", input_shape=input_shape))
    model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512, activation='relu'))
    model.add(Dropout(0.5))
    for i in range(2, approx_order+1):
        y=add([y, Dense(output_shape)(Activation(lambda x: pown(x, n=i))(x))])
    model.add(Dense(n_class, activation='softmax')(y))
    return model

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

желаемый результат:

Я ожидаю расширения CNN с помощью нелинейного расширения серии Маклорена, как сделать приведенную выше реализацию правильной и эффективной? любая возможная идея или подход?


person Jared    schedule 02.04.2020    source источник


Ответы (1)


Интересный вопрос. Я реализовал модель Кераса, которая вычисляет расширение Тейлора, как вы описали:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Input, Lambda


def taylor_expansion_network(input_dim, max_pow):
    x = Input((input_dim,))

    # 1. Raise input x_i to power p_i for each i in [0, max_pow].
    def raise_power(x, max_pow):
        x_ = x[..., None]  # Shape=(batch_size, input_dim, 1)
        x_ = tf.tile(x_, multiples=[1, 1, max_pow + 1])  # Shape=(batch_size, input_dim, max_pow+1)
        pows = tf.range(0, max_pow + 1, dtype=tf.float32)  # Shape=(max_pow+1,)
        x_p = tf.pow(x_, pows)  # Shape=(batch_size, input_dim, max_pow+1)
        x_p_ = x_p[..., None]  # Shape=(batch_size, input_dim, max_pow+1, 1)
        return x_p_

    x_p_ = Lambda(lambda x: raise_power(x, max_pow))(x)

    # 2. Multiply by alpha coefficients
    h = LocallyConnected2D(filters=1,
                           kernel_size=1,  # This layer is computing a_i * x^{p_i} for each i in [0, max_pow]
                           use_bias=False)(x_p_)  # Shape=(batch_size, input_dim, max_pow+1, 1)

    # 3. Compute s_i for each i in [0, max_pow]
    def cumulative_sum(h):
        h = tf.squeeze(h, axis=-1)  # Shape=(batch_size, input_dim, max_pow+1)
        s = tf.cumsum(h, axis=-1)  # s_i = sum_{j=0}^i h_j. Shape=(batch_size, input_dim, max_pow+1)
        s_ = s[..., None]  # Shape=(batch_size, input_dim, max_pow+1, 1)
        return s_

    s_ = Lambda(cumulative_sum)(h)

    # 4. Compute sum w_i * s_i each i in [0, max_pow]
    s_ = LocallyConnected2D(filters=1,  # This layer is computing w_i * s_i for each i in [0, max_pow]
                            kernel_size=1,
                            use_bias=False)(s_)  # Shape=(batch_size, input_dim, max_pow+1)
    y = Lambda(lambda s_: tf.reduce_sum(tf.squeeze(s_, axis=-1), axis=-1))(s_)  # Shape=(batch_size, input_dim)

    # Return Taylor expansion model
    model = Model(inputs=x, outputs=y)
    model.summary()
    return model

Реализация применяет одно и то же расширение Тейлора к каждому элементу сплющенного тензора с формой (batch_size, input_dim=512), полученной из сверточной сети.


ОБНОВЛЕНИЕ. Как мы обсуждали в разделе комментариев, вот некоторый код, показывающий, как ваша функция expandable_cnn может быть изменена для интеграции модели, определенной выше:

def expandable_cnn(input_shape, nclass, approx_order):
    inputs = Input(shape=(input_shape))
    h = inputs
    h = Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation='relu', input_shape=input_shape)(h)
    h = Conv2D(filters=32, kernel_size=(3, 3), activation='relu')(h)
    h = MaxPooling2D(pool_size=(2, 2))(h)
    h = Dropout(0.25)(h)
    h = Flatten()(h)
    h = Dense(512, activation='relu')(h)
    h = Dropout(0.5)(h)
    taylor_model = taylor_expansion_network(input_dim=512, max_pow=approx_order)
    h = taylor_model(h)
    h = Activation('relu')(h)
    print(h.shape)
    h = Dense(nclass, activation='softmax')(h)
    model = Model(inputs=inputs, outputs=h)
    return model

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

person rvinas    schedule 05.04.2020
comment
не могли бы вы сначала позволить мне воспроизвести ваш ответ с набором данных cifar-10? Большое спасибо! - person Jared; 05.04.2020
comment
Не за что :) Я не включил активацию g из уравнения, но вы можете легко вычислить ее на выходе этой модели. Кроме того, я буду рад внести любые необходимые изменения. Например, неясно, следует ли модель применять независимо к каждому элементу входного тензора или нужно обучать альфа и w (в моей реализации они обучаемы) - person rvinas; 05.04.2020
comment
Я пытаюсь воспроизвести ваш ответ с набором данных cifar-10, но мне трудно понять эти строки: x_p_ = x_p[..., None], s_ = s[..., None]. ... в s_ = s[..., None] относится к параметрам по умолчанию или ... равно Shape=(batch_size, input_dim, max_pow+1, 1)? что, если модель будет применяться к каждому элементу входного тензора, как это реализовать? В моем конвейере у меня есть 3 conv_filter и два скрытых слоя и слой FC, что, если я хочу использовать расширение Тейлора на скрытом слое с max_pow=2, как я могу сделать ваш ответ повторно используемым в piepelie? - person Jared; 05.04.2020
comment
ваш ответ мне очень помог, не могли бы вы обновить мой комментарий выше? спасибо - person Jared; 05.04.2020
comment
Я рад, что это полезно. Что касается многоточия ..., я в основном использую его для расширения последнего измерения тензор, например x_p[..., None] эквивалентно x_p[:, :, : , None] и tf.expand_dims(x_p, -1) . Другими словами, размеры идут от (batch_size, input_dim, max_pow+1) до (batch_size, input_dim, max_pow+1, 1). - person rvinas; 05.04.2020
comment
Прямо сейчас модель готова к применению к каждому элементу входного тензора, то есть вы можете применить модель к выходу сети FC (скажем, тензор формы (bs, nb_hidden)), и ряд Тейлора будет расширен для каждый элемент вдоль второй оси. Обратите внимание, что в текущей реализации веса alpha и w распределяются между элементами — также можно было бы сделать их независимыми для каждого элемента, если вы этого хотите. - person rvinas; 05.04.2020
comment
Давайте продолжим обсуждение в чате. - person Jared; 05.04.2020