حلقه های آموزشی اولیه

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

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

TensorFlow همچنین شامل tf.Keras API است، یک API شبکه عصبی سطح بالا که انتزاعات مفیدی را برای کاهش صفحه دیگ ارائه می دهد. با این حال، در این راهنما، شما از کلاس های پایه استفاده خواهید کرد.

برپایی

import tensorflow as tf

import matplotlib.pyplot as plt

colors = plt.rcParams['axes.prop_cycle'].by_key()['color']

حل مشکلات یادگیری ماشین

حل مشکل یادگیری ماشین معمولاً شامل مراحل زیر است:

  • داده های آموزشی را به دست آورید
  • مدل را تعریف کنید.
  • یک تابع ضرر را تعریف کنید.
  • داده های آموزشی را اجرا کنید و ضرر را از مقدار ایده آل محاسبه کنید
  • گرادیان ها را برای آن ضرر محاسبه کنید و از یک بهینه ساز برای تنظیم متغیرها برای تناسب با داده ها استفاده کنید.
  • نتایج خود را ارزیابی کنید

برای اهداف تصویری، در این راهنما شما یک مدل خطی ساده، \(f(x) = x * W + b\)را ایجاد خواهید کرد که دارای دو متغیر است: \(W\) (وزن ها) و \(b\) (طرفداری).

این ابتدایی ترین مشکلات یادگیری ماشین است: با توجه به \(x\) و \(y\)، سعی کنید شیب و افست یک خط را از طریق رگرسیون خطی ساده پیدا کنید.

داده ها

یادگیری تحت نظارت از ورودی‌ها (معمولاً x نشان داده می‌شود) و خروجی‌ها (با نشان‌دادن y که اغلب برچسب‌ها نامیده می‌شود) استفاده می‌کند. هدف یادگیری از ورودی ها و خروجی های جفت شده است تا بتوانید مقدار یک خروجی را از یک ورودی پیش بینی کنید.

هر ورودی از داده‌های شما، در TensorFlow، تقریباً همیشه با یک تانسور نشان داده می‌شود و اغلب یک بردار است. در آموزش نظارت شده، خروجی (یا مقداری که می‌خواهید پیش‌بینی کنید) نیز یک تانسور است.

در اینجا برخی از داده ها با افزودن نویز گاوسی (نرمال) به نقاط در امتداد یک خط سنتز شده است.

# The actual line
TRUE_W = 3.0
TRUE_B = 2.0

NUM_EXAMPLES = 201

# A vector of random x values
x = tf.linspace(-2,2, NUM_EXAMPLES)
x = tf.cast(x, tf.float32)

def f(x):
  return x * TRUE_W + TRUE_B

# Generate some noise
noise = tf.random.normal(shape=[NUM_EXAMPLES])

# Calculate y
y = f(x) + noise
# Plot all the data
plt.plot(x, y, '.')
plt.show()

png

تانسورها معمولاً به صورت دسته‌ای با هم جمع می‌شوند ، یا گروه‌هایی از ورودی‌ها و خروجی‌ها روی هم چیده می‌شوند. دسته‌بندی می‌تواند برخی از مزایای آموزشی را به همراه داشته باشد و با شتاب‌دهنده‌ها و محاسبات برداری به خوبی کار می‌کند. با توجه به اینکه این مجموعه داده چقدر کوچک است، می توانید کل مجموعه داده را به عنوان یک دسته واحد در نظر بگیرید.

مدل را تعریف کنید

از tf.Variable برای نمایش تمام وزن ها در یک مدل استفاده کنید. یک tf.Variable یک مقدار را ذخیره می کند و در صورت نیاز آن را به شکل تانسور ارائه می دهد. برای جزئیات بیشتر به راهنمای متغیر مراجعه کنید.

از tf.Module برای کپسوله کردن متغیرها و محاسبات استفاده کنید. شما می توانید از هر شی پایتون استفاده کنید، اما به این ترتیب می توان آن را به راحتی ذخیره کرد.

در اینجا، شما هم w و هم b را به عنوان متغیر تعریف می کنید.

class MyModel(tf.Module):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    # Initialize the weights to `5.0` and the bias to `0.0`
    # In practice, these should be randomly initialized
    self.w = tf.Variable(5.0)
    self.b = tf.Variable(0.0)

  def __call__(self, x):
    return self.w * x + self.b

model = MyModel()

# List the variables tf.modules's built-in variable aggregation.
print("Variables:", model.variables)

# Verify the model works
assert model(3.0).numpy() == 15.0
Variables: (<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=5.0>)
2021-12-08 17:11:44.542944: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.

متغیرهای اولیه در اینجا به روشی ثابت تنظیم شده‌اند، اما Keras با هر یک از تعداد اولیه‌کننده‌هایی که می‌توانید استفاده کنید، با یا بدون بقیه Keras ارائه می‌شود.

یک تابع ضرر را تعریف کنید

یک تابع ضرر اندازه گیری می کند که چگونه خروجی یک مدل برای یک ورودی داده شده با خروجی هدف مطابقت دارد. هدف این است که این تفاوت در طول تمرین به حداقل برسد. از دست دادن استاندارد L2 را که به عنوان خطای میانگین مربع نیز شناخته می شود، تعریف کنید:

# This computes a single loss value for an entire batch
def loss(target_y, predicted_y):
  return tf.reduce_mean(tf.square(target_y - predicted_y))

قبل از آموزش مدل، می‌توانید با ترسیم پیش‌بینی‌های مدل به رنگ قرمز و داده‌های آموزشی به رنگ آبی، مقدار ضرر را تجسم کنید:

plt.plot(x, y, '.', label="Data")
plt.plot(x, f(x), label="Ground truth")
plt.plot(x, model(x), label="Predictions")
plt.legend()
plt.show()

print("Current loss: %1.6f" % loss(y, model(x)).numpy())

png

Current loss: 10.301712

یک حلقه آموزشی تعریف کنید

حلقه آموزش شامل انجام مکرر سه کار به ترتیب است:

  • ارسال دسته ای از ورودی ها از طریق مدل برای تولید خروجی
  • محاسبه ضرر با مقایسه خروجی ها با خروجی (یا برچسب)
  • استفاده از نوار گرادیان برای یافتن گرادیان ها
  • بهینه سازی متغیرها با آن گرادیان ها

برای این مثال، می‌توانید مدل را با استفاده از گرادیان نزول آموزش دهید.

انواع زیادی از طرح نزول گرادیان وجود دارد که در tf.keras.optimizers شده است. اما با روحیه ساختن از اصول اولیه، در اینجا شما ریاضیات پایه را خودتان با کمک tf.GradientTape برای تمایز خودکار و tf.assign_sub برای کاهش یک مقدار (که tf.assign و tf.sub را ترکیب می‌کند) پیاده‌سازی می‌کنید:

# Given a callable model, inputs, outputs, and a learning rate...
def train(model, x, y, learning_rate):

  with tf.GradientTape() as t:
    # Trainable variables are automatically tracked by GradientTape
    current_loss = loss(y, model(x))

  # Use GradientTape to calculate the gradients with respect to W and b
  dw, db = t.gradient(current_loss, [model.w, model.b])

  # Subtract the gradient scaled by the learning rate
  model.w.assign_sub(learning_rate * dw)
  model.b.assign_sub(learning_rate * db)

برای نگاهی به آموزش، می توانید همان دسته x و y را از طریق حلقه آموزشی ارسال کنید و ببینید W و b چگونه تکامل می یابند.

model = MyModel()

# Collect the history of W-values and b-values to plot later
weights = []
biases = []
epochs = range(10)

# Define a training loop
def report(model, loss):
  return f"W = {model.w.numpy():1.2f}, b = {model.b.numpy():1.2f}, loss={current_loss:2.5f}"


def training_loop(model, x, y):

  for epoch in epochs:
    # Update the model with the single giant batch
    train(model, x, y, learning_rate=0.1)

    # Track this before I update
    weights.append(model.w.numpy())
    biases.append(model.b.numpy())
    current_loss = loss(y, model(x))

    print(f"Epoch {epoch:2d}:")
    print("    ", report(model, current_loss))

آموزش را انجام دهید

current_loss = loss(y, model(x))

print(f"Starting:")
print("    ", report(model, current_loss))

training_loop(model, x, y)
Starting:
     W = 5.00, b = 0.00, loss=10.30171
Epoch  0:
     W = 4.46, b = 0.40, loss=10.30171
Epoch  1:
     W = 4.06, b = 0.72, loss=10.30171
Epoch  2:
     W = 3.77, b = 0.97, loss=10.30171
Epoch  3:
     W = 3.56, b = 1.18, loss=10.30171
Epoch  4:
     W = 3.40, b = 1.34, loss=10.30171
Epoch  5:
     W = 3.29, b = 1.47, loss=10.30171
Epoch  6:
     W = 3.21, b = 1.58, loss=10.30171
Epoch  7:
     W = 3.15, b = 1.66, loss=10.30171
Epoch  8:
     W = 3.10, b = 1.73, loss=10.30171
Epoch  9:
     W = 3.07, b = 1.78, loss=10.30171

تکامل وزن ها را در طول زمان ترسیم کنید:

plt.plot(epochs, weights, label='Weights', color=colors[0])
plt.plot(epochs, [TRUE_W] * len(epochs), '--',
         label = "True weight", color=colors[0])

plt.plot(epochs, biases, label='bias', color=colors[1])
plt.plot(epochs, [TRUE_B] * len(epochs), "--",
         label="True bias", color=colors[1])

plt.legend()
plt.show()

png

نحوه عملکرد مدل آموزش دیده را تجسم کنید

plt.plot(x, y, '.', label="Data")
plt.plot(x, f(x), label="Ground truth")
plt.plot(x, model(x), label="Predictions")
plt.legend()
plt.show()

print("Current loss: %1.6f" % loss(model(x), y).numpy())

png

Current loss: 0.897898

همان راه حل، اما با Keras

مغایرت کد بالا با معادل آن در Keras مفید است.

اگر زیر کلاس tf.keras.Model را تعریف کنید دقیقاً یکسان به نظر می رسد. به یاد داشته باشید که مدل‌های Keras در نهایت از ماژول به ارث می‌برند.

class MyModelKeras(tf.keras.Model):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    # Initialize the weights to `5.0` and the bias to `0.0`
    # In practice, these should be randomly initialized
    self.w = tf.Variable(5.0)
    self.b = tf.Variable(0.0)

  def call(self, x):
    return self.w * x + self.b

keras_model = MyModelKeras()

# Reuse the training loop with a Keras model
training_loop(keras_model, x, y)

# You can also save a checkpoint using Keras's built-in support
keras_model.save_weights("my_checkpoint")
Epoch  0:
     W = 4.46, b = 0.40, loss=10.30171
Epoch  1:
     W = 4.06, b = 0.72, loss=10.30171
Epoch  2:
     W = 3.77, b = 0.97, loss=10.30171
Epoch  3:
     W = 3.56, b = 1.18, loss=10.30171
Epoch  4:
     W = 3.40, b = 1.34, loss=10.30171
Epoch  5:
     W = 3.29, b = 1.47, loss=10.30171
Epoch  6:
     W = 3.21, b = 1.58, loss=10.30171
Epoch  7:
     W = 3.15, b = 1.66, loss=10.30171
Epoch  8:
     W = 3.10, b = 1.73, loss=10.30171
Epoch  9:
     W = 3.07, b = 1.78, loss=10.30171

