Özel Temsilci uygulama

LiteRT Yetki verme özelliği şunları yapmanıza olanak tanır: modellerinizi (kısmi veya bütün) başka bir yürütücüde çalıştırabilirsiniz. Bu mekanizmanın amacı GPU veya Edge TPU (Tensor) gibi çeşitli cihaz üzerinde hızlandırıcılar İşleme Birimi) kullanın. Bu, geliştiricilere esnek ve esnek çıkarımı hızlandırmak için varsayılan TFLite'tan ayrılmış yöntem.

Aşağıdaki şemada, yetki verilmiş kullanıcılar özetlenmiştir. Daha fazla ayrıntıyı aşağıdaki bölümlerde bulabilirsiniz.

TFLite Delegeleri

Özel yetki verilmiş kullanıcıyı ne zaman oluşturmam gerekir?

LiteRT, hedef hızlandırıcılar için çok çeşitli delegelere sahiptir. Örneğin, GPU, DSP ve EdgeTPU.

Kendi temsilcinizi oluşturmak aşağıdaki senaryolarda faydalı olabilir:

  • Hiçbir makinenin desteklemediği yeni bir makine öğrenimi çıkarım motoru kullanabilirsiniz.
  • Bilinen işlemlerde çalışma zamanını iyileştiren özel bir donanım hızlandırıcı senaryoları ele alacağız.
  • CPU optimizasyonları (ör. operatör kaynaştırma) geliştiriyorsanız hızlandırıyor.

Yetki verilmiş kullanıcıların işleyiş şekli nasıldır?

Aşağıdaki gibi basit bir model grafiğini kullanabilir, yetki verdiğiniz bir “MyDelegate”i kullanabilirsiniz. Dönş.2D ve Ortalama işlemleri için daha hızlı bir uygulama sunar.

Orijinal grafik

Bu "MyDelegate" öğesi uygulandıktan sonra orijinal LiteRT grafiği şu şekilde olacaktır: aşağıdaki gibi güncellendi:

Yetki verilmiş kullanıcı grafiği

Yukarıdaki grafik, LiteRT orijinal grafiği bölerken elde edilir şu iki kuralı izler:

  • Yetki verilen kişinin gerçekleştirebileceği belirli işlemler, Bölümlendirme, başlangıçtaki bilgi işlem iş akışını karşılamaya devam ederken ve operasyonlar arasındaki bağımlılıkları ifade eder.
  • Yetki verilecek her bölümde yalnızca karar verilen kullanıcı tarafından işletilir.

Bir yetki verilmiş kullanıcı tarafından işlenen her bölümlendirme, ona atanmış bir düğüm ile değiştirilir ( aynı zamanda temsilci çekirdeği olarak da adlandırılır) bölümlendirmesi gerekir.

Modele bağlı olarak, nihai grafik bir veya daha fazla düğümle sonuçlanabilir. ikincisi, bazı işlemlerin yetki verilen kullanıcı tarafından desteklenmediği anlamına gelir. Genel olarak birden fazla bölümün ele alınmasını istemezsiniz, çünkü her biri ana grafiğe geçiş yaptığınızda bu geçişin üzerinde yetki verilen alt grafikten elde edilen sonuçların ana grafiğe (örneğin, GPU'dan CPU'ya). Bu tür genel giderler, özellikle de çok sayıda bellek kopyası olduğunda performans kazançlarını artırır.

Kendi özel yetki verdiğinizi uygulama

Tercih edilen yöntem, yetki verilmiş kullanıcı eklemek için SimpleDelegate API'si

Yeni bir yetki verilmiş kullanıcı oluşturmak için 2 arayüz uygulamanız ve kendi uygulamanıza.

1 - SimpleDelegateInterface

Bu sınıf, yetki verilen kullanıcının özelliklerini, yani ve aşağıdakini içeren bir çekirdek oluşturmaya yönelik bir fabrika sınıfı temsil eder. Daha fazla ayrıntı için bu C++ başlık dosyası. Koddaki yorumlar her API'yi ayrıntılı olarak açıklar.

2 - SimpleDelegateKernelInterface

Bu sınıf, projeyi başlatma / hazırlama / ve çalıştırma mantığını içerir. yetki verilmiş bölüm.

Şunları içeriyor: ( tanım)

  • Init(...): Bir defalık başlatmanın yapılması için bir kez çağrılır.
  • Prepare(...): Bu düğümün her farklı örneği için çağrılır. Bu gerçekleşir yetki verilmiş birden fazla bölümünüz varsa. Çoğunlukla hafızayı kullanarak tensörler her yeniden boyutlandırıldığında çağrılacağı için bu değer burada ayırmalıdır.
  • Çağır(...): Çıkarım için çağrılır.

Örnek

Bu örnekte, çok basit bir yetki verilmiş ve yalnızca 2 kişiyi destekleyebilen float32 tensörleriyle birlikte (ADD) ve (SUB) işlem türlerini kapsar.

// 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>();
  }
};

Ardından, 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_;
};

Yetki verdiğiniz yeni kişiyi karşılaştırma ve değerlendirme

TFLite, TFLite modellerine göre hızlıca test edebileceğiniz bir araç seti sunar.

  • Model Karşılaştırma Aracı: Araç bir TFLite modelini alır, rastgele girişler oluşturur ve ardından tekrar tekrar modeli belirtilen sayıda çalıştırma için çalıştırır. Toplu gecikmeyi yazdırır ekleyebilirsiniz.
  • Çıkarım Farkı Aracı: Araç, belirli bir model için rastgele Gauss verileri üretir ve bu verileri iletir. biri tek iş parçacıklı CPU çalıştıran iki farklı TFLite yorumcusu aracılığıyla diğeri ise kullanıcı tanımlı spesifikasyonları kullanıyor. Mutlak değeri ölçer her yorumlayıcıdan gelen çıkış tensörleri arasındaki farkın öğe bazında yapılır. Bu araç, hata ayıklama konusunda da faydalı olabilir sorunları.
  • Görüntü sınıflandırma ve değerlendirme gibi görevlere özel değerlendirme nesne algılama. Bu araçları ziyaret ederek burada

Buna ek olarak TFLite, aşağıdakileri karşılayabilecek çok sayıda çekirdek ve işlem birimi test etmek ve düzenli olarak kampanyanın düzenli olarak TFLite yürütme yolu bozuk değil.

Yeni yetki verilmiş kullanıcı için TFLite testlerini ve araçlarını yeniden kullanmak üzere şu iki seçenekten birini tercih edebilirsiniz:

En iyi yaklaşımı seçme

Her iki yaklaşımda da aşağıda açıklandığı şekilde birkaç değişiklik yapılması gerekir. Ancak ilk yaklaşım, delegeyi statik olarak bağlar ve testin yeniden oluşturulmasını gerektirir. araç olarak kullanabilirsiniz. Buna karşın ikinci seçenek, paylaşılan kitaplık olarak temsil eder ve oluşturma/silme işlemini açmanızı gerektirir yöntemleri içerir.

Sonuç olarak, harici yetki mekanizması TFLite’ın önceden oluşturulmuş LiteRT aracı ikili programları. Ancak bu yöntem daha az müstehcendir ve otomatikleştirilmiş bir modelde ayarlanması daha karmaşık olabilir. entegrasyon testleri. Daha net bilgiler için delege kayıt operatörü yaklaşımını kullanın.

1. seçenek: Yetki verilmiş kayıt operatöründen yararlanın

İlgili içeriği oluşturmak için kullanılan yetki verilmiş kayıt operatörü yetki verilmiş sağlayıcıların bir listesini tutar. TFLite delegeleri komut satırı işaretlerine dayanır ve bu nedenle araçlardır. Yeni temsilciyi söz konusu tüm LiteRT araçlarına dahil etmek için önce yeni bir yetki verilmiş sağlayıcı oluşturmalısınız. ve ardından BUILD kurallarında yalnızca birkaç değişiklik yapın. Bunun tam bir örneği entegrasyon işlemi aşağıda gösterilmiştir (ve kod burada bulabilirsiniz).

SimpleDelegate API'lerini ve extern "C" Bu "kurmaca"yı oluşturma/silme API'leri aşağıda gösterildiği gibi yetki verin:

// 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"i Karşılaştırma Aracı ve Çıkarım Aracı ile entegre etmek için şunu tanımlayın: aşağıdaki gibi bir 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*) {});
}

BUILD kuralı tanımları önemlidir çünkü kitaplığı her zaman bağlıdır ve optimize edici tarafından indirilmez.

#### 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.
)

Şimdi bu iki sarmalayıcı kuralını BUILD dosyanıza ekleyerek Karşılaştırma Aracı ve Çıkarım Aracı ile kullanabileceğiniz diğer değerlendirme araçları sizinle paylaşabilirsiniz.

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",
    ],
)

Ayrıca, bu yetki verilmiş sağlayıcıyı açıklandığı şekilde TFLite çekirdek testlerine de bağlayabilirsiniz. burada bulabilirsiniz.

2. Seçenek: Harici yetki özelliğinden yararlanma

Bu alternatifte, önce bir harici yetki bağdaştırıcısı external_delegate_adaptor.cc aşağıda gösterildiği gibidir. Bu yaklaşım, şuna kıyasla daha az tercih edilir: Daha önce de belirtildiği gibi 1. Seçenek.

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

Şimdi de gösterildiği gibi dinamik bir kitaplık oluşturmak için ilgili BUILD hedefini oluşturun aşağıda bulabilirsiniz:

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",
    ],
)

Bu harici delege .so dosyası oluşturulduktan sonra, ikili programlar oluşturabilir veya ve yeni temsil edilen bir kullanıcıya bağlı olduğu sürece, yeni delegeyle birlikte çalışacak "the" external_delegate_provider açıklandığı gibi komut satırı işaretlerini destekleyen kitaplık burada bulabilirsiniz. Not: Bu harici yetki verilmiş sağlayıcı zaten mevcut test etme ve araç ikili programları oluşturma.

Açıklamalara bakın burada bu model sayesinde, olası bir temsilciyi karşılaştırma üçüncü taraf delege yaklaşımını öğrenmiştik. Test ve kullanıcı dinamikleri için değerlendirme araçlarına odaklanacağız.

Buradaki harici yetkin, ilgili C++ gösterildiği gibi LiteRT Python bağlamasında delege uygulaması burada bulabilirsiniz. Dolayısıyla, burada oluşturulan dinamik harici yetki bağdaştırıcı kitaplığı doğrudan LiteRT Python API'leriyle kullanılır.

Kaynaklar

OS ARCH BINARY_NAME
Linux x86_64
kol
aarch64
Android kol
aarch64