Tutorial iOS Edge TF Lite

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 siap pakai yang menggunakan model untuk mendeteksi beberapa objek dalam gambar (dengan kotak pembatas), dan memberikan pelabelan kustom kategori objek.

Screenshot seluler produk akhir

Tujuan

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

  • Jalankan model AutoML Vision Object Detection Edge di aplikasi iOS menggunakan penafsir TF Lite.

Sebelum memulai

Meng-clone repositori Git

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

git clone https://github.com/tensorflow/examples.git

Buka direktori ios clone lokal repositori (examples/lite/examples/object_detection/ios/). Anda akan menjalankan semua contoh kode berikut dari direktori ios:

cd examples/lite/examples/object_detection/ios

Prasyarat

  • Git diinstal.
  • Versi iOS yang didukung: iOS 12.0 dan yang lebih baru.

Menyiapkan aplikasi iOS

Membuat & membuka file ruang kerja

Untuk mulai menyiapkan aplikasi iOS asli, Anda harus terlebih dahulu membuat file ruang kerja menggunakan software yang diperlukan:

  1. Buka folder ios jika Anda belum melakukannya:

    cd examples/lite/examples/object_detection/ios
  2. Instal pod untuk membuat file ruang kerja:

    pod install

    Jika Anda sudah pernah menginstal pod ini, gunakan perintah berikut:

    pod update
  3. Setelah membuat file ruang kerja, Anda dapat membuka project dengan Xcode. Untuk membuka project melalui command line, jalankan perintah berikut dari direktori ios:

    open ./ObjectDetection.xcworkspace

Membuat ID unik & membuat aplikasi

Saat ObjectDetection.xcworkspace terbuka di Xcode, Anda harus terlebih dahulu mengubah ID paket (ID paket) ke nilai yang unik.

  1. Pilih item project ObjectDetection teratas pada navigator project di sebelah kiri.

    gambar project ObjectDetection di navigasi samping

  2. Pastikan Anda telah memilih Targets > ObjectDetection.

    gambar opsi Targets dipilih

  3. Di bagian General > Identity, ubah kolom ID Paket ke nilai yang unik. Gaya yang lebih disukai adalah notasi nama domain terbalik.

    gambar contoh ID Paket di bagian Identitas

  4. Di bagian Umum > Penandatanganan di bawah Identitas, tentukan Tim dari menu drop-down. Nilai ini diberikan dari ID Developer Anda.

    Gambar menu drop-down pilih tim

  5. Hubungkan perangkat iOS ke komputer Anda. Setelah perangkat terdeteksi, pilih dari daftar perangkat.

    perangkat default dipilih

    pilih perangkat yang terhubung

  6. Setelah menentukan semua perubahan konfigurasi, build aplikasi di Xcode menggunakan perintah berikut: Command + B.

Menjalankan aplikasi asli

Aplikasi contoh adalah aplikasi kamera yang terus mendeteksi objek (kotak pembatas dan label) dalam frame yang terlihat oleh kamera belakang perangkat, menggunakan model SSD MobileNet terkuantifikasi yang dilatih pada COCO.

Petunjuk ini akan memandu Anda dalam membuat dan menjalankan demo di perangkat iOS.

File model didownload melalui skrip di Xcode saat Anda mem-build dan menjalankan. Anda tidak perlu melakukan langkah-langkah apa pun untuk mendownload model TF Lite ke dalam project secara eksplisit.

Sebelum memasukkan model yang disesuaikan, uji versi dasar aplikasi yang menggunakan model terlatih "mobilenet" dasar.

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

    gambar perintah izinkan akses kamera

  2. Setelah Anda mengizinkan aplikasi mengakses kamera dengan memilih tombol Izinkan aplikasi akan memulai deteksi dan anotasi langsung. Objek akan dideteksi dan ditandai dengan kotak pembatas dan label di setiap frame kamera.

  3. Pindahkan perangkat ke berbagai objek di sekeliling Anda dan pastikan aplikasi mendeteksi gambar dengan benar.

    Screenshot seluler produk akhir

Menjalankan aplikasi yang disesuaikan

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

Menambahkan file model Anda ke project

Project demo dikonfigurasi untuk menelusuri dua file dalam direktori ios/objectDetection/model:

  • detect.tflite
  • labelmap.txt

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

cp tf_files/optimized_graph.lite ios/objectDetection/model/detect.tflite
cp tf_files/retrained_labels.txt ios/objectDetection/model/labelmap.txt

Jalankan aplikasi Anda

Untuk meluncurkan kembali aplikasi di perangkat iOS, pilih tombol play ikon xcode play di sudut kiri atas jendela Xcode.

Untuk menguji modifikasi, gerakkan kamera perangkat Anda ke berbagai objek untuk melihat prediksi langsung.

Hasilnya akan terlihat seperti ini:

deteksi objek aplikasi kustom dengan item dapur

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

# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'

target 'ObjectDetection' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for ObjectDetection
  pod 'TensorFlowLiteSwift'

end

Kode yang berinteraksi ke TF Lite ada di dalam file ModelDataHandler.swift. Class ini menangani semua pra-pemrosesan data dan membuat panggilan untuk menjalankan inferensi pada frame tertentu dengan memanggil Interpreter. Kemudian, fitur ini akan memformat inferensi yang diperoleh dan menampilkan hasil N teratas untuk inferensi yang berhasil.

Menjelajahi kode

ModelDataHandler.swift

Blok minat pertama (setelah impor yang diperlukan) adalah deklarasi properti. Parameter inputShape model tfLite (batchSize, inputChannels, inputWidth, inputHeight) dapat ditemukan di tflite_metadata.json. Anda akan memiliki file ini saat mengekspor model tflite. Untuk mengetahui info selengkapnya, buka topik petunjuk Mengekspor model Edge.

Contoh tflite_metadata.json terlihat mirip dengan kode berikut:

{
    "inferenceType": "QUANTIZED_UINT8",
    "inputShape": [
        1,   // This represents batch size
        512,  // This represents image width
        512,  // This represents image Height
        3  //This represents inputChannels
    ],
    "inputTensor": "normalized_input_image_tensor",
    "maxDetections": 20,  // This represents max number of boxes.
    "outputTensorRepresentation": [
        "bounding_boxes",
        "class_labels",
        "class_confidences",
        "num_of_boxes"
    ],
    "outputTensors": [
        "TFLite_Detection_PostProcess",
        "TFLite_Detection_PostProcess:1",
        "TFLite_Detection_PostProcess:2",
        "TFLite_Detection_PostProcess:3"
    ]
}
...

Parameter model:

Ganti nilai di bawah sesuai dengan file tflite_metadata.json untuk model Anda.

let batchSize = 1 //Number of images to get prediction, the model takes 1 image at a time
let inputChannels = 3 //The pixels of the image input represented in RGB values
let inputWidth = 300 //Width of the image
let inputHeight = 300 //Height of the image
...

init

Metode init, yang membuat Interpreter dengan Modeljalur dan InterpreterOptions, lalu mengalokasikan memori untuk input model.

init?(modelFileInfo: FileInfo, labelsFileInfo: FileInfo, threadCount: Int = 1) {
    let modelFilename = modelFileInfo.name

    // Construct the path to the model file.
    guard let modelPath = Bundle.main.path(forResource: modelFilename,ofType: modelFileInfo.extension)

    // Specify the options for the `Interpreter`.
   var options = InterpreterOptions()
    options.threadCount = threadCount
    do {
      // Create the `Interpreter`.
      interpreter = try Interpreter(modelPath: modelPath, options: options)
      // Allocate memory for the model's input  `Tensor`s.
      try interpreter.allocateTensors()
    }

    super.init()

    // Load the classes listed in the labels file.
    loadLabels(fileInfo: labelsFileInfo)
  }
…

runModel

Metode runModel di bawah:

  1. Menskalakan gambar input ke rasio aspek yang modelnya dilatih.
  2. Menghapus komponen alfa dari buffering gambar untuk mendapatkan data RGB.
  3. Menyalin data RGB ke Tensor input.
  4. Menjalankan inferensi dengan memanggil Interpreter.
  5. Mendapatkan output dari Penerjemah.
  6. Memformat output.
func runModel(onFrame pixelBuffer: CVPixelBuffer) -> Result? {

Pangkas gambar ke persegi terbesar di tengah dan perkecil skalanya untuk menyesuaikan dimensi model:

let scaledSize = CGSize(width: inputWidth, height: inputHeight)
guard let scaledPixelBuffer = pixelBuffer.resized(to: scaledSize) else
{
    return nil
}
...

do {
  let inputTensor = try interpreter.input(at: 0)

Hapus komponen alfa dari buffering gambar untuk mendapatkan data RGB:

guard let rgbData = rgbDataFromBuffer(
  scaledPixelBuffer,
  byteCount: batchSize * inputWidth * inputHeight * inputChannels,
  isModelQuantized: inputTensor.dataType == .uInt8
) else {
  print("Failed to convert the image buffer to RGB data.")
  return nil
}

Salin data RGB ke Tensor input:

try interpreter.copy(rgbData, toInputAt: 0)

Jalankan inferensi dengan memanggil Interpreter:

    let startDate = Date()
    try interpreter.invoke()
    interval = Date().timeIntervalSince(startDate) * 1000
    outputBoundingBox = try interpreter.output(at: 0)
    outputClasses = try interpreter.output(at: 1)
    outputScores = try interpreter.output(at: 2)
    outputCount = try interpreter.output(at: 3)
  }

Memformat hasil:

    let resultArray = formatResults(
      boundingBox: [Float](unsafeData: outputBoundingBox.data) ?? [],
      outputClasses: [Float](unsafeData: outputClasses.data) ?? [],
      outputScores: [Float](unsafeData: outputScores.data) ?? [],
      outputCount: Int(([Float](unsafeData: outputCount.data) ?? [0])[0]),
      width: CGFloat(imageWidth),
      height: CGFloat(imageHeight)
    )
...
}

Memfilter semua hasil dengan skor keyakinan < ambang batas dan menampilkan N hasil teratas yang diurutkan dalam urutan menurun:

  func formatResults(boundingBox: [Float], outputClasses: [Float],
  outputScores: [Float], outputCount: Int, width: CGFloat, height: CGFloat)
  -> [Inference]{
    var resultsArray: [Inference] = []
    for i in 0...outputCount - 1 {

      let score = outputScores[i]

Filter hasil dengan keyakinan < ambang batas:

      guard score >= threshold else {
        continue
      }

Mendapatkan nama class output untuk class yang terdeteksi dari daftar label:

      let outputClassIndex = Int(outputClasses[i])
      let outputClass = labels[outputClassIndex + 1]

      var rect: CGRect = CGRect.zero

Menerjemahkan kotak pembatas yang terdeteksi ke CGRect.

      rect.origin.y = CGFloat(boundingBox[4*i])
      rect.origin.x = CGFloat(boundingBox[4*i+1])
      rect.size.height = CGFloat(boundingBox[4*i+2]) - rect.origin.y
      rect.size.width = CGFloat(boundingBox[4*i+3]) - rect.origin.x

Sudut yang terdeteksi adalah untuk dimensi model. Jadi, kita menskalakan rect sesuai dengan dimensi gambar yang sebenarnya.

let newRect = rect.applying(CGAffineTransform(scaleX: width, y: height))

Mendapatkan warna yang ditetapkan untuk class:

let colorToAssign = colorForClass(withIndex: outputClassIndex + 1)
      let inference = Inference(confidence: score,
                                className: outputClass,
                                rect: newRect,
                                displayColor: colorToAssign)
      resultsArray.append(inference)
    }

    // Sort results in descending order of confidence.
    resultsArray.sort { (first, second) -> Bool in
      return first.confidence  > second.confidence
    }

    return resultsArray
  }

CameraFeedManager

CameraFeedManager.swift mengelola semua fungsi terkait kamera.

  1. Tindakan ini akan melakukan inisialisasi dan mengonfigurasi AVCaptureSession:

    private func configureSession() {
    session.beginConfiguration()
  2. Kemudian, kode ini akan mencoba menambahkan AVCaptureDeviceInput dan menambahkan builtInWideAngleCamera sebagai input perangkat untuk Sesi.

    addVideoDeviceInput()

    Kemudian, kode ini akan mencoba menambahkan AVCaptureVideoDataOutput:

    addVideoDataOutput()

       session.commitConfiguration()
        self.cameraConfiguration = .success
      }
  3. Memulai sesi.

  4. Menghentikan sesi.

  5. Menambahkan dan menghapus notifikasi AVCaptureSession.

Penanganan Error:

  • NSNotification.Name.AVCaptureSessionRuntimeError: Pesan ini diposting saat terjadi error yang tidak terduga saat instance AVCaptureSession berjalan. Kamus userInfo berisi objek NSError untuk kunci AVCaptureSessionErrorKey.
  • NSNotification.Name.AVCaptureSessionWasInterrupted: Pesan ini diposting saat gangguan (mis. Panggilan telepon, alarm, dll.) terjadi. Jika sesuai, instance AVCaptureSession akan berhenti berjalan secara otomatis karena gangguan respons. userInfo akan berisi AVCaptureSessionInterruptionReasonKey yang menunjukkan alasan gangguan.
  • NSNotification.Name.AVCaptureSessionInterruptionEnded: Pesan ini diposting saat AVCaptureSession menghentikan gangguan. Instance sesi dapat dilanjutkan setelah gangguan seperti panggilan telepon berakhir.

Class InferenceViewController.swift bertanggung jawab di bawah layar, yang mana sebagai fokus utama kita akan menjadi bagian yang ditandai.

  • Resolution: Fitur ini menampilkan resolusi frame saat ini (Gambar dari sesi Video).
  • Pangkas: Menampilkan ukuran pemangkasan frame yang aktif.
  • InferenceTime: Metrik ini menampilkan berapa lama waktu yang diperlukan model untuk mendeteksi objek.
  • Thread: Panel ini menampilkan jumlah thread yang berjalan. Pengguna dapat menambah atau mengurangi jumlah ini dengan mengetuk tanda + atau - Stepper. Jumlah thread saat ini yang digunakan oleh TensorFlow Lite Interpreter.

gambar sesuaikan rangkaian pesan

Class ViewController.swift menyimpan instance CameraFeedManager, yang mengelola fungsi terkait kamera dan ModelDataHandler. ModelDataHandler menangani Model (model terlatih) dan mendapatkan output untuk frame gambar sesi video.

private lazy var cameraFeedManager = CameraFeedManager(previewView: previewView)

private var modelDataHandler: ModelDataHandler? =
    ModelDataHandler(modelFileInfo: MobileNetSSD.modelInfo, labelsFileInfo: MobileNetSSD.labelsInfo)

Mulai sesi kamera dengan memanggil:

cameraFeedManager.checkCameraConfigurationAndStartSession()

Jika Anda mengubah jumlah thread, class ini akan menginisialisasi ulang model dengan jumlah thread baru dalam fungsi didChangeThreadCount.

Class CameraFeedManager akan mengirim ImageFrame sebagai CVPixelBuffer ke ViewController, yang akan dikirim ke model untuk prediksi.

Metode ini menjalankan pixelBuffer kamera live melalui TensorFlow untuk mendapatkan hasilnya.

@objc
func runModel(onPixelBuffer pixelBuffer: CVPixelBuffer) {

Jalankan pixelBuffer k amera live melalui tensorFlow untuk mendapatkan hasil:

result = self.modelDataHandler?.runModel(onFrame: pixelBuffer)
...
let displayResult = result

let width = CVPixelBufferGetWidth(pixelBuffer)
    let height = CVPixelBufferGetHeight(pixelBuffer)

    DispatchQueue.main.async {

Tampilkan hasil dengan memberikan ke InferenceViewController:

self.inferenceViewController?.resolution = CGSize(width: width, height: height)

self.inferenceViewController?.inferenceTime = inferenceTime

Menggambar kotak pembatas dan menampilkan nama kelas dan skor keyakinan:

self.drawAfterPerformingCalculations(onInferences: displayResult.inferences, withImageSize: CGSize(width: CGFloat(width), height: CGFloat(height)))
    }
  }

Apa Selanjutnya

Sekarang Anda telah menyelesaikan panduan aplikasi deteksi dan anotasi objek iOS menggunakan model Edge. Anda telah menggunakan model Edge Tensorflow Lite yang terlatih untuk menguji aplikasi deteksi objek sebelum memodifikasinya 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: