ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

حفظ وتحميل نماذج Keras

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

المقدمة

يتكون نموذج 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() )
  • المُحسِّن وحالته ، إن وجدت (يتيح لك ذلك إعادة بدء التدريب من حيث تركت)

واجهات برمجة التطبيقات

هناك تنسيقان يمكنك استخدامهما لحفظ نموذج كامل على القرص: تنسيق TensorFlow SavedModel ، وتنسيق Keras H5 الأقدم . التنسيق الموصى به هو SavedModel. هذا هو model.save() الافتراضي عند استخدام model.save() .

يمكنك التبديل إلى تنسيق H5 عن طريق:

  • تمرير save_format='h5' save() .
  • تمرير اسم ملف ينتهي بـ .h5 أو. .keras save() .

شكل SavedModel

مثال:

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 [==============================] - 0s 1ms/step - loss: 1.1917
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
INFO:tensorflow:Assets written to: my_model/assets
4/4 [==============================] - 0s 1ms/step - loss: 1.0581

<tensorflow.python.keras.callbacks.History at 0x7f13700096d8>

ما يحتويه ملف SavedModel

يؤدي استدعاء model.save('my_model') إنشاء مجلد باسم my_model ، يحتوي على ما يلي:

ls my_model
assets  saved_model.pb  variables

يتم تخزين بنية النموذج وتكوين التدريب (بما في ذلك المحسن والخسائر والمقاييس) في saved_model.pb . يتم حفظ الأوزان في variables/ الدليل.

للحصول على معلومات مفصلة حول تنسيق SavedModel ، راجع دليل SavedModel ( تنسيق SavedModel على القرص ) .

كيف يعالج SavedModel الكائنات المخصصة

عند حفظ النموذج وطبقاته ، يقوم تنسيق SavedModel بتخزين اسم الفئة ووظيفة الاستدعاء والخسائر والأوزان (والتكوين ، إذا تم تنفيذه). تحدد وظيفة الاستدعاء الرسم البياني لحساب النموذج / الطبقة.

في حالة عدم وجود تهيئة النموذج / الطبقة ، يتم استخدام وظيفة الاستدعاء لإنشاء نموذج موجود مثل النموذج الأصلي الذي يمكن تدريبه وتقييمه واستخدامه للاستدلال.

ومع ذلك، هو دائما ممارسة جيدة لتحديد get_config و from_config الأساليب عند كتابة نموذج مخصص أو فئة الطبقة. يتيح لك ذلك تحديث الحساب بسهولة لاحقًا إذا لزم الأمر. راجع قسم الكائنات المخصصة لمزيد من المعلومات.

يوجد أدناه مثال لما يحدث عند تحميل طبقات مخصصة من تنسيق SavedModel دون الكتابة فوق طرق التكوين.

class CustomModel(keras.Model):
    def __init__(self, hidden_units):
        super(CustomModel, self).__init__()
        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


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

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

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

print("Original model:", model)
print("Loaded model:", loaded)
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.
Original model: <__main__.CustomModel object at 0x7f1370081550>
Loaded model: <tensorflow.python.keras.saving.saved_model.load.CustomModel object at 0x7f1328722e48>

كما هو موضح في المثال أعلاه ، يقوم المُحمل بشكل ديناميكي بإنشاء فئة طراز جديدة تعمل مثل النموذج الأصلي.

تنسيق 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: 4.1064
4/4 [==============================] - 0s 1ms/step - loss: 3.8469

<tensorflow.python.keras.callbacks.History at 0x7f14171934a8>

محددات

مقارنةً بتنسيق SavedModel ، هناك شيئان لا يتم تضمينهما في ملف H5:

  • الخسائر الخارجية والمقاييس المضافة عبر model.add_loss() & model.add_metric() لا يتم حفظها (على عكس SavedModel). إذا كانت لديك مثل هذه الخسائر والمقاييس في نموذجك وتريد استئناف التدريب ، فأنت بحاجة إلى إضافة هذه الخسائر مرة أخرى بنفسك بعد تحميل النموذج. لاحظ أن هذا لا ينطبق على الخسائر / المقاييس التي تم إنشاؤها داخل الطبقات عبر self.add_loss() & self.add_metric() . طالما يتم تحميل الطبقة ، يتم الاحتفاظ بهذه الخسائر والمقاييس ، لأنها جزء من طريقة call الطبقة.
  • لا يتم تضمين الرسم البياني لحساب الكائنات المخصصة مثل الطبقات المخصصة في الملف المحفوظ. في وقت التحميل ، سيحتاج Keras إلى الوصول إلى فئات / وظائف Python لهذه الكائنات لإعادة بناء النموذج. انظر الكائنات المخصصة .

حفظ العمارة

يحدد تكوين النموذج (أو البنية) الطبقات التي يحتوي عليها النموذج ، وكيفية توصيل هذه الطبقات *. إذا كان لديك تكوين نموذج ، فيمكن إنشاء النموذج بحالة تمت تهيئتها حديثًا للأوزان ولا توجد معلومات تجميع.

* لاحظ أن هذا ينطبق فقط على النماذج المحددة باستخدام النماذج الوظيفية أو التسلسلية غير المصنفة ضمن الفئات الفرعية.

تكوين نموذج تسلسلي أو نموذج API وظيفي

هذه الأنواع من النماذج عبارة عن رسوم بيانية صريحة للطبقات: تكوينها متاح دائمًا في شكل منظم.

واجهات برمجة التطبيقات

get_config() و from_config()

config = model.get_config() استدعاء config = model.get_config() إلى إرجاع config = model.get_config() Python يحتوي على تكوين النموذج. يمكن بعد ذلك إعادة بناء النموذج نفسه عبر 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)

كائنات مخصصة

النماذج والطبقات

يتم تعريف بنية النماذج والطبقات __init__ طريقتين __init__ و call . تعتبر Python bytecode ، والتي لا يمكن تحويلها إلى تكوين متوافق مع JSON - يمكنك محاولة إجراء تسلسل للرمز الثانوي (على سبيل المثال عبر pickle ) ، ولكنه غير آمن تمامًا ويعني أنه لا يمكن تحميل النموذج الخاص بك على نظام مختلف.

من أجل حفظ / تحميل نموذج بطبقات معرّفة بشكل مخصص ، أو نموذج get_config ، يجب استبدال from_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()
INFO:tensorflow:Assets written to: my_model/assets

لاحظ أن هذه الطريقة لها عدة عيوب:

  • لأسباب تتعلق بإمكانية التتبع ، يجب أن يكون لديك دائمًا حق الوصول إلى الكائنات المخصصة التي تم استخدامها. لن ترغب في إنتاج نموذج لا يمكنك إعادة إنشائه.
  • الكائن الذي تم إرجاعه بواسطة tf.saved_model.load ليس نموذج Keras. لذا فهي ليست سهلة الاستخدام. على سبيل المثال ، لن تتمكن من الوصول إلى .predict() أو .fit()

حتى إذا تم تثبيط استخدامه ، يمكن أن يساعدك إذا كنت في مأزق ، على سبيل المثال ، إذا فقدت رمز tf.keras.models.load_model() المخصصة أو tf.keras.models.load_model() مشكلات في تحميل النموذج باستخدام tf.keras.models.load_model() .

يمكنك معرفة المزيد في الصفحة حول tf.saved_model.load

تحديد طرق التكوين

مواصفات:

  • يجب أن تعيد get_config JSON حتى يكون متوافقًا مع واجهات برمجة التطبيقات (API) الموفرة للنماذج وهندسة Keras.
  • from_config(config) ( classmethod ) طبقة جديدة أو كائن نموذج تم إنشاؤه من ملف config. يعيد التنفيذ الافتراضي 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 ). هناك عدة طرق لتسجيل الفصول المخصصة في هذه القائمة:

  1. تعيين وسيطة custom_objects في دالة التحميل. (راجع المثال في القسم أعلاه "تحديد طرق التكوين")
  2. tf.keras.utils.custom_object_scope أو tf.keras.utils.CustomObjectScope
  3. 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 :

الأمثلة أدناه.

نقل الأوزان من طبقة إلى أخرى في الذاكرة

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 2 to layer 1
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 checkpoint. هناك طريقتان لتحديد تنسيق الحفظ:

  1. وسيطة save_format : اضبط القيمة على save_format="tf" أو save_format="h5" .
  2. وسيطة path : إذا انتهى المسار بـ .h5 أو .hdf5 ، فسيتم استخدام تنسيق .hdf5 . ستؤدي اللواحق الأخرى إلى نقطة save_format ما لم يتم تعيين 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 0x7f1416793ba8>

تفاصيل التنسيق

يحفظ تنسيق TensorFlow Checkpoint الأوزان ويستعيدها باستخدام أسماء سمات الكائن. على سبيل المثال ، ضع في tf.keras.layers.Dense طبقة tf.keras.layers.Dense . تحتوي الطبقة على dense.kernel : dense.kernel dense.bias . عندما يتم حفظ الطبقة بتنسيق tf ، فإن نقطة التحقق الناتجة تحتوي على المفاتيح "kernel" و "bias" وقيم الوزن المقابلة لها. لمزيد من المعلومات ، راجع "تحميل ميكانيكي" في دليل TF Checkpoint .

لاحظ أن السمة / حافة الرسم البياني تتم تسميتها بالاسم المستخدم في الكائن الأصل ، وليس اسم المتغير . ضع في اعتبارك 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()
لأنه 618234

نقل مثال التعلم

بشكل أساسي ، طالما أن نموذجين لهما نفس البنية ، فيمكنهما مشاركة نفس نقطة التفتيش.

مثال:

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 (Model)           (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 0x7f1416704278>

يوصى عمومًا بالالتزام بنفس واجهة برمجة التطبيقات لنماذج البناء. إذا قمت بالتبديل بين المتسلسلة والوظيفية ، أو الوظيفية والفئة الفرعية ، وما إلى ذلك ، فقم دائمًا بإعادة بناء النموذج المدرب مسبقًا وتحميل الأوزان المدربة مسبقًا على هذا النموذج.

السؤال التالي هو ، كيف يمكن حفظ الأوزان وتحميلها على نماذج مختلفة إذا كانت بنى النموذج مختلفة تمامًا؟ الحل هو استخدام 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()
WARNING:tensorflow:From <ipython-input-21-eec1d28bc826>:15: Layer.add_variable (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
Please use `layer.add_weight` method instead.

<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f1416713358>

تنسيق 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 ترتيب 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
_________________________________________________________________