keras BatchNormalization axis clarification

Слой keras BatchNormalization использует axis=-1 в качестве значения по умолчанию и утверждает, что ось объекта обычно нормализована. Почему это так?

Я полагаю, это удивительно, потому что я более знаком с использованием чего-то вроде StandardScaler, что было бы эквивалентно использованию axis=0. Это нормализует функции индивидуально.

Есть ли причина, по которой выборки по умолчанию индивидуально нормализуются (т.е. axis=-1) в кератах, а не по функциям?

Изменение: пример для конкретности

Обычно данные преобразуются таким образом, что каждый объект имеет нулевое среднее значение и единичную дисперсию. Давайте просто рассмотрим часть с "нулевым средним" в этом фиктивном наборе данных, где каждая строка является выборкой:

>>> data = np.array([[   1,   10,  100, 1000],
                     [   2,   20,  200, 2000],
                     [   3,   30,  300, 3000]])

>>> data.mean(axis=0)
array([    2.,    20.,   200.,  2000.])

>>> data.mean(axis=1)
array([ 277.75,  555.5 ,  833.25])

Не имеет ли больше смысла вычитать среднее значение axis=0, а не среднее axis=1? Используя axis=1, единицы измерения и шкалы могут быть совершенно разными.

Изменить 2:

Первое уравнение раздела 3 в этой статье, по-видимому, подразумевает, что axis=0 следует использовать для расчета ожиданий и отклонений для каждого элемента в отдельности, предполагая, что у вас есть (m, n) -образный набор данных, где m - это количество образцов, а n - это число признаков.

Изменить 3: еще один пример

Я хотел увидеть размеры средних и отклонений, которые BatchNormalization рассчитывал на наборе игрушечных данных:

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris

from keras.optimizers import Adam
from keras.models import Model
from keras.layers import BatchNormalization, Dense, Input


iris = load_iris()
X = iris.data
y = pd.get_dummies(iris.target).values

input_ = Input(shape=(4, ))
norm = BatchNormalization()(input_)
l1 = Dense(4, activation='relu')(norm)
output = Dense(3, activation='sigmoid')(l1)

model = Model(input_, output)
model.compile(Adam(0.01), 'categorical_crossentropy')
model.fit(X, y, epochs=100, batch_size=32)

bn = model.layers[1]
bn.moving_mean  # <tf.Variable 'batch_normalization_1/moving_mean:0' shape=(4,) dtype=float32_ref>

Вход X имеет форму (150, 4), а слой BatchNormalization рассчитан по 4 средним значениям, что означает, что он работал над axis=0.

Если BatchNormalization имеет значение по умолчанию axis=-1, тогда не должно ли быть 150 средних?

Ответ 1

Путаница объясняется значением axis в np.mean сравнению с BatchNormalization.

Когда мы берем среднее по оси, мы разрушаем это измерение и сохраняем все остальные измерения. В вашем примере data.mean(axis=0) сворачивает 0-axis, которая является вертикальным размером data.

Когда мы вычисляем BatchNormalization вдоль оси, мы сохраняем размеры массива, и мы нормализуемся относительно среднего и стандартного отклонения по любой другой оси. Поэтому в вашем 2D примере BatchNormalization с axis=1 вычитает среднее значение для axis=0, как и ожидалось. Вот почему bn.moving_mean имеет форму (4,).

Ответ 2

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

  1. Переменная оси, которая задокументирована как целое число, может фактически быть списком целых чисел, обозначающих несколько осей. Так, например, если у моего ввода было изображение в форматах NHWC или NCHW, укажите axis = [1,2,3], если бы я хотел выполнить BatchNormalization так, как этого хочет OP (то есть нормализовать только по измерению пакета).
  2. Список осей (или целое число) должен содержать оси, которые вы не хотите уменьшать при вычислении среднего значения и дисперсии. Другими словами, это дополнение осей, вдоль которых вы хотите нормализоваться - совершенно противоположное тому, что документация говорит, если вы придерживаетесь обычного определения "осей". Так, например, если вы указали значение я (N, H, W, C) или (N, C, H, W), то есть первое измерение было измерением партии, а вы хотели, чтобы только среднее значение и дисперсия вычислялись по измерению партии Вы должны предоставить ось = [1,2,3]. Это заставит Keras вычислять среднее значение M и дисперсию V тензоров формы (1, H, W, C) или (1, C, H, W) соответственно - т.е. размер партии будет маргинализирован/уменьшен вследствие агрегации (то есть среднее значение или дисперсия рассчитывается по первому измерению). В более поздних операциях, таких как (I-M) и (I-M)/V, первое измерение M и V будет передаваться всем N выборкам партии.
  3. В этом примере слой BatchNorm вызывает tf.nn.moments с axes = (1,)! Это так, потому что определение осей в tf.nn.moments является правильным.
  4. Точно так же tf.nn.moments вызывает tf.nn.reduce_mean, где опять-таки определение осей является правильным (то есть противоположным tf.keras.layers.BatchNormalization).
  5. Тем не менее, в документе BatchNormalization предлагается нормализация по пространственной карте HxW в дополнение к измерению партии (N). Следовательно, если следовать этому совету, то ось будет включать только измерение канала (C), потому что это единственное оставшееся измерение, которое вы не хотите уменьшать. Документация Keras, вероятно, намекает на это, хотя и довольно загадочно.

Ответ 3

если ваша мини-партия представляет собой матрицу A mxn, т.е. m образцов и n объектов, ось нормализации должна быть axis = 0, Как вы сказали, мы хотим нормализовать каждый объект индивидуально, по умолчанию axis = -1 в кератах, потому что когда он используется в свёрточном слое, размеры набора данных фигур обычно (сэмплы, ширина, высота, канал), а пакетные сэмплы нормализуются по длинной оси канала (последняя ось).