![]() | ![]() | ![]() | ![]() |
مقدمة
يتكون نموذج Keras من مكونات متعددة:
- العمارة ، أو التكوين ، الذي يحدد الطبقات التي يحتوي عليها النموذج ، وكيف يتم توصيلها.
- مجموعة من قيم الأوزان ("حالة النموذج").
- مُحسِّن (يُعرَّف عن طريق تجميع النموذج).
- وهناك مجموعة من الخسائر والمقاييس (المعرفة عن طريق تجميع نموذج أو الدعوة
add_loss()
أوadd_metric()
).
تتيح واجهة برمجة تطبيقات Keras إمكانية حفظ كل هذه القطع على القرص مرة واحدة ، أو حفظ بعضها بشكل انتقائي فقط:
- حفظ كل شيء في أرشيف واحد بتنسيق TensorFlow SavedModel (أو بتنسيق Keras H5 الأقدم). هذه هي الممارسة القياسية.
- حفظ البنية / التكوين فقط ، عادةً كملف JSON.
- حفظ قيم الأوزان فقط. يستخدم هذا بشكل عام عند تدريب النموذج.
دعنا نلقي نظرة على كل من هذه الخيارات. متى تستخدم أحدهما أو الآخر ، وكيف يعملان؟
كيفية حفظ وتحميل نموذج
إذا كان لديك 10 ثوانٍ فقط لقراءة هذا الدليل ، فإليك ما تحتاج إلى معرفته.
حفظ نموذج Keras:
model = ... # Get model (Sequential, Functional Model, or Model subclass)
model.save('path/to/location')
تحميل النموذج مرة أخرى:
from tensorflow import keras
model = keras.models.load_model('path/to/location')
الآن ، دعونا نلقي نظرة على التفاصيل.
يثبت
import numpy as np
import tensorflow as tf
from tensorflow import keras
حفظ وتحميل نموذج كامل
يمكنك حفظ نموذج كامل في قطعة أثرية واحدة. سوف تشمل:
- بنية النموذج / config
- قيم وزن النموذج (التي تم تعلمها أثناء التدريب)
- معلومات تجميع نموذج (إن
compile()
كان يسمى) - المُحسِّن وحالته ، إن وجدت (يتيح لك ذلك إعادة بدء التدريب من حيث تركت)
واجهات برمجة التطبيقات
-
model.save()
أوtf.keras.models.save_model()
-
tf.keras.models.load_model()
هناك نوعان من الأشكال التي يمكن استخدامها لحفظ نموذج كامل على القرص: شكل TensorFlow SavedModel، وشكل Keras H5 السن. التنسيق الموصى به هو SavedModel. هذا هو الافتراضي عند استخدام model.save()
.
يمكنك التبديل إلى تنسيق H5 عن طريق:
- يمر
save_format='h5'
لsave()
. - تمرير اسم الملف الذي ينتهي في
.h5
أو.keras
لsave()
.
شكل SavedModel
SavedModel هو تنسيق الحفظ الأكثر شمولاً الذي يحفظ بنية النموذج والأوزان والرسوم الفرعية المتتبعة Tensorflow لوظائف الاتصال. يتيح ذلك لـ Keras استعادة كل من الطبقات المضمنة وكذلك الكائنات المخصصة.
مثال:
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>
ما يحتويه ملف SavedModel
داعيا model.save('my_model')
بإنشاء مجلد اسمه my_model
، تحتوي على ما يلي:
ls my_model
assets keras_metadata.pb saved_model.pb variables
يتم تخزين بنية النموذج، والتكوين التدريب (بما في ذلك محسن والخسائر والمقاييس) في saved_model.pb
. يتم حفظ الأوزان في variables/
الدليل.
للحصول على معلومات مفصلة عن شكل SavedModel، راجع دليل SavedModel (تنسيق SavedModel على القرص) .
كيف يعالج SavedModel الكائنات المخصصة
عند حفظ النموذج وطبقات، وSavedModel شكل مخازن اسم الفئة، وظيفة الدعوة، والخسائر، والأوزان (والتكوين، في حال تنفيذها). تحدد وظيفة الاستدعاء الرسم البياني لحساب النموذج / الطبقة.
في حالة عدم وجود تهيئة النموذج / الطبقة ، يتم استخدام وظيفة الاستدعاء لإنشاء نموذج موجود مثل النموذج الأصلي والذي يمكن تدريبه وتقييمه واستخدامه للاستدلال.
ومع ذلك، هو دائما ممارسة جيدة لتحديد get_config
و from_config
الأساليب عند كتابة نموذج مخصص أو فئة الطبقة. يتيح لك ذلك تحديث الحساب بسهولة لاحقًا إذا لزم الأمر. راجع المقطع حول الأشياء مخصص للمزيد من المعلومات.
مثال:
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>
يتم تحميل أول نموذج تحميل باستخدام التكوين و CustomModel
الصف. يتم تحميل النموذج الثاني عن طريق الإنشاء الديناميكي لفئة النموذج التي تعمل مثل النموذج الأصلي.
تكوين SavedModel
الجديد في TensoFlow 2.4 الحجة save_traces
تمت إضافة إلى model.save
، والذي يسمح لك لتبديل SavedModel وظيفة البحث عن المفقودين. يتم حفظ وظائف للسماح للKeras إلى كائنات مخصصة إعادة التحميل دون definitons الطبقة الأصلية، وذلك عندما save_traces=False
، كل الكائنات المخصصة يجب أن يكون تعريف get_config
/ from_config
الأساليب. عند تحميل، يجب أن يتم تمرير الكائنات مخصصة إلى custom_objects
حجة. save_traces=False
يقلل من مساحة القرص المستخدمة من قبل SavedModel وتوفير الوقت.
تنسيق Keras H5
يدعم Keras أيضا حفظ ملف HDF5 واحد يحتوي على الهندسة المعمارية للنموذج، قيم الأوزان، و compile()
المعلومات. إنه بديل خفيف الوزن لـ SavedModel.
مثال:
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>
محددات
مقارنةً بتنسيق SavedModel ، هناك شيئان لا يتم تضمينهما في ملف H5:
- خسائر الخارجية ومقاييس وأضاف عبر
model.add_loss()
وmodel.add_metric()
لا يتم حفظ (خلافا SavedModel). إذا كانت لديك مثل هذه الخسائر والمقاييس في نموذجك وترغب في استئناف التدريب ، فأنت بحاجة إلى إضافة هذه الخسائر مرة أخرى بنفسك بعد تحميل النموذج. لاحظ أن هذا لا ينطبق على خسائر / المقاييس التي تم إنشاؤها داخل طبقات عبرself.add_loss()
وself.add_metric()
. ما دام يحصل على تحميل الطبقة، وتحفظ هذه الخسائر والمقاييس، لأنها جزء منcall
طريقة طبقة. - الرسم البياني حساب مخصص كائنات مثل لا يتم تضمين طبقات مخصصة في الملف المحفوظ. في وقت التحميل ، سيحتاج Keras إلى الوصول إلى فئات / وظائف Python لهذه الكائنات لإعادة بناء النموذج. انظر كائنات مخصص .
إنقاذ العمارة
يحدد تكوين النموذج (أو البنية) الطبقات التي يحتوي عليها النموذج ، وكيف يتم توصيل هذه الطبقات *. إذا كان لديك تكوين نموذج ، فيمكن إنشاء النموذج بحالة تمت تهيئتها حديثًا للأوزان وعدم وجود معلومات تجميع.
* لاحظ أن هذا ينطبق فقط على النماذج المحددة باستخدام النماذج الوظيفية أو التتابعية لواجهة برمجة التطبيقات غير المصنفة ضمن الفئات الفرعية.
تكوين نموذج تسلسلي أو نموذج API وظيفي
هذه الأنواع من النماذج عبارة عن رسوم بيانية صريحة للطبقات: تكوينها متاح دائمًا في شكل منظم.
واجهات برمجة التطبيقات
-
get_config()
وfrom_config()
-
tf.keras.models.model_to_json()
وtf.keras.models.model_from_json()
get_config()
و from_config()
داعيا config = model.get_config()
سيعود ديكت بيثون تحتوي على تكوين نموذج. نفس النموذج ومن ثم يمكن بناؤها عبر Sequential.from_config(config)
(ل Sequential
نموذج) أو Model.from_config(config)
(لنموذج API الوظيفي).
يعمل نفس سير العمل أيضًا مع أي طبقة قابلة للتسلسل.
مثال الطبقة:
layer = keras.layers.Dense(3, activation="relu")
layer_config = layer.get_config()
new_layer = keras.layers.Dense.from_config(layer_config)
مثال على النموذج المتسلسل:
model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
config = model.get_config()
new_model = keras.Sequential.from_config(config)
مثال على النموذج الوظيفي:
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()
و tf.keras.models.model_from_json()
هذا هو مماثل ل get_config
/ from_config
، إلا أنه يتحول النموذج إلى سلسلة JSON، ومن ثم يمكن تحميلها دون الطبقة النموذج الأصلي. كما أنه خاص بالنماذج ، وليس مخصصًا للطبقات.
مثال:
model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)])
json_config = model.to_json()
new_model = keras.models.model_from_json(json_config)
كائنات مخصصة
النماذج والطبقات
يتم تعريف بنية نماذج subclassed وطبقات في أساليب __init__
و call
. وهي تعتبر بيثون بايت كود، التي لا يمكن إجراء تسلسل إلى التكوين JSON متوافق مع - قد تتمكن من محاولة تسلسل بايت كود (على سبيل المثال عن طريق pickle
)، لكنه غير آمن تماما، ويعني النموذج الخاص بك لا يمكن تحميلها على نظام مختلف.
من أجل حفظ / تحميل نموذج مع طبقات المعرفة من قبل العرف، أو نموذج subclassed، يجب أن الكتابة فوق get_config
واختياريا from_config
الأساليب. بالإضافة إلى ذلك ، يجب عليك استخدام تسجيل الكائن المخصص حتى يكون Keras على علم به.
وظائف مخصصة
وظائف محددة مخصصة (مثل فقدان التنشيط أو التهيئة) لا تحتاج إلى get_config
الأسلوب. اسم الوظيفة كافٍ للتحميل طالما تم تسجيله ككائن مخصص.
تحميل الرسم البياني TensorFlow فقط
من الممكن تحميل الرسم البياني TensorFlow الذي تم إنشاؤه بواسطة Keras. إذا قمت بذلك، لن تحتاج لتقديم أي custom_objects
. يمكنك القيام بذلك على النحو التالي:
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
لاحظ أن هذه الطريقة لها عدة عيوب:
- لأسباب تتعلق بإمكانية التتبع ، يجب أن يكون لديك دائمًا حق الوصول إلى الكائنات المخصصة التي تم استخدامها. لن ترغب في إنتاج نموذج لا يمكنك إعادة إنشائه.
- الكائن إرجاعها بواسطة
tf.saved_model.load
ليست نموذجا Keras. لذا فهي ليست سهلة الاستخدام. على سبيل المثال، سوف لا يكون لديك الوصول إلى.predict()
أو.fit()
حتى لو تم تخيف استخدامه، يمكن أن تساعدك إذا كنت في مأزق، على سبيل المثال، إذا كنت فقدت رمز من كائنات مخصصة أو لديك مشاكل تحميل نموذج مع tf.keras.models.load_model()
.
يمكنك معرفة المزيد في صفحة حول tf.saved_model.load
تحديد طرق التكوين
تحديد:
-
get_config
يجب أن تعود إلى القاموس JSON للتسلسل لكي تكون متوافقة مع Keras architecture- واجهات برمجة التطبيقات الموفرة للنموذج. -
from_config(config)
(classmethod
) يجب إرجاع كائن طبقة أو النموذج الجديد الذي تم إنشاؤه من التكوين. يعود تطبيق الافتراضيcls(**config)
.
مثال:
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}
)
تسجيل الكائن المخصص
يحتفظ Keras بملاحظة حول الفئة التي تم إنشاء ملف config. من المثال أعلاه، tf.keras.layers.serialize
يولد شكل تسلسل طبقة مخصصة:
{'class_name': 'CustomLayer', 'config': {'a': 2} }
Keras يحتفظ قائمة رئيسية من جميع المدمج في طبقة، نموذج، محسن، والطبقات متري، والذي يستخدم للعثور على الدرجة الصحيحة لدعوة from_config
. وإذا لم يمكن العثور على الصف، ثم يظهر خطأ ( Value Error: Unknown layer
). هناك عدة طرق لتسجيل الفصول المخصصة في هذه القائمة:
- وضع
custom_objects
حجة في وظيفة التحميل. (راجع المثال في القسم أعلاه "تحديد طرق التكوين") -
tf.keras.utils.custom_object_scope
أوtf.keras.utils.CustomObjectScope
-
tf.keras.utils.register_keras_serializable
طبقة مخصصة ومثال وظيفي
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)
استنساخ نموذج في الذاكرة
يمكنك أيضا القيام الاستنساخ في الذاكرة نموذج عبر tf.keras.models.clone_model()
. هذا يعادل الحصول على التكوين ثم إعادة إنشاء النموذج من التكوين الخاص به (لذلك لا يحتفظ بمعلومات التجميع أو قيم أوزان الطبقة).
مثال:
with keras.utils.custom_object_scope(custom_objects):
new_model = keras.models.clone_model(model)
حفظ وتحميل قيم أوزان النموذج فقط
يمكنك اختيار حفظ أوزان النموذج وتحميلها فقط. يمكن أن يكون هذا مفيدًا إذا:
- تحتاج فقط إلى نموذج للاستدلال: في هذه الحالة لن تحتاج إلى إعادة التدريب ، لذلك لا تحتاج إلى معلومات التجميع أو حالة المحسن.
- أنت تقوم بالتعلم عن طريق التحويل: في هذه الحالة سوف تقوم بتدريب نموذج جديد على إعادة استخدام حالة النموذج السابق ، لذلك لا تحتاج إلى معلومات التجميع الخاصة بالنموذج السابق.
واجهات برمجة التطبيقات لنقل الوزن في الذاكرة
يمكن نسخ الأوزان بين كائنات مختلفة باستخدام get_weights
و set_weights
:
-
tf.keras.layers.Layer.get_weights()
: إرجاع قائمة صفائف نمباي. -
tf.keras.layers.Layer.set_weights()
: تعيين الأوزان نموذج للقيم فيweights
حجة.
الأمثلة أدناه.
نقل الأوزان من طبقة إلى أخرى في الذاكرة
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())
نقل الأوزان من نموذج إلى نموذج آخر بهندسة معمارية متوافقة في الذاكرة
# 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())
حالة الطبقات عديمة الجنسية
نظرًا لأن الطبقات عديمة الحالة لا تغير ترتيب أو عدد الأوزان ، يمكن أن تحتوي النماذج على بنيات متوافقة حتى إذا كانت هناك طبقات عديمة الحالة إضافية / مفقودة.
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())
واجهات برمجة التطبيقات لحفظ الأوزان على القرص وإعادة تحميلها
يمكن حفظ الأوزان إلى القرص عن طريق الاتصال model.save_weights
في الأشكال التالية:
- TensorFlow Checkpoint
- HDF5
التنسيق الافتراضي لل model.save_weights
هو نقطة تفتيش TensorFlow. هناك طريقتان لتحديد تنسيق الحفظ:
-
save_format
حجة: تعيين القيمة إلىsave_format="tf"
أوsave_format="h5"
. -
path
حجة: إذا كان طرفي الطريق مع.h5
أو.hdf5
، ثم يتم استخدام تنسيق HDF5. واللواحق الأخرى يؤدي في نقطة تفتيش TensorFlow ما لمsave_format
ومن المقرر.
هناك أيضًا خيار لاسترداد الأوزان كمصفوفات غير متجانسة في الذاكرة. كل واجهة برمجة تطبيقات لها مزاياها وعيوبها الموضحة أدناه.
تنسيق TF Checkpoint
مثال:
# 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>
تفاصيل التنسيق
يحفظ تنسيق TensorFlow Checkpoint الأوزان ويستعيدها باستخدام أسماء سمات الكائن. على سبيل المثال، والنظر في tf.keras.layers.Dense
طبقة. طبقة يحتوي على اثنين من الأوزان: dense.kernel
و dense.bias
. عند حفظ طبقة إلى tf
الشكل، وتفتيش الناتج على مفاتيح "kernel"
و "bias"
والقيم الوزن يناظرها. لمزيد من المعلومات، راجع "الميكانيكا تحميل" في دليل TF نقطة تفتيش .
ملاحظة يدعى أن حافة السمة / الرسم البياني بعد اسم استخدامها في الكائن الأصل، وليس اسم المتغير. النظر في CustomLayer
في المثال التالي. المتغير CustomLayer.var
يتم حفظها مع "var"
كجزء من المفتاح، وليس "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}
نقل مثال التعلم
بشكل أساسي ، طالما أن نموذجين لهما نفس البنية ، فإنهما قادران على مشاركة نفس نقطة التفتيش.
مثال:
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>
يوصى عمومًا بالالتزام بنفس واجهة برمجة التطبيقات لنماذج البناء. إذا قمت بالتبديل بين المتسلسلة والوظيفية ، أو الوظيفية والفئة الفرعية ، وما إلى ذلك ، فقم دائمًا بإعادة بناء النموذج المدرب مسبقًا وتحميل الأوزان المدربة مسبقًا على هذا النموذج.
السؤال التالي هو ، كيف يمكن حفظ الأوزان وتحميلها على نماذج مختلفة إذا كانت بنيات النموذج مختلفة تمامًا؟ الحل هو استخدام tf.train.Checkpoint
لحفظ واستعادة طبقات دقيقة / المتغيرات.
مثال:
# 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>
تنسيق HDF5
يحتوي تنسيق HDF5 على أوزان مجمعة حسب أسماء الطبقات. الأوزان هي قوائم التي أمر بها وصل قائمة الأوزان المدربة على قائمة الأوزان غير قابلة للتدريب (نفس layer.weights
). وبالتالي ، يمكن للنموذج استخدام نقطة تفتيش hdf5 إذا كان لديه نفس الطبقات والحالات القابلة للتدريب كما تم حفظها في نقطة التفتيش.
مثال:
# 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")
علما بأن تغيير layer.trainable
قد يؤدي في مختلف layer.weights
ترتيب عندما يحتوي نموذج طبقات متداخلة.
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
نقل مثال التعلم
عند تحميل الأوزان مسبقة الصنع من HDF5 ، يوصى بتحميل الأوزان في النموذج الأصلي ذي نقاط التفتيش ، ثم استخراج الأوزان / الطبقات المطلوبة في نموذج جديد.
مثال:
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 _________________________________________________________________