При выполнении последовательного расширения, как описано, если вход имеет C каналов, а расширение имеет T членов, расширенный ввод должен иметь каналы C * T и в остальном иметь ту же форму. Таким образом, исходный вход и функция, аппроксимируемая до каждого члена, должны быть объединены по размерности канала. Это немного проще сделать с транспонированием и изменением формы, чем с конкатенацией.
Вот пример кода сверточной сети, обученной на 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-й и т. д.) в одном тензоре (где 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) вход содержит все частичные суммы (т.е. c_1 * x ^ p_1, c_1 * x ^ p_1 + c_2 * x ^ p_2 и т. д.), но не содержит членов (опять же, выглядит так, как на диаграмме)
person
Alex I
schedule
05.08.2020
for x in range(term):
повторно использовать одно и то же имяx
. А что такоеm_i
? Это значитm_ij
? - person yao99   schedule 02.08.2020