ML с Android

В этой статье мы увидим, как обучить модель и интегрировать ее в приложение для Android. Если у вас уже есть модель ml и вы хотите увидеть, как интегрировать ее в Android, вы можете прокрутить вниз до раздела «Реализация».

Цель этой статьи - продемонстрировать, как обучить ML-модель и использовать ее в Android, и вам не потребуются какие-либо знания о машинном обучении, чтобы прочитать эту статью.

Модель машинного обучения - это псевдоним обученной (или еще не обученной) модели, которая ожидает выполнения некоторых интеллектуальных задач, в нашем случае мы обучаем ее, чтобы идентифицировать некоторые конкретные объекты

Обучение модели

Мы используем обучаемую машину Google для обучения модели. Это фантастический инструмент, который позволяет нам обучать модель, не требуя каких-либо ноу-хау в области машинного обучения. В настоящее время он позволяет нам обучать модели распознавать объекты на изображениях, конкретный звук или позу для нашего проекта. Мы используем изображения для распознавания объектов.

  • Перейдите на сайт обучаемой машины здесь

Теперь, чтобы наша модель распознавала определенные объекты, мы предоставляем несколько изображений этого объекта, мы можем использовать веб-камеру или загрузить набор изображений, здесь мы загружаем больше изображений, тем более точный результат мы получаем, не забудьте щелкнуть изображения с разных позиций, углы и окружение

  • Предоставьте изображения и отредактируйте имя класса с именем объекта

Я добавил два класса для распознавания двух разных автомобилей как «Автомобиль 1» и «Автомобиль 2».

  • как только закончите, нажмите на модель поезда

Как только модель будет обучена, мы сможем посмотреть предварительный просмотр в реальном времени. Теперь наша модель различает два объекта при размещении перед веб-камерой, единственный недостаток заключается в том, что она всегда возвращает нам одно из значений класса, поэтому, если ни один из объектов класса (в данном случае автомобили), помещенных перед веб-камерой, не показывает нам значение первого класса нашей модели (в данном случае «Автомобиль 1»)

  • Нажмите на модель экспорта, кроме предварительного просмотра.
  • В диалоговом окне выберите «Tensorflow Lite» → «Плавающая точка» и нажмите «Загрузить мою модель».

  • Извлечение загруженной модели дает нам файл «tflite» и один файл «txt», которые мы будем использовать в Android.

Реализация на Android

Есть 2 способа интегрировать нашу модель на Android

  1. Использование библиотеки Tensorflow Lite
  2. Использование набора Firebase ml

Для нашего проекта мы будем использовать комплект Firebase ml как

  • Легко настроить
  • Модель может быть размещена на базе firebase, а также в комплекте с приложением.
  • Мы можем обновить нашу модель, не обновляя приложение

Приступим!

  • Создать новый проект на android studio
  • Перейти к инструментам - ›firebase
  • В навигационном ящике firebase перейдите в ML KIT и выберите любой из 4 вариантов.

  • Нажмите «Подключиться к Firebase», войдите в систему с помощью firebase и выберите «Создать новый проект Firebase».
  • После создания проекта нажмите «Добавить ML Kit в свое приложение», примите изменения…
  • В файле Gradle уровня приложения добавьте эту зависимость
implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.1'
  • В том же файле добавьте это, чтобы убедиться, что файл локальной модели не сжат.
android{
...
aaptOptions {
    noCompress "tflite"  // Your model's file extension: "tflite", "lite", etc.
}
...
}

и с этим мы успешно настроили firebase для нашего приложения

Теперь, чтобы использовать его, нам нужно будет добавить нашу модель (файл .tflite) и файл метки в папку с ресурсами.

  • Создайте папку с активами, щелкнув правой кнопкой мыши приложение → новая → папка → папка с ресурсами.
  • Скопируйте и вставьте оба файла в папку с ресурсами
  • Обновите файл activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvIdentifiedItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Loading..."
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • Добавьте изображение одного из объектов (в нашем случае автомобиль 2) в папку с возможностью переноса изображений.
  • Добавьте этот код в MainActivity.kt
package com.kdtech.mlwithandroid

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.firebase.ml.custom.*
import kotlinx.android.synthetic.main.activity_main.*
import java.io.BufferedReader
import java.io.InputStreamReader

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
//for loading model from local assets folder
        val localModel = FirebaseCustomLocalModel.Builder() 
            .setAssetFilePath("model_unquant.tflite")
            .build()

        val options = FirebaseModelInterpreterOptions.Builder(localModel).build()

        val interpreter = FirebaseModelInterpreter.getInstance(options)

        val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
            .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3))
            .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 2)) 
// here replace 2 with no of class added in your model , for //production apps you can read the labels.txt files here and to get //no of classes dynamically
            .build()


        /* Here we are using static image from drawable to keep the code minimum and avoid distraction, Recommended method would be to get the image from user by camera or device photos using the same code by handling all this logic in a method and calling that every time */
        val bitmap = Bitmap.createScaledBitmap(
            BitmapFactory.decodeResource(
                resources,
                R.drawable.car2), 224, 224, true)

        val batchNum = 0
        val input = Array(1) { Array(224) { Array(224) { FloatArray(3) } } }
        for (x in 0..223) {
            for (y in 0..223) {
                val pixel = bitmap.getPixel(x, y)
                // Normalize channel values to [-1.0, 1.0]. This requirement varies by
                // model. For example, some models might require values to be normalized
                // to the range [0.0, 1.0] instead.
                input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 255.0f
                input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 255.0f
                input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 255.0f
            }
        }

        val inputs = FirebaseModelInputs.Builder()
            .add(input) // add() as many input arrays as your model requires
            .build()
        interpreter!!.run(inputs, inputOutputOptions)
            .addOnSuccessListener { result ->
                // ...
                val output = result.getOutput<Array<FloatArray>>(0)
                val probabilities = output[0]
                val reader = BufferedReader(
                    InputStreamReader(assets.open("labels.txt"))
                )
                var higherProbablityFloat = 0F
                for (i in probabilities.indices) {

                    if (higherProbablityFloat<probabilities[i]){
                        val label = reader.readLine()
                        higherProbablityFloat = probabilities[i]
                        tvIdentifiedItem.text = "The Image is of ${label.substring(2)}"
                    }
                }
            }
            .addOnFailureListener { e ->
                // Task failed with an exception
                // ...
                tvIdentifiedItem.text = "exception ${e.message}"
            }
    }
}

Здесь мы используем статическое изображение из drawable, чтобы сохранить минимум кода и избежать отвлечения внимания. Рекомендуемый метод - получить изображение от пользователя с помощью камеры или фотографий устройства с использованием того же кода, обрабатывая всю эту логику в методе и вызывая это каждый раз

  • Запускаем приложение :)

Этим мы завершили локальную интеграцию ml, весь код вы можете найти на github здесь

  • Теперь для комбинации удаленной и локальной интеграции для комплекта ml нам нужно будет добавить разрешение на Интернет и внести несколько изменений в проверку кода эта ветка.

И наконец, позвольте не забыть поблагодарить разработчиков Teachable machine и команду Firebase за их удивительные продукты, они написали тысячи строк кода, которые позволили нам обучать и использовать наши модели в этих нескольких строках кода.

Спасибо за чтение! Не стесняйтесь поздороваться или поделиться своими мыслями в Twitter @that_kushal_guy или в ответах ниже!

Вы можете ознакомиться с вариантом этой статьи для iOS здесь.



Также ознакомьтесь с моей другой статьей об использовании Jetpack Compose (Declarative ui) с архитектурой MVVM