TensorFlow Lite çıkarımı

Çıkarım terimi, girdi verilerine dayalı tahminler yapmak için cihazda bir TensorFlow Lite modeli yürütme sürecini ifade eder. Bir TensorFlow Lite modeliyle çıkarım gerçekleştirmek için, onu bir yorumlayıcı aracılığıyla çalıştırmalısınız. TensorFlow Lite yorumlayıcı, yalın ve hızlı olacak şekilde tasarlanmıştır. Yorumlayıcı, minimum yük, başlatma ve yürütme gecikmesi sağlamak için statik bir grafik sıralaması ve özel (daha az dinamik) bir bellek ayırıcı kullanır.

Bu sayfa, TensorFlow Lite yorumlayıcısına nasıl erişileceğini ve C++, Java ve Python kullanarak bir çıkarımın nasıl gerçekleştirileceğini ve ayrıca desteklenen her platform için diğer kaynaklara bağlantıları açıklar.

Önemli kavramlar

TensorFlow Lite çıkarımı genellikle aşağıdaki adımları izler:

  1. model yükleme

    .tflite modelini, modelin yürütme grafiğini içeren belleğe yüklemelisiniz.

  2. Verileri dönüştürme

    Model için ham girdi verileri genellikle model tarafından beklenen girdi verileri biçimiyle eşleşmez. Örneğin, modelle uyumlu olması için bir görüntüyü yeniden boyutlandırmanız veya görüntü biçimini değiştirmeniz gerekebilir.

  3. Çalışan çıkarım

    Bu adım, modeli çalıştırmak için TensorFlow Lite API'nin kullanılmasını içerir. Aşağıdaki bölümlerde açıklandığı gibi yorumlayıcıyı oluşturmak ve tensörleri tahsis etmek gibi birkaç adımı içerir.

  4. Çıktıyı yorumlama

    Model çıkarımından sonuçlar aldığınızda, tensörleri uygulamanızda yararlı olacak şekilde anlamlı bir şekilde yorumlamanız gerekir.

    Örneğin, bir model yalnızca bir olasılık listesi döndürebilir. Olasılıkları ilgili kategorilere göre haritalamak ve son kullanıcınıza sunmak size kalmış.

desteklenen platformlar

TensorFlow çıkarım API'leri, birden çok programlama dilinde Android , iOS ve Linux gibi en yaygın mobil/gömülü platformlar için sağlanır.

Çoğu durumda, API tasarımı, kullanım kolaylığı yerine performans tercihini yansıtır. TensorFlow Lite, küçük cihazlarda hızlı çıkarım için tasarlanmıştır, bu nedenle API'lerin kolaylık pahasına gereksiz kopyalardan kaçınmaya çalışması şaşırtıcı olmamalıdır. Benzer şekilde, TensorFlow API'leri ile tutarlılık açık bir hedef değildi ve diller arasında bir miktar farklılık beklenebilir.

TensorFlow Lite API, tüm kitaplıklarda modelleri yüklemenizi, girdileri beslemenizi ve çıkarım çıktılarını almanızı sağlar.

Android Platformu

Android'de TensorFlow Lite çıkarımı, Java veya C++ API'leri kullanılarak gerçekleştirilebilir. Java API'leri kolaylık sağlar ve doğrudan Android Etkinlik sınıflarınızda kullanılabilir. C++ API'leri daha fazla esneklik ve hız sunar, ancak verileri Java ve C++ katmanları arasında taşımak için JNI sarmalayıcıları yazmayı gerektirebilir.

C++ ve Java kullanımıyla ilgili ayrıntılar için aşağıya bakın veya bir eğitim ve örnek kod için Android hızlı başlangıcını izleyin.

TensorFlow Lite Android sarmalayıcı kod üreteci

Meta verilerle geliştirilmiş TensorFlow Lite modeli için geliştiriciler, platforma özel sarmalayıcı kodu oluşturmak için TensorFlow Lite Android sarmalayıcı kod üretecini kullanabilir. Sarmalayıcı kod, Android'de ByteBuffer ile doğrudan etkileşime girme ihtiyacını ortadan kaldırır. Bunun yerine geliştiriciler, Bitmap ve Rect gibi yazılan nesnelerle TensorFlow Lite modeliyle etkileşim kurabilir. Daha fazla bilgi için lütfen TensorFlow Lite Android sarmalayıcı kod üretecine bakın.

iOS Platformu

iOS'ta TensorFlow Lite, Swift ve Objective-C ile yazılmış yerel iOS kitaplıklarıyla kullanılabilir. C API'yi doğrudan Objective-C kodlarında da kullanabilirsiniz.

Swift , Objective-C ve C API kullanımıyla ilgili ayrıntılar için aşağıya bakın veya bir öğretici ve örnek kod için iOS hızlı başlangıcını izleyin.

Linux Platformu

Linux platformlarında ( Raspberry Pi dahil), aşağıdaki bölümlerde gösterildiği gibi, C++ ve Python'da bulunan TensorFlow Lite API'lerini kullanarak çıkarımlar çalıştırabilirsiniz.

model çalıştırma

Bir TensorFlow Lite modelini çalıştırmak birkaç basit adımı içerir:

  1. Modeli belleğe yükleyin.
  2. Mevcut bir modele dayalı bir Interpreter oluşturun.
  3. Giriş tensörü değerlerini ayarlayın. (Önceden tanımlanmış boyutlar istenmiyorsa isteğe bağlı olarak giriş tensörlerini yeniden boyutlandırın.)
  4. Çıkarımı çağırın.
  5. Çıkış tensör değerlerini okuyun.

Aşağıdaki bölümlerde, bu adımların her dilde nasıl yapılabileceği açıklanmaktadır.

Java'da bir model yükleyin ve çalıştırın

Platform: android

TensorFlow Lite ile çıkarım çalıştırmak için Java API, öncelikle Android ile kullanım için tasarlanmıştır, bu nedenle Android kitaplığı bağımlılığı olarak mevcuttur: org.tensorflow:tensorflow-lite .

Java'da, bir model yüklemek ve model çıkarımını yürütmek için Interpreter sınıfını kullanacaksınız. Çoğu durumda, ihtiyacınız olan tek API bu olabilir.

Bir Interpreter bir .tflite dosyası kullanarak başlatabilirsiniz:

public Interpreter(@NotNull File modelFile);

Veya bir MappedByteBuffer ile:

public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);

Her iki durumda da geçerli bir TensorFlow Lite modeli sağlamanız gerekir, aksi takdirde API, IllegalArgumentException hatası verir. Bir Interpreter başlatmak için MappedByteBuffer kullanırsanız, Interpreter tüm ömrü boyunca değişmeden kalmalıdır.

Bir model üzerinde çıkarım yapmanın tercih edilen yolu imza kullanmaktır - Tensorflow 2.5'ten başlayarak dönüştürülen modeller için kullanılabilir

try (Interpreter interpreter = new Interpreter(file_of_tensorflowlite_model)) {
  Map<String, Object> inputs = new HashMap<>();
  inputs.put("input_1", input1);
  inputs.put("input_2", input2);
  Map<String, Object> outputs = new HashMap<>();
  outputs.put("output_1", output1);
  interpreter.runSignature(inputs, outputs, "mySignature");
}

runSignature yöntemi üç bağımsız değişken alır:

  • Girişler : imzadaki giriş adından bir giriş nesnesine girişler için harita.

  • Çıktılar : imzadaki çıktı adından çıktı verilerine çıktı eşlemesi için eşleme.

  • İmza Adı [isteğe bağlı]: İmza adı (Modelde tek imza varsa boş bırakılabilir).

Modelin tanımlı imzaları olmadığında çıkarım yapmanın başka bir yolu. Yalnızca Interpreter.run() çağırın. Örneğin:

try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
  interpreter.run(input, output);
}

run() yöntemi yalnızca bir girdi alır ve yalnızca bir çıktı döndürür. Dolayısıyla, modelinizde birden çok giriş veya birden çok çıkış varsa, bunun yerine şunu kullanın:

interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);

Bu durumda, inputs her giriş bir giriş tensörüne karşılık gelir ve map_of_indices_to_outputs , çıkış tensörlerinin indekslerini karşılık gelen çıkış verilerine eşler.

Her iki durumda da tensör indeksleri, modeli oluşturduğunuzda TensorFlow Lite Converter'a verdiğiniz değerlere karşılık gelmelidir. input tensörlerin sırasının, TensorFlow Lite Converter'a verilen sıra ile eşleşmesi gerektiğini unutmayın.

Interpreter sınıfı, bir işlem adı kullanarak herhangi bir model girişinin veya çıktısının dizinini almanız için uygun işlevler de sağlar:

public int getInputIndex(String opName);
public int getOutputIndex(String opName);

opName modelde geçerli bir işlem değilse, bir IllegalArgumentException fırlatır.

Ayrıca Interpreter kaynaklara sahip olduğuna dikkat edin. Bellek sızıntısını önlemek için, kaynaklar aşağıdakiler tarafından kullanımdan sonra serbest bırakılmalıdır:

interpreter.close();

Java ile örnek bir proje için, Android görüntü sınıflandırma örneğine bakın.

Desteklenen veri türleri (Java'da)

TensorFlow Lite'ı kullanmak için giriş ve çıkış tensörlerinin veri türleri aşağıdaki ilkel türlerden biri olmalıdır:

  • float
  • int
  • long
  • byte

String türleri de desteklenir, ancak bunlar ilkel türlerden farklı şekilde kodlanır. Özellikle, bir Tensör dizisinin şekli, Tensördeki dizilerin sayısını ve düzenini belirler, her bir öğenin kendisi değişken uzunlukta bir dizedir. Bu anlamda, Tensörün (bayt) boyutu yalnızca şekilden ve türden hesaplanamaz ve sonuç olarak dizeler tek, düz bir ByteBuffer bağımsız değişkeni olarak sağlanamaz. Bu sayfada bazı örnekler görebilirsiniz.

Integer ve Float gibi kutulu türler dahil olmak üzere diğer veri türleri kullanılırsa, bir IllegalArgumentException oluşturulur.

girişler

Her giriş, desteklenen ilkel türlerin bir dizisi veya çok boyutlu dizisi veya uygun boyutta ham bir ByteBuffer olmalıdır. Girdi bir dizi veya çok boyutlu bir diziyse, ilgili girdi tensörü, çıkarım zamanında dolaylı olarak dizinin boyutlarına göre yeniden boyutlandırılacaktır. Girdi bir ByteBuffer ise, arayanın çıkarımı çalıştırmadan önce ilgili giriş tensörünü ( Interpreter.resizeInput() aracılığıyla) manuel olarak yeniden boyutlandırması gerekir.

ByteBuffer kullanırken, Interpreter gereksiz kopyalardan kaçınmasına izin verdiği için doğrudan bayt arabelleklerini kullanmayı tercih edin. ByteBuffer doğrudan bir bayt arabelleğiyse sırası ByteOrder.nativeOrder() olmalıdır. Bir model çıkarımı için kullanıldıktan sonra, model çıkarımı bitene kadar değişmeden kalmalıdır.

çıktılar

Her çıktı, desteklenen ilkel türlerin bir dizisi veya çok boyutlu dizisi veya uygun boyutta bir ByteBuffer olmalıdır. Bazı modellerin, çıkış tensörlerinin şeklinin girişe bağlı olarak değişebildiği dinamik çıkışlara sahip olduğuna dikkat edin. Mevcut Java çıkarım API'si ile bunu halletmenin doğrudan bir yolu yoktur, ancak planlanan uzantılar bunu mümkün kılacaktır.

Swift'de bir model yükleyin ve çalıştırın

Platform: iOS

Swift API, Cocoapods'tan TensorFlowLiteSwift Pod'da mevcuttur.

Öncelikle, TensorFlowLite modülünü içe aktarmanız gerekir.

import TensorFlowLite
// Getting model path
guard
  let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
else {
  // Error handling...
}

do {
  // Initialize an interpreter with the model.
  let interpreter = try Interpreter(modelPath: modelPath)

  // Allocate memory for the model's input `Tensor`s.
  try interpreter.allocateTensors()

  let inputData: Data  // Should be initialized

  // input data preparation...

  // Copy the input data to the input `Tensor`.
  try self.interpreter.copy(inputData, toInputAt: 0)

  // Run inference by invoking the `Interpreter`.
  try self.interpreter.invoke()

  // Get the output `Tensor`
  let outputTensor = try self.interpreter.output(at: 0)

  // Copy output to `Data` to process the inference results.
  let outputSize = outputTensor.shape.dimensions.reduce(1, {x, y in x * y})
  let outputData =
        UnsafeMutableBufferPointer<Float32>.allocate(capacity: outputSize)
  outputTensor.data.copyBytes(to: outputData)

  if (error != nil) { /* Error handling... */ }
} catch error {
  // Error handling...
}

Objective-C'de bir model yükleyin ve çalıştırın

Platform: iOS

Objective-C API, Cocoapods'tan TensorFlowLiteObjC Pod'da mevcuttur.

Öncelikle, TensorFlowLite modülünü içe aktarmanız gerekir.

@import TensorFlowLite;
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];
NSError *error;

// Initialize an interpreter with the model.
TFLInterpreter *interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath
                                                                  error:&error];
if (error != nil) { /* Error handling... */ }

// Allocate memory for the model's input `TFLTensor`s.
[interpreter allocateTensorsWithError:&error];
if (error != nil) { /* Error handling... */ }

NSMutableData *inputData;  // Should be initialized
// input data preparation...

// Get the input `TFLTensor`
TFLTensor *inputTensor = [interpreter inputTensorAtIndex:0 error:&error];
if (error != nil) { /* Error handling... */ }

// Copy the input data to the input `TFLTensor`.
[inputTensor copyData:inputData error:&error];
if (error != nil) { /* Error handling... */ }

// Run inference by invoking the `TFLInterpreter`.
[interpreter invokeWithError:&error];
if (error != nil) { /* Error handling... */ }

// Get the output `TFLTensor`
TFLTensor *outputTensor = [interpreter outputTensorAtIndex:0 error:&error];
if (error != nil) { /* Error handling... */ }

// Copy output to `NSData` to process the inference results.
NSData *outputData = [outputTensor dataWithError:&error];
if (error != nil) { /* Error handling... */ }

Objective-C kodunda C API kullanma

Şu anda Objective-C API, temsilcileri desteklemiyor. Objective-C koduyla delegeleri kullanmak için, doğrudan temel C API'sini çağırmanız gerekir.

#include "tensorflow/lite/c/c_api.h"
TfLiteModel* model = TfLiteModelCreateFromFile([modelPath UTF8String]);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();

// Create the interpreter.
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);

// Allocate tensors and populate the input tensor data.
TfLiteInterpreterAllocateTensors(interpreter);
TfLiteTensor* input_tensor =
    TfLiteInterpreterGetInputTensor(interpreter, 0);
TfLiteTensorCopyFromBuffer(input_tensor, input.data(),
                           input.size() * sizeof(float));

// Execute inference.
TfLiteInterpreterInvoke(interpreter);

// Extract the output tensor data.
const TfLiteTensor* output_tensor =
    TfLiteInterpreterGetOutputTensor(interpreter, 0);
TfLiteTensorCopyToBuffer(output_tensor, output.data(),
                         output.size() * sizeof(float));

// Dispose of the model and interpreter objects.
TfLiteInterpreterDelete(interpreter);
TfLiteInterpreterOptionsDelete(options);
TfLiteModelDelete(model);

C++'da bir model yükleyin ve çalıştırın

Platformlar: Android, iOS ve Linux

C++'da model FlatBufferModel sınıfında saklanır. Bir TensorFlow Lite modelini içine alır ve modelin nerede depolandığına bağlı olarak onu birkaç farklı şekilde oluşturabilirsiniz:

class FlatBufferModel {
  // Build a model based on a file. Return a nullptr in case of failure.
  static std::unique_ptr<FlatBufferModel> BuildFromFile(
      const char* filename,
      ErrorReporter* error_reporter);

  // Build a model based on a pre-loaded flatbuffer. The caller retains
  // ownership of the buffer and should keep it alive until the returned object
  // is destroyed. Return a nullptr in case of failure.
  static std::unique_ptr<FlatBufferModel> BuildFromBuffer(
      const char* buffer,
      size_t buffer_size,
      ErrorReporter* error_reporter);
};

Artık modeli bir FlatBufferModel nesnesi olarak aldığınıza göre, onu bir Interpreter ile yürütebilirsiniz. Tek bir FlatBufferModel birden fazla Interpreter tarafından aynı anda kullanılabilir.

Interpreter API'nin önemli bölümleri aşağıdaki kod parçacığında gösterilmiştir. Bu not alınmalı:

  • Dizi karşılaştırmalarından (ve dizi kitaplıklarına herhangi bir sabit bağımlılıktan) kaçınmak için tensörler tamsayılarla temsil edilir.
  • Bir tercümana eşzamanlı iş parçacıklarından erişilmemelidir.
  • Giriş ve çıkış tensörleri için bellek tahsisi, tensörleri yeniden boyutlandırmanın hemen ardından AllocateTensors() çağrılarak tetiklenmelidir.

TensorFlow Lite'ın C++ ile en basit kullanımı şöyle görünür:

// Load the model
std::unique_ptr<tflite::FlatBufferModel> model =
    tflite::FlatBufferModel::BuildFromFile(filename);

// Build the interpreter
tflite::ops::builtin::BuiltinOpResolver resolver;
std::unique_ptr<tflite::Interpreter> interpreter;
tflite::InterpreterBuilder(*model, resolver)(&interpreter);

// Resize input tensors, if desired.
interpreter->AllocateTensors();

float* input = interpreter->typed_input_tensor<float>(0);
// Fill `input`.

interpreter->Invoke();

float* output = interpreter->typed_output_tensor<float>(0);

Daha fazla örnek kod için bkz. minimal.cc ve label_image.cc .

Python'da bir model yükleyin ve çalıştırın

Platform: Linux

Çıkarım çalıştırmak için Python API, tf.lite modülünde sağlanır. Buradan, bir model yüklemek ve bir çıkarım yapmak için çoğunlukla yalnızca tf.lite.Interpreter ihtiyacınız vardır.

Aşağıdaki örnek, bir .tflite dosyasını yüklemek ve rasgele girdi verileriyle çıkarım yapmak için Python yorumlayıcısının nasıl kullanılacağını gösterir:

Tanımlı bir SignatureDef ile SavedModel'den dönüştürme yapıyorsanız bu örnek önerilir. TensorFlow 2.5'ten itibaren kullanılabilir

class TestModel(tf.Module):
  def __init__(self):
    super(TestModel, self).__init__()

  @tf.function(input_signature=[tf.TensorSpec(shape=[1, 10], dtype=tf.float32)])
  def add(self, x):
    '''
    Simple method that accepts single input 'x' and returns 'x' + 4.
    '''
    # Name the output 'result' for convenience.
    return {'result' : x + 4}


SAVED_MODEL_PATH = 'content/saved_models/test_variable'
TFLITE_FILE_PATH = 'content/test_variable.tflite'

# Save the model
module = TestModel()
# You can omit the signatures argument and a default signature name will be
# created with name 'serving_default'.
tf.saved_model.save(
    module, SAVED_MODEL_PATH,
    signatures={'my_signature':module.add.get_concrete_function()})

# Convert the model using TFLiteConverter
converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_PATH)
tflite_model = converter.convert()
with open(TFLITE_FILE_PATH, 'wb') as f:
  f.write(tflite_model)

# Load the TFLite model in TFLite Interpreter
interpreter = tf.lite.Interpreter(TFLITE_FILE_PATH)
# There is only 1 signature defined in the model,
# so it will return it by default.
# If there are multiple signatures then we can pass the name.
my_signature = interpreter.get_signature_runner()

# my_signature is callable with input as arguments.
output = my_signature(x=tf.constant([1.0], shape=(1,10), dtype=tf.float32))
# 'output' is dictionary with all outputs from the inference.
# In this case we have single output 'result'.
print(output['result'])

Modelde tanımlanmış SignatureDefs yoksa başka bir örnek.

import numpy as np
import tensorflow as tf

# Load the TFLite model and allocate tensors.
interpreter = tf.lite.Interpreter(model_path="converted_model.tflite")
interpreter.allocate_tensors()

# Get input and output tensors.
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# Test the model on random input data.
input_shape = input_details[0]['shape']
input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32)
interpreter.set_tensor(input_details[0]['index'], input_data)

interpreter.invoke()

# The function `get_tensor()` returns a copy of the tensor data.
# Use `tensor()` in order to get a pointer to the tensor.
output_data = interpreter.get_tensor(output_details[0]['index'])
print(output_data)

Modeli önceden dönüştürülmüş bir .tflite dosyası olarak yüklemeye alternatif olarak, kodunuzu TensorFlow Lite Converter Python API ( tf.lite.TFLiteConverter ) ile birleştirerek Keras modelinizi TensorFlow Lite formatına ve ardından çıkarımı çalıştır:

import numpy as np
import tensorflow as tf

img = tf.keras.Input(shape=(64, 64, 3), name="img")
const = tf.constant([1., 2., 3.]) + tf.constant([1., 4., 4.])
val = img + const
out = tf.identity(val, name="out")

# Convert to TF Lite format
converter = tf.lite.TFLiteConverter.from_keras_model(tf.keras.models.Model(inputs=[img], outputs=[out]))
tflite_model = converter.convert()

# Load the TFLite model and allocate tensors.
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

# Continue to get tensors and so forth, as shown above...

Daha fazla Python örnek kodu için bkz label_image.py .

Dinamik şekil modeliyle çıkarım çalıştırma

Dinamik giriş şekli olan bir model çalıştırmak istiyorsanız, çıkarımı çalıştırmadan önce giriş şeklini yeniden boyutlandırın . Aksi takdirde, Tensorflow modellerindeki None şekli, TFLite modellerinde yer tutucu olan 1 ile değiştirilecektir.

Aşağıdaki örnekler, farklı dillerde çıkarım çalıştırmadan önce giriş şeklinin nasıl yeniden boyutlandırılacağını gösterir. Tüm örnekler, giriş şeklinin [1/None, 10] olarak tanımlandığını ve [3, 10] olarak yeniden boyutlandırılması gerektiğini varsayar.

C++ örneği:

// Resize input tensors before allocate tensors
interpreter->ResizeInputTensor(/*tensor_index=*/0, std::vector<int>{3,10});
interpreter->AllocateTensors();

Python örneği:

# Load the TFLite model in TFLite Interpreter
interpreter = tf.lite.Interpreter(model_path=TFLITE_FILE_PATH)

# Resize input shape for dynamic shape model and allocate tensor
interpreter.resize_tensor_input(interpreter.get_input_details()[0]['index'], [3, 10])
interpreter.allocate_tensors()

# Get input and output tensors.
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()