![]() | ![]() | ![]() | ![]() |
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()
atauadd_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
-
model.save()
atautf.keras.models.save_model()
-
tf.keras.models.load_model()
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'
untuksave()
. - Melewati nama file yang berakhir di
.h5
atau.keras
untuksave()
.
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 viaself.add_loss()
&self.add_metric()
. Selama lapisan akan dimuat, kerugian ini & metrik disimpan, karena mereka adalah bagian daricall
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()
danfrom_config()
-
tf.keras.models.model_to_json()
dantf.keras.models.model_from_json()
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 pengembaliancls(**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:
- Pengaturan
custom_objects
argumen dalam fungsi pemuatan. (lihat contoh di bagian di atas "Mendefinisikan metode konfigurasi") -
tf.keras.utils.custom_object_scope
atautf.keras.utils.CustomObjectScope
-
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
:
-
tf.keras.layers.Layer.get_weights()
: Mengembalikan daftar array numpy. -
tf.keras.layers.Layer.set_weights()
: Mengatur bobot Model dengan nilai-nilai dalamweights
argumen.
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:
-
save_format
argumen: Set nilai untuksave_format="tf"
atausave_format="h5"
. -
path
argumen: Jika jalur ujung dengan.h5
atau.hdf5
, maka format HDF5 digunakan. Akhiran lainnya akan menghasilkan sebuah pos pemeriksaan TensorFlow kecualisave_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 _________________________________________________________________