Async HLO নির্দেশাবলী

  1. এইচএলও-তে অ্যাসিঙ্ক অপারেশন যোগ করা কষ্টকর (যেমন all-reduce-start এবং all-reduce-done )।
  2. কিছু অ্যাসিঙ্ক্রোনাস ব্যবহারের ক্ষেত্রে শুরু এবং সম্পন্ন করা বিভাজন অপর্যাপ্ত হতে পারে।

প্রথম ত্রুটি লক্ষ্য করার জন্য, আমরা নতুন অ্যাসিঙ্ক্রোনাস অপকোডগুলির একটি শেষ সেট প্রবর্তনের প্রস্তাব করি: kAsyncStart , kAsyncUpdate , এবং kAsyncDone । ধারণাটি হল একটি জেনেরিক অ্যাসিঙ্ক্রোনাস অপকোড তৈরি করা যা যেকোন HLO নির্দেশকে মোড়ানো করতে পারে। অ্যাসিঙ্ক্রোনাসভাবে সম্পাদিত প্রকৃত ক্রিয়াকলাপটি একটি নামক কম্পিউটেশন ব্যবহার করে এনকোড করা হবে যার মূল হিসাবে নির্দেশনা এবং ইনপুটগুলির জন্য যেকোনো পরামিতি রয়েছে। ইন-ফ্লাইট ইনপুট/আউটপুট বাফার হ্যান্ডলিং এবং অ্যালিয়াসিং তারপরে যেকোনো অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য ভাগ করা যেতে পারে। async-start নির্দেশের আউটপুট আকারটি তখন ইনপুট অপারেন্ড, আউটপুট মান এবং যে কোনো মধ্যবর্তী অবস্থার একটি টিপল হবে যা async-update বা async-done নির্দেশাবলীর জন্য প্রয়োজন।

%async_op {
  %param0 = f32[64] parameter(0)
  ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=foo
}

%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
                                         calls=%async_op
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-start)

উপরোক্ত উপস্থাপনায়, শুধুমাত্র async-start একটি নামক গণনা রয়েছে কারণ async-done কী করে তার অপারেন্ড অনুসরণ করে অনুরূপ async-start খুঁজে বের করার জন্য বলা কম্পিউটেশন খুঁজে পাওয়া তুচ্ছ।

এছাড়াও মনে রাখবেন যে অপারেন্ডের সাথে async-start উপনামের আউটপুট টিপলে প্রথম উপাদান, তাই অন্তত অ্যাসিঙ্ক-সম্পন্ন নির্দেশনা পর্যন্ত বাফারটি জীবিত থাকে। একইভাবে, দ্বিতীয় উপাদানটি async-done এর আউটপুট সহ উপনাম দেয় এবং তৃতীয় উপাদানটি হল প্রসঙ্গ অবস্থা যা অ্যাসিঙ্ক্রোনাস অপারেশনের ট্র্যাক রাখতে ব্যবহৃত হয়। এই উপস্থাপনাটি অ্যাসিঙ্ক্রোনাস অপারেশন ইনপুট এবং/অথবা আউটপুটে একাধিক টেনসর সমর্থন করে এবং অ্যালিয়াসিং একইভাবে কাজ করে:

%async_op {
  %param0 = f32[64] parameter(0)
  %param1 = f32[64] parameter(1)
  ROOT %op = (f32[32], f32[32]) op(f32[64] %param0, f32[64] %param1),
                                op_specific_attr=foo
}

%async-start = ((f32[64], f32[64]), (f32[32], f32[32]), s32[])
               async-start(f32[64] %operand0, f32[64] %operand1),
               calls=%async_op
%async-done = (f32[32], f32[32]) async-done(%async-start)

উপরন্তু, অপটি শূন্য বা আরও বেশি async-update ধাপে পচনশীল হতে পারে যা মধ্যবর্তী গণনা সম্পাদন করে। ইনপুট/আউটপুট অ্যালিয়াসিং async-update নির্দেশের সাথে একইভাবে কাজ করে এবং প্রতিটি async-start এবং async-update নির্দেশাবলীতে অবশ্যই একজন ব্যবহারকারী থাকতে হবে যেটি হয় অন্য async-update বা async-done :

%async_op {
  %param0 = f32[64] parameter(0)
  ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=foo
}

%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
                                         calls=%async_op
%async-update0 = (f32[64], f32[32], s32[]) async-update(
                           (f32[64], f32[32], s32[]) %async-start)
%async-update1 = (f32[64], f32[32], s32[]) async-update(
                           (f32[64], f32[32], s32[]) %async-update0)
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-update1)

সিনট্যাক্স চিনি

যেহেতু অ্যাসিঙ্ক্রোনাসভাবে সম্পাদিত অপারেশনটি সংজ্ঞায়িত করার জন্য একটি পৃথক গণনা করা কিছুটা কষ্টকর, তাই আমরা একটি সিনট্যাক্স চিনির প্রস্তাবও করি যাতে স্বয়ংক্রিয়ভাবে অ্যাসিঙ্ক্রোনাস অপারেশনগুলি মুদ্রণ এবং পার্স করা যায় যেন সেগুলি প্রথম শ্রেণীর অপকোড। ধারণাটি হল পার্স করার সময় স্বয়ংক্রিয়ভাবে গণনা এবং নির্দেশনা (প্রত্যয় ছাড়া) তৈরি করে বিশেষভাবে “-শুরু”, “-আপডেট” এবং “-ডন” প্রত্যয়গুলিকে ব্যবহার করা। উদাহরণস্বরূপ, উপরের কোড স্নিপেটটি নিম্নলিখিতগুলিতে বেশ-মুদ্রিত হতে পারে এবং দুটিকে একই উপস্থাপনায় পার্স করা যেতে পারে:

%op-start = (f32[64], f32[32], s32[]) op-start(f32[64] %operand),
                                      op_specific_attr=foo
%op-update0 = (f32[64], f32[32], s32[]) op-update(
                        (f32[64], f32[32], s32[]) %op-start),
                        op_specific_attr=foo
%op-update1 = (f32[64], f32[32], s32[]) op-update(
                        (f32[64], f32[32], s32[]) %op-update0)
%op-done = f32[32] op-done((f32[64], f32[32], s32[]) %op-update1)

অস্পষ্টতা তৈরি না করার জন্য, যাচাইকারী একটি অপারেশনকে async-start দিয়ে মোড়ানোর অনুমতি দেবে না যদি আমরা "-start" এবং/অথবা "-done" প্রত্যয়গুলির সাথে সেই অপারেশনের জন্য একটি অপকোডকে স্পষ্টভাবে সংজ্ঞায়িত করি। এটিও একটি পালানোর হ্যাচ যদি আমাদের কাছে এমন কোনো নির্দেশনা থাকে যার জন্য HLO-স্তরের চিকিত্সার প্রয়োজন যা উপরে বর্ণিত মডেলের সাথে খাপ খায় না (যেমন অ্যালিয়াসিং ইনপুট/আউটপুট বাফার)। সুতরাং, প্রাথমিকভাবে, copy-start / copy-done , collective-permute-start / collective-permute-done ইত্যাদি নতুন async-start / async-done অপকোডের পরিবর্তে তাদের নিজ নিজ প্রথম শ্রেণীর অপকোড ব্যবহার করতে থাকবে যতক্ষণ না আমরা পরিষ্কার করি এই "-start"/"-done" অপকোডগুলি সরাতে কোডটি আপ করুন।

,

  1. এইচএলও-তে অ্যাসিঙ্ক অপারেশন যোগ করা কষ্টকর (যেমন all-reduce-start এবং all-reduce-done )।
  2. কিছু অ্যাসিঙ্ক্রোনাস ব্যবহারের ক্ষেত্রে শুরু এবং সম্পন্ন করা বিভাজন অপর্যাপ্ত হতে পারে।

প্রথম ত্রুটি লক্ষ্য করার জন্য, আমরা নতুন অ্যাসিঙ্ক্রোনাস অপকোডগুলির একটি শেষ সেট প্রবর্তনের প্রস্তাব করি: kAsyncStart , kAsyncUpdate , এবং kAsyncDone । ধারণাটি হল একটি জেনেরিক অ্যাসিঙ্ক্রোনাস অপকোড তৈরি করা যা যেকোন HLO নির্দেশকে মোড়ানো করতে পারে। অ্যাসিঙ্ক্রোনাসভাবে সম্পাদিত প্রকৃত ক্রিয়াকলাপটি একটি নামক কম্পিউটেশন ব্যবহার করে এনকোড করা হবে যার মূল হিসাবে নির্দেশনা এবং ইনপুটগুলির জন্য যেকোনো পরামিতি রয়েছে। ইন-ফ্লাইট ইনপুট/আউটপুট বাফার হ্যান্ডলিং এবং অ্যালিয়াসিং তারপরে যেকোনো অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য ভাগ করা যেতে পারে। async-start নির্দেশের আউটপুট আকারটি তখন ইনপুট অপারেন্ড, আউটপুট মান এবং যে কোনো মধ্যবর্তী অবস্থার একটি টিপল হবে যা async-update বা async-done নির্দেশাবলীর জন্য প্রয়োজন।

%async_op {
  %param0 = f32[64] parameter(0)
  ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=foo
}

%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
                                         calls=%async_op
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-start)

উপরোক্ত উপস্থাপনায়, শুধুমাত্র async-start একটি নামক গণনা রয়েছে কারণ async-done কী করে তার অপারেন্ড অনুসরণ করে অনুরূপ async-start খুঁজে বের করার জন্য বলা কম্পিউটেশন খুঁজে পাওয়া তুচ্ছ।

এছাড়াও মনে রাখবেন যে অপারেন্ডের সাথে async-start উপনামের আউটপুট টিপলে প্রথম উপাদান, তাই অন্তত অ্যাসিঙ্ক-সম্পন্ন নির্দেশনা পর্যন্ত বাফারটি জীবিত থাকে। একইভাবে, দ্বিতীয় উপাদানটি async-done এর আউটপুট সহ উপনাম দেয় এবং তৃতীয় উপাদানটি হল প্রসঙ্গ অবস্থা যা অ্যাসিঙ্ক্রোনাস অপারেশনের ট্র্যাক রাখতে ব্যবহৃত হয়। এই উপস্থাপনাটি অ্যাসিঙ্ক্রোনাস অপারেশন ইনপুট এবং/অথবা আউটপুটে একাধিক টেনসর সমর্থন করে এবং অ্যালিয়াসিং একইভাবে কাজ করে:

%async_op {
  %param0 = f32[64] parameter(0)
  %param1 = f32[64] parameter(1)
  ROOT %op = (f32[32], f32[32]) op(f32[64] %param0, f32[64] %param1),
                                op_specific_attr=foo
}

%async-start = ((f32[64], f32[64]), (f32[32], f32[32]), s32[])
               async-start(f32[64] %operand0, f32[64] %operand1),
               calls=%async_op
%async-done = (f32[32], f32[32]) async-done(%async-start)

উপরন্তু, অপটি শূন্য বা আরও বেশি async-update ধাপে পচনশীল হতে পারে যা মধ্যবর্তী গণনা সম্পাদন করে। ইনপুট/আউটপুট অ্যালিয়াসিং async-update নির্দেশের সাথে একইভাবে কাজ করে এবং প্রতিটি async-start এবং async-update নির্দেশাবলীতে অবশ্যই একজন ব্যবহারকারী থাকতে হবে যেটি হয় অন্য async-update বা async-done :

%async_op {
  %param0 = f32[64] parameter(0)
  ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=foo
}

%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
                                         calls=%async_op
%async-update0 = (f32[64], f32[32], s32[]) async-update(
                           (f32[64], f32[32], s32[]) %async-start)
%async-update1 = (f32[64], f32[32], s32[]) async-update(
                           (f32[64], f32[32], s32[]) %async-update0)
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-update1)

সিনট্যাক্স চিনি

যেহেতু অ্যাসিঙ্ক্রোনাসভাবে সম্পাদিত অপারেশনটি সংজ্ঞায়িত করার জন্য একটি পৃথক গণনা করা কিছুটা কষ্টকর, তাই আমরা একটি সিনট্যাক্স চিনির প্রস্তাবও করি যাতে স্বয়ংক্রিয়ভাবে অ্যাসিঙ্ক্রোনাস অপারেশনগুলি মুদ্রণ এবং পার্স করা যায় যেন সেগুলি প্রথম শ্রেণীর অপকোড। ধারণাটি হল পার্স করার সময় স্বয়ংক্রিয়ভাবে গণনা এবং নির্দেশনা (প্রত্যয় ছাড়া) তৈরি করে বিশেষভাবে “-শুরু”, “-আপডেট” এবং “-ডন” প্রত্যয়গুলিকে ব্যবহার করা। উদাহরণস্বরূপ, উপরের কোড স্নিপেটটি নিম্নলিখিতগুলিতে বেশ-মুদ্রিত হতে পারে এবং দুটিকে একই উপস্থাপনায় পার্স করা যেতে পারে:

%op-start = (f32[64], f32[32], s32[]) op-start(f32[64] %operand),
                                      op_specific_attr=foo
%op-update0 = (f32[64], f32[32], s32[]) op-update(
                        (f32[64], f32[32], s32[]) %op-start),
                        op_specific_attr=foo
%op-update1 = (f32[64], f32[32], s32[]) op-update(
                        (f32[64], f32[32], s32[]) %op-update0)
%op-done = f32[32] op-done((f32[64], f32[32], s32[]) %op-update1)

অস্পষ্টতা তৈরি না করার জন্য, যাচাইকারী একটি অপারেশনকে async-start দিয়ে মোড়ানোর অনুমতি দেবে না যদি আমরা "-start" এবং/অথবা "-done" প্রত্যয়গুলির সাথে সেই অপারেশনের জন্য একটি অপকোডকে স্পষ্টভাবে সংজ্ঞায়িত করি। এটিও একটি পালানোর হ্যাচ যদি আমাদের কাছে এমন কোনো নির্দেশনা থাকে যার জন্য HLO-স্তরের চিকিত্সার প্রয়োজন যা উপরে বর্ণিত মডেলের সাথে খাপ খায় না (যেমন অ্যালিয়াসিং ইনপুট/আউটপুট বাফার)। সুতরাং, প্রাথমিকভাবে, copy-start / copy-done , collective-permute-start / collective-permute-done ইত্যাদি নতুন async-start / async-done অপকোডের পরিবর্তে তাদের নিজ নিজ প্রথম শ্রেণীর অপকোড ব্যবহার করতে থাকবে যতক্ষণ না আমরা পরিষ্কার করি এই "-start"/"-done" অপকোডগুলি সরাতে কোডটি আপ করুন।