Как на Raspberry Pi запустить модель ML и сэкономить пространство одноплатника

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Представьте ситуацию: впереди выходные, а у вас есть достаточно нагруженная малинка и вы — ради эксперимента — хотите посмотреть, что ML умеет на мощностях RPi, но не хотите слишком перегружать машину, даже всей облегчённой версией TF. Что можно сделать? Мы уже писали о классификации мусора с помощью RPi, а сегодня, к старту курса о глубоком и машинном обучении, делимся переводом руководства, автор которого приводит простейший пример работы с необходимым минимумом TFLite. Выводы делаются моделью менее чем за секунду, при этом не нужно устанавливать весь пакет TensorFlow; используется только tflite_runtime, поддерживающий класс Interpreter.


Доступ к Raspberry Pi с компьютера

Есть несколько способов доступа к Raspberry Pi. Вне зависимости от способа цель — получить доступ к терминалу RPi для ввода команд, помогающих подготовить компьютер к работе с TFLite.

Можно работать с RPi как с обычным ПК, подключив его к монитору через порт HDMI, а также подсоединив мышь и клавиатуру. После успешного запуска RPi вы сможете получить доступ к его графическому интерфейсу и открыть терминал. К сожалению, этот метод может не сработать при покупке новой RPi: чтобы разрешить использование порта HDMI, нужно изменить некоторые настройки.

Доступ к RPi через специальный монитор и периферийные устройства обойдётся дорого, если у вас нет собственного ПК/ноутбука. Для управления RPi через свой ПК сначала нужно подключить порт Ethernet RPi к порту коммутатора. Коммутатор должен поддерживать протокол DHCP, чтобы IP-адрес для RPi присваивался автоматически.

Назначив IP, при помощи IP-сканера вы найдёте IP Ethernet-интерфейса RPi с подключённого через тот же коммутатор ПК, а имея IP-адрес RPi, с вашего ПК вы сможете открыть сеанс SSH, где получите доступ к терминалу RPi. Подробности читайте в этом учебном руководстве.

При таком доступе RPi нужно каждый раз подключать к коммутатору. Чтобы упростить работу, можно воспользоваться беспроводным интерфейсом. Подключив RPi к порту коммутатора и настроив его беспроводной интерфейс на беспроводную сеть, вы облегчите доступ к малинке в будущем. Эта сеть может быть создана со смартфона, он будет точкой доступа.

Возможно, после настройки сети коммутатор не понадобится. Всё, что нужно сделать, — подключить ПК к той же беспроводной сети. IP-сканер сообщит IP беспроводного интерфейса в RPi. После этого можно открыть сеанс SSH и достучаться до терминала одноплатника.

Независимо от метода доступа к RPi вы должны иметь возможность получить доступ к терминалу, как на рисунке ниже. На этом этапе можно подготовить TFLite командами терминала, их обсудим ниже.

Подготовка TFLite в RPi

Здесь предполагается, что у вас уже есть модель TensorFlow, преобразованная в модель TensorFlow Lite. Если это не так, есть множество моделей TensorFlow Lite, которые можно загрузить; воспользуемся Lite-версией MobileNet.

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

Единственный класс TensorFlow, необходимый для прогнозирования в режиме TFLite — это Interpreter, доступ к нему можно получить так:

import tensorflow.lite.python.interpreter.Interpreter

То есть вместо установки всего TensorFlow можно установить только этот класс, сэкономив пространство на RPi. Но как именно установить только этот класс?

Пакет tflite_runtime содержит только класс Interpreter. Доступ к нему можно получить по адресу tflite_runtime.interpreter.Interpreter. Чтобы установить tflite_runtime, просто скачайте подходящее версии Python wheel, например Python 3.5 или Python 3.7.

В моей RPi файл .whl расположен здесь: 

/home/pi/Downloads/tflite_runtime-1.14.0-cp35-cp35m-linux_armv7l.whl

Чтобы установить скачанный пакет, я запустил pip3 install. Обратите внимание: нужно использовать pip3: просто pip будет работать с Python 2.

pip3 install /home/pi/Downloads/tflite_runtime-1.14.0-cp35-cp35m-linux_armv7l.whl
Пакет успешно установлен
Пакет успешно установлен

Установив tflite_runtime, вы можете проверить, что всё работает правильно, импортировав класс Interpreter:

from tflite_runtime.interpreter import Interpreter

И вот результат:

Установка tflite_runtime не означает, что установлена вся TFLite. Доступен только класс Interpreter, который делает прогнозы на основе TFLite. Если нужны другие возможности TFLite, установите TensorFlow.

После установки tflite_runtime и подготовки RPi к прогнозированию переходим к следующему шагу.

Загрузка MobileNet

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

1) mobilenet_v1_1.0_224_quant.tflite;

2) labels_mobilenet_quant_v1_224.txt.

У MobileNet две версии, от версии зависит разрешение входного изображения. Здесь воспользуемся первой версией, она принимает изображения с разрешением 224x224. Модель подвергается квантованию, то есть она уменьшается, снижается задержка прогнозов. Для двух изображений на RPi я создал новую папку TFLite_MobileNet.

/home/pi/TFLite_MobileNetmobilenet_v1_1.0_224_quant.tflitelabels_mobilenet_quant_v1_224.txttest.jpg

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

Классификация одного изображения

Код загрузки модели TFLite и классификации приведён ниже. Пути к модели и файла меток классов содержатся в model_path и labels. Пути к модели для её загрузки передаются конструктору класса Interpreter. Загруженная модель возвращается в переменной interpreter.

from tflite_runtime.interpreter import Interpreter 
from PIL import Image
import numpy as np
import time

data_folder = "/home/pi/TFLite_MobileNet/"

model_path = data_folder + "mobilenet_v1_1.0_224_quant.tflite"
label_path = data_folder + "labels_mobilenet_quant_v1_224.txt"

interpreter = Interpreter(model_path)
print("Model Loaded Successfully.")

interpreter.allocate_tensors()
_, height, width, _ = interpreter.get_input_details()[0]['shape']
print("Image Shape (", width, ",", height, ")")

# Load an image to be classified.
image = Image.open(data_folder + "test.jpg").convert('RGB').resize((width, height))

# Classify the image.
time1 = time.time()
label_id, prob = classify_image(interpreter, image)
time2 = time.time()
classification_time = np.round(time2-time1, 3)
print("Classificaiton Time =", classification_time, "seconds.")

# Read class labels.
labels = load_labels(label_path)

# Return the classification label of the image.
classification_label = labels[label_id]
print("Image Label is :", classification_label, ", with Accuracy :", np.round(prob*100, 2), "%.")

После загрузки модели для выделения памяти под входные и выходные тензоры вызывается метод allocate_tensors(), затем, чтобы вернуть информацию о входном тензоре, вызывается get_input_details(). В возвращаемую информацию входят ширина и высота входного изображения. Для чего они?

Вспомните, что загруженная модель принимает изображения 224x224. Если подать изображение другого размера, мы получим ошибку. Зная ширину и высоту принимаемого моделью изображения, можно изменить размер входных данных так, чтобы модель могла работать с ними. Тестовое изображение считывается с помощью PIL, и возвращается изображение с подходящим модели разрешением.

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

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

Далее для запуска модели и передачи входных данных вызывается invoke(). Выходные данные — индекс класса и его вероятность.

def classify_image(interpreter, image, top_k=1):
  set_input_tensor(interpreter, image)

  interpreter.invoke()
  output_details = interpreter.get_output_details()[0]
  output = np.squeeze(interpreter.get_tensor(output_details['index']))

  scale, zero_point = output_details['quantization']
  output = scale * (output - zero_point)

  ordered = np.argpartition(-output, 1)
  return [(i, output[i]) for i in ordered[:top_k]][0]

Далее метки классов загружаются из текстового файла с помощью функции load_labels(), её реализация показана ниже. Она принимает путь к текстовому файлу и возвращает список с метками классов. Индекс класса, к которому отнесено изображение, используется для возврата соответствующей метки класса. Наконец, метка выводится на консоль.

def load_labels(path): # Read the labels from the text file as a Python list.
  with open(path, 'r') as f:
    return [line.strip() for i, line in enumerate(f.readlines())]

Весь код приведён ниже.

from tflite_runtime.interpreter import Interpreter 
from PIL import Image
import numpy as np
import time

def load_labels(path): # Read the labels from the text file as a Python list.
  with open(path, 'r') as f:
    return [line.strip() for i, line in enumerate(f.readlines())]

def set_input_tensor(interpreter, image):
  tensor_index = interpreter.get_input_details()[0]['index']
  input_tensor = interpreter.tensor(tensor_index)()[0]
  input_tensor[:, :] = image

def classify_image(interpreter, image, top_k=1):
  set_input_tensor(interpreter, image)

  interpreter.invoke()
  output_details = interpreter.get_output_details()[0]
  output = np.squeeze(interpreter.get_tensor(output_details['index']))

  scale, zero_point = output_details['quantization']
  output = scale * (output - zero_point)

  ordered = np.argpartition(-output, 1)
  return [(i, output[i]) for i in ordered[:top_k]][0]

data_folder = "/home/pi/TFLite_MobileNet/"

model_path = data_folder + "mobilenet_v1_1.0_224_quant.tflite"
label_path = data_folder + "labels_mobilenet_quant_v1_224.txt"

interpreter = Interpreter(model_path)
print("Model Loaded Successfully.")

interpreter.allocate_tensors()
_, height, width, _ = interpreter.get_input_details()[0]['shape']
print("Image Shape (", width, ",", height, ")")

# Load an image to be classified.
image = Image.open(data_folder + "test.jpg").convert('RGB').resize((width, height))

# Classify the image.
time1 = time.time()
label_id, prob = classify_image(interpreter, image)
time2 = time.time()
classification_time = np.round(time2-time1, 3)
print("Classificaiton Time =", classification_time, "seconds.")

# Read class labels.
labels = load_labels(label_path)

# Return the classification label of the image.
classification_label = labels[label_id]
print("Image Label is :", classification_label, ", with Accuracy :", np.round(prob*100, 2), "%.")

Вывод программы:

Model Loaded Successfully.
Image Shape ( 224 , 224 )
Classificaiton Time = 0.345 seconds.
Image Label is : Egyptian cat , with Accuracy : 53.12 %.

Raspberry Pi — относительно недорогой компьютер, на котором уже сегодня можно запускать простые модели — ML идёт к тому, чтобы стать таким же естественным, как вода в вашем доме — и если вы не хотите оставаться в стороне от сферы ИИ, то можете обратить внимание на наш курс «Machine Learning и Deep Learning», а если предпочитаете полагаться не на машины, но на себя, то можете присмотреться к нашему флагманскому курсу о Data Science.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

  • Профессия Data Scientist

  • Профессия Data Analyst

  • Курс по Data Engineering

Другие профессии и курсы

ПРОФЕССИИ

  • Профессия Fullstack-разработчик на Python

  • Профессия Java-разработчик

  • Профессия QA-инженер на JAVA

  • Профессия Frontend-разработчик

  • Профессия Этичный хакер

  • Профессия C++ разработчик

  • Профессия Разработчик игр на Unity

  • Профессия Веб-разработчик

  • Профессия iOS-разработчик с нуля

  • Профессия Android-разработчик с нуля

КУРСЫ

  • Курс по Machine Learning

  • Курс «Machine Learning и Deep Learning»

  • Курс «Математика для Data Science»

  • Курс «Математика и Machine Learning для Data Science»

  • Курс «Python для веб-разработки»

  • Курс «Алгоритмы и структуры данных»

  • Курс по аналитике данных

  • Курс по DevOps

Источник: https://habr.com/ru/company/skillfactory/blog/566926/


Интересные статьи

Интересные статьи

Здесь есть поклонники Kubernetes? Я уже довольно давно пользуюсь Kubernetes как на работе, так и в других местах, где занимаюсь частными проектами, но иногда мне нужно ме...
Так как agile и scrum сегодня строят большинство проектных работ внутри каждой большой компании, мы задумались над тем, каким должно быть офисное пространство нового типа – пространство, ...
Недавно мы опубликовали статью о VMware ESXi на Raspberry Pi. В начале октября разработчики анонсировали техническое превью гипервизора VMware ESXi на архитектуре aarch64 под названием ...
Введение. Конкурентный корутинизм. Предыдущие статьи на тему автоматного программирования были всего лишь «цветочками». «Ягодкой» автоматного программирования, т.е. ради чего нужно им занимать...
Компании растут и меняются. Если для небольшого бизнеса легко прогнозировать последствия любых изменений, то у крупного для такого предвидения — необходимо изучение деталей.