การใช้การมอบสิทธิ์ที่กำหนดเอง

ผู้รู้จริง การมอบสิทธิ์ช่วยให้คุณทำสิ่งต่อไปนี้ได้ เรียกใช้โมเดลของคุณ (บางส่วนหรือทั้งหมด) กับผู้ดำเนินการรายอื่น กลไกนี้สามารถใช้ประโยชน์จาก Accelerator ต่างๆ ในอุปกรณ์ เช่น GPU หรือ Edge TPU (Tensor หน่วยประมวลผล) สำหรับการอนุมาน ซึ่งทำให้นักพัฒนาแอปมีความยืดหยุ่นและ เมธอดที่แยกออกจาก TFLite เริ่มต้นเพื่อเพิ่มความเร็วในการอนุมาน

แผนภาพด้านล่างจะสรุปผู้รับมอบสิทธิ์ โปรดดูรายละเอียดเพิ่มเติมในส่วนด้านล่าง

ตัวแทน TFLite

ฉันควรสร้างผู้รับมอบสิทธิ์ที่กำหนดเองเมื่อใด

LiteRT มีผู้แทนที่หลากหลายสำหรับ Accelerator เป้าหมาย เช่น GPU, DSP และ EdgeTPU

การสร้างผู้รับมอบสิทธิ์ของคุณเองมีประโยชน์ในสถานการณ์ต่อไปนี้

  • คุณต้องการผสานรวมเครื่องมือการอนุมาน ML ใหม่ที่ไม่มีการสนับสนุน ผู้แทนที่มีอยู่
  • คุณมีตัวเร่งฮาร์ดแวร์ที่กำหนดเองซึ่งปรับปรุงรันไทม์สำหรับ สถานการณ์
  • คุณกำลังพัฒนาการเพิ่มประสิทธิภาพ CPU (เช่น การรวมโอเปอเรเตอร์) ซึ่งสามารถ รถบางรุ่นอาจเร็วขึ้น

ผู้รับมอบสิทธิ์ทำงานอย่างไร

ลองพิจารณากราฟโมเดลง่ายๆ อย่างเช่นกราฟต่อไปนี้ และผู้รับมอบสิทธิ์ "MyDelegate" ซึ่งมีการติดตั้งใช้งาน Conversion 2D และค่าเฉลี่ยได้เร็วขึ้น

กราฟเดิม

หลังจากใช้ "MyDelegate" นี้ กราฟ LiteRT เดิมจะเป็น มีการอัปเดตดังต่อไปนี้

กราฟที่มีผู้รับมอบสิทธิ์

กราฟด้านบนได้มาจากการที่ LiteRT แยกกราฟต้นฉบับ กฎสองข้อต่อไปนี้:

  • การดำเนินงานบางอย่างที่ผู้ได้รับมอบสิทธิ์จัดการได้จะจัดไว้ใน แบ่งพาร์ติชันในขณะที่ยังคงพึงพอใจกับเวิร์กโฟลว์การประมวลผลแบบเดิม ทรัพยากร Dependency ระหว่างการดำเนินการต่างๆ
  • แต่ละพาร์ติชันที่ต้องได้รับมอบสิทธิ์จะมีเฉพาะโหนดอินพุตและเอาต์พุตที่ไม่ได้ ที่ผู้ได้รับมอบสิทธิ์จัดการ

แต่ละพาร์ติชันที่จัดการโดยผู้รับมอบสิทธิ์จะถูกแทนที่ด้วยโหนดที่ได้รับมอบสิทธิ์ (สามารถ หรือที่เรียกว่าเคอร์เนลที่ได้รับมอบสิทธิ์) ในกราฟดั้งเดิมที่ประเมินฟิลด์ พาร์ติชันในการเรียก

กราฟสุดท้ายอาจมีโหนด 1 โหนดหรือมากกว่าก็ได้ ทั้งนี้ขึ้นอยู่กับโมเดล หมายความว่าผู้ได้รับมอบสิทธิ์ไม่รองรับการดำเนินการบางรายการ โดยทั่วไป คุณ ไม่ต้องการให้มีพาร์ติชันหลายพาร์ติชันโดยผู้รับมอบสิทธิ์ เนื่องจากแต่ละพาร์ติชัน เมื่อคุณเปลี่ยนจากผู้รับมอบสิทธิ์ไปเป็นกราฟหลัก ก็จะมีค่าใช้จ่าย ส่งผลลัพธ์จากกราฟย่อยที่ได้รับมอบสิทธิ์ไปยังกราฟหลักที่ได้ผลลัพธ์ เนื่องจากการคัดลอกหน่วยความจำ (เช่น GPU ไปยัง CPU) ค่าใช้จ่ายในการดำเนินการดังกล่าวอาจชดเชย ประสิทธิภาพจะเพิ่มขึ้น โดยเฉพาะเมื่อมีสำเนาหน่วยความจำจำนวนมาก

การใช้ผู้รับมอบสิทธิ์ที่กำหนดเอง

วิธีที่แนะนำในการเพิ่มผู้รับมอบสิทธิ์คือ SimpleDelegate API

หากต้องการสร้างผู้รับมอบสิทธิ์ใหม่ คุณต้องใช้อินเทอร์เฟซ 2 รายการและระบุ ของตัวเองสำหรับเมธอดอินเทอร์เฟซ

1 - SimpleDelegateInterface

คลาสนี้แสดงถึงความสามารถของผู้รับมอบสิทธิ์ ซึ่งการดำเนินการที่ และคลาสจากโรงงานสำหรับการสร้างเคอร์เนลที่รวมค่า กราฟที่ได้รับมอบสิทธิ์ สำหรับรายละเอียดเพิ่มเติม โปรดดูอินเทอร์เฟซที่กำหนดไว้ใน ไฟล์ส่วนหัว C++ ความคิดเห็นในโค้ดจะอธิบาย API แต่ละรายการอย่างละเอียด

2 - SimpleDelegateKernelInterface

คลาสนี้สรุปตรรกะสำหรับการเริ่มต้น / เตรียม / และเรียกใช้ พาร์ติชันที่ได้รับมอบสิทธิ์

ซึ่งมี: (ดู คำจำกัดความ)

  • Init(...): ซึ่งจะถูกเรียกใช้ 1 ครั้งเพื่อทำการเริ่มต้นแบบครั้งเดียว
  • Prepare(...): เรียกใช้สำหรับอินสแตนซ์แต่ละรายการของโหนดนี้ - กรณีนี้ หากมีพาร์ติชันที่มอบสิทธิ์หลายพาร์ติชัน โดยปกติแล้วคุณจะอยากทำความทรงจำ การจัดสรรที่นี่ เนื่องจากจะมีการเรียกทุกครั้งที่มีการปรับขนาด Tensor
  • เรียกใช้(...): ซึ่งจะถูกเรียกใช้เพื่ออนุมาน

ตัวอย่าง

ในตัวอย่างนี้ คุณจะสร้างผู้รับมอบสิทธิ์อย่างง่ายซึ่งรองรับได้เพียง 2 รายการ ประเภทของการดำเนินการ (ADD) และ (SUB) ที่มี Float32 เท่านั้น

// MyDelegate implements the interface of SimpleDelegateInterface.
// This holds the Delegate capabilities.
class MyDelegate : public SimpleDelegateInterface {
 public:
  bool IsNodeSupportedByDelegate(const TfLiteRegistration* registration,
                                 const TfLiteNode* node,
                                 TfLiteContext* context) const override {
    // Only supports Add and Sub ops.
    if (kTfLiteBuiltinAdd != registration->builtin_code &&
        kTfLiteBuiltinSub != registration->builtin_code)
      return false;
    // This delegate only supports float32 types.
    for (int i = 0; i < node->inputs->size; ++i) {
      auto& tensor = context->tensors[node->inputs->data[i]];
      if (tensor.type != kTfLiteFloat32) return false;
    }
    return true;
  }

