بهینه سازی نمودار TensorFlow با Grappler

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

بررسی اجمالی

TensorFlow از هر دو گراف و اجرای مشتاق برای اجرای محاسبات استفاده می کند. یک tf.Graph شامل مجموعه ای از اشیاء tf.Operation (ops) است که واحدهای محاسباتی را نشان می دهد و اشیاء tf.Tensor که واحدهای داده ای را نشان می دهد که بین عملیات جریان دارد.

Grappler سیستم بهینه سازی نمودار پیش فرض در زمان اجرا TensorFlow است. Grappler بهینه‌سازی‌ها را در حالت نمودار (در داخل tf.function ) برای بهبود عملکرد محاسبات TensorFlow از طریق ساده‌سازی گراف و دیگر بهینه‌سازی‌های سطح بالا مانند توابع درونی برای فعال کردن بهینه‌سازی‌های بین رویه‌ای اعمال می‌کند. بهینه‌سازی tf.Graph همچنین میزان استفاده از حافظه دستگاه را کاهش می‌دهد و با بهینه‌سازی نگاشت گره‌های گراف برای محاسبه منابع، استفاده از سخت‌افزار را بهبود می‌بخشد.

از tf.config.optimizer.set_experimental_options() برای کنترل دقیق تر روی بهینه سازی tf.Graph خود استفاده کنید.

بهینه سازهای گراف موجود

Grappler بهینه سازی نمودار را از طریق یک درایور سطح بالا به نام MetaOptimizer انجام می دهد. بهینه سازهای نمودار زیر با TensorFlow در دسترس هستند:

  • بهینه ساز تاشو ثابت - به صورت ایستا مقدار تانسورها را در صورت امکان با تا کردن گره های ثابت در نمودار استنباط می کند و نتیجه را با استفاده از ثابت ها تحقق می بخشد.
  • بهینه ساز حسابی - عملیات حسابی را با حذف عبارات فرعی رایج و ساده کردن عبارات حسابی ساده می کند.
  • بهینه‌ساز چیدمان - طرح‌بندی‌های تانسور را بهینه می‌کند تا عملیات‌های وابسته به قالب داده‌ها مانند کانولوشن‌ها را با کارایی بیشتری اجرا کند.
  • بهینه ساز Remapper - با جایگزین کردن زیرگراف های رایج با هسته های یکپارچه ذوب شده بهینه سازی شده، زیرگراف ها را به پیاده سازی های کارآمدتر تغییر می دهد.
  • بهینه ساز حافظه - نمودار را تجزیه و تحلیل می کند تا حداکثر مصرف حافظه را برای هر عملیات بررسی کند و عملیات کپی حافظه CPU-GPU را برای تعویض حافظه GPU به CPU وارد می کند تا حداکثر مصرف حافظه را کاهش دهد.
  • بهینه ساز وابستگی - وابستگی های کنترل را حذف یا مرتب می کند تا مسیر بحرانی یک مرحله مدل را کوتاه کند یا بهینه سازی های دیگر را فعال می کند. همچنین گره هایی را که عملاً بدون عملیات هستند مانند Identity حذف می کند.
  • بهینه ساز هرس - گره هایی را که هیچ تأثیری بر خروجی نمودار ندارند، هرس می کند. معمولاً ابتدا برای کاهش اندازه نمودار و سرعت بخشیدن به پردازش در سایر پاس های Grappler اجرا می شود.
  • بهینه‌ساز توابع - کتابخانه توابع یک برنامه TensorFlow را بهینه می‌کند و بدنه‌های تابع را برای فعال کردن سایر بهینه‌سازی‌های بین رویه‌ای بهینه می‌کند.
  • بهینه ساز شکل - زیرگراف هایی را که بر روی اطلاعات مربوط به شکل و شکل کار می کنند بهینه می کند.
  • بهینه‌ساز موازی خودکار - به‌طور خودکار نمودارها را با تقسیم در امتداد ابعاد دسته‌ای موازی می‌کند. این بهینه ساز به طور پیش فرض خاموش است.
  • بهینه ساز حلقه - جریان کنترل گراف را با بلند کردن زیرگراف های ثابت حلقه از حلقه ها و با حذف عملیات پشته اضافی در حلقه ها بهینه می کند. همچنین حلقه‌ها را با تعداد سفرهای شناخته شده استاتیکی بهینه می‌کند و شاخه‌های مرده شناخته شده استاتیکی را به صورت شرطی حذف می‌کند.
  • بهینه‌ساز اختصاص‌دهنده محدوده - تخصیص‌دهنده‌های محدوده‌ای را برای کاهش حرکت داده‌ها و تجمیع برخی از عملیات‌ها معرفی می‌کند.
  • پین به هاست بهینه ساز - عملیات های کوچک را روی CPU جابجا می کند. این بهینه ساز به طور پیش فرض خاموش است.
  • بهینه‌ساز دقیق ترکیبی خودکار - برای بهبود عملکرد، در صورت لزوم، انواع داده‌ها را به float16 تبدیل می‌کند. در حال حاضر فقط برای GPU ها اعمال می شود.
  • رفع اشکال - گره های مربوط به عملیات اشکال زدایی مانند tf.debugging.Assert ، tf.debugging.check_numerics و tf.print را از نمودار جدا می کند. این بهینه ساز به طور پیش فرض خاموش است.

