GPU-তে টেনসরফ্লো লাইট

TensorFlow Lite বেশ কিছু হার্ডওয়্যার এক্সিলারেটর সমর্থন করে। এই দস্তাবেজটি বর্ণনা করে কিভাবে GPU ব্যাকএন্ড ব্যবহার করে টেনসরফ্লো লাইট ডেলিগেট এপিআই ব্যবহার করে অ্যান্ড্রয়েড (ওপেনসিএল বা ওপেনজিএল ইএস 3.1 এবং উচ্চতর প্রয়োজন) এবং আইওএস (আইওএস 8 বা পরবর্তী সংস্করণ প্রয়োজন)।

GPU ত্বরণের সুবিধা

দ্রুততা

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

সঠিকতা

জিপিইউগুলি 16-বিট বা 32-বিট ফ্লোটিং পয়েন্ট নম্বরগুলির সাথে তাদের গণনা করে এবং (সিপিইউগুলির বিপরীতে) সর্বোত্তম কর্মক্ষমতার জন্য পরিমাপকরণের প্রয়োজন হয় না। যদি সঠিকতা হ্রাস আপনার মডেলগুলির জন্য পরিমাপকরণকে অযোগ্য করে তোলে, তাহলে একটি GPU তে আপনার নিউরাল নেটওয়ার্ক চালানো এই উদ্বেগ দূর করতে পারে।

শক্তির দক্ষতা

GPU অনুমানের সাথে আসা আরেকটি সুবিধা হল এর পাওয়ার দক্ষতা। একটি জিপিইউ একটি খুব দক্ষ এবং অপ্টিমাইজড উপায়ে গণনা করে, কম শক্তি খরচ করে এবং একটি সিপিইউতে চালানো একই কাজের তুলনায় কম তাপ উৎপন্ন করে।

সমর্থিত অপারেশন

GPU-তে টেনসরফ্লো লাইট 16-বিট এবং 32-বিট ফ্লোট নির্ভুলতায় নিম্নলিখিত অপ্সগুলিকে সমর্থন করে:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

ডিফল্টরূপে, সমস্ত অপ্স শুধুমাত্র সংস্করণ 1 এ সমর্থিত। পরীক্ষামূলক পরিমাপকরণ সমর্থন সক্ষম করা উপযুক্ত সংস্করণগুলিকে অনুমতি দেয়; উদাহরণস্বরূপ, ADD v2.

মৌলিক ব্যবহার

আপনি অ্যান্ড্রয়েড স্টুডিও এমএল মডেল বাইন্ডিং বা টেনসরফ্লো লাইট ইন্টারপ্রেটার ব্যবহার করছেন কিনা তার উপর নির্ভর করে অ্যান্ড্রয়েডে মডেল অ্যাক্সিলারেশন চালু করার দুটি উপায় রয়েছে।

টেনসরফ্লো লাইট ইন্টারপ্রেটারের মাধ্যমে অ্যান্ড্রয়েড

বিদ্যমান dependencies ব্লকে বিদ্যমান tensorflow-lite প্যাকেজের পাশাপাশি tensorflow-lite-gpu প্যাকেজ যোগ করুন।

dependencies {
    ...
    implementation 'org.tensorflow:tensorflow-lite:2.3.0'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0'
}

তারপর TfLiteDelegate দিয়ে GPU-তে TfLiteDelegate Lite চালান। জাভাতে, আপনি Interpreter.Options এর মাধ্যমে GpuDelegate নির্দিষ্ট করতে পারেন।

কোটলিন

    import org.tensorflow.lite.Interpreter
    import org.tensorflow.lite.gpu.CompatibilityList
    import org.tensorflow.lite.gpu.GpuDelegate

    val compatList = CompatibilityList()

    val options = Interpreter.Options().apply{
        if(compatList.isDelegateSupportedOnThisDevice){
            // if the device has a supported GPU, add the GPU delegate
            val delegateOptions = compatList.bestOptionsForThisDevice
            this.addDelegate(GpuDelegate(delegateOptions))
        } else {
            // if the GPU is not supported, run on 4 threads
            this.setNumThreads(4)
        }
    }

    val interpreter = Interpreter(model, options)

    // Run inference
    writeToInput(input)
    interpreter.run(input, output)
    readFromOutput(output)
      

জাভা

    import org.tensorflow.lite.Interpreter;
    import org.tensorflow.lite.gpu.CompatibilityList;
    import org.tensorflow.lite.gpu.GpuDelegate;

    // Initialize interpreter with GPU delegate
    Interpreter.Options options = new Interpreter.Options();
    CompatibilityList compatList = CompatibilityList();

    if(compatList.isDelegateSupportedOnThisDevice()){
        // if the device has a supported GPU, add the GPU delegate
        GpuDelegate.Options delegateOptions = compatList.getBestOptionsForThisDevice();
        GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions);
        options.addDelegate(gpuDelegate);
    } else {
        // if the GPU is not supported, run on 4 threads
        options.setNumThreads(4);
    }

    Interpreter interpreter = new Interpreter(model, options);

    // Run inference
    writeToInput(input);
    interpreter.run(input, output);
    readFromOutput(output);
      

অ্যান্ড্রয়েড (C/C++)

Android-এ TensorFlow Lite GPU-এর C/C++ ব্যবহারের জন্য, GPU প্রতিনিধিকে TfLiteGpuDelegateV2Create() দিয়ে তৈরি করা যেতে পারে এবং TfLiteGpuDelegateV2Delete TfLiteGpuDelegateV2Delete() TfLiteGpuDelegateV2Create() দিয়ে ধ্বংস করা যেতে পারে।

// Set up interpreter.
auto model = FlatBufferModel::BuildFromFile(model_path);
if (!model) return false;
ops::builtin::BuiltinOpResolver op_resolver;
std::unique_ptr<Interpreter> interpreter;
InterpreterBuilder(*model, op_resolver)(&interpreter);

// NEW: Prepare GPU delegate.
auto* delegate = TfLiteGpuDelegateV2Create(/*default options=*/nullptr);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

// Run inference.
WriteToInputTensor(interpreter->typed_input_tensor<float>(0));
if (interpreter->Invoke() != kTfLiteOk) return false;
ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0));

// NEW: Clean up.
TfLiteGpuDelegateV2Delete(delegate);

কাস্টম বিকল্পগুলির সাথে একটি প্রতিনিধি উদাহরণ তৈরি করতে TfLiteGpuDelegateOptionsV2 দেখুন। আপনি TfLiteGpuDelegateOptionsV2Default() দিয়ে ডিফল্ট বিকল্পগুলি শুরু করতে পারেন এবং তারপরে প্রয়োজনে সেগুলি সংশোধন করতে পারেন।

Android C/C++ এর জন্য TFLite GPU ব্যাজেল বিল্ড সিস্টেম ব্যবহার করে। প্রতিনিধি তৈরি করা যেতে পারে, উদাহরণস্বরূপ, নিম্নলিখিত কমান্ড ব্যবহার করে:

bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:delegate                           # for static library
bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:libtensorflowlite_gpu_delegate.so  # for dynamic library

iOS (C++)

GPU-তে TensorFlow Lite ব্যবহার করতে, TFLGpuDelegateCreate() এর মাধ্যমে GPU প্রতিনিধি পান এবং তারপরে এটিকে Interpreter::ModifyGraphWithDelegate() ( Interpreter::AllocateTensors() ::AllocateTensors() কল করার পরিবর্তে) পাস করুন।

// Set up interpreter.
auto model = FlatBufferModel::BuildFromFile(model_path);
if (!model) return false;
tflite::ops::builtin::BuiltinOpResolver op_resolver;
std::unique_ptr<Interpreter> interpreter;
InterpreterBuilder(*model, op_resolver)(&interpreter);

// NEW: Prepare GPU delegate.

auto* delegate = TFLGpuDelegateCreate(/*default options=*/nullptr);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

// Run inference.
WriteToInputTensor(interpreter->typed_input_tensor<float>(0));
if (interpreter->Invoke() != kTfLiteOk) return false;
ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0));

// Clean up.
TFLGpuDelegateDelete(delegate);

উন্নত ব্যবহার

আইওএসের জন্য বিকল্পগুলি অর্পণ করুন

GPU প্রতিনিধির জন্য কনস্ট্রাক্টর বিকল্পগুলির একটি struct গ্রহণ করে। ( Swift API , Objective-C API , C API )

nullptr (C API) বা কিছুই (Objective-C এবং Swift API) পাস করা ডিফল্ট বিকল্পগুলিকে সেট করে (যা উপরে বেসিক ব্যবহারের উদাহরণে ব্যাখ্যা করা হয়েছে)।

সুইফট

    // THIS:
    var options = MetalDelegate.Options()
    options.isPrecisionLossAllowed = false
    options.waitType = .passive
    options.isQuantizationEnabled = true
    let delegate = MetalDelegate(options: options)

    // IS THE SAME AS THIS:
    let delegate = MetalDelegate()
      

উদ্দেশ্য গ

    // THIS:
    TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
    options.precisionLossAllowed = false;
    options.waitType = TFLMetalDelegateThreadWaitTypePassive;
    options.quantizationEnabled = true;

    TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] initWithOptions:options];

    // IS THE SAME AS THIS:
    TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] init];
      

    // THIS:
    const TFLGpuDelegateOptions options = {
      .allow_precision_loss = false,
      .wait_type = TFLGpuDelegateWaitType::TFLGpuDelegateWaitTypePassive,
      .enable_quantization = true,
    };

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);

    // IS THE SAME AS THIS:
    TfLiteDelegate* delegate = TFLGpuDelegateCreate(nullptr);
      

nullptr বা ডিফল্ট কনস্ট্রাক্টর ব্যবহার করা সুবিধাজনক হলেও, ভবিষ্যতে ডিফল্ট মান পরিবর্তন করা হলে কোনো অপ্রত্যাশিত আচরণ এড়াতে আমরা আপনাকে স্পষ্টভাবে বিকল্পগুলি সেট করার পরামর্শ দিই।

জিপিইউতে কোয়ান্টাইজড মডেল চালানো হচ্ছে

এই বিভাগটি ব্যাখ্যা করে কিভাবে GPU প্রতিনিধি 8-বিট কোয়ান্টাইজড মডেলগুলিকে ত্বরান্বিত করে। এতে কোয়ান্টাইজেশনের সমস্ত স্বাদ অন্তর্ভুক্ত রয়েছে, সহ:

কর্মক্ষমতা অপ্টিমাইজ করতে, ফ্লোটিং-পয়েন্ট ইনপুট এবং আউটপুট টেনসর আছে এমন মডেলগুলি ব্যবহার করুন৷

কিভাবে কাজ করে?

যেহেতু GPU ব্যাকএন্ড শুধুমাত্র ফ্লোটিং-পয়েন্ট এক্সিকিউশনকে সমর্থন করে, তাই আমরা মূল মডেলের 'ফ্লোটিং-পয়েন্ট ভিউ' দিয়ে কোয়ান্টাইজড মডেল চালাই। উচ্চ-স্তরে, এটি নিম্নলিখিত পদক্ষেপগুলিকে অন্তর্ভুক্ত করে:

  • ধ্রুবক টেনসর (যেমন ওজন/পক্ষপাত) একবার জিপিইউ মেমরিতে ডিকুয়ান্টাইজ করা হয়। যখন প্রতিনিধি টিএফলাইট ইন্টারপ্রেটারে প্রয়োগ করা হয় তখন এটি ঘটে।

  • GPU প্রোগ্রামে ইনপুট এবং আউটপুট , যদি 8-বিট কোয়ান্টাইজ করা হয়, প্রতিটি অনুমানের জন্য ডিকোয়ান্টাইজড এবং কোয়ান্টাইজ করা হয় (যথাক্রমে)। এটি TFLite-এর অপ্টিমাইজ করা কার্নেল ব্যবহার করে CPU-তে করা হয়।

  • ক্রিয়াকলাপের মধ্যে কোয়ান্টাইজেশন সিমুলেটর সন্নিবেশ করে কোয়ান্টাইজড আচরণ অনুকরণ করার জন্য GPU প্রোগ্রামটি পরিবর্তন করা হয়েছে। এটি এমন মডেলগুলির জন্য প্রয়োজনীয় যেখানে অপস আশা করে অ্যাক্টিভেশনগুলি কোয়ান্টাইজেশনের সময় শেখা সীমা অনুসরণ করবে।

এই বৈশিষ্ট্যটি নিম্নরূপ প্রতিনিধি বিকল্পগুলি ব্যবহার করে সক্রিয় করা যেতে পারে:

অ্যান্ড্রয়েড

অ্যান্ড্রয়েড এপিআই ডিফল্টরূপে কোয়ান্টাইজড মডেল সমর্থন করে। নিষ্ক্রিয় করতে, নিম্নলিখিতগুলি করুন:

C++ API

TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
options.experimental_flags = TFLITE_GPU_EXPERIMENTAL_FLAGS_NONE;

auto* delegate = TfLiteGpuDelegateV2Create(options);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

জাভা API

GpuDelegate delegate = new GpuDelegate(new GpuDelegate.Options().setQuantizedModelsAllowed(false));

Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);

iOS

iOS API ডিফল্টরূপে কোয়ান্টাইজড মডেল সমর্থন করে। নিষ্ক্রিয় করতে, নিম্নলিখিতগুলি করুন:

সুইফট

    var options = MetalDelegate.Options()
    options.isQuantizationEnabled = false
    let delegate = MetalDelegate(options: options)
      

উদ্দেশ্য গ

    TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
    options.quantizationEnabled = false;
      

    TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault();
    options.enable_quantization = false;

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

ইনপুট/আউটপুট বাফার (শুধুমাত্র iOS, C++ API)

GPU-তে গণনা করতে, GPU-তে ডেটা উপলব্ধ করতে হবে। এটি প্রায়ই একটি মেমরি অনুলিপি সম্পাদন প্রয়োজন. সম্ভব হলে CPU/GPU মেমরির সীমানা অতিক্রম না করা বাঞ্ছনীয়, কারণ এটি একটি উল্লেখযোগ্য পরিমাণ সময় নিতে পারে। সাধারণত, এই ধরনের ক্রসিং অনিবার্য, কিন্তু কিছু বিশেষ ক্ষেত্রে, এক বা অন্য বাদ দেওয়া যেতে পারে।

যদি নেটওয়ার্কের ইনপুটটি GPU মেমরিতে ইতিমধ্যেই লোড করা একটি ছবি হয় (উদাহরণস্বরূপ, ক্যামেরা ফিড ধারণকারী একটি GPU টেক্সচার) এটি CPU মেমরিতে প্রবেশ না করেই GPU মেমরিতে থাকতে পারে। একইভাবে, যদি নেটওয়ার্কের আউটপুট একটি রেন্ডারযোগ্য চিত্রের আকারে হয় (উদাহরণস্বরূপ, চিত্র শৈলী স্থানান্তর ) এটি সরাসরি স্ক্রিনে প্রদর্শিত হতে পারে।

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

ইমেজ ইনপুটটি GPU মেমরিতে আছে বলে ধরে নিই, এটিকে প্রথমে মেটালের জন্য একটি MTLBuffer অবজেক্টে রূপান্তর করতে হবে। আপনি TFLGpuDelegateBindMetalBufferToTensor() এর সাথে একটি ব্যবহারকারী-প্রস্তুত MTLBuffer সাথে একটি TfLiteTensor যুক্ত করতে পারেন। মনে রাখবেন TFLGpuDelegateBindMetalBufferToTensor() অবশ্যই Interpreter::ModifyGraphWithDelegate() পরে কল করতে হবে। উপরন্তু, অনুমান আউটপুট, ডিফল্টরূপে, GPU মেমরি থেকে CPU মেমরিতে অনুলিপি করা হয়। শুরু করার সময় Interpreter::SetAllowBufferHandleOutput(true) কল করে এই আচরণটি বন্ধ করা যেতে পারে।

#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
#include "tensorflow/lite/delegates/gpu/metal_delegate_internal.h"

// ...

// Prepare GPU delegate.
auto* delegate = TFLGpuDelegateCreate(nullptr);

if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

interpreter->SetAllowBufferHandleOutput(true);  // disable default gpu->cpu copy
if (!TFLGpuDelegateBindMetalBufferToTensor(
        delegate, interpreter->inputs()[0], user_provided_input_buffer)) {
  return false;
}
if (!TFLGpuDelegateBindMetalBufferToTensor(
        delegate, interpreter->outputs()[0], user_provided_output_buffer)) {
  return false;
}

// Run inference.
if (interpreter->Invoke() != kTfLiteOk) return false;

GPU প্রতিনিধি সিরিয়ালাইজেশন

জিপিইউ কার্নেল কোডের সিরিয়ালাইজেশন ব্যবহার করে এবং পূর্ববর্তী ইনিশিয়ালাইজেশন থেকে মডেল ডেটা ব্যবহার করলে জিপিইউ প্রতিনিধির ইনিশিয়ালাইজেশনের লেটেন্সি 90% পর্যন্ত কমাতে পারে। এই উন্নতি সময় সাশ্রয়ের জন্য ডিস্ক স্থান বিনিময় দ্বারা অর্জন করা হয়. আপনি কয়েকটি কনফিগারেশন বিকল্পের সাথে এই বৈশিষ্ট্যটি সক্ষম করতে পারেন, যেমনটি নিম্নলিখিত কোড উদাহরণগুলিতে দেখানো হয়েছে:

সি++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

জাভা

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

সিরিয়ালাইজেশন বৈশিষ্ট্য ব্যবহার করার সময়, নিশ্চিত করুন যে আপনার কোড এই বাস্তবায়নের নিয়মগুলি মেনে চলছে:

  • সিরিয়ালাইজেশন ডেটা এমন একটি ডিরেক্টরিতে সংরক্ষণ করুন যা অন্য অ্যাপগুলিতে অ্যাক্সেসযোগ্য নয়। অ্যান্ড্রয়েড ডিভাইসে, getCodeCacheDir() ব্যবহার করুন যা বর্তমান অ্যাপ্লিকেশনের জন্য ব্যক্তিগত এমন একটি অবস্থান নির্দেশ করে।
  • মডেল টোকেন নির্দিষ্ট মডেলের জন্য ডিভাইসের জন্য অনন্য হতে হবে। আপনি মডেল ডেটা থেকে একটি আঙ্গুলের ছাপ তৈরি করে একটি মডেল টোকেন গণনা করতে পারেন (যেমন farmhash::Fingerprint64 ব্যবহার করে)।

কৌশল

  • CPU-তে তুচ্ছ কিছু ক্রিয়াকলাপ একটি GPU-তে উচ্চ খরচ হতে পারে। এই ধরনের অপারেশনের একটি ক্লাসে বিভিন্ন ধরনের রিশেপ অপারেশন অন্তর্ভুক্ত থাকে ( BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH , এবং অনুরূপ অপারেশন সহ)। যদি এই ক্রিয়াকলাপগুলির প্রয়োজন না হয় (উদাহরণস্বরূপ, এগুলি সিস্টেম সম্পর্কে নেটওয়ার্ক আর্কিটেক্টকে সহায়তা করার জন্য ঢোকানো হয়েছিল কিন্তু অন্যথায় আউটপুটকে প্রভাবিত করে না), তবে কর্মক্ষমতার জন্য তাদের অপসারণ করা মূল্যবান।

  • একটি GPU-তে, টেনসর ডেটা 4-চ্যানেলগুলিতে কাটা হয়। এইভাবে, আকৃতির একটি টেনসরের [B, H, W, 5] উপর একই কাজ করবে, তবে [B, H, W, 4] [B, H, W, 8] এর চেয়ে উল্লেখযোগ্যভাবে খারাপ [B, H, W, 4]

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