Google I/O adalah bungkusnya! Ikuti sesi TensorFlow Lihat sesi

Simpan dan muat model Keras

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

pengantar

Model Keras terdiri dari beberapa komponen:

  • Arsitektur, atau konfigurasi, yang menentukan lapisan apa yang terdapat dalam model, dan bagaimana mereka terhubung.
  • Satu set nilai bobot ("status model").
  • Pengoptimal (didefinisikan dengan mengkompilasi model).
  • Satu set kerugian dan metrik (didefinisikan oleh kompilasi model atau menelepon add_loss() atau add_metric() ).

Keras API memungkinkan untuk menyimpan semua bagian ini ke disk sekaligus, atau hanya secara selektif menyimpan beberapa di antaranya:

  • Menyimpan semuanya ke dalam satu arsip dalam format TensorFlow SavedModel (atau dalam format Keras H5) yang lebih lama. Ini adalah praktik standar.
  • Menyimpan arsitektur/konfigurasi saja, biasanya sebagai file JSON.
  • Menyimpan nilai bobot saja. Ini biasanya digunakan saat melatih model.

Mari kita lihat masing-masing opsi ini. Kapan Anda akan menggunakan satu atau yang lain, dan bagaimana cara kerjanya?

Bagaimana cara menyimpan dan memuat model

Jika Anda hanya memiliki 10 detik untuk membaca panduan ini, inilah yang perlu Anda ketahui.

Menyimpan model Keras:

model = ...  # Get model (Sequential, Functional Model, or Model subclass)
model.save('path/to/location')

Memuat kembali model:

from tensorflow import keras
model = keras.models.load_model('path/to/location')

Sekarang, mari kita lihat detailnya.

Mempersiapkan

import numpy as np
import tensorflow as tf
from tensorflow import keras

Penyimpanan & pemuatan seluruh model

Anda dapat menyimpan seluruh model ke satu artefak. Ini akan mencakup:

  • Arsitektur/konfigurasi model
  • Nilai bobot model (yang dipelajari selama pelatihan)
  • Informasi kompilasi model (jika compile() dipanggil)
  • Pengoptimal dan statusnya, jika ada (ini memungkinkan Anda untuk memulai kembali pelatihan di tempat yang Anda tinggalkan)

Lebah

Ada dua format yang dapat digunakan untuk menyimpan seluruh model ke disk: format TensorFlow SavedModel, dan lebih tua format yang Keras H5. Format yang disarankan adalah SavedModel. Ini adalah default ketika Anda menggunakan model.save() .

Anda dapat beralih ke format H5 dengan:

  • Melewati save_format='h5' untuk save() .
  • Melewati nama file yang berakhir di .h5 atau .keras untuk save() .

Format Model Tersimpan

SavedModel adalah format penyimpanan yang lebih komprehensif yang menyimpan arsitektur model, bobot, dan subgraf Tensorflow yang dilacak dari fungsi panggilan. Ini memungkinkan Keras untuk memulihkan baik lapisan bawaan maupun objek khusus.

Contoh:

def get_model():
    # Create a simple model.
    inputs = keras.Input(shape=(32,))
    outputs = keras.layers.Dense(1)(inputs)
    model = keras.Model(inputs, outputs)
    model.compile(optimizer="adam", loss="mean_squared_error")
    return model


model = get_model()

# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)

# Calling `save('my_model')` creates a SavedModel folder `my_model`.
model.save("my_model")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_model")

# Let's check:
np.testing.assert_allclose(
    model.predict(test_input), reconstructed_model.predict(test_input)
)

# The reconstructed model is already compiled and has retained the optimizer
# state, so training can resume:
reconstructed_model.fit(test_input, test_target)
4/4 [==============================] - 1s 2ms/step - loss: 0.5884
2021-08-25 17:49:05.320893: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: my_model/assets
4/4 [==============================] - 0s 2ms/step - loss: 0.5197
<keras.callbacks.History at 0x7f99486ad490>

Apa yang terkandung dalam Model Tersimpan

Memanggil model.save('my_model') membuat folder bernama my_model , yang berisi hal berikut:

ls my_model
assets  keras_metadata.pb  saved_model.pb  variables

Arsitektur model, dan konfigurasi pelatihan (termasuk optimizer, kerugian, dan metrik) disimpan dalam saved_model.pb . Bobot disimpan dalam variables/ direktori.

Untuk informasi rinci tentang format SavedModel, lihat panduan SavedModel (Format SavedModel pada disk) .

Bagaimana SavedModel menangani objek khusus

Saat menyimpan model dan lapisan nya, SavedModel format yang menyimpan nama kelas, fungsi panggilan, kerugian, dan berat (dan konfigurasi, jika diterapkan). Fungsi panggilan mendefinisikan grafik komputasi model/lapisan.

Dengan tidak adanya konfigurasi model/lapisan, fungsi panggilan digunakan untuk membuat model yang ada seperti model asli yang dapat dilatih, dievaluasi, dan digunakan untuk inferensi.

Namun demikian, itu selalu merupakan praktik yang baik untuk menentukan get_config dan from_config metode saat menulis model kustom atau kelas lapisan. Ini memungkinkan Anda untuk dengan mudah memperbarui perhitungan nanti jika diperlukan. Lihat bagian tentang obyek Kustom untuk informasi lebih lanjut.

Contoh:

class CustomModel(keras.Model):
    def __init__(self, hidden_units):
        super(CustomModel, self).__init__()
        self.hidden_units = hidden_units
        self.dense_layers = [keras.layers.Dense(u) for u in hidden_units]

    def call(self, inputs):
        x = inputs
        for layer in self.dense_layers:
            x = layer(x)
        return x

    def get_config(self):
        return {"hidden_units": self.hidden_units}

    @classmethod
    def from_config(cls, config):
        return cls(**config)


model = CustomModel([16, 16, 10])
# Build the model by calling it
input_arr = tf.random.uniform((1, 5))
outputs = model(input_arr)
model.save("my_model")

# Option 1: Load with the custom_object argument.
loaded_1 = keras.models.load_model(
    "my_model", custom_objects={"CustomModel": CustomModel}
)

# Option 2: Load without the CustomModel class.

# Delete the custom-defined model class to ensure that the loader does not have
# access to it.
del CustomModel

loaded_2 = keras.models.load_model("my_model")
np.testing.assert_allclose(loaded_1(input_arr), outputs)
np.testing.assert_allclose(loaded_2(input_arr), outputs)

print("Original model:", model)
print("Model Loaded with custom objects:", loaded_1)
print("Model loaded without the custom object class:", loaded_2)
INFO:tensorflow:Assets written to: my_model/assets
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
Original model: <__main__.CustomModel object at 0x7f9949c86810>
Model Loaded with custom objects: <__main__.CustomModel object at 0x7f99681f61d0>
Model loaded without the custom object class: <keras.saving.saved_model.load.CustomModel object at 0x7f9aaceefd10>

Model dimuat pertama dimuat menggunakan config dan CustomModel kelas. Model kedua dimuat dengan secara dinamis membuat kelas model yang bertindak seperti model aslinya.

Mengonfigurasi Model Tersimpan

Baru di TensoFlow 2.4 Argumen save_traces telah ditambahkan ke model.save , yang memungkinkan Anda untuk beralih SavedModel fungsi tracing. Fungsi disimpan untuk memungkinkan Keras untuk re-beban objek kustom tanpa definitons kelas yang asli, jadi ketika save_traces=False , semua benda adat harus didefinisikan get_config / from_config metode. Ketika loading, objek kustom harus diteruskan ke custom_objects argumen. save_traces=False mengurangi ruang disk yang digunakan oleh SavedModel dan menghemat waktu.

Format Keras H5

Keras juga mendukung menyimpan file HDF5 yang berisi arsitektur model, nilai-nilai bobot, dan compile() informasi. Ini adalah alternatif ringan untuk SavedModel.

Contoh:

model = get_model()

# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)

# Calling `save('my_model.h5')` creates a h5 file `my_model.h5`.
model.save("my_h5_model.h5")

# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_h5_model.h5")

# Let's check:
np.testing.assert_allclose(
    model.predict(test_input), reconstructed_model.predict(test_input)
)

# The reconstructed model is already compiled and has retained the optimizer
# state, so training can resume:
reconstructed_model.fit(test_input, test_target)
4/4 [==============================] - 0s 1ms/step - loss: 1.6322
4/4 [==============================] - 0s 1ms/step - loss: 1.4790
<keras.callbacks.History at 0x7f9aacc0fd50>

Keterbatasan

Dibandingkan dengan format SavedModel, ada dua hal yang tidak disertakan dalam file H5:

  • Eksternal kerugian & metrik ditambahkan melalui model.add_loss() & model.add_metric() tidak disimpan (tidak seperti SavedModel). Jika Anda memiliki kerugian & metrik seperti itu pada model Anda dan Anda ingin melanjutkan pelatihan, Anda perlu menambahkan kembali kerugian ini sendiri setelah memuat model. Perhatikan bahwa ini tidak berlaku untuk kerugian / metrik dibuat di dalam lapisan via self.add_loss() & self.add_metric() . Selama lapisan akan dimuat, kerugian ini & metrik disimpan, karena mereka adalah bagian dari call metode lapisan.
  • Grafik Perhitungan kustom objek seperti lapisan kustom tidak termasuk dalam file yang disimpan. Saat memuat, Keras akan membutuhkan akses ke kelas/fungsi Python dari objek ini untuk merekonstruksi model. Lihat objek kustom .

Menyimpan arsitektur

Konfigurasi model (atau arsitektur) menentukan lapisan apa yang dikandung model, dan bagaimana lapisan ini terhubung*. Jika Anda memiliki konfigurasi model, maka model dapat dibuat dengan status yang baru diinisialisasi untuk bobot dan tanpa informasi kompilasi.

*Perhatikan bahwa ini hanya berlaku untuk model yang ditentukan menggunakan api fungsional atau api berurutan bukan model yang disubklasifikasikan.

Konfigurasi model Sequential atau model API Fungsional

Jenis model ini adalah grafik lapisan eksplisit: konfigurasinya selalu tersedia dalam bentuk terstruktur.

Lebah

get_config() dan from_config()

Memanggil config = model.get_config() akan mengembalikan dict Python yang berisi konfigurasi model. Model yang sama kemudian dapat direkonstruksi melalui Sequential.from_config(config) (untuk Sequential model) atau Model.from_config(config) (untuk model API Fungsional).

Alur kerja yang sama juga berfungsi untuk semua lapisan serial.

Contoh lapisan:

layer = keras.layers.Dense(3, activation="relu")
layer_config = layer.get_config()
new_layer = keras.layers.Dense.from_config(layer_config)

Contoh model berurutan:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
config = model.get_config()
new_model = keras.Sequential.from_config(config)

Contoh model fungsional:

inputs = keras.Input((32,))
outputs = keras.layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)
config = model.get_config()
new_model = keras.Model.from_config(config)

to_json() dan tf.keras.models.model_from_json()

Hal ini mirip dengan get_config / from_config , kecuali ternyata model ke string JSON, yang kemudian dapat dimuat tanpa kelas model asli. Ini juga khusus untuk model, tidak dimaksudkan untuk lapisan.

Contoh:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
json_config = model.to_json()
new_model = keras.models.model_from_json(json_config)

Objek khusus

Model dan lapisan

Arsitektur model subclassed dan lapisan didefinisikan dalam metode __init__ dan call . Mereka dianggap Python bytecode, yang tidak dapat serial menjadi config JSON-kompatibel - Anda bisa mencoba serialisasi bytecode (misalnya melalui pickle ), tapi itu benar-benar tidak aman dan berarti model Anda tidak dapat dimuat pada sistem yang berbeda.

Untuk menghemat / memuat model dengan adat-didefinisikan lapisan, atau model subclassed, Anda harus menimpa get_config dan opsional from_config metode. Selain itu, Anda harus menggunakan register objek kustom sehingga Keras mengetahuinya.

Fungsi kustom

Fungsi-didefinisikan kustom (misalnya hilangnya aktivasi atau inisialisasi) tidak perlu get_config metode. Nama fungsi cukup untuk memuat selama itu terdaftar sebagai objek kustom.

Memuat grafik TensorFlow saja

Dimungkinkan untuk memuat grafik TensorFlow yang dihasilkan oleh Keras. Jika Anda melakukannya, Anda tidak akan perlu memberikan custom_objects . Anda dapat melakukannya seperti ini:

model.save("my_model")
tensorflow_graph = tf.saved_model.load("my_model")
x = np.random.uniform(size=(4, 32)).astype(np.float32)
predicted = tensorflow_graph(x).numpy()
WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.
INFO:tensorflow:Assets written to: my_model/assets

Perhatikan bahwa metode ini memiliki beberapa kelemahan:

  • Untuk alasan keterlacakan, Anda harus selalu memiliki akses ke objek kustom yang digunakan. Anda tidak ingin memasukkan model produksi yang tidak dapat Anda buat ulang.
  • Objek dikembalikan oleh tf.saved_model.load bukan model Keras. Jadi penggunaannya tidak semudah itu. Misalnya, Anda tidak akan memiliki akses ke .predict() atau .fit()

Bahkan jika penggunaannya tidak disarankan, dapat membantu Anda jika Anda berada di tempat yang ketat, misalnya, jika Anda kehilangan kode objek kustom Anda atau memiliki masalah memuat model dengan tf.keras.models.load_model() .

Anda dapat mengetahui lebih lanjut di halaman tentang tf.saved_model.load

Mendefinisikan metode konfigurasi

Spesifikasi:

  • get_config harus kembali kamus JSON-serializable agar kompatibel dengan Keras architecture- dan model hemat API.
  • from_config(config) ( classmethod ) harus kembali lapisan atau model objek baru yang dibuat dari konfigurasi. Implementasi standar pengembalian cls(**config) .

Contoh:

class CustomLayer(keras.layers.Layer):
    def __init__(self, a):
        self.var = tf.Variable(a, name="var_a")

    def call(self, inputs, training=False):
        if training:
            return inputs * self.var
        else:
            return inputs

    def get_config(self):
        return {"a": self.var.numpy()}

    # There's actually no need to define `from_config` here, since returning
    # `cls(**config)` is the default behavior.
    @classmethod
    def from_config(cls, config):
        return cls(**config)


layer = CustomLayer(5)
layer.var.assign(2)

serialized_layer = keras.layers.serialize(layer)
new_layer = keras.layers.deserialize(
    serialized_layer, custom_objects={"CustomLayer": CustomLayer}
)

Mendaftarkan objek khusus

Keras mencatat kelas mana yang menghasilkan konfigurasi. Dari contoh di atas, tf.keras.layers.serialize menghasilkan bentuk serial dari lapisan kustom:

{'class_name': 'CustomLayer', 'config': {'a': 2} }

Keras menyimpan daftar master semua built-in lapisan, model, optimizer, dan kelas metrik, yang digunakan untuk menemukan kelas yang benar untuk panggilan from_config . Jika kelas tidak dapat ditemukan, maka kesalahan dinaikkan ( Value Error: Unknown layer ). Ada beberapa cara untuk mendaftarkan kelas khusus ke daftar ini:

  1. Pengaturan custom_objects argumen dalam fungsi pemuatan. (lihat contoh di bagian di atas "Mendefinisikan metode konfigurasi")
  2. tf.keras.utils.custom_object_scope atau tf.keras.utils.CustomObjectScope
  3. tf.keras.utils.register_keras_serializable

Contoh lapisan dan fungsi khusus

class CustomLayer(keras.layers.Layer):
    def __init__(self, units=32, **kwargs):
        super(CustomLayer, self).__init__(**kwargs)
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

    def get_config(self):
        config = super(CustomLayer, self).get_config()
        config.update({"units": self.units})
        return config


def custom_activation(x):
    return tf.nn.tanh(x) ** 2


# Make a model with the CustomLayer and custom_activation
inputs = keras.Input((32,))
x = CustomLayer(32)(inputs)
outputs = keras.layers.Activation(custom_activation)(x)
model = keras.Model(inputs, outputs)

# Retrieve the config
config = model.get_config()

# At loading time, register the custom objects with a `custom_object_scope`:
custom_objects = {"CustomLayer": CustomLayer, "custom_activation": custom_activation}
with keras.utils.custom_object_scope(custom_objects):
    new_model = keras.Model.from_config(config)

Kloning model dalam memori

Anda juga dapat melakukan in-memory kloning model melalui tf.keras.models.clone_model() . Ini sama dengan mendapatkan konfigurasi kemudian membuat ulang model dari konfigurasinya (sehingga tidak menyimpan informasi kompilasi atau nilai bobot lapisan).

Contoh:

with keras.utils.custom_object_scope(custom_objects):
    new_model = keras.models.clone_model(model)

Menyimpan & memuat hanya nilai bobot model

Anda dapat memilih untuk hanya menyimpan & memuat bobot model. Ini dapat berguna jika:

  • Anda hanya memerlukan model untuk inferensi: dalam hal ini Anda tidak perlu memulai ulang pelatihan, jadi Anda tidak memerlukan informasi kompilasi atau status pengoptimal.
  • Anda sedang melakukan transfer learning: dalam hal ini Anda akan melatih model baru dengan menggunakan kembali keadaan model sebelumnya, jadi Anda tidak memerlukan informasi kompilasi dari model sebelumnya.

API untuk transfer berat dalam memori

Berat dapat disalin antara objek yang berbeda dengan menggunakan get_weights dan set_weights :

Contoh di bawah ini.

Mentransfer bobot dari satu lapisan ke lapisan lain, dalam memori

def create_layer():
    layer = keras.layers.Dense(64, activation="relu", name="dense_2")
    layer.build((None, 784))
    return layer


layer_1 = create_layer()
layer_2 = create_layer()

# Copy weights from layer 1 to layer 2
layer_2.set_weights(layer_1.get_weights())

Mentransfer bobot dari satu model ke model lain dengan arsitektur yang kompatibel, dalam memori

# Create a simple functional model
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

# Define a subclassed model with the same architecture
class SubclassedModel(keras.Model):
    def __init__(self, output_dim, name=None):
        super(SubclassedModel, self).__init__(name=name)
        self.output_dim = output_dim
        self.dense_1 = keras.layers.Dense(64, activation="relu", name="dense_1")
        self.dense_2 = keras.layers.Dense(64, activation="relu", name="dense_2")
        self.dense_3 = keras.layers.Dense(output_dim, name="predictions")

    def call(self, inputs):
        x = self.dense_1(inputs)
        x = self.dense_2(x)
        x = self.dense_3(x)
        return x

    def get_config(self):
        return {"output_dim": self.output_dim, "name": self.name}


subclassed_model = SubclassedModel(10)
# Call the subclassed model once to create the weights.
subclassed_model(tf.ones((1, 784)))

# Copy weights from functional_model to subclassed_model.
subclassed_model.set_weights(functional_model.get_weights())

