היכרות עם מודולים, שכבות ודגמים

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

כדי לבצע למידת מכונה ב-TensorFlow, סביר להניח שתצטרך להגדיר, לשמור ולשחזר מודל.

מודל הוא, באופן מופשט:

  • פונקציה שמחשבת משהו על טנסורים ( מעבר קדימה )
  • כמה משתנים שניתן לעדכן בתגובה לאימון

במדריך זה, תעברו מתחת לפני השטח של Keras כדי לראות כיצד מוגדרים דגמי TensorFlow. זה בוחן כיצד TensorFlow אוספת משתנים ומודלים, כמו גם כיצד הם נשמרים ומשחזרים.

להכין

import tensorflow as tf
from datetime import datetime

%load_ext tensorboard

הגדרת מודלים ושכבות ב- TensorFlow

רוב הדגמים עשויים משכבות. שכבות הן פונקציות בעלות מבנה מתמטי ידוע שניתן לעשות בהן שימוש חוזר ויש להן משתנים הניתנים לאימון. ב-TensorFlow, רוב ההטמעות ברמה גבוהה של שכבות ומודלים, כגון Keras או Sonnet , בנויים על אותה מחלקה בסיסית: tf.Module .

הנה דוגמה tf.Module פשוט מאוד הפועל על טנזור סקלרי:

class SimpleModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)
    self.a_variable = tf.Variable(5.0, name="train_me")
    self.non_trainable_variable = tf.Variable(5.0, trainable=False, name="do_not_train_me")
  def __call__(self, x):
    return self.a_variable * x + self.non_trainable_variable

simple_module = SimpleModule(name="simple")

simple_module(tf.constant(5.0))
<tf.Tensor: shape=(), dtype=float32, numpy=30.0>

מודולים, ובהרחבה, שכבות הם מינוח למידה עמוק עבור "אובייקטים": יש להם מצב פנימי, ושיטות שמשתמשות במצב זה.

אין שום דבר מיוחד __call__ מלבד להתנהג כמו Python הניתן להתקשרות; אתה יכול להפעיל את הדגמים שלך עם כל פונקציה שתרצה.

ניתן להגדיר את יכולת האימון של משתנים להפעיל ולכבות מכל סיבה שהיא, כולל הקפאת שכבות ומשתנים במהלך כוונון עדין.

על ידי סיווג משנה tf.Module , כל tf.Variable או tf.Module שהוקצו למאפייני אובייקט זה נאספים אוטומטית. זה מאפשר לך לשמור ולטעון משתנים, וגם ליצור אוספים של tf.Module s.

# All trainable variables
print("trainable variables:", simple_module.trainable_variables)
# Every variable
print("all variables:", simple_module.variables)
trainable variables: (<tf.Variable 'train_me:0' shape=() dtype=float32, numpy=5.0>,)
all variables: (<tf.Variable 'train_me:0' shape=() dtype=float32, numpy=5.0>, <tf.Variable 'do_not_train_me:0' shape=() dtype=float32, numpy=5.0>)
2021-10-26 01:29:45.284549: 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.

זוהי דוגמה למודל שכבה לינארית דו-שכבתית העשוי ממודולים.

ראשית שכבה צפופה (לינארית):

class Dense(tf.Module):
  def __init__(self, in_features, out_features, name=None):
    super().__init__(name=name)
    self.w = tf.Variable(
      tf.random.normal([in_features, out_features]), name='w')
    self.b = tf.Variable(tf.zeros([out_features]), name='b')
  def __call__(self, x):
    y = tf.matmul(x, self.w) + self.b
    return tf.nn.relu(y)

ואז המודל השלם, שיוצר שני מופעי שכבות ומחיל אותם:

class SequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = Dense(in_features=3, out_features=3)
    self.dense_2 = Dense(in_features=3, out_features=2)

  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

# You have made a model!
my_model = SequentialModule(name="the_model")

# Call it, with random results
print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))
Model results: tf.Tensor([[7.706234  3.0919805]], shape=(1, 2), dtype=float32)

