Neural Networks HAL 1.2, বার্স্ট এক্সিকিউশন সংক্রান্ত ধারণা নিয়ে আসে। বার্স্ট এক্সিকিউশন হল একই প্রিপেয়ার করা মডেলের এক্সিকিউশনের একটি ক্রম যা খুব দ্রুত পরপর ঘটে, যেমন ক্যামেরা ক্যাপচারের ফ্রেম বা পরপর অডিও স্যাম্পেল। বার্স্ট অবজেক্ট ব্যবহার করে বার্স্ট এক্সিকিউশনের সেট নিয়ন্ত্রণ করা হয় এবং এক্সিকিউশনের মধ্যে রিসোর্স সংরক্ষণ করা হয়, যাতে এক্সিকিউশনের সময় কম ওভারহেড হয়। বার্স্ট অবজেক্ট তিনটি অপ্টিমাইজেশন চালু করে:
- এক্সিকিউশনের একটি সিকোয়েন্সের আগে একটি বার্স্ট অবজেক্ট তৈরি করা হয় এবং সিকোয়েন্স শেষ হয়ে গেলে সেটি ফ্রি করে দেওয়া হয়। এই কারণে, বার্স্ট অবজেক্টের লাইফটাইম ড্রাইভারকে জানায় যে এটি কতক্ষণ হাই-পারফর্ম্যান্স স্টেটে থাকবে।
- এক্সিকিউশনের মধ্যে বার্স্ট অবজেক্ট রিসোর্স সংরক্ষণ করতে পারে। যেমন, কোনও ড্রাইভার প্রথমবার এক্সিকিউট করার সময় মেমরি অবজেক্ট ম্যাপ করতে এবং পরবর্তী এক্সিকিউশনে আবার ব্যবহার করার জন্য বার্স্ট অবজেক্টে ম্যাপিং ক্যাশে করতে পারে। বার্স্ট অবজেক্ট নষ্ট হয়ে গেলে অথবা NNAPI রানটাইম বার্স্ট অবজেক্টকে রিসোর্স আর প্রয়োজন নেই বলে বিজ্ঞপ্তি দিলে, ক্যাশে করা যেকোনও রিসোর্স রিলিজ করা যেতে পারে।
- অ্যাপ ও ড্রাইভার প্রসেসের মধ্যে যোগাযোগ করতে, বার্স্ট অবজেক্ট দ্রুত মেসেজ কিউ (FMQ) ব্যবহার করে। এর ফলে লেটেন্সি কমে যেতে পারে কারণ FMQ, HIDL-কে বাইপাস করে এবং শেয়ার করা মেমরিতে অ্যাটমিক সার্কুলার FIFO-এর মাধ্যমে অন্য প্রসেসে সরাসরি ডেটা পাস করে। কনজিউমার প্রসেস জানে যে কীভাবে কোনও আইটেম ডিকিউ করতে হয় এবং FIFO-তে এলিমেন্টের সংখ্যা পোল করে অথবা FMQ-এর ইভেন্ট ফ্ল্যাগে অপেক্ষা করে প্রসেসিং শুরু করতে হয়, যা প্রোডিউসার সিগন্যাল করে। এই ইভেন্ট ফ্ল্যাগ হল একটি ফাস্ট ইউজারস্পেস মিউটেক্স (futex)।
FMQ হল একটি লো-লেভেল ডেটা স্ট্রাকচার যা প্রসেস জুড়ে কোনও লাইফটাইম গ্যারান্টি দেয় না এবং FMQ-এর অন্য প্রান্তে থাকা প্রসেসটি প্রত্যাশিতভাবে চলছে কিনা তা নির্ধারণ করার জন্য কোনও বিল্ট-ইন মেকানিজম নেই। এর ফলে, FMQ-এর প্রডিউসার মারা গেলে, কনজিউমার এমন ডেটার জন্য অপেক্ষা করতে পারে যা কখনও আসবে না। এই সমস্যার একটি সমাধান হল, ড্রাইভারকে FMQ-কে উচ্চ-স্তরের বার্স্ট অবজেক্টের সাথে যুক্ত করতে হবে যাতে বার্স্ট এক্সিকিউশন কখন শেষ হয়েছে তা শনাক্ত করা যায়।
যেহেতু বার্স্ট এক্সিকিউশন একই আর্গুমেন্টের উপর কাজ করে এবং অন্যান্য এক্সিকিউশন পাথের মতো একই
ফলাফল দেয়, তাই NNAPI পরিষেবা ড্রাইভারকে এবং তার থেকে আন্ডারলায়িং FMQ-কে একই ডেটা পাস করতে
হবে। তবে, FMQ শুধুমাত্র
পুরনো ডেটার ধরন ট্রান্সফার করতে পারে। FMQ-তে সরাসরি নেস্টেড বাফার (ভেক্টর টাইপ) সিরিয়ালাইজ
ও ডিসিরিয়ালাইজ করে এবং চাহিদা মতো মেমরি পুল হ্যান্ডেল ট্রান্সফার করতে
HIDL কলব্যাক অবজেক্ট ব্যবহার করে জটিল ডেটা ট্রান্সফার করা হয়। FMQ-এর প্রোডিউসার
সাইডকে অবশ্যই অনুরোধ বা ফলাফল মেসেজ কনজিউমারকে পাঠাতে হবে
অ্যাটমিক্যালি MessageQueue::writeBlocking ব্যবহার করে যদি সারিটি ব্লক করা থাকে, অথবা
MessageQueue::write ব্যবহার করে যদি সারিটি নন-ব্লকিং হয়।
বার্স্ট ইন্টারফেস
নিউরাল নেটওয়ার্ক HAL-এর জন্য বার্স্ট ইন্টারফেস
hardware/interfaces/neuralnetworks/1.2/
এ পাওয়া যায় এবং নিচে এর বিবরণ দেওয়া হল। NDK
লেয়ারে বার্স্ট ইন্টারফেস সম্পর্কে আরও জানতে, frameworks/ml/nn/runtime/include/NeuralNetworks.h দেখুন।
types.hal
types.hal
FMQ-এর মাধ্যমে পাঠানো ডেটার ধরন নির্ধারণ করে।
FmqRequestDatum: একটি এক্সিকিউশনRequestঅবজেক্টের সিরিয়ালাইজড উপস্থাপনার একটি এলিমেন্ট এবং একটিMeasureTimingভ্যালু, যা ফাস্ট মেসেজ কিউতে পাঠানো হয়।FmqResultDatum: কোনও এক্সিকিউশন (ErrorStatus,OutputShapesওTiming) থেকে প্রাপ্ত ভ্যালুর সিরিয়ালাইজড উপস্থাপনার একটি এলিমেন্ট, যা দ্রুত মেসেজ কোয়ের মাধ্যমে রিটার্ন করা হয়।
IBurstContext.hal
IBurstContext.hal
HIDL ইন্টারফেস অবজেক্টকে সংজ্ঞায়িত করে যা Neural Networks পরিষেবায় থাকে।
IBurstContext: বার্স্টের রিসোর্স ম্যানেজ করার জন্য কনটেক্সট অবজেক্ট।
IBurstCallback.hal
IBurstCallback.hal
নিউরাল নেটওয়ার্ক
রানটাইম দ্বারা তৈরি কলব্যাকের জন্য HIDL ইন্টারফেস অবজেক্টকে ডিফাইন করে এবং নিউরাল নেটওয়ার্ক পরিষেবা এটিকে hidl_memory
স্লট শনাক্তকারীর সাথে সম্পর্কিত অবজেক্ট রিট্রিভ করতে ব্যবহার করে।
- IBurstCallback: মেমরি অবজেক্ট রিট্রিভ করার জন্য কোনও পরিষেবা দ্বারা ব্যবহৃত কলব্যাক অবজেক্ট।
IPreparedModel.hal
IPreparedModel.hal
HAL 1.2-এ একটি IBurstContext অবজেক্ট তৈরি করার পদ্ধতি সহ এক্সটেন্ড করা হয়েছে, যা
প্রস্তুত মডেল থেকে তৈরি করা হয়।
configureExecutionBurst: প্রস্তুত করা মডেলে দ্রুত একের পর এক একাধিক ইনফারেন্স এক্সিকিউট করার জন্য ব্যবহৃত একটি বার্স্ট অবজেক্ট কনফিগার করে।
ড্রাইভারে বার্স্ট এক্সিকিউশন সাপোর্ট করে
HIDL NNAPI পরিষেবায় বার্স্ট অবজেক্ট সাপোর্ট করার সবচেয়ে সহজ উপায় হল
বার্স্ট ইউটিলিটি ফাংশন ::android::nn::ExecutionBurstServer::create ব্যবহার করা, যা
ExecutionBurstServer.h-এ
পাওয়া যায় এবং libneuralnetworks_common ও libneuralnetworks_util
স্ট্যাটিক লাইব্রেরিতে প্যাকেজ করা থাকে। এই ফ্যাক্টরি ফাংশনে দুটি ওভারলোড আছে:
- একটি ওভারলোড
IPreparedModelঅবজেক্টের পয়েন্টার গ্রহণ করে। এই ইউটিলিটি ফাংশন, মডেল এক্সিকিউট করার জন্যIPreparedModelঅবজেক্টেexecuteSynchronouslyপদ্ধতি ব্যবহার করে। - একটি ওভারলোড কাস্টমাইজ করা যায় এমন
IBurstExecutorWithCacheঅবজেক্ট গ্রহণ করে, যা একাধিক এক্সিকিউশন জুড়ে টিকে থাকে এমন রিসোর্স (যেমন,hidl_memoryম্যাপিং) ক্যাশে করতে ব্যবহার করা যেতে পারে।
প্রতিটি ওভারলোড একটি IBurstContext অবজেক্ট (যা বার্স্ট
অবজেক্টকে উপস্থাপন করে) রিটার্ন করে যার মধ্যে নিজস্ব ডেডিকেটেড লিসনার থ্রেড থাকে এবং সেটি ম্যানেজ করে। এই থ্রেড
requestChannel FMQ থেকে অনুরোধ পায়, ইনফারেন্স পারফর্ম করে, তারপর
resultChannel FMQ-এর মাধ্যমে ফলাফল রিটার্ন করে। এই থ্রেড এবং IBurstContext অবজেক্টে থাকা অন্যান্য সব রিসোর্স
অটোমেটিক রিলিজ হয়ে যায়
যখন বার্স্টের ক্লায়েন্ট IBurstContext-এর সাথে তার রেফারেন্স হারিয়ে ফেলে।
অথবা, আপনি IBurstContext-এর নিজস্ব প্রয়োগ তৈরি করতে পারেন যা requestChannel-এর মাধ্যমে মেসেজ পাঠানো ও পাওয়া এবং
resultChannel IPreparedModel::configureExecutionBurst-এ পাস করা FMQ বুঝতে পারে।
বার্স্ট ইউটিলিটি ফাংশন
ExecutionBurstServer.h-এ পাওয়া যায়।
/**
* Create automated context to manage FMQ-based executions.
*
* This function is intended to be used by a service to automatically:
* 1) Receive data from a provided FMQ
* 2) Execute a model with the given information
* 3) Send the result to the created FMQ
*
* @param callback Callback used to retrieve memories corresponding to
* unrecognized slots.
* @param requestChannel Input FMQ channel through which the client passes the
* request to the service.
* @param resultChannel Output FMQ channel from which the client can retrieve
* the result of the execution.
* @param executorWithCache Object which maintains a local cache of the
* memory pools and executes using the cached memory pools.
* @result IBurstContext Handle to the burst context.
*/
static sp<ExecutionBurstServer> create(
const sp<IBurstCallback>& callback, const FmqRequestDescriptor& requestChannel,
const FmqResultDescriptor& resultChannel,
std::shared_ptr<IBurstExecutorWithCache> executorWithCache);
/**
* Create automated context to manage FMQ-based executions.
*
* This function is intended to be used by a service to automatically:
* 1) Receive data from a provided FMQ
* 2) Execute a model with the given information
* 3) Send the result to the created FMQ
*
* @param callback Callback used to retrieve memories corresponding to
* unrecognized slots.
* @param requestChannel Input FMQ channel through which the client passes the
* request to the service.
* @param resultChannel Output FMQ channel from which the client can retrieve
* the result of the execution.
* @param preparedModel PreparedModel that the burst object was created from.
* IPreparedModel::executeSynchronously will be used to perform the
* execution.
* @result IBurstContext Handle to the burst context.
*/
static sp<ExecutionBurstServer> create(const sp<IBurstCallback>& callback,
const FmqRequestDescriptor& requestChannel,
const FmqResultDescriptor& resultChannel,
IPreparedModel* preparedModel);
নিম্নলিখিতটি হল
frameworks/ml/nn/driver/sample/SampleDriver.cpp-এ নিউরাল নেটওয়ার্ক স্যাম্পেল ড্রাইভারের
বার্স্ট ইন্টারফেসের রেফারেন্স ইমপ্লিমেন্টেশন।
Return<void> SamplePreparedModel::configureExecutionBurst(
const sp<V1_2::IBurstCallback>& callback,
const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
configureExecutionBurst_cb cb) {
NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION,
"SampleDriver::configureExecutionBurst");
// Alternatively, the burst could be configured via:
// const sp<V1_2::IBurstContext> burst =
// ExecutionBurstServer::create(callback, requestChannel,
// resultChannel, this);
//
// However, this alternative representation does not include a memory map
// caching optimization, and adds overhead.
const std::shared_ptr<BurstExecutorWithCache> executorWithCache =
std::make_shared<BurstExecutorWithCache>(mModel, mDriver, mPoolInfos);
const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(
callback, requestChannel, resultChannel, executorWithCache);
if (burst == nullptr) {
cb(ErrorStatus::GENERAL_FAILURE, {});
} else {
cb(ErrorStatus::NONE, burst);
}
return Void();
}