Динамические и статические вычислительные графы в PyTorch и TensorFlow

Разница между статическими вычислительными графами в TensorFlow и динамическими вычислительными графами в Pytorch


Хотя обе библиотеки используют ориентированный ациклический граф (или DAG) для представления своих моделей машинного обучения и глубокого обучения, все же существует большая разница между тем, как они обрабатывают данные и как проходит вычисления через граф. Тонкое различие между двумя библиотеками заключается в том, что, хотя Tensorflow (v < 2.0) позволяет выполнять вычисления статического графа, Pytorch позволяет выполнять вычисления динамического графа. В этой статье эти различия будут представлены наглядно с примерами кода. Статья предполагает наличие практических знаний графов вычислений и базового понимания модулей TensorFlow и Pytorch. Для быстрого освежения в памяти этих концепций читателю предлагается просмотреть следующие статьи:

https://www.geeksforgeeks.org/computational-graphs-in-deep-learning/

Графы статических вычислений в Tensorflow
Свойства узлов и ребер.

Узлы представляют операции, которые применяются непосредственно к данным, входящим и исходящим через ребра. Работа с графами в TensorFlow :

  • Поскольку входные данные действуют как края графа, мы можем использовать объект tf.Placeholder(), который может принимать любые входные данные желаемого типа данных.
  • Для вычисления выходного значения «c» мы выполняем простую операцию умножения и запускаем сеанс tensorflow session, в которой мы передаем необходимые входные значения через атрибут feed_dict в методе session.run() для вычисления выходных данных и градиентов.

Теперь давайте реализуем приведенные выше вычисления в TensorFlow и посмотрим, как происходят операции:

#  импортируем tensorflow
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
  
# Initializing placeholder variables of
# the graph
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
  
# Defining the operation
c = tf.multiply(a, b)
  
# Instantiating a tensorflow session
with tf.Session() as sess:
  
    # Computing the output of the graph by giving
    # respective input values
    out = sess.run(, feed_dict={a: [15.0], b: [20.0]})[0][0]
  
    # Computing the output gradient of the output with
    # respect to the input 'a'
    derivative_out_a = sess.run(tf.gradients(c, a), feed_dict={
                                a: [15.0], b: [20.0]})[0][0]
  
    # Computing the output gradient of the output with
    # respect to the input 'b'
    derivative_out_b = sess.run(tf.gradients(c, b), feed_dict={
                                a: [15.0], b: [20.0]})[0][0]
  
    # Displaying the outputs
    print(f'c = {out}')
    print(f'Derivative of c with respect to a = {derivative_out_a}')
    print(f'Derivative of c with respect to b = {derivative_out_b}')

Вывод:

c = 300.0
Derivative of c with respect to a = 20.0
Derivative of c with respect to b = 15.0

Статическая структура очевидна из кода, так как мы можем видеть сеанс работы TF и не можем определить новые операции (или узлы), но мы, можем изменить входные переменные, используя атрибут feed_dict в sess.run() метод.

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

Недостатки:
– Плохо масштабируется для входных данных разного размера. Например, архитектура CNN (сверточной нейронной сети) со статическим графом вычислений, обученным на изображениях 28 × 28, не будет нормально работать на изображениях разных размеров, таких как 100 × 100, без большого количества шаблонного кода предварительной обработки.
– Плохая отладка.Такие графы очень сложно отлаживать, прежде всего потому, что у пользователя нет никакого доступа к тому, как происходит обработка данных. Предположим, что мы создаем статический граф, мы не может отслеживать ошибки напрямую, пока сеанс TensorFlow не обнаружит ошибку при вычислении. Это становится серьезной проблемой, когда модель огромна, поскольку мы тратим впустую как время, так и вычислительные ресурсы.

Графы динамических вычислений в Pytorch
Свойства узлов и ребер: узлы представляют данные (в виде тензоров), а ребра представляют операции, применяемые к входным данным.

 Реадизация в Pytorch:

– Поскольку все в Pytorch создается динамически, мы можем определять наши входные данные и операции на лету.
– После определения входных данных и вычисления выходного значения «с» мы вызовем метод reverse(), который вычислит соответствующие частные производные по входным данным, доступным через спецификатор .grad.
Теперь давайте посмотрим на это на примере кода:

# Importing torch
import torch
  
# Initializing input tensors
a = torch.tensor(15.0, requires_grad=True)
b = torch.tensor(20.0, requires_grad=True)
  
# Computing the output
c = a * b
  
# Computing the gradients
c.backward()
  
# Collecting the output gradient of the
# output with respect to the input 'a'
derivative_out_a = a.grad
  
# Collecting the output gradient of the
# output with respect to the input 'b'
derivative_out_b = b.grad
  
# Displaying the outputs
print(f'c = {c}')
print(f'Derivative of c with respect to a = {derivative_out_a}')
print(f'Derivative of c with respect to b = {derivative_out_b}')

Вывод:

c = 300.0
Derivative of c with respect to a = 20.0
Derivative of c with respect to b = 15.0

Динамическая структура видна в коде. Мы видим, что ко всем входным данным и выходу можно получить доступ и изменить их во время выполнения, что недоступно при использованим Tensorflow.

Преимущества:
Масштабируемость для различных объемных входных данных:

  • модель очень хорошо масштабируется для различных объемных входных данных, поскольку новый уровень предварительной обработки.
  • Простота отладки: модель очень легко отладить, и это одна из причин, по которой многие люди переходят с Tensorflow на Pytorch. С Pytorch легко отседить ошибки во время запуска модели.

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

Заключение
Эта статья проливает свет на разницу между структурой моделирования Tensorflow и Pytorch. В статье также перечислены некоторые преимущества и недостатки обоих подходов с примерами кода.

Ответить