Сбросить вес в слое Keras

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

Вдохновленный этим обсуждением, я пробую следующий код:

# Reset weights
for layer in KModel.layers:
    if hasattr(layer,'init'):
        input_dim = layer.input_shape[1]
        new_weights = layer.init((input_dim, layer.output_dim),name='{}_W'.format(layer.name))
        layer.trainable_weights[0].set_value(new_weights.get_value())

Однако это только отчасти работает.

Отчасти, потому что я проверил некоторые значения layer.get_weights(), и они, похоже, меняются. Но когда я перезапускаю обучение, значения стоимости намного ниже начальных стоимостных значений при первом запуске. Это почти так, как будто мне удалось сбросить некоторые весы, но не все из них.

Любые советы о том, куда я иду, будут глубоко оценены. Спасибо..

Ответы

Ответ 1

Сохраните начальные веса сразу после компиляции модели, но перед ее обучением:

model.save_weights('model.h5')

а затем после тренировки "перезагрузите" модель, перезагрузив исходные веса:

model.load_weights('model.h5')

Это дает вам модель яблок для яблок для сравнения разных наборов данных и должна быть быстрее, чем перекомпиляция всей модели.

Ответ 2

Если вы хотите по-настоящему рандомизировать веса, а не просто восстановить начальные веса, вы можете сделать следующее. Код немного отличается в зависимости от того, используете ли вы TensorFlow или Theano.

from keras.initializers import glorot_uniform  # Or your initializer of choice
import keras.backend as K

initial_weights = model.get_weights()

backend_name = K.backend()
if backend_name == 'tensorflow': 
    k_eval = lambda placeholder: placeholder.eval(session=K.get_session())
elif backend_name == 'theano': 
    k_eval = lambda placeholder: placeholder.eval()
else: 
    raise ValueError("Unsupported backend")

new_weights = [k_eval(glorot_uniform()(w.shape)) for w in initial_weights]

model.set_weights(new_weights)

Ответ 3

Сбросьте все слои, проверив инициализаторы:

def reset_weights(model):
    session = K.get_session()
    for layer in model.layers: 
        if hasattr(layer, 'kernel_initializer'):
            layer.kernel_initializer.run(session=session)
        if hasattr(layer, 'bias_initializer'):
            layer.bias_initializer.run(session=session)     

Ответ 4

Попробуйте set_weights.

например:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import numpy as np
np.random.seed(1234)
from keras.layers import Input
from keras.layers.convolutional import Convolution2D
from keras.models import Model

print("Building Model...")
inp = Input(shape=(1,None,None))
x   = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(inp)
output = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(x)
model_network = Model(input=inp, output=output)

w = np.asarray([ 
    [[[
    [0,0,0],
    [0,2,0],
    [0,0,0]
    ]]]
    ])

for layer_i in range(len(model_network.layers)):
    print (model_network.layers[layer_i])

for layer_i in range(1,len(model_network.layers)):
    model_network.layers[layer_i].set_weights(w)



input_mat = np.asarray([ 
    [[
    [1.,2.,3.,10.],
    [4.,5.,6.,11.],
    [7.,8.,9.,12.]
    ]]
    ])

print("Input:")
print(input_mat)
print("Output:")
print(model_network.predict(input_mat))

w2 = np.asarray([ 
    [[[
    [0,0,0],
    [0,3,0],
    [0,0,0]
    ]]]
    ])


for layer_i in range(1,len(model_network.layers)):
    model_network.layers[layer_i].set_weights(w2)

print("Output:")
print(model_network.predict(input_mat))

построить модель, скажем, двух сверточных слоев

print("Building Model...")
inp = Input(shape=(1,None,None))
x   = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(inp)
output = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(x)
model_network = Model(input=inp, output=output)

затем определите свои веса (я использую простой w, но вы можете использовать np.random.uniform или что-то в этом роде, если хотите)

w = np.asarray([ 
    [[[
    [0,0,0],
    [0,2,0],
    [0,0,0]
    ]]]
    ])

Взгляните на то, какие слои внутри модели

for layer_i in range(len(model_network.layers)):
    print (model_network.layers[layer_i])

Установите каждый вес для каждого сверточного слоя (вы увидите, что первый уровень действительно введен, и вы не хотите его изменять, поэтому диапазон начинается с 1 не ноль).

for layer_i in range(1,len(model_network.layers)):
    model_network.layers[layer_i].set_weights(w)

Создайте некоторый ввод для своего теста и предскажите результат с вашей модели

input_mat = np.asarray([ 
    [[
    [1.,2.,3.,10.],
    [4.,5.,6.,11.],
    [7.,8.,9.,12.]
    ]]
    ])

print("Output:")
print(model_network.predict(input_mat))

Вы можете изменить его снова, если хотите, и снова проверить выход:

w2 = np.asarray([ 
    [[[
    [0,0,0],
    [0,3,0],
    [0,0,0]
    ]]]
    ])

for layer_i in range(1,len(model_network.layers)):
    model_network.layers[layer_i].set_weights(w2)

print("Output:")
print(model_network.predict(input_mat))

Пример вывода:

Using Theano backend.
Building Model...
<keras.engine.topology.InputLayer object at 0x7fc0c619fd50>
<keras.layers.convolutional.Convolution2D object at 0x7fc0c6166250>
<keras.layers.convolutional.Convolution2D object at 0x7fc0c6150a10>
Weights after change:
[array([[[[ 0.,  0.,  0.],
         [ 0.,  2.,  0.],
         [ 0.,  0.,  0.]]]], dtype=float32)]
Input:
[[[[  1.   2.   3.  10.]
   [  4.   5.   6.  11.]
   [  7.   8.   9.  12.]]]]
Output:
[[[[  4.   8.  12.  40.]
   [ 16.  20.  24.  44.]
   [ 28.  32.  36.  48.]]]]
Output:
[[[[   9.   18.   27.   90.]
   [  36.   45.   54.   99.]
   [  63.   72.   81.  108.]]]]

С вашего взгляда на.layers вы можете видеть, что первый слой введен, а остальные - сверточными.

Ответ 5

K.get_session().close()
K.set_session(tf.Session())
K.get_session().run(tf.global_variables_initializer())

Ответ 6

Хорошо, так что, похоже, у кого-то была такая же проблема. Здесь вы найдете хорошее решение, которое решает проблему (для всех практических целей): https://gist.github.com/jkleint/eb6dc49c861a1c21b612b568dd188668

Ответ 7

Для "случайной" повторной инициализации весов скомпилированной неподготовленной модели в TF 2.0 (tf.keras):

weights = [glorot_uniform(seed=random.randint(0, 1000))(w.shape) if w.ndim > 1 else w for w in model.get_weights()]

Обратите внимание на "if wdim> 1 else w". Вы не хотите повторно инициализировать смещения (они остаются 0 или 1).