Slide 1

Slide 1 text

Android Training Program PORTUGAL Aula #10 TensorFlow Lite no Android

Slide 2

Slide 2 text

● Sejam excelentes uns para os outros ● Fale mais alto se vir ou ouvir alguma coisa ● O assédio não é tolerado ● Pratique "Sim e" um ao outro Código de conduta Mais informações: http://bit.ly/2IhF0l3

Slide 3

Slide 3 text

Andres-Leonardo Martinez-Ortiz Google Carlos Mota Formador Renato Almeida Formador @davilagrau @cafonsomota @tallnato Equipa Daniela Ferreira Gestora de comunidades

Slide 4

Slide 4 text

● 12 aulas ● 1h30 cada aula ● ~1 aula por semana ● 14 Outubro a 16 Dezembro ● YouTube live ● Suporte assíncrono contínuo via Discord/email ● Todo o código disponível no GitHub Photo by Arif Riyanto on Unspla O programa

Slide 5

Slide 5 text

#0 14 de Outubro Pronto para começar #1 21 de Outubro Bem-vindos ao Android #2 28 de Outubro Fundações I #3 04 de Novembro Fundações II #4 11 de Novembro Fundações III #5 18 de Novembro Listas, listas e mais listas #6 25 de Novembro Jetpack, Jetpack, Jetpack! #7 - #8 02 - 03 de Dezembro Firebase #9 - #10 09 - 10 de Dezembro MLKit & TensorFlow #11 16 de Dezembro Resumo Semana Semana Calendário ✅ ✅ ✅ ✅ Direto ✅ ✅ ✅ ✅

Slide 6

Slide 6 text

Sumário Photo by Mika Baumeister on Unsplash ● Resumo da aula anterior ● TensorFlow Lite ● Kotlin para principiantes ● É Natal

Slide 7

Slide 7 text

http://events.withgoogle.com/atp2020 ✉ [email protected] http://bit.ly/atp2020-youtube http://bit.ly/atp2020-discord Links

Slide 8

Slide 8 text

http://bit.ly/atp2020-live

Slide 9

Slide 9 text

http://bit.ly/atp2020-codelabs

Slide 10

Slide 10 text

http://bit.ly/kahoot-aula10

Slide 11

Slide 11 text

Resumo da Aula #9

Slide 12

Slide 12 text

● Pode ser visto como uma forma de ajudar o software a realizar uma tarefa sem programar explicitamente ou criar regras ● Na programação tradicional, um programador especifica as regras que o computador deve usar ● Focado mais em análise de dados do que em programação ● São disponibilizados um conjunto de exemplos e o computador aprende a partir destes dados ● Podemos ver o machine learning como “programar com dados” Machine learning

Slide 13

Slide 13 text

https://about.google/intl/ALL_us/stories/seeingpotential/

Slide 14

Slide 14 text

Navegação com uma conta registada

Slide 15

Slide 15 text

https://about.google/intl/ALL_us/stories/save-the-bees/

Slide 16

Slide 16 text

● O ML Kit leva a experiência em machine learning até aos dispositivos móveis ● É uma biblioteca poderosa e fácil de utilizar ● Permite que as aplicações Android/iOS ○ Sejam personalizadas com base nas interações dos utilizadores ○ Ao mesmo tempo, está otimizada para correr nestes dispositivos ● Totalmente gratuito Machine learning para dispositivos móveis

Slide 17

Slide 17 text

● Identificar e processar códigos de barras ● Suporta a maioria dos formatos de 1D e 2D disponíveis Detectar códigos de barras Visão

Slide 18

Slide 18 text

● Detetar rostos ● Identificar características faciais ● Obter os contornos dos rostos Deteção de caras Visão

Slide 19

Slide 19 text

● Detetar e extrair informações dos objetos ● Identifica objetos, locais, espécies de animais, produtos, entre outros ● Consegue identificar cerca de 400 entidades diferentes Classificação de imagens Visão

Slide 20

Slide 20 text

● Localizar e seguir até 5 objetos diretamente da câmera ou de uma imagem, fornecendo a sua posição e um ID que permite identificar esse objeto num vídeo ● Permite personalizar a classificação de objetos com modelos do TensorFlow Lite Detectar e seguir objetos Visão

Slide 21

Slide 21 text

● Reconhecimento e extração de texto de imagens ● Facilita a deteção de cartões de crédito, recibos ou cartões de visita Reconhecimento de texto Visão

Slide 22

Slide 22 text

● Reconhece texto manuscrito e formas desenhadas à mão numa superfície digital ● Usa a mesma tecnologia utilizada no teclado GBoard e Google tradutor para deteção de escrita manual Reconhecimento de escrita Visão

Slide 23

Slide 23 text

● Permite detetar a posição do corpo humano em tempo real de um vídeo ou de uma imagem estática ● Detecta partes do corpo humano tais como ombros e cintura Deteção de poses Visão

Slide 24

Slide 24 text

● Permite detetar o idioma apenas com algumas palavras ● Consegue identificar mais de 100 idiomas diferentes Identificação do idioma Linguagem natural

Slide 25

Slide 25 text

● Permite traduzir entre 58 idiomas, tudo no dispositivo, mas apenas para traduções simples ● Permite transferir outros idiomas (30MB cada) Tradução no dispositivo Linguagem natural

Slide 26

Slide 26 text

● Gera sugestões relevantes de respostas em conversas de texto ● Utiliza o contexto de toda a conversa para dar sugestões ● Tudo no dispositivo, sem necessitar de enviar as conversas para o servidor ● Apenas funciona em Inglês Sugestões de respostas Linguagem natural

Slide 27

Slide 27 text

Aula #10

Slide 28

Slide 28 text

TensorFlow

Slide 29

Slide 29 text

● É uma biblioteca de código aberto, desenvolvida pela Google ● Oferece API’s que facilitam a implementação de machine learning ● Tem um tempo de compilação inferior comparando com outras bibliotecas ● Permite fazer o processamento tanto no CPU e GPU ● Tem ganho bastante relevo na área ● Permite que qualquer pessoa, com ou sem experiência em machine learning, possa construir e utilizar os modelos de machine learning O que é o TensorFlow?

Slide 30

Slide 30 text

TensorFlow Lite

Slide 31

Slide 31 text

● Latência muito mais reduzida ○ Uma vez que corre tudo localmente ● Funciona offline ● Os dados nunca saem do dispositivo ○ Ideal para o caso destes serem sensíveis ● Mais eficiente ○ Não é necessário estar a enviar/ receber dados do servidor ● Todos os sensores já se encontram disponíveis nos telemóveis atuais Porquê correr nos telemóveis?

Slide 32

Slide 32 text

● Recursos limitados ○ Não é possível modificar o hardware dos telemóveis… ○ … a não ser comprando um novo ● Outras aplicações também se encontram a competir por recursos ● Limites de memória ● Tem de utilizar pouca energia de forma a poupar as baterias ● Baixo poder computacional Dificuldades

Slide 33

Slide 33 text

Mas o TensorFlow foi inicial desenvolvido para ser utilizado em servidores....

Slide 34

Slide 34 text

● O TensorFlow Lite é uma versão do TensorFlow mais leve, desenvolvida especificamente para dispositivos móveis ou dispositivos embutidos ● Tipicamente têm menos capacidade de processamento e armazenamento ● O TensorFlow Lite permite que o processamento seja feito no dispositivo, evitando o envio dos dados para o servidor para posterior análise ● Disponível para Android, iOS e Linux O que é o TensorFlow Lite?

Slide 35

Slide 35 text

● Um modelo de TensorFlow é uma estrutura de dados que contém a lógica e conhecimento de uma rede de machine learning treinada para resolver uma problema específico ● Para utilizar um modelo no TensorFlow Lite é primeiro preciso converter um treinado previamente no formato do TensorFlow. Escolher um modelo Como funciona?

Slide 36

Slide 36 text

● Para utilizar um modelo TensorFlow no TensorFlow Lite é necessário converter o modelo ● A conversão do modelo reduz o tamanho do ficheiro e introduz o otimizações que não afectam a precisão Converter Como funciona?

Slide 37

Slide 37 text

● Pegar no ficheiro .tflite comprimido e adicionar à aplicação ● Correr os dados no modelo para obter as previsões Lançar Como funciona?

Slide 38

Slide 38 text

● O TF Lite tem ferramentas para otimizar o tamanho e performance dos modelos, com impacto mínimo na precisão. ● Modelos otimizados podem precisar de um treino, conversão ou integração mais complexos ● O objetivo, é chegar a um equilíbrio ideal de desempenho, tamanho do modelo e precisão para um determinado dispositivo Otimizar Como funciona?

Slide 39

Slide 39 text

Resumo Como funciona? Treinado Modelo de TensorFlow Convertido (para o formato do TensorFlow lite) Android App (Java/C++ API) iOS App (C++ API) Linux (ex. Pi) (Python/Java/C++ API)

Slide 40

Slide 40 text

E se o nosso modelo alterar?

Slide 41

Slide 41 text

Lançar uma versão nova da aplicação?

Slide 42

Slide 42 text

Lançar uma versão nova da aplicação? meh

Slide 43

Slide 43 text

E se existir uma forma melhor?

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

https://firebase.google.com/products/ml

Slide 46

Slide 46 text

● O Firebase ML permite guardar o nosso modelo num servidor, e depois distribuir pelos utilizadores ● Permite reduzir o tamanho do APK, sendo que a transferência do modelo é feito posteriormente ● Permite ainda realizar testes A/B, para medir a performance e valor dos diferentes modelos ● Permite atualizar o modelo sem ter que lançar uma aplicação nova Firebase ML

Slide 47

Slide 47 text

dependencies { implementation platform('com.google.firebase:firebase-bom:26.1.0') implementation 'com.google.firebase:firebase-ml-model-interpreter' } Como utilizar? Importar a biblioteca app/build.gradle

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

val remoteModel = FirebaseCustomRemoteModel.Builder("dogs").build() val conditions = FirebaseModelDownloadConditions.Builder() .requireWifi() .build() FirebaseModelManager.getInstance().download(remoteModel, conditions) .addOnCompleteListener { // Usar o modelo } Como utilizar? Transferir o modelo

Slide 50

Slide 50 text

val remoteModel = FirebaseCustomRemoteModel.Builder("dogs").build() val conditions = FirebaseModelDownloadConditions.Builder() .requireWifi() .build() FirebaseModelManager.getInstance().download(remoteModel, conditions) .addOnCompleteListener { // Usar o modelo } Como utilizar? Transferir o modelo

Slide 51

Slide 51 text

val remoteModel = FirebaseCustomRemoteModel.Builder("dogs").build() val conditions = FirebaseModelDownloadConditions.Builder() .requireWifi() .build() FirebaseModelManager.getInstance().download(remoteModel, conditions) .addOnCompleteListener { // Usar o modelo } Como utilizar? Transferir o modelo

Slide 52

Slide 52 text

val remoteModel = FirebaseCustomRemoteModel.Builder("dogs").build() val conditions = FirebaseModelDownloadConditions.Builder() .requireWifi() .build() FirebaseModelManager.getInstance().download(remoteModel, conditions) .addOnCompleteListener { // Usar o modelo } Como utilizar? Transferir o modelo

Slide 53

Slide 53 text

Fabiana Clemente Federated Learning e casos de uso Chief Data Officer @YData @fab_clemente

Slide 54

Slide 54 text

Exemplos

Slide 55

Slide 55 text

● Solução que permite reconhecer a partir de um modelo pré-treinado, 1000 tipos de itens diferentes diretamente da câmera de um dispositivo móvel ● Curiosidade: ○ Exemplo disponível para Raspberry Pi Classificação de imagens https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/android

Slide 56

Slide 56 text

● Utilizando um modelo pré-treinado, permite desenhar um retângulo com a respectiva descrição de mais de 1000 objetos Deteção de objectos https://github.com/tensorflow/examples/blob/master/lite/examples/object_detection/android/

Slide 57

Slide 57 text

● Este exemplo deteta continuamente as partes do corpo que estão visíveis pela câmera do dispositivo Deteção de pose https://github.com/tensorflow/examples/blob/master/lite/examples/posenet/android/

Slide 58

Slide 58 text

● A segmentação de uma imagem é o processo de dividir a imagem em vários segmentos ● O objetivo é simplificar a representação da imagem para algo com mais significado e fácil de analisar Segmentação https://github.com/tensorflow/examples/tree/master/lite/examples/image_segmentation/android

Slide 59

Slide 59 text

● É uma técnica que permite pegar no estilo de uma imagem e aplicar a outra Transferência de estilo https://github.com/tensorflow/examples/tree/master/lite/examples/style_transfer/android

Slide 60

Slide 60 text

Transferência de estilo

Slide 61

Slide 61 text

● BERT ○ Bidirectional Encoder Representations from Transformers ● Permite utilizar um modelo pré-treinado para responder a questões baseadas num excerto de texto BERT - Questões e respostas https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/android

Slide 62

Slide 62 text

● Recomendações personalidades são usadas numa variedade de casos, como sugestão de uma produto, sugestão de próximo vídeo a ver, ou aplicação a abrir ● As recomendações são baseados nas opções feitas pelo utilizador Recomendações https://github.com/tensorflow/examples/tree/master/lite/examples/recommendation/android

Slide 63

Slide 63 text

https://www.tensorflow.org/lite/examples

Slide 64

Slide 64 text

Demos

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

https://teachablemachine.withgoogle.com/

Slide 67

Slide 67 text

https://emojiscavengerhunt.withgoogle.com/

Slide 68

Slide 68 text

https://magenta.tensorflow.org/demos/

Slide 69

Slide 69 text

https://experiments.withgoogle.com/search?q=tensorflow

Slide 70

Slide 70 text

https://deepdreamgenerator.com/

Slide 71

Slide 71 text

Casos de estudo

Slide 72

Slide 72 text

● Utiliza o TensorFlow de forma a melhorar a experiência dos hóspedes. ● Através do Machine Learning conseguiram categorizar as imagens das casas permitindo agrupar e identificar as várias divisões da casa. ● Com isto também conseguiram validar as características das casas, e por exemplo, validar o número de quartos https://medium.com/airbnb-engineering/categorizing-listing-photos-at-airbnb-f9483f3ab7e3 Airbnb Casos de estudo

Slide 73

Slide 73 text

● Com a API de detecção de objetos, conseguiram rapidamente detetar objetos e outras propriedades que constituem uma casa, através da análise das imagens ● Isto permite fornecer ao hóspede a hipótese de escolher a casa em função das características pretendidas https://medium.com/airbnb-engineering/categorizing-listing-photos-at-airbnb-f9483f3ab7e3 Airbnb Casos de estudo

Slide 74

Slide 74 text

● A Coca-Cola utilizou machine learning para detetar os códigos das tampas das garrafas em dispositivos móveis ● Os OCR’s convencionais não eram suficientemente eficazes a ler códigos, que por vezes até eram difíceis de ler com o olho humano https://developers.googleblog.com/2017/09/how-machine-learning-with-tensorflow.html Coca-Cola Casos de estudo

Slide 75

Slide 75 text

● O PayPal utilizar TensorFlow para estar sempre na vanguarda no que diz respeito à deteção de fraudes ● Usando TensorFlow, deep transfer learning e generative modeling, o PayPal foi capaz de reconhecer cada vez com mais precisão possíveis fraudes enquanto que ao mesmo tempo melhora a experiência de utilização aos clientes legítimos https://medium.com/paypal-engineering PayPal Casos de estudo

Slide 76

Slide 76 text

https://blog.tensorflow.org/2019/03/ranking-tweets-with-tensorflow.html Twitter Testemunhos ● O Twitter usa machine learning para melhorar a feed dos utilizadores ● Usando várias variáveis, como quando foi feito o Tweet, o número de Retweets ou likes, interações passadas entres os utilizadores, entre outras coisas ● Permite que seja feita uma ordenação dos Tweets em função das preferências do utilizador

Slide 77

Slide 77 text

TenserFlow Hub

Slide 78

Slide 78 text

https://www.tensorflow.org/hub

Slide 79

Slide 79 text

TensorFlow Hub ● O TensorFlow Hub é um repositório de modelos de machine learning já treinados, prontos a serem utilizados e lançados em qualquer plataforma ● Permite utilizar modelos já treinados, tais como o BERT, apenas com algumas linhas de código ● É aberto a contributos da comunidade

Slide 80

Slide 80 text

Abre o Android Studio e vamos começar a programar ‍‍

Slide 81

Slide 81 text

https://codelabs.developers.google.com/codelabs/recognize-flowers-with-tensorflow-on-android

Slide 82

Slide 82 text

http://vision.stanford.edu/aditya86/ImageNetDogs/

Slide 83

Slide 83 text

http://vision.stanford.edu/aditya86/ImageNetDogs/

Slide 84

Slide 84 text

VS Ronda 9

Slide 85

Slide 85 text

@Deprecated fun getBreedsList(): List { // Código } val breeds = getBreedsList() Deprecated @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList();

Slide 86

Slide 86 text

@Deprecated fun getBreedsList(): List { // Código } val breeds = getBreedsList() @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList(); getBreedsList() : List is deprecated. getBreedsList() : List is deprecated. Deprecated

Slide 87

Slide 87 text

@Deprecated( message = “Use getBreeds() instead”, replaceWith = ReplaceWith(“getBreeds()”) fun getBreedsList(): List { // Código } val breeds = getBreedsList() @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList(); Deprecated

Slide 88

Slide 88 text

@Deprecated( message = “Use getBreeds() instead”, replaceWith = ReplaceWith(“getBreeds()”) fun getBreedsList(): List { // Código } val breeds = getBreedsList() @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList(); getBreedsList() : List is deprecated. Replace with ‘getBreeds()’ Replace usages of ‘getBreedsList() on List’ in whole project Deprecated

Slide 89

Slide 89 text

@Deprecated( message = “Use getBreeds() instead”, replaceWith = ReplaceWith(“getBreeds()”) fun getBreedsList(): List { // Código } val breeds = getBreedsList() @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList(); getBreedsList() : List is deprecated. Replace with ‘getBreeds()’ Replace usages of ‘getBreedsList() on List’ in whole project alt + enter Deprecated

Slide 90

Slide 90 text

@Deprecated( message = “Use getBreeds() instead”, replaceWith = ReplaceWith(“getBreeds()”) fun getBreedsList(): List { // Código } val breeds = getBreeds() @Deprecated public List getBreedsList() { // Código } List breeds = getBreedsList(); getBreedsList() : List is deprecated. Deprecated

Slide 91

Slide 91 text

fun createDog(name: String, breed: String) {} createDog(“Fifi”, “Yorkshire Terrier”) public void createDog(String name, String breed) {} createDog(“Fifi”, “Yorkshire Terrier”) Constructor overloads

Slide 92

Slide 92 text

fun createDog(name: String = “unknown”, breed: String) {} createDog(“Fifi”, “Yorkshire Terrier”) createDog(breed = “Yorkshire Terrier”) public void createDog(String name, String breed) {} public void createDog(String breed) { String name = “unknown” } createDog(“Fifi”, “Yorkshire Terrier”) createDog(“Yorkshire Terrier”) Constructor overloads

Slide 93

Slide 93 text

fun createDog(name: String = “unknown”, breed: String = “unknown”) {} createDog(“Fifi”, “Yorkshire Terrier”) createDog(breed = “Yorkshire Terrier”) createDog() public void createDog(String name, String breed) {} public void createDog(String breed) { String name = “unknown” } public void createDog() { String name = “unknown” String breed = “unkown” } createDog(“Fifi”, “Yorkshire Terrier”) createDog(“Yorkshire Terrier”) createDog() Constructor overloads

Slide 94

Slide 94 text

fun createDog(name: String = “unknown”, breed: String = “unknown”) {} createDog(“Fifi”, “Yorkshire Terrier”) createDog(breed = “Yorkshire Terrier”) createDog() public void createDog(String name, String breed) {} public void createDog(String breed) { String name = “unknown” } public void createDog() { String name = “unknown” String breed = “unkown” } createDog(“Fifi”, “Yorkshire Terrier”) createDog(“Yorkshire Terrier”) createDog() Constructor overloads Kotlin, vem dar uma mão nas chamadas a partir de Java

Slide 95

Slide 95 text

@JvmOverloads fun createDog(name: String = “unknown”, breed: String = “unknown”) {} createDog(“Fifi”, “Yorkshire Terrier”) createDog(breed = “Yorkshire Terrier”) createDog() createDog(“Fifi”, “Yorkshire Terrier”) createDog(“Yorkshire Terrier”) createDog() @JvmOverloads

Slide 96

Slide 96 text

fun createDog(name: String = “unknown”, breed: String = “unknown”) { // Código } Chamar código escrito em Kotlin a partir de Java @JVMOverloads .decompiled.java

Slide 97

Slide 97 text

@JvmOverloads fun createDog(name: String = “unknown”, breed: String = “unknown”) { // Código } Chamar código escrito em Kotlin a partir de Java @JVMOverloads @JvmOverloads public createDog(String name, String breed) {} @JvmOverloads public createDog(String name) { createDog(name, “unknown”) } @JvmOverloads public createDog() { createDog(“unknown”, “unknown”) } .decompiled.java

Slide 98

Slide 98 text

fun deviceName() Chamar código escrito em Kotlin a partir de Java @file:JvmName ValuesKt.deviceName(); Values.kt

Slide 99

Slide 99 text

@file:JvmName(“Cat”) fun deviceName() Chamar código escrito em Kotlin a partir de Java @file:JvmName Cat.deviceName(); Values.kt

Slide 100

Slide 100 text

@file:JvmName(“Cat”) @file:JvmMultifileClass fun deviceName() Chamar código escrito em Kotlin a partir de Java @file:JvmMultifileClass @file:JvmName(“Cat”) @file:JvmMultifileClass fun hasBattery() Values.kt DeviceInfo.kt

Slide 101

Slide 101 text

class Values { companion object { fun dogs() {} } } Chamar código escrito em Kotlin a partir de Java @JvmStatic Valueskt.dogs() // Erro Values.dogs() // Erro Values.kt

Slide 102

Slide 102 text

class Values { companion object { @JvmStatic fun dogs() {} } } Chamar código escrito em Kotlin a partir de Java @JvmStatic Values.dogs() Values.kt

Slide 103

Slide 103 text

Natal Photo by Mel Poole Unsplash

Slide 104

Slide 104 text

Lottie Uma biblioteca para Android e iOS que permite utilizar as animações criadas com o Adobe After Effects (exportadas no formato JSON) nativamente no telemóvel. https://github.com/airbnb/lottie-android

Slide 105

Slide 105 text

AppIntro https://github.com/AppIntro/AppIntro Biblioteca Android que te permite construir muito facilmente um ecrã introdutório para a tua app. Tens ainda a possibilidade de integrar com o sistema de permissões nativo

Slide 106

Slide 106 text

Balloon https://github.com/skydoves/Balloon Uma biblioteca muito leve que permite criar popups muito facilmente, customizáveis e com diferentes animações.

Slide 107

Slide 107 text

RecyclerView animators https://github.com/wasabeef/recyclerview-animators Uma biblioteca de animações que podes utilizar nas RecyclerView’s da tua aplicação.

Slide 108

Slide 108 text

SmallBang ❤ https://github.com/hanks-zyh/SmallBang Animação de favoritos numa vista.

Slide 109

Slide 109 text

FABProgressCircle https://github.com/JorgeCastilloPrz/FABProgressCircle Animação de progresso em volta de um FloatingActionButton.

Slide 110

Slide 110 text

AnimatedBottomBar https://github.com/Droppers/AnimatedBottomBar Uma bottom bar customizável com diferentes tipos de animações.

Slide 111

Slide 111 text

Trabalho Para Casa ‍‍

Slide 112

Slide 112 text

Trabalho para casa ● Adicionar à nossa aplicação a opção de identificar a raça de um cão ○ Ou se quiserem, vários cães ao mesmo tempo 1 - Yorkshire Terrier 2 - Labrador Retriever 3 - Boxer

Slide 113

Slide 113 text

Dúvidas?

Slide 114

Slide 114 text

Continuamos a responder no discord

Slide 115

Slide 115 text

Obrigado ‍♀

Slide 116

Slide 116 text

Android Training Program PORTUGAL Aula #11 Resumo Próxima aula: 16 de Dezembro