Keras с Activity_regularizer, который обновляется каждую итерацию - PullRequest
2 голосов
/ 25 сентября 2019

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

import numpy as np
import math
import keras
from keras.models import Model, Sequential
from keras.layers import Input, Dense, Activation
from keras import regularizers
from keras import backend as K

a=1

def my_regularizer(inputs):
     means=K.mean((inputs),axis=1)
     return a*K.sum(means)**2

x_train=np.random.uniform(low=-1,high=1,size=(200,2))

model=Sequential([
     Dense(20,input_shape=(2,),activity_regularizer=my_regularizer),
     Activation('tanh'),
     Dense(2,),
     Activation('linear')
])

model.compile(optimizer='adam',loss='mean_squared_error')
model.fit(x_train,x_train,epochs=20,validation_split=0.1)

Вопросы:

1) В настоящее время параметр a установлен в начале и не изменяется.Как я могу изменить код так, чтобы параметр a обновлялся после каждой итерации, так что

a_new = f (a_old, input)

где input - значения в скрытом слое, а f (.) - произвольная функция.

2) Я хочу, чтобы мой регуляризатор активности был применен после применения первой функции активации tanh.Правильно ли я написал свой код?Термин «activity_regularizer = my_regularizer» в

Dense(20,input_sahpe=(2,),activity_regularizer=my_regularizer)

заставляет меня чувствовать, что регуляризатор применяется к значениям до функции активации tanh.

1 Ответ

1 голос
/ 25 сентября 2019

Вы можете - но сначала вам нужен действительный объект Keras Regularizer (ваша функция не будет работать):

class MyActivityRegularizer(Regularizer):
    def __init__(self, a=1):
        self.a = K.variable(a, name='a')

    # gets called at each train iteration
    def __call__(self, x): # your custom function here
        means = K.mean(x, axis=1)
        return self.a * K.sum(means)**2

    def get_config(self): # required class method
        return {"a": float(K.get_value(self.a))}

Далее, чтобы работать с .fit, вам нужен пользовательский KerasCallback объект (см. Альтернативу внизу):

class ActivityRegularizerScheduler(Callback):
    """ 'on_batch_end' gets automatically called by .fit when finishing
    iterating over a batch. The model, and its attributes, are inherited by 
    'Callback' (except at __init__) and can be accessed via, e.g., self.model """

    def __init__(self, model, update_fn):
        self.update_fn=update_fn
        self.activity_regularizers=_get_activity_regularizers(model)

    def on_batch_end(self, batch, logs=None):
        iteration = K.get_value(self.model.optimizer.iterations)
        new_activity_reg = self.update_fn(iteration) 

        # 'activity_regularizer' references model layer's activity_regularizer (in this 
        # case 'MyActivityRegularizer'), so its attributes ('a') can be set directly
        for activity_regularizer in self.activity_regularizers:
            K.set_value(activity_regularizer.a, new_activity_reg)

def _get_activity_regularizers(model):
    activity_regularizers = []
    for layer in model.layers:
        a_reg = getattr(layer,'activity_regularizer',None)
        if a_reg is not None:
            activity_regularizers.append(a_reg)
    return activity_regularizers

Наконец, вам нужно создать свою модель в Keras CustomObjectScope - см. Полный пример.ниже.


Пример использования :
from keras.layers import Dense
from keras.models import Sequential
from keras.regularizers import Regularizer
from keras.callbacks import Callback
from keras.utils import CustomObjectScope
from keras.optimizers import Adam
import keras.backend as K
import numpy as np

def make_model(my_reg):
    return Sequential([
        Dense(20, activation='tanh', input_shape=(2,), activity_regularizer=my_reg),
        Dense(2,  activation='linear'),
        ])
my_reg = MyActivityRegularizer(a=1)

with CustomObjectScope({'MyActivityRegularizer':my_reg}): # required for Keras to recognize
    model = make_model(my_reg)
opt = Adam(lr=1e-4)
model.compile(optimizer=opt, loss='mse')
x = np.random.randn(320,2) # dummy data
y = np.random.randn(320,2) # dummy labels

update_fn = lambda x: .5 + .4*np.cos(x) #x = number of train updates (optimizer.iterations)
activity_regularizer_scheduler = ActivityRegularizerScheduler(model, update_fn)

model.fit(x,y,batch_size=32,callbacks=[activity_regularizer_scheduler],
          epochs=4,verbose=1)

Чтобы отследить ваш a и убедиться, что он меняется, вы можете получить его значение, например, в каждой эпохеконец через:

for epoch in range(4):
    model.fit(x,y,batch_size=32,callbacks=[activity_regularizer_scheduler],epochs=1)
    print("Epoch {} activity_regularizer 'a': {}".format(epoch,
            K.get_value(_get_activity_regularizers(model)[0].a)))
# My output:
# Epoch 0 activity_regularizer 'a': 0.7190816402435303
# Epoch 1 activity_regularizer 'a': 0.4982417821884155
# Epoch 2 activity_regularizer 'a': 0.2838689386844635
# Epoch 3 activity_regularizer 'a': 0.8644570708274841


Относительно (2) , боюсь, вы правы - выходы 'tanh' не будут использоваться;вам нужно будет передать activation='tanh' вместо этого.
Наконец, вы можете сделать это без обратного вызова, через train_on_batch - но недостатком является то, что вам нужно будет подавать данные в модель самостоятельно (и тасовать их, и т. Д.):
activity_regularizers = _get_activity_regularizers(model)

for iteration in range(100):
   x, y = get_data()
   model.train_on_batch(x,y)
   iteration = K.get_value(model.optimizer.iterations)

   for activity_regularizer in activity_regularizers:
       K.set_value(activity_regularizer, update_fn(iteration))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...