нормализация партии, да или нет? - PullRequest
5 голосов
/ 29 октября 2019

Я использую Tensorflow 1.14.0 и Keras 2.2.4. Следующий код реализует простую нейронную сеть:

import numpy as np
np.random.seed(1)
import random
random.seed(2)
import tensorflow as tf
tf.set_random_seed(3)

from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Input, Dense, Activation


x_train=np.random.normal(0,1,(100,12))

model = Sequential()
model.add(Dense(8, input_shape=(12,)))
# model.add(tf.keras.layers.BatchNormalization())
model.add(Activation('linear'))
model.add(Dense(12))
model.add(Activation('linear'))
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x_train, x_train,epochs=20, validation_split=0.1, shuffle=False,verbose=2)

Конечный val_loss после 20 эпох составляет 0,7751. Когда я раскомментирую единственную строку комментария для добавления слоя нормализации партии, val_loss изменится на 1.1230.

Моя главная проблема намного сложнее, но происходит то же самое. Так как моя активация линейная, не имеет значения, ставлю ли я нормализацию партии после или перед активацией.

Вопросы: Почему нормализация партии не может помочь? Могу ли я что-нибудь изменить, чтобы нормализация партии улучшила результат без изменения функций активации?

Обновление после получения комментария:

NN с одним скрытым слоеми линейные активации вроде как PCA. На это есть тонны бумаг. Для меня этот параметр дает минимальное значение MSE среди всех комбинаций функций активации для скрытого слоя и вывода.

Некоторые ресурсы, которые указывают на линейную активацию, означают PCA:

https://arxiv.org/pdf/1702.07800.pdf

https://link.springer.com/article/10.1007/BF00275687

https://www.quora.com/How-can-I-make-a-neural-network-to-work-as-a-PCA

1 Ответ

3 голосов
/ 30 октября 2019

Да.

Наблюдаемое вами поведение является ошибкой - и вам не нужен BN, чтобы его увидеть;График слева для #V1, справа для #V2:

enter image description here

#V1
model = Sequential()
model.add(Dense(8, input_shape=(12,)))
#model.add(Activation('linear')) <-- uncomment == #V2
model.add(Dense(12))
model.compile(optimizer='adam', loss='mean_squared_error')

Совершенно бессмысленно, как Activation('linear')после слоя с activation=None (== 'linear') будет тождество : model.layers[1].output.name == 'activation/activation/Identity:0'. Это может быть подтверждено в дальнейшем путем выборки и построения графиков выходных данных промежуточного слоя, которые идентичны для 'dense' и 'activation' - здесь не будут указаны.

Итак, активация буквально ничего не делает, кроме этого - где-тов цепочке коммитов между 1.14.0 и 2.0.0 это было исправлено, хотя я не знаю где. Результаты с BN с использованием TF 2.0.0 с Keras 2.3.1 ниже:

val_loss = 0.840 # without BN
val_loss = 0.819 # with BN

enter image description here


Решение : обновление до TensorFlow 2.0.0, Keras 2.3.1.

Совет : использование Anaconda с виртуальной средой. Если у вас еще нет виртуальных envs, запустите:

conda create --name tf2_env --clone base
conda activate tf2_env
conda uninstall tensorflow-gpu
conda uninstall keras
conda install -c anaconda tensorflow-gpu==2.0.0
conda install -c conda-forge keras==2.3.1

Может быть немного сложнее, чем это, но это тема другого вопроса.


ОБНОВЛЕНИЕ : импорт из keras вместо tf.keras также решает проблему.


Отказ от ответственности : BN остается «спорным» слоем в Keras, но еще не полностью исправлен - см. Соответствующий Git ;Я планирую исследовать это сам в конечном счете, но для ваших целей этого ответа должно хватить.

Я также рекомендую ознакомиться с основополагающей теорией BN, в частности, касающейся ее работы "поезд против логического вывода";в двух словах, размеры пакетов до 32 - довольно плохая идея, и набор данных должен быть достаточно большим, чтобы BN мог точно аппроксимировать набор тестов gamma и beta.


Кодиспользуется:

x_train=np.random.normal(0, 1, (100, 12))

model = Sequential()
model.add(Dense(8, input_shape=(12,)))
#model.add(Activation('linear'))
#model.add(tf.keras.layers.BatchNormalization())
model.add(Dense(12))
model.compile(optimizer='adam', loss='mean_squared_error')

W_sum_all = []  # fit rewritten to allow runtime weight collection
for _ in range(20):
    for i in range(9):
        x = x_train[i*10:(i+1)*10]
        model.train_on_batch(x, x)

        W_sum_all.append([])
        for layer in model.layers:
            if layer.trainable_weights != []:
                W_sum_all[-1] += [np.sum(layer.get_weights()[0])]
model.evaluate(x[-10:], x[-10:])

plt.plot(W_sum_all)
plt.title("Sum of weights (#V1)", weight='bold', fontsize=14)
plt.legend(labels=["dense", "dense_1"], fontsize=14)
plt.gcf().set_size_inches(7, 4)

Импорт / предварительное выполнение:

import numpy as np
np.random.seed(1)
import random
random.seed(2)
import tensorflow as tf
if tf.__version__[0] == '2':
    tf.random.set_seed(3)
else:
    tf.set_random_seed(3)

import matplotlib.pyplot as plt
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Input, Dense, Activation
...