Tensorflow: Model keras dapat dibuat acar tetapi model tf.keras tidak dapat dibuat acar

Dibuat pada 29 Nov 2019  ·  34Komentar  ·  Sumber: tensorflow/tensorflow

Sistem Informasi

  • Windows 10
  • Tensorflow 2.0 (CPU)
  • joblib 0.14.0.0
  • Python 3.7.5
  • Keras 2.3.1

Halo semua! Ini adalah posting pertama saya jadi mohon maafkan saya jika saya melewatkan sesuatu. Jadi saya mencoba menggunakan algoritma genetika untuk melatih dan mengevaluasi beberapa arsitektur NN, jadi saya perlu memparalelkannya pada CPU multi-core. Oleh karena itu saya telah menggunakan joblib untuk mencoba memparalelkan ini. Namun, saya terjebak pada kode tf.keras saya karena tidak bisa dijadikan acar. Setelah berjam-jam debugging, saya akhirnya menyadari bahwa model tf.keras tidak dapat diawetkan sedangkan model keras.

Jelaskan perilaku saat ini
Kode di bawah ini berfungsi tetapi jika Anda mengganti keras dengan tf.keras, akan ada kesalahan:
Tidak dapat membuat acar tugas untuk dikirim ke pekerja.

Jelaskan perilaku yang diharapkan
Ke depan, tf.keras harus menggantikan keras dan oleh karena itu tf.keras juga harus menjadi acar.

Kode untuk mereproduksi masalah

#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

Komentar lain
Saya kira perbaikan cepat hanya akan mengganti semua kode yang ada dengan tf.keras menjadi hanya keras tetapi karena dukungan keras akan dihentikan dan diserap oleh Tensorflow 2.0, saya pikir ini harus diperbaiki.

TF 2.2 keras awaiting tensorflower bug

Komentar yang paling membantu

Berikut adalah alternatif jawaban @epetrovski yang tidak memerlukan penyimpanan ke file:

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)

Sumber: https://docs.python.org/3/library/pickle.html#object.__reduce__

Saya merasa mungkin ini bisa ditambahkan ke Model? Apakah ada kasus dimana ini tidak akan berhasil?

Semua 34 komentar

@ Edwin-Koh

Bisakah Anda memeriksa dengan versi nightly ( !pip install tf-nightly==2.1.0dev20191201 ) dan melihat apakah kesalahan masih berlanjut. Ada banyak peningkatan kinerja dalam versi nightly terbaru. Terima kasih!

Tutup otomatis karena kurangnya aktivitas baru-baru ini. Perbarui masalah saat informasi baru tersedia, dan kami akan membuka kembali masalah tersebut. Terima kasih!

@ravikyram Saya masih melihat masalah ini di 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()

menghasilkan

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

Saya telah mencoba colab dengan TF versi 2.1.0-rc2, 2.2.0-dev20200113 dan dapat mereproduksi masalah tersebut. Temukan intinya di sini . Terima kasih!

@ravikyram , haruskah model keras fungsional juga bisa di-picklable? Saya akan berasumsi jika model Sequential kemudian model fungsional juga harus? Atau apakah model fungsional memiliki beberapa sifat yang membuatnya lebih sulit untuk dijadikan acar?

$ 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

Halo semuanya,
Saya mencoba untuk beralih dari mandiri keras menjadi tensorflow.keras sesuai rekomendasi di https://keras.io/.
Saya mendapatkan pengecualian yang sama seperti https://github.com/tensorflow/tensorflow/issues/34697#issuecomment -575705599 dengan joblib (yang menggunakan pickle bawah tenda).

Sistem Informasi:

  • Debian 10 (buster)
  • Python 3.7.6
  • joblib 0.14.1
  • tensorflow 2.1.0

Script untuk direproduksi:

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')

Keluaran:

TypeError: can't pickle _thread.RLock objects

Berikut ini perbaikan yang diadaptasi dari http://zachmoshe.com/2017/04/03/pickling-keras-models.html dimaksudkan untuk memecahkan masalah yang sama saat model Keras dulu tidak dapat dijadikan acar.

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 Haruskah saya memanggil kode ini setiap kali saya akan membuat acar model atau dapatkah saya menyebutnya di awal aplikasi saya (sebelum membuat model)?

@epetrovski Haruskah saya memanggil kode ini setiap kali saya akan membuat acar model atau dapatkah saya menyebutnya di awal aplikasi saya (sebelum membuat model)?

Anda pasti dapat memanggilnya sekali di awal aplikasi Anda setelah mengimpor tensorflow.keras.models.Model . Menjalankan fungsi menambahkan dua metode baru __getstate__() dan __setstate__() ke kelas tensorflow.keras.models.Model sehingga harus bekerja setiap kali Anda ingin membuat acar anggota kelas Model tf.keras yang diperbarui - yaitu. model Anda sendiri.

Berikut adalah alternatif jawaban @epetrovski yang tidak memerlukan penyimpanan ke file:

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)

Sumber: https://docs.python.org/3/library/pickle.html#object.__reduce__

Saya merasa mungkin ini bisa ditambahkan ke Model? Apakah ada kasus dimana ini tidak akan berhasil?

Sepertinya ada dua atribut yang tidak bisa dipilih di kelas Sequential. Perbaikan ini juga berhasil untuk saya:

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)
~                     

Saya telah mencoba di colab dengan TF versi 2.2, versi nightly dan dapat mereproduksi masalah tersebut. Silakan, temukan intinya di sini. Terima kasih!

Saya telah mencoba di colab dengan TF versi 2.2, versi nightly dan dapat mereproduksi masalah tersebut. Silakan, temukan intinya di sini. Terima kasih!

model keras dapat dipilih tetapi tf.keras tidak dapat dipilih, jadi solusi alternatif untuk ini adalah merujuk kode di bawah ini
Saya melihat notebook colab Anda dan membuat perubahan yang diperlukan cukup salin kode yang sama seperti di bawah ini dan Anda selesai dengan menyelesaikan kesalahan

impor tensorflow sebagai 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)

jika __name__ == '__main__':
utama()

@ Edwin-Koh

Sesuai saran dari @lahsrahtidnap saya telah mencoba di colab dan saya tidak melihat masalah apa pun. Silakan, temukan intinya di sini. Terima kasih!

Halo semuanya,
Saya mencoba untuk beralih dari mandiri keras menjadi tensorflow.keras sesuai rekomendasi di https://keras.io/.
Saya mendapatkan pengecualian yang sama seperti # 34697 (komentar) dengan joblib (yang menggunakan pickle bawah tenda).

Sistem Informasi:

  • Debian 10 (buster)
  • Python 3.7.6
  • joblib 0.14.1
  • tensorflow 2.1.0

Script untuk direproduksi:

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')

Keluaran:

TypeError: can't pickle _thread.RLock objects

Menggunakan acar atau joblib tidak akan menyelesaikan masalah Anda karena tensorflow.keras tidak mendukung ini.
Jadi solusi alternatif untuk ini adalah: -

mempertimbangkan kode Anda: -
ganti baris ini: - joblib.dump (model, 'model.pkl')
dengan: -
untuk menghemat penggunaan model: -
-----> model.save ('new_model.h5')
dan jika Anda ingin memuat model ini, gunakan: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

mempertimbangkan kode Anda: -
ganti baris ini: - joblib.dump (model, 'model.pkl')
dengan: -
untuk menghemat penggunaan model: -
-----> model.save ('new_model.h5')
dan jika Anda ingin memuat model ini, gunakan: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

Ini berfungsi dalam beberapa kasus, namun, itu tidak membantu ketika model diawetkan sebagai bagian dari fungsi lain, dalam kasus saya ini terjadi saat menggunakan pustaka python multiprocessing .

@ Edwin-Koh

Apakah ini masih menjadi masalah?
Mohon konfirmasi. Terima kasih!

Apakah mungkin untuk membuang Model Sekuensial Keras dalam wadah 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

atau di tempfile

tempfile.TemporaryFile().write(Keras_model)

atau

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

