В статье поговорим как обучить несложную CNN сеть с помощью tensorflow, конвертировать готовое с помощью tensoflow-lite и перенести на мобильное устройство под управлением android.
Описывается личный опыт автора, поэтому нет претензий на всеохватывающее руководство.
код нейросети
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 и далее конвертирована в формат 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.
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.
Для этих целей воспользуемся IDE - Android Studio, которая в особом представлении не нуждается.
Скачивание и установка Android Studio может занять время, поэтому, если с этим возникнут сложности, лучше обратиться к сторонним мануалам. Язык, который будет использоваться при создании нашего приложения — Kotlin.
Приложение, которое будет перенесено на android — это простая нейросеть, которая была создана и конвертирована выше по тексту. При вводе значения Х пользователем, нейросеть будет предсказывать Y, выводя результат на экране смартфона.
File → New → New Project→ Empty Activity
Далее заполним поля проекта, не забыв указать язык — Kotlin:
После нажатия Finish, Android Studio создаст проект.
*На картинке уже готовый проект, при создании дизайн выглядит иначе.
Правим activity_main.xml:
Заменим код, который там приведен на
следующий
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android
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:
В этом файле, в конце, надо добавить зависимость tensorflow lite согласно установленной версии на ПК. В моем случае установлен «древний» tensorflow 1.9.0, поэтому добавлена эта зависимость —
*Как узнать версию tensorflow lite? Выполнить в cmd — pip freeze и посмотреть версию tensorflow либо через idle python — import tensorflow as tf; print(tf.__version__) .
В этом же файле также необходимо добавить:
Полностью файл 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'
}
Перенесем в него
код
После этого, можно протестировать готовое приложение, нажав на кнопку Run 'app'
Тестирование проведем в эмуляторе android устройства:
После ввода X, приложение выдаст значение Y, приближенное к расчетному значению по формуле Y=2X-1, то есть нейросеть работает.
Android Studio сформирует приложение с расширением .apk, которое можно забрать из ~\app\build\outputs\apk\debug и, подключив смартфон к ПК, перенести на смартфон.
вид на телефоне
В принципе, все, теперь простая нейросеть живет на смартфоне, занимая всего 10Мб.
Приложения:
— не конвертированная нейросеть — скачать
— конвертированная в tf-lite нейросеть — скачать
— apk приложение для android — скачать
Может быть интересно:
— Как обойти капчу Гугл
— Как прикрутить нейросеть к сайту по-быстрому
— Как обойти капчу: нейросеть на Tensorflow,Keras,python v числовая зашумленная капча
Источник статьи: https://habr.com/ru/post/570052/
Описывается личный опыт автора, поэтому нет претензий на всеохватывающее руководство.

Нейросеть до конвертации.
Для старта возьмем не слишком сложную нейросеть, код которой приведен ниже:код нейросети
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

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

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

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

Заменим код, который там приведен на
следующий
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android
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:


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

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

Полностью файл 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 и перенесем туда ранее сконвертированную модель —
Привяжем модель нейросети к android приложению.
Откроем файл MainActivity.kt:
Перенесем в него
код
После этого, можно протестировать готовое приложение, нажав на кнопку Run 'app'

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

После ввода X, приложение выдаст значение Y, приближенное к расчетному значению по формуле Y=2X-1, то есть нейросеть работает.
Создадим .apk и перенесем его на мобильный телефон.
Выберем Build ->Build bundle.
Android Studio сформирует приложение с расширением .apk, которое можно забрать из ~\app\build\outputs\apk\debug и, подключив смартфон к ПК, перенести на смартфон.
вид на телефоне

В принципе, все, теперь простая нейросеть живет на смартфоне, занимая всего 10Мб.
Приложения:
— не конвертированная нейросеть — скачать
— конвертированная в tf-lite нейросеть — скачать
— apk приложение для android — скачать
Может быть интересно:
— Как обойти капчу Гугл
— Как прикрутить нейросеть к сайту по-быстрому
— Как обойти капчу: нейросеть на Tensorflow,Keras,python v числовая зашумленная капча
Источник статьи: https://habr.com/ru/post/570052/