Основы TensorFlow

Посмотреть на TensorFlow.org Запустить в Google Colab Посмотреть исходный код на 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>

Выполнение больших вычислений на ЦП может быть медленным. При правильной настройке TensorFlow может использовать аппаратные ускорители, такие как графические процессоры, для очень быстрого выполнения операций.

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

Подробную информацию см. в руководстве по тензору.

Переменные

Обычные объекты 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 .