Ini bekerja dengan sempurna, Anda mungkin tidak perlu base64, untuk saya simpan di database yang saya lakukan, semua yang ada di memori, tidak ada disk yang menyentuh

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)

@hanifah
Ini solusi yang bagus, terima kasih. Berhati-hatilah jika Anda berencana untuk terus melatih model ini, karena metode ini tidak mempertahankan status pengoptimal.

@Johnny
Ya, kami harus mengkompilasi dengan pengoptimal sebelum melakukan fit dengan data baru, yang seharusnya tidak memakan waktu,

Cara lain model.save sangat sulit untuk disimpan dalam memori.

Cara lain adalah kita bisa melakukan get_config () dan from_config () dengan inisialisasi dan kompilasi kemudian fit harus dilakukan untuk data baru.

@ Edwin-Koh

Setiap pembaruan tentang masalah ini, terima kasih!

Masalah ini secara otomatis ditandai sebagai usang karena tidak ada aktivitas terbaru. Ini akan ditutup jika tidak ada aktivitas lebih lanjut. Terima kasih.

mempertimbangkan kode Anda: -
ganti baris ini: - joblib.dump (model, 'model.pkl')
dengan: -
untuk menghemat penggunaan model: -
-----> model.save ('new_model.h5')
dan jika Anda ingin memuat model ini, gunakan: -
-----> new_model = tf.keras.models.load_model ('new_model.h5')

Ini berfungsi dalam beberapa kasus, namun, itu tidak membantu ketika model diawetkan sebagai bagian dari fungsi lain, dalam kasus saya ini terjadi saat menggunakan pustaka python multiprocessing .

@JohannesAck , saya pikir saya mungkin memiliki masalah serupa. Saya melatih model Keras di GPU, menyimpannya menggunakan format TensorFlow SavedModel menggunakan API Keras, memuatnya kembali di sesi baru dan mencoba membuat prediksi secara paralel di beberapa CPU menggunakan library multiprocessing dan starmap fungsi. Jika saya memuat model sebelum memparalelkan prediksi, saya mendapatkan kesalahan pengawetan ( TypeError: can't pickle _thread.RLock objects ). Jika saya memuat model dalam fungsi prediksi saya setiap kali dan menghapusnya di akhir setiap fungsi, panggilan akan macet setelah beberapa prediksi. Apakah Anda tahu apa yang mungkin terjadi di sini?

Menutup sebagai basi. Harap buka kembali jika Anda ingin menangani ini lebih lanjut.

Apakah Anda puas dengan penyelesaian masalah Anda?
Iya
Tidak

Apakah ini WONTFIX setelah masalah ditutup sekarang?

Dalam kasus saya, saya tidak bisa begitu saja menggunakan model.save() karena pengawetan dilakukan dari alat eksternal yang kode saya hanya menyediakan model yang kompatibel dengan scikit-learn (kelas saya menyediakan metode get_clf ). Saya dapat mengatasi masalah ini karena kode saya (hampir) kompatibel dengan Keras (bukan tf.keras), dan dengan pengawetan Keras 2.3.1 (TF 1.15.0) bekerja tanpa masalah.

@mimxrt jika Anda ingin menggunakan model Keras dalam scikit-learn env, silakan lihat SciKeras (pengungkapan lengkap: Saya penulisnya). Jika Anda hanya mencari cara untuk membuat objek Keras dapat dipilih, periksa https://github.com/tensorflow/tensorflow/pull/39609 dan khususnya https://github.com/tensorflow/tensorflow/pull/39609#issuecomment -683370566

Edit: tautan tetap

Kami tidak sedang mengerjakannya secara aktif sekarang, tetapi membuka kembali karena masih menjadi masalah.

Menutup sebagai basi. Harap buka kembali jika Anda ingin menangani ini lebih lanjut.

Apakah Anda puas dengan penyelesaian masalah Anda?
Iya
Tidak

Ini akan terhenti lagi.

Masalah ini secara otomatis ditandai sebagai usang karena tidak ada aktivitas terbaru. Ini akan ditutup jika tidak ada aktivitas lebih lanjut. Terima kasih.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat