Сбросить вес в слое 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 (), и они, похоже, меняются. Но когда я перезапускаю обучение, значения затрат намного ниже, чем значения начальных затрат при первом запуске. Как будто мне удалось сбросить некоторые веса, но не все.

Будем очень признательны за любые советы о том, где я ошибаюсь. Спасибо..


person Tor    schedule 08.11.2016    source источник


Ответы (8)


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

model.save_weights('model.h5')

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

model.load_weights('model.h5')

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

person ezChx    schedule 13.05.2017
comment
В итоге я сделал нечто подобное. Сохранение на диск и загрузка занимает много времени, поэтому я просто сохраняю веса в переменной: weights = model.get_weights () Я получаю такие начальные веса перед запуском первого обучения. Затем перед каждым последующим обучением я перезагружаю начальные веса и запускаю метод перемешивания jkleint, как указано в опубликованной мной ссылке. Вроде работает плавно .. - person Tor; 15.05.2017
comment
Полный фрагмент кода предложения @ Tor: weights = model.get_weights(), model.compile(args), model.fit(args), model.set_weights(weights) - person BallpointBen; 08.05.2018
comment
Исходя из этого, я начал создавать лямбда-функцию при инициализации моей модели. Я строю модель, затем делаю что-то вроде weights = model.get_weights(); reset_model = lambda model: model.set_weights(weights), тогда я могу позвонить reset_model(model) позже. - person Andrew; 05.07.2019

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

def reset_weights(model):
    import keras.backend as K
    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)     

Обновление: kernel_initializer теперь является kernel.initializer.

person Mendi Barel    schedule 07.08.2018
comment
На мой взгляд, это лучший подход. - person SuperNES; 15.02.2019
comment
Это устарело? Теперь kernel_initializer не имеет атрибута run. В моем случае kernel_initializer - это объект VarianceScaling - person Xiaohong Deng; 29.03.2019
comment
@XiaohongDeng попробуйте вместо этого kernel.initializer.run(session=session). У меня такая же проблема - person tkchris; 15.07.2019
comment
AttributeError: module 'tensorflow_core.keras.backend' has no attribute 'get_session' с использованием tensorflow.keras - person Bersan; 02.01.2020
comment
Да, в tf2 это не сработает, посмотрите здесь в конце для tf2: github. com / keras-team / keras / issues / 341 - person Mendi Barel; 02.01.2020

Если вы хотите действительно повторно рандомизировать веса, а не просто восстановить исходные веса, вы можете сделать следующее. Код немного отличается в зависимости от того, используете ли вы 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)
person BallpointBen    schedule 09.05.2018
comment
Красивое и простое решение! - person guillefix; 22.12.2018

Я нашел функцию clone_model, которая создает клонированную сеть с та же архитектура, но новый вес модели.

Пример использования:

model_cloned = tensorflow.keras.models.clone_model(model_base)

Сравнение весов:

original_weights = model_base.get_weights()
print("Original weights", original_weights)
print("========================================================")
print("========================================================")
print("========================================================")
model_cloned = tensorflow.keras.models.clone_model(model_base)
new_weights = model_cloned.get_weights()
print("New weights", new_weights)

Если вы выполните этот код несколько раз, вы заметите, что клонированная модель каждый раз получает новые веса.

person danielsaromo    schedule 29.11.2020
comment
RuntimeError: вы должны скомпилировать свою модель перед обучением / тестированием. Используйте 1_. - person isobretatel; 12.12.2020

Попробуйте 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, вы увидите, что первый слой является входным, а остальные - вашими сверточными слоями.

person maz    schedule 08.03.2017

Ответ Tensorflow 2:

for ix, layer in enumerate(model.layers):
    if hasattr(model.layers[ix], 'kernel_initializer') and \
            hasattr(model.layers[ix], 'bias_initializer'):
        weight_initializer = model.layers[ix].kernel_initializer
        bias_initializer = model.layers[ix].bias_initializer

        old_weights, old_biases = model.layers[ix].get_weights()

        model.layers[ix].set_weights([
            weight_initializer(shape=old_weights.shape),
            bias_initializer(shape=old_biases.shape)])

Исходные веса:

model.layers[1].get_weights()[0][0]
array([ 0.4450057 , -0.13564804,  0.35884023,  0.41411972,  0.24866664,
        0.07641453,  0.45726687, -0.04410008,  0.33194816, -0.1965386 ,
       -0.38438258, -0.13263905, -0.23807487,  0.40130925, -0.07339832,
        0.20535922], dtype=float32)

Новые веса:

model.layers[1].get_weights()[0][0]
array([-0.4607593 , -0.13104361, -0.0372932 , -0.34242013,  0.12066692,
       -0.39146423,  0.3247317 ,  0.2635846 , -0.10496247, -0.40134245,
        0.19276887,  0.2652442 , -0.18802321, -0.18488845,  0.0826562 ,
       -0.23322225], dtype=float32)

person Nicolas Gervais    schedule 16.08.2020

Для «случайной» повторной инициализации весов скомпилированной необученной модели в 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).

person Andrew - OpenGeoCode    schedule 06.09.2019

person    schedule
comment
Не так портативно, но хорошо работает для бэкэнда tenorflow! - person bendl; 14.12.2018