مترجم StableHLO

هدف اصلی مفسر StableHLO ارائه یک پیاده سازی مرجع به معنایی StableHLO opset با توجه به مشخصات آن است. هدف ثانویه این است که پیاده‌سازی دقیقاً از مشخصات پیروی کند، خوانایی را به عملکرد ترجیح دهد، تا وضوح بیشتری به معنای حتی درگیرترین عملیات مانند Convolution ، Gather / Scatter و DotGeneral ارائه دهد.

در حال حاضر، OpenXLA از تفسیر 91 از 96 عملیات مشخص شده StableHLO پشتیبانی می کند. 3 عملیات باقیمانده ( FftOp ، RngOp ، RngBitGeneratorOp ) دارای معناشناسی خود در spec.md مستند شده اند، و تحقیقات اولیه در مورد چگونگی حرکت به جلو را تکمیل کرده اند (برای لیست کامل عملیات ها و آخرین وضعیت آن به status.md مراجعه کنید). این پیشرفت های نهایی بر اساس نیاز جامعه اجرا خواهد شد.

دامنه

ما opset StableHLO را به 11 دسته دسته بندی کردیم که در مجموع از 118 عملیات تشکیل شده است ( به پیوست مراجعه کنید). جریان کاری Reference Implementation کار پیاده سازی مفسر را برای 100% عملیات StableHLO همانطور که در مشخصات StableHLO تعریف شده است، سازماندهی می کند. ما در حال برنامه ریزی برای تکمیل تمام یا تقریباً تمام کارهای این جریان کاری در StableHLO v1.0 هستیم. از 96 عملیاتی که در حال حاضر دارای مشخصات هستند، می‌توانیم 91 عملیات را از طریق OpenXLA تفسیر کنیم (برای 5 مورد باقیمانده به موارد ویژه مراجعه کنید).

مشخصات

شرط اصلی مترجم این است که مطابقت 1:1 با مشخصات داشته باشد. این مشخصات اجازه می‌دهد تا مفسر را در عملیات‌های مشابه استانداردسازی کند که منجر به اجرای مدولار و با کیفیت بالا از مفسر می‌شود.

موارد خاص

متفرقه

این دسته دارای عملیات های تجزیه پذیر است که آینده آنها در حال حاضر نامشخص است. سه عملیات مشخص در این دسته وجود دارد که مترجم در حال حاضر از آنها پشتیبانی نمی کند:

  • FftOp
  • RngOp
  • RngBitGeneratorOp

FftOp به عنوان متفرقه طبقه بندی می شود، اما بر خلاف سایر عملیات های این دسته، این عملیات دارای پاس توسعه دهنده نیست و پشتیبانی از آن در StableHLO یک WIP است.

RngOp و RngBitGeneratorOp می توان به عملیات MHLO تجزیه کرد، اما تجزیه یک XlaRngGetAndUpdateStateOp را معرفی می کند که یک عملیات خاص MHLO است. تفسیر پشتیبانی کننده از این دو عملیات یک WIP است.

ابزار تبدیل عملیات باقی مانده در این دسته به عملیات StableHLO که مفسر پشتیبانی می کند در hlo_expand_main.cc قرار دارد.

در HLO نیست

به غیر از عملیات مشخص، این دسته شامل 8 عملیات غیرمشخص است (به مقوله‌های عملیات StableHLO مراجعه کنید) که قرار است از StableHLO خارج شوند. اکثر این عملیات ها دارای پاس های موجود در mhlo برای تبدیل آنها به عملیات های معادل StableHLO هستند.

ابزار تبدیل عملیات‌های باقی‌مانده در این دسته به عملیات‌های StableHLO معادل که مفسر پشتیبانی می‌کند در mlir-hlo-opt.cc قرار دارد.

کوانتیزاسیون

پشتیبانی مترجم برای عملیات stablehlo.constant با نوع کوانتیزه پشتیبانی نمی شود و از طریق #1691 ردیابی می شود.

دستورالعمل استفاده

ساخت مترجم مرجع

مفسر را می توان از طریق Bazel یا CMake ساخته و آزمایش کرد (ترجیحا). برای دستورالعمل‌های کامل، به README.md مراجعه کنید.

بازل:

bazel build //...

CMake:

mkdir -p build && cd build

cmake .. -GNinja \
  -DLLVM_ENABLE_LLD="$LLVM_ENABLE_LLD" \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_ASSERTIONS=On \
  -DMLIR_DIR=${PWD}/../llvm-build/lib/cmake/mlir

برای اجرای مفسر، یک ابزار ترجمه برای تفسیر برنامه های StableHLO نوشته شده در MLIR داریم.

stablehlo-translate --interpret <path/to/program>

گویش مترجم

گویش Interpreter شامل عملیات های مختلف کاربردی مربوط به مفسر است. به طور خاص، interpreter.run_parallel (به InterpreterOps.td برای معناشناسی عملیات و کاربرد مثال مراجعه کنید) اجازه می دهد تا تفسیر عملیات توزیع، و برنامه های کاربردی بیشتری بر اساس نیازهای جامعه اضافه شود.

گویش چک

گویش Check برای مقایسه مقادیر زمان اجرا مفسر با مقادیر مورد انتظار استفاده می شود. خروجی‌های برنامه StableHLO را می‌توان از طریق بررسی‌های مختلف آزمایش کرد (به CheckOps.td برای معناشناسی عملیات و استفاده از مثال مراجعه کنید).

برنامه های تست نوشتن

ما از ابزار روشن LLVM برای اجرا و مقایسه با فایل تولید شده استفاده می کنیم تا با خروجی مفسر تفاوت داشته باشد (به عنوان مثال به stablehlo/tests/interpret مراجعه کنید).

آزمایش AddOp (نمونه از interpret_add.mlir ):

// RUN: stablehlo-translate --interpret %s

func.func @add_op_scalar() {
  %0 = stablehlo.constant dense<2> : tensor<i4>
  %1 = stablehlo.constant dense<3> : tensor<i4>
  %2 = stablehlo.add %0, %1 : tensor<i4>
  check.expect_eq_const %2, dense<5> : tensor<i4>
  func.return
}

آزمایش عملیات در دسته توزیع نیاز به اجرای آن از طریق ابزار interpreter.run_parallel دارد.

تست AllReduceOp (نمونه از all_reduce.mlir ):

// RUN: stablehlo-translate --interpret %s

module @cross_replica {
  func.func public @all_reduce(%operand : tensor<4xi64>) -> tensor<4xi64> {
    %result = "stablehlo.all_reduce"(%operand) ({
      ^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
        %0 = stablehlo.add %arg0, %arg1 : tensor<i64>
        stablehlo.return %0 : tensor<i64>
    }) {
      replica_groups = dense<[[0, 1]]> : tensor<1x2xi64>,
      channel_handle = #stablehlo.channel_handle<handle = 0, type = 0>
    } : (tensor<4xi64>) -> tensor<4xi64>
    return %result : tensor<4xi64>
  }
  func.func public @main() {
    %inputs0 = stablehlo.constant dense<[1, 2, 3, 4]> : tensor<4xi64>
    %inputs1 = stablehlo.constant dense<[5, 6, 7, 8]> : tensor<4xi64>
    %results:2 = "interpreter.run_parallel"(%inputs0, %inputs1) {
      programs=[[@all_reduce], [@all_reduce]]
    } : (tensor<4xi64>, tensor<4xi64>) -> (tensor<4xi64>, tensor<4xi64>)
    check.expect_eq_const %results#0, dense<[6, 8, 10, 12]> : tensor<4xi64>
    check.expect_eq_const %results#1, dense<[6, 8, 10, 12]> : tensor<4xi64>
    func.return
  }
}

