Классификация изображений в React Native с моделями TensorFlow.js и MobileNet

React Native
Классификация изображений в React Native с моделями TensorFlow.js и MobileNet

Оригинальная ссылкасердцебиение.Fritz.love/image-класс…

В последнее время дляReact NativeиExpoПрограммыTensorFlow.jsизalphaвыпущена версия. В настоящее время поддерживается загрузка предварительно обученных моделей и обучение новых моделей, вот объявление в твиттере:

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

Примечание. В прошлом я прикасался к Google Vision API, чтобы создать приложение для классификации изображений, которое могло бы определять, является ли данное изображение хот-догом. Если вам интересно прочитать пример, пожалуйста, нажмите на следующую ссылку:heartbeat.Fritz.love/build-ah-not…

Содержание этой статьи

  • Подготовка окружающей среды
  • Интегрируйте TF.js в приложение Expo
  • Протестируйте интеграцию с TF.js
  • Загрузите модель MobileNet
  • Запрашивать разрешения пользователя
  • Преобразование необработанного изображения в тензор
  • Загрузка и классификация изображений
  • Разрешить пользователю выбирать изображение
  • запустить приложение
  • в заключении

Ссылка на полный код:GitHub.com/EP Амана в Массачусетском технологическом институте…

Подготовка окружающей среды

  • местная средаNodejs >= 10.x.x
  • expo-cli
  • применять кAndroidилиiOSПриложение Expo Client для тестирования APP

Интегрируйте TF.js в приложение Expo

существуетReact Nativeиспользуется вTensorFlowбиблиотека, первый шаг — интегрировать адаптер платформы —tfjs-react-nativeМодули, поддерживающие загрузку всех основных из ИнтернетаtfjsМодель. Он также используетexpo-glпри условииGPUслужба поддержки.

Откройте окно терминала и создайте новое приложение Expo, выполнив следующие команды.

expo init mobilenet-tfjs-expo

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

yarn add @react-native-community/async-storage @tensorflow/tfjs @tensorflow/tfjs-react-native expo-gl @tensorflow-models/mobilenet jpeg-js
Примечание. Если вы хотите использовать react-native-cli для создания своего приложения, вы можете следовать явным инструкциям по изменению файла metro.config.js и другим необходимым шагам, как описано здесь.

Даже если вы используете Expo, вам все равно нужно установить зависимости модуля tfjsasync-storage.

Протестируйте интеграцию с TF.js

Нам нужно убедиться, что tfjs успешно загружен в приложение перед рендерингом приложения. Вот асинхронная функция, называемаяtf.ready(). ОткрытымApp.jsфайл, импортируйте необходимые зависимости и определитеisTfReadyНачальное состояниеfalse.

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import * as tf from '@tensorflow/tfjs'
import { fetch } from '@tensorflow/tfjs-react-native'

class App extends React.Component {
  state = {
    isTfReady: false
  }

  async componentDidMount() {
    await tf.ready()
    this.setState({
      isTfReady: true
    })

    //Output in Expo console
    console.log(this.state.isTfReady)
  }

  render() {
    return (
      <View style={styles.container}>
        <Text>TFJS ready? {this.state.isTfReady ? <Text>Yes</Text> : ''}</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
})

export default App

Поскольку методы жизненного цикла являются асинхронными, только когда фактическая нагрузкаtfjsбудетisTfReadyЗначение обновляется доtrue.

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

или в консоли (при использовании оператора консоли)

Загрузите модуль MobileNet

Как и в предыдущем шаге, перед предоставлением входного изображения вы также должны загрузитьMobileNetМодель. Загрузить предварительно обученный из ИнтернетаTensorFlow.jsМоделирование — это дорогостоящий сетевой вызов, который займет много времени. ИсправлятьApp.jsфайл для загрузкиMobileNetМодель. Сначала импортируйте его:

import * as mobilenet from '@tensorflow-models/mobilenet'

Добавьте другие свойства начального состояния:

state = {
  isTfReady: false,
  isModelReady: false
}

Измените метод жизненного цикла:

async componentDidMount() {
    await tf.ready()
    this.setState({
      isTfReady: true
    })
    this.model = await mobilenet.load()
    this.setState({ isModelReady: true })
}

Наконец, давайте отобразим индикатор на экране, когда модель загружена.

<Text>
  Model ready?{' '}
  {this.state.isModelReady ? <Text>Yes</Text> : <Text>Loading Model...</Text>}
</Text>

При загрузке модуля отображается следующая информация:

Загрузка модуля завершена и появится

Запрашивать разрешения пользователя

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

expo install expo-permissions expo-constants expo-image-picker

существуетAPP.jsдобавлено вimportутверждение

import Constants from 'expo-constants'
import * as Permissions from 'expo-permissions'

существуетAPPДобавьте метод в класс:

getPermissionAsync = async () => {
  if (Constants.platform.ios) {
    const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL)
    if (status !== 'granted') {
      alert('Sorry, we need camera roll permissions to make this work!')
    }
  }
}

существуетcomponentDidMount()Этот асинхронный метод вызывается внутри:

async componentDidMount() {
    await tf.ready()
    this.setState({
      isTfReady: true
    })
    this.model = await mobilenet.load()
    this.setState({ isModelReady: true })

    // add this
    this.getPermissionAsync()
  }

Преобразование необработанного изображения в тензор

Приложение попросит пользователей загрузить изображения с камеры или галереи телефона. Вы должны добавить метод для загрузки изображения и разрешитьTensorFlowРасшифруйте данные на изображении.TensorFlowслужба поддержкиJPEGиPNGФормат.

существуетApp.jsфайл, первый импортjpeg-jsПакет, который будет использоваться для декодирования данных в изображении.

import * as jpeg from 'jpeg-js'

методimageToTensorДля декодирования ширины, высоты и двоичных данных изображения этот метод принимает параметры исходных данных изображения.

imageToTensor(rawImageData) {
    const TO_UINT8ARRAY = true
    const { width, height, data } = jpeg.decode(rawImageData, TO_UINT8ARRAY)
    // Drop the alpha channel info for mobilenet
    const buffer = new Uint8Array(width * height * 3)
    let offset = 0 // offset into original data
    for (let i = 0; i < buffer.length; i += 3) {
      buffer[i] = data[offset]
      buffer[i + 1] = data[offset + 1]
      buffer[i + 2] = data[offset + 2]

      offset += 4
    }

    return tf.tensor3d(buffer, [height, width, 3])
  }

TO_UINT8ARRAYмассив представляет собой массив 8-битных целых чисел без знака. Метод строительстваUint8Array()— это новый синтаксис ES2017. Для различных типизированных массивов каждый тип массива имеет свой собственный диапазон байтов в памяти.

Загрузка и классификация изображений

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

должен быть в компоненте приложенияstateПуть для сохранения этого источника изображения для чтения изображения из источника. Точно так же должен быть включен результат, полученный описанным выше асинхронным методом. Это последняя модификацияApp.jsСуществующее состояние в файле.

state = {
  isTfReady: false,
  isModelReady: false,
  predictions: null,
  image: null
}

Добавьте асинхронный метод:

classifyImage = async () => {
  try {
    const imageAssetPath = Image.resolveAssetSource(this.state.image)
    const response = await fetch(imageAssetPath.uri, {}, { isBinary: true })
    const rawImageData = await response.arrayBuffer()
    const imageTensor = this.imageToTensor(rawImageData)
    const predictions = await this.model.classify(imageTensor)
    this.setState({ predictions })
    console.log(predictions)
  } catch (error) {
    console.log(error)
  }
}

Результаты предварительно обученной модели выводятся в виде массива. Пример выглядит следующим образом:

Разрешить пользователю выбирать изображение

Для выбора изображения с камеры системного устройства необходимо использоватьexpo-image-pickerАсинхронные методы, предоставляемые пакетомImagePicker.launchImageLibraryAsync. импортный пакет:

import * as Permissions from 'expo-permissions'

Добавьте метод selectImage для:

  • Позвольте пользователю выбрать изображение
  • выбрать изображение, вstate.imageисточник заполненияURIобъект
  • Наконец, позвонитеclassifyImage()метод прогнозирования на основе заданных входных данных

selectImage = async () => {
  try {
    let response = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3]
    })

    if (!response.cancelled) {
      const source = { uri: response.uri }
      this.setState({ image: source })
      this.classifyImage()
    }
  } catch (error) {
    console.log(error)
  }
}

Сумкаexpo-image-pickerВозвращает объект. Если пользователь отменит процесс выбора изображения, модуль выбора изображения вернет одно свойство:canceled:true. В случае успеха модуль выбора изображений вернет такие атрибуты, как само изображение.uri. Таким образом, в приведенном выше фрагментеifПредложения важны.

запустить приложение

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

ЭтоApp.jsв файлеrenderПолный фрагмент кода метода:

render() {
    const { isTfReady, isModelReady, predictions, image } = this.state

    return (
      <View style={styles.container}>
        <StatusBar barStyle='light-content' />
        <View style={styles.loadingContainer}>
          <Text style={styles.commonTextStyles}>
            TFJS ready? {isTfReady ? <Text>✅</Text> : ''}
          </Text>

          <View style={styles.loadingModelContainer}>
            <Text style={styles.text}>Model ready? </Text>
            {isModelReady ? (
              <Text style={styles.text}>✅</Text>
            ) : (
              <ActivityIndicator size='small' />
            )}
          </View>
        </View>
        <TouchableOpacity
          style={styles.imageWrapper}
          onPress={isModelReady ? this.selectImage : undefined}>
          {image && <Image source={image} style={styles.imageContainer} />}

          {isModelReady && !image && (
            <Text style={styles.transparentText}>Tap to choose image</Text>
          )}
        </TouchableOpacity>
        <View style={styles.predictionWrapper}>
          {isModelReady && image && (
            <Text style={styles.text}>
              Predictions: {predictions ? '' : 'Predicting...'}
            </Text>
          )}
          {isModelReady &&
            predictions &&
            predictions.map(p => this.renderPrediction(p))}
        </View>
        <View style={styles.footer}>
          <Text style={styles.poweredBy}>Powered by:</Text>
          <Image source={require('./assets/tfjs.jpg')} style={styles.tfLogo} />
        </View>
      </View>
    )
  }
}

полныйstylesОбъект:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#171f24',
    alignItems: 'center'
  },
  loadingContainer: {
    marginTop: 80,
    justifyContent: 'center'
  },
  text: {
    color: '#ffffff',
    fontSize: 16
  },
  loadingModelContainer: {
    flexDirection: 'row',
    marginTop: 10
  },
  imageWrapper: {
    width: 280,
    height: 280,
    padding: 10,
    borderColor: '#cf667f',
    borderWidth: 5,
    borderStyle: 'dashed',
    marginTop: 40,
    marginBottom: 10,
    position: 'relative',
    justifyContent: 'center',
    alignItems: 'center'
  },
  imageContainer: {
    width: 250,
    height: 250,
    position: 'absolute',
    top: 10,
    left: 10,
    bottom: 10,
    right: 10
  },
  predictionWrapper: {
    height: 100,
    width: '100%',
    flexDirection: 'column',
    alignItems: 'center'
  },
  transparentText: {
    color: '#ffffff',
    opacity: 0.7
  },
  footer: {
    marginTop: 40
  },
  poweredBy: {
    fontSize: 20,
    color: '#e69e34',
    marginBottom: 6
  },
  tfLogo: {
    width: 125,
    height: 70
  }
})

Выполнить из окна терминалаexpo startкоманда для запуска этой программы. Первое, что вы заметите, это то, что вExpoПосле загрузки приложения в клиенте оно запросит разрешение.

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

Прогнозирование результатов может занять некоторое время. Это результат ранее выбранного изображения.

в заключении

Цель этой статьи — дать вам первое представление о том, какReact Nativeреализовано в приложенииTesnorFlow.jsмодели и лучшее понимание классификации изображений, основного варианта использования машинного обучения на основе компьютерного зрения.

Поскольку на момент написанияReact NativeизTF.jsвalphaверсии, поэтому мы надеемся увидеть более продвинутые примеры для создания приложений реального времени в будущем. Вот некоторые ресурсы, которые я считаю очень полезными.tfjs-react-native GitHubРепозиторий с большим количеством примеров с использованием различных предварительно обученных моделейInfinite RedизNSFW JSиReact NativeПримеры понятны и очень полезныTensorflow.jsВведение