برپایی

import numpy as np
import timeit
import traceback
import contextlib


import tensorflow as tf

یک مدیر زمینه ایجاد کنید تا به راحتی حالت های بهینه ساز را تغییر دهید.

@contextlib.contextmanager
def options(options):
  old_opts = tf.config.optimizer.get_experimental_options()
  tf.config.optimizer.set_experimental_options(options)
  try:
    yield
  finally:
    tf.config.optimizer.set_experimental_options(old_opts)

مقایسه عملکرد اجرا با و بدون Grappler

TensorFlow 2 و فراتر از آن به طور پیش فرض مشتاقانه اجرا می شود. از tf.function برای تغییر اجرای پیش فرض به حالت Graph استفاده کنید. Grappler به طور خودکار در پس‌زمینه اجرا می‌شود تا بهینه‌سازی‌های نمودار بالا را اعمال کند و عملکرد اجرا را بهبود بخشد.

بهینه ساز تاشو ثابت

به عنوان مثال مقدماتی، تابعی را در نظر بگیرید که عملیاتی را روی ثابت ها انجام می دهد و خروجی را برمی گرداند.

def test_function_1():
  @tf.function
  def simple_function(input_arg):
    print('Tracing!')
    a = tf.constant(np.random.randn(2000,2000), dtype = tf.float32)
    c = a
    for n in range(50):
      c = c@a
    return tf.reduce_mean(c+input_arg)

  return simple_function

بهینه ساز ثابت تاشو را خاموش کنید و عملکرد زیر را اجرا کنید:

with options({'constant_folding': False}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Vanilla execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': False, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Vanilla execution: 0.0018392090000816097 s

بهینه ساز ثابت تاشو را فعال کنید و عملکرد را دوباره اجرا کنید تا سرعت اجرای عملکرد مشاهده شود.

with options({'constant_folding': True}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Constant folded execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': True, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Constant folded execution: 0.0006749789999958011 s

اشکال زدایی بهینه ساز stripper

یک تابع ساده را در نظر بگیرید که مقدار عددی آرگومان ورودی خود را بررسی کرده و آن را برمی گرداند.

def test_function_2():
  @tf.function
  def simple_func(input_arg):
    output = input_arg
    tf.debugging.check_numerics(output, "Bad!")
    return output
  return simple_func

ابتدا، عملکرد را با خاموش کردن بهینه ساز رفع اشکال اجرا کنید.

test_func = test_function_2()
p1 = tf.constant(float('inf'))
try:
  test_func(p1)
except tf.errors.InvalidArgumentError as e:
  traceback.print_exc(limit=2)
2021-09-22 20:34:55.871238: E tensorflow/core/kernels/check_numerics_op.cc:292] abnormal_detected_host @0x7f4878e00100 = {0, 1} Bad!
Traceback (most recent call last):
  File "/tmp/ipykernel_22954/3616845043.py", line 4, in <module>
    test_func(p1)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py", line 885, in __call__
    result = self._call(*args, **kwds)
tensorflow.python.framework.errors_impl.InvalidArgumentError:  Bad! : Tensor had Inf values
     [[node CheckNumerics (defined at tmp/ipykernel_22954/2241890286.py:5) ]] [Op:__inference_simple_func_131]

Errors may have originated from an input operation.
Input Source operations connected to node CheckNumerics:
 input_arg (defined at tmp/ipykernel_22954/3616845043.py:4)

Function call stack:
simple_func

tf.debugging.check_numerics یک خطای آرگومان نامعتبر را به دلیل آرگومان Inf در test_func ایجاد می کند.

بهینه ساز رفع اشکال را فعال کرده و دوباره عملکرد را اجرا کنید.

with options({'debug_stripper': True}):
  test_func2 = test_function_2()
  p1 = tf.constant(float('inf'))
  try:
    test_func2(p1)
  except tf.errors.InvalidArgumentError as e:
    traceback.print_exc(limit=2)

بهینه ساز stripper debug گره tf.debug.check_numerics را از نمودار جدا می کند و تابع را بدون ایجاد هیچ خطایی اجرا می کند.

خلاصه

زمان اجرا TensorFlow از Grappler برای بهینه سازی خودکار نمودارها قبل از اجرا استفاده می کند. از tf.config.optimizer.set_experimental_options برای فعال یا غیرفعال کردن بهینه سازهای مختلف نمودار استفاده کنید.

برای اطلاعات بیشتر در مورد Grappler، به بهینه سازی نمودار TensorFlow مراجعه کنید.