В моем предыдущем посте я рассмотрел вычислительные графы с помощью TensorFlow 1.0. Как мы узнали, эти графики стабильны и производительны, но необязательный способ работы с ними создает дополнительную когнитивную нагрузку на разработчиков.
С появлением TensorFlow 2.0 произошла смена парадигмы. В этом посте я остановлюсь на нескольких наиболее важных изменениях. К концу вы будете знать:
- Что такое нетерпеливое исполнение;
- Что такое AutoGraph;
- Когда и как используются и то, и другое.
Нетерпеливое исполнение
Графики TensorFlow, которые мы рассмотрели на прошлой неделе, не очень удобны для новичков, но TensorFlow 2.0 частично снижает трудности, поскольку по умолчанию поставляется с Eager Execution.
Фактически, активное выполнение было возможно в TensorFlow 1.0, но оно было введено как «простой режим» для обучения и экспериментов. Даже сейчас, в определенной степени, так оно и есть.
Мы можем активировать нетерпеливый режим в TensorFlow 1.0 с помощью следующего кода:
# TensorFlow 1.x only import tensorflow as tf tf.enable_eager_execution()
Но что такое режим нетерпения?
Определение нетерпеливого исполнения или нетерпеливого режима
Вот определение нетерпеливого исполнения из официальной документации:
Стремительное исполнение - это гибкая платформа машинного обучения для исследований и экспериментов, обеспечивающая:
Интуитивно понятный интерфейс - структурируйте свой код естественным образом и используйте структуры данных Python.
Упрощенная отладка - вызовите команду напрямую, чтобы проверить работающие модели и проверить изменения.
Естественный поток управления - используйте поток управления Python вместо потока управления графом.
Чтобы увидеть, как код Eager отличается от кода графика, давайте посмотрим на них в действии:
# TensorFlow 1.+ a = tf.constant([[1, 2],[3, 4]]) print(a) # output: # Tensor(“Const:0”, shape=(2, 2), dtype=int32)
Как видно из приведенного выше кода, мы не можем видеть значение a
, потому что оценка еще не запущена.
В режиме графика, который используется по умолчанию в TensorFlow 1.0, оценка происходит только после того, как мы заключили наш код в tf.Session.
Таким образом, оценке придется подождать, пока мы построим весь график, что довольно нелогично для новичков!
Мы также должны контролировать зависимости.
# only TensorFlow 1.x requires this statement to enable eager mode # for TensorFlow, eager mode is enabled by default. tf.enable_eager_execution() a = tf.constant([[1, 2],[3, 4]]) print(a) # output: # tf.Tensor([[1 2][3 4]], shape=(2, 2), dtype=int32)
Теперь мы можем увидеть значение переменной a
.
С Eager execution нам не нужен tf.Session для запуска нашего кода. Ого! Он ведет себя так же, как и любой другой код Python. Он прямой и интуитивно понятный. Мы можем использовать чистый Python if
, while
и for
в потоке управления. Легко свежий.
Если мы удалим связующий код графа вычислений, он перейдет в режим ожидания. В частности, я говорю об удалении следующего:
- tf.Session
- tf.Graph
- директивы потока управления (tf.if, tf. While, tf.control_depnedencies)
- заполнители
- инициализация переменной
- совместное использование переменных
При активном выполнении TensorFlow будет вычислять значения тензоров по мере их появления в вашем коде. Поскольку нет графиков в нетерпеливом исполнении, у нас не может быть магии графиков (автоматического дифференцирования). Мы должны полагаться на tf.GradientTape для записи операций.
Линейная регрессия с нетерпеливым исполнением
Вот пример линейной регрессии в TensorFlow 2.0 с нетерпеливым исполнением. Большая часть кода довольно проста и написана на Pythonic, и только tf.GradientTape является дополнительным необходимым шагом для вычисления градиентов.
# Training Data train_X = [3.3, 4.4, 5.5, 6.71, 6.93, 4.168, 9.779, 6.182, 7.59, 2.167, 7.042, 10.791, 5.313, 7.997, 5.654, 9.27, 3.1] train_Y = [1.7, 2.76, 2.09, 3.19, 1.694, 1.573, 3.366, 2.596, 2.53, 1.221, 2.827, 3.465, 1.65, 2.904, 2.42, 2.94, 1.3] n_samples = len(train_X) # Parameters learning_rate = 0.01 display_step = 100 num_steps = 1000 # Weight and Bias W = tfe.Variable(np.random.randn()) b = tfe.Variable(np.random.randn()) # Linear regression (Wx + b) def linear_regression(inputs): return inputs * W + b # Mean square error def mean_square_fn(model_fn, inputs, labels): return tf.reduce_sum(tf.pow(model_fn(inputs) - labels, 2)) / (2 * n_samples) # SGD Optimizer optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate) # Compute gradients grad = tfe.implicit_gradients(mean_square_fn) # Initial cost, before optimizing print("Initial cost= {:.9f}".format( mean_square_fn(linear_regression, train_X, train_Y)), "W=", W.numpy(), "b=", b.numpy()) # Training for step in range(num_steps): optimizer.apply_gradients(grad(linear_regression, train_X, train_Y)) if (step + 1) % display_step == 0 or step == 0: print("Epoch:", '%04d' % (step + 1), "cost=", "{:.9f}".format(mean_square_fn(linear_regression, train_X, train_Y)), "W=", W.numpy(), "b=", b.numpy()) # Graphic display plt.plot(train_X, train_Y, 'ro', label='Original data') plt.plot(train_X, np.array(W * train_X + b), label='Fitted line') plt.legend() plt.show()
Поскольку большая часть сложности исчезла, не следует ли нам просто отказаться от Graph mode
на Eager mode
? Ну, держи лошадей. Как и все новинки, «Стремительный режим» пока не готов для прайм-тайма.
В то время как активное выполнение делает разработку и отладку более интерактивными, выполнение графа в стиле TensorFlow 1.x имеет преимущества для распределенного обучения, оптимизации производительности и производственного развертывания.
Чтобы преодолеть разрыв между режимом нетерпения и режимом графика, TensorFlow 2.0 представляет некоторые полезные функции через API AutoGraph (tf.function).
Автограф
AutoGraph сочетает в себе простоту исполнения Eager и мощь Graphs.
Короче говоря, AutoGraph - это мини-компилятор, который преобразует подмножество синтаксиса Python в переносимые высокопроизводительные графики TensorFlow. Как видно ниже, AutoGraph реализован с помощью декоратора tf.function:
@tf.function def simpler_nn_layer(x,y): return tf.nn.relu(tf.matmul(x,y))
Простая функция, такая как simple_nn_layer
, будет перенесена в этот код графика.
Чтобы увидеть преобразованный код, мы можем использовать tf.autograph_to_code(simple_nn_layer)
, чтобы увидеть фактический сгенерированный код.
def tf__simpler_nn_layer(x, y): do_return = False retval_ = ag__.UndefinedReturnValue() with ag__.FunctionScope('simpler_nn_layer', 'simpler_nn_layer_scope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as simpler_nn_layer_scope: do_return = True retval_ = simpler_nn_layer_scope.mark_return_value(ag__.converted_call(tf.nn.relu, simpler_nn_layer_scope.callopts, (ag__.converted_call(tf.matmul, simpler_nn_layer_scope.callopts, (x, y), None, simpler_nn_layer_scope),), None, simpler_nn_layer_scope)) do_return, return ag__.retval(retval_)
AutoGraph рекомендует использовать функциональный стиль и неизменяемые коллекции Python. Это не совсем красиво, но эффективно.
Чтобы узнать больше об AutoGraph, ознакомьтесь с некоторыми полезными ресурсами, доступными в Интернете, например:
- Полный список ограничений;
- Чрезвычайно полезный Справочник по AutoGraph;
- Официальный документ RFC.
В итоге
Когда мы должны использовать TensorFlow 2.0 с нетерпением исполнения, а когда мы должны использовать AutoGraph?
Я думаю, что для исследования и экспериментов «Стремительное исполнение» - идеальный выбор. А для производства на данный момент наилучшими вариантами являются графики и автографы.
Сейчас прилагается много усилий, чтобы сделать режим Eager более функциональным, производительным и готовым к работе. В ближайшем будущем он может полностью заменить графический режим.
Одна из основных претензий к TensorFlow заключается в том, что он слишком низкоуровневый. Начиная с версии 2.0, TensorFlow рекомендует пользователям воспользоваться более доступным tf.keras более высокого уровня, о котором я расскажу в части 3. Следите за обновлениями!
Спасибо за внимание! Если вам понравилась эта статья, пожалуйста, нажимайте кнопку хлопка столько раз, сколько сможете. Это будет много значить и побудит меня продолжать делиться своими знаниями.
Не стесняйтесь делиться здесь своими вопросами и комментариями и подписывайтесь на меня, чтобы не пропустить последний контент!