“A robot named Pepper holding an iPad” by Alex Knight on Unsplash

Existem algumas tecnologias que surgem e são esquecidas. Outras, surgem e viram moda. Inteligência artificial é um exemplo de tecnologia que está em alta no momento.Dentro da área da inteligência artificial, temos o aprendizado de máquina, que compreende a parte de utilizar técnicas estatísticas para dar a habilidade aos computadores de melhorar sua performance em uma tarefa definida. A Apple não poderia deixar passar este momento e vamos ver como colocar um modelo de aprendizado de máquina em um aplicativo iOS. Falei um monte de palavras difíceis, alguns casos de uso devem simplificar nosso entendimento:

  • Utilizar a camera do seu iPhone para descobrir qual o nome daquela planta que você viu na praça do seu bairro.
  • Utilizar o teclado do seu iPhone para te ajudar a escrever mais rapidamente, recebendo sugestões de próximas palavras de acordo com o que você acabou de escrever.
  • Separar as fotos e vídeos daquela ultima viagem para o litoral e criar montagens a partir dos mesmos.

Fazer isso tudo funcionar é mais simples do que parece. Para tanto, a Apple criou os Modelos de aprendizagem de máquina CoreML, no formato de arquivos .mlmodel. Quando acionados, eles conseguem por exemplo tentar identificar a partir de uma foto de uma fruta se aquela fruta é uma maçã ou uma laranja. Essa é a essência dos modelos. Você vai passar uma ou mais informações para eles e após o processamento, vão te retornar uma ou mais informações. Para efeitos práticos vamos criar um projeto capaz de classificar objetos usando a câmera do telefone, mas as possibilidades são infinitas.

TuriCreate:

Vamos começar, codificando em python. Para o nosso projeto, devemos definir quais objetos queremos que nosso app saiba classificar e pegar um monte de imagens deles. No exemplo, estou detectando celulares, comida, copos, canecas, paisagens, entre outros. A Apple disponibilizou uma biblioteca chamada turicreate que permite a conversão de modelos já existentes de outras plataformas (como tensor flow, do google) para coreML ou a criação dos mesmos. Para o nosso caso, criei o código disponível neste link, que analisa uma série de imagens dentro de pastas nomeadas e gera um modelo que aprende a classificar um objeto novo comparando com o que ele já sabe. Não vou entrar muito em detalhes sobre este processo pois o foco aqui será o aplicativo. Se quiser executar este script ou outro editado com a mesma finalidade, é recomendada a utilização de uma máquina com bastante memória RAM, pois o processo demora um pouco.

Vamos ao app:

Primeiro, crie um projeto novo no Xcode do tipo single view application. Logo após, adicione o arquivo imageClassifier.mlmodel encontrado neste repositório:https://github.com/eduardolomb/ClassificadorML dentro do projeto. Ao clicar nele nos deparamos com esta tela:

Perceba que em Model Evaluation Parameters temos a definição do modelo: ele recebe uma imagem colorida de resolução 224 x 224 e retorna um dicionário com as probabilidades de previsão e um texto com a previsão de maior probabilidade de acerto.

Nossa interface, será bem simples. Teremos uma UiView para adicionar a imagem da câmera e umUiLabel.

Exemplo de Interface do aplicativo.

Faça a ligação de todos os IBoutlets para a sua ViewController e também realize a conexão entre essa viewController e sua classe. Já no código, precisamos importar os frameworks CoreML e o Vision. Logo após devemos implementar o AVCaptureVideoDataOutputSampleBufferDelegate para capturar imagens da câmera como abaixo:

//MARK: - Camera capture delegates
private lazy var captureSession: AVCaptureSession = {
let session = AVCaptureSession()
session.sessionPreset = AVCaptureSession.Preset.hd1920x1080
guard let backCamera =
AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),let input = try? AVCaptureDeviceInput(device: backCamera) else { return session }
session.addInput(input)
return session
}()

Devemos também implementar o método do vision abaixo. Esse método vai transferindo uma sequencia de imagens para o nosso modelo que fará o reconhecimento de cada uma delas.

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
var requestOptions:[VNImageOption : Any] = [:]
if let cameraIntrinsicData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) {
requestOptions = [.cameraIntrinsics:cameraIntrinsicData]
}
guard let value = CGImagePropertyOrientation(rawValue: 1) else {
return
}
let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation:value , options: requestOptions)
do {
try imageRequestHandler.perform(self.requests)
} catch {
print(error)
}
}

Temos que implementar também um método que deverá ser chamado em algum delegate da ViewController para poder carregar o modelo no código. Estamos trabalhando com VNCoreMLModels, ou seja modelos de aprendizagem de máquina voltados para visão computacional. Para modelos que não utilizem uma imagem como entrada podemos criar um MLModel

func setupVision() {
guard let visionModel = try? VNCoreMLModel(for: imageClassifier().model) else {
fatalError("Can't load VisionML model")
}
let classificationRequest = VNCoreMLRequest(model: visionModel, completionHandler: handleClassifications)
classificationRequest.imageCropAndScaleOption = VNImageCropAndScaleOption.centerCrop
self.requests = [classificationRequest]
}

O método abaixo deve ser implementado para colher os resultados da saída do modelo VNCoreMLModel e exibir na tela:

func handleClassifications(request: VNRequest, error: Error?) {
guard let observations = request.results
else { print("no results: \(error!)"); return }
print(observations)
let classifications = observations[0...4]
.flatMap({ $0 as? VNClassificationObservation })
.filter({ $0.confidence > 0.3 })
.sorted(by: { $0.confidence > $1.confidence })
.map {
(prediction: VNClassificationObservation) -> String in
return "\(round(prediction.confidence * 100 * 100)/100)%: \(prediction.identifier)"
}
DispatchQueue.main.async {
print(classifications.joined(separator: "###"))
self.uiRecognitionLabel?.text = classifications.joined(separator: "\n")
}
}

Mas aí você deve estar se perguntando…esse modelo pode classificar algo errado? O que acontece nesse caso? Nada. Esses modelos .coreml implementados nos apps são modelos estáticos e seria muito custoso (processamento, bateria) para o aplicativo retreinar o modelo durante seu uso. Mas temos uma forma de contornar esse problema. Podemos colher novas amostras a partir do aplicativo, enviar para um backend e permitir que o backend gere um modelo re-treinado utilizando as novas amostras. Esse modelo então pode ser baixado no celular e recompilado em tempo de execução no aplicativo. Só devemos tomar cuidado porque os modelos gerados geralmente são grandes e pode ser custoso para o usuário baixar um modelo grande na internet movel.

Extras

Por: Eduardo Lombardi
 https://medium.com/@eduardolomb

Source: Artificial Intelligence on Medium