TensorFlow Lite çıkarımı

Çıkarım terimi, giriş verilerine dayalı tahminlerde bulunmak için cihaz üzerinde bir TensorFlow Lite modelini çalıştırma işlemini ifade eder. TensorFlow Lite modeliyle çıkarım yapmak için modeli bir yorumlayıcı üzerinden çalıştırmanız gerekir. TensorFlow Lite yorumlayıcısı basit ve hızlı olacak şekilde tasarlanmıştır. Çevirmen, minimum yükleme, başlatma ve yürütme gecikmesi için statik grafik sıralaması ve özel (daha az dinamik) bir bellek ayırıcı kullanır.

Bu sayfada, TensorFlow Lite yorumlayıcısına nasıl erişileceği ve C++, Java ve Python kullanarak nasıl çıkarım yapılacağı, ayrıca desteklenen her bir platform için diğer kaynakların bağlantıları açıklanmaktadır.

Önemli kavramlar

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

  1. Model yükleme

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

  2. Verileri dönüştürme

    Modelin ham giriş verileri genellikle modelin beklediği giriş verisi biçimiyle eşleşmez. Örneğin, bir resmi yeniden boyutlandırmanız veya resim biçimini modelle uyumlu olması için değiştirmeniz gerekebilir.

  3. Çıkarım yapma

    Bu adım, modeli yürütmek için TensorFlow Lite API'nin kullanılmasını içerir. Bu işlem, aşağıdaki bölümlerde açıklandığı gibi yorumlayıcıyı derleme ve tensörleri ayırma gibi birkaç adımdan oluşur.

  4. Çıkışı yorumlama

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

    Örneğin, bir model yalnızca olasılıklar listesi döndürebilir. Olasılıkları ilgili kategorilerle eşleştirip son kullanıcınıza sunmak size kalmıştır.

Desteklenen platformlar

TensorFlow çıkarım API'leri Android, iOS ve Linux gibi en yaygın mobil/yerleşik platformlar için birden fazla programlama dilinde 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 sağlamak amacıyla gereksiz kopyalardan kaçınmaya çalışması şaşırtıcı değildir. Benzer şekilde, TensorFlow API'leriyle tutarlılık da açık bir hedef değildi ve diller arasında bazı farklılıklar olması beklenmektedir.

Tüm kitaplıklarda TensorFlow Lite API'yi kullanarak modelleri yükleyebilir, girişleri yayınlayabilir ve çıkarım çıkışları alabilirsiniz.

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 Etkinliği sınıflarınızda kullanılabilir. C++ API'leri daha fazla esneklik ve hız sunar ancak Java ve C++ katmanları arasında veri taşımak için JNI sarmalayıcılarının yazılmasını gerektirebilir.

C++ ve Java kullanımıyla ilgili ayrıntılar için aşağıdaki bilgilere bakın veya eğitim ve örnek kod için Android hızlı başlangıç kılavuzunu takip edin.

TensorFlow Lite Android sarmalayıcı kodu oluşturma aracı

Geliştiriciler, meta verilerle geliştirilmiş TensorFlow Lite modelinde, platforma özel sarmalayıcı kodu oluşturmak için TensorFlow Lite Android sarmalayıcı kod oluşturma aracını kullanabilir. Sarmalayıcı kodu, Android'de doğrudan ByteBuffer ile etkileşim ihtiyacını ortadan kaldırır. Geliştiriciler bunun yerine Bitmap ve Rect gibi yazılmış nesneler kullanarak TensorFlow Lite modeliyle etkileşim kurabilir. Daha fazla bilgi için TensorFlow Lite Android sarmalayıcı kodu oluşturma aracına bakın.

iOS Platformu

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

Swift, Objective-C ve C API'yi kullanmayla ilgili ayrıntılar için aşağıya bakın. Ayrıca eğitim ve örnek kod için iOS hızlı başlangıç kılavuzunu da takip edebilirsiniz.

Linux Platformu

Linux platformlarında (Raspberry Pi dahil) C++ ve Python'da kullanılabilen TensorFlow Lite API'lerini kullanarak aşağıdaki bölümlerde gösterildiği gibi çıkarım yapabilirsiniz.

Model çalıştırma

TensorFlow Lite modelini çalıştırmak birkaç basit adımdan oluşur:

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

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

Java'da model yükleme ve çalıştırma

Platform: Android

TensorFlow Lite ile çıkarım çalıştırmak için kullanılan Java API, temel olarak Android ile kullanılmak üzere tasarlanmıştır. Bu nedenle Android kitaplığı bağımlılığı olarak kullanılabilir: org.tensorflow:tensorflow-lite.

Java'da bir model yüklemek ve model çıkarımını yönlendirmek için Interpreter sınıfını kullanacaksınız. Çoğu durumda ihtiyaç duyduğunuz tek API bu olabilir.

.tflite dosyası kullanarak bir Interpreter başlatabilirsiniz:

public Interpreter(@NotNull File modelFile);

Veya 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. Interpreter öğesini başlatmak için MappedByteBuffer kullanırsanız Interpreter kullanım ömrü boyunca değişmeden kalmalıdır.

Bir model üzerinde çıkarım çalıştırmanın tercih edilen yolu imza kullanmaktır. Tensorflow 2.5'ten itibaren 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 : İmzadaki giriş adından bir giriş nesnesine yapılan girişleri eşler.

  • Çıkışlar : İmzadaki çıkış adından çıkış verilerine çıkış eşlemeyi eşler.

  • İmza Adı (isteğe bağlı): İmza adı (Modelin tek imzası varsa boş bırakılabilir).

Modelin tanımlı bir imzası olmadığında çıkarımda bulunmanın başka bir yolu da budur. Interpreter.run() numaralı telefonu arayın. Örneğin:

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

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

interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);

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

Her iki durumda da tensör dizinleri, modeli oluştururken TensorFlow Lite Converter'a verdiğiniz değerlere karşılık gelmelidir. input içindeki tensörlerin sırasının, TensorFlow Lite Dönüştürücü'ye verilen sırayla eşleşmesi gerektiğini unutmayın.

Interpreter sınıfı, bir işlem adı kullanarak herhangi bir model girişi veya çıkışının dizinini alabilmenizi sağlayan kullanışlı işlevler de sunar:

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

opName, modelde geçerli bir işlem değilse bir IllegalArgumentException hatası verir.

Ayrıca, kaynakların Interpreter sahibi olduğuna dikkat edin. Bellek sızıntısını önlemek için kaynakların, aşağıdaki işlemler tarafından kullanıldıktan sonra serbest bırakılması gerekir:

interpreter.close();

Java içeren ö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 temel türlerden biri olmalıdır:

  • float
  • int
  • long
  • byte

String türleri de desteklenir ancak bunlar temel türlerden farklı şekilde kodlanır. Özellikle Tensor dizesinin şekli, Tensor'daki dizelerin sayısını ve düzenini belirler. Her öğenin kendisi değişken uzunluktaki bir dizedir. Bu anlamda, Tensor'ın (bayt) boyutu tek başına şekilden ve türünden hesaplanamaz ve sonuç olarak dizeler tek ve düz bir ByteBuffer bağımsız değişkeni olarak sağlanamaz.

Integer ve Float gibi kutulu türler dahil olmak üzere diğer veri türleri kullanılırsa IllegalArgumentException döndürülür.

Girişler

Her giriş, desteklenen temel türlerden oluşan bir dizi veya çok boyutlu dizi ya da uygun boyutta ham ByteBuffer olmalıdır. Giriş bir dizi veya çok boyutlu diziyse ilişkili giriş tensörü, çıkarım zamanında dizinin boyutlarına dolaylı olarak yeniden boyutlandırılır. Giriş bir ByteBuffer ise çağrıyı yapanın çıkarımı çalıştırmadan önce ilişkili giriş tensörünü manuel olarak yeniden boyutlandırması (Interpreter.resizeInput() ile) gerekir.

ByteBuffer kullanırken doğrudan bayt arabellekleri kullanmayı tercih edin. Bu, Interpreter ürününün gereksiz kopyalardan kaçınmasına olanak tanır. ByteBuffer, doğrudan bayt arabelleğiyse sırası ByteOrder.nativeOrder() olmalıdır. Model çıkarımı için kullanıldıktan sonra, model çıkarımı tamamlanana kadar değişmeden kalmalıdır.

Çıkışlar

Her çıktı, desteklenen temel türlerden oluşan bir dizi veya çok boyutlu dizi ya da uygun boyutta bir ByteBuffer olmalıdır. Bazı modellerde, çıkış tensörlerinin şeklinin girişe bağlı olarak değişebileceği dinamik çıkışların bulunduğunu unutmayın. Mevcut Java inference API ile bu sorunu halletmenin doğrudan bir yolu yoktur ancak planlanan uzantılar bunu mümkün kılar.

Swift'te model yükleme ve çalıştırma

Platform: iOS

Swift API, Cocoapods'dan TensorFlowLiteSwift Pod'da kullanılabilir.

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

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ükleme ve çalıştırma

Platform: iOS

Objective-C API, Cocoapods'tan TensorFlowLiteObjC Kapsülde kullanılabilir.

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

@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'yi kullanma

Objective-C API şu anda yetki verilmiş kullanıcıları desteklememektedir. Yetki verilmiş kullanıcıları Objective-C koduyla kullanmak için temel C API'yi doğrudan ç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++ ürününde model yükleme ve çalıştırma

Platformlar: Android, iOS ve Linux

C++'ta model, FlatBufferModel sınıfında depolanır. TensorFlow Lite modelini içerir ve nerede depolandığına bağlı olarak bu modeli 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 FlatBufferModel nesnesi olarak bildiğinize göre Interpreter ile yürütebilirsiniz. Tek bir FlatBufferModel, aynı anda birden fazla Interpreter tarafından kullanılabilir.

Interpreter API'nin önemli parçaları, aşağıdaki kod snippet'inde gösterilmiştir. Aşağıdaki noktalara dikkat edilmelidir:

  • Tensörler, dize karşılaştırmalarını (ve dize kitaplıklarındaki sabit bağımlılıkları) önlemek için tam sayılarla temsil edilir.
  • Eşzamanlı iş parçacıklarından çevirmene erişilmemelidir.
  • Giriş ve çıkış tensörleri için bellek ayırma, tensörler yeniden boyutlandırıldıktan hemen sonra AllocateTensors() çağrısı yapı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 minimal.cc ve label_image.cc sayfalarına bakın.

Python'da model yükleme ve çalıştırma

Platform: Linux

Çıkarım çalıştırmak için kullanılan Python API'nin bir model yüklemek ve çıkarım yapmak için çoğunlukla yalnızca tf.lite.Interpreter yeterlidir.

Aşağıdaki örnekte .tflite dosyası yüklemek ve rastgele giriş verileriyle çıkarım yapmak için Python yorumlayıcının nasıl kullanılacağı gösterilmektedir:

Tanımlı bir SignatureDef içeren bir SavedModel'den dönüşüm gerçekleştiriyorsanı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ımlı 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üş .tflite dosyası olarak yüklemeye alternatif olarak, kodunuzu TensorFlow Lite Converter Python API ile birleştirebilirsiniz. Böylece Keras modelinizi TensorFlow Lite biçimine dönüştürüp çıkarım yapabilirsiniz:

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 label_image.py sayfasını inceleyin.

Dinamik şekil modeliyle çıkarım yapma

Bir modeli dinamik giriş şekline sahip ç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 bir 1 yer tutucusuyla değiştirilir.

Aşağıdaki örneklerde, farklı dillerde çıkarım yapmadan önce giriş şeklinin nasıl yeniden boyutlandırılacağı gösterilmektedir. Tüm örneklerde, giriş şeklinin [1/None, 10] olarak tanımlandığı ve [3, 10] olarak yeniden boyutlandırılması gerektiği varsayılmıştır.

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()

Desteklenen işlemler

TensorFlow Lite, bazı kısıtlamalarla TensorFlow işlemlerinin bir alt kümesini destekler. İşlemlerin ve sınırlamaların tam listesi için TF Lite İşlemleri sayfasına bakın.