Tutorial men-deploy Edge ke iOS

Hal yang akan Anda buat

Dalam tutorial ini, Anda akan mendownload model TensorFlow Lite kustom yang diekspor dari AutoML Vision Edge. Kemudian, Anda akan menjalankan aplikasi iOS bawaan yang menggunakan model untuk mengidentifikasi gambar bunga.

Screenshot seluler produk akhir
Kredit gambar: Felipe Venâncio, "dari taman ibu saya" (CC BY 2.0, gambar ditunjukkan di aplikasi).

Tujuan

Dalam panduan pengantar menyeluruh ini, Anda akan menggunakan kode untuk:

  • Jalankan model terlatih dalam aplikasi iOS menggunakan penafsir TFLite.

Sebelum memulai

Menginstal TensorFlow

Sebelum memulai tutorial, Anda perlu menginstal beberapa software:

Jika Anda memiliki penginstalan Python yang berfungsi, jalankan perintah berikut untuk mendownload software ini:

pip install --upgrade  "tensorflow==1.7.*"
pip install PILLOW

Meng-clone repositori Git

Dengan menggunakan command line, clone repositori Git dengan perintah berikut:

git clone https://github.com/googlecodelabs/tensorflow-for-poets-2

Buka direktori clone lokal repositori (direktori tensorflow-for-poets-2). Anda akan menjalankan semua contoh kode berikut dari direktori ini:

cd tensorflow-for-poets-2

Menyiapkan aplikasi iOS

Aplikasi iOS demo memerlukan beberapa alat tambahan:

  1. Xcode
  2. Alat command line Xcode
  3. Cocoapods

Mendownload Xcode

Gunakan link berikut untuk mendownload Xcode di komputer Anda.

Menginstal alat command line Xcode

Instal alat command line Xcode dengan menjalankan perintah berikut:

xcode-select --install

Menginstal Cocoapods

Cocoapods menggunakan Ruby, yang diinstal secara default di macOS.

Untuk menginstal cocoapods, jalankan perintah ini:

sudo gem install cocoapods
Install TFLite Cocoapod

Bagian lainnya dari codelab ini harus dijalankan langsung di macOS, jadi tutup docker sekarang (Ctrl-D akan keluar dari Docker).

Gunakan perintah berikut untuk menginstal TensorFlow Lite dan membuat file .xcworkspace menggunakan cocoapods:

pod install --project-directory=ios/tflite/

Buka project dengan Xcode. Anda dapat membuka project melalui command line atau UI.

Untuk membuka project melalui command line, jalankan perintah berikut:

open ios/tflite/tflite_photos_example.xcworkspace

Untuk membuka project melalui UI, luncurkan Xcode dan pilih tombol "Open another Project".

UI Xcode

Setelah membuka project, buka file .xcworkspace (bukan file .xcproject).

Menjalankan aplikasi asli

Aplikasi ini adalah contoh sederhana yang menjalankan model pengenalan gambar di Simulator iOS. Aplikasi membaca dari galeri foto, karena Simulator tidak mendukung input kamera.

Sebelum memasukkan model yang disesuaikan, uji versi dasar aplikasi yang menggunakan "mobilenet" dasar yang dilatih pada 1.000 kategori ImageNet.

Untuk meluncurkan aplikasi di Simulator, pilih tombol play ikon xcode play di sudut kanan atas jendela Xcode.

Tombol "Foto Berikutnya" akan muncul di antara foto-foto di perangkat.

Anda dapat menambahkan foto ke galeri foto perangkat dengan menarik lalu melepasnya ke jendela Simulator

Hasilnya akan menampilkan anotasi yang mirip dengan gambar ini:

uji coba screenshot aplikasi

Menjalankan aplikasi yang disesuaikan

Penyiapan aplikasi asli mengklasifikasikan gambar ke dalam salah satu class 1.000 ImageNet, menggunakan MobileNet standar.

Ubah aplikasi agar akan menggunakan model yang dilatih ulang dengan kategori gambar kustom.

Menambahkan file model Anda ke project

Project demo dikonfigurasi untuk menelusuri file graph.lite dan labels.txt dalam direktori android/tflite/app/src/main/assets/.

Untuk mengganti kedua file tersebut dengan versi Anda, jalankan perintah berikut:

cp tf_files/optimized_graph.lite ios/tflite/data/graph.lite
cp tf_files/retrained_labels.txt ios/tflite/data/labels.txt

Jalankan aplikasi Anda

Untuk meluncurkan aplikasi di Simulator, pilih tombol play ikon xcode play di sudut kanan atas jendela Xcode.

