יסודות TensorFlow

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

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

TensorFlow היא פלטפורמה מקצה לקצה ללמידת מכונה. הוא תומך בדברים הבאים:

  • חישוב מספרי מבוסס מערך רב-ממדי (בדומה ל- NumPy .)
  • GPU ועיבוד מבוזר
  • בידול אוטומטי
  • בניית דגמים, הדרכה ויצוא
  • ועוד

טנזורים

TensorFlow פועל על מערכים או טנסורים רב-ממדיים המיוצגים tf.Tensor . הנה טנזור דו מימדי:

import tensorflow as tf

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

print(x)
print(x.shape)
print(x.dtype)
tf.Tensor(
[[1. 2. 3.]
 [4. 5. 6.]], shape=(2, 3), dtype=float32)
(2, 3)
<dtype: 'float32'>

התכונות החשובות ביותר של tf.Tensor הן shape וה- dtype שלו:

  • Tensor.shape : אומר לך את גודל הטנזור לאורך כל אחד מהצירים שלו.
  • Tensor.dtype : אומר לך את סוג כל האלמנטים בטנזור.

TensorFlow מיישמת פעולות מתמטיות סטנדרטיות על טנסורים, כמו גם פעולות רבות המתמחות ללמידת מכונה.

לדוגמה:

x + x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]], dtype=float32)>
5 * x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 5., 10., 15.],
       [20., 25., 30.]], dtype=float32)>
x @ tf.transpose(x)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[14., 32.],
       [32., 77.]], dtype=float32)>
tf.concat([x, x, x], axis=0)
<tf.Tensor: shape=(6, 3), dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
tf.nn.softmax(x, axis=-1)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0.09003057, 0.24472848, 0.6652409 ],
       [0.09003057, 0.24472848, 0.6652409 ]], dtype=float32)>
tf.reduce_sum(x)
<tf.Tensor: shape=(), dtype=float32, numpy=21.0>

הפעלת חישובים גדולים ב-CPU יכולה להיות איטית. כאשר מוגדר כהלכה, TensorFlow יכול להשתמש בחומרת מאיץ כמו GPUs כדי לבצע פעולות במהירות רבה.

if tf.config.list_physical_devices('GPU'):
  print("TensorFlow **IS** using the GPU")
else:
  print("TensorFlow **IS NOT** using the GPU")
TensorFlow **IS** using the GPU

עיין במדריך Tensor לפרטים.

משתנים

אובייקטים tf.Tensor רגילים אינם ניתנים לשינוי. כדי לאחסן משקלי דגם (או מצב אחר שניתן לשינוי) ב-TensorFlow השתמש ב- tf.Variable .

var = tf.Variable([0.0, 0.0, 0.0])
var.assign([1, 2, 3])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>
var.assign_add([1, 1, 1])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([2., 3., 4.], dtype=float32)>

עיין במדריך המשתנים לפרטים.

בידול אוטומטי

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

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

x = tf.Variable(1.0)

def f(x):
  y = x**2 + 2*x - 5
  return y
f(x)
<tf.Tensor: shape=(), dtype=float32, numpy=-2.0>

ב- x = 1.0 , y = f(x) = (1**2 + 2*1 - 5) = -2 .

הנגזרת של y היא y' = f'(x) = (2*x + 2) = 4 . TensorFlow יכול לחשב זאת באופן אוטומטי:

with tf.GradientTape() as tape:
  y = f(x)

g_x = tape.gradient(y, x)  # g(x) = dy/dx

g_x
<tf.Tensor: shape=(), dtype=float32, numpy=4.0>

דוגמה מפושטת זו לוקחת את הנגזרת רק ביחס לסקלרי בודד ( x ), אך TensorFlow יכול לחשב את הגרדיאנט ביחס לכל מספר של טנסורים לא סקלרים בו זמנית.

עיין במדריך Autodiff לפרטים.

גרפים ו-tf.function

בעוד שאתה יכול להשתמש ב-TensorFlow באופן אינטראקטיבי כמו כל ספריית Python, TensorFlow מספקת גם כלים עבור:

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

אלה דורשים שתשתמש ב- tf.function כדי להפריד את קוד TensorFlow הטהור שלך מ-Python.

@tf.function
def my_func(x):
  print('Tracing.\n')
  return tf.reduce_sum(x)

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

x = tf.constant([1, 2, 3])
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=int32, numpy=6>

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

x = tf.constant([10, 9, 8])
my_func(x)
<tf.Tensor: shape=(), dtype=int32, numpy=27>

ייתכן שגרף אינו ניתן לשימוש חוזר עבור קלט עם חתימה אחרת ( shape ו- dtype ), ולכן במקום זאת נוצר גרף חדש:

x = tf.constant([10.0, 9.1, 8.2], dtype=tf.float32)
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=float32, numpy=27.3>

הגרפים המצולמים הללו מספקים שני יתרונות:

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

עיין במבוא לגרפים לפרטים נוספים.

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

tf.Module הוא מחלקה לניהול אובייקטי tf.Variable שלך, ואובייקטי tf.function שפועלים עליהם. המחלקה tf.Module נחוצה כדי לתמוך בשתי תכונות משמעותיות:

  1. אתה יכול לשמור ולשחזר את הערכים של המשתנים שלך באמצעות tf.train.Checkpoint . זה שימושי במהלך האימון מכיוון שהוא מהיר לשמור ולשחזר את מצב הדגם.
  2. אתה יכול לייבא ולייצא את ערכי tf.Variable ואת גרפי tf.function באמצעות tf.saved_model . זה מאפשר לך להפעיל את המודל שלך ללא תלות בתוכנית Python שיצרה אותו.

הנה דוגמה מלאה לייצוא אובייקט tf.Module פשוט:

class MyModule(tf.Module):
  def __init__(self, value):
    self.weight = tf.Variable(value)

  @tf.function
  def multiply(self, x):
    return x * self.weight
mod = MyModule(3)
mod.multiply(tf.constant([1, 2, 3]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

שמור את Module :

save_path = './saved'
tf.saved_model.save(mod, save_path)
INFO:tensorflow:Assets written to: ./saved/assets
2022-01-19 02:29:48.135588: 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.

SavedModel המתקבל אינו תלוי בקוד שיצר אותו. אתה יכול לטעון SavedModel מ-Python, כריכות שפות אחרות או TensorFlow Serving . אתה יכול גם להמיר אותו להפעלה עם TensorFlow Lite או TensorFlow JS .

reloaded = tf.saved_model.load(save_path)
reloaded.multiply(tf.constant([1, 2, 3]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

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

עיין במבוא למודולים לפרטים.

לולאות אימון

כעת חבר את כל זה יחד כדי לבנות מודל בסיסי ולאמן אותו מאפס.

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

import matplotlib
from matplotlib import pyplot as plt

matplotlib.rcParams['figure.figsize'] = [9, 6]
x = tf.linspace(-2, 2, 201)
x = tf.cast(x, tf.float32)

def f(x):
  y = x**2 + 2*x - 5
  return y

y = f(x) + tf.random.normal(shape=[201])

plt.plot(x.numpy(), y.numpy(), '.', label='Data')
plt.plot(x, f(x),  label='Ground truth')
plt.legend();

png

צור דגם:

class Model(tf.keras.Model):
  def __init__(self, units):
    super().__init__()
    self.dense1 = tf.keras.layers.Dense(units=units,
                                        activation=tf.nn.relu,
                                        kernel_initializer=tf.random.normal,
                                        bias_initializer=tf.random.normal)
    self.dense2 = tf.keras.layers.Dense(1)

  def call(self, x, training=True):
    # For Keras layers/models, implement `call` instead of `__call__`.
    x = x[:, tf.newaxis]
    x = self.dense1(x)
    x = self.dense2(x)
    return tf.squeeze(x, axis=1)
model = Model(64)
plt.plot(x.numpy(), y.numpy(), '.', label='data')
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Untrained predictions')
plt.title('Before training')
plt.legend();

png

כתוב לולאת אימון בסיסית:

variables = model.variables

optimizer = tf.optimizers.SGD(learning_rate=0.01)

for step in range(1000):
  with tf.GradientTape() as tape:
    prediction = model(x)
    error = (y-prediction)**2
    mean_error = tf.reduce_mean(error)
  gradient = tape.gradient(mean_error, variables)
  optimizer.apply_gradients(zip(gradient, variables))

  if step % 100 == 0:
    print(f'Mean squared error: {mean_error.numpy():0.3f}')
Mean squared error: 16.123
Mean squared error: 0.997
Mean squared error: 0.964
Mean squared error: 0.946
Mean squared error: 0.932
Mean squared error: 0.921
Mean squared error: 0.913
Mean squared error: 0.907
Mean squared error: 0.901
Mean squared error: 0.897
plt.plot(x.numpy(),y.numpy(), '.', label="data")
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Trained predictions')
plt.title('After training')
plt.legend();

png

זה עובד, אבל זכור שהטמעות של כלי אימון נפוצים זמינים במודול tf.keras . אז שקול להשתמש באלו לפני שאתה כותב משלך. ראשית, השיטות Model.compile ו- Model.fit מיישמות עבורך לולאת אימון:

new_model = Model(64)
new_model.compile(
    loss=tf.keras.losses.MSE,
    optimizer=tf.optimizers.SGD(learning_rate=0.01))

history = new_model.fit(x, y,
                        epochs=100,
                        batch_size=32,
                        verbose=0)

model.save('./my_model')
INFO:tensorflow:Assets written to: ./my_model/assets
plt.plot(history.history['loss'])
plt.xlabel('Epoch')
plt.ylim([0, max(plt.ylim())])
plt.ylabel('Loss [Mean Squared Error]')
plt.title('Keras training progress');

png

עיין בלולאות אימון בסיסיות ובמדריך Keras לפרטים נוספים.