Вдохновленный @Srihari Humbarwadi, я нахожу способ реализовать сложную регуляризацию, которая включает:
- добавление обучаемого параметра для потери регуляризатора
- настраиваемый расчет между весами в разных слои
Идея состоит в том, чтобы построить модель подкласса:
class Pseudo_Model(Model):
def __init__(self, **kwargs):
super(Pseudo_Model, self).__init__(**kwargs)
self.dense1 = Dense(16)
self.dense2 = Dense(4)
self.dense3 = Dense(2)
self.a = tf.Variable(shape=(1,), initial_value=tf.ones(shape=(1,)))
def call(self, inputs, training=True, mask=None):
x = self.dense1(inputs)
x = self.dense2(x)
x = self.dense3(x)
return x
Модель построена через:
sub_model = Pseudo_Model(name='sub_model')
inputs = Input(shape=(32,))
outputs = sub_model(inputs)
model = Model(inputs, outputs)
model.summary()
model.get_layer('sub_model').summary()
Структура модели:
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 32)] 0
_________________________________________________________________
sub_model (Pseudo_Model) (None, 2) 607
=================================================================
Total params: 607
Trainable params: 607
Non-trainable params: 0
_________________________________________________________________
Model: "sub_model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 16) 528
_________________________________________________________________
dense_1 (Dense) (None, 4) 68
_________________________________________________________________
dense_2 (Dense) (None, 2) 10
=================================================================
Total params: 607
Trainable params: 607
Non-trainable params: 0
_________________________________________________________________
Затем определите функцию потерь, как упомянул @Srihari Humbarwadi, только чтобы добавить новый обучаемый параметр a:
def custom_loss(weight_a, weight_b, a):
def _custom_loss():
# This can include any arbitrary logic
loss = a * tf.norm(weight_a) + tf.norm(weight_b)
return loss
return _custom_loss
Потеря добавляется к модели с помощью add_loss () API :
a_ = model.get_layer('sub_model').a
weighta = model.get_layer('sub_model').layers[0].kernel
weightb = model.get_layer('sub_model').layers[1].kernel
model.get_layer('sub_model').add_loss(custom_loss(weighta, weightb, a_))
print(model.losses)
#[<tf.Tensor: id=116, shape=(1,), dtype=float32, numpy=array([7.2659254], dtype=float32)>]
Затем я создаю поддельный набор данных, чтобы проверить его:
fake_data = np.random.rand(1000, 32)
fake_labels = np.random.rand(1000, 2)
model.compile(optimizer=tf.keras.optimizers.SGD(), loss='mse')
model.fit(x=fake_data, y=fake_labels, epochs=5)
print(model.get_layer(name='sub_model').a)
Как видите, переменные и потери обновляются:
Train on 1000 samples
Epoch 1/5
2020-06-19 19:21:02.475464: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library cublas64_100.dll
1000/1000 - 1s - loss: 3.9039
Epoch 2/5
1000/1000 - 0s - loss: -3.0905e+00
Epoch 3/5
1000/1000 - 0s - loss: -1.2103e+01
Epoch 4/5
1000/1000 - 0s - loss: -2.6855e+01
Epoch 5/5
1000/1000 - 0s - loss: -5.3408e+01
<tf.Variable 'Variable:0' shape=(1,) dtype=float32, numpy=array([-8.13609], dtype=float32)>
Process finished with exit code 0
Но все же это действительно хитрый метод. Я не знаю, есть ли более элегантный и стабильный способ достижения той же функции.