  TfLiteStatus Initialize(TfLiteContext* context) override { return kTfLiteOk; }

  const char* Name() const override {
    static constexpr char kName[] = "MyDelegate";
    return kName;
  }

  std::unique_ptr<SimpleDelegateKernelInterface> CreateDelegateKernelInterface()
      override {
    return std::make_unique<MyDelegateKernel>();
  }
};

ถัดไป ให้สร้างเคอร์เนลที่มอบสิทธิ์ของคุณเองโดยรับค่าจาก SimpleDelegateKernelInterface

// My delegate kernel.
class MyDelegateKernel : public SimpleDelegateKernelInterface {
 public:
  TfLiteStatus Init(TfLiteContext* context,
                    const TfLiteDelegateParams* params) override {
    // Save index to all nodes which are part of this delegate.
    inputs_.resize(params->nodes_to_replace->size);
    outputs_.resize(params->nodes_to_replace->size);
    builtin_code_.resize(params->nodes_to_replace->size);
    for (int i = 0; i < params->nodes_to_replace->size; ++i) {
      const int node_index = params->nodes_to_replace->data[i];
      // Get this node information.
      TfLiteNode* delegated_node = nullptr;
      TfLiteRegistration* delegated_node_registration = nullptr;
      TF_LITE_ENSURE_EQ(
          context,
          context->GetNodeAndRegistration(context, node_index, &delegated_node,
                                          &delegated_node_registration),
          kTfLiteOk);
      inputs_[i].push_back(delegated_node->inputs->data[0]);
      inputs_[i].push_back(delegated_node->inputs->data[1]);
      outputs_[i].push_back(delegated_node->outputs->data[0]);
      builtin_code_[i] = delegated_node_registration->builtin_code;
    }
    return kTfLiteOk;
  }

  TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) override {
    return kTfLiteOk;
  }

  TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) override {
    // Evaluate the delegated graph.
    // Here we loop over all the delegated nodes.
    // We know that all the nodes are either ADD or SUB operations and the
    // number of nodes equals ''inputs_.size()'' and inputs[i] is a list of
    // tensor indices for inputs to node ''i'', while outputs_[i] is the list of
    // outputs for node
    // ''i''. Note, that it is intentional we have simple implementation as this
    // is for demonstration.

    for (int i = 0; i < inputs_.size(); ++i) {
      // Get the node input tensors.
      // Add/Sub operation accepts 2 inputs.
      auto& input_tensor_1 = context->tensors[inputs_[i][0]];
      auto& input_tensor_2 = context->tensors[inputs_[i][1]];
      auto& output_tensor = context->tensors[outputs_[i][0]];
      TF_LITE_ENSURE_EQ(
          context,
          ComputeResult(context, builtin_code_[i], &input_tensor_1,
                        &input_tensor_2, &output_tensor),
          kTfLiteOk);
    }
    return kTfLiteOk;
  }

 private:
  // Computes the result of addition of 'input_tensor_1' and 'input_tensor_2'
  // and store the result in 'output_tensor'.
  TfLiteStatus ComputeResult(TfLiteContext* context, int builtin_code,
                             const TfLiteTensor* input_tensor_1,
                             const TfLiteTensor* input_tensor_2,
                             TfLiteTensor* output_tensor) {
    if (NumElements(input_tensor_1) != NumElements(input_tensor_2) ||
        NumElements(input_tensor_1) != NumElements(output_tensor)) {
      return kTfLiteDelegateError;
    }
    // This code assumes no activation, and no broadcasting needed (both inputs
    // have the same size).
    auto* input_1 = GetTensorData<float>(input_tensor_1);
    auto* input_2 = GetTensorData<float>(input_tensor_2);
    auto* output = GetTensorData<float>(output_tensor);
    for (int i = 0; i < NumElements(input_tensor_1); ++i) {
      if (builtin_code == kTfLiteBuiltinAdd)
        output[i] = input_1[i] + input_2[i];
      else
        output[i] = input_1[i] - input_2[i];
    }
    return kTfLiteOk;
  }

  // Holds the indices of the input/output tensors.
  // inputs_[i] is list of all input tensors to node at index 'i'.
  // outputs_[i] is list of all output tensors to node at index 'i'.
  std::vector<std::vector<int>> inputs_, outputs_;
  // Holds the builtin code of the ops.
  // builtin_code_[i] is the type of node at index 'i'
  std::vector<int> builtin_code_;
};

เปรียบเทียบและประเมินผู้รับมอบสิทธิ์ใหม่

TFLite มีชุดเครื่องมือที่คุณสามารถทดสอบกับโมเดล TFLite ได้อย่างรวดเร็ว

  • เครื่องมือเปรียบเทียบโมเดล: เครื่องมือจะใช้โมเดล TFLite สร้างอินพุตแบบสุ่ม แล้วทำซ้ำ เรียกใช้โมเดลสำหรับจำนวนการเรียกใช้ที่ระบุ พิมพ์เวลาในการตอบสนองแบบรวม สถิติในช่วงท้าย
  • เครื่องมือเปรียบเทียบการอนุมาน: สำหรับโมเดลหนึ่งๆ เครื่องมือจะสร้างข้อมูลเกาส์เชียนแบบสุ่มและส่งต่อข้อมูลดังกล่าว ผ่านอินเทอร์พรีเตอร์ TFLite 2 ตัว ตัวหนึ่งใช้ CPU แบบเทรดเดี่ยว และเคอร์เนลอีกอย่างหนึ่งโดยใช้ข้อกำหนดที่ผู้ใช้กำหนด วัดค่าสัมบูรณ์ ความแตกต่างระหว่าง Tensor เอาต์พุตจากล่ามแต่ละตัว ต่อองค์ประกอบ เครื่องมือนี้ยังช่วยเพิ่มความแม่นยำในการแก้ไขข้อบกพร่องด้วย ปัญหา
  • นอกจากนี้ยังมีเครื่องมือการประเมินเฉพาะงาน สำหรับการจำแนกประเภทรูปภาพ การตรวจจับออบเจ็กต์ เครื่องมือเหล่านี้จะพบได้ ที่นี่

นอกจากนี้ TFLite ยังมีชุดการทดสอบเคอร์เนลและหน่วยการทดสอบจำนวนมากที่อาจ ใช้ซ้ำเพื่อทดสอบตัวแทนใหม่ที่มีความครอบคลุมมากขึ้น และเพื่อให้ เส้นทางการดำเนินการ TFLite ไม่ทำงาน

หากต้องการนําการทดสอบและเครื่องมือ TFLite มาใช้ซ้ำสําหรับผู้รับมอบสิทธิ์ใหม่ คุณสามารถใช้ ตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้

การเลือกแนวทางที่ดีที่สุด

ทั้ง 2 วิธีต้องมีการเปลี่ยนแปลงเล็กน้อยดังรายละเอียดด้านล่าง อย่างไรก็ตาม จะลิงก์ผู้รับมอบสิทธิ์แบบคงที่และต้องสร้างการทดสอบใหม่ การเปรียบเทียบและการประเมินผล ในทางกลับกัน โฆษณาประเภทที่ 2 เป็นไลบรารีที่ใช้ร่วมกัน และกำหนดให้คุณแสดงการสร้าง/ลบ จากไลบรารีที่ใช้ร่วมกัน

ด้วยเหตุนี้ กลไกการมอบสิทธิ์ภายนอกจะทำงานร่วมกับ TFLite ไบนารีเครื่องมือ LiteRT ที่สร้างไว้ล่วงหน้า แต่การตั้งค่าการทำงานอัตโนมัติอาจมีความชัดเจนน้อยลง และอาจทำให้การตั้งค่าโดยอัตโนมัติมีความซับซ้อนกว่า การทดสอบการผสานรวม ใช้แนวทางผู้รับจดทะเบียนแบบมอบสิทธิ์เพื่อความชัดเจนยิ่งขึ้น

ตัวเลือกที่ 1: ใช้ประโยชน์จากผู้รับจดทะเบียนผู้รับมอบสิทธิ์

ผู้รับจดทะเบียนผู้รับมอบสิทธิ์ จะมีรายชื่อผู้ให้บริการที่ได้รับมอบสิทธิ์ ซึ่งแต่ละรายมีวิธีง่ายๆ ในการสร้าง ตัวแทน TFLite ตามแฟล็กบรรทัดคำสั่ง ดังนั้นจึงสะดวกสำหรับ เครื่องมือ เพิ่มการมอบสิทธิ์ใหม่ให้กับเครื่องมือ LiteRT ทั้งหมดที่กล่าวถึง ด้านบน ให้สร้างผู้ให้บริการผู้รับมอบสิทธิ์รายใหม่ จากนั้นทำการเปลี่ยนแปลงเพียงเล็กน้อยกับกฎ "สร้าง" ตัวอย่างฉบับเต็มของ ขั้นตอนการผสานรวมแสดงอยู่ด้านล่าง (และดูโค้ด ที่นี่)

สมมติว่าคุณมีผู้รับมอบสิทธิ์ที่ใช้ SimpleDelegate API และ "C" ภายนอก API ของการสร้าง/ลบ "แบบจำลอง" นี้ ที่ได้รับมอบสิทธิ์ดังที่แสดงด้านล่าง

// Returns default options for DummyDelegate.
DummyDelegateOptions TfLiteDummyDelegateOptionsDefault();

// Creates a new delegate instance that need to be destroyed with
// `TfLiteDummyDelegateDelete` when delegate is no longer used by TFLite.
// When `options` is set to `nullptr`, the above default values are used:
TfLiteDelegate* TfLiteDummyDelegateCreate(const DummyDelegateOptions* options);

// Destroys a delegate created with `TfLiteDummyDelegateCreate` call.
void TfLiteDummyDelegateDelete(TfLiteDelegate* delegate);

ในการผสานรวม "DummyDelegate" ในเครื่องมือเปรียบเทียบและเครื่องมือการอนุมาน ให้ระบุ DelegateProvider อย่างเช่นด้านล่างนี้

class DummyDelegateProvider : public DelegateProvider {
 public:
  DummyDelegateProvider() {
    default_params_.AddParam("use_dummy_delegate",
                             ToolParam::Create<bool>(false));
  }

  std::vector<Flag> CreateFlags(ToolParams* params) const final;

  void LogParams(const ToolParams& params) const final;

  TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final;

  std::string GetName() const final { return "DummyDelegate"; }
};
REGISTER_DELEGATE_PROVIDER(DummyDelegateProvider);

std::vector<Flag> DummyDelegateProvider::CreateFlags(ToolParams* params) const {
  std::vector<Flag> flags = {CreateFlag<bool>("use_dummy_delegate", params,
                                              "use the dummy delegate.")};
  return flags;
}

void DummyDelegateProvider::LogParams(const ToolParams& params) const {
  TFLITE_LOG(INFO) << "Use dummy test delegate : ["
                   << params.Get<bool>("use_dummy_delegate") << "]";
}

TfLiteDelegatePtr DummyDelegateProvider::CreateTfLiteDelegate(
    const ToolParams& params) const {
  if (params.Get<bool>("use_dummy_delegate")) {
    auto default_options = TfLiteDummyDelegateOptionsDefault();
    return TfLiteDummyDelegateCreateUnique(&default_options);
  }
  return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {});
}

คำจำกัดความของกฎ "สร้าง" เป็นสิ่งสำคัญ เพราะคุณต้องตรวจสอบว่า มีการเชื่อมโยงไลบรารีเสมอ และไม่ถูกลบโดยเครื่องมือเพิ่มประสิทธิภาพ

#### The following are for using the dummy test delegate in TFLite tooling ####
cc_library(
    name = "dummy_delegate_provider",
    srcs = ["dummy_delegate_provider.cc"],
    copts = tflite_copts(),
    deps = [
        ":dummy_delegate",
        "//tensorflow/lite/tools/delegates:delegate_provider_hdr",
    ],
    alwayslink = 1, # This is required so the optimizer doesn't optimize the library away.
)

ตอนนี้ให้เพิ่มกฎ Wrapper สองข้อนี้ในไฟล์ BUILD เพื่อสร้างเวอร์ชันของ เครื่องมือเปรียบเทียบและเครื่องมืออนุมาน และเครื่องมือการประเมินอื่นๆ ที่สามารถเรียกใช้ กับผู้ได้รับมอบสิทธิ์ของคุณเอง

cc_binary(
    name = "benchmark_model_plus_dummy_delegate",
    copts = tflite_copts(),
    linkopts = task_linkopts(),
    deps = [
        ":dummy_delegate_provider",
        "//tensorflow/lite/tools/benchmark:benchmark_model_main",
    ],
)

cc_binary(
    name = "inference_diff_plus_dummy_delegate",
    copts = tflite_copts(),
    linkopts = task_linkopts(),
    deps = [
        ":dummy_delegate_provider",
        "//tensorflow/lite/tools/evaluation/tasks:task_executor_main",
        "//tensorflow/lite/tools/evaluation/tasks/inference_diff:run_eval_lib",
    ],
)

cc_binary(
    name = "imagenet_classification_eval_plus_dummy_delegate",
    copts = tflite_copts(),
    linkopts = task_linkopts(),
    deps = [
        ":dummy_delegate_provider",
        "//tensorflow/lite/tools/evaluation/tasks:task_executor_main",
        "//tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification:run_eval_lib",
    ],
)

cc_binary(
    name = "coco_object_detection_eval_plus_dummy_delegate",
    copts = tflite_copts(),
    linkopts = task_linkopts(),
    deps = [
        ":dummy_delegate_provider",
        "//tensorflow/lite/tools/evaluation/tasks:task_executor_main",
        "//tensorflow/lite/tools/evaluation/tasks/coco_object_detection:run_eval_lib",
    ],
)

คุณยังเชื่อมต่อผู้ให้บริการที่ได้รับมอบสิทธิ์รายนี้กับการทดสอบเคอร์เนล TFLite ตามที่อธิบายไว้ได้อีกด้วย ที่นี่

ตัวเลือกที่ 2: ใช้ประโยชน์จากผู้รับมอบสิทธิ์ภายนอก

ในกรณีนี้ คุณต้องสร้างอะแดปเตอร์ที่ได้รับมอบสิทธิ์ภายนอก external_delegate_adaptor.cc ดังที่แสดงด้านล่าง โปรดทราบว่าวิธีนี้เป็นที่ชื่นชอบน้อยกว่าเล็กน้อยเมื่อเทียบกับ ตัวเลือกที่ 1 ตามที่ได้กล่าวไปแล้ว

TfLiteDelegate* CreateDummyDelegateFromOptions(char** options_keys,
                                               char** options_values,
                                               size_t num_options) {
  DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault();

  // Parse key-values options to DummyDelegateOptions.
  // You can achieve this by mimicking them as command-line flags.
  std::unique_ptr<const char*> argv =
      std::unique_ptr<const char*>(new const char*[num_options + 1]);
  constexpr char kDummyDelegateParsing[] = "dummy_delegate_parsing";
  argv.get()[0] = kDummyDelegateParsing;

  std::vector<std::string> option_args;
  option_args.reserve(num_options);
  for (int i = 0; i < num_options; ++i) {
    option_args.emplace_back("--");
    option_args.rbegin()->append(options_keys[i]);
    option_args.rbegin()->push_back('=');
    option_args.rbegin()->append(options_values[i]);
    argv.get()[i + 1] = option_args.rbegin()->c_str();
  }

  // Define command-line flags.
  // ...
  std::vector<tflite::Flag> flag_list = {
      tflite::Flag::CreateFlag(...),
      ...,
      tflite::Flag::CreateFlag(...),
  };

  int argc = num_options + 1;
  if (!tflite::Flags::Parse(&argc, argv.get(), flag_list)) {
    return nullptr;
  }

  return TfLiteDummyDelegateCreate(&options);
}

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

// Defines two symbols that need to be exported to use the TFLite external
// delegate. See tensorflow/lite/delegates/external for details.
TFL_CAPI_EXPORT TfLiteDelegate* tflite_plugin_create_delegate(
    char** options_keys, char** options_values, size_t num_options,
    void (*report_error)(const char*)) {
  return tflite::tools::CreateDummyDelegateFromOptions(
      options_keys, options_values, num_options);
}

TFL_CAPI_EXPORT void tflite_plugin_destroy_delegate(TfLiteDelegate* delegate) {
  TfLiteDummyDelegateDelete(delegate);
}

#ifdef __cplusplus
}
#endif  // __cplusplus

สร้างเป้าหมาย BUILD ที่เกี่ยวข้องเพื่อสร้างไลบรารีแบบไดนามิกตามที่แสดง ด้านล่าง

cc_binary(
    name = "dummy_external_delegate.so",
    srcs = [
        "external_delegate_adaptor.cc",
    ],
    linkshared = 1,
    linkstatic = 1,
    deps = [
        ":dummy_delegate",
        "//tensorflow/lite/c:common",
        "//tensorflow/lite/tools:command_line_flags",
        "//tensorflow/lite/tools:logging",
    ],
)

หลังจากสร้างไฟล์ .so ที่มอบสิทธิ์ภายนอกนี้แล้ว คุณจะสร้างไบนารีหรือใช้ รายการที่สร้างไว้ล่วงหน้าเพื่อทำงานกับผู้รับมอบสิทธิ์ใหม่ตราบใดที่ไบนารีนั้นลิงก์อยู่ เวลา external_delegate_provider ไลบรารีที่รองรับแฟล็กบรรทัดคำสั่งตามที่อธิบายไว้ ที่นี่ หมายเหตุ: ลิงก์ผู้ให้บริการที่ได้รับมอบสิทธิ์ภายนอกรายนี้กับ การทดสอบและไบนารีเครื่องมือ

ดูคำอธิบาย ที่นี่ สำหรับภาพประกอบวิธีเปรียบเทียบตัวแทนจำลองผ่าน ผู้รับมอบสิทธิ์ภายนอก คุณสามารถใช้คำสั่งที่คล้ายกันสำหรับการทดสอบและ เครื่องมือประเมินที่พูดถึงไปก่อนหน้านี้

โปรดทราบว่าผู้รับมอบสิทธิ์ภายนอกคือ C++ ที่เกี่ยวข้อง การนำการมอบสิทธิ์ไปใช้ในการเชื่อมโยง LiteRT Python ดังที่แสดง ที่นี่ ดังนั้น ไลบรารีอะแดปเตอร์สำหรับมอบสิทธิ์ภายนอกแบบไดนามิกที่สร้างขึ้นที่นี่อาจเป็น ที่ใช้กับ LiteRT Python API ได้โดยตรง

แหล่งข้อมูล

ระบบปฏิบัติการ ARCH BINARY_NAME
Linux x86_64
กลุ่ม
aarch64
Android กลุ่ม
aarch64