assert len(functional_model.weights) == len(subclassed_model.weights)
for a, b in zip(functional_model.weights, subclassed_model.weights):
    np.testing.assert_allclose(a.numpy(), b.numpy())

Kasus lapisan tanpa kewarganegaraan

Karena lapisan stateless tidak mengubah urutan atau jumlah bobot, model dapat memiliki arsitektur yang kompatibel bahkan jika ada lapisan stateless tambahan/hilang.

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)

# Add a dropout layer, which does not contain any weights.
x = keras.layers.Dropout(0.5)(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model_with_dropout = keras.Model(
    inputs=inputs, outputs=outputs, name="3_layer_mlp"
)

functional_model_with_dropout.set_weights(functional_model.get_weights())

API untuk menyimpan bobot ke disk & memuatnya kembali

Berat dapat disimpan ke disk dengan memanggil model.save_weights dalam format berikut:

  • Pos Pemeriksaan TensorFlow
  • HDF5

Format default untuk model.save_weights adalah TensorFlow pos pemeriksaan. Ada dua cara untuk menentukan format penyimpanan:

  1. save_format argumen: Set nilai untuk save_format="tf" atau save_format="h5" .
  2. path argumen: Jika jalur ujung dengan .h5 atau .hdf5 , maka format HDF5 digunakan. Akhiran lainnya akan menghasilkan sebuah pos pemeriksaan TensorFlow kecuali save_format diatur.

Ada juga opsi untuk mengambil bobot sebagai array numpy dalam memori. Setiap API memiliki pro dan kontra yang dirinci di bawah ini.

Format Pos Pemeriksaan TF

Contoh:

# Runnable example
sequential_model = keras.Sequential(
    [
        keras.Input(shape=(784,), name="digits"),
        keras.layers.Dense(64, activation="relu", name="dense_1"),
        keras.layers.Dense(64, activation="relu", name="dense_2"),
        keras.layers.Dense(10, name="predictions"),
    ]
)
sequential_model.save_weights("ckpt")
load_status = sequential_model.load_weights("ckpt")

# `assert_consumed` can be used as validation that all variable values have been
# restored from the checkpoint. See `tf.train.Checkpoint.restore` for other
# methods in the Status object.
load_status.assert_consumed()
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca4ced0>

Detail format

Format TensorFlow Checkpoint menyimpan dan memulihkan bobot menggunakan nama atribut objek. Sebagai contoh, mempertimbangkan tf.keras.layers.Dense lapisan. Layer berisi dua bobot: dense.kernel dan dense.bias . Ketika lapisan disimpan ke tf Format, pos pemeriksaan yang dihasilkan mengandung kunci "kernel" dan "bias" dan nilai-nilai berat badan yang sesuai mereka. Untuk informasi lebih lanjut lihat "Loading mekanik" di TF Checkpoint panduan .

Perhatikan bahwa tepi atribut / grafik dinamai nama yang digunakan dalam objek induk, bukan nama variabel. Pertimbangkan CustomLayer pada contoh di bawah. Variabel CustomLayer.var disimpan dengan "var" sebagai bagian dari kunci, bukan "var_a" .

class CustomLayer(keras.layers.Layer):
    def __init__(self, a):
        self.var = tf.Variable(a, name="var_a")


layer = CustomLayer(5)
layer_ckpt = tf.train.Checkpoint(layer=layer).save("custom_layer")

ckpt_reader = tf.train.load_checkpoint(layer_ckpt)

ckpt_reader.get_variable_to_dtype_map()
{'save_counter/.ATTRIBUTES/VARIABLE_VALUE': tf.int64,
 '_CHECKPOINTABLE_OBJECT_GRAPH': tf.string,
 'layer/var/.ATTRIBUTES/VARIABLE_VALUE': tf.int32}

Contoh pembelajaran transfer

Pada dasarnya, selama dua model memiliki arsitektur yang sama, mereka dapat berbagi pos pemeriksaan yang sama.

Contoh:

inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(10, name="predictions")(x)
functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")

# Extract a portion of the functional model defined in the Setup section.
# The following lines produce a new model that excludes the final output
# layer of the functional model.
pretrained = keras.Model(
    functional_model.inputs, functional_model.layers[-1].input, name="pretrained_model"
)
# Randomly assign "trained" weights.
for w in pretrained.weights:
    w.assign(tf.random.normal(w.shape))
pretrained.save_weights("pretrained_ckpt")
pretrained.summary()

# Assume this is a separate program where only 'pretrained_ckpt' exists.
# Create a new functional model with a different output dimension.
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = keras.layers.Dense(5, name="predictions")(x)
model = keras.Model(inputs=inputs, outputs=outputs, name="new_model")

# Load the weights from pretrained_ckpt into model.
model.load_weights("pretrained_ckpt")

# Check that all of the pretrained weights have been loaded.
for a, b in zip(pretrained.weights, model.weights):
    np.testing.assert_allclose(a.numpy(), b.numpy())

print("\n", "-" * 50)
model.summary()

# Example 2: Sequential model
# Recreate the pretrained model, and load the saved weights.
inputs = keras.Input(shape=(784,), name="digits")
x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
pretrained_model = keras.Model(inputs=inputs, outputs=x, name="pretrained")

# Sequential example:
model = keras.Sequential([pretrained_model, keras.layers.Dense(5, name="predictions")])
model.summary()

pretrained_model.load_weights("pretrained_ckpt")

# Warning! Calling `model.load_weights('pretrained_ckpt')` won't throw an error,
# but will *not* work as expected. If you inspect the weights, you'll see that
# none of the weights will have loaded. `pretrained_model.load_weights()` is the
# correct method to call.
Model: "pretrained_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
digits (InputLayer)          [(None, 784)]             0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
=================================================================
Total params: 54,400
Trainable params: 54,400
Non-trainable params: 0
_________________________________________________________________

 --------------------------------------------------
Model: "new_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
digits (InputLayer)          [(None, 784)]             0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
_________________________________________________________________
predictions (Dense)          (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
pretrained (Functional)      (None, 64)                54400     
_________________________________________________________________
predictions (Dense)          (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca76990>

Biasanya disarankan untuk tetap menggunakan API yang sama untuk membangun model. Jika Anda beralih antara Sequential dan Functional, atau Functional dan subclassed, dll., maka selalu buat ulang model yang sudah dilatih sebelumnya dan muat bobot yang sudah dilatih sebelumnya ke model itu.

Pertanyaan selanjutnya adalah, bagaimana bobot dapat disimpan dan dimuat ke model yang berbeda jika arsitektur model sangat berbeda? Solusinya adalah dengan menggunakan tf.train.Checkpoint untuk menyimpan dan mengembalikan tepat lapisan / variabel.

Contoh:

# Create a subclassed model that essentially uses functional_model's first
# and last layers.
# First, save the weights of functional_model's first and last dense layers.
first_dense = functional_model.layers[1]
last_dense = functional_model.layers[-1]
ckpt_path = tf.train.Checkpoint(
    dense=first_dense, kernel=last_dense.kernel, bias=last_dense.bias
).save("ckpt")

# Define the subclassed model.
class ContrivedModel(keras.Model):
    def __init__(self):
        super(ContrivedModel, self).__init__()
        self.first_dense = keras.layers.Dense(64)
        self.kernel = self.add_variable("kernel", shape=(64, 10))
        self.bias = self.add_variable("bias", shape=(10,))

    def call(self, inputs):
        x = self.first_dense(inputs)
        return tf.matmul(x, self.kernel) + self.bias


model = ContrivedModel()
# Call model on inputs to create the variables of the dense layer.
_ = model(tf.ones((1, 784)))

# Create a Checkpoint with the same structure as before, and load the weights.
tf.train.Checkpoint(
    dense=model.first_dense, kernel=model.kernel, bias=model.bias
).restore(ckpt_path).assert_consumed()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/engine/base_layer.py:2223: UserWarning: `layer.add_variable` is deprecated and will be removed in a future version. Please use `layer.add_weight` method instead.
  warnings.warn('`layer.add_variable` is deprecated and '
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f9aaca6f390>

format HDF5

Format HDF5 berisi bobot yang dikelompokkan berdasarkan nama lapisan. Bobot adalah daftar memerintahkan dengan menggabungkan daftar bobot dilatih untuk daftar bobot non-dilatih (sama seperti layer.weights ). Dengan demikian, model dapat menggunakan pos pemeriksaan hdf5 jika memiliki lapisan yang sama dan status yang dapat dilatih seperti yang disimpan di pos pemeriksaan.

Contoh:

# Runnable example
sequential_model = keras.Sequential(
    [
        keras.Input(shape=(784,), name="digits"),
        keras.layers.Dense(64, activation="relu", name="dense_1"),
        keras.layers.Dense(64, activation="relu", name="dense_2"),
        keras.layers.Dense(10, name="predictions"),
    ]
)
sequential_model.save_weights("weights.h5")
sequential_model.load_weights("weights.h5")

Perhatikan bahwa mengubah layer.trainable dapat mengakibatkan berbeda layer.weights memesan ketika model mengandung lapisan bersarang.

class NestedDenseLayer(keras.layers.Layer):
    def __init__(self, units, name=None):
        super(NestedDenseLayer, self).__init__(name=name)
        self.dense_1 = keras.layers.Dense(units, name="dense_1")
        self.dense_2 = keras.layers.Dense(units, name="dense_2")

    def call(self, inputs):
        return self.dense_2(self.dense_1(inputs))


nested_model = keras.Sequential([keras.Input((784,)), NestedDenseLayer(10, "nested")])
variable_names = [v.name for v in nested_model.weights]
print("variables: {}".format(variable_names))

print("\nChanging trainable status of one of the nested layers...")
nested_model.get_layer("nested").dense_1.trainable = False

variable_names_2 = [v.name for v in nested_model.weights]
print("\nvariables: {}".format(variable_names_2))
print("variable ordering changed:", variable_names != variable_names_2)
variables: ['nested/dense_1/kernel:0', 'nested/dense_1/bias:0', 'nested/dense_2/kernel:0', 'nested/dense_2/bias:0']

Changing trainable status of one of the nested layers...

variables: ['nested/dense_2/kernel:0', 'nested/dense_2/bias:0', 'nested/dense_1/kernel:0', 'nested/dense_1/bias:0']
variable ordering changed: True

Contoh pembelajaran transfer

Saat memuat anak timbangan yang telah dilatih sebelumnya dari HDF5, direkomendasikan untuk memuat anak timbangan ke dalam model checkpoint asli, dan kemudian mengekstrak berat/lapisan yang diinginkan ke dalam model baru.

Contoh:

def create_functional_model():
    inputs = keras.Input(shape=(784,), name="digits")
    x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs)
    x = keras.layers.Dense(64, activation="relu", name="dense_2")(x)
    outputs = keras.layers.Dense(10, name="predictions")(x)
    return keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp")


functional_model = create_functional_model()
functional_model.save_weights("pretrained_weights.h5")

# In a separate program:
pretrained_model = create_functional_model()
pretrained_model.load_weights("pretrained_weights.h5")

# Create a new model by extracting layers from the original model:
extracted_layers = pretrained_model.layers[:-1]
extracted_layers.append(keras.layers.Dense(5, name="dense_3"))
model = keras.Sequential(extracted_layers)
model.summary()
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 64)                50240     
_________________________________________________________________
dense_2 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_3 (Dense)              (None, 5)                 325       
=================================================================
Total params: 54,725
Trainable params: 54,725
Non-trainable params: 0
_________________________________________________________________