Tensorflow: Модель Keras маринованная, но модель tf.keras не маринованная

Созданный на 29 нояб. 2019  ·  34Комментарии  ·  Источник: tensorflow/tensorflow

Системная информация

  • Windows 10
  • Tensorflow 2.0 (ЦП)
  • joblib 0.14.0
  • Python 3.7.5
  • Керас 2.3.1

Всем привет! Это мой первый пост, так что простите меня, если я что-то упустил. Поэтому я пытаюсь использовать генетический алгоритм для обучения и оценки нескольких архитектур NN, поэтому мне нужно распараллелить их на многоядерном процессоре. Поэтому я использовал joblib, чтобы попытаться распараллелить это. Однако я застрял в коде tf.keras, потому что его нельзя было мариновать. После многих часов отладки я наконец понял, что модели tf.keras нельзя мариновать, а модели keras - нет.

Опишите текущее поведение
Приведенный ниже код работает, но если вы замените keras на tf.keras, возникнет ошибка:
Не удалось засолить задачу отправить в рабочие.

Опишите ожидаемое поведение
Двигаясь вперед, tf.keras должен заменить keras, и поэтому tf.keras также должны быть маринованными.

Код для воспроизведения проблемы

#The following is a simple code to illustrate the problem:
from joblib import Parallel, delayed
import keras
import tensorflow as tf

def test():
    model = keras.models.Sequential()
    return

Parallel(n_jobs=8)(delayed(test)(i) for i in range(10)) #this works as intended

def test_tf():
    model = tf.keras.models.Sequential()
    return

Parallel(n_jobs=8)(delayed(test_tf)(i) for i in range(10)) #this will spit out the error above

Другие комментарии
Я предполагаю, что быстрое исправление было бы просто заменить весь существующий код с tf.keras на просто keras, но, поскольку поддержка keras будет прекращена и поглощена Tensorflow 2.0, я думаю, что это должно быть исправлено.

TF 2.2 keras awaiting tensorflower bug

Самый полезный комментарий

Вот альтернатива ответу @epetrovski , не требующая сохранения в файл:

import pickle

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense
from tensorflow.python.keras.layers import deserialize, serialize
from tensorflow.python.keras.saving import saving_utils


def unpack(model, training_config, weights):
    restored_model = deserialize(model)
    if training_config is not None:
        restored_model.compile(
            **saving_utils.compile_args_from_training_config(
                training_config
            )
        )
    restored_model.set_weights(weights)
    return restored_model

# Hotfix function
def make_keras_picklable():

    def __reduce__(self):
        model_metadata = saving_utils.model_metadata(self)
        training_config = model_metadata.get("training_config", None)
        model = serialize(self)
        weights = self.get_weights()
        return (unpack, (model, training_config, weights))

    cls = Model
    cls.__reduce__ = __reduce__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

Источник: https://docs.python.org/3/library/pickle.html#object.__reduce__

Я чувствую, что это можно было бы добавить в Модель? Есть ли случаи, когда это не сработает?

Все 34 Комментарий

@ Edwin-Koh1

Не могли бы вы проверить ночную версию ( !pip install tf-nightly==2.1.0dev20191201 ) и посмотреть, сохраняется ли ошибка. В последних ночных версиях значительно улучшена производительность. Благодаря!

Автоматически закрывается из-за отсутствия активности в последнее время. Обновите проблему, когда станет доступна новая информация, и мы повторно откроем ее. Благодаря!

@ravikyram Я все еще вижу эту проблему в tensorflow == 2.1.0:

import pickle

import tensorflow as tf


def main():
    model_1 = tf.keras.Sequential((
        tf.keras.layers.Dense(16, activation='relu'),
        tf.keras.layers.Dense(1, activation='linear'),
    ))

    _ = model_1(tf.random.uniform((15, 3)))

    model_2 = pickle.loads(pickle.dumps(model_1))

    for w1, w2 in zip(model_1.get_weights(), model_2.get_weights()):
        tf.debugging.assert_equal(w1, w2)


if __name__ == '__main__':
    main()

приводит к

Traceback (most recent call last):
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_model.py", line 25, in <module>
    main()
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_model.py", line 18, in main
    model_2 = pickle.loads(pickle.dumps(model_1))
TypeError: can't pickle weakref objects
$ pip freeze | grep "tf\|tensor"
tensorboard==2.1.0
tensorflow==2.1.0
tensorflow-estimator==2.1.0
tensorflow-probability==0.9.0
$ python --version
Python 3.7.5

Я пробовал использовать colab с TF версии 2.1.0-rc2, 2.2.0-dev20200113 и смог воспроизвести проблему. Пожалуйста, найдите суть здесь . Благодаря!

@ravikyram , функциональные модели keras тоже должны быть травимыми или нет? Я бы предположил, что если последовательные модели являются, то функциональные модели тоже должны быть? Или функциональные модели обладают некоторыми свойствами, из-за которых их сложнее мариновать?

$ python -m tests.test_pickle_keras_functional_model
2020-01-17 16:47:08.567598: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-01-17 16:47:08.581327: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fa0a55aa6c0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-01-17 16:47:08.581362: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Traceback (most recent call last):
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/hartikainen/conda/envs/softlearning-3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_functional_model.py", line 20, in <module>
    main()
  File "/Users/hartikainen/github/rail-berkeley/softlearning-3/tests/test_pickle_keras_functional_model.py", line 13, in main
    model_2 = pickle.loads(pickle.dumps(model_1))
TypeError: can't pickle _thread.RLock objects

Всем привет,
Я пытаюсь переключиться с автономного keras на tensorflow.keras в соответствии с рекомендацией на https://keras.io/.
Я попал в то же исключение, что и https://github.com/tensorflow/tensorflow/issues/34697#issuecomment -575705599 с joblib (который использует pickle под капотом).

Системная информация:

  • Debian 10 (прерыватель)
  • Python 3.7.6
  • joblib 0.14.1
  • тензор потока 2.1.0

Скрипт для воспроизведения:

import joblib
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
joblib.dump(model, 'model.pkl')

Вывод:

TypeError: can't pickle _thread.RLock objects

Вот исправление, адаптированное из http://zachmoshe.com/2017/04/03/pickling-keras-models.html, предназначенное для решения той же проблемы, когда раньше модели Keras не поддавались маринованию.

import pickle
import tempfile
from tensorflow.keras.models import Sequential, load_model, save_model, Model
from tensorflow.keras.layers import Dense

# Hotfix function
def make_keras_picklable():
    def __getstate__(self):
        model_str = ""
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            save_model(self, fd.name, overwrite=True)
            model_str = fd.read()
        d = {'model_str': model_str}
        return d

    def __setstate__(self, state):
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            fd.write(state['model_str'])
            fd.flush()
            model = load_model(fd.name)
        self.__dict__ = model.__dict__


    cls = Model
    cls.__getstate__ = __getstate__
    cls.__setstate__ = __setstate__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

@epetrovski Должен ли я вызывать этот код всякий раз, когда я собираюсь мариновать модель, или я могу просто вызвать его в начале моего приложения (перед созданием модели)?

@epetrovski Должен ли я вызывать этот код всякий раз, когда я собираюсь мариновать модель, или я могу просто вызвать его в начале моего приложения (перед созданием модели)?

Вы можете просто вызвать его один раз в начале вашего приложения после импорта tensorflow.keras.models.Model . Выполнение функции добавляет два новых метода __getstate__() и __setstate__() к классу tensorflow.keras.models.Model поэтому он должен работать каждый раз, когда вы хотите обработать член обновленного класса модели tf.keras - т.е. ваша собственная модель.

Вот альтернатива ответу @epetrovski , не требующая сохранения в файл:

import pickle

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense
from tensorflow.python.keras.layers import deserialize, serialize
from tensorflow.python.keras.saving import saving_utils


def unpack(model, training_config, weights):
    restored_model = deserialize(model)
    if training_config is not None:
        restored_model.compile(
            **saving_utils.compile_args_from_training_config(
                training_config
            )
        )
    restored_model.set_weights(weights)
    return restored_model

# Hotfix function
def make_keras_picklable():

    def __reduce__(self):
        model_metadata = saving_utils.model_metadata(self)
        training_config = model_metadata.get("training_config", None)
        model = serialize(self)
        weights = self.get_weights()
        return (unpack, (model, training_config, weights))

    cls = Model
    cls.__reduce__ = __reduce__

# Run the function
make_keras_picklable()

# Create the model
model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])

# Save
with open('model.pkl', 'wb') as f:
    pickle.dump(model, f)

Источник: https://docs.python.org/3/library/pickle.html#object.__reduce__

Я чувствую, что это можно было бы добавить в Модель? Есть ли случаи, когда это не сработает?

Кажется, что есть два атрибута, которые нельзя выбрать в классе Sequential. Это исправление также сработало для меня:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

class PickableSequential(Sequential):
    def __getstate__(self):
        state = super().__getstate__()
        state.pop("_trackable_saver")
        state.pop("_compiled_trainable_state")
        return state

model = PickableSequential(Dense(10))

import pickle

pickle.dumps(model)
~                     

Я пробовал использовать colab с TF версии 2.2, ночные версии и смог воспроизвести проблему. Пожалуйста, найдите суть здесь. Спасибо!

Я пробовал использовать colab с TF версии 2.2, ночные версии и смог воспроизвести проблему. Пожалуйста, найдите суть здесь. Спасибо!

Модель keras выбирается, но tf.keras не выбирается, поэтому альтернативное решение для этого - см. приведенный ниже код: -
Я увидел вашу записную книжку Colab и внес необходимые изменения, просто скопируйте тот же код, что и ниже, и вы закончите с устранением ошибки

импортировать тензорный поток как tf

def main ():
model_1 = tf.keras.Sequential ((
tf.keras.layers.Dense (16, Activation = 'relu'),
tf.keras.layers.Dense (1, Activation = 'linear'),
))

_ = model_1(tf.random.uniform((15, 3)))
model_1.save('model_2.h5')
model_2 = tf.keras.models.load_model('model_2.h5')

for w1, w2 in zip(model_1.get_weights(), model_2.get_weights()):
    tf.debugging.assert_equal(w1, w2)

если __name__ == '__main__':
главный()

@ Edwin-Koh1

Согласно предложению @lahsrahtidnap, я пробовал использовать colab и не вижу никаких проблем. Пожалуйста, найдите суть здесь. Спасибо!

Всем привет,
Я пытаюсь переключиться с автономного keras на tensorflow.keras в соответствии с рекомендацией на https://keras.io/.
Я попал в то же исключение, что и # 34697 (комментарий) с joblib (который использует pickle под капотом).

Системная информация:

  • Debian 10 (прерыватель)
  • Python 3.7.6
  • joblib 0.14.1
  • тензор потока 2.1.0

Скрипт для воспроизведения:

import joblib
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()
model.add(Dense(1, input_dim=42, activation='sigmoid'))
model.compile(optimizer='Nadam', loss='binary_crossentropy', metrics=['accuracy'])
joblib.dump(model, 'model.pkl')

Вывод:

TypeError: can't pickle _thread.RLock objects

Использование pickle или joblib не решит вашу проблему, поскольку tensorflow.keras этого не поддерживает.
Итак, альтернативное решение для этого: -

учитывая ваш код: -
замените эту строку: - joblib.dump (model, 'model.pkl')
с участием: -
для сохранения модели используйте: -
-----> model.save ('new_model.h5')
и если вы хотите загрузить эту модель, используйте: -
-----> новая_модель = tf.keras.models.load_model ('новая_модель.h5')

учитывая ваш код: -
замените эту строку: - joblib.dump (model, 'model.pkl')
с участием: -
для сохранения модели используйте: -
-----> model.save ('new_model.h5')
и если вы хотите загрузить эту модель, используйте: -
-----> новая_модель = tf.keras.models.load_model ('новая_модель.h5')

В некоторых случаях это работает, однако не помогает, когда модель обрабатывается как часть другой функции, в моем случае это происходит при использовании библиотеки python multiprocessing .

@ Edwin-Koh1

Это все еще проблема?
Подтвердите, спасибо!

Можно ли сбросить последовательную модель Keras в контейнер byteIO

bytes_container = BytesIO()
joblib.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle _thread.RLock objects

pickle.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle _thread.RLock objects

dill.dump(Keras_model, bytes_container, protocol=4)
# Error
TypeError: can't pickle tensorflow.python._tf_stack.StackSummary objects

или во временном файле

tempfile.TemporaryFile().write(Keras_model)

или же

save_model(Keras_model, bytes_container)
# Error
TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO

Это сработало отлично, ну, возможно, вам не понадобится base64, чтобы я мог хранить в базе данных, которую я сделал, все в памяти, без касания диска

from io import BytesIO
import dill,base64,tempfile

#Saving Model as base64
model_json = Keras_model.to_json()

def Base64Converter(ObjectFile):
    bytes_container = BytesIO()
    dill.dump(ObjectFile, bytes_container)
    bytes_container.seek(0)
    bytes_file = bytes_container.read()
    base64File = base64.b64encode(bytes_file)
    return base64File

base64KModelJson = Base64Converter(model_json)  
base64KModelJsonWeights = Base64Converter(Keras_model.get_weights())  

#Loading Back
from joblib import load
from keras.models import model_from_json
def ObjectConverter(base64_File):
    loaded_binary = base64.b64decode(base64_File)
    loaded_object = tempfile.TemporaryFile()
    loaded_object.write(loaded_binary)
    loaded_object.seek(0)
    ObjectFile = load(loaded_object)
    loaded_object.close()
    return ObjectFile

modeljson = ObjectConverter(base64KModelJson)
modelweights = ObjectConverter(base64KModelJsonWeights)
loaded_model = model_from_json(modeljson)
loaded_model.set_weights(modelweights)

@hanzigs
Хорошее решение, спасибо. Только будьте осторожны, если планируете продолжить обучение этой модели, так как этот метод не сохраняет состояние оптимизатора.

@JohannesAck
Да, мы должны скомпилировать с оптимизатором, прежде чем соответствовать новым данным, это не должно занимать много времени,

С другой стороны, model.save очень сложно хранить в памяти.

Другой способ - мы можем выполнить get_config () и from_config () с инициализацией и компиляцией, после чего необходимо выполнить подгонку для новых данных.

@ Edwin-Koh1

Любые обновления по этому вопросу, пожалуйста. Спасибо!

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

учитывая ваш код: -
замените эту строку: - joblib.dump (model, 'model.pkl')
с участием: -
для сохранения модели используйте: -
-----> model.save ('new_model.h5')
и если вы хотите загрузить эту модель, используйте: -
-----> новая_модель = tf.keras.models.load_model ('новая_модель.h5')

В некоторых случаях это работает, однако не помогает, когда модель обрабатывается как часть другой функции, в моем случае это происходит при использовании библиотеки python multiprocessing .

@JohannesAck , я думаю, у меня может быть похожая проблема. Я обучаю модель Keras на графическом процессоре, сохраняю ее в формате TensorFlow SavedModel с помощью Keras API, перезагружаю ее в новом сеансе и пытаюсь делать прогнозы параллельно на нескольких процессорах с помощью библиотеки multiprocessing и starmap функция. Если я загружаю модель перед распараллеливанием прогнозов, я получаю ошибку травления ( TypeError: can't pickle _thread.RLock objects ). Если я загружаю модель в свою функцию прогнозирования каждый раз и удаляю ее в конце каждого вызова функции, она зависает после нескольких прогнозов. Ты хоть представляешь, что здесь может происходить?

Закрытие как устаревшее. Пожалуйста, откройте снова, если вы хотите продолжить работу над этим.

Довольны ли вы решением вашей проблемы?
да
Нет

Насколько я знаю, он не устарел.

Во вторник, 25 августа 2020 г., 5:26 tenorflow-butler [bot] <
[email protected]> написал:

Довольны ли вы решением вашей проблемы?
да
https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=Yes&entry.2137816233=https://githues.com/tens69/github.com/
Нет
https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=No&entry.2137816233=https://github.com/tens69/github.com/

-
Вы получили это, потому что оставили комментарий.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/tensorflow/tensorflow/issues/34697#issuecomment-679941192 ,
или отказаться от подписки
https://github.com/notifications/unsubscribe-auth/AANMPP2EF3PRKBYRYHOHY3TSCOGTXANCNFSM4JSZ4QSA
.

Это WONTFIX после того, как проблема была закрыта?

В моем случае я не могу просто использовать model.save() потому что травление выполняется из внешнего инструмента, для которого мой код просто предоставляет модель, совместимую с scikit-learn (мой класс предоставляет метод get_clf ). Я мог бы обойти проблему, поскольку мой код был (почти) Keras-совместимым (не tf.keras), а с Keras 2.3.1 (TF 1.15.0) травление работает без проблем.

@mimxrt, если вы хотите использовать модели Keras в среде scikit-learn, ознакомьтесь с SciKeras (полное раскрытие: я являюсь автором). Если вы просто ищете способ сделать объекты Keras доступными для выбора, проверьте https://github.com/tensorflow/tensorflow/pull/39609 и, в частности, https://github.com/tensorflow/tensorflow/pull/39609#issuecomment -683370566

Изменить: фиксированная ссылка

Мы не ведем активной работы над этим прямо сейчас, но возобновляем работу, так как это все еще проблема.

Закрытие как устаревшее. Пожалуйста, откройте снова, если вы хотите продолжить работу над этим.

Довольны ли вы решением вашей проблемы?
да
Нет

Это снова остановится.

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги