Как перенести нейросеть на мобильное устройство

Kate

Administrator
Команда форума
В статье поговорим как обучить несложную CNN сеть с помощью tensorflow, конвертировать готовое с помощью tensoflow-lite и перенести на мобильное устройство под управлением android.
Описывается личный опыт автора, поэтому нет претензий на всеохватывающее руководство.
v9rzynqqbpveh1aoktj9bj4bu1s.jpeg



Нейросеть до конвертации.​

Для старта возьмем не слишком сложную нейросеть, код которой приведен ниже:
код нейросети
import tensorflow as tf
import numpy as np
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense

model = Sequential([Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')

xs = np.array([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model.fit(xs, ys, epochs=500)
print(model.predict([10.0]))


Краткое пояснение по коду. После импорта пакетов tensorflow,numpy мы формируем модель нейросети. Модель представляет из себя только один слой и только один нейрон.
Сама структура модели представляет из себя два набора данных, в которых:
X = –1, 0, 1, 2, 3, 4
Y = –3, –1, 1, 3, 5, 7


Данные наборы «укладываются» в формулу Y = 2X – 1. Таким образом, для каждого Y из набора прослеживается зависимость.
После формирования модели производится ее компиляция с оптимизатором sgd и функцией потерь mean_squared_error.
Далее в модель попадают наборы данных и производится обучение на протяжении 500 эпох
(model.fit(xs, ys, epochs=500).
*Нейросеть лучше обучать на железе помощнее либо в Google colab для ускорения процесса, так как 500 эпох могут занять до 2-3 часов времени.
И, наконец, модель проверяется путем подачи ей на вход числа 10.0. То есть мы пытаемся выяснить с помощью модели значение Y при X=10.0. В идеале, согласно формуле, Y должен быть 19.0. Но в итоге будет число, сильно приближенное по значению к 19.0.
Так работает созданная нейросеть. Именно ее мы и будем конвертировать и переносить на android устройство.

Конвертация нейросети.​

Для целей переноса модели на мобильное устройство воспользуемся tensorflow-lite. Сам по себе tensorflow-lite представляется из себя набор утилит, преследующий две основные цели. Первая из которых — сделать из нейросети модель, приемлемую для мобильного устройства. Обычно под этим подразумевается уменьшение размера и сложности сети, что, в свою очередь, приводит к небольшому падению точности работы. Тем не менее это необходимый компромисс между аккуратностью работы нейросети и ее размерами на мобильном устройстве. Вторая цель — создание среды выполнения для различных мобильных платформ, включая android,ios, микроконтроллеры.
Важной чертой tensorflow-lite является то, что с ее помощью невозможно тренировать модель. Нейросеть должна быть сначала обучена с помощью tensorflow и далее конвертирована в формат tensorflow-lite.

Зачем вообще переносить нейросеть на мобильное устройство?
Вопрос риторический, но из аргументов «за» — приватность используемых данных и отсутствие необходимости использования сетей связи при работе, например, с облачными решениями.

Говоря о конвертации в приемлемый tensorflow-lite формат, вернемся к коду нейросети из предыдущего блока.
Необходимо сперва сохранить готовую модель:
export_dir = 'model'
tf.saved_model.save(model,'model')


В результате получится файл «model.pb».
Теперь очередь конвертации:
converter = tf.lite.TFLiteConverter.from_saved_model(export_dir)
tflite_model = converter.convert()


Далее сохраним сконвертированную модель в формате .tflite используя pathlib:
import pathlib
tflite_model_file = pathlib.Path('model.tflite')
tflite_model_file.write_bytes(tflite_model)


Готовую model.tflite модель можно использовать в различных окружениях, например, android или ios.

Как работает модель в tensorflow-lite.​

Загрузка модели, выделение тензоров.​

Загрузим модель в интерпретатор, выделим тензоры, которые будут использоваться для ввода данных в модель для прогнозирования, а затем прочитаем то, что выводит модель.
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()


Здесь проявляется главное отличие tensorflow-lite от Tensorflow. Если во втором случае возможно просто использовать model.predict(что-то) и сразу получить результат, то в tensorflow-lite необходимо поработать с сходными и выходными тензорами, приводя свои данные для соответствия их формату.
Посмотрим как это выглядит:
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
print(input_details)
print(output_details)


В результате вывод будет следующим:
[{'name': 'dense_input', 'index': 0,<b> 'shape': array([1, 1]</b>, dtype=int32),
'shape_signature': array([1, 1], dtype=int32),
'dtype': class 'numpy.float32', 'quantization': (0.0, 0),
'quantization_parameters':
{'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32),
'quantized_dimension': 0}, 'sparsity_parameters': {}}]


В выводе input_details необходимо обратить внимание на shape(размерность) — массив 1,1 и класс данных — numpy.float32. Эти параметры будут определять входные данные и их формат.
Используя данную информацию, определим Y для X=10.0:
to_predict = np.array([[10.0]], dtype=np.float32)
print(to_predict)



В выводе output_details формат данных схож, поэтому ответ нейросети будет в виде [[y]], также как и [[x]]:
[{'name': 'Identity', 'index': 3, 'shape': array([1, 1], dtype=int32),
'shape_signature': array([1, 1], dtype=int32), 'dtype': <class
'numpy.float32'>, 'quantization': (0.0, 0), 'quantization_parameters':
{'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32),
'quantized_dimension': 0}, 'sparsity_parameters': {}}]



Прогнозирование, использование модели.​

Чтобы заставить интерпретатор выполнить прогнозирование, необходимо задать входной тензор со значением для прогнозирования:
interpreter.set_tensor(input_details[0]['index'], to_predict)
interpreter.invoke()


Так как у нас очень простая модель, в которой есть только один параметр ввода, поэтому это input_details[0], к нему мы и обращаемся в индексе.
Затем мы вызываем интерпретатор с помощью метода invoke.

Теперь мы осуществим прогнозирование с помощью модели, используя выражение get_tensor:
tflite_results = interpreter.get_tensor(output_details[0]['index'])
print(tflite_results)


Опять же, существует только один выходной тензор, поэтому он будет выглядеть как output_details[0].

В целом код выглядит следующим образом:
to_predict = np.array([[10.0]], dtype=np.float32)
print(to_predict)
interpreter.set_tensor(input_details[0]['index'], to_predict)
interpreter.invoke()
tflite_results = interpreter.get_tensor(output_details[0]['index'])
print(tflite_results)


Вывод:
[[10.]]
[[18.975412]]


Где 10 — это входное значение или X, а 18.97 — предсказанная величина, близкая к 19 (формула нейросети та же Y=2X – 1).

Перенос модели на android устройство (мобильный телефон).​

После создания модели нейросети и ее конвертации в формат tensorflow-lite,
создадим приложение для Android.
Для этих целей воспользуемся IDE - Android Studio, которая в особом представлении не нуждается.
Скачивание и установка Android Studio может занять время, поэтому, если с этим возникнут сложности, лучше обратиться к сторонним мануалам. Язык, который будет использоваться при создании нашего приложения — Kotlin.
Приложение, которое будет перенесено на android — это простая нейросеть, которая была создана и конвертирована выше по тексту. При вводе значения Х пользователем, нейросеть будет предсказывать Y, выводя результат на экране смартфона.

Создаем новый проект в Android Studio.​

Цепочка действий после запуска Android Studio следующая:
File → New → New Project→ Empty Activity
zqatcarqwutiqso9biaqbuoafb8.png

Далее заполним поля проекта, не забыв указать язык — Kotlin:
22wysemp73czxrk7etxw2uwkjnm.png


После нажатия Finish, Android Studio создаст проект.
xfipyosmnssktgtssyuvfhlc56a.png

*На картинке уже готовый проект, при создании дизайн выглядит иначе.

Правим activity_main.xml:
rxmkqrcxuhb62dgmiyxfreoq_sc.png

Заменим код, который там приведен на
следующий
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:eek:rientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/lblEnter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enter X: "
android:textSize="18sp"></TextView>

<EditText
android:id="@+id/txtValue"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:inputType="number"
android:text="1"></EditText>

<Button
android:id="@+id/convertButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Convert">
</Button>
</LinearLayout>
</LinearLayout>


Это сформирует внешний вид приложения.

Добавим зависимости Tensorflow lite.
Нам нужны build.gradle файлы. Их в проекте два, и нужен тот, который содержит app в названии и расположен в директории app:
uwnget0ptfqu05_ywjdmnurjze8.png


ew9ns-kzrobc5zm8weytvwoa2qm.png


В этом файле, в конце, надо добавить зависимость tensorflow lite согласно установленной версии на ПК. В моем случае установлен «древний» tensorflow 1.9.0, поэтому добавлена эта зависимость —
otbmwz7ponis9yxyvv6vnyzoyuy.png

*Как узнать версию tensorflow lite? Выполнить в cmd — pip freeze и посмотреть версию tensorflow либо через idle python — import tensorflow as tf; print(tf.__version__) .

В этом же файле также необходимо добавить:
nzs87pneav4jy-dnjyuoagv-fok.png

Полностью файл build.gradle будет выглядеть так:
код
plugins {
id 'com.android.application'
id 'kotlin-android'
}

android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "com.example.firsttflite"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
aaptOptions {
noCompress "tflite"
}
}

dependencies {
implementation 'org.tensorflow:tensorflow-lite:1.9.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}



Теперь добавим в проект саму модель нейросети tf-lite.​

В папке main создадим папку assets и перенесем туда ранее сконвертированную модель —
ftruq3atbxq8_4dy0rezu9ak5hg.png


Привяжем модель нейросети к android приложению.​

Откроем файл MainActivity.kt:
vyskpkll7ynymw1ieg4umwywsf4.png

Перенесем в него
код


После этого, можно протестировать готовое приложение, нажав на кнопку Run 'app'
zkrwaoxt-pqbwy30i_nrsj_xa9u.png


Тестирование проведем в эмуляторе android устройства:
fgqilvqyu09xahpcuzqvapvcvas.png

После ввода X, приложение выдаст значение Y, приближенное к расчетному значению по формуле Y=2X-1, то есть нейросеть работает.

Создадим .apk и перенесем его на мобильный телефон.​

Выберем Build ->Build bundle.
owfexqgxympwxrcpsvbb0wbfduc.png


Android Studio сформирует приложение с расширением .apk, которое можно забрать из ~\app\build\outputs\apk\debug и, подключив смартфон к ПК, перенести на смартфон.
вид на телефоне
bmrwcwlbezesvpcd1evy8rzuxqk.jpeg


В принципе, все, теперь простая нейросеть живет на смартфоне, занимая всего 10Мб.

Приложения:
— не конвертированная нейросеть — скачать
— конвертированная в tf-lite нейросеть — скачать
— apk приложение для android — скачать

Может быть интересно:
Как обойти капчу Гугл
Как прикрутить нейросеть к сайту по-быстрому
Как обойти капчу: нейросеть на Tensorflow,Keras,python v числовая зашумленная капча


Источник статьи: https://habr.com/ru/post/570052/
 
Сверху