آشنایی با ماژول ها ، لایه ها و مدل ها

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در 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__ وجود ندارد جز اینکه مانند پایتون قابل فراخوانی عمل کند. شما می توانید مدل های خود را با هر عملکردی که می خواهید فراخوانی کنید.

شما می توانید قابلیت آموزش متغیرها را به هر دلیلی روشن و خاموش کنید، از جمله انجماد لایه ها و متغیرها در هنگام تنظیم دقیق.

با زیرکلاس بندی 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 را هم به عنوان یک چک پوینت و هم به عنوان SavedModel ذخیره کنید.

چک پوینت ها فقط وزن ها هستند (یعنی مقادیر مجموعه ای از متغیرهای داخل ماژول و زیرماژول های آن):

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

می‌توانید به داخل یک چکپوینت نگاه کنید تا مطمئن شوید کل مجموعه متغیرها ذخیره شده‌اند، مرتب‌سازی شده توسط شی پایتون که آنها را در خود دارد.

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'). در این مورد، هر چند، تنها یک قطعه وجود دارد.

وقتی مدل‌ها را دوباره بارگذاری می‌کنید، مقادیر را در شی پایتون خود بازنویسی می‌کنید.

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 Serving و TensorFlow Lite نشان داده شده است، TensorFlow می تواند مدل ها را بدون اشیاء اصلی پایتون اجرا کند، حتی زمانی که یک مدل آموزش دیده را از TensorFlow Hub دانلود می کنید.

TensorFlow باید بداند که چگونه محاسبات توصیف شده در پایتون را بدون کد اصلی انجام دهد. برای انجام این کار، می توانید یک نمودار بسازید که در راهنمای معرفی نمودارها و توابع توضیح داده شده است.

این نمودار شامل عملیات یا عملیاتی است که تابع را پیاده سازی می کند.

می توانید با افزودن @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 کاربردی را توصیف می کند.

مدل‌ها و لایه‌ها را می‌توان از این نمایش بارگذاری کرد، بدون اینکه در واقع نمونه‌ای از کلاسی که آن را ایجاد کرده است، بسازیم. این مورد در شرایطی که مفسر پایتون ندارید (یا نمی خواهید) مانند سرویس دهی در مقیاس یا روی یک دستگاه لبه، یا در شرایطی که کد اصلی پایتون در دسترس نیست یا استفاده از آن کاربردی نیست، مطلوب است.

می توانید مدل را به عنوان شی جدید بارگذاری کنید:

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 به ارث می‌رسد.

فقط با تعویض والد و سپس تغییر __call__ برای call ، می توانید یک ماژول را به لایه Keras تبدیل کنید:

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 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 که به شما امکان می‌دهند پیکربندی‌ها را به دقت ذخیره کنید تا امکان شبیه‌سازی مدل در پایتون فراهم شود.

در راهنمای کامل لایه‌ها و مدل‌های سفارشی درباره آنها بخوانید.

مدل های کراس

شما می توانید مدل خود را به عنوان لایه های 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

مدل‌های 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 است که در سایت آنها پوشش داده شده است.