#tensorflow #reshape #convolution
Вопрос:
Чего я хотел бы добиться, так это применения 2D-свертки с одним фильтром, который применяется по всем каналам. Обратите внимание, что я ищу не глубинную свертку, а действительно один фильтр. Чтобы сделать это, мой план состоял в том , чтобы изменить [N,H,W,C]
[N*C,H,W,1]
форму, применить свертку, а затем изменить ее обратно, чтобы мой результат был [N,H,W,C]
снова.
_, self.h, self.w, self.c = inputs.shape self.conv = tf.keras.layers.Conv2D(filters=2, kernel_size=3, strides=1, padding='same') x = tf.reshape(inputs, [-1,self.h,self.w,1]) x = self.conv(x) x = tf.math.argmax(x, axis=3) output = tf.reshape(x ,[-1,self.h,self.w,self.c])
Однако, реализуя это, я заметил, что результат первого изменения формы содержит какой-то перемежающий переход между каналами или пакетом или чем-то еще (изображение из ImageNet): До изменения формы, После изменения формы. Моя интуиция подсказывала, что это может быть связано с тем, что пакет и каналы не соседствуют в памяти.
По этой причине я экспериментировал, сначала транспонируя входные данные, а затем применяя изменение формы, свертку, изменение формы и транспонирование обратно:
_, self.h, self.w, self.c = inputs.shape self.conv = tf.keras.layers.Conv2D(filters=2, kernel_size=3, strides=1, padding='same', data_format="channels_first") x_t = tf.transpose(inputs, [0,3,1,2]) # convert nhwc to nchw x_t = tf.reshape(x_t, [-1,1,self.h,self.w]) x_t = self.conv(x_t) x_t = tf.math.argmax(x_t, axis=1) x_t = tf.reshape(x_t ,[-1,self.c,self.h,self.w]) output = tf.transpose(x_t, [0,2,3,1])
Это действительно, кажется, работает так, как я ожидал, но это довольно медленный подход. У меня есть ряд вопросов:
- Какова точная причина чередования, которое я испытываю?
- Был бы способ изменить мои данные без необходимости использования транспонирования? Я знаю, что, возможно, я мог бы везде использовать
NCHW
формат данных, но, поскольку я пытаюсь построить реализацию на существующей платформе, я думаю, что изменение формата данных нарушит другие части кода. - Есть ли, возможно, совершенно другой подход, который я мог бы применить для свертки на канал? Я думал об использовании
unstack
или о чем-то подобном, но для этого потребовались бы циклы, что еще более неэффективно в моей идее.
Заранее спасибо
edit: I think I at least understand why the interleaving is happening. Let me try to explain by how I understand it, and format it as good as possible. The letters n,h,w,c here should help identifying to what a number belongs.
Suppose I have 16 numbers which are contiguous in memory:
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
Если они имеют форму NHWC: 2,2,2,2
[n[h[w[c1,c2], w[c3,c4]], h[w[c5,c6], w[c7,c8]]], n[h[w[c9,c10], w[c11,c12]], h[w[c13,c14], w[c15,c16]]]]
Затем, если они будут изменены NHWC: 4,2,2,1
и, сохраняя непрерывность базовых данных, мы получим:
[n[h[w[c1], w[c2]], h[w[c3], w[c4]]], n[h[w[c5], w[c6]], h[w[c7], w[c8]]], n[h[w[c9], w[c10]], h[w[c11], w[c12]]], n[h[w[c13], w[c14]], h[w[c15], w[c16]]]]
Таким образом, каналы путаются в пространственных измерениях изображения.
Ответ №1:
Во-первых, изменение формы не работает должным образом, если вы хотите объединить не последовательные измерения, поэтому транспонирование-хорошая идея. Однако Conv2d ожидает, что последним измерением будут входные каналы. В вашем случае это self.w
так, но, скорее всего, это то, что вы хотите. Вы можете изменить линию изменения формы на: tf.reshape(x_t, [-1, self.h, self.w, 1])
как и ранее.
Комментарии:
1. Действительно, я, кажется, понимаю, что происходит с точки зрения изменения формы. Я попытался написать это в правке своего поста. Вторая версия (с транспонированием) на самом деле имеет свертку
dataformat="channels_first"
для обработки каналов во втором измерении.2. о, я ничего не понял, ладно