מופעי tf.Module יאספו אוטומטית, רקורסיבית, כל tf.Variable או tf.Module שהוקצו לו. זה מאפשר לך לנהל אוספים של tf.Module s עם מופע מודל יחיד, ולשמור ולטעון מודלים שלמים.

print("Submodules:", my_model.submodules)
Submodules: (<__main__.Dense object at 0x7f7ab2391290>, <__main__.Dense object at 0x7f7b6869ea10>)
for var in my_model.variables:
  print(var, "\n")
<tf.Variable 'b:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)> 

<tf.Variable 'w:0' shape=(3, 3) dtype=float32, numpy=
array([[ 0.05711935,  0.22440144,  0.6370985 ],
       [ 0.3136791 , -1.7006774 ,  0.7256515 ],
       [ 0.16120772, -0.8412193 ,  0.5250952 ]], dtype=float32)> 

<tf.Variable 'b:0' shape=(2,) dtype=float32, numpy=array([0., 0.], dtype=float32)> 

<tf.Variable 'w:0' shape=(3, 2) dtype=float32, numpy=
array([[-0.5353216 ,  1.2815404 ],
       [ 0.62764466,  0.47087234],
       [ 2.19187   ,  0.45777202]], dtype=float32)>

מחכה ליצירת משתנים

אולי שמתם לב כאן שעליכם להגדיר גם גדלי קלט ופלט לשכבה. זה כך שלמשתנה w יש צורה ידועה וניתן להקצותו.

על ידי דחיית יצירת משתנה לפעם הראשונה שהמודול נקרא עם צורת קלט ספציפית, אינך צריך לציין את גודל הקלט מראש.

class FlexibleDenseModule(tf.Module):
  # Note: No need for `in_features`
  def __init__(self, out_features, name=None):
    super().__init__(name=name)
    self.is_built = False
    self.out_features = out_features

  def __call__(self, x):
    # Create variables on first call.
    if not self.is_built:
      self.w = tf.Variable(
        tf.random.normal([x.shape[-1], self.out_features]), name='w')
      self.b = tf.Variable(tf.zeros([self.out_features]), name='b')
      self.is_built = True

    y = tf.matmul(x, self.w) + self.b
    return tf.nn.relu(y)
# Used in a module
class MySequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = FlexibleDenseModule(out_features=3)
    self.dense_2 = FlexibleDenseModule(out_features=2)

  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

my_model = MySequentialModule(name="the_model")
print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))
Model results: tf.Tensor([[4.0598335 0.       ]], shape=(1, 2), dtype=float32)

גמישות זו היא הסיבה לכך ששכבות TensorFlow צריכות לעתים קרובות רק לציין את צורת הפלטים שלהן, כגון ב- tf.keras.layers.Dense , ולא גם את גודל הקלט וגם את גודל הפלט.

חיסכון במשקלים

אתה יכול לשמור tf.Module גם כנקודת ביקורת וגם כ-SaveModel .

מחסומים הם רק המשקולות (כלומר, הערכים של קבוצת המשתנים בתוך המודול ותתי המודולים שלו):

chkp_path = "my_checkpoint"
checkpoint = tf.train.Checkpoint(model=my_model)
checkpoint.write(chkp_path)
'my_checkpoint'

המחסומים מורכבים משני סוגים של קבצים: הנתונים עצמם וקובץ אינדקס למטא נתונים. קובץ האינדקס עוקב אחר מה נשמר בפועל ומספור המחסומים, בעוד שנתוני המחסום מכילים את ערכי המשתנים ואת נתיבי בדיקת המאפיינים שלהם.

ls my_checkpoint*
my_checkpoint.data-00000-of-00001  my_checkpoint.index

אתה יכול להסתכל בתוך מחסום כדי להיות בטוח שכל אוסף המשתנים נשמר, ממוין לפי אובייקט Python שמכיל אותם.

tf.train.list_variables(chkp_path)
[('_CHECKPOINTABLE_OBJECT_GRAPH', []),
 ('model/dense_1/b/.ATTRIBUTES/VARIABLE_VALUE', [3]),
 ('model/dense_1/w/.ATTRIBUTES/VARIABLE_VALUE', [3, 3]),
 ('model/dense_2/b/.ATTRIBUTES/VARIABLE_VALUE', [2]),
 ('model/dense_2/w/.ATTRIBUTES/VARIABLE_VALUE', [3, 2])]

במהלך אימון מבוזר (רב-מכונות) ניתן לגזור אותם, וזו הסיבה שהם ממוספרים (למשל, '00000-of-00001'). במקרה זה, עם זאת, יש רק רסיס אחד.

כאשר אתה טוען מודלים בחזרה, אתה מחליף את הערכים באובייקט Python שלך.

new_model = MySequentialModule()
new_checkpoint = tf.train.Checkpoint(model=new_model)
new_checkpoint.restore("my_checkpoint")

# Should be the same result as above
new_model(tf.constant([[2.0, 2.0, 2.0]]))
<tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[4.0598335, 0.       ]], dtype=float32)>

שמירת פונקציות

TensorFlow יכול להריץ מודלים ללא אובייקטי Python המקוריים, כפי שהדגימו על ידי TensorFlow Serving ו- TensorFlow Lite , גם כאשר אתה מוריד מודל מאומן מ- TensorFlow Hub .

TensorFlow צריך לדעת כיצד לבצע את החישובים המתוארים ב- Python, אך ללא הקוד המקורי . לשם כך, אתה יכול ליצור גרף , המתואר במדריך מבוא לגרפים ופונקציות .

גרף זה מכיל פעולות, או ops , המיישמות את הפונקציה.

אתה יכול להגדיר גרף במודל שלמעלה על ידי הוספת ה- @tf.function decorator כדי לציין שקוד זה צריך לפעול כגרף.

class MySequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = Dense(in_features=3, out_features=3)
    self.dense_2 = Dense(in_features=3, out_features=2)

  @tf.function
  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

# You have made a model with a graph!
my_model = MySequentialModule(name="the_model")

המודול שעשית עובד בדיוק כמו קודם. כל חתימה ייחודית המועברת לפונקציה יוצרת גרף נפרד. עיין במדריך מבוא לגרפים ופונקציות לפרטים.

print(my_model([[2.0, 2.0, 2.0]]))
print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))
tf.Tensor([[0.62891716 0.        ]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[[0.62891716 0.        ]
  [0.62891716 0.        ]]], shape=(1, 2, 2), dtype=float32)

אתה יכול לדמיין את הגרף על ידי מעקב אחריו בתוך סיכום TensorBoard.

# Set up logging.
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
logdir = "logs/func/%s" % stamp
writer = tf.summary.create_file_writer(logdir)

# Create a new model to get a fresh trace
# Otherwise the summary will not see the graph.
new_model = MySequentialModule()

# Bracket the function call with
# tf.summary.trace_on() and tf.summary.trace_export().
tf.summary.trace_on(graph=True)
tf.profiler.experimental.start(logdir)
# Call only one tf.function when tracing.
z = print(new_model(tf.constant([[2.0, 2.0, 2.0]])))
with writer.as_default():
  tf.summary.trace_export(
      name="my_func_trace",
      step=0,
      profiler_outdir=logdir)
tf.Tensor([[0.         0.01750386]], shape=(1, 2), dtype=float32)

הפעל את TensorBoard כדי להציג את המעקב שהתקבל:

#docs_infra: no_execute
%tensorboard --logdir logs/func

צילום מסך של הגרף ב-TensorBoard

יצירת SavedModel

הדרך המומלצת לשיתוף מודלים מאומנים לחלוטין היא להשתמש ב- SavedModel . SavedModel מכיל גם אוסף של פונקציות וגם אוסף משקלים.

אתה יכול לשמור את הדגם שאימנת זה עתה באופן הבא:

tf.saved_model.save(my_model, "the_saved_model")
INFO:tensorflow:Assets written to: the_saved_model/assets
# Inspect the SavedModel in the directory
ls -l the_saved_model
total 24
drwxr-sr-x 2 kbuilder kokoro  4096 Oct 26 01:29 assets
-rw-rw-r-- 1 kbuilder kokoro 14702 Oct 26 01:29 saved_model.pb
drwxr-sr-x 2 kbuilder kokoro  4096 Oct 26 01:29 variables
# The variables/ directory contains a checkpoint of the variables
ls -l the_saved_model/variables
total 8
-rw-rw-r-- 1 kbuilder kokoro 408 Oct 26 01:29 variables.data-00000-of-00001
-rw-rw-r-- 1 kbuilder kokoro 356 Oct 26 01:29 variables.index

הקובץ saved_model.pb הוא מאגר פרוטוקול המתאר את ה- tf.Graph הפונקציונלי.

ניתן לטעון מודלים ושכבות מהייצוג הזה מבלי ליצור מופע של המחלקה שיצרה אותו. זה רצוי במצבים שבהם אין לך (או רוצה) מתורגמן של Python, כגון הגשה בקנה מידה או במכשיר קצה, או במצבים שבהם קוד Python המקורי אינו זמין או מעשי לשימוש.

אתה יכול לטעון את המודל כאובייקט חדש:

new_model = tf.saved_model.load("the_saved_model")

new_model , שנוצר מטעינת מודל שמור, הוא אובייקט משתמש פנימי של TensorFlow ללא שום ידע בכיתה. זה לא מסוג SequentialModule .

isinstance(new_model, SequentialModule)
False

המודל החדש הזה עובד על חתימות הקלט שהוגדרו כבר. אתה לא יכול להוסיף חתימות נוספות לדגם ששוחזר כך.

print(my_model([[2.0, 2.0, 2.0]]))
print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))
tf.Tensor([[0.62891716 0.        ]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[[0.62891716 0.        ]
  [0.62891716 0.        ]]], shape=(1, 2, 2), dtype=float32)

לפיכך, באמצעות SavedModel , אתה יכול לשמור משקלים וגרפים של TensorFlow באמצעות tf.Module , ולאחר מכן לטעון אותם שוב.

דגמי קרס ושכבות

שימו לב שעד לנקודה זו, אין אזכור של קרס. אתה יכול לבנות ממשק API ברמה גבוהה משלך על גבי tf.Module , ולאנשים יש.

בחלק זה, תבחן כיצד Keras משתמש ב- tf.Module . מדריך למשתמש מלא לדגמי Keras ניתן למצוא במדריך Keras .

שכבות קרס

tf.keras.layers.Layer היא המחלקה הבסיסית של כל שכבות Keras, והיא יורשת מ- tf.Module .

אתה יכול להמיר מודול לשכבת Keras רק על ידי החלפת האב ואז שינוי __call__ ל- call :

class MyDense(tf.keras.layers.Layer):
  # Adding **kwargs to support base Keras layer arguments
  def __init__(self, in_features, out_features, **kwargs):
    super().__init__(**kwargs)

    # This will soon move to the build step; see below
    self.w = tf.Variable(
      tf.random.normal([in_features, out_features]), name='w')
    self.b = tf.Variable(tf.zeros([out_features]), name='b')
  def call(self, x):
    y = tf.matmul(x, self.w) + self.b
    return tf.nn.relu(y)

simple_layer = MyDense(name="simple", in_features=3, out_features=3)

לשכבות Keras יש __call__ משלהן שעושה קצת הנהלת חשבונות המתוארת בסעיף הבא ולאחר מכן קורא ל- call() . אתה לא אמור לשים לב לשום שינוי בפונקציונליות.

simple_layer([[2.0, 2.0, 2.0]])
<tf.Tensor: shape=(1, 3), dtype=float32, numpy=array([[0.      , 0.179402, 0.      ]], dtype=float32)>

שלב build

כפי שצוין, במקרים רבים נוח להמתין ליצירת משתנים עד שאתה בטוח בצורת הקלט.

שכבות Keras מגיעות עם שלב נוסף במחזור החיים המאפשר לך גמישות רבה יותר באופן שבו אתה מגדיר את השכבות שלך. זה מוגדר בפונקציית build .

build נקרא פעם אחת בדיוק, והוא נקרא עם צורת הקלט. הוא משמש בדרך כלל ליצירת משתנים (משקלים).

אתה יכול לשכתב את שכבת MyDense למעלה כדי להיות גמיש לגודל הכניסות שלה:

class FlexibleDense(tf.keras.layers.Layer):
  # Note the added `**kwargs`, as Keras supports many arguments
  def __init__(self, out_features, **kwargs):
    super().__init__(**kwargs)
    self.out_features = out_features

  def build(self, input_shape):  # Create the state of the layer (weights)
    self.w = tf.Variable(
      tf.random.normal([input_shape[-1], self.out_features]), name='w')
    self.b = tf.Variable(tf.zeros([self.out_features]), name='b')

  def call(self, inputs):  # Defines the computation from inputs to outputs
    return tf.matmul(inputs, self.w) + self.b

# Create the instance of the layer
flexible_dense = FlexibleDense(out_features=3)

בשלב זה, המודל לא נבנה, כך שאין משתנים:

flexible_dense.variables
[]

קריאה לפונקציה מקצה משתנים בגודל מתאים:

# Call it, with predictably random results
print("Model results:", flexible_dense(tf.constant([[2.0, 2.0, 2.0], [3.0, 3.0, 3.0]])))
Model results: tf.Tensor(
[[-1.6998017  1.6444504 -1.3103955]
 [-2.5497022  2.4666753 -1.9655929]], shape=(2, 3), dtype=float32)
flexible_dense.variables
[<tf.Variable 'flexible_dense/w:0' shape=(3, 3) dtype=float32, numpy=
 array([[ 1.277462  ,  0.5399406 , -0.301957  ],
        [-1.6277349 ,  0.7374014 , -1.7651852 ],
        [-0.49962795, -0.45511687,  1.4119445 ]], dtype=float32)>,
 <tf.Variable 'flexible_dense/b:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

מכיוון ש- build נקרא פעם אחת בלבד, קלטים יידחו אם צורת הקלט אינה תואמת למשתני השכבה:

try:
  print("Model results:", flexible_dense(tf.constant([[2.0, 2.0, 2.0, 2.0]])))
except tf.errors.InvalidArgumentError as e:
  print("Failed:", e)
Failed: In[0] mismatch In[1] shape: 4 vs. 3: [1,4] [3,3] 0 0 [Op:MatMul]

לשכבות Keras יש הרבה יותר תכונות נוספות כולל:

  • הפסדים אופציונליים
  • תמיכה במדדים
  • תמיכה מובנית בטיעון training אופציונלי כדי להבדיל בין אימון לשימוש בהסקת מסקנות
  • שיטות get_config ו- from_config המאפשרות לך לאחסן במדויק תצורות כדי לאפשר שיבוט מודלים ב- Python

קרא עליהם במדריך המלא לשכבות ודגמים מותאמים אישית.

דגמי קרס

אתה יכול להגדיר את המודל שלך כשכבות Keras מקוננות.

עם זאת, Keras מספקת גם מחלקת דגמים מלאה בשם tf.keras.Model . הוא יורש מ- tf.keras.layers.Layer , כך שניתן להשתמש במודל Keras, לקנן ולשמור באותו אופן כמו שכבות Keras. דגמי Keras מגיעים עם פונקציונליות נוספת שמקלה עליהם לאמן, להעריך, לטעון, לשמור ואפילו לאמן אותם במספר מכונות.

אתה יכול להגדיר את ה- SequentialModule מלמעלה עם קוד כמעט זהה, שוב להמיר את __call__ ל- call() ולשנות את האב:

class MySequentialModel(tf.keras.Model):
  def __init__(self, name=None, **kwargs):
    super().__init__(**kwargs)

    self.dense_1 = FlexibleDense(out_features=3)
    self.dense_2 = FlexibleDense(out_features=2)
  def call(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

# You have made a Keras model!
my_sequential_model = MySequentialModel(name="the_model")

# Call it on a tensor, with random results
print("Model results:", my_sequential_model(tf.constant([[2.0, 2.0, 2.0]])))
Model results: tf.Tensor([[5.5604653 3.3511646]], shape=(1, 2), dtype=float32)

כל אותן תכונות זמינות, כולל משתני מעקב ותת-מודולים.

my_sequential_model.variables
[<tf.Variable 'my_sequential_model/flexible_dense_1/w:0' shape=(3, 3) dtype=float32, numpy=
 array([[ 0.05627853, -0.9386015 , -0.77410126],
        [ 0.63149   ,  1.0802224 , -0.37785745],
        [-0.24788402, -1.1076807 , -0.5956209 ]], dtype=float32)>,
 <tf.Variable 'my_sequential_model/flexible_dense_1/b:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>,
 <tf.Variable 'my_sequential_model/flexible_dense_2/w:0' shape=(3, 2) dtype=float32, numpy=
 array([[-0.93912166,  0.77979285],
        [ 1.4049559 , -1.9380962 ],
        [-2.6039495 ,  0.30885765]], dtype=float32)>,
 <tf.Variable 'my_sequential_model/flexible_dense_2/b:0' shape=(2,) dtype=float32, numpy=array([0., 0.], dtype=float32)>]
my_sequential_model.submodules
(<__main__.FlexibleDense at 0x7f7b48525550>,
 <__main__.FlexibleDense at 0x7f7b48508d10>)

עקיפת tf.keras.Model היא גישה פייתונית מאוד לבניית מודלים של TensorFlow. אם אתה מעביר מודלים ממסגרות אחרות, זה יכול להיות מאוד פשוט.

אם אתה בונה מודלים שהם מכלולים פשוטים של שכבות ותשומות קיימות, אתה יכול לחסוך זמן ומקום על ידי שימוש ב- API הפונקציונלי , שמגיע עם תכונות נוספות סביב שחזור וארכיטקטורה של מודל.

הנה אותו דגם עם ה-API הפונקציונלי:

inputs = tf.keras.Input(shape=[3,])

x = FlexibleDense(3)(inputs)
x = FlexibleDense(2)(x)

my_functional_model = tf.keras.Model(inputs=inputs, outputs=x)

my_functional_model.summary()
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 3)]               0         
_________________________________________________________________
flexible_dense_3 (FlexibleDe (None, 3)                 12        
_________________________________________________________________
flexible_dense_4 (FlexibleDe (None, 2)                 8         
=================================================================
Total params: 20
Trainable params: 20
Non-trainable params: 0
_________________________________________________________________
my_functional_model(tf.constant([[2.0, 2.0, 2.0]]))
<tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[8.219393, 4.511119]], dtype=float32)>

ההבדל העיקרי כאן הוא שצורת הקלט מצוינת מלפנים כחלק מתהליך הבנייה הפונקציונלי. הארגומנט input_shape במקרה זה אינו חייב להיות מוגדר לחלוטין; אתה יכול להשאיר כמה ממדים בתור None .

שמירת דגמי קרס

ניתן לבדוק את דגמי Keras, וזה ייראה כמו tf.Module .

ניתן לשמור מודלים של Keras גם עם tf.saved_model.save() , מכיוון שהם מודולים. עם זאת, לדגמי Keras יש שיטות נוחות ופונקציונליות אחרת:

my_sequential_model.save("exname_of_file")
INFO:tensorflow:Assets written to: exname_of_file/assets

באותה קלות, ניתן לטעון אותם בחזרה ב:

reconstructed_model = tf.keras.models.load_model("exname_of_file")
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

Keras SavedModels שומר גם מצבי מדדים, אובדן ואופטימיזציה.

ניתן להשתמש במודל המשוחזר הזה והוא יפיק את אותה תוצאה כאשר נקרא על אותם נתונים:

reconstructed_model(tf.constant([[2.0, 2.0, 2.0]]))
<tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[5.5604653, 3.3511646]], dtype=float32)>

יש עוד מה לדעת על שמירה והסדרה של דגמי Keras, כולל מתן שיטות תצורה לשכבות מותאמות אישית לתמיכה בתכונות. עיין במדריך לשמירה והסדרה .

מה הלאה

אם אתה רוצה לדעת פרטים נוספים על Keras, אתה יכול לעקוב אחר מדריכי Keras הקיימים כאן .

דוגמה נוספת ל-API ברמה גבוהה הבנויה על tf.module היא Sonnet מ-DeepMind, אשר מכוסה באתר שלהם .