Untuk menguji modifikasi, tambahkan file gambar dari direktori flower_photos/ dan dapatkan prediksinya.

Hasilnya akan terlihat seperti ini:

Screenshot seluler produk akhir
Kredit gambar: Felipe Venâncio, "dari kebun ibu saya" (CC BY 2.0, gambar ditampilkan dalam aplikasi).

Perlu diketahui bahwa gambar default bukan bunga.

Untuk benar-benar mencoba model tersebut, tambahkan beberapa gambar data pelatihan yang Anda download sebelumnya, atau download beberapa gambar dari penelusuran Google untuk digunakan dalam prediksi.

Bagaimana cara kerjanya?

Setelah aplikasi berjalan, lihat kode khusus TensorFlow Lite.

Pod TensorFlowLite

Aplikasi ini menggunakan TFLite Cocoapod yang telah dikompilasi sebelumnya. Podfile berisi cocoapod dalam project:

Podfile

platform :ios, '8.0'
inhibit_all_warnings!

target 'tflite_photos_example'
       pod 'TensorFlowLite'

Kode yang berinteraksi ke TFLite terdapat di dalam file CameraExampleViewController.mm.

Penyiapan

Blok pertama yang diinginkan (setelah impor yang diperlukan) adalah metode viewDidLoad:

CameraExampleViewController.mm

#include "tensorflow/contrib/lite/kernels/register.h"
#include "tensorflow/contrib/lite/model.h"
#include "tensorflow/contrib/lite/string_util.h"
#include "tensorflow/contrib/lite/tools/mutable_op_resolver.h"

...

- (void)viewDidLoad {
  [super viewDidLoad];
  labelLayers = [[NSMutableArray alloc] init];

  NSString* graph_path = FilePathForResourceName(model_file_name, model_file_type);
  model = tflite::FlatBufferModel::BuildFromFile([graph_path UTF8String]);
  if (!model) {
    LOG(FATAL) << "Failed to mmap model " << graph_path;
  }
  LOG(INFO) << "Loaded model " << graph_path;
  model->error_reporter();
  LOG(INFO) << "resolved reporter";

  ...

Baris kunci di paruh pertama metode ini adalah baris model = tflite::FlatBufferModel::BuildFromFile([graph_path UTF8String]);. Kode ini membuat FlatBufferModel dari file grafik.

FlatBuffer adalah struktur data yang dapat dipetakan memori. Ini adalah fitur utama TFLite karena memungkinkan sistem mengelola memori yang digunakan oleh model dengan lebih baik. Sistem dapat menukar bagian model secara transparan ke dalam atau ke luar memori sesuai kebutuhan.

Bagian kedua metode ini mem-build penafsir untuk model, dengan melampirkan implementasi Op ke struktur data grafik yang telah dimuat sebelumnya:

CameraExampleViewController.mm

- (void)viewDidLoad {
  ...

  tflite::ops::builtin::BuiltinOpResolver resolver;
  LoadLabels(labels_file_name, labels_file_type, &labels);

  tflite::InterpreterBuilder(*model, resolver)(&interpreter);
  if (!interpreter) {
    LOG(FATAL) << "Failed to construct interpreter";
  }
  if (interpreter->AllocateTensors() != kTfLiteOk) {
    LOG(FATAL) << "Failed to allocate tensors!";
  }

  [self attachPreviewLayer];
}

Jika Anda terbiasa dengan TensorFlow di python, ini kira-kira setara dengan mem-build tf.Session().

Menjalankan model

Metode UpdatePhoto menangani semua detail pengambilan foto berikutnya, memperbarui jendela pratinjau, dan menjalankan model pada foto.

CameraExampleViewController.mm

- (void)UpdatePhoto{
  PHAsset* asset;
  if (photos==nil || photos_index >= photos.count){
    [self updatePhotosLibrary];
    photos_index=0;
  }
  if (photos.count){
    asset = photos[photos_index];
    photos_index += 1;
    input_image = [self convertImageFromAsset:asset
                                   targetSize:CGSizeMake(wanted_input_width, wanted_input_height)
                                         mode:PHImageContentModeAspectFill];
    display_image = [self convertImageFromAsset:asset
                                     targetSize:CGSizeMake(asset.pixelWidth,asset.pixelHeight)
                                           mode:PHImageContentModeAspectFit];
    [self DrawImage];
  }

  if (input_image != nil){
    image_data image = [self CGImageToPixels:input_image.CGImage];
    [self inputImageToModel:image];
    [self runModel];
  }
}

Ada tiga baris terakhir yang menjadi perhatian kita.

Metode CGImageToPixels mengonversi CGImage yang ditampilkan oleh galeri Foto iOS menjadi struktur sederhana yang berisi data lebar, tinggi, saluran, dan piksel.

CameraExampleViewController.h

typedef struct {
  int width;
  int height;
  int channels;
  std::vector<uint8_t> data;
} image_data;

Metode inputImageToModel menangani penyisipan gambar ke dalam memori penafsir. Ini termasuk mengubah ukuran gambar dan menyesuaikan nilai piksel agar sesuai dengan yang diharapkan oleh model.

CameraExampleViewController.mm

- (void)inputImageToModel:(image_data)image{
  float* out = interpreter->typed_input_tensor<float>(0);

  const float input_mean = 127.5f;
  const float input_std = 127.5f;
  assert(image.channels >= wanted_input_channels);
  uint8_t* in = image.data.data();

  for (int y = 0; y < wanted_input_height; ++y) {
    const int in_y = (y * image.height) / wanted_input_height;
    uint8_t* in_row = in + (in_y * image.width * image.channels);
    float* out_row = out + (y * wanted_input_width * wanted_input_channels);
    for (int x = 0; x < wanted_input_width; ++x) {
      const int in_x = (x * image.width) / wanted_input_width;
      uint8_t* in_pixel = in_row + (in_x * image.channels);
      float* out_pixel = out_row + (x * wanted_input_channels);
      for (int c = 0; c < wanted_input_channels; ++c) {
        out_pixel[c] = (in_pixel[c] - input_mean) / input_std;
      }
    }
  }
}

Kita mengetahui bahwa model hanya memiliki satu input, sehingga baris float* out = interpreter->typed_input_tensor<float>(0); akan meminta penafsir pointer ke memori untuk input 0. Metode lainnya menangani aritmetika pointer dan penskalaan piksel untuk menyalin data ke dalam array input tersebut.

Terakhir, metode runModel akan menjalankan model:

CameraExampleViewController.mm

- (void)runModel {
  double startTimestamp = [[NSDate new] timeIntervalSince1970];
  if (interpreter->Invoke() != kTfLiteOk) {
    LOG(FATAL) << "Failed to invoke!";
  }
  double endTimestamp = [[NSDate new] timeIntervalSince1970];
  total_latency += (endTimestamp - startTimestamp);
  total_count += 1;
  NSLog(@"Time: %.4lf, avg: %.4lf, count: %d", endTimestamp - startTimestamp,
        total_latency / total_count,  total_count);

  ...

}

runModel berikutnya akan membaca kembali hasilnya. Untuk melakukan ini, kode ini meminta penafsir untuk memberikan pointer ke data array output. Output-nya adalah array sederhana dari float. Metode GetTopN menangani ekstraksi dari 5 hasil teratas (menggunakan antrean prioritas).

CameraExampleViewController.mm

- (void)runModel {
  ...

  const int output_size = (int)labels.size();
  const int kNumResults = 5;
  const float kThreshold = 0.1f;

  std::vector<std::pair<float, int>> top_results;

  float* output = interpreter->typed_output_tensor<float>(0);
  GetTopN(output, output_size, kNumResults, kThreshold, &top_results);

  ...
}

Beberapa baris berikutnya hanya mengonversi 5 pasangan (probability, class_id) teratas tersebut menjadi pasangan (probability, label), lalu meneruskan hasil tersebut, secara asinkron, ke metode setPredictionValues yang memperbarui laporan layar:

CameraExampleViewController.mm

- (void)runModel {
  ...

  std::vector<std::pair<float, std::string>> newValues;
  for (const auto& result : top_results) {
    std::pair<float, std::string> item;
    item.first = result.first;
    item.second = labels[result.second];

    newValues.push_back(item);
  }
  dispatch_async(dispatch_get_main_queue(), ^(void) {
    [self setPredictionValues:newValues];
  });
}

Apa Selanjutnya

Sekarang Anda telah menyelesaikan panduan aplikasi klasifikasi bunga iOS menggunakan menggunakan model Edge. Anda telah menggunakan model Edge Tensorflow Lite terlatih untuk menguji aplikasi klasifikasi gambar sebelum memodifikasi dan mendapatkan anotasi contoh. Anda kemudian memeriksa kode khusus TensorFlow Lite untuk memahami fungsionalitas yang mendasarinya.

Referensi berikut dapat membantu Anda terus mempelajari model TensorFlow dan AutoML Vision Edge: