Статьи

Как использовать TensorFlow Mobile в приложениях для Android

С TensorFlow , одной из самых популярных на сегодняшний день систем машинного обучения, вы можете легко создавать и обучать глубокие модели, также называемые глубокими нейронными сетями с прямой связью, которые могут решать различные сложные задачи, такие как классификация изображений, объект. обнаружение и понимание естественного языка. TensorFlow Mobile — это библиотека, которая поможет вам использовать эти модели в своих мобильных приложениях.

В этом уроке я покажу вам, как использовать TensorFlow Mobile в проектах Android Studio.

Чтобы следовать этому руководству, вам понадобится:

  • Android Studio 3.0 или выше
  • TensorFlow 1.5.0 или выше
  • Android-устройство под управлением API уровня 21 или выше
  • и базовое понимание структуры TensorFlow

Прежде чем мы начнем использовать TensorFlow Mobile, нам понадобится обученная модель TensorFlow. Давайте создадим один сейчас.

Наша модель будет очень простой. Он будет вести себя как вентиль XOR, принимая два входа, каждый из которых может быть либо ноль, либо один, и создавая один выход, который будет равен нулю, если оба входа идентичны, и один — в противном случае. Кроме того, поскольку это будет глубокая модель, у нее будет два скрытых слоя: один с четырьмя нейронами, а другой с тремя нейронами. Вы можете изменить количество скрытых слоев и количество нейронов, которые они содержат.

Чтобы этот учебник был коротким, вместо непосредственного использования низкоуровневых API-интерфейсов TensorFlow , мы будем использовать TFLearn , популярную оболочку для TensorFlow, предлагающую более интуитивно понятные и лаконичные API-интерфейсы. Если у вас его еще нет, используйте следующую команду, чтобы установить его в виртуальной среде TensorFlow:

1
pip install tflearn

Чтобы начать создавать модель, создайте скрипт Python с именем create_model.py , предпочтительно в пустой папке, и откройте его в своем любимом текстовом редакторе.

Внутри файла первое, что нам нужно сделать, это импортировать API TFLearn.

1
import tflearn

Далее мы должны создать тренировочные данные. Для нашей простой модели будет только четыре возможных входа и выхода, которые будут напоминать содержимое таблицы истинности гейта XOR.

01
02
03
04
05
06
07
08
09
10
11
12
13
X = [
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
]
 
Y = [
    [0], # Desired output for inputs 0, 0
    [1], # Desired output for inputs 0, 1
    [1], # Desired output for inputs 1, 0
    [0] # Desired output for inputs 1, 1
]

Обычно рекомендуется использовать случайные значения, выбранные из равномерного распределения, при назначении начальных весов всем нейронам в скрытых слоях. Чтобы сгенерировать значения, используйте uniform() .

1
weights = tflearn.initializations.uniform(minval = -1, maxval = 1)

На этом этапе мы можем начать создавать слои нашей нейронной сети. Чтобы создать входной слой, мы должны использовать метод input_data() , который позволяет нам указать количество входов, которые может принять сеть. Когда входной слой готов, мы можем несколько раз вызвать метод fully_connected() чтобы добавить больше слоев в сеть.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
# Input layer
net = tflearn.input_data(
        shape = [None, 2],
        name = ‘my_input’
)
 
# Hidden layers
net = tflearn.fully_connected(net, 4,
        activation = ‘sigmoid’,
        weights_init = weights
)
net = tflearn.fully_connected(net, 3,
        activation = ‘sigmoid’,
        weights_init = weights
)
 
# Output layer
net = tflearn.fully_connected(net, 1,
        activation = ‘sigmoid’,
        weights_init = weights,
        name = ‘my_output’
)

Обратите внимание, что в приведенном выше коде мы дали значимые имена входному и выходному слоям. Это важно, потому что они нам понадобятся при использовании сети из нашего приложения для Android. Также обратите внимание, что скрытый и выходной слои используют функцию активации sigmoid . Вы можете экспериментировать с другими функциями активации, такими как softmax , tanh и relu .

Как последний уровень нашей сети, мы должны создать уровень регрессии, используя функцию regression() , которая ожидает в качестве аргументов несколько гиперпараметров, таких как скорость обучения сети и функции оптимизатора и потерь, которые она должна использовать. Следующий код показывает, как использовать стохастический градиентный спуск, SGD для краткости, в качестве функции оптимизатора и среднеквадратичное в качестве функции потерь:

1
2
3
4
5
net = tflearn.regression(net,
        learning_rate = 2,
        optimizer = ‘sgd’,
        loss = ‘mean_square’
)

Далее, чтобы дать понять инфраструктуре TFLearn, что наша модель сети на самом деле является моделью глубокой нейронной сети, мы должны вызвать функцию DNN() .

1
model = tflearn.DNN(net)

Модель теперь готова. Все, что нам нужно сделать сейчас, это обучить его, используя данные обучения, которые мы создали ранее. Поэтому вызовите метод fit() модели и, вместе с данными обучения, укажите количество тренировочных эпох для запуска. Поскольку данные обучения очень малы, нашей модели потребуются тысячи эпох, чтобы достичь разумной точности.

1
model.fit(X, Y, 5000)

Когда обучение завершено, мы можем вызвать метод predict() модели, чтобы проверить, генерирует ли она желаемые результаты. Следующий код показывает, как проверить выходы для всех допустимых входов:

1
2
3
4
print(«1 XOR 0 = %f» % model.predict([[1,0]]).item(0))
print(«1 XOR 1 = %f» % model.predict([[1,1]]).item(0))
print(«0 XOR 1 = %f» % model.predict([[0,1]]).item(0))
print(«0 XOR 0 = %f» % model.predict([[0,0]]).item(0))

Если вы сейчас запустите скрипт Python, вы должны увидеть вывод, который выглядит следующим образом:

Predictions after training

Обратите внимание, что выходные значения никогда не равны 0 или 1. Вместо этого они являются числами с плавающей запятой, которые либо близки к нулю, либо близки к единице. Поэтому при использовании выходных данных вы можете использовать функцию round() в Python.

Если мы не сохраним модель явно после обучения, мы потеряем ее, как только закончится сценарий. К счастью, в TFLearn простой вызов метода save() сохраняет модель. Однако, чтобы иметь возможность использовать сохраненную модель с TensorFlow Mobile, перед ее сохранением необходимо убедиться, что мы удалили все связанные с обучением операции, которые присутствуют в коллекции tf.GraphKeys.TRAIN_OPS , связанной с ней. Следующий код показывает вам, как это сделать:

1
2
3
4
5
6
# Remove train ops
with net.graph.as_default():
    del tf.get_collection_ref(tf.GraphKeys.TRAIN_OPS)[:]
 
# Save the model
model.save(‘xor.tflearn’)

Если вы снова запустите скрипт, вы увидите, что он генерирует файл контрольных точек, файл метаданных, индексный файл и файл данных, каждый из которых при совместном использовании может быстро воссоздать нашу обученную модель.

Помимо сохранения модели, мы должны заморозить ее, прежде чем использовать с TensorFlow Mobile. Процесс замораживания модели, как вы могли догадаться, включает преобразование всех ее переменных в константы. Кроме того, замороженная модель должна представлять собой отдельный двоичный файл, соответствующий формату сериализации в буфере протокола Google.

Создайте новый скрипт Python с именем freeze_model.py и откройте его с помощью текстового редактора. Мы напишем весь код, чтобы заморозить нашу модель внутри этого файла.

Поскольку в TFLearn нет функций для замораживания моделей, нам придется использовать API-интерфейсы TensorFlow прямо сейчас. Импортируйте их, добавив в файл следующую строку:

1
import tensorflow as tf

На протяжении всего сценария мы будем использовать один сеанс TensorFlow. Чтобы создать сеанс, используйте конструктор класса Session .

1
2
with tf.Session() as session:
   # Rest of the code goes here

На этом этапе мы должны создать объект Saver , вызвав import_meta_graph() и передав ей имя файла метаданных модели. Помимо возврата объекта Saver , import_meta_graph() также автоматически добавляет определение графа модели в определение графа сеанса.

После создания заставки мы можем инициализировать все переменные, присутствующие в определении графа, вызвав метод restore() , который ожидает путь к каталогу, содержащему файл последней контрольной точки модели.

1
2
my_saver = tf.train.import_meta_graph(‘xor.tflearn.meta’)
my_saver.restore(session, tf.train.latest_checkpoint(‘.’))

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

1
2
3
4
5
frozen_graph = tf.graph_util.convert_variables_to_constants(
    session,
    session.graph_def,
    [‘my_output/Sigmoid’]
)

Вызов метода SerializeToString() определения замороженного графа дает нам двоичное прототипное представление модели. Используя основные возможности ввода / вывода в Python, я предлагаю вам сохранить его как файл с именем frozen_model.pb .

1
2
with open(‘frozen_model.pb’, ‘wb’) as f:
   f.write(frozen_graph.SerializeToString())

Вы можете запустить скрипт сейчас, чтобы сгенерировать замороженную модель.

Теперь у нас есть все, что нужно, чтобы начать использовать TensorFlow Mobile.

Библиотека TensorFlow Mobile доступна в JCenter, поэтому мы можем напрямую добавить ее в качестве зависимости implementation в файл build.gradle модуля app .

1
implementation ‘org.tensorflow:tensorflow-android:1.7.0’

Чтобы добавить замороженную модель в проект, поместите файл frozen_model.pb в папку ресурсов проекта.

TensorFlow Mobile предлагает простой интерфейс, который мы можем использовать для взаимодействия с нашей замороженной моделью. Чтобы создать интерфейс, используйте конструктор класса AssetManager , который ожидает экземпляр AssetManager и имя файла замороженной модели.

1
2
3
4
5
6
thread {
    val tfInterface = TensorFlowInferenceInterface(assets,
                                        «frozen_model.pb»)
     
    // More code here
}

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

Чтобы убедиться, что TensorFlow Mobile удалось правильно прочитать файл нашей модели, давайте теперь попробуем напечатать имена всех операций, присутствующих в графике модели. Чтобы получить ссылку на график, мы можем использовать метод graph() интерфейса, а для получения всех операций — метод operations() графа. Следующий код показывает вам, как:

1
2
3
4
val graph = tfInterface.graph()
graph.operations().forEach {
    println(it.name())
}

Если вы запустите приложение сейчас, вы сможете увидеть более десятка имен операций, напечатанных в окне Logcat в Android Studio. Среди всех этих имен, если при замораживании модели не было ошибок, вы сможете найти имена входных и выходных слоев: my_input / X и my_output / Sigmoid .

Logcat window showing list of operations

Чтобы делать прогнозы с помощью модели, мы должны поместить данные в ее входной слой и извлечь данные из его выходного слоя. Чтобы поместить данные во входной слой, используйте метод feed() интерфейса, который ожидает имя слоя, массив, содержащий входные данные, и размеры массива. Следующий код показывает, как отправить цифры 0 и 1 на входной слой:

1
2
tfInterface.feed(«my_input/X»,
           floatArrayOf(0f, 1f), 1, 2)

После загрузки данных во входной слой мы должны выполнить операцию вывода с помощью метода run() , который ожидает имя выходного слоя. После завершения операции выходной слой будет содержать прогноз модели. Чтобы загрузить прогноз в массив Kotlin, мы можем использовать метод fetch() . Следующий код показывает вам, как это сделать:

1
2
3
4
tfInterface.run(arrayOf(«my_output/Sigmoid»))
 
val output = floatArrayOf(-1f)
tfInterface.fetch(«my_output/Sigmoid», output)

Как вы используете прогноз, конечно, зависит от вас. На данный момент я предлагаю вам просто распечатать его.

1
println(«Output is ${output[0]}»)

Вы можете запустить приложение сейчас, чтобы убедиться в правильности прогноза модели.

Logcat window displaying the prediction

Не стесняйтесь менять числа, которые вы вводите во входной слой, чтобы подтвердить, что прогнозы модели всегда верны.

Теперь вы знаете, как создать простую модель TensorFlow и использовать ее с TensorFlow Mobile в приложениях Android. Вы не всегда должны ограничивать себя своими собственными моделями. С навыками, которые вы приобрели сегодня, у вас не должно возникнуть проблем при использовании более крупных моделей, таких как MobileNet и Inception, доступных в зоопарке TensorFlow. Тем не менее, обратите внимание, что такие модели приведут к увеличению размера APK, что может создать проблемы для пользователей с недорогими устройствами.

Чтобы узнать больше о TensorFlow Mobile, обратитесь к официальной документации .