به جای نوشتن حلقه های آموزشی جدید هر بار که یک مدل ایجاد می کنید، می توانید از ویژگی های داخلی Keras به عنوان میانبر استفاده کنید. این می تواند زمانی مفید باشد که نمی خواهید حلقه های آموزشی پایتون را بنویسید یا اشکال زدایی کنید.

اگر این کار را انجام دادید، باید از model.compile() برای تنظیم پارامترها و model.fit() برای آموزش استفاده کنید. استفاده از پیاده‌سازی Keras از L2 از دست دادن و نزول گرادیان، دوباره به‌عنوان میان‌بر، می‌تواند کد کمتری داشته باشد. تلفات و بهینه سازهای Keras را می توان خارج از این توابع راحتی نیز استفاده کرد و مثال قبلی می توانست از آنها استفاده کند.

keras_model = MyModelKeras()

# compile sets the training parameters
keras_model.compile(
    # By default, fit() uses tf.function().  You can
    # turn that off for debugging, but it is on now.
    run_eagerly=False,

    # Using a built-in optimizer, configuring as an object
    optimizer=tf.keras.optimizers.SGD(learning_rate=0.1),

    # Keras comes with built-in MSE error
    # However, you could use the loss function
    # defined above
    loss=tf.keras.losses.mean_squared_error,
)

Keras fit داده های دسته ای یا مجموعه داده کامل را به عنوان یک آرایه NumPy انتظار دارد. آرایه‌های NumPy به دسته‌ای خرد شده و به‌طور پیش‌فرض به اندازه دسته‌ای 32 است.

در این مورد، برای مطابقت با رفتار حلقه دست نویس، باید x را به عنوان یک دسته به اندازه 1000 ارسال کنید.

print(x.shape[0])
keras_model.fit(x, y, epochs=10, batch_size=1000)
201
Epoch 1/10
1/1 [==============================] - 0s 242ms/step - loss: 10.3017
Epoch 2/10
1/1 [==============================] - 0s 3ms/step - loss: 6.3148
Epoch 3/10
1/1 [==============================] - 0s 3ms/step - loss: 4.0341
Epoch 4/10
1/1 [==============================] - 0s 3ms/step - loss: 2.7191
Epoch 5/10
1/1 [==============================] - 0s 3ms/step - loss: 1.9548
Epoch 6/10
1/1 [==============================] - 0s 2ms/step - loss: 1.5068
Epoch 7/10
1/1 [==============================] - 0s 3ms/step - loss: 1.2422
Epoch 8/10
1/1 [==============================] - 0s 2ms/step - loss: 1.0845
Epoch 9/10
1/1 [==============================] - 0s 2ms/step - loss: 0.9899
Epoch 10/10
1/1 [==============================] - 0s 3ms/step - loss: 0.9327
<keras.callbacks.History at 0x7f02ad940050>

توجه داشته باشید که Keras باخت را بعد از تمرین چاپ می کند، نه قبل از آن، بنابراین ضرر اول کمتر به نظر می رسد، اما در غیر این صورت اساساً همان عملکرد تمرینی را نشان می دهد.

مراحل بعدی

در این راهنما، نحوه استفاده از کلاس‌های اصلی تانسورها، متغیرها، ماژول‌ها و نوار گرادیان برای ساخت و آموزش یک مدل، و نحوه نگاشت آن ایده‌ها به Keras را مشاهده کرده‌اید.

با این حال، این یک مشکل بسیار ساده است. برای مقدمه عملی تر، به راهنمای آموزش سفارشی مراجعه کنید.

برای اطلاعات بیشتر در مورد استفاده از حلقه‌های آموزشی داخلی Keras، به این راهنما مراجعه کنید. برای اطلاعات بیشتر در مورد حلقه های آموزشی و Keras، به این راهنما مراجعه کنید. برای نوشتن حلقه های آموزشی توزیع شده سفارشی، به این راهنما مراجعه کنید.