сделать карту входных функций из нейронов расширения для сверточного слоя в keras - PullRequest
6 голосов
/ 13 июля 2020

Я использовал расширение Тейлора в задаче классификации изображений. В основном, во-первых, вектор пикселей генерируется из изображения RGB, и значения каждого пикселя из вектора пикселей аппроксимируются с расширением ряда Тейлора sin(x). В реализации тензорного потока я попытался кодировать это с помощью тензорного потока, и у меня все еще есть проблема, когда я пытался создать карты функций, складывая тензор с условиями расширения. Может ли кто-нибудь представить возможную точку зрения, как я могу сделать мою текущую попытку более эффективной? Любые возможные мысли?

иллюстрация

вот простая архитектура, которую я пытаюсь правильно реализовать с помощью tenorflow для задачи классификации изображений.

enter image description here

I want to input feature maps from expansion neurons, delta_1, delta_2, but I didn't figure out how to make this happen. Can any one point me out possible way of doing this?

Here is the expansion terms of Taylor series of sin(x):

Разложение Тейлора sin (x)

вот моя текущая попытка:

term = 2
c = tf.constant([1, -1/6])
power = tf.constant([1, 3])

x = tf.keras.Input(shape=(32, 32, 3))
res =[]
for x in range(term):
    expansion = c * tf.math.pow(tf.tile(x[..., None], [1, 1, 1, 1, term]),power)
    m_ij = tf.math.cumsum(expansion, axis=-1)
    res.append(m_i)

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

1 Ответ

5 голосов
/ 05 августа 2020

При расширении серии, как описано, если вход имеет C каналов, а расширение имеет Т-члены, расширенный вход должен иметь C* Т каналов и в остальном иметь ту же форму. Таким образом, исходный ввод и аппроксимируемая функция до каждого члена должны быть объединены по размеру канала. Это немного проще сделать с транспонированием и изменением формы, чем с фактическим объединением.

Вот пример кода для сверточной сети, обученной на CIFAR10:

inputs = tf.keras.Input(shape=(32, 32, 3))

x = inputs
n_terms = 2
c = tf.constant([1, -1/6])
p = tf.constant([1, 3], dtype=tf.float32)

terms = []
for i in range(n_terms):
    m = c[i] * tf.math.pow(x, p[i])
    terms.append(m)
expansion = tf.math.cumsum(terms)
expansion_terms_last = tf.transpose(expansion, perm=[1, 2, 3, 4, 0])
x = tf.reshape(expansion_terms_last, tf.constant([-1, 32, 32, 3*n_terms])) 

x = Conv2D(32, (3, 3), input_shape=(32,32,3*n_terms))(x)

Это предполагает исходную сеть (без расширения) будет иметь первый уровень, который выглядит следующим образом:

x = Conv2D(32, (3, 3), input_shape=(32,32,3))(inputs)

, а остальная часть сети точно такая же, как и без расширения.

terms содержит список c_i * x ^ p_i из оригинала; expansion содержит сумму термов (1-е, затем 1-е и 2-е, и т. Д. c) в одном тензоре (где T - первое измерение). expansion_terms_last перемещает размер T в последний, а изменение формы меняет форму с (..., C, T) на (..., C*T)

Результат model.summary() затем выглядит следующим образом:

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_4 (InputLayer)            [(None, 32, 32, 3)]  0                                            
__________________________________________________________________________________________________
tf_op_layer_Pow_6 (TensorFlowOp [(None, 32, 32, 3)]  0           input_4[0][0]                    
__________________________________________________________________________________________________
tf_op_layer_Pow_7 (TensorFlowOp [(None, 32, 32, 3)]  0           input_4[0][0]                    
__________________________________________________________________________________________________
tf_op_layer_Mul_6 (TensorFlowOp [(None, 32, 32, 3)]  0           tf_op_layer_Pow_6[0][0]          
__________________________________________________________________________________________________
tf_op_layer_Mul_7 (TensorFlowOp [(None, 32, 32, 3)]  0           tf_op_layer_Pow_7[0][0]          
__________________________________________________________________________________________________
tf_op_layer_x_3 (TensorFlowOpLa [(2, None, 32, 32, 3 0           tf_op_layer_Mul_6[0][0]          
                                                                 tf_op_layer_Mul_7[0][0]          
__________________________________________________________________________________________________
tf_op_layer_Cumsum_3 (TensorFlo [(2, None, 32, 32, 3 0           tf_op_layer_x_3[0][0]            
__________________________________________________________________________________________________
tf_op_layer_Transpose_3 (Tensor [(None, 32, 32, 3, 2 0           tf_op_layer_Cumsum_3[0][0]       
__________________________________________________________________________________________________
tf_op_layer_Reshape_3 (TensorFl [(None, 32, 32, 6)]  0           tf_op_layer_Transpose_3[0][0]    
__________________________________________________________________________________________________
conv2d_5 (Conv2D)               (None, 30, 30, 32)   1760        tf_op_layer_Reshape_3[0][0]      

На CIFAR10 эта сеть обучается немного лучше с расширением - возможно, повышение точности на 1% (с 71 до 72%).

Пошаговое объяснение кода с использованием примеров данных:

# create a sample input
x = tf.convert_to_tensor([[1,2,3],[4,5,6],[7,8,9]], dtype=tf.float32) # start with H=3, W=3
x = tf.expand_dims(x, axis=0) # add batch dimension N=1
x = tf.expand_dims(x, axis=3) # add channel dimension C=1
# x is now NHWC or (1, 3, 3, 1)

n_terms = 2 # expand to T=2
c = tf.constant([1, -1/6])
p = tf.constant([1, 3], dtype=tf.float32)

terms = []
for i in range(n_terms):
    # this simply calculates m = c_i * x ^ p_i
    m = c[i] * tf.math.pow(x, p[i])
    terms.append(m)
print(terms)
# list of two tensors with shape NHWC or (1, 3, 3, 1)

# calculate each partial sum
expansion = tf.math.cumsum(terms)
print(expansion.shape)
# tensor with shape TNHWC or (2, 1, 3, 3, 1)

# move the T dimension last
expansion_terms_last = tf.transpose(expansion, perm=[1, 2, 3, 4, 0])
print(expansion_terms_last.shape)
# tensor with shape NHWCT or (1, 3, 3, 1, 2)

# stack the last two dimensions together
x = tf.reshape(expansion_terms_last, tf.constant([-1, 3, 3, 1*2])) 
print(x.shape)
# tensor with shape NHW and C*T or (1, 3, 3, 2)
# if the input had 3 channels for example, this would be (1, 3, 3, 6)
# now use this as though it was the input

Ключевые предположения (1) c_i и p_i не являются изученными параметрами, поэтому «нейроны расширения» на самом деле не нейроны, они просто узел умножения и суммирования (хотя нейроны звучат круче :) и (2 ) расширение происходит для каждого входного канала независимо, таким образом, C входных каналов, расширенных до T, каждый дает C* T входных характеристик, но T-характеристики каждого канала вычисляются полностью независимо от других каналов (похоже, что на диаграмме), и (3) входные данные содержат все частичные суммы (ie c_1 * x ^ p_1, c_1 * x ^ p_1 + c_2 * x ^ p_2 и т. д.), но не содержат t термины (опять же, как на схеме)

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