اشکال زدایی StableHLO

پس از مراحل ساخت StableHLO، باینری های StableHLO برای ابزارهای stablehlo/tools باید در /build/bin قرار گیرند. از ابزارهای رایج اشکال زدایی مانند GDB می توان برای گذر از کد استفاده کرد:

gdb --args ./build/bin/stablehlo-translate -allow-unregistered-dialect --interpret ./stablehlo/tests/interpret/<test>.mlir

ضمیمه

تبدیل عملیات متفرقه

# batch_norm_grad
hlo-expand --batch_norm_grad_expander <path/to/hlo_module>

# batch_norm_inference
hlo-expand --batch_norm_inference_expander <path/to/hlo_module>

# batch_norm_training
hlo-expand --batch_norm_training_expander <path/to/hlo_module>

# cholesky
hlo-expand --cholesky_expander <path/to/hlo_module>

# constant
# Supported in StableHLO interpreter.

# fft
# TBD

# iota
# Supported in StableHLO interpreter.

# rng
# TBD

# rng_bit_generator
# TBD

# triangular_solve
hlo-expand --triangular_solve_expander <path/to/hlo_module>

تبدیل نشدن در HLO Ops

# dot
mlir-hlo-opt -mhlo-legalize-dot-to-dot-general <path/to/input>

# einsum
mlir-hlo-opt -mhlo-legalize-einsum-to-dot-general <path/to/input>

# torch_index_select
mlir-hlo-opt -mhlo-legalize-torch-index-select-to-gather <path/to/input>

# unary_einsum
mlir-hlo-opt --canonicalize -mhlo-legalize-einsum-to-dot-general <path/to/input>

دسته های عملیات StableHLO

دسته بندی ها یادگاری مجموع
119
کنترل جریان after_all، case، if، optimization_barrier، while 5
حرکت داده ها پخش_در_کم، الحاق، برش_دینامیک، تکه_به روز رسانی_دینامیک، جمع آوری، پد، تغییر شکل، معکوس، پراکنده، برش، مرتب سازی، جابجایی 12
توزیع all_gather, all_reduce, all_to_all, collective_permute, infeed, outfeed, partition_id, recv, small_scatter, replica_id, send 11
پویایی dynamic_broadcast_in_dim، dynamic_conv، dynamic_gather، dynamic_iota، dynamic_pad، dynamic_reshape، get_dimension_size، real_dynamic_slice، set_dimension_size 9
از نظر عنصری abs، افزودن، و، atan2، bitcast_convert، cbrt، سقف، گیره، مقایسه، مختلط، تبدیل، کسینوس، شمارش_صفرهای پیشرو، تقسیم، نمایی، نمایی_منهای_یک، طبقه، تصویر، محدود است، ورود به سیستم، log_plus_one، لجستیک، نقشه، حداکثر، ضرب، نفی، نه، یا، popcnt، توان، واقعی، کاهش_دقت، باقیمانده، دور_نزدیکترین_افز، گرد_نزدیکترین_زوج، rsqrt، انتخاب، shift_left، shift_right_hismetic، shift_right_logical، علامت، سینوس، sqrt، تفریق، tan، tanh، xor 48
توسعه پذیری custom_call، get_tuple_element، tuple 3
متفرقه batch_norm_grad, batch_norm_inference, batch_norm_training, cholesky, ثابت, fft, iota, rng, rng_bit_generator, triangular_solve 10
مدولار بودن تماس، تابع، ماژول، بازگشت 4
در HLO نیست پخش، ایجاد_توکن، جمع کپی متقابل، نقطه، einsum، torch_index_select، unary_einsum 8
کوانتیزاسیون یکنواخت_دکوانتیز کردن، یکنواخت_کوانتیزه کردن 2
کاهش پیچیدگی، نقطه_عمومی، کاهش، پنجره_کاهش، انتخاب_و_پراکندگی 5