TensorFlow представляет выполнение точно в срок

машинное обучение искусственный интеллект TensorFlow глубокое обучение Нейронные сети
TensorFlow представляет выполнение точно в срок
Авторы: Асим Шанкар и Вольф Добсон, команда Google Brain

Сегодня мы объявляем о внедрении точного выполнения для TensorFlow. Немедленное выполнение — это определяемый запуском императивный интерфейс, в котором операции выполняются немедленно при вызове из Python. Это упрощает начало работы с TensorFlow и делает разработку более интуитивно понятной.

К преимуществам мгновенного исполнения относятся:
  • Быстрая отладка мгновенных ошибок во время выполнения и интеграция с инструментами Python
  • Поддерживает динамические модели с помощью простого в использовании потока управления Python.
  • Мощная поддержка пользовательских и расширенных градиентов
  • Работает практически со всеми доступными операциями TensorFlow.
Мгновенное выполнение в настоящее время доступно в качестве экспериментальной функции, поэтому мы хотим, чтобы отзывы сообщества направляли нашу работу.

Чтобы лучше понять эту функцию, давайте посмотрим на код. Это очень технично; знакомство с TensorFlow поможет.


Используйте мгновенное исполнение

Когда немедленное выполнение включено, операции будут выполняться немедленно и возвращать свои значения в Python без Session.run(). Например, чтобы перемножить две матрицы, мы можем написать такой код:
import tensorflow as tf
import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

x = [[2.]]
m = tf.matmul(x, x)
Проверить промежуточные результаты с помощью печати или отладчика Python несложно.
print(m)
# The 1x1 matrix [[4.]]
Динамические модели можно создавать с помощью управления потоком Python. Ниже приведена арифметическая операция с использованием TensorFlow.Гипотеза КоллардаПример:
a = tf.constant(12)
counter = 0
while not tf.equal(a, 1):
  if tf.equal(a % 2, 0):
    a = a / 2
  else:
    a = 3 * a + 1
  print(a)
Здесь использование тензорных объектов tf.constant(12) превращает все математические операции в тензорные операции, поэтому все возвращаемые значения являются тензорами.

Градиент

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

если вы знакомы сautogradpackage, вы обнаружите, что API будет очень похожим. Например:
def square(x):
  return tf.multiply(x, x)

grad = tfe.gradients_function(square)

print(square(3.))    # [9.]
print(grad(3.))      # [6.]
Вызов градиентной_функции принимает функцию квадрата Python в качестве аргумента и возвращает вызываемый объект Python, который может вычислять частные производные квадрата () из входных данных. Итак, чтобы получить производную от Square() со входом 3.0, вызовите grad(3.0), что равно 6.

Тот же вызов градиентной_функции можно использовать для получения квадрата второй производной:
gradgrad = tfe.gradients_function(lambda x: grad(x)[0])

print(gradgrad(3.))  # [2.]
Как упоминалось ранее, поток управления приводит к различным операциям, как показано в следующем примере.
def abs(x):
  return x if x > 0. else -x

grad = tfe.gradients_function(abs)

print(grad(2.0))  # [1.]
print(grad(-2.0)) # [-1.]

пользовательский градиент

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

В следующем примере демонстрируется использование пользовательских градиентов. Давайте сначала посмотрим на log(1 + ex), которая обычно используется для вычисления кросс-энтропии и логарифмического правдоподобия.
def log1pexp(x):
  return tf.log(1 + tf.exp(x))
grad_log1pexp = tfe.gradients_function(log1pexp)

# The gradient computation works fine at x = 0.
print(grad_log1pexp(0.))
# [0.5]
# However it returns a `nan` at x = 100 due to numerical instability.
print(grad_log1pexp(100.))
# [nan]
Мы можем использовать собственный градиент для вышеуказанной функции, чтобы аналитически упростить выражение градиента. Обратите внимание, что приведенная ниже реализация функции градиента повторно использует выражение (tf.exp(x)), вычисленное во время прямого прохода, повышая эффективность вычисления градиента за счет исключения избыточных вычислений.
@tfe.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.log(1 + e), grad
grad_log1pexp = tfe.gradients_function(log1pexp)

# Gradient at x = 0 works as before.
print(grad_log1pexp(0.))
# [0.5]
# And now gradient computation at x=100 works as well.
print(grad_log1pexp(100.))
# [1.0]

Построить модель

Модели можно разделить на несколько категорий. Следующий класс модели создает (простую) двухслойную сеть для классификации стандартных рукописных цифр MNIST.
class MNISTModel(tfe.Network):
  def __init__(self):
    super(MNISTModel, self).__init__()
    self.layer1 = self.track_layer(tf.layers.Dense(units=10))
    self.layer2 = self.track_layer(tf.layers.Dense(units=10))
  def call(self, input):
    """Actually runs the model."""
    result = self.layer1(input)
    result = self.layer2(result)
    return result
Поскольку tf.layer создает и содержит параметры модели (переменные), мы рекомендуем использовать классы в tf.layer вместо функций. Время жизни переменных привязано к времени жизни объектов слоя, поэтому важно их отслеживать.

Зачем использовать tfe.Network? Сеть является контейнером слоев и сама является tf.layer.Layer, так что объекты сети могут быть встроены в другие объекты сети. Он также содержит утилиты для проверки, сохранения и восстановления.

Даже без обучения модели мы можем вызвать ее императивно и проверить вывод:
# Let's make up a blank input image
model = MNISTModel()
batch = tf.zeros([1, 1, 784])
print(batch.shape)
# (1, 1, 784)
result = model(batch)
print(result)
# tf.Tensor([[[ 0.  0., ...., 0.]]], shape=(1, 1, 10), dtype=float32)
Обратите внимание, что нам не нужны никакие заполнители или сеансы. Размер параметров слоя устанавливается при первом входе.

Чтобы обучить любую модель, нам нужно определить функцию потерь для оптимизации, вычислить градиенты и использовать оптимизатор для обновления переменных. Во-первых, вот функция потерь:
def loss_function(model, x, y):
  y_ = model(x)
  return tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=y_)
Тогда наш тренировочный цикл выглядит так:
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
for (x, y) in tfe.Iterator(dataset):
  grads = tfe.implicit_gradients(loss_function)(model, x, y)
  optimizer.apply_gradients(grads)
implicit_gradients() будет вычислять производную функции loss_function по отношению ко всем переменным TensorFlow, используемым во время вычислений.

Мы можем перенести вычисления на GPU так же, как обычно делаем с TensorFlow:
with tf.device("/gpu:0"):
  for (x, y) in tfe.Iterator(dataset):
    optimizer.minimize(lambda: loss_function(model, x, y))
(Примечание: мы упростили хранение функции потерь и вызвали optimizer.minimize напрямую, однако вы также можете использовать приведенную выше функцию apply_gradients(); они эквивалентны.)

Использование мгновенного исполнения с графиками

Своевременное выполнение делает разработку и отладку более интерактивными, однако графы TensorFlow также имеют много преимуществ для распределенного обучения, оптимизации производительности и производственного развертывания.

Тот же код, который выполняет операцию с включенным немедленным выполнением, построит график, иллюстрирующий вычисление без включенного немедленного выполнения. Чтобы преобразовать вашу модель в график, просто запустите тот же код в новом сеансе Python без включения мгновенного выполнения, как мы сделали впример MNISTтак же, как видно в. Значения переменных модели можно сохранять и восстанавливать из контрольных точек, что позволяет легко переключаться между немедленным (императивным) и графовым (декларативным) программированием. Поэтому модели, разработанные с включенным мгновенным выполнением, можно легко экспортировать для производственного развертывания.

В ближайшем будущем мы предоставим утилиты, которые позволят вам выборочно преобразовывать части ваших моделей в диаграммы. Таким образом, вы можете объединять части вычислений (например, настройку внутренних элементов ячеек RNN) для достижения высокой производительности, сохраняя при этом гибкость и удобочитаемость выполнения «на лету».

Как я могу переписать свой код?

Использование точного выполнения должно быть интуитивно понятным для текущих пользователей TensorFlow. В настоящее время существует лишь несколько API, специфичных для мгновенного выполнения; большинство существующих API и операций подходят для мгновенного выполнения. Вот некоторые аспекты, о которых следует знать:
  • Как мы обычно рекомендуем для TensorFlow, если вы еще не перешли от очередей к использованию tf.data для обработки ввода, мы рекомендуем сделать это сейчас. TensorFlow проще в использовании и, как правило, быстрее. Для справки см.этот пост в блогеиСтраница документации.
  • Используйте объектно-ориентированные слои, такие как tf.layer.Conv2D() или слои Keras; эти слои могут явно хранить переменные.
  • Для большинства моделей вы можете написать код, который работает как на лету, так и при построении графика. Есть некоторые исключения, такие как динамические модели, которые используют поток управления Python для изменения вычислений на основе входных данных.
  • Как только вы вызовете tfe.enable_eager_execution(), его нельзя будет закрыть. Чтобы получить поведение графика, запустите новый сеанс Python.

Начало и будущее

Это все еще предварительная версия, поэтому вы можете столкнуться с несколькими не такими, как ожидалось. Если вы хотите начать прямо сейчас, сделайте следующее:
Нам есть, чем поделиться с вами о мгновенном исполнении, и мы очень рады, или очень счастливы.жаждущийВы можете попробовать эту функцию прямо сейчас. Тепло приветствуем всех предоставитьОбратная связь.