সংকলন ক্যাশিং

অ্যান্ড্রয়েড ১০ থেকে, নিউরাল নেটওয়ার্কস এপিআই (NNAPI) কম্পাইলেশন আর্টিফ্যাক্ট ক্যাশিং সমর্থন করার জন্য ফাংশন সরবরাহ করে, যা একটি অ্যাপ চালু হওয়ার সময় কম্পাইলেশনের জন্য ব্যবহৃত সময় কমিয়ে দেয়। এই ক্যাশিং কার্যকারিতা ব্যবহার করার ফলে, ড্রাইভারকে ক্যাশ করা ফাইলগুলি পরিচালনা বা পরিষ্কার করার প্রয়োজন হয় না। এটি একটি ঐচ্ছিক বৈশিষ্ট্য যা NN HAL 1.2 দিয়ে প্রয়োগ করা যেতে পারে। এই ফাংশনটি সম্পর্কে আরও তথ্যের জন্য, ANeuralNetworksCompilation_setCaching দেখুন।

ড্রাইভারটি NNAPI থেকে স্বাধীনভাবেও কম্পাইলেশন ক্যাশিং প্রয়োগ করতে পারে। NNAPI NDK এবং HAL ক্যাশিং বৈশিষ্ট্যগুলো ব্যবহৃত হোক বা না হোক, এটি প্রয়োগ করা যেতে পারে। AOSP একটি নিম্ন-স্তরের ইউটিলিটি লাইব্রেরি (একটি ক্যাশিং ইঞ্জিন) প্রদান করে। আরও তথ্যের জন্য, "একটি ক্যাশিং ইঞ্জিন বাস্তবায়ন" দেখুন।

ওয়ার্কফ্লো ওভারভিউ

এই অংশে কম্পাইলেশন ক্যাশিং বৈশিষ্ট্য বাস্তবায়িত অবস্থায় সাধারণ কার্যপ্রবাহ বর্ণনা করা হয়েছে।

প্রদত্ত ক্যাশে তথ্য এবং ক্যাশে হিট

  1. অ্যাপটি একটি ক্যাশিং ডিরেক্টরি এবং মডেলটির জন্য অনন্য একটি চেক্সাম প্রেরণ করে।
  2. NNAPI রানটাইম চেকসাম, এক্সিকিউশন প্রেফারেন্স এবং পার্টিশনিং ফলাফলের উপর ভিত্তি করে ক্যাশ ফাইলগুলো অনুসন্ধান করে এবং খুঁজে পায়।
  3. NNAPI prepareModelFromCache ব্যবহার করে ক্যাশ ফাইলগুলো খোলে এবং হ্যান্ডেলগুলো ড্রাইভারের কাছে পাঠিয়ে দেয়।
  4. ড্রাইভারটি সরাসরি ক্যাশ ফাইলগুলো থেকে মডেলটি প্রস্তুত করে এবং প্রস্তুতকৃত মডেলটি ফেরত দেয়।

প্রদত্ত ক্যাশে তথ্য এবং ক্যাশে মিস

  1. অ্যাপটি মডেলের জন্য একটি অনন্য চেকসাম এবং একটি ক্যাশিং ডিরেক্টরি প্রেরণ করে।
  2. NNAPI রানটাইম চেকসাম, এক্সিকিউশন প্রেফারেন্স এবং পার্টিশনিং ফলাফলের উপর ভিত্তি করে ক্যাশিং ফাইলগুলি খোঁজে, কিন্তু ক্যাশ ফাইলগুলি খুঁজে পায় না।
  3. NNAPI চেকসাম, এক্সিকিউশন প্রেফারেন্স এবং পার্টিশনিং-এর উপর ভিত্তি করে খালি ক্যাশ ফাইল তৈরি করে, ক্যাশ ফাইলগুলো খোলে এবং prepareModel_1_2 এর মাধ্যমে হ্যান্ডেল ও মডেলটি ড্রাইভারের কাছে পাঠায়।
  4. ড্রাইভারটি মডেলটি কম্পাইল করে, ক্যাশিং তথ্য ক্যাশ ফাইলগুলোতে লিখে রাখে এবং প্রস্তুতকৃত মডেলটি ফেরত দেয়।

ক্যাশে তথ্য প্রদান করা হয়নি

  1. অ্যাপটি কোনো ক্যাশিং তথ্য প্রদান না করেই কম্পাইলেশন শুরু করে।
  2. অ্যাপটি ক্যাশিং সম্পর্কিত কিছুই প্রেরণ করে না।
  3. NNAPI রানটাইম prepareModel_1_2 এর মাধ্যমে মডেলটিকে ড্রাইভারের কাছে প্রেরণ করে।
  4. ড্রাইভারটি মডেলটি কম্পাইল করে প্রস্তুতকৃত মডেলটি ফেরত দেয়।

ক্যাশে তথ্য

ড্রাইভারকে যে ক্যাশিং তথ্য সরবরাহ করা হয়, তাতে একটি টোকেন এবং ক্যাশ ফাইল হ্যান্ডেল অন্তর্ভুক্ত থাকে।

টোকেন

টোকেনটি হলো Constant::BYTE_SIZE_OF_CACHE_TOKEN দৈর্ঘ্যের একটি ক্যাশিং টোকেন যা প্রস্তুতকৃত মডেলটিকে শনাক্ত করে। prepareModel_1_2 দিয়ে ক্যাশ ফাইলগুলো সংরক্ষণ করার সময় এবং prepareModelFromCache দিয়ে প্রস্তুতকৃত মডেলটি পুনরুদ্ধার করার সময় একই টোকেন সরবরাহ করা হয়। ড্রাইভারের ক্লায়েন্টের এমন একটি টোকেন বেছে নেওয়া উচিত যার সংঘর্ষের হার কম। ড্রাইভার টোকেন সংঘর্ষ শনাক্ত করতে পারে না। একটি সংঘর্ষের ফলে এক্সিকিউশন ব্যর্থ হয় অথবা সফল এক্সিকিউশনের পরেও ভুল আউটপুট মান তৈরি হয়।

ক্যাশ ফাইল হ্যান্ডেল (দুই ধরনের ক্যাশ ফাইল)

ক্যাশ ফাইল দুই প্রকারের হয়: ডেটা ক্যাশ এবং মডেল ক্যাশ

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

ড্রাইভারকে অবশ্যই সিদ্ধান্ত নিতে হবে যে দুই ধরনের ক্যাশ ফাইলের মধ্যে ক্যাশ তথ্য কীভাবে বন্টন করা হবে, এবং getNumberOfCacheFilesNeeded ব্যবহার করে প্রতিটি ধরনের জন্য কতগুলো ক্যাশ ফাইল প্রয়োজন তা জানাতে হবে।

NNAPI রানটাইম সর্বদা ক্যাশ ফাইল হ্যান্ডেলগুলো পঠন এবং লিখন উভয় অনুমতিসহ খোলে।

নিরাপত্তা

কম্পাইলেশন ক্যাশিং-এর ক্ষেত্রে, মডেল ক্যাশে নিরাপত্তা-সংবেদনশীল ডেটা থাকতে পারে, যেমন ডিভাইসের নিজস্ব বাইনারি ফরম্যাটে কম্পাইল করা এক্সিকিউটেবল মেশিন কোড। যদি সঠিকভাবে সুরক্ষিত না থাকে, তবে মডেল ক্যাশে কোনো পরিবর্তন ড্রাইভারের এক্সিকিউশন আচরণকে প্রভাবিত করতে পারে। যেহেতু ক্যাশের বিষয়বস্তু অ্যাপ ডিরেক্টরিতে সংরক্ষিত থাকে, তাই ক্লায়েন্ট ক্যাশ ফাইলগুলো পরিবর্তন করতে পারে। একটি ত্রুটিপূর্ণ ক্লায়েন্ট ভুলবশত ক্যাশটি নষ্ট করে ফেলতে পারে, এবং একটি ক্ষতিকর ক্লায়েন্ট ইচ্ছাকৃতভাবে এটি ব্যবহার করে ডিভাইসে যাচাইবিহীন কোড চালাতে পারে। ডিভাইসের বৈশিষ্ট্যের উপর নির্ভর করে, এটি একটি নিরাপত্তা সমস্যা হতে পারে। সুতরাং, ক্যাশ থেকে মডেল প্রস্তুত করার আগে ড্রাইভারকে অবশ্যই সম্ভাব্য মডেল ক্যাশ করাপশন শনাক্ত করতে সক্ষম হতে হবে।

এটি করার একটি উপায় হলো, ড্রাইভার টোকেন থেকে মডেল ক্যাশের ক্রিপ্টোগ্রাফিক হ্যাশ পর্যন্ত একটি ম্যাপ বজায় রাখবে। কম্পাইলেশনটি ক্যাশে সংরক্ষণ করার সময় ড্রাইভার তার টোকেন এবং মডেল ক্যাশের হ্যাশ সংরক্ষণ করতে পারে। ক্যাশ থেকে কম্পাইলেশনটি পুনরুদ্ধার করার সময় ড্রাইভার রেকর্ড করা টোকেন এবং হ্যাশ জোড়ার সাথে মডেল ক্যাশের নতুন হ্যাশটি মিলিয়ে দেখে। এই ম্যাপিংটি সিস্টেম রিবুটের পরেও স্থায়ী থাকা উচিত। একটি ম্যাপিং ম্যানেজার বাস্তবায়নের জন্য ড্রাইভার অ্যান্ড্রয়েড কীস্টোর সার্ভিস , framework/ml/nn/driver/cache এর ইউটিলিটি লাইব্রেরি, বা অন্য কোনো উপযুক্ত পদ্ধতি ব্যবহার করতে পারে। ড্রাইভার আপডেট করার পর, পূর্ববর্তী সংস্করণের ক্যাশ ফাইল প্রস্তুত করা প্রতিরোধ করার জন্য এই ম্যাপিং ম্যানেজারটিকে পুনরায় চালু করা উচিত।

টাইম-অফ-চেক টু টাইম-অফ-ইউজ (TOCTOU) আক্রমণ প্রতিরোধ করার জন্য, ড্রাইভারকে অবশ্যই ফাইলে সংরক্ষণ করার আগে রেকর্ড করা হ্যাশটি গণনা করতে হবে এবং ফাইলের বিষয়বস্তু একটি অভ্যন্তরীণ বাফারে অনুলিপি করার পরে নতুন হ্যাশটি গণনা করতে হবে।

এই নমুনা কোডটি দেখায় কিভাবে এই লজিকটি প্রয়োগ করতে হয়।

bool saveToCache(const sp<V1_2::IPreparedModel> preparedModel,
                 const hidl_vec<hidl_handle>& modelFds, const hidl_vec<hidl_handle>& dataFds,
                 const HidlToken& token) {
    // Serialize the prepared model to internal buffers.
    auto buffers = serialize(preparedModel);

    // This implementation detail is important: the cache hash must be computed from internal
    // buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
    auto hash = computeHash(buffers);

    // Store the {token, hash} pair to a mapping manager that is persistent across reboots.
    CacheManager::get()->store(token, hash);

    // Write the cache contents from internal buffers to cache files.
    return writeToFds(buffers, modelFds, dataFds);
}

sp<V1_2::IPreparedModel> prepareFromCache(const hidl_vec<hidl_handle>& modelFds,
                                          const hidl_vec<hidl_handle>& dataFds,
                                          const HidlToken& token) {
    // Copy the cache contents from cache files to internal buffers.
    auto buffers = readFromFds(modelFds, dataFds);

    // This implementation detail is important: the cache hash must be computed from internal
    // buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
    auto hash = computeHash(buffers);

    // Validate the {token, hash} pair by a mapping manager that is persistent across reboots.
    if (CacheManager::get()->validate(token, hash)) {
        // Retrieve the prepared model from internal buffers.
        return deserialize<V1_2::IPreparedModel>(buffers);
    } else {
        return nullptr;
    }
}

উন্নত ব্যবহারের ক্ষেত্র

কিছু বিশেষ উন্নত ক্ষেত্রে, কম্পাইলেশন কলের পরে একটি ড্রাইভারের ক্যাশে কন্টেন্টে অ্যাক্সেসের (পড়া বা লেখার) প্রয়োজন হয়। উদাহরণস্বরূপ কিছু ব্যবহার হলো:

  • জাস্ট-ইন-টাইম কম্পাইলেশন: প্রথমবার কার্যকর হওয়া পর্যন্ত কম্পাইলেশন বিলম্বিত করা হয়।
  • বহু-পর্যায়ের কম্পাইলেশন: প্রথমে একটি দ্রুত কম্পাইলেশন করা হয় এবং ব্যবহারের ঘনত্বের উপর নির্ভর করে পরবর্তীতে একটি ঐচ্ছিক অপ্টিমাইজড কম্পাইলেশন করা হয়।

কম্পাইলেশন কলের পরে ক্যাশের বিষয়বস্তু অ্যাক্সেস (পড়া বা লেখা) করতে, নিশ্চিত করুন যে ড্রাইভারটি:

  • prepareModel_1_2 বা prepareModelFromCache কল করার সময় ফাইল হ্যান্ডেলগুলির প্রতিলিপি তৈরি করে এবং পরবর্তীতে ক্যাশের বিষয়বস্তু পড়ে ও আপডেট করে।
  • একই সাথে কোনো রিড বা অন্য কোনো রাইট হওয়া প্রতিরোধ করার জন্য, সাধারণ কম্পাইলেশন কলের বাইরে ফাইল লকিং লজিক প্রয়োগ করে।

একটি ক্যাশিং ইঞ্জিন বাস্তবায়ন করুন

NN HAL 1.2 কম্পাইলেশন ক্যাশিং ইন্টারফেস ছাড়াও, আপনি frameworks/ml/nn/driver/cache ডিরেক্টরিতে একটি ক্যাশিং ইউটিলিটি লাইব্রেরিও খুঁজে পাবেন। nnCache সাবডিরেক্টরিতে ড্রাইভারের জন্য পারসিস্টেন্ট স্টোরেজ কোড থাকে, যা NNAPI ক্যাশিং ফিচার ব্যবহার না করেই কম্পাইলেশন ক্যাশিং বাস্তবায়ন করে। এই ধরনের কম্পাইলেশন ক্যাশিং NN HAL-এর যেকোনো সংস্করণের সাথে বাস্তবায়ন করা যেতে পারে। যদি ড্রাইভার HAL ইন্টারফেস থেকে বিচ্ছিন্নভাবে ক্যাশিং বাস্তবায়ন করতে চায়, তবে ক্যাশ করা আর্টিফ্যাক্টগুলোর আর প্রয়োজন না হলে সেগুলো মুক্ত করার দায়িত্ব ড্রাইভারের।