Как мобильный разработчик, я всегда ищу новые интересные способы создания приложений, которые могут быть полезны пользователям. Одной из областей, которая меня особенно интересовала в последнее время, является машинное обучение, которое может изменить то, как мы создаем приложения и взаимодействуем с окружающим миром. В этой статье я поделюсь примером того, как создать простое приложение для машинного обучения в React Native с использованием TensorFlow.js.

Почему React Native и TensorFlow.js?

React Native — это популярная платформа для создания мобильных приложений, которая позволяет разработчикам использовать JavaScript и модель программирования React для создания приложений как для iOS, так и для Android. TensorFlow.js — это библиотека, которая позволяет разработчикам использовать машинное обучение в JavaScript и может использоваться в веб-приложениях, приложениях Node.js и даже мобильных приложениях, созданных с помощью React Native.

Используя вместе React Native и TensorFlow.js, разработчики могут создавать приложения машинного обучения, которые работают на устройствах iOS и Android, используя знакомую модель программирования и мощную библиотеку машинного обучения.

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

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

Начиная

Прежде чем мы сможем начать создавать наше приложение для машинного обучения, нам нужно настроить новый проект React Native и установить необходимые зависимости. Для этого мы будем использовать инструмент expo-cli для создания нового проекта React Native.

Если у вас еще не установлен expo-cli, вы можете установить его, выполнив следующую команду:

npm install -g expo-cli

После установки expo-cli вы можете создать новый проект React Native, выполнив следующую команду:

expo init my-app

Это создаст новый проект React Native с именем my-app. Далее нам нужно установить необходимые зависимости для нашего приложения машинного обучения. Нам потребуется установить следующие пакеты:

  • expo-camera: библиотека, обеспечивающая доступ к камере устройства.
  • expo-permissions: библиотека, предоставляющая простой в использовании интерфейс для запроса разрешений у пользователя.
  • expo-image-picker: библиотека, которая позволяет пользователю выбирать изображение из галереи своего устройства.
  • @tensorflow-models/mobilenet: предварительно обученная модель, которую можно использовать для задач классификации изображений.
  • @tensorflow-models/knn-classifier: библиотека, обеспечивающая реализацию алгоритма KNN для задач машинного обучения.
  • @tensorflow/tfjs: Основная библиотека TensorFlow.js.

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

cd HandwrittenDigitClassifier
npm install expo-camera expo-permissions expo-image-picker @tensorflow-models/mobilenet @tensorflow-models/knn-classifier @tensorflow/tfjsOnce 

Веселая часть

Чтобы все было организовано, мы создадим новый файл с именем CameraScreen.tsx в каталоге src нашего проекта. Этот файл будет содержать код экрана нашей камеры, который позволит пользователю сфотографировать написанную от руки цифру. Вот код для CameraScreen.tsx:

import * as React from 'react';
import { View, Text, Button } from 'react-native';
import { Camera } from 'expo-camera';
import { Tensor3D } from '@tensorflow/tfjs';
import * as mobilenet from '@tensorflow-models/mobilenet';
import * as knnClassifier from '@tensorflow-models/knn-classifier';

interface Props {
  navigation: any;
}

export default function CameraScreen({ navigation }: Props) {
  const [hasPermission, setHasPermission] = React.useState<boolean | null>(null);
  const [cameraRef, setCameraRef] = React.useState<Camera | null>(null);
  const [classifier, setClassifier] = React.useState<knnClassifier.KNNClassifier | null>(null);
  const [isModelReady, setIsModelReady] = React.useState<boolean>(false);
  const [result, setResult] = React.useState<string>('');

  React.useEffect(() => {
    (async () => {
      const { status } = await Camera.requestPermissionsAsync();
      setHasPermission(status === 'granted');
      if (status !== 'granted') {
        alert('Sorry, we need camera permissions to make this work!');
      }
    })();
  }, []);

  React.useEffect(() => {
    (async () => {
      const classifier = knnClassifier.create();

      const mobileNet = await mobilenet.load();
      const model = mobileNet.model;

      const image = await Camera.takePictureAsync({ base64: true });

      const activation = model.predict(imageToTensor(image)).squeeze() as Tensor3D;
      classifier.addExample(activation, '1');

      setClassifier(classifier);
      setIsModelReady(true);
    })();
  }, []);

  const imageToTensor = (image: { base64: string }): Tensor3D => {
    const buffer = tf.util.encodeString(image.base64, 'base64');
    const decoded = tf.util.decodeString(buffer, 'binary');
    const imageTensor = tf.node.decodeImage(decoded);
    return imageTensor.expandDims(0);
  };

  const handleCameraRef = (ref: Camera | null) => {
    setCameraRef(ref);
  };

  const handleTakePicture = async () => {
    if (!classifier || classifier.getNumClasses() === 0) {
      setResult('No examples trained');
      return;
    }

    if (cameraRef) {
      const photo = await cameraRef.takePictureAsync({ base64: true });
      const activation = mobilenet.infer(imageToTensor(photo), 'conv_preds');
      const result = await classifier.predictClass(activation);

      setResult(result.label);
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <Camera style={{ flex: 1 }} type={Camera.Constants.Type.back} ref={handleCameraRef}>
        <View
          style={{
            flex: 1,
            backgroundColor: 'transparent',
            flexDirection: 'row',
          }}>
          <Button title="Take Picture" onPress={handleTakePicture} />
        </View>
      </Camera>
      <Text style={{ fontSize: 24, margin: 16 }}>Prediction: {result}</Text>
    </View>
  );
}

Хуки useEffect используются для запроса разрешений камеры и загрузки предварительно обученной модели и классификатора KNN при монтировании компонента.

Функция imageToTensor используется для преобразования изображения в тензор TensorFlow.

Функция handleCameraRef используется для установки ссылки на камеру при установке компонента.

Функция handleTakePicture используется, чтобы сделать снимок с помощью камеры и использовать предварительно обученную модель и классификатор KNN для предсказания цифры. Если в классификаторе KNN нет обученных примеров, приложение отобразит сообщение «Нет обученных примеров».

Наконец, мы возвращаем компонент камеры с кнопкой «Сделать снимок» и текстовым компонентом для отображения предсказанной цифры.

В файле utils.ts мы определяем функцию encodeImageBase64, которая используется для кодирования изображения в виде строки base64.

export const encodeImageBase64 = (image: ArrayBuffer): string => {
  return btoa(new Uint8Array(image).reduce((data, byte) => data + String.fromCharCode(byte), ''));
};

Эта функция используется для кодирования изображений в виде строк base64 перед их передачей в TensorFlow.js.

Тестирование

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

import 'react-native';
import React from 'react';
import CameraScreen from '../CameraScreen';

import { render } from '@testing-library/react-native';

describe('CameraScreen', () => {
  it('renders correctly', () => {
    const { toJSON } = render(<CameraScreen navigation={{}} />);
    expect(toJSON()).toMatchSnapshot();
  });
});

Мы можем запустить этот тест, выполнив следующую команду:

npm test

В этой статье мы рассмотрели, как создать простое приложение для машинного обучения в React Native с использованием TensorFlow.js. Мы создали приложение с двумя экранами, которое может идентифицировать рукописные цифры с помощью предварительно обученной модели и классификатора KNN. Мы также рассмотрели некоторые базовые модульные тесты. Используя вместе React Native и TensorFlow.js, мобильные разработчики могут создавать мощные приложения для машинного обучения, которые могут работать как на устройствах iOS, так и на устройствах Android.

Если вам нравится, пожалуйста 👏🏽