From 352850828380e3e3368d1ddb5838ba0c1d1e00f6 Mon Sep 17 00:00:00 2001 From: ilyaspiridonov Date: Sat, 4 Nov 2023 14:58:36 +0300 Subject: [PATCH 1/5] PT-BR translations --- site/pt-br/community/contribute/code.md | 130 ++ site/pt-br/guide/core/mlp_core.ipynb | 1023 ++++++++++ site/pt-br/guide/saved_model.ipynb | 1020 ++++++++++ site/pt-br/guide/tpu.ipynb | 623 ++++++ site/pt-br/guide/versions.md | 202 ++ site/pt-br/lite/android/delegates/gpu.md | 212 ++ .../lite/android/delegates/gpu_native.md | 70 + site/pt-br/lite/android/delegates/gpu_task.md | 130 ++ site/pt-br/lite/android/delegates/hexagon.md | 237 +++ site/pt-br/lite/android/delegates/nnapi.md | 121 ++ site/pt-br/lite/android/play_services.md | 499 +++++ .../android/tutorials/audio_classification.md | 247 +++ .../android/tutorials/object_detection.md | 343 ++++ .../lite/android/tutorials/question_answer.md | 390 ++++ .../android/tutorials/text_classification.md | 331 ++++ site/pt-br/lite/guide/build_arm.md | 82 + site/pt-br/lite/guide/build_cmake.md | 242 +++ site/pt-br/lite/guide/build_cmake_arm.md | 153 ++ site/pt-br/lite/guide/build_cmake_pip.md | 73 + site/pt-br/lite/guide/build_ios.md | 147 ++ site/pt-br/lite/guide/faq.md | 77 + site/pt-br/lite/guide/inference.md | 517 +++++ site/pt-br/lite/guide/ios.md | 126 ++ site/pt-br/lite/guide/model_analyzer.ipynb | 257 +++ site/pt-br/lite/guide/op_select_allowlist.md | 888 +++++++++ site/pt-br/lite/guide/ops_compatibility.md | 82 + site/pt-br/lite/guide/ops_custom.md | 245 +++ site/pt-br/lite/guide/ops_select.md | 220 +++ site/pt-br/lite/guide/ops_version.md | 208 ++ site/pt-br/lite/guide/python.md | 79 + site/pt-br/lite/guide/reduce_binary_size.md | 379 ++++ site/pt-br/lite/guide/roadmap.md | 79 + site/pt-br/lite/guide/signatures.ipynb | 491 +++++ .../lite/inference_with_metadata/codegen.md | 214 ++ .../inference_with_metadata/lite_support.md | 238 +++ .../lite/inference_with_metadata/overview.md | 31 + .../task_library/audio_classifier.md | 281 +++ .../task_library/bert_nl_classifier.md | 151 ++ .../task_library/bert_question_answerer.md | 166 ++ .../task_library/customized_task_api.md | 360 ++++ .../task_library/image_classifier.md | 254 +++ .../task_library/image_embedder.md | 112 ++ .../task_library/image_searcher.md | 140 ++ .../task_library/image_segmenter.md | 251 +++ .../task_library/nl_classifier.md | 179 ++ .../task_library/object_detector.md | 267 +++ .../task_library/overview.md | 242 +++ .../task_library/text_embedder.md | 127 ++ .../task_library/text_searcher.md | 134 ++ site/pt-br/lite/ios/delegates/gpu.md | 303 +++ .../lite/microcontrollers/build_convert.md | 61 + .../microcontrollers/get_started_low_level.md | 268 +++ site/pt-br/lite/microcontrollers/library.md | 124 ++ site/pt-br/lite/models/convert/api_updates.md | 25 + .../lite/models/convert/convert_models.md | 168 ++ .../convert/metadata_writer_tutorial.ipynb | 885 +++++++++ .../lite/models/convert/operation_fusion.md | 256 +++ site/pt-br/lite/models/convert/rnn.md | 113 ++ .../model_maker/audio_classification.ipynb | 661 +++++++ .../model_maker/image_classification.ipynb | 969 +++++++++ .../modify/model_maker/object_detection.ipynb | 872 +++++++++ .../modify/model_maker/question_answer.ipynb | 653 +++++++ .../model_maker/speech_recognition.ipynb | 948 +++++++++ .../model_maker/text_classification.ipynb | 1062 ++++++++++ .../pt-br/lite/models/smart_reply/overview.md | 49 + site/pt-br/lite/performance/best_practices.md | 60 + .../pt-br/lite/performance/coreml_delegate.md | 275 +++ site/pt-br/lite/performance/delegates.md | 140 ++ site/pt-br/lite/performance/gpu.md | 139 ++ .../lite/performance/implementing_delegate.md | 506 +++++ site/pt-br/lite/performance/measurement.md | 473 +++++ .../lite/performance/model_optimization.md | 144 ++ .../post_training_float16_quant.ipynb | 575 ++++++ .../post_training_integer_quant.ipynb | 735 +++++++ .../post_training_integer_quant_16x8.ipynb | 626 ++++++ .../performance/post_training_quant.ipynb | 586 ++++++ .../performance/post_training_quantization.md | 213 ++ .../performance/quantization_debugger.ipynb | 833 ++++++++ .../lite/performance/quantization_spec.md | 500 +++++ .../lite/tutorials/pose_classification.ipynb | 1413 ++++++++++++++ site/pt-br/mlir/dialects.md | 19 + site/pt-br/mlir/tf_passes.md | 7 + site/pt-br/tfx/api_overview.md | 35 + site/pt-br/tfx/guide/airflow.md | 7 + site/pt-br/tfx/guide/beam.md | 92 + site/pt-br/tfx/guide/build_local_pipeline.md | 278 +++ site/pt-br/tfx/guide/build_tfx_pipeline.md | 55 + site/pt-br/tfx/guide/bulkinferrer.md | 33 + site/pt-br/tfx/guide/cli.md | 1051 ++++++++++ site/pt-br/tfx/guide/container_component.md | 74 + site/pt-br/tfx/guide/custom_component.md | 141 ++ .../tfx/guide/custom_function_component.md | 114 ++ site/pt-br/tfx/guide/custom_orchestrator.md | 34 + site/pt-br/tfx/guide/evaluator.md | 116 ++ site/pt-br/tfx/guide/examplegen.md | 504 +++++ site/pt-br/tfx/guide/exampleval.md | 30 + site/pt-br/tfx/guide/fairness_indicators.md | 247 +++ site/pt-br/tfx/guide/infra_validator.md | 174 ++ site/pt-br/tfx/guide/keras.md | 239 +++ site/pt-br/tfx/guide/kubeflow.md | 7 + site/pt-br/tfx/guide/local_orchestrator.md | 7 + site/pt-br/tfx/guide/mlmd.md | 339 ++++ site/pt-br/tfx/guide/modelval.md | 74 + site/pt-br/tfx/guide/non_tf.md | 24 + site/pt-br/tfx/guide/pusher.md | 47 + site/pt-br/tfx/guide/schemagen.md | 77 + site/pt-br/tfx/guide/serving.md | 11 + site/pt-br/tfx/guide/solutions.md | 41 + site/pt-br/tfx/guide/statsgen.md | 51 + site/pt-br/tfx/guide/tfdv.md | 193 ++ site/pt-br/tfx/guide/tfma.md | 22 + site/pt-br/tfx/guide/tft.md | 8 + site/pt-br/tfx/guide/train.md | 27 + site/pt-br/tfx/guide/trainer.md | 74 + site/pt-br/tfx/guide/transform.md | 167 ++ .../tutorials/images/transfer_learning.ipynb | 639 +++--- .../integrated_gradients.ipynb | 168 +- site/pt-br/tutorials/load_data/csv.ipynb | 1730 ++++++++++++++--- .../video/video_classification.ipynb | 1107 +++++++++++ site/pt-br/xla/aliasing.md | 51 + site/pt-br/xla/architecture.md | 37 + site/pt-br/xla/broadcasting.md | 146 ++ site/pt-br/xla/code_reviews_guide.md | 52 + site/pt-br/xla/custom_call.md | 213 ++ site/pt-br/xla/developing_new_backend.md | 36 + site/pt-br/xla/known_issues.md | 49 + site/pt-br/xla/shapes.md | 102 + site/pt-br/xla/tfcompile.md | 218 +++ site/pt-br/xla/tiled_layout.md | 55 + .../xla/tutorials/autoclustering_xla.ipynb | 276 +++ site/pt-br/xla/tutorials/compile.ipynb | 283 +++ 131 files changed, 36702 insertions(+), 584 deletions(-) create mode 100644 site/pt-br/community/contribute/code.md create mode 100644 site/pt-br/guide/core/mlp_core.ipynb create mode 100644 site/pt-br/guide/saved_model.ipynb create mode 100644 site/pt-br/guide/tpu.ipynb create mode 100644 site/pt-br/guide/versions.md create mode 100644 site/pt-br/lite/android/delegates/gpu.md create mode 100644 site/pt-br/lite/android/delegates/gpu_native.md create mode 100644 site/pt-br/lite/android/delegates/gpu_task.md create mode 100644 site/pt-br/lite/android/delegates/hexagon.md create mode 100644 site/pt-br/lite/android/delegates/nnapi.md create mode 100644 site/pt-br/lite/android/play_services.md create mode 100644 site/pt-br/lite/android/tutorials/audio_classification.md create mode 100644 site/pt-br/lite/android/tutorials/object_detection.md create mode 100644 site/pt-br/lite/android/tutorials/question_answer.md create mode 100644 site/pt-br/lite/android/tutorials/text_classification.md create mode 100644 site/pt-br/lite/guide/build_arm.md create mode 100644 site/pt-br/lite/guide/build_cmake.md create mode 100644 site/pt-br/lite/guide/build_cmake_arm.md create mode 100644 site/pt-br/lite/guide/build_cmake_pip.md create mode 100644 site/pt-br/lite/guide/build_ios.md create mode 100644 site/pt-br/lite/guide/faq.md create mode 100644 site/pt-br/lite/guide/inference.md create mode 100644 site/pt-br/lite/guide/ios.md create mode 100644 site/pt-br/lite/guide/model_analyzer.ipynb create mode 100644 site/pt-br/lite/guide/op_select_allowlist.md create mode 100644 site/pt-br/lite/guide/ops_compatibility.md create mode 100644 site/pt-br/lite/guide/ops_custom.md create mode 100644 site/pt-br/lite/guide/ops_select.md create mode 100644 site/pt-br/lite/guide/ops_version.md create mode 100644 site/pt-br/lite/guide/python.md create mode 100644 site/pt-br/lite/guide/reduce_binary_size.md create mode 100644 site/pt-br/lite/guide/roadmap.md create mode 100644 site/pt-br/lite/guide/signatures.ipynb create mode 100644 site/pt-br/lite/inference_with_metadata/codegen.md create mode 100644 site/pt-br/lite/inference_with_metadata/lite_support.md create mode 100644 site/pt-br/lite/inference_with_metadata/overview.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/audio_classifier.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/bert_nl_classifier.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/bert_question_answerer.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/customized_task_api.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/image_classifier.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/image_embedder.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/image_searcher.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/image_segmenter.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/nl_classifier.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/object_detector.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/overview.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/text_embedder.md create mode 100644 site/pt-br/lite/inference_with_metadata/task_library/text_searcher.md create mode 100644 site/pt-br/lite/ios/delegates/gpu.md create mode 100644 site/pt-br/lite/microcontrollers/build_convert.md create mode 100644 site/pt-br/lite/microcontrollers/get_started_low_level.md create mode 100644 site/pt-br/lite/microcontrollers/library.md create mode 100644 site/pt-br/lite/models/convert/api_updates.md create mode 100644 site/pt-br/lite/models/convert/convert_models.md create mode 100644 site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb create mode 100644 site/pt-br/lite/models/convert/operation_fusion.md create mode 100644 site/pt-br/lite/models/convert/rnn.md create mode 100644 site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb create mode 100644 site/pt-br/lite/models/modify/model_maker/image_classification.ipynb create mode 100644 site/pt-br/lite/models/modify/model_maker/object_detection.ipynb create mode 100644 site/pt-br/lite/models/modify/model_maker/question_answer.ipynb create mode 100644 site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb create mode 100644 site/pt-br/lite/models/modify/model_maker/text_classification.ipynb create mode 100644 site/pt-br/lite/models/smart_reply/overview.md create mode 100644 site/pt-br/lite/performance/best_practices.md create mode 100644 site/pt-br/lite/performance/coreml_delegate.md create mode 100644 site/pt-br/lite/performance/delegates.md create mode 100644 site/pt-br/lite/performance/gpu.md create mode 100644 site/pt-br/lite/performance/implementing_delegate.md create mode 100644 site/pt-br/lite/performance/measurement.md create mode 100644 site/pt-br/lite/performance/model_optimization.md create mode 100644 site/pt-br/lite/performance/post_training_float16_quant.ipynb create mode 100644 site/pt-br/lite/performance/post_training_integer_quant.ipynb create mode 100644 site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb create mode 100644 site/pt-br/lite/performance/post_training_quant.ipynb create mode 100644 site/pt-br/lite/performance/post_training_quantization.md create mode 100644 site/pt-br/lite/performance/quantization_debugger.ipynb create mode 100644 site/pt-br/lite/performance/quantization_spec.md create mode 100644 site/pt-br/lite/tutorials/pose_classification.ipynb create mode 100644 site/pt-br/mlir/dialects.md create mode 100644 site/pt-br/mlir/tf_passes.md create mode 100644 site/pt-br/tfx/api_overview.md create mode 100644 site/pt-br/tfx/guide/airflow.md create mode 100644 site/pt-br/tfx/guide/beam.md create mode 100644 site/pt-br/tfx/guide/build_local_pipeline.md create mode 100644 site/pt-br/tfx/guide/build_tfx_pipeline.md create mode 100644 site/pt-br/tfx/guide/bulkinferrer.md create mode 100644 site/pt-br/tfx/guide/cli.md create mode 100644 site/pt-br/tfx/guide/container_component.md create mode 100644 site/pt-br/tfx/guide/custom_component.md create mode 100644 site/pt-br/tfx/guide/custom_function_component.md create mode 100644 site/pt-br/tfx/guide/custom_orchestrator.md create mode 100644 site/pt-br/tfx/guide/evaluator.md create mode 100644 site/pt-br/tfx/guide/examplegen.md create mode 100644 site/pt-br/tfx/guide/exampleval.md create mode 100644 site/pt-br/tfx/guide/fairness_indicators.md create mode 100644 site/pt-br/tfx/guide/infra_validator.md create mode 100644 site/pt-br/tfx/guide/keras.md create mode 100644 site/pt-br/tfx/guide/kubeflow.md create mode 100644 site/pt-br/tfx/guide/local_orchestrator.md create mode 100644 site/pt-br/tfx/guide/mlmd.md create mode 100644 site/pt-br/tfx/guide/modelval.md create mode 100644 site/pt-br/tfx/guide/non_tf.md create mode 100644 site/pt-br/tfx/guide/pusher.md create mode 100644 site/pt-br/tfx/guide/schemagen.md create mode 100644 site/pt-br/tfx/guide/serving.md create mode 100644 site/pt-br/tfx/guide/solutions.md create mode 100644 site/pt-br/tfx/guide/statsgen.md create mode 100644 site/pt-br/tfx/guide/tfdv.md create mode 100644 site/pt-br/tfx/guide/tfma.md create mode 100644 site/pt-br/tfx/guide/tft.md create mode 100644 site/pt-br/tfx/guide/train.md create mode 100644 site/pt-br/tfx/guide/trainer.md create mode 100644 site/pt-br/tfx/guide/transform.md create mode 100644 site/pt-br/tutorials/video/video_classification.ipynb create mode 100644 site/pt-br/xla/aliasing.md create mode 100644 site/pt-br/xla/architecture.md create mode 100644 site/pt-br/xla/broadcasting.md create mode 100644 site/pt-br/xla/code_reviews_guide.md create mode 100644 site/pt-br/xla/custom_call.md create mode 100644 site/pt-br/xla/developing_new_backend.md create mode 100644 site/pt-br/xla/known_issues.md create mode 100644 site/pt-br/xla/shapes.md create mode 100644 site/pt-br/xla/tfcompile.md create mode 100644 site/pt-br/xla/tiled_layout.md create mode 100644 site/pt-br/xla/tutorials/autoclustering_xla.ipynb create mode 100644 site/pt-br/xla/tutorials/compile.ipynb diff --git a/site/pt-br/community/contribute/code.md b/site/pt-br/community/contribute/code.md new file mode 100644 index 0000000000..1b582f8af7 --- /dev/null +++ b/site/pt-br/community/contribute/code.md @@ -0,0 +1,130 @@ +# Contribuir para o código do TensorFlow + +Esteja você adicionando uma função de perda, melhorando a cobertura de teste, ou escrevendo um RFC para uma grande mudança de design, essa parte do guia do contribuidor o ajudará a começar. Obrigado pelo seu trabalho e interece em melhorar o TensorFlow. + +## Antes de começar + +Antes de contribuir ao codigo fonte de um projeto TensorFlow, por favor revise o arquivo `CONTRIBUTING.md` no repositório GitHub do projeto. Por exemplo, veja o arquivo [CONTRIBUTING.md](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md) no núcleo do repositório TensorFlow. Todos os contribuidores de código precisam assinar um [Contributor License Agreement](https://cla.developers.google.com/clas) (CLA). + +Para evitar trabalho duplicado, por vafor revise [current](https://github.com/tensorflow/community/tree/master/rfcs) ou [proposed](https://github.com/tensorflow/community/labels/RFC%3A%20Proposed) RFCs e contacte os desenvolvedores nos fóruns do TensorFlow ([developers@tensorflow.org](https://groups.google.com/u/1/a/tensorflow.org/g/developers)) antes de você começar a trabalhar em uma feature não trivial. Nós somos um pouco seletivos ao decidir adicionar novas funcionalidades, e a melhor maneira de contribuir e ajudar o projeto é trabalhar em problemas conhecidos. + +## Issues para novos contribuidores + +Novos contribuidores deveriam buscar as seguintes tags ao procurar por uma primeira contribuição a base de código do TensorFlow. Nós fortemente recomendamos que novos contribuidores abordem projetos “good first issue” e "contributions welcome" primeiro; isso ajuda o contribuidor a se familiarizar com o fluxo de contribuição, e para o núcleo de desenvolvedores conhecer o contribuidor. + +- [good first issue](https://github.com/tensorflow/tensorflow/labels/good%20first%20issue) +- [contributions welcome](https://github.com/tensorflow/tensorflow/labels/stat%3Acontributions%20welcome) + +se você está interessado em recrutar um time para abordar um problema de larga escala ou uma nova feature, por favor email o [developers@ group](https://groups.google.com/a/tensorflow.org/g/developers) e revise nossa atual lista de RFCs. + +## Revisão de código + +Novas features, correção de bugs, e quaisquer outras alterações a base de código são sujeitas a revisão de código. + +Revisão de código contribuido a projetos como pull request é um componente crucial para o desenvolvimento do TensorFlow. Nós encorajamos qualquer um a começar a revisar código submetido por outros desenvolvedores, especialmente se a feature é algo que você provavelmente vá usar. + +Aqui estão algumas perguntas a serem lembradas durante o processo de revisão de código: + +- *Queremos isso no TensorFlow?* É provável que seja usado? Você, como usuário do TensorFlow, gosta da mudança e pretende usá-la? Essa mudança está no escopo do TensorFlow? O custo de manutenção de um novo recurso valerá seus benefícios? + +- *O código é concistente com a API do TensorFlow?* São funções públicas, classes e parâmetros bem nomeados e projetados intuitivamente? + +- *Inclui documentação?* Todas as funções públicas, classes, parâmetros, tipos de retorno e atributos armazenados são nomeados de acordo com as convenções do TensorFlow e claramente documentados? A nova funcionalidade é descrita na documentação do TensorFlow e ilustrada com exemplos, sempre que possível? A documentação é renderizada corretamente? + +- *O código é humanamente legível?* Possui pouca redundância? Os nomes das variáveis devem ser melhorados para maior clareza ou consistência? Comentários devem ser adicionados? Algum comentário deve ser removido como inútil ou irrelevante? + +- *O código é eficiente?* Poderia ser reescrito facilmente para ser executado com mais eficiência? + +- O código é *retrocompatível* com verções anteriores do TensorFlow? + +- O novo código adicionará *novas dependências* em outras bibliotecas? + +## Testar e melhorar cobertura de teste + +Testes de unidade de alta qualidade são a base do processo de desnvolvimento do TensoFlow. Para esse propósito, utilizamos imagens Docker. As funções de teste são nomeadas apropiadamente e são responsaveis por checar a validade dos algoritomos, assim como as diferentes opções de código. + +Todos os novos recursos e correções de bugs *devem* incluir cobertura de teste adequada. Também recebemos contribuições de novos casos de teste ou melhorias nos testes existentes. Se você descobrir que nossos testes existentes não estão completos - mesmo que isso não esteja causando um bug no momento - registre um problema e, se possível, uma solicitação pull. + +Para obter os detalhes específicos dos procedimentos de teste em cada projeto do TensorFlow, consulte os arquivos `README.md` e `CONTRIBUTING.md` no repositório do projeto no GitHub. + +De preocupações particulares em *testes adequados* : + +- São, *todas as funções e classes públicas* testadas? +- Há um *conjunto razoável de parâmetros*, seus valores, tipos e combinações testados? +- Os testes validam que o *código está correto* e que está *fazendo o que a documentação diz que* o código deveria fazer? +- Se a alteração for uma correção de bug, um *teste de não regressão* está incluído? +- Os testes *passam na build de integração contínua*? +- Os testes *cobrem todas as linhas de código?* Se não, as exceções são razoáveis e explícitas? + +Se você encontrar algum problema, considere ajudar o colaborador a entender esses problemas e resolvê-los. + +## Melhorar mensagens de erro ou logs + +Contribuições que melhoram mensagens de erro e registro são bem vindas. + +## Fluxo de trabalho de contribuição + +Contribuições de código—correções de bugs, novos desenvolvimentos, melhorias de teste—seguem um fluxo de trabalho centrado no GitHub. Para participar do desenvolvimento do TensorFlow, configure uma conta do GitHub. Então: + +1. Faça um Fork do repositório no qual planeja trabalhar. Vá para a página do repositório do projeto e use o botão *Fork* . Isso criará uma cópia do repositório, sob seu nome de usuário. (Para obter mais detalhes sobre como fazer um branch de um repositório, consulte [este guia](https://help.github.com/articles/fork-a-repo/) .) + +2. Clone o repositório para o seu sistema local. + + `$ git clone git@github.com:your-user-name/project-name.git` + +3. Crie uma nova branch para armazenar seu trabalho. + + `$ git checkout -b new-branch-name` + +4. Trabalhe em seu novo código. Escreva e execute testes. + +5. Confirme suas alterações. + + `$ git add -A` + + `$ git commit -m "commit message here"` + +6. Envie suas alterações para o repositório do GitHub. + + `$ git push origin branch-name` + +7. Abra um *Pull Request*(PR). Acesse o repositório do projeto original no GitHub. Haverá uma mensagem sobre seu branch enviado recentemente, perguntando se você gostaria de abrir um Pull Request. Siga os prompts, *compare os repositórios* e envie o PR. Isso enviará um email para os committers. Você pode querer considerar o envio de um email para a lista de discussão para obter mais visibilidade. (Para mais detalhes, consulte o [guia do GitHub sobre PRs](https://help.github.com/articles/creating-a-pull-request-from-a-fork) . + +8. Os mantenedores e outros contribuidores *revisarão seu PR*. Participe da conversa e tente *fazer as alterações solicitadas*. Assim que o PR for aprovado, o código será merged. + +*Antes de trabalhar em sua próxima contribuição* , certifique-se de que seu repositório local esteja atualizado. + +1. Defina o upstream remote. (Você só precisa fazer isso uma vez por projeto, não sempre.) + + `$ git remote add upstream git@github.com:tensorflow/project-repo-name` + +2. Alterne para a branch master local. + + `$ git checkout master` + +3. Pull down as alterações do upstream. + + `$ git pull upstream master` + +4. Envie as alterações para sua conta do GitHub. (Opcional, mas uma boa prática.) + + `$ git push origin master` + +5. Crie uma nova branch se estiver iniciando um novo trabalho. + + `$ git checkout -b branch-name` + +Recursos adicionais do `git` e do GitHub: + +- [Documentação Git](https://git-scm.com/documentation) +- [Fluxo de desenvolvimento do Git](https://docs.scipy.org/doc/numpy/dev/development_workflow.html) +- [Resolução de conflitos de merge](https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/) . + +## Checklist do colaborador + +- Leia as [diretrizes de contribuição](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md) . +- Leia o [Código de Conduta](https://github.com/tensorflow/tensorflow/blob/master/CODE_OF_CONDUCT.md) . +- Certifique-se de ter assinado o [Contrato de licença do colaborador (CLA)](https://cla.developers.google.com/) . +- Verifique se suas alterações estão de acordo com as [diretrizes](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#general-guidelines-and-philosophy-for-contribution) . +- Verifique se suas alterações são consistentes com o [estilo de código do TensorFlow](https://www.tensorflow.org/community/contribute/code_style) . +- [Execute os testes de unidade](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#running-unit-tests) . diff --git a/site/pt-br/guide/core/mlp_core.ipynb b/site/pt-br/guide/core/mlp_core.ipynb new file mode 100644 index 0000000000..2f7aab79cd --- /dev/null +++ b/site/pt-br/guide/core/mlp_core.ipynb @@ -0,0 +1,1023 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "FhGuhbZ6M5tl" + }, + "source": [ + "##### Copyright 2022 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "AwOEIRJC6Une" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EIdT9iu_Z4Rb" + }, + "source": [ + "# Perceptrons multicamadas para reconhecimento de dígitos com APIs Core" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bBIlTPscrIT9" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SjAxxRpBzVYg" + }, + "source": [ + "Este notebook usa as [APIs de baixo nível do TensorFlow Core](https://www.tensorflow.org/guide/core) para criar um fluxo de trabalho de aprendizado de máquina completo para classificação de dígitos manuscritos com [perceptrons multicamadas](https://developers.google.com/machine-learning/crash-course/introduction-to-neural-networks/anatomy) e o [conjunto de dados MNIST](http://yann.lecun.com/exdb/mnist). Veja a [Visão geral das APIs Core](https://www.tensorflow.org/guide/core) para saber mais sobre o TensorFlow Core e seus casos de uso pretendidos." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GHVMVIFHSzl1" + }, + "source": [ + "## Visão geral do perceptron multicamadas (MLP)\n", + "\n", + "O Perceptron Multicamadas (Multilayer Perceptron - MLP) é um tipo de rede neural feedforward usada para abordar problemas de [classificação multiclasse](https://developers.google.com/machine-learning/crash-course/multi-class-neural-networks/video-lecture) . Antes de construir um MLP, é de fundamental importância entender os conceitos de perceptrons, camadas e funções de ativação.\n", + "\n", + "Perceptrons multicamadas são compostos de unidades funcionais chamadas de perceptrons. A equação de um perceptron é a seguinte:\n", + "\n", + "$$Z = \\vec{w}⋅\\mathrm{X} + b$$\n", + "\n", + "onde\n", + "\n", + "- $Z$: saída do perceptron\n", + "- $\\mathrm{X}$: matriz de características\n", + "- $\\vec{w}$: vetor de peso\n", + "- $b$: bias\n", + "\n", + "Quando esses perceptrons são empilhados, eles formam estruturas chamadas de camadas densas, que podem ser conectadas para construir uma rede neural. A equação de uma camada densa é semelhante à de um perceptron, mas usa uma matriz de peso e um vetor de bias:\n", + "\n", + "```\n", + "GL_FORMULA_1\n", + "```\n", + "\n", + "onde\n", + "\n", + "- $Z$: saída da camada densa\n", + "- $\\mathrm{X}$: matriz de características\n", + "- $\\mathrm{W}$: matriz de pesos\n", + "- $\\vec{b}$: vetor de bias\n", + "\n", + "Numa MLP, múltiplas camadas densas são conectadas de forma tal que as saídas de uma camada sejam totalmente conectadas às entradas da camada seguinte. Adicionar funções de ativação não lineares às saídas de camadas densas pode ajudar o classificador MLP a aprender limites de decisão complexos e fazer boas generalizações para dados não vistos." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nchsZfwEVtVs" + }, + "source": [ + "## Configuração\n", + "\n", + "Importe TensorFlow, [pandas](https://pandas.pydata.org) , [Matplotlib](https://matplotlib.org) e [seaborn](https://seaborn.pydata.org) para começar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mSfgqmwBagw_" + }, + "outputs": [ + + ], + "source": [ + "# Use seaborn for countplot.\n", + "!pip install -q seaborn" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1rRo8oNqZ-Rj" + }, + "outputs": [ + + ], + "source": [ + "import pandas as pd\n", + "import matplotlib\n", + "from matplotlib import pyplot as plt\n", + "import seaborn as sns\n", + "import tempfile\n", + "import os\n", + "# Preset Matplotlib figure sizes.\n", + "matplotlib.rcParams['figure.figsize'] = [9, 6]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9xQKvCJ85kCQ" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "import tensorflow_datasets as tfds\n", + "print(tf.__version__)\n", + "# Set random seed for reproducible results \n", + "tf.random.set_seed(22)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F_72b0LCNbjx" + }, + "source": [ + "## Carregando os dados\n", + "\n", + "Este tutorial usa o [dataset MNIST](http://yann.lecun.com/exdb/mnist) e demonstra como construir um modelo MLP que pode classificar dígitos manuscritos. O dataset está disponível em [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/mnist).\n", + "\n", + "Divida o conjunto de dados MNIST em conjuntos de treinamento, validação e teste. O conjunto de validação pode ser usado para avaliar a generalização do modelo durante o treinamento para que o dataset de teste possa servir como um estimador final imparcial para o desempenho do modelo.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Uiuh0B098_3p" + }, + "outputs": [ + + ], + "source": [ + "train_data, val_data, test_data = tfds.load(\"mnist\", \n", + " split=['train[10000:]', 'train[0:10000]', 'test'],\n", + " batch_size=128, as_supervised=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "X9uN3Lf6ANtn" + }, + "source": [ + "O dataset MNIST consiste em dígitos manuscritos e seus true labels (rótulos verdadeiros) correspondentes. Veja alguns exemplos abaixo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6V8hSqJ7AMjQ" + }, + "outputs": [ + + ], + "source": [ + "x_viz, y_viz = tfds.load(\"mnist\", split=['train[:1500]'], batch_size=-1, as_supervised=True)[0]\n", + "x_viz = tf.squeeze(x_viz, axis=3)\n", + "\n", + "for i in range(9):\n", + " plt.subplot(3,3,1+i)\n", + " plt.axis('off')\n", + " plt.imshow(x_viz[i], cmap='gray')\n", + " plt.title(f\"True Label: {y_viz[i]}\")\n", + " plt.subplots_adjust(hspace=.5)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bRald9dSE4qS" + }, + "source": [ + "Veja também a distribuição de dígitos nos dados de treinamento para verificar se cada classe está bem representada no dataset.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Rj3K4XgQE7qR" + }, + "outputs": [ + + ], + "source": [ + "sns.countplot(x=y_viz.numpy());\n", + "plt.xlabel('Digits')\n", + "plt.title(\"MNIST Digit Distribution\");" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "x_Wt4bDx_BRV" + }, + "source": [ + "## Pré-processamento dos dados\n", + "\n", + "Primeiro, remodele as matrizes de atributos para que sejam bidimensionais achatando as imagens. Em seguida, redimensione os dados para que os valores de pixel de [0,255] caibam no intervalo de [0,1]. Essa etapa garante que os pixels de entrada tenham distribuições semelhantes e ajuda na convergência do treinamento." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JSyCm2V2_AvI" + }, + "outputs": [ + + ], + "source": [ + "def preprocess(x, y):\n", + " # Reshaping the data\n", + " x = tf.reshape(x, shape=[-1, 784])\n", + " # Rescaling the data\n", + " x = x/255\n", + " return x, y\n", + "\n", + "train_data, val_data = train_data.map(preprocess), val_data.map(preprocess)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6o3CrycBXA2s" + }, + "source": [ + "## Construção do MLP\n", + "\n", + "Comece visualizando as funções de ativação [ReLU](https://developers.google.com/machine-learning/glossary#ReLU) e [Softmax](https://developers.google.com/machine-learning/glossary#softmax) . Ambas as funções estão disponíveis em `tf.nn.relu` e `tf.nn.softmax` respectivamente. O ReLU é uma função de ativação não linear que produz na saída a entrada se for positiva e 0 caso contrário:\n", + "\n", + "$$\\text{ReLU}(X) = max(0, X)$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hYunzt3UyT9G" + }, + "outputs": [ + + ], + "source": [ + "x = tf.linspace(-2, 2, 201)\n", + "x = tf.cast(x, tf.float32)\n", + "plt.plot(x, tf.nn.relu(x));\n", + "plt.xlabel('x')\n", + "plt.ylabel('ReLU(x)')\n", + "plt.title('ReLU activation function');" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fuGrM9jMwsRM" + }, + "source": [ + "A função de ativação softmax é uma função exponencial normalizada que converte $m$ números reais numa distribuição de probabilidade com $m$ resultados/classes. Isto é útil para prever probabilidades de classe a partir da saída de uma rede neural:\n", + "\n", + "$$\\text{Softmax}(X) = \\frac{e^{X}}{\\sum_{i=1}^{m}e^{X_i}}$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fVM8pvhWwuwI" + }, + "outputs": [ + + ], + "source": [ + "x = tf.linspace(-4, 4, 201)\n", + "x = tf.cast(x, tf.float32)\n", + "plt.plot(x, tf.nn.softmax(x, axis=0));\n", + "plt.xlabel('x')\n", + "plt.ylabel('Softmax(x)')\n", + "plt.title('Softmax activation function');" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OHW6Yvg2yS6H" + }, + "source": [ + "### A camada densa\n", + "\n", + "Crie uma classe para a camada densa. Por definição, as saídas de uma camada estão totalmente conectadas às entradas da camada seguinte numa MLP. Portanto, a dimensão de entrada para uma camada densa pode ser inferida com base na dimensão de saída de sua camada anterior e não precisa ser especificada antecipadamente durante a inicialização. Os pesos também devem ser inicializados corretamente para evitar que as saídas de ativação se tornem muito grandes ou pequenas. Um dos métodos de inicialização de pesos mais populares é o esquema Xavier, onde cada elemento da matriz de pesos é amostrado da seguinte maneira:\n", + "\n", + "$$W_{ij} \\sim \\text{Uniform}(-\\frac{\\sqrt{6}}{\\sqrt{n + m}},\\frac{\\sqrt{6}}{\\sqrt{n + m}})$$\n", + "\n", + "O vetor de bias pode ser inicializado com zeros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "re1SSFyBdMrS" + }, + "outputs": [ + + ], + "source": [ + "def xavier_init(shape):\n", + " # Computes the xavier initialization values for a weight matrix\n", + " in_dim, out_dim = shape\n", + " xavier_lim = tf.sqrt(6.)/tf.sqrt(tf.cast(in_dim + out_dim, tf.float32))\n", + " weight_vals = tf.random.uniform(shape=(in_dim, out_dim), \n", + " minval=-xavier_lim, maxval=xavier_lim, seed=22)\n", + " return weight_vals" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "otDFX4u6e6ml" + }, + "source": [ + "O método de inicialização Xavier também pode ser implementado com `tf.keras.initializers.GlorotUniform` ." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IM0yJos25FG5" + }, + "outputs": [ + + ], + "source": [ + "class DenseLayer(tf.Module):\n", + "\n", + " def __init__(self, out_dim, weight_init=xavier_init, activation=tf.identity):\n", + " # Initialize the dimensions and activation functions\n", + " self.out_dim = out_dim\n", + " self.weight_init = weight_init\n", + " self.activation = activation\n", + " self.built = False\n", + "\n", + " def __call__(self, x):\n", + " if not self.built:\n", + " # Infer the input dimension based on first call\n", + " self.in_dim = x.shape[1]\n", + " # Initialize the weights and biases\n", + " self.w = tf.Variable(self.weight_init(shape=(self.in_dim, self.out_dim)))\n", + " self.b = tf.Variable(tf.zeros(shape=(self.out_dim,)))\n", + " self.built = True\n", + " # Compute the forward pass\n", + " z = tf.add(tf.matmul(x, self.w), self.b)\n", + " return self.activation(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "X-7MzpjgyHg6" + }, + "source": [ + "Em seguida, construa uma classe para o modelo MLP que execute as camadas sequencialmente. Lembre-se de que as variáveis ​​do modelo só estão disponíveis após a primeira sequência de chamadas de camada densa devido à inferência de dimensão." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6XisRWiCyHAb" + }, + "outputs": [ + + ], + "source": [ + "class MLP(tf.Module):\n", + "\n", + " def __init__(self, layers):\n", + " self.layers = layers\n", + " \n", + " @tf.function\n", + " def __call__(self, x, preds=False): \n", + " # Execute the model's layers sequentially\n", + " for layer in self.layers:\n", + " x = layer(x)\n", + " return x" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "luXKup-43nd7" + }, + "source": [ + "Inicialize um modelo MLP com a seguinte arquitetura:\n", + "\n", + "- Passagem para a frente: ReLU (784 x 700) x ReLU (700 x 500) x Softmax (500 x 10)\n", + "\n", + "A função de ativação softmax não precisa ser aplicada pelo MLP. É computada separadamente nas funções de perda e previsão." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VmlACuki3oPi" + }, + "outputs": [ + + ], + "source": [ + "hidden_layer_1_size = 700\n", + "hidden_layer_2_size = 500\n", + "output_size = 10\n", + "\n", + "mlp_model = MLP([\n", + " DenseLayer(out_dim=hidden_layer_1_size, activation=tf.nn.relu),\n", + " DenseLayer(out_dim=hidden_layer_2_size, activation=tf.nn.relu),\n", + " DenseLayer(out_dim=output_size)])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tyBATDoRmDkg" + }, + "source": [ + "### Definição da função de perda\n", + "\n", + "A função de perda de entropia cruzada é uma ótima escolha para problemas de classificação multiclasse, pois mede a verossimilhança logarítmica negativa dos dados de acordo com as previsões de probabilidade do modelo. Quanto maior a probabilidade atribuída à classe verdadeira, menor a perda. A equação para a perda de entropia cruzada é a seguinte:\n", + "\n", + "$$L = -\\frac{1}{n}\\sum_{i=1}^{n}\\sum_{i=j}^{n} {y_j}^{[i]}⋅\\log(\\hat{{y_j}}^{[i]})$$\n", + "\n", + "onde\n", + "\n", + "- $\\underset{n\\times m}{\\hat{y}}$: uma matriz de distribuições de classes previstas\n", + "- $\\underset{n\\times m}{y}$: uma matriz codificada (com hot encoding) de classes verdadeiras\n", + "\n", + "A função `tf.nn.sparse_softmax_cross_entropy_with_logits` pode ser usada para calcular a perda de entropia cruzada. Esta função não requer que a última camada do modelo aplique a função de ativação softmax nem requer que os rótulos de classe sejam codificados com hot encoding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rskOYA7FVCwg" + }, + "outputs": [ + + ], + "source": [ + "def cross_entropy_loss(y_pred, y):\n", + " # Compute cross entropy loss with a sparse operation\n", + " sparse_ce = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=y_pred)\n", + " return tf.reduce_mean(sparse_ce)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BvWxED1km8jh" + }, + "source": [ + "Escreva uma função básica de exatidão que calcule a proporção de classificações corretas durante o treinamento. Para gerar previsões de classe a partir das saídas softmax, retorne o índice que corresponde à maior probabilidade de classe. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jPJMWx2UgiBm" + }, + "outputs": [ + + ], + "source": [ + "def accuracy(y_pred, y):\n", + " # Compute accuracy after extracting class predictions\n", + " class_preds = tf.argmax(tf.nn.softmax(y_pred), axis=1)\n", + " is_equal = tf.equal(y, class_preds)\n", + " return tf.reduce_mean(tf.cast(is_equal, tf.float32))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JSiNRhTOnKZr" + }, + "source": [ + "### Treinamento do modelo\n", + "\n", + "O uso de um otimizador pode resultar numa convergência significativamente mais rápida em comparação com o método do gradiente descendente padrão. O otimizador Adam é implementado abaixo. Consulte o guia [Otimizadores](https://www.tensorflow.org/guide/core/optimizers_core) para saber mais sobre como criar otimizadores personalizados com o TensorFlow Core." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iGIBDk3cAv6a" + }, + "outputs": [ + + ], + "source": [ + "class Adam:\n", + "\n", + " def __init__(self, learning_rate=1e-3, beta_1=0.9, beta_2=0.999, ep=1e-7):\n", + " # Initialize optimizer parameters and variable slots\n", + " self.beta_1 = beta_1\n", + " self.beta_2 = beta_2\n", + " self.learning_rate = learning_rate\n", + " self.ep = ep\n", + " self.t = 1.\n", + " self.v_dvar, self.s_dvar = [], []\n", + " self.built = False\n", + " \n", + " def apply_gradients(self, grads, vars):\n", + " # Initialize variables on the first call\n", + " if not self.built:\n", + " for var in vars:\n", + " v = tf.Variable(tf.zeros(shape=var.shape))\n", + " s = tf.Variable(tf.zeros(shape=var.shape))\n", + " self.v_dvar.append(v)\n", + " self.s_dvar.append(s)\n", + " self.built = True\n", + " # Update the model variables given their gradients\n", + " for i, (d_var, var) in enumerate(zip(grads, vars)):\n", + " self.v_dvar[i].assign(self.beta_1*self.v_dvar[i] + (1-self.beta_1)*d_var)\n", + " self.s_dvar[i].assign(self.beta_2*self.s_dvar[i] + (1-self.beta_2)*tf.square(d_var))\n", + " v_dvar_bc = self.v_dvar[i]/(1-(self.beta_1**self.t))\n", + " s_dvar_bc = self.s_dvar[i]/(1-(self.beta_2**self.t))\n", + " var.assign_sub(self.learning_rate*(v_dvar_bc/(tf.sqrt(s_dvar_bc) + self.ep)))\n", + " self.t += 1.\n", + " return " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "osEK3rqpYfKd" + }, + "source": [ + "Agora, escreva um loop de treinamento personalizado que atualize os parâmetros MLP com o método do gradiente descendente em minilotes. O uso de minilotes para treinamento garante uma eficiência de memória e convergência mais rápida." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CJLeY2ao1aw6" + }, + "outputs": [ + + ], + "source": [ + "def train_step(x_batch, y_batch, loss, acc, model, optimizer):\n", + " # Update the model state given a batch of data\n", + " with tf.GradientTape() as tape:\n", + " y_pred = model(x_batch)\n", + " batch_loss = loss(y_pred, y_batch)\n", + " batch_acc = acc(y_pred, y_batch)\n", + " grads = tape.gradient(batch_loss, model.variables)\n", + " optimizer.apply_gradients(grads, model.variables)\n", + " return batch_loss, batch_acc\n", + "\n", + "def val_step(x_batch, y_batch, loss, acc, model):\n", + " # Evaluate the model on given a batch of validation data\n", + " y_pred = model(x_batch)\n", + " batch_loss = loss(y_pred, y_batch)\n", + " batch_acc = acc(y_pred, y_batch)\n", + " return batch_loss, batch_acc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oC85kuZgmh3q" + }, + "outputs": [ + + ], + "source": [ + "def train_model(mlp, train_data, val_data, loss, acc, optimizer, epochs):\n", + " # Initialize data structures\n", + " train_losses, train_accs = [], []\n", + " val_losses, val_accs = [], []\n", + "\n", + " # Format training loop and begin training\n", + " for epoch in range(epochs):\n", + " batch_losses_train, batch_accs_train = [], []\n", + " batch_losses_val, batch_accs_val = [], []\n", + "\n", + " # Iterate over the training data\n", + " for x_batch, y_batch in train_data:\n", + " # Compute gradients and update the model's parameters\n", + " batch_loss, batch_acc = train_step(x_batch, y_batch, loss, acc, mlp, optimizer)\n", + " # Keep track of batch-level training performance\n", + " batch_losses_train.append(batch_loss)\n", + " batch_accs_train.append(batch_acc)\n", + "\n", + " # Iterate over the validation data\n", + " for x_batch, y_batch in val_data:\n", + " batch_loss, batch_acc = val_step(x_batch, y_batch, loss, acc, mlp)\n", + " batch_losses_val.append(batch_loss)\n", + " batch_accs_val.append(batch_acc)\n", + "\n", + " # Keep track of epoch-level model performance\n", + " train_loss, train_acc = tf.reduce_mean(batch_losses_train), tf.reduce_mean(batch_accs_train)\n", + " val_loss, val_acc = tf.reduce_mean(batch_losses_val), tf.reduce_mean(batch_accs_val)\n", + " train_losses.append(train_loss)\n", + " train_accs.append(train_acc)\n", + " val_losses.append(val_loss)\n", + " val_accs.append(val_acc)\n", + " print(f\"Epoch: {epoch}\")\n", + " print(f\"Training loss: {train_loss:.3f}, Training accuracy: {train_acc:.3f}\")\n", + " print(f\"Validation loss: {val_loss:.3f}, Validation accuracy: {val_acc:.3f}\")\n", + " return train_losses, train_accs, val_losses, val_accs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FvbfXlN5lwwB" + }, + "source": [ + "Treine o modelo MLP por 10 épocas com tamanho de lote de 128. Aceleradores de hardware como GPUs ou TPUs também podem ajudar a acelerar o tempo de treinamento. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zPlT8QfxptYl" + }, + "outputs": [ + + ], + "source": [ + "train_losses, train_accs, val_losses, val_accs = train_model(mlp_model, train_data, val_data, \n", + " loss=cross_entropy_loss, acc=accuracy,\n", + " optimizer=Adam(), epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j_RVmt43G12R" + }, + "source": [ + "### Avaliação de desempenho\n", + "\n", + "Comece escrevendo uma função de plotagem para visualizar a perda e a precisão do modelo durante o treinamento. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VXTCYVtNDjAM" + }, + "outputs": [ + + ], + "source": [ + "def plot_metrics(train_metric, val_metric, metric_type):\n", + " # Visualize metrics vs training Epochs\n", + " plt.figure()\n", + " plt.plot(range(len(train_metric)), train_metric, label = f\"Training {metric_type}\")\n", + " plt.plot(range(len(val_metric)), val_metric, label = f\"Validation {metric_type}\")\n", + " plt.xlabel(\"Epochs\")\n", + " plt.ylabel(metric_type)\n", + " plt.legend()\n", + " plt.title(f\"{metric_type} vs Training epochs\");" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DC-qIvZbHo0G" + }, + "outputs": [ + + ], + "source": [ + "plot_metrics(train_losses, val_losses, \"cross entropy loss\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "P-w2xk2PIDve" + }, + "outputs": [ + + ], + "source": [ + "plot_metrics(train_accs, val_accs, \"accuracy\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tbrJJaFrD_XR" + }, + "source": [ + "## Salvando e carregando o modelo\n", + "\n", + "Comece criando um módulo de exportação que receba dados brutos e execute as seguintes operações:\n", + "\n", + "- Pré-processamento de dados\n", + "- Previsão de probabilidade\n", + "- Previsão de classe" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1sszfWuJJZoo" + }, + "outputs": [ + + ], + "source": [ + "class ExportModule(tf.Module):\n", + " def __init__(self, model, preprocess, class_pred):\n", + " # Initialize pre and postprocessing functions\n", + " self.model = model\n", + " self.preprocess = preprocess\n", + " self.class_pred = class_pred\n", + "\n", + " @tf.function(input_signature=[tf.TensorSpec(shape=[None, None, None, None], dtype=tf.uint8)]) \n", + " def __call__(self, x):\n", + " # Run the ExportModule for new data points\n", + " x = self.preprocess(x)\n", + " y = self.model(x)\n", + " y = self.class_pred(y)\n", + " return y " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "p8x6gjTDVi5d" + }, + "outputs": [ + + ], + "source": [ + "def preprocess_test(x):\n", + " # The export module takes in unprocessed and unlabeled data\n", + " x = tf.reshape(x, shape=[-1, 784])\n", + " x = x/255\n", + " return x\n", + "\n", + "def class_pred_test(y):\n", + " # Generate class predictions from MLP output\n", + " return tf.argmax(tf.nn.softmax(y), axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vu9H5STrJzdo" + }, + "source": [ + "Este módulo de exportação agora pode ser salvo com a função `tf.saved_model.save`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fN9pPBQTKTe3" + }, + "outputs": [ + + ], + "source": [ + "mlp_model_export = ExportModule(model=mlp_model,\n", + " preprocess=preprocess_test,\n", + " class_pred=class_pred_test)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "idS7rQKbKwRS" + }, + "outputs": [ + + ], + "source": [ + "models = tempfile.mkdtemp()\n", + "save_path = os.path.join(models, 'mlp_model_export')\n", + "tf.saved_model.save(mlp_model_export, save_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_zZxO8iqBGZ-" + }, + "source": [ + "Carregue o modelo salvo com `tf.saved_model.load` e examine seu desempenho nos dados de teste não vistos." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "W5cwBTUqxldW" + }, + "outputs": [ + + ], + "source": [ + "mlp_loaded = tf.saved_model.load(save_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bmv0u6j_b5OC" + }, + "outputs": [ + + ], + "source": [ + "def accuracy_score(y_pred, y):\n", + " # Generic accuracy function\n", + " is_equal = tf.equal(y_pred, y)\n", + " return tf.reduce_mean(tf.cast(is_equal, tf.float32))\n", + "\n", + "x_test, y_test = tfds.load(\"mnist\", split=['test'], batch_size=-1, as_supervised=True)[0]\n", + "test_classes = mlp_loaded(x_test)\n", + "test_acc = accuracy_score(test_classes, y_test)\n", + "print(f\"Test Accuracy: {test_acc:.3f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j5t9vgv_ciQ_" + }, + "source": [ + "O modelo faz um ótimo trabalho de classificação de dígitos manuscritos no dataset de treinamento e também generaliza bem para dados não vistos. Agora, examine a precisão de classe do modelo para garantir um bom desempenho para cada dígito. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UD8YiC1Vfeyp" + }, + "outputs": [ + + ], + "source": [ + "print(\"Accuracy breakdown by digit:\")\n", + "print(\"---------------------------\")\n", + "label_accs = {}\n", + "for label in range(10):\n", + " label_ind = (y_test == label)\n", + " # extract predictions for specific true label\n", + " pred_label = test_classes[label_ind]\n", + " labels = y_test[label_ind]\n", + " # compute class-wise accuracy\n", + " label_accs[accuracy_score(pred_label, labels).numpy()] = label\n", + "for key in sorted(label_accs):\n", + " print(f\"Digit {label_accs[key]}: {key:.3f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rcykuJFhdGb0" + }, + "source": [ + "Parece que o modelo luta com alguns dígitos um pouco mais do que outros, o que é bastante comum em muitos problemas de classificação multiclasse. Como exercício final, desenhe uma matriz de confusão das previsões do modelo e seus true labels correspondentes para reunir mais insights em nível de classe. Sklearn e seaborn têm funções para gerar e visualizar matrizes de confusão. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JqCaqPwwh1tN" + }, + "outputs": [ + + ], + "source": [ + "import sklearn.metrics as sk_metrics\n", + "\n", + "def show_confusion_matrix(test_labels, test_classes):\n", + " # Compute confusion matrix and normalize\n", + " plt.figure(figsize=(10,10))\n", + " confusion = sk_metrics.confusion_matrix(test_labels.numpy(), \n", + " test_classes.numpy())\n", + " confusion_normalized = confusion / confusion.sum(axis=1, keepdims=True)\n", + " axis_labels = range(10)\n", + " ax = sns.heatmap(\n", + " confusion_normalized, xticklabels=axis_labels, yticklabels=axis_labels,\n", + " cmap='Blues', annot=True, fmt='.4f', square=True)\n", + " plt.title(\"Confusion matrix\")\n", + " plt.ylabel(\"True label\")\n", + " plt.xlabel(\"Predicted label\")\n", + "\n", + "show_confusion_matrix(y_test, test_classes)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JT-WA7GVda6d" + }, + "source": [ + "Os insights em nível de classe podem ajudar a identificar motivos para erros de classificação e melhorar o desempenho do modelo em futuros ciclos de treinamento." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VFLfEH4ManbW" + }, + "source": [ + "## Conclusão\n", + "\n", + "Este notebook apresentou algumas técnicas para lidar com um problema de classificação multiclasse usando uma [MLP](https://developers.google.com/machine-learning/crash-course/multi-class-neural-networks/softmax). Aqui estão mais algumas dicas que podem ser úteis:\n", + "\n", + "- As [APIs do TensorFlow Core](https://www.tensorflow.org/guide/core) podem ser usadas para criar workflows de aprendizado de máquina com altos níveis de configurabilidade\n", + "- Os esquemas de inicialização podem ajudar a evitar que os parâmetros do modelo desapareçam ou explodam durante o treinamento.\n", + "- O overfitting é outro problema comum para redes neurais, embora não tenha sido um problema neste tutorial. Consulte o tutorial [Overfit e underfit](overfit_and_underfit.ipynb) para mais informações sobre esse tema.\n", + "\n", + "Para obter mais exemplos de uso das APIs Core do TensorFlow, confira o [guia](https://www.tensorflow.org/guide/core). Se você quiser saber mais sobre como carregar e preparar dados, veja os tutoriais sobre [carregamento de dados de imagem](https://www.tensorflow.org/tutorials/load_data/images) ou [carregamento de dados CSV](https://www.tensorflow.org/tutorials/load_data/csv)." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + "FhGuhbZ6M5tl" + ], + "name": "mlp_core.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/guide/saved_model.ipynb b/site/pt-br/guide/saved_model.ipynb new file mode 100644 index 0000000000..c609f29143 --- /dev/null +++ b/site/pt-br/guide/saved_model.ipynb @@ -0,0 +1,1020 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "6bYaCABobL5q" + }, + "source": [ + "##### Copyright 2018 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "FlUw7tSKbtg4" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xc1srSc51n_4" + }, + "source": [ + "# Usando o formato SavedModel" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-nBUqG2rchGH" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CPE-fshLTsXU" + }, + "source": [ + "Um SavedModel contém um programa TensorFlow completo, incluindo parâmetros treinados (ou seja, objetos `tf.Variable`) e computação. Ele não requer a execução do código de construção do modelo original, o que o torna útil para compartilhamento ou implantação com [TFLite](https://tensorflow.org/lite), [TensorFlow.js](https://js.tensorflow.org/), [TensorFlow Serving](https://www.tensorflow.org/tfx/serving/tutorials/Serving_REST_simple) ou [TensorFlow Hub](https://tensorflow.org/hub).\n", + "\n", + "Você pode salvar e carregar um modelo no formato SavedModel usando as seguintes APIs:\n", + "\n", + "- API `tf.saved_model` de baixo nível. Este documento descreve detalhadamente como usar esta API.\n", + " - Salvar: `tf.saved_model.save(model, path_to_dir)`\n", + " - Carregar: `model = tf.saved_model.load(path_to_dir)`\n", + "- API `tf.keras.Model` de alto nível. Consulte o [guia de salvamento e serialização do keras](https://www.tensorflow.org/guide/keras/save_and_serialize).\n", + "- Se quiser apenas salvar/carregar pesos durante o treino, consulte o [guia de checkpoints](./checkpoint.ipynb).\n", + "\n", + "Atenção: os modelos do TensorFlow são códigos, e é importante ter cuidado com código não confiável. Saiba mais em [Como usar o TensorFlow com segurança](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9SuIC7FiI9g8" + }, + "source": [ + "## Criando um SavedModel a partir do Keras" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AtSmftAvhJvE" + }, + "source": [ + "Obsoleto: para objetos do Keras, recomenda-se usar o novo formato de alto nível `.keras` e `tf.keras.Model.export`, conforme demonstrado [neste guia](https://www.tensorflow.org/guide/keras/save_and_serialize). O formato de baixo nível SavedModel continua com suporte para códigos existentes." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eLSOptpYhJvE" + }, + "source": [ + "Para uma introdução rápida, esta seção exporta um modelo Keras pré-treinado e atende solicitações de classificação de imagem com ele. O restante do guia preencherá detalhes e discutirá outras maneiras de criar SavedModels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Le5OB-fBHHW7" + }, + "outputs": [ + + ], + "source": [ + "import os\n", + "import tempfile\n", + "\n", + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "import tensorflow as tf\n", + "\n", + "tmpdir = tempfile.mkdtemp()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wlho4HEWoHUT" + }, + "outputs": [ + + ], + "source": [ + "physical_devices = tf.config.list_physical_devices('GPU')\n", + "for device in physical_devices:\n", + " tf.config.experimental.set_memory_growth(device, True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SofdPKo0G8Lb" + }, + "outputs": [ + + ], + "source": [ + "file = tf.keras.utils.get_file(\n", + " \"grace_hopper.jpg\",\n", + " \"https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg\")\n", + "img = tf.keras.utils.load_img(file, target_size=[224, 224])\n", + "plt.imshow(img)\n", + "plt.axis('off')\n", + "x = tf.keras.utils.img_to_array(img)\n", + "x = tf.keras.applications.mobilenet.preprocess_input(\n", + " x[tf.newaxis,...])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sqVcFL10JkF0" + }, + "source": [ + "Você usará uma imagem de Grace Hopper como exemplo em execução e um modelo de classificação de imagens pré-treinado do Keras, pois é mais fácil de usar. Modelos personalizados também funcionam e serão abordados em detalhes posteriormente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JhVecdzJTsKE" + }, + "outputs": [ + + ], + "source": [ + "labels_path = tf.keras.utils.get_file(\n", + " 'ImageNetLabels.txt',\n", + " 'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')\n", + "imagenet_labels = np.array(open(labels_path).read().splitlines())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aEHSYjW6JZHV" + }, + "outputs": [ + + ], + "source": [ + "pretrained_model = tf.keras.applications.MobileNet()\n", + "result_before_save = pretrained_model(x)\n", + "\n", + "decoded = imagenet_labels[np.argsort(result_before_save)[0,::-1][:5]+1]\n", + "\n", + "print(\"Result before saving:\\n\", decoded)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r4KIsQDZJ5PS" + }, + "source": [ + "A principal previsão para esta imagem é “uniforme militar”." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8nfznDmHCW6F" + }, + "outputs": [ + + ], + "source": [ + "mobilenet_save_path = os.path.join(tmpdir, \"mobilenet/1/\")\n", + "tf.saved_model.save(pretrained_model, mobilenet_save_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pyX-ETE3wX63" + }, + "source": [ + "O caminho de salvamento (save-path) segue uma convenção usada pelo TensorFlow Serving, onde o último componente do caminho (`1/` aqui) é um número de versão do seu modelo. Ele permite que ferramentas como o Tensorflow Serving raciocinem sobre a atualização relativa.\n", + "\n", + "Você pode carregar o SavedModel de volta no Python com `tf.saved_model.load` e ver como a imagem do Admiral Hopper é classificada." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NP2UpVFRV7N_" + }, + "outputs": [ + + ], + "source": [ + "loaded = tf.saved_model.load(mobilenet_save_path)\n", + "print(list(loaded.signatures.keys())) # [\"serving_default\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K5srGzowfWff" + }, + "source": [ + "Assinaturas importadas sempre retornam dicionários. Para personalizar nomes de assinaturas e chaves de dicionários de saída, veja [Especificando assinaturas durante a exportação](#specifying_signatures_during_export)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ChFLpegYfQGR" + }, + "outputs": [ + + ], + "source": [ + "infer = loaded.signatures[\"serving_default\"]\n", + "print(infer.structured_outputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cJYyZnptfuru" + }, + "source": [ + "Executar a inferência do SavedModel fornece o mesmo resultado que o modelo original." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9WjGEaS3XfX7" + }, + "outputs": [ + + ], + "source": [ + "labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]\n", + "\n", + "decoded = imagenet_labels[np.argsort(labeling)[0,::-1][:5]+1]\n", + "\n", + "print(\"Result after saving and loading:\\n\", decoded)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SJEkdXjTWbtl" + }, + "source": [ + "## Executando um SavedModel no TensorFlow Serving\n", + "\n", + "Os SavedModels podem ser usados ​​a partir do Python (mais sobre isso abaixo), mas ambientes de produção normalmente usam um serviço dedicado para inferência sem executar código Python. Isto é fácil de configurar a partir de um SavedModel usando o TensorFlow Serving.\n", + "\n", + "Consulte o [Tutorial REST do TensorFlow Serving](https://www.tensorflow.org/tfx/tutorials/serving/rest_simple) para um exemplo completo com o tensorflow-serving." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Bi0ILzu1XdWw" + }, + "source": [ + "## O formato SavedModel no disco\n", + "\n", + "Um SavedModel é um diretório que contém assinaturas serializadas e o estado necessário para executá-las, incluindo valores de variáveis ​​e vocabulários.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6u3YZuYZXyTO" + }, + "outputs": [ + + ], + "source": [ + "!ls {mobilenet_save_path}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ple4X5utX8ue" + }, + "source": [ + "O arquivo `saved_model.pb` armazena o programa ou modelo real do TensorFlow e um conjunto de assinaturas nomeadas, cada uma identificando uma função que aceita entradas de tensor e produz saídas de tensor.\n", + "\n", + "Os SavedModels podem conter múltiplas variantes do modelo (múltiplas `v1.MetaGraphDefs`, identificadas com o sinalizador `--tag_set` para `saved_model_cli`), mas isto é raro. APIs que criam múltiplas variantes de um modelo incluem [`tf.Estimator.experimental_export_all_saved_models`](https://www.tensorflow.org/api_docs/python/tf/estimator/Estimator#experimental_export_all_saved_models) e no TensorFlow 1.x `tf.saved_model.Builder`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Pus0dOYTYXbI" + }, + "outputs": [ + + ], + "source": [ + "!saved_model_cli show --dir {mobilenet_save_path} --tag_set serve" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eALHpGvRZOhk" + }, + "source": [ + "O diretório `variables` ​​contém um checkpoint de treinamento padrão (veja o [guia de checkpoints de treinamento](./checkpoint.ipynb))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EDYqhDlNZAC2" + }, + "outputs": [ + + ], + "source": [ + "!ls {mobilenet_save_path}/variables" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VKmaZQpHahGh" + }, + "source": [ + "O diretório `assets` contém arquivos usados ​​pelo grafo do TensorFlow, por exemplo, arquivos de texto usados ​​para inicializar tabelas de vocabulário. Não é utilizado neste exemplo.\n", + "\n", + "SavedModels pode ter um diretório `assets.extra` para quaisquer arquivos não usados ​​pelo grafo do TensorFlow, por exemplo, informações para consumidores sobre o que fazer com o SavedModel. O próprio TensorFlow não usa esse diretório.\n", + "\n", + "O arquivo `fingerprint.pb` contém a [impressão digital](https://en.wikipedia.org/wiki/Fingerprint_(computing)) do SavedModel, que é composta por vários hashes de 64 bits que identificam exclusivamente o conteúdo do SavedModel. A API de impressão digital é atualmente experimental, mas `tf.saved_model.experimental.read_fingerprint` pode ser usado para ler a impressão digital SavedModel num objeto `tf.saved_model.experimental.Fingerprint`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zIceoF_CYmaF" + }, + "source": [ + "## Salvando um modelo personalizado\n", + "\n", + "`tf.saved_model.save` suporta o salvamento de objetos `tf.Module` e suas subclasses, como `tf.keras.Layer` e `tf.keras.Model`.\n", + "\n", + "Vejamos um exemplo de como salvar e restaurar um `tf.Module`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6EPvKiqXMm3d" + }, + "outputs": [ + + ], + "source": [ + "class CustomModule(tf.Module):\n", + "\n", + " def __init__(self):\n", + " super(CustomModule, self).__init__()\n", + " self.v = tf.Variable(1.)\n", + "\n", + " @tf.function\n", + " def __call__(self, x):\n", + " print('Tracing with', x)\n", + " return x * self.v\n", + "\n", + " @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])\n", + " def mutate(self, new_v):\n", + " self.v.assign(new_v)\n", + "\n", + "module = CustomModule()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "J4FcP-Co3Fnw" + }, + "source": [ + "Quando você salva um `tf.Module`, quaisquer atributos `tf.Variable`, métodos decorados `tf.function` e `tf.Module` encontrados via travessia recursiva são salvos. (Consulte o [tutorial sobre checkpoints](./checkpoint.ipynb) para saber mais sobre essa travessia recursiva.) No entanto, quaisquer atributos, funções e dados do Python são perdidos. Isto significa que quando uma `tf.function` é salva, nenhum código Python é salvo.\n", + "\n", + "Se nenhum código Python for salvo, como o SavedModel saberá restaurar a função?\n", + "\n", + "Resumidamente, `tf.function` funciona rastreando o código Python para gerar um ConcreteFunction (um wrapper em torno de `tf.Graph` que pode ser chamado). Ao salvar um `tf.function`, você está na verdade salvando o cache `tf.function` de ConcreteFunctions.\n", + "\n", + "Para saber mais sobre o relacionamento entre `tf.function` e ConcreteFunctions, veja o [guia sobre tf.function](function.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "85PUO9iWH7xn" + }, + "outputs": [ + + ], + "source": [ + "module_no_signatures_path = os.path.join(tmpdir, 'module_no_signatures')\n", + "module(tf.constant(0.))\n", + "print('Saving model...')\n", + "tf.saved_model.save(module, module_no_signatures_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2ujwmMQg7OUo" + }, + "source": [ + "## Carregando e usando um modelo personalizado" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QpxQy5Eb77qJ" + }, + "source": [ + "Quando você carrega um SavedModel em Python, todos os atributos de `tf.Variable`, métodos decorados com `tf.function` e `tf.Module` são restaurados na mesma estrutura de objeto do `tf.Module` salvo originalmente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EMASjADPxPso" + }, + "outputs": [ + + ], + "source": [ + "imported = tf.saved_model.load(module_no_signatures_path)\n", + "assert imported(tf.constant(3.)).numpy() == 3\n", + "imported.mutate(tf.constant(2.))\n", + "assert imported(tf.constant(3.)).numpy() == 6" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CDiauvb_99uk" + }, + "source": [ + "Como nenhum código Python é salvo, a chamada de `tf.function` com uma nova assinatura de entrada falhará:\n", + "\n", + "```python\n", + "imported(tf.constant([3.]))\n", + "```\n", + "\n", + "
\n",
+        "ValueError: Could not find matching function to call for canonicalized inputs ((<tf.Tensor 'args_0:0' shape=(1,) dtype=float32>,), {}). Only existing signatures are [((TensorSpec(shape=(), dtype=tf.float32, name=u'x'),), {})].\n",
+        "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4Vsva3UZ-2sf" + }, + "source": [ + "### Tuning básico\n", + "\n", + "Objetos variáveis ​​estão disponíveis e você pode fazer backprop através de funções importadas. Isto é suficiente para fazer um ajuste fino (ou seja, treinar novamente) um SavedModel em casos simples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PEkQNarJ-7nT" + }, + "outputs": [ + + ], + "source": [ + "optimizer = tf.keras.optimizers.SGD(0.05)\n", + "\n", + "def train_step():\n", + " with tf.GradientTape() as tape:\n", + " loss = (10. - imported(tf.constant(2.))) ** 2\n", + " variables = tape.watched_variables()\n", + " grads = tape.gradient(loss, variables)\n", + " optimizer.apply_gradients(zip(grads, variables))\n", + " return loss" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "p41NM6fF---3" + }, + "outputs": [ + + ], + "source": [ + "for _ in range(10):\n", + " # \"v\" approaches 5, \"loss\" approaches 0\n", + " print(\"loss={:.2f} v={:.2f}\".format(train_step(), imported.v.numpy()))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XuXtkHSD_KSW" + }, + "source": [ + "### Tuning geral\n", + "\n", + "Um SavedModel da Keras fornece [mais detalhes](https://github.com/tensorflow/community/blob/master/rfcs/20190509-keras-saved-model.md#serialization-details) do que uma simples `__call__` para abordar casos mais avançados de ajuste fino. O TensorFlow Hub recomenda fornecer o seguinte, se aplicável, em SavedModels compartilhados para fins de tuning:\n", + "\n", + "- Se o modelo usar dropout ou outra técnica na qual o passo para a frente difere no treinamento e na inferência (como normalização em lote), o método `__call__` usará um argumento `training=` opcional com valor Python cujo padrão é `False`, mas pode ser definido como `True`.\n", + "- Depois do atributo `__call__`, existem os atributos `.variable` e `.trainable_variable` com listas de variáveis ​​correspondentes. Uma variável que era originalmente treinável, mas que deveria ser congelada durante o ajuste fino, é omitida de `.trainable_variables`.\n", + "- Para o bem de estruturas como Keras, que representam regularizadores de peso como atributos de camadas ou submodelos, também poderá haver um atributo `.regularization_losses`. Ele contém uma lista de funções com argumento zero cujos valores devem ser adicionados à perda total.\n", + "\n", + "Voltando ao exemplo inicial do MobileNet, você poderá ver alguns desses em ação:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Y6EUFdY8_PRD" + }, + "outputs": [ + + ], + "source": [ + "loaded = tf.saved_model.load(mobilenet_save_path)\n", + "print(\"MobileNet has {} trainable variables: {}, ...\".format(\n", + " len(loaded.trainable_variables),\n", + " \", \".join([v.name for v in loaded.trainable_variables[:5]])))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "B-mQJ8iP_R0h" + }, + "outputs": [ + + ], + "source": [ + "trainable_variable_ids = {id(v) for v in loaded.trainable_variables}\n", + "non_trainable_variables = [v for v in loaded.variables\n", + " if id(v) not in trainable_variable_ids]\n", + "print(\"MobileNet also has {} non-trainable variables: {}, ...\".format(\n", + " len(non_trainable_variables),\n", + " \", \".join([v.name for v in non_trainable_variables[:3]])))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qGlHlbd3_eyO" + }, + "source": [ + "## Especificando assinaturas durante a exportação\n", + "\n", + "Ferramentas como TensorFlow Serving e `saved_model_cli` podem interagir com SavedModels. Para ajudar essas ferramentas a determinar quais ConcreteFunctions usar, você precisa especificar assinaturas de serviço. Os `tf.keras.Model` especificam automaticamente assinaturas de serviço, mas você terá que declarar explicitamente uma assinatura de serviço para nossos módulos personalizados.\n", + "\n", + "IMPORTANTE: a menos que você precise exportar seu modelo para um ambiente diferente do TensorFlow 2.x com Python, provavelmente não será necessário exportar assinaturas explicitamente. Se você está procurando uma maneira de impor uma assinatura de entrada para uma função específica, veja o argumento [`input_signature`](https://www.tensorflow.org/api_docs/python/tf/function#args_1) para `tf.function`.\n", + "\n", + "Por padrão, nenhuma assinatura é declarada num `tf.Module` personalizado." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "h-IB5Xa0NxLa" + }, + "outputs": [ + + ], + "source": [ + "assert len(imported.signatures) == 0" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BiNtaMZSI8Tb" + }, + "source": [ + "Para declarar uma assinatura de serviço, especifique uma ConcreteFunction usando o kwarg `signatures`. Ao especificar uma única assinatura, sua chave de assinatura será `'serving_default'`, que é salva como a constante `tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_pAdgIORR2yH" + }, + "outputs": [ + + ], + "source": [ + "module_with_signature_path = os.path.join(tmpdir, 'module_with_signature')\n", + "call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))\n", + "tf.saved_model.save(module, module_with_signature_path, signatures=call)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nAzRHR0UT4hv" + }, + "outputs": [ + + ], + "source": [ + "imported_with_signatures = tf.saved_model.load(module_with_signature_path)\n", + "list(imported_with_signatures.signatures.keys())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_gH91j1IR4tq" + }, + "source": [ + "Para exportar múltiplas assinaturas, passe um dicionário de chaves de assinatura para ConcreteFunctions. Cada chave de assinatura corresponde a uma ConcreteFunction." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6VYAiQmLUiox" + }, + "outputs": [ + + ], + "source": [ + "module_multiple_signatures_path = os.path.join(tmpdir, 'module_with_multiple_signatures')\n", + "signatures = {\"serving_default\": call,\n", + " \"array_input\": module.__call__.get_concrete_function(tf.TensorSpec([None], tf.float32))}\n", + "\n", + "tf.saved_model.save(module, module_multiple_signatures_path, signatures=signatures)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8IPx_0RWEx07" + }, + "outputs": [ + + ], + "source": [ + "imported_with_multiple_signatures = tf.saved_model.load(module_multiple_signatures_path)\n", + "list(imported_with_multiple_signatures.signatures.keys())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "43_Qv2W_DJZZ" + }, + "source": [ + "Por padrão, os nomes dos tensores de saída são bastante genéricos, como `output_0`. Para controlar os nomes das saídas, modifique seu `tf.function` para retornar um dicionário que mapeia nomes de saída para saídas. Os nomes das entradas são derivados dos nomes dos argumentos da função Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ACKPl1X8G1gw" + }, + "outputs": [ + + ], + "source": [ + "class CustomModuleWithOutputName(tf.Module):\n", + " def __init__(self):\n", + " super(CustomModuleWithOutputName, self).__init__()\n", + " self.v = tf.Variable(1.)\n", + "\n", + " @tf.function(input_signature=[tf.TensorSpec(None, tf.float32)])\n", + " def __call__(self, x):\n", + " return {'custom_output_name': x * self.v}\n", + "\n", + "module_output = CustomModuleWithOutputName()\n", + "call_output = module_output.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))\n", + "module_output_path = os.path.join(tmpdir, 'module_with_output_name')\n", + "tf.saved_model.save(module_output, module_output_path,\n", + " signatures={'serving_default': call_output})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1yGVy4MuH-V0" + }, + "outputs": [ + + ], + "source": [ + "imported_with_output_name = tf.saved_model.load(module_output_path)\n", + "imported_with_output_name.signatures['serving_default'].structured_outputs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Q4bCK55x1IBW" + }, + "source": [ + "## Divisão de arquivos proto\n", + "\n", + "Observação: este recurso fará parte da versão 2.15 do TensorFlow. No momento, ele está disponível em build noturno, que você pode instalar com `pip install tf-nightly`.\n", + "\n", + "Devido aos limites da implementação do protobuf, os tamanhos do proto não podem ultrapassar 2 GB. Isso pode levar aos seguintes erros ao tentar salvar modelos muito grandes:\n", + "\n", + "```\n", + "ValueError: Message tensorflow.SavedModel exceeds maximum protobuf size of 2GB: ...\n", + "```\n", + "\n", + "```\n", + "google.protobuf.message.DecodeError: Error parsing message as the message exceeded the protobuf limit with type 'tensorflow.GraphDef'\n", + "```\n", + "\n", + "Se você quiser salvar modelos que ultrapassam o limite de 2 GB, será necessário salvar usando a nova opção de divisão de proto:\n", + "\n", + "```python\n", + "tf.saved_model.save(\n", + " ...,\n", + " options=tf.saved_model.SaveOptions(experimental_image_format=True)\n", + ")\n", + "```\n", + "\n", + "Encontre mais informações no [guia da biblioteca de divisão / fusão de proto](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/proto_splitter/in-depth-guide.md)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Co6fDbzw_UnD" + }, + "source": [ + "## Carregue um SavedModel em C++\n", + "\n", + "A versão C++ do [carregador](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/cc/saved_model/loader.h) do SavedModel fornece uma API para carregar um SavedModel de um caminho, enquanto permite SessionOptions e RunOptions. Você deve especificar as tags associadas ao grafo a ser carregado. A versão carregada do SavedModel é chamada de SavedModelBundle e contém o MetaGraphDef e a sessão na qual ele é carregado.\n", + "\n", + "```C++\n", + "const string export_dir = ...\n", + "SavedModelBundle bundle;\n", + "...\n", + "LoadSavedModel(session_options, run_options, export_dir, {kSavedModelTagTrain},\n", + " &bundle);\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b33KuyEuAO3Z" + }, + "source": [ + "\n", + "\n", + "## Detalhes da interface de linha de comando SavedModel\n", + "\n", + "Você pode usar a interface de linha de comando (CLI) do SavedModel para inspecionar e executar um SavedModel. Por exemplo, você pode usar a CLI para inspecionar os `SignatureDef` do modelo. A CLI permite que você confirme rapidamente se o tipo e o formato do Tensor de entrada correspondem ao modelo. Além disso, se quiser testar seu modelo, você pode usar a CLI para fazer uma verificação de integridade, passando amostras de entradas em vários formatos (por exemplo, expressões Python) e, em seguida, obtendo a saída.\n", + "\n", + "### Instale a SavedModel CLI\n", + "\n", + "Em termos gerais, você pode instalar o TensorFlow de uma das duas maneiras a seguir:\n", + "\n", + "- Instalando um binário TensorFlow pré-compilado.\n", + "- Compilando o TensorFlow a partir do código-fonte.\n", + "\n", + "Se você instalou o TensorFlow através de um binário pré-compilado do TensorFlow, a CLI do SavedModel já estará instalada no seu sistema no caminho `bin/saved_model_cli`.\n", + "\n", + "Se você compilou o TensorFlow a partir do código-fonte, deverá executar o seguinte comando adicional para compilar o `saved_model_cli`:\n", + "\n", + "```\n", + "$ bazel build //tensorflow/python/tools:saved_model_cli\n", + "```\n", + "\n", + "### Visão geral dos comandos\n", + "\n", + "A CLI do SavedModel oferece suporte aos dois comandos a seguir num SavedModel:\n", + "\n", + "- `show`, que mostra as computações disponíveis num SavedModel.\n", + "- `run`, que executa uma computação em um SavedModel.\n", + "\n", + "### Comando `show`\n", + "\n", + "Um SavedModel contém uma ou mais variantes de modelos (tecnicamente, `v1.MetaGraphDef`), identificadas por seus conjuntos de tags. Para servir um modelo, você pode se perguntar que tipo de `SignatureDef` existem em cada variante de modelo e quais são suas entradas e saídas. O comando `show` permite examinar o conteúdo do SavedModel em ordem hierárquica. Aqui está a sintaxe:\n", + "\n", + "```\n", + "usage: saved_model_cli show [-h] --dir DIR [--all]\n", + "[--tag_set TAG_SET] [--signature_def SIGNATURE_DEF_KEY]\n", + "```\n", + "\n", + "Por exemplo, o comando a seguir mostra todos os conjuntos de tags disponíveis no SavedModel:\n", + "\n", + "```\n", + "$ saved_model_cli show --dir /tmp/saved_model_dir\n", + "The given SavedModel contains the following tag-sets:\n", + "serve\n", + "serve, gpu\n", + "```\n", + "\n", + "O comando a seguir mostra todas as chaves `SignatureDef` disponíveis para um conjunto de tags:\n", + "\n", + "```\n", + "$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve The given SavedModel `MetaGraphDef` contains `SignatureDefs` with the following keys: SignatureDef key: \"classify_x2_to_y3\" SignatureDef key: \"classify_x_to_y\" SignatureDef key: \"regress_x2_to_y3\" SignatureDef key: \"regress_x_to_y\" SignatureDef key: \"regress_x_to_y2\" SignatureDef key: \"serving_default\"\n", + "```\n", + "\n", + "Se houver *múltiplos* tags no conjunto de tags, você deverá especificar todas as tags, cada tag separada por uma vírgula. Por exemplo:\n", + "\n", + "
\n",
+        "$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve,gpu\n",
+        "
\n", + "\n", + "Para mostrar todas as entradas e saídas do TensorInfo para um `SignatureDef` específico, passe a chave `SignatureDef` para a opção `signature_def`. Isso é muito útil quando você deseja saber o valor da chave do tensor, o tipo e formato dos tensores de entrada para executar o grafo de computação posteriormente. Por exemplo:\n", + "\n", + "```\n", + "$ saved_model_cli show --dir \\ /tmp/saved_model_dir --tag_set serve --signature_def serving_default The given SavedModel SignatureDef contains the following input(s): inputs['x'] tensor_info: dtype: DT_FLOAT shape: (-1, 1) name: x:0 The given SavedModel SignatureDef contains the following output(s): outputs['y'] tensor_info: dtype: DT_FLOAT shape: (-1, 1) name: y:0 Method name is: tensorflow/serving/predict\n", + "```\n", + "\n", + "Para mostrar todas as informações disponíveis no SavedModel, use a opção `--all`. Por exemplo:\n", + "\n", + "
\n",
+        "$ saved_model_cli show --dir /tmp/saved_model_dir --all\n",
+        "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
+        "\n",
+        "signature_def['classify_x2_to_y3']:\n",
+        "  The given SavedModel SignatureDef contains the following input(s):\n",
+        "    inputs['inputs'] tensor_info:\n",
+        "        dtype: DT_FLOAT\n",
+        "        shape: (-1, 1)\n",
+        "        name: x2:0\n",
+        "  The given SavedModel SignatureDef contains the following output(s):\n",
+        "    outputs['scores'] tensor_info:\n",
+        "        dtype: DT_FLOAT\n",
+        "        shape: (-1, 1)\n",
+        "        name: y3:0\n",
+        "  Method name is: tensorflow/serving/classify\n",
+        "\n",
+        "...\n",
+        "\n",
+        "signature_def['serving_default']:\n",
+        "  The given SavedModel SignatureDef contains the following input(s):\n",
+        "    inputs['x'] tensor_info:\n",
+        "        dtype: DT_FLOAT\n",
+        "        shape: (-1, 1)\n",
+        "        name: x:0\n",
+        "  The given SavedModel SignatureDef contains the following output(s):\n",
+        "    outputs['y'] tensor_info:\n",
+        "        dtype: DT_FLOAT\n",
+        "        shape: (-1, 1)\n",
+        "        name: y:0\n",
+        "  Method name is: tensorflow/serving/predict\n",
+        "
\n", + "\n", + "### Comando `run`\n", + "\n", + "Chame o comando `run` para executar uma computação do grafo, passando entradas e exibindo (e opcionalmente salvando) as saídas. Aqui está a sintaxe:\n", + "\n", + "```\n", + "usage: saved_model_cli run [-h] --dir DIR --tag_set TAG_SET --signature_def\n", + " SIGNATURE_DEF_KEY [--inputs INPUTS]\n", + " [--input_exprs INPUT_EXPRS]\n", + " [--input_examples INPUT_EXAMPLES] [--outdir OUTDIR]\n", + " [--overwrite] [--tf_debug]\n", + "```\n", + "\n", + "O comando `run` fornece três maneiras de passar entradas para o modelo, mostradas a seguir:\n", + "\n", + "- A opção `--inputs` permite que você passe numpy ndarray em arquivos.\n", + "- A opção `--input_exprs` permite que você passe expressões Python.\n", + "- A opção `--input_examples` permite que você passe `tf.train.Example`.\n", + "\n", + "#### `--inputs`\n", + "\n", + "Para passar dados de entrada em arquivos, especifique a opção `--inputs`, que assume o seguinte formato geral:\n", + "\n", + "```bsh\n", + "--inputs <INPUTS>\n", + "```\n", + "\n", + "onde *INPUTS* é um dos seguintes formatos:\n", + "\n", + "- `=`\n", + "- `=[]`\n", + "\n", + "Você pode passar múltiplos *INPUTS*. Se você fizer isso, use ponto e vírgula para separar cada uma das *INPUTS*.\n", + "\n", + "`saved_model_cli` usa `numpy.load` para carregar o nome do arquivo *filename*. O *filename* pode estar em qualquer um dos seguintes formatos:\n", + "\n", + "- `.npy`\n", + "- `.npz`\n", + "- formato pickle\n", + "\n", + "Um arquivo `.npy` sempre contém um ndarray numpy. Portanto, ao carregar de um arquivo `.npy`, o conteúdo será diretamente atribuído ao tensor de entrada especificado. Se você especificar um *nome_variável* com esse arquivo `.npy`, o *nome_variável* será ignorado e um aviso será emitido.\n", + "\n", + "Ao carregar de um arquivo `.npz` (zip), você poderá opcionalmente especificar um *nome_da_variável* para identificar a variável dentro do arquivo zip a ser carregada para a chave do tensor de entrada. Se você não especificar um *variable_name*, a CLI SavedModel verificará se apenas um arquivo está incluído no arquivo zip e o carregará para a chave do tensor de entrada especificada.\n", + "\n", + "Ao carregar a partir de um arquivo pickle, se nenhum `variable_name` for especificado entre colchetes, tudo o que estiver dentro do arquivo pickle será passado para a chave de entrada especificada do tensor. Caso contrário, a CLI do SavedModel assumirá que um dicionário está armazenado no arquivo pickle e o valor correspondente ao *nome_variável* será usado.\n", + "\n", + "#### `--input_exprs`\n", + "\n", + "Para passar entradas via expressões Python, especifique a opção `--input_exprs`. Isto pode ser útil quando você não tem arquivos de dados disponíveis, mas ainda deseja verificar a integridade do modelo com algumas entradas simples que correspondem ao dtype e à forma dos `SignatureDef` do modelo. Por exemplo:\n", + "\n", + "```bsh\n", + "`<input_key>=[[1],[2],[3]]`\n", + "```\n", + "\n", + "Além das expressões Python, você também pode passar funções numpy. Por exemplo:\n", + "\n", + "```bsh\n", + "`<input_key>=np.ones((32,32,3))`\n", + "```\n", + "\n", + "(Observe que o módulo `numpy` já está disponível para você como `np`.)\n", + "\n", + "#### `--input_examples`\n", + "\n", + "Para passar objetos `tf.train.Example` como entradas, especifique a opção `--input_examples`. Para cada chave de entrada, é necessária uma lista de dicionários, onde cada dicionário é uma instância de `tf.train.Example`. As chaves do dicionário são as características e os valores são as listas de valores de cada característica. Por exemplo:\n", + "\n", + "```bsh\n", + "`<input_key>=[{\"age\":[22,24],\"education\":[\"BS\",\"MS\"]}]`\n", + "```\n", + "\n", + "#### Salvando a saída\n", + "\n", + "Por padrão, a CLI do SavedModel grava a saída em stdout. Se um diretório for passado para a opção `--outdir`, as saídas serão salvas como arquivos `.npy` nomeados com base nas chaves do tensor de saída no diretório fornecido.\n", + "\n", + "Use `--overwrite` para sobrescrever arquivos de saída existentes.\n" + ] + } + ], + "metadata": { + "colab": { + "name": "saved_model.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/guide/tpu.ipynb b/site/pt-br/guide/tpu.ipynb new file mode 100644 index 0000000000..82dcd23d75 --- /dev/null +++ b/site/pt-br/guide/tpu.ipynb @@ -0,0 +1,623 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Tce3stUlHN0L" + }, + "source": [ + "##### Copyright 2018 The TensorFlow Authors.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tuOe1ymfHZPu" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MfBg1C5NB3X0" + }, + "source": [ + "# Use TPUs\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + "
Veja em TensorFlow.org Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ys81cOhXOWUP" + }, + "source": [ + "Este guia demonstra como realizar treinamento básico em [Unidades de Processamento de Tensores (TPUs)](https://cloud.google.com/tpu/) e TPU Pods, uma coleção de dispositivos de TPU conectados por interfaces de rede de alta velocidade dedicadas, com `tf.keras` e loops de treinamento personalizados.\n", + "\n", + "TPUs são circuitos integrados de aplicação específica (ASICs) desenvolvidos sob medida pelo Google e usados para acelerar as cargas de trabalho de aprendizado de máquina. Eles estão disponíveis no [Google Colab](https://colab.research.google.com/), [TPU Research Cloud](https://sites.research.google/trc/) e [Cloud TPU](https://cloud.google.com/tpu)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ek5Hop74NVKm" + }, + "source": [ + "## Configuração" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ebf7f8489bb7" + }, + "source": [ + "Antes de executar este notebook do Colab, confira se o acelerador de hardware é um TPU ao verificar as configurações do seu notebook: **Runtime** > **Change runtime type** > **Hardware accelerator** > **TPU**.\n", + "\n", + "Importe algumas bibliotecas necessárias, incluindo o TensorFlow Datasets:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Cw0WRaChRxTL" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "\n", + "import os\n", + "import tensorflow_datasets as tfds" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yDWaRxSpwBN1" + }, + "source": [ + "## Inicialização da TPU\n", + "\n", + "TPUs são tipicamente workers [da Cloud TPU](https://cloud.google.com/tpu/docs/), que são diferentes do processo local que executa o programa Python do usuário. Portanto, você precisa fazer algum trabalho de inicialização para conectar-se ao cluster remoto e inicializar as TPUs. Observe que o argumento `tpu` recebido por `tf.distribute.cluster_resolver.TPUClusterResolver` é um endereço especial apenas para o Colab. Se você estiver executando seu código no Google Compute Engine (GCE), deverá passar o nome do Cloud TPU." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dCqWMqvtwOLs" + }, + "source": [ + "Observação: O código de inicialização da TPU deve estar no início do seu programa." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dKPqF8d1wJCV" + }, + "outputs": [ + + ], + "source": [ + "resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='')\n", + "tf.config.experimental_connect_to_cluster(resolver)\n", + "# This is the TPU initialization code that has to be at the beginning.\n", + "tf.tpu.experimental.initialize_tpu_system(resolver)\n", + "print(\"All devices: \", tf.config.list_logical_devices('TPU'))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Mv7kehTZ1Lq_" + }, + "source": [ + "## Posicionamento manual dos dispositivos\n", + "\n", + "Depois que a TPU for inicializada, você poderá usar o posicionamento manual do dispositivo para colocar a computação num único dispositivo de TPU:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XRZ4kMoxBNND" + }, + "outputs": [ + + ], + "source": [ + "a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])\n", + "b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])\n", + "\n", + "with tf.device('/TPU:0'):\n", + " c = tf.matmul(a, b)\n", + "\n", + "print(\"c device: \", c.device)\n", + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_NJm-kgFO0cC" + }, + "source": [ + "## Estratégias de distribuição\n", + "\n", + "Geralmente você executará seu modelo em múltiplas TPUs de maneira paralela aos dados. Para distribuir seu modelo em múltiplas TPUs (assim como em múltiplas GPUs ou em múltiplas máquinas), o TensorFlow oferece a API `tf.distribute.Strategy`. Você pode substituir sua estratégia de distribuição e o modelo será executado em qualquer dispositivo (TPU). Saiba mais no guia [Treinamento distribuído com TensorFlow](./distributed_training.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DcDPMZs-9uLJ" + }, + "source": [ + "O uso da opção `tf.distribute.TPUStrategy` implementa treinamento distribuído síncrono. As TPUs fornecem sua própria implementação de operações all-reduce eficientes e outras operações coletivas em múltiplos cores de TPU, que são usados ​​na `TPUStrategy`.\n", + "\n", + "Para demonstrar isso, crie um objeto `tf.distribute.TPUStrategy`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7SO23K8oRpjI" + }, + "outputs": [ + + ], + "source": [ + "strategy = tf.distribute.TPUStrategy(resolver)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JlaAmswWPsU6" + }, + "source": [ + "Para replicar uma computação para que ela possa ser executada em todos os cores da TPU, você pode passá-la para a API `Strategy.run`. Abaixo está um exemplo que mostra todos os cores recebendo as mesmas entradas `(a, b)` e realizando multiplicação matricial em cada core de forma independente. As saídas serão os valores obtidos de todas as réplicas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-90CL5uFPTOa" + }, + "outputs": [ + + ], + "source": [ + "@tf.function\n", + "def matmul_fn(x, y):\n", + " z = tf.matmul(x, y)\n", + " return z\n", + "\n", + "z = strategy.run(matmul_fn, args=(a, b))\n", + "print(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uxgYl6kGHJLc" + }, + "source": [ + "## Classificação em TPUs\n", + "\n", + "Tendo coberto os conceitos básicos, considere um exemplo mais concreto. Esta seção demonstra como usar a estratégia de distribuição `tf.distribute.TPUStrategy`) para treinar um modelo Keras numa Cloud TPU." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gKRALGgt_kCo" + }, + "source": [ + "### Defina um modelo Keras\n", + "\n", + "Comece com uma definição de um [modelo `Sequential` Keras](https://www.tensorflow.org/guide/keras/sequential_model) para classificação de imagens no dataset MNIST. Não é diferente do que você usaria se estivesse treinando em CPUs ou GPUs. Observe que a criação do modelo Keras precisa estar dentro do `Strategy.scope`, para que as variáveis ​​possam ser criadas em cada dispositivo TPU. Outras partes do código não são necessárias para estarem dentro do escopo de `Strategy`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DiBiN-Z_R7P7" + }, + "outputs": [ + + ], + "source": [ + "def create_model():\n", + " regularizer = tf.keras.regularizers.L2(1e-5)\n", + " return tf.keras.Sequential(\n", + " [tf.keras.layers.Conv2D(256, 3, input_shape=(28, 28, 1),\n", + " activation='relu',\n", + " kernel_regularizer=regularizer),\n", + " tf.keras.layers.Conv2D(256, 3,\n", + " activation='relu',\n", + " kernel_regularizer=regularizer),\n", + " tf.keras.layers.Flatten(),\n", + " tf.keras.layers.Dense(256,\n", + " activation='relu',\n", + " kernel_regularizer=regularizer),\n", + " tf.keras.layers.Dense(128,\n", + " activation='relu',\n", + " kernel_regularizer=regularizer),\n", + " tf.keras.layers.Dense(10,\n", + " kernel_regularizer=regularizer)])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "h-2qaXgfyONQ" + }, + "source": [ + "Este modelo coloca os termos de regularização L2 nos pesos de cada camada, para que o loop de treinamento personalizado abaixo possa mostrar como obtê-los de `Model.losses`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qYOYjYTg_31l" + }, + "source": [ + "### Carregue o dataset\n", + "\n", + "O uso eficiente da API `tf.data.Dataset` é fundamental ao usar uma Cloud TPU. Você pode saber mais sobre o desempenho do dataset no [Guia de desempenho do pipeline de entrada](./data_performance.ipynb).\n", + "\n", + "Se você estiver usando [TPU Nodes](https://cloud.google.com/tpu/docs/managing-tpus-tpu-vm), precisará armazenar todos os arquivos de dados lidos pelo `Dataset` do TensorFlow nos [buckets do Google Cloud Storage (GCS)](https://cloud.google.com/tpu/docs/storage-buckets). Se você estiver usando [TPU VMs](https://cloud.google.com/tpu/docs/users-guide-tpu-vm), poderá armazenar dados onde quiser. Para mais informações sobre TPU Nodes e TPU VMs, consulte a documentação da [Arquitetura do Sistema TPU](https://cloud.google.com/tpu/docs/system-architecture-tpu-vm).\n", + "\n", + "Para a maioria dos casos de uso, é recomendado converter seus dados para o formato `TFRecord` e usar `tf.data.TFRecordDataset` para lê-los. Verifique o [tutorial sobre TFRecord e tf.Example](../tutorials/load_data/tfrecord.ipynb) para detalhes sobre como fazer isso. Não é um requisito difícil e você pode usar outros leitores de dataset, como `tf.data.FixedLengthRecordDataset` ou `tf.data.TextLineDataset`.\n", + "\n", + "Você pode carregar pequenos datasets inteiros na memória usando `tf.data.Dataset.cache`.\n", + "\n", + "Independentemente do formato de dados utilizado, é altamente recomendável usar arquivos grandes, da ordem de 100 MB. Isto é especialmente importante neste ambiente de rede, pois o overhead na abertura de um arquivo é significativamente maior.\n", + "\n", + "Conforme mostrado no código abaixo, você deve usar o módulo `tfds.load` do Tensorflow Datasets para obter uma cópia dos dados de treinamento e teste do MNIST. Observe que `try_gcs` é especificado para usar uma cópia que está disponível num bucket público do GCS. Se você não especificar isso, a TPU não poderá acessar os dados baixados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "noAd416KSCo7" + }, + "outputs": [ + + ], + "source": [ + "def get_dataset(batch_size, is_training=True):\n", + " split = 'train' if is_training else 'test'\n", + " dataset, info = tfds.load(name='mnist', split=split, with_info=True,\n", + " as_supervised=True, try_gcs=True)\n", + "\n", + " # Normalize the input data.\n", + " def scale(image, label):\n", + " image = tf.cast(image, tf.float32)\n", + " image /= 255.0\n", + " return image, label\n", + "\n", + " dataset = dataset.map(scale)\n", + "\n", + " # Only shuffle and repeat the dataset in training. The advantage of having an\n", + " # infinite dataset for training is to avoid the potential last partial batch\n", + " # in each epoch, so that you don't need to think about scaling the gradients\n", + " # based on the actual batch size.\n", + " if is_training:\n", + " dataset = dataset.shuffle(10000)\n", + " dataset = dataset.repeat()\n", + "\n", + " dataset = dataset.batch(batch_size)\n", + "\n", + " return dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mgUC6A-zCMEr" + }, + "source": [ + "### Treine o modelo usando APIs de alto nível do Keras\n", + "\n", + "Você pode treinar seu modelo com APIs Keras `Model.fit` e `Model.compile`. Não há nada específico de TPU nesta etapa – você escreve o código como se estivesse usando múltiplas GPUs e uma `MirroredStrategy` em vez de `TPUStrategy`. Você pode aprender mais no tutorial [Treinamento distribuído com Keras](../tutorials/distribute/keras.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ubmDchPqSIx0" + }, + "outputs": [ + + ], + "source": [ + "with strategy.scope():\n", + " model = create_model()\n", + " model.compile(optimizer='adam',\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['sparse_categorical_accuracy'])\n", + "\n", + "batch_size = 200\n", + "steps_per_epoch = 60000 // batch_size\n", + "validation_steps = 10000 // batch_size\n", + "\n", + "train_dataset = get_dataset(batch_size, is_training=True)\n", + "test_dataset = get_dataset(batch_size, is_training=False)\n", + "\n", + "model.fit(train_dataset,\n", + " epochs=5,\n", + " steps_per_epoch=steps_per_epoch,\n", + " validation_data=test_dataset,\n", + " validation_steps=validation_steps)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8hSGBIYtUugJ" + }, + "source": [ + "Para reduzir o overhead do Python e maximizar o desempenho da sua TPU, passe o argumento `steps_per_execution` para o Keras `Model.compile`. Neste exemplo, isto aumenta o rendimento em cerca de 50%:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "M6e3aVVLUorL" + }, + "outputs": [ + + ], + "source": [ + "with strategy.scope():\n", + " model = create_model()\n", + " model.compile(optimizer='adam',\n", + " # Anything between 2 and `steps_per_epoch` could help here.\n", + " steps_per_execution = 50,\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['sparse_categorical_accuracy'])\n", + "\n", + "model.fit(train_dataset,\n", + " epochs=5,\n", + " steps_per_epoch=steps_per_epoch,\n", + " validation_data=test_dataset,\n", + " validation_steps=validation_steps)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0rRALBZNCO4A" + }, + "source": [ + "### Treine o modelo usando um loop de treinamento personalizado\n", + "\n", + "Você também pode criar e treinar seu modelo usando as APIs `tf.function` e `tf.distribute` diretamente. Você pode usar a API `Strategy.experimental_distribute_datasets_from_function` para distribuir o `tf.data.Dataset` dada uma função de dataset. Observe que no exemplo abaixo o tamanho do lote passado para o `Dataset` é o tamanho do lote por réplica em vez do tamanho do lote global. Para saber mais, confira o tutorial [Treinamento personalizado com `tf.distribute.Strategy`](../tutorials/distribute/custom_training.ipynb).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DxdgXPAL6iFE" + }, + "source": [ + "Primeiro, crie o modelo, os datasets e as `tf.function`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9aHhqwao2Fxi" + }, + "outputs": [ + + ], + "source": [ + "# Create the model, optimizer and metrics inside the `tf.distribute.Strategy`\n", + "# scope, so that the variables can be mirrored on each device.\n", + "with strategy.scope():\n", + " model = create_model()\n", + " optimizer = tf.keras.optimizers.Adam()\n", + " training_loss = tf.keras.metrics.Mean('training_loss', dtype=tf.float32)\n", + " training_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(\n", + " 'training_accuracy', dtype=tf.float32)\n", + "\n", + "# Calculate per replica batch size, and distribute the `tf.data.Dataset`s\n", + "# on each TPU worker.\n", + "per_replica_batch_size = batch_size // strategy.num_replicas_in_sync\n", + "\n", + "train_dataset = strategy.experimental_distribute_datasets_from_function(\n", + " lambda _: get_dataset(per_replica_batch_size, is_training=True))\n", + "\n", + "@tf.function\n", + "def train_step(iterator):\n", + " \"\"\"The step function for one training step.\"\"\"\n", + "\n", + " def step_fn(inputs):\n", + " \"\"\"The computation to run on each TPU device.\"\"\"\n", + " images, labels = inputs\n", + " with tf.GradientTape() as tape:\n", + " logits = model(images, training=True)\n", + " per_example_loss = tf.keras.losses.sparse_categorical_crossentropy(\n", + " labels, logits, from_logits=True)\n", + " loss = tf.nn.compute_average_loss(per_example_loss)\n", + " model_losses = model.losses\n", + " if model_losses:\n", + " loss += tf.nn.scale_regularization_loss(tf.add_n(model_losses))\n", + "\n", + " grads = tape.gradient(loss, model.trainable_variables)\n", + " optimizer.apply_gradients(list(zip(grads, model.trainable_variables)))\n", + " training_loss.update_state(loss * strategy.num_replicas_in_sync)\n", + " training_accuracy.update_state(labels, logits)\n", + "\n", + " strategy.run(step_fn, args=(next(iterator),))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ibi7Z97V6xsQ" + }, + "source": [ + "Em seguida, execute o loop de treinamento:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1du5cXWt6Vtw" + }, + "outputs": [ + + ], + "source": [ + "steps_per_eval = 10000 // batch_size\n", + "\n", + "train_iterator = iter(train_dataset)\n", + "for epoch in range(5):\n", + " print('Epoch: {}/5'.format(epoch))\n", + "\n", + " for step in range(steps_per_epoch):\n", + " train_step(train_iterator)\n", + " print('Current step: {}, training loss: {}, training accuracy: {}%'.format(\n", + " optimizer.iterations.numpy(),\n", + " round(float(training_loss.result()), 4),\n", + " round(float(training_accuracy.result()) * 100, 2)))\n", + " training_loss.reset_states()\n", + " training_accuracy.reset_states()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TnZJUM3qIjKu" + }, + "source": [ + "### Melhorando o desempenho com múltiplos passos dentro de `tf.function`\n", + "\n", + "Você pode melhorar o desempenho executando múltiplos passos numa `tf.function`. Isso é conseguido empacotando a chamada `Strategy.run` com um `tf.range` dentro de `tf.function`, e o AutoGraph irá convertê-la num `tf.while_loop` no worker TPU. Você pode aprender mais sobre `tf.function` no guia Melhor desempenho com `tf.function`.\n", + "\n", + "Apesar do desempenho aprimorado, há vantagens e desvantagens nesse método em comparação com a execução de um único passo dentro de um `tf.function`. Executar vários passos em uma `tf.function` é menos flexível – você não pode executar coisas de forma eager ou código Python arbitrário dentro dos passos.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2grYvXLzJYkP" + }, + "outputs": [ + + ], + "source": [ + "@tf.function\n", + "def train_multiple_steps(iterator, steps):\n", + " \"\"\"The step function for one training step.\"\"\"\n", + "\n", + " def step_fn(inputs):\n", + " \"\"\"The computation to run on each TPU device.\"\"\"\n", + " images, labels = inputs\n", + " with tf.GradientTape() as tape:\n", + " logits = model(images, training=True)\n", + " per_example_loss = tf.keras.losses.sparse_categorical_crossentropy(\n", + " labels, logits, from_logits=True)\n", + " loss = tf.nn.compute_average_loss(per_example_loss)\n", + " model_losses = model.losses\n", + " if model_losses:\n", + " loss += tf.nn.scale_regularization_loss(tf.add_n(model_losses))\n", + " grads = tape.gradient(loss, model.trainable_variables)\n", + " optimizer.apply_gradients(list(zip(grads, model.trainable_variables)))\n", + " training_loss.update_state(loss * strategy.num_replicas_in_sync)\n", + " training_accuracy.update_state(labels, logits)\n", + "\n", + " for _ in tf.range(steps):\n", + " strategy.run(step_fn, args=(next(iterator),))\n", + "\n", + "# Convert `steps_per_epoch` to `tf.Tensor` so the `tf.function` won't get\n", + "# retraced if the value changes.\n", + "train_multiple_steps(train_iterator, tf.convert_to_tensor(steps_per_epoch))\n", + "\n", + "print('Current step: {}, training loss: {}, training accuracy: {}%'.format(\n", + " optimizer.iterations.numpy(),\n", + " round(float(training_loss.result()), 4),\n", + " round(float(training_accuracy.result()) * 100, 2)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WBKVhMvWjibf" + }, + "source": [ + "## Próximos passos\n", + "\n", + "Para saber mais sobre as Cloud TPUs e como usá-las, consulte:\n", + "\n", + "- [Google Cloud TPU](https://cloud.google.com/tpu): a página principal da Google Cloud TPU.\n", + "- [Documentação da Google Cloud TPU documentation](https://cloud.google.com/tpu/docs/): toda a documentação da Google Cloud TPU, que inclui:\n", + " - [Introdução à Cloud TPU](https://cloud.google.com/tpu/docs/intro-to-tpu): uma visão geral de como trabalhar com Cloud TPUs.\n", + " - [Guias de início rápido do Cloud TPU](https://cloud.google.com/tpu/docs/quick-starts): guias introdutórios de como trabalhar com VMs da Cloud TPU usando o TensorFlow e outros frameworks de machine learning.\n", + "- [Notebooks Colab do Google Cloud TPU](https://cloud.google.com/tpu/docs/colabs): exemplos de treinamento completo.\n", + "- [Guia de desempenho do Google Cloud TPU](https://cloud.google.com/tpu/docs/performance-guide): melhore ainda mais o desempenho do Cloud TPU ajustando os parâmetros de configuração do Cloud TPU para seu aplicativo\n", + "- [Treinamento distribuído com TensorFlow](./distributed_training.ipynb): como usar estratégias de distribuição, incluindo `tf.distribute.TPUStrategy`, com exemplos que mostram as práticas recomendadas.\n", + "- Embeddings de TPU: o TensorFlow inclui suporte especializado para treinamento de embeddings em TPUs por meio de `tf.tpu.experimental.embedding`. Além disso, o [TensorFlow Tecommenders](https://www.tensorflow.org/recommenders) possui `tfrs.layers.embedding.TPUEmbedding`. Os embeddings fornecem representações eficientes e densas, capturando similaridades e relacionamentos complexos entre características. O suporte a embeddings específicos para TPU do TensorFlow permite treinar embeddings maiores que a memória de um único dispositivo TPU e usar entradas esparsas e irregulares em TPUs.\n", + "- [TPU Research Cloud (TRC)](https://sites.research.google/trc/about/): o TRC permite que pesquisadores solicitem acesso a um cluster de mais de 1.000 dispositivos Cloud TPU.\n" + ] + } + ], + "metadata": { + "accelerator": "TPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "tpu.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/guide/versions.md b/site/pt-br/guide/versions.md new file mode 100644 index 0000000000..85804bcc2c --- /dev/null +++ b/site/pt-br/guide/versions.md @@ -0,0 +1,202 @@ +# Compatibilidade das versões do TensorFlow + +Este documento é para usuários que precisam da compatibilidade com versões anteriores em diferentes versões do TensorFlow (seja para código ou dados) e para desenvolvedores que querem modificar o TensorFlow enquanto preservam a compatibilidade. + +## Versionamento Semântico 2.0 + +O TensorFlow segue o Versionamento Semântico 2.0 ([semver](http://semver.org)) para a API pública. Cada versão do TensorFlow tem o formato `MAJOR.MINOR.PATCH`. Por exemplo, a versão 1.2.3 do TensorFlow tem a versão 1 `MAJOR`, versão 2 `MINOR` e versão 3 `PATCH`. As mudanças em cada número tem o seguinte significado: + +- **MAJOR**: mudanças possivelmente incompatíveis com versões anteriores. O código e os dados que funcionavam com uma versão major anterior não funcionarão necessariamente com a nova versão. No entanto, em alguns casos, os grafos e checkpoints existentes do TensorFlow podem ser migrados para a versão mais recente. Confira mais detalhes sobre a compatibilidade de dados em [Compatibilidade de grafos e checkpoints](#compatibility_of_graphs_and_checkpoints). + +- **MINOR**: recursos compatíveis com versões anteriores, melhorias na velocidade etc. O código e os dados que funcionavam com uma versão minor anterior *e* que dependiam apenas da API pública não experimental continuarão a funcionar sem alterações. Para saber mais sobre o que é ou não a API pública, confira [O que está coberto](#what_is_covered). + +- **PATCH**: correções de bugs compatíveis com versões anteriores. + +Por exemplo, a versão 1.0.0 apresentou mudanças *incompatíveis* com versões anteriores a partir da versão 0.12.1. No entanto, a versão 1.1.1 era *compatível* com a versão 1.0.0. + +## O que está coberto + +Somente as APIs públicas do TensorFlow são compatíveis com versões anteriores minor e patch. As APIs públicas consistem em: + +- Todas as funções e classes documentadas do [Python](https://www.tensorflow.org/api_docs/python) no módulo e submódulos do `tensorflow`, com exceção de + + - Símbolos particulares: qualquer função, classe, entre outros, cujo nome comece com `_` + - Símbolos experimentais e `tf.contrib`, confira mais detalhes [abaixo](#not_covered). + + Observe que o código nos diretórios `examples/` e `tools/` não pode ser alcançado pelo módulo `tensorflow` do Python. Portanto, não é coberto pela garantia de compatibilidade. + + Se um símbolo estiver disponível pelo módulo ou submódulos do `tensorflow` do Python, mas não estiver documentado, então ele **não** será considerado parte da API pública. + +- A API de compatibilidade (no Python, o módulo `tf.compat`). Em versões major, podemos lançar utilitários e endpoints adicionais para ajudar os usuários com a transição para uma nova versão major. Esses símbolos de API foram descontinuados e não são compatíveis (ou seja, não vamos adicionar recursos nem corrigir bugs além das vulnerabilidades), mas eles são abarcados pelas nossas garantias de compatibilidade. + +- A API C do TensorFlow: + + - [tensorflow/c/c_api.h](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h)) + +- A API C do TensorFlow Lite: + + - [tensorflow/lite/c/c_api.h](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/c_api.h) + - [tensorflow/lite/c/c_api_types.h](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/c_api_types.h). + +- Os seguintes arquivos de buffer de protocolo: + + - [`attr_value`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/attr_value.proto) + - [`config`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/protobuf/config.proto) + - [`event`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/util/event.proto) + - [`graph`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/graph.proto) + - [`op_def`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/op_def.proto) + - [`reader_base`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/reader_base.proto) + - [`summary`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/summary.proto) + - [`tensor`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/tensor.proto) + - [`tensor_shape`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/tensor_shape.proto) + - [`types`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/types.proto) + + + +## O que *não* está coberto + +Algumas partes do TensorFlow podem mudar de maneiras incompatíveis com versões anteriores a qualquer momento. Isso incluem: + +- **APIs experimentais**: para facilitar o desenvolvimento, isentamos alguns símbolos de API claramente marcados como experimentais das garantias de compatibilidade. Especificamente, o seguinte não é coberto por quaisquer garantias de compatibilidade: + + - qualquer símbolo no módulo ou submódulos do `tf.contrib`; + - qualquer símbolo (módulo, função, argumento, propriedade, classe ou constante) cujo nome contém `experimental` ou `Experimental`; ou + - qualquer símbolo cujo nome totalmente qualificado inclui um módulo ou uma classe que é experimental. Isso inclui campos e submensagens de qualquer buffer de protocolo chamado `experimental`. + +- **Outras linguagens**: as APIs TensorFlow em linguagens diferentes do Python e C, como: + + - [C++](../install/lang_c.ipynb) (exposta através de arquivos de cabeçalho em [`tensorflow/cc`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/cc)) + - [Java](../install/lang_java_legacy.md) + - [Go](https://github.com/tensorflow/build/blob/master/golang_install_guide/README.md) + - [JavaScript](https://www.tensorflow.org/js) + +- **Detalhes das operações compostas:** várias funções públicas no Python expandem para diversas operações primitivas no grafo, e esses detalhes farão parte de quaisquer grafos salvos no disco como `GraphDef`s. Esses detalhes podem mudar para versões minor. Especialmente, testes de regressão que verificam a correspondência exata entre grafos tendem a perder a compatibilidade entre versões minor, mesmo que o comportamento do grafo não seja alterado e os checkpoints existentes ainda funcionem. + +- **Detalhes numéricos de ponto flutuante:** os valores de ponto flutuante específicos computados pelas operações podem mudar a qualquer momento. Os usuários devem contar somente com a exatidão aproximada e a estabilidade numérica, e não os bits específicos computados. As mudanças nas fórmulas numéricas em versões minor e patch devem resultar em exatidão comparável ou melhorada, com a ressalva de que a melhoria na exatidão de determinadas fórmulas no aprendizado de máquina pode resultar em menor exatidão do sistema em geral. + +- **Números aleatórios:** os números aleatórios específicos computados podem mudar a qualquer momento. Os usuários devem contar apenas com as distribuições aproximadamente corretas e o poder estatístico, e não com os bits específicos computados. Confira mais detalhes em [geração de números aleatórios](random_numbers.ipynb). + +- **Desvio de versão no Tensorflow distribuído:** a execução de duas versões diferentes do TensorFlow em um único cluster não é compatível. Não há garantias de compatibilidade do wire protocol com versões anteriores. + +- **Bugs:** reservamos o direito de fazer alterações incompatíveis com versões anteriores no comportamento (embora não na API) se a implementação atual estiver claramente quebrada, ou seja, se contradiz a documentação ou se um comportamento pretendido que é bem definido e conhecido não for implementado corretamente devido a um bug. Por exemplo, se um otimizador afirma implementar um algoritmo de otimização bem conhecido, mas não corresponde a esse algoritmo devido a um bug, vamos corrigir o otimizador. Nossa correção pode quebrar o código que depende do comportamento errado para convergência. Vamos apontar essas mudanças nas notas da versão. + +- **API não utilizada:** reservamos o direito de realizar mudanças incompatíveis com versões anteriores nas APIs que não tiverem usos documentados (ao realizar auditoria do uso do TensorFlow pela pesquisa do GitHub). Antes de fazer essas alterações, vamos anunciar nossa intenção de fazer as mudanças na [lista de e-mails announce@](https://groups.google.com/a/tensorflow.org/forum/#!forum/announce), fornecendo instruções de como resolver qualquer quebra (se aplicável), e vamos esperar duas semanas para dar à comunidade a chance de compartilhar feedback. + +- **Comportamento do erro:** podemos substituir erros pelo comportamento não errado. Por exemplo, podemos mudar uma função para computar um resultado em vez de gerar um erro, mesmo se esse erro estiver documentado. Também reservamos o direito de mudar o texto das mensagens de erro. Além disso, o tipo de um erro pode mudar, a menos que o tipo de exceção para uma determinada condição de erro seja especificado na documentação. + + + +## Compatibilidade de SavedModels, grafos e checkpoints + +O SavedModel é o formato de serialização preferencial para o uso nos programas do TensorFlow. O SavedModel contém duas partes: um ou mais grafos codificados como `GraphDefs` e um Checkpoint. Os grafos descrevem os fluxos de dados de operações a serem executadas, e os checkpoints contêm os valores de tensor salvos das variáveis em um grafo. + +Vários usuários do TensorFlow criam SavedModels e os carregam e executam com uma versão mais recente do TensorFlow. Em conformidade com o [semver](https://semver.org), os SavedModels escritos com uma versão do TensorFlow podem ser carregados e avaliados com uma versão mais recente do TensorFlow com o mesmo major. + +Fazemos garantias adicionais para SavedModels *compatíveis*. Chamamos um SavedModel que foi criado usando **apenas APIs não compatíveis, não descontinuadas e não experimentais** na versão major `N` do TensorFlow um SavedModel compatível com a versão `N`. Qualquer SavedModel compatível com a versão major `N` do TensorFlow pode ser carregado e executado com a versão major `N+1` do TensorFlow. No entanto, a funcionalidade necessária para criar ou modificar esse modelo pode não estar mais disponível, então essa garantia só se aplica ao SavedModel não modificado. + +Vamos nos empenhar para preservar a compatibilidade com versões anteriores o máximo possível, para que os arquivos serializados possam ser utilizados por um longo período. + +### Compatibilidade de GraphDef + +Os grafos são serializados pelo buffer de protocolo `GraphDef`. Para facilitar as mudanças incompatíveis com as versões anteriores nos grafos, cada `GraphDef` tem um número de versão separado da versão do TensorFlow. Por exemplo, a versão 17 do `GraphDef` descontinuou a operação `inv` em favor de `reciprocal`. A semântica é esta: + +- Cada versão do TensorFlow é compatível com um intervalo de versões do `GraphDef`. Esse intervalo será constante em versões patch e só crescerá em versões minor. A interrupção do suporte para uma versão `GraphDef` só ocorrerá para uma versão major do TensorFlow (e apenas alinhado ao suporte com a versão garantido para SavedModels). + +- Os grafos criados recentemente são atribuídos ao número de versão mais recente do `GraphDef`. + +- Se uma determinada versão do TensorFlow for compatível com a versão `GraphDef` de um grafo, ela carregará e avaliará com o mesmo comportamento que a versão do TensorFlow usada na geração dela (exceto para detalhes numéricos de ponto flutuante e números aleatórios, conforme descrito acima), independentemente da versão major do TensorFlow. Especialmente, um GraphDef compatível com um arquivo de checkpoint em uma versão do TensorFlow (como é o caso em um SavedModel) permanecerá compatível com esse checkpoint em versões subsequentes, enquanto o GraphDef for compatível. + + Observe que isso se aplica apenas a grafos serializados em GraphDefs (e SavedModels): o *código* que lê um checkpoint talvez não consiga ler checkpoints gerados pelo mesmo código que executa uma versão diferente do TensorFlow. + +- Se o limite *superior* do `GraphDef` for aumentado para X em uma versão (minor), o limite *inferior* será aumentado para X no mínimo seis meses depois. Por exemplo (estamos usando números de versões hipotéticas aqui): + + - O TensorFlow 1.2 talvez seja compatível com as versões 4 a 7 do `GraphDef`. + - O TensorFlow 1.3 poderia adicionar a versão 8 do `GraphDef` e oferecer suporte às versões 4 a 8. + - Pelo menos seis meses depois, o TensorFlow 2.0.0 poderia interromper o suporte para as versões 4 a 7, deixando apenas a versão 8. + + Como as versões major do TensorFlow são geralmente publicadas com mais de 6 meses de intervalo, as garantias para os SavedModels compatíveis detalhados acima são muito mais fortes do que a garantia de 6 meses para GraphDefs. + +Por fim, quando o suporte a uma versão do `GraphDef` é interrompido, vamos tentar oferecer ferramentas para converter automaticamente os grafos para uma versão mais recente do `GraphDef` compatível. + +## Compatibilidade de grafos e checkpoints ao estender o TensorFlow + +Esta seção só é relevante ao fazer alterações incompatíveis com o formato `GraphDef`, como ao adicionar operações, remover operações ou mudar a funcionalidade de operações existentes. A seção anterior deve bastar para a maioria dos usuários. + + + +### Compatibilidade total com versões anteriores e parcial com versões futuras + +Nosso esquema de versionamento tem três requisitos: + +- **Compatibilidade com versões anteriores** para dar suporte ao carregamento de grafos e checkpoints criados com versões mais antigas do TensorFlow. +- **Compatibilidade com versões futuras** para dar suporte aos cenários em que o produtor de um grafo ou checkpoint faz upgrade para uma versão mais recente do TensorFlow antes do consumidor. +- Evolução do TensorFlow de maneiras incompatíveis. Por exemplo, removendo operações e adicionando ou removendo atributos. + +Embora o mecanismo de versão do `GraphDef` seja separado da versão do TensorFlow, as mudanças incompatíveis com versões anteriores no formato `GraphDef` ainda estão restritas ao Versionamento Semântico. Isso significa que a funcionalidade só pode ser removida ou alterada entre as versões `MAJOR` do TensorFlow (como `1.7` a `2.0`). Além disso, a compatibilidade com versões futuras é aplicada nas versões Patch (`1.x.1` a `1.x.2`, por exemplo). + +Para atingir a compatibilidade com versões anteriores e futuras e para saber quando aplicar as mudanças nos formatos, os grafos e checkpoints têm metadados que descrevem quando foram produzidos. As seções abaixo detalham a implementação e as diretrizes do TensorFlow para a evolução das versões do `GraphDef`. + +### Esquemas de versões de dados independentes + +Há diferentes versões de dados para grafos e checkpoints. Os dois formatos de dados evoluem a taxas diferentes em comparação com um ao outro e também com o TensorFlow. Os dois sistemas de versionamento são definidos em [`core/public/version.h`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/public/version.h). Quando uma nova versão é adicionada, uma nota é incluída no cabeçalho detalhando as alterações e a data. + +### Dados, produtores e consumidores + +Distinguimos entre os seguintes tipos de informações sobre as versões dos dados: + +- **produtores**: binários que produzem dados. Os produtores têm uma versão (`producer`) e são compatíveis com uma versão de consumidor mínima (`min_consumer`). +- **consumidores**: binários que consomem dados. Os consumidores têm uma versão (`consumer`) e são compatíveis com uma versão de produtor mínima (`min_producer`). + +Cada parte dos dados versionados tem um campo [`VersionDef versions`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/versions.proto) que registra o `producer` que criou os dados, o `min_consumer` compatível e a lista de versões `bad_consumers` proibidas. + +Por padrão, quando um produtor cria alguns dados, os dados herdam as versões `producer` e `min_consumer` do produtor. `bad_consumers` pode ser definido se versões do consumidor específicas tiverem bugs conhecidos e precisarem ser evitadas. Um consumidor pode aceitar alguns dados se todas as afirmações a seguir forem verdadeiras. + +- `consumer` >= `min_consumer` dos dados +- `producer` dos dados >= `min_producer` do consumidor +- `consumer` não está no `bad_consumers` dos dados + +Como ambos os produtores e consumidores vêm da mesma base de código do TensorFlow, [`core/public/version.h`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/public/version.h) contém uma versão de dados principal que é tratada como `producer` ou `consumer` dependendo do contexto, além de ambas as versões `min_consumer` e `min_producer` (exigidas por produtores e consumidores, respectivamente). Especificamente, + +- Para versões `GraphDef`, temos `TF_GRAPH_DEF_VERSION`, `TF_GRAPH_DEF_VERSION_MIN_CONSUMER` e `TF_GRAPH_DEF_VERSION_MIN_PRODUCER`. +- Para versões de checkpoint, temos `TF_CHECKPOINT_VERSION`, `TF_CHECKPOINT_VERSION_MIN_CONSUMER` e `TF_CHECKPOINT_VERSION_MIN_PRODUCER`. + +### Adicione um novo atributo com uma operação existente como padrão + +Seguindo as orientações abaixo, você só alcança a compatibilidade com versões futuras se o conjunto de operações não tiver mudado: + +1. Se você desejar a compatibilidade com versões futuras, defina `strip_default_attrs` como `True` ao exportar o modelo usando os métodos `tf.saved_model.SavedModelBuilder.add_meta_graph_and_variables` e `tf.saved_model.SavedModelBuilder.add_meta_graph` da classe `SavedModelBuilder` ou `tf.estimator.Estimator.export_saved_model` +2. Isso retira os atributos de valor padrão no momento de produção/exportação dos modelos, garantindo que `tf.MetaGraphDef` não contenha o novo op-attribute quando o valor padrão é usado. +3. Ter esse controle pode permitir que consumidores desatualizados (por exemplo, que veiculam binários com atraso em relação aos binários de treinamento) continuem carregando modelos e evitem interrupções na veiculação do modelo. + +### Evolução das versões do GraphDef + +Esta seção explica como usar esse mecanismo de versionamento para fazer diferentes tipos de mudanças no formato `GraphDef`. + +#### Adicione uma operação + +Adicione a nova operação a ambos os consumidores e produtores ao mesmo tempo e não mude qualquer versão do `GraphDef`. Esse tipo de mudança é automaticamente compatível com versões anteriores e não afeta o plano de compatibilidade com as versões futuras, já que os scripts de produtores existentes não usarão a nova funcionalidade de repente. + +#### Adicione uma operação e faça com que seja usada pelos wrappers existentes do Python + +1. Implemente a nova funcionalidade de consumidor e incremente a versão do `GraphDef`. +2. Se for possível fazer os wrappers usarem a nova funcionalidade apenas em casos que não funcionavam antes, os wrappers podem ser atualizados agora. +3. Altere os wrappers do Python para que usem a nova funcionalidade. Não incremente `min_consumer`, já que os modelos que não usam essa operação não devem quebrar. + +#### Remova ou restrinja a funcionalidade de uma operação + +1. Corrija todos os scripts (e não o próprio TensorFlow) para que não usem a operação ou funcionalidade banida. +2. Incremente a versão do `GraphDef` e implemente uma nova funcionalidade de consumidor para banir a operação ou funcionalidade removida para GraphDefs na versão nova e mais recente. Se possível, faça com que o TensorFlow pare de produzir `GraphDefs` com a funcionalidade banida. Para isso, adicione [`REGISTER_OP(...).Deprecated(deprecated_at_version, message)`](https://github.com/tensorflow/tensorflow/blob/b289bc7a50fc0254970c60aaeba01c33de61a728/tensorflow/core/ops/array_ops.cc#L1009). +3. Aguarde uma versão major para fins de compatibilidade com versões anteriores. +4. Aumente `min_producer` para a versão do GraphDef de (2) e remova toda a funcionalidade. + +#### Mude a funcionalidade de uma operação + +1. Adicione uma nova operação parecida com o nome `SomethingV2` ou algo semelhante e passe pelo processo de adicioná-la e fazer com que seja usada pelos wrappers existentes do Python. Para garantir a compatibilidade com versões futuras, use as verificações sugeridas em [compat.py](https://www.tensorflow.org/code/tensorflow/python/compat/compat.py) ao mudar os wrappers do Python. +2. Remova a operação antiga (só pode ser feito com a mudança em uma versão major devido à compatibilidade com versões anteriores). +3. Aumente `min_consumer` para descartar consumidores com a operação antiga, adicione a operação antiga de volta como um alias para `SomethingV2` e faça com que ela seja usada pelos wrappers existentes do Python. +4. Conclua o processo de remoção de `SomethingV2`. + +#### Proíba uma única versão de consumidor arriscada + +1. Eleve a versão `GraphDef` e adicione a versão ruim a `bad_consumers` para todos os novos GraphDefs. Se possível, adicione a `bad_consumers` somente para GraphDefs que contém uma operação específica ou semelhante. +2. Se os consumidores existentes têm a versão ruim, eles devem ser migrados assim que possível. diff --git a/site/pt-br/lite/android/delegates/gpu.md b/site/pt-br/lite/android/delegates/gpu.md new file mode 100644 index 0000000000..16b21d4a12 --- /dev/null +++ b/site/pt-br/lite/android/delegates/gpu.md @@ -0,0 +1,212 @@ +# Delegado de aceleração de GPU com a API Interpreter + +O uso de unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho a experiência do usuário dos seus aplicativos com tecnologia de ML. Nos dispositivos Android, você pode ativar + +o [*delegado*](../../performance/delegates) e uma das seguintes APIs: + +- API Interpreter - este guia +- API Biblioteca Task - [guia](./gpu_task) +- API nativa (C/C++) - [guia](./gpu_native) + +Esta página descreve como ativar a aceleração de GPU para os modelos do TensorFlow Lite nos apps Android usando a API Interpreter. Para mais informações sobre como usar o delegado de GPU para o TensorFlow Lite, incluindo práticas recomendadas e técnicas avançadas, confira a página [delegados de GPU](../../performance/gpu). + +## Use a GPU com o TensorFlow Lite e o Google Play Services + +A [API Interpreter](https://tensorflow.org/lite/api_docs/java/org/tensorflow/lite/InterpreterApi) do TensorFlow Lite fornece um conjunto de APIs de uso geral para criar aplicativos de aprendizado de máquina. Esta seção descreve como usar o delegado acelerador de GPU com essas APIs usando o TensorFlow Lite com o Google Play Services. + +O [TensorFlow com o Google Play Services](../play_services) é o método recomendado para usar o TensorFlow Lite no Android. Se o seu aplicativo segmentar dispositivos que não executam o Google Play, confira a seção [GPU com a API Interpreter e o TensorFlow Lite standalone](#standalone). + +### Adicione as dependências do projeto + +Para habilitar o acesso ao delegado de GPU, adicione `com.google.android.gms:play-services-tflite-gpu` ao arquivo `build.gradle` do seu aplicativo: + +``` +dependencies { + ... + implementation 'com.google.android.gms:play-services-tflite-java:16.0.1' + implementation 'com.google.android.gms:play-services-tflite-gpu:16.1.0' +} +``` + +### Ative a aceleração de GPU + +Em seguida, inicialize o TensorFlow Lite com o Google Play Services e o suporte à GPU: + +
+ +
+

Kotlin

+

+
    val useGpuTask = TfLiteGpu.isGpuDelegateAvailable(context)
+
+    val interpreterTask = useGpuTask.continueWith { useGpuTask ->
+      TfLite.initialize(context,
+          TfLiteInitializationOptions.builder()
+          .setEnableGpuDelegateSupport(useGpuTask.result)
+          .build())
+      }
+      
+
+
+

Java

+

+
    Task<boolean> useGpuTask = TfLiteGpu.isGpuDelegateAvailable(context);
+
+    Task<Options> interpreterOptionsTask = useGpuTask.continueWith({ task ->
+      TfLite.initialize(context,
+      TfLiteInitializationOptions.builder()
+        .setEnableGpuDelegateSupport(true)
+        .build());
+    });
+      
+
+
+
+ +Por fim, você pode inicializar o interpretador passando um `GpuDelegateFactory` pelo `InterpreterApi.Options`: + +
+ +
+

Kotlin

+

+
+    val options = InterpreterApi.Options()
+      .setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+      .addDelegateFactory(GpuDelegateFactory())
+
+    val interpreter = InterpreterApi(model, options)
+
+    // Run inference
+    writeToInput(input)
+    interpreter.run(input, output)
+    readFromOutput(output)
+      
+
+
+

Java

+

+
+    Options options = InterpreterApi.Options()
+      .setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+      .addDelegateFactory(new GpuDelegateFactory());
+
+    Interpreter interpreter = new InterpreterApi(model, options);
+
+    // Run inference
+    writeToInput(input);
+    interpreter.run(input, output);
+    readFromOutput(output);
+      
+
+
+
+ +Observação: o delegado de GPU precisa ser criado no mesmo thread que o executa. Caso contrário, você pode ver o seguinte erro: `TfLiteGpuDelegate Invoke: GpuDelegate must run on the same thread where it was initialized` (GpuDelegate precisa ser executado no mesmo thread em que foi inicializado). + +O delegado de GPU também pode ser usado com a vinculação de modelo de ML no Android Studio. Para mais informações, consulte [Gere interfaces de modelo usando metadados](../../inference_with_metadata/codegen#acceleration). + +## Use a GPU com o TensorFlow Lite standalone {:#standalone} + +Se o seu aplicativo segmentar dispositivos que não executam o Google Play, é possível empacotar o delegado de GPU com seu aplicativo e usá-lo com a versão standalone do TensorFlow Lite. + +### Adicione as dependências do projeto + +Para habilitar o acesso ao delegado de GPU, adicione `org.tensorflow:tensorflow-lite-gpu-delegate-plugin` ao arquivo `build.gradle` do seu aplicativo: + +``` +dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite' + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +### Ative a aceleração de GPU + +Em seguida, execute o TensorFlow Lite na GPU com `TfLiteDelegate`. No Java, você pode especificar o `GpuDelegate` pelo `Interpreter.Options`. + +
+ +
+

Kotlin

+

+
      import org.tensorflow.lite.Interpreter
+      import org.tensorflow.lite.gpu.CompatibilityList
+      import org.tensorflow.lite.gpu.GpuDelegate
+
+      val compatList = CompatibilityList()
+
+      val options = Interpreter.Options().apply{
+          if(compatList.isDelegateSupportedOnThisDevice){
+              // if the device has a supported GPU, add the GPU delegate
+              val delegateOptions = compatList.bestOptionsForThisDevice
+              this.addDelegate(GpuDelegate(delegateOptions))
+          } else {
+              // if the GPU is not supported, run on 4 threads
+              this.setNumThreads(4)
+          }
+      }
+
+      val interpreter = Interpreter(model, options)
+
+      // Run inference
+      writeToInput(input)
+      interpreter.run(input, output)
+      readFromOutput(output)
+      
+
+
+

Java

+

+
      import org.tensorflow.lite.Interpreter;
+      import org.tensorflow.lite.gpu.CompatibilityList;
+      import org.tensorflow.lite.gpu.GpuDelegate;
+
+      // Initialize interpreter with GPU delegate
+      Interpreter.Options options = new Interpreter.Options();
+      CompatibilityList compatList = CompatibilityList();
+
+      if(compatList.isDelegateSupportedOnThisDevice()){
+          // if the device has a supported GPU, add the GPU delegate
+          GpuDelegate.Options delegateOptions = compatList.getBestOptionsForThisDevice();
+          GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions);
+          options.addDelegate(gpuDelegate);
+      } else {
+          // if the GPU is not supported, run on 4 threads
+          options.setNumThreads(4);
+      }
+
+      Interpreter interpreter = new Interpreter(model, options);
+
+      // Run inference
+      writeToInput(input);
+      interpreter.run(input, output);
+      readFromOutput(output);
+      
+
+
+
+ +### Modelos quantizados {:#quantized-models} + +As bibliotecas de delegados GPU do Android são compatíveis com os modelos quantizados por padrão. Você não precisa fazer nenhuma alteração no código para usar modelos quantizados com o delegado de GPU. A seção a seguir explica como desativar o suporte quantizado para testes ou fins experimentais. + +#### Desative o suporte ao modelo quantizado + +O código a seguir mostra como ***desativar*** o suporte a modelos quantizados. + +
+ +
+

Java

+

+
GpuDelegate delegate = new GpuDelegate(new GpuDelegate.Options().setQuantizedModelsAllowed(false));
+
+Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
+      
+
+
+
+ +Para mais informações sobre como executar modelos quantizados com a aceleração de GPU, confira a visão geral do [delegado de GPU](../../performance/gpu#quantized-models). diff --git a/site/pt-br/lite/android/delegates/gpu_native.md b/site/pt-br/lite/android/delegates/gpu_native.md new file mode 100644 index 0000000000..cc0916fd2f --- /dev/null +++ b/site/pt-br/lite/android/delegates/gpu_native.md @@ -0,0 +1,70 @@ +# Delegado de aceleração de GPU com a API C/C++ + +O uso de unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho e a experiência do usuário dos seus aplicativos com tecnologia de ML. Nos dispositivos Android, você pode ativar a execução dos seus modelos com a aceleração de GPU usando um [*delegado*](../../performance/delegates) e uma das seguintes APIs: + +- API Interpreter - [guia](./gpu) +- API Biblioteca Task - [guia](./gpu_task) +- API nativa (C/C++) - este guia + +Este guia aborda os usos avançados do delegado de GPU para a API C e C++, além do uso de modelos quantizados. Para mais informações sobre como usar o delegado de GPU para o TensorFlow Lite, incluindo práticas recomendadas e técnicas avançadas, confira a página [delegados de GPU](../../performance/gpu). + +## Ative a aceleração de GPU + +Use o delegado de GPU do TensorFlow Lite para Android em C ou C++ ao criar o delegado com `TfLiteGpuDelegateV2Create()` e o destruir com `TfLiteGpuDelegateV2Delete()`, conforme mostrado no código de exemplo a seguir: + +```c++ +// Set up interpreter. +auto model = FlatBufferModel::BuildFromFile(model_path); +if (!model) return false; +ops::builtin::BuiltinOpResolver op_resolver; +std::unique_ptr interpreter; +InterpreterBuilder(*model, op_resolver)(&interpreter); + +// NEW: Prepare GPU delegate. +auto* delegate = TfLiteGpuDelegateV2Create(/*default options=*/nullptr); +if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false; + +// Run inference. +WriteToInputTensor(interpreter->typed_input_tensor(0)); +if (interpreter->Invoke() != kTfLiteOk) return false; +ReadFromOutputTensor(interpreter->typed_output_tensor(0)); + +// NEW: Clean up. +TfLiteGpuDelegateV2Delete(delegate); +``` + +Revise o código do objeto `TfLiteGpuDelegateOptionsV2` para criar uma instância de delegado com opções personalizadas. Você pode inicializar as opções padrão com `TfLiteGpuDelegateOptionsV2Default()` e, em seguida, modificá-las conforme necessário. + +O delegado de GPU do TensorFlow Lite para Android em C ou C++ usa o sistema de build [Bazel](https://bazel.io). Você pode compilar o delegado usando o comando a seguir: + +```sh +bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:delegate # for static library +bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:libtensorflowlite_gpu_delegate.so # for dynamic library +``` + +Ao chamar `Interpreter::ModifyGraphWithDelegate()` ou `Interpreter::Invoke()`, o autor da chamada precisa ter um `EGLContext` no thread atual, e `Interpreter::Invoke()` precisa ser chamado do mesmo `EGLContext`. Se não houver um `EGLContext`, o delegado cria um internamente, mas, depois, você precisará garantir que `Interpreter::Invoke()` seja sempre chamado do mesmo thread em que `Interpreter::ModifyGraphWithDelegate()` foi chamado. + +## Modelos quantizados {:#quantized-models} + +As bibliotecas de delegados GPU do Android são compatíveis com os modelos quantizados por padrão. Você não precisa fazer nenhuma alteração no código para usar modelos quantizados com o delegado de GPU. A seção a seguir explica como desativar o suporte quantizado para testes ou fins experimentais. + +#### Desative o suporte ao modelo quantizado + +O código a seguir mostra como ***desativar*** o suporte a modelos quantizados. + +
+ +
+

C++

+

+
TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
+options.experimental_flags = TFLITE_GPU_EXPERIMENTAL_FLAGS_NONE;
+
+auto* delegate = TfLiteGpuDelegateV2Create(options);
+if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
+      
+
+
+
+ +Para mais informações sobre como executar modelos quantizados com a aceleração de GPU, confira a visão geral do [delegado de GPU](../../performance/gpu#quantized-models). diff --git a/site/pt-br/lite/android/delegates/gpu_task.md b/site/pt-br/lite/android/delegates/gpu_task.md new file mode 100644 index 0000000000..fc9ad92e67 --- /dev/null +++ b/site/pt-br/lite/android/delegates/gpu_task.md @@ -0,0 +1,130 @@ +# Delegado de aceleração de GPU com a Biblioteca Task + +O uso de unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho e a experiência do usuário dos seus aplicativos com tecnologia de ML. Nos dispositivos Android, você pode ativar a execução dos seus modelos com a aceleração de GPU usando um [*delegado*](../../performance/delegates) e uma das seguintes APIs: + +- API Interpreter - [guia](./gpu) +- API Biblioteca Task - este guia +- API nativa (C/C++) - [guia](./gpu_native) + +Esta página descreve como ativar a aceleração de GPU para os modelos do TensorFlow Lite nos apps Android usando a Biblioteca Task. Para mais informações sobre como usar o delegado de GPU para o TensorFlow Lite, incluindo práticas recomendadas e técnicas avançadas, confira a página [delegados de GPU](../../performance/gpu). + +## Use a GPU com o TensorFlow Lite e o Google Play Services + +As [Task Libraries](../../inference_with_metadata/task_library/overview) do TensorFlow Lite fornecem um conjunto de APIs específicas a tarefas para criar aplicativos de aprendizado de máquina. Esta seção descreve como usar o delegado acelerador de GPU com essas APIs usando o TensorFlow Lite com o Google Play Services. + +O [TensorFlow com o Google Play Services](../play_services) é o método recomendado para usar o TensorFlow Lite no Android. Se o seu aplicativo segmentar dispositivos que não executam o Google Play, confira a seção [GPU com a Biblioteca Task e o TensorFlow Lite standalone](#standalone). + +### Adicione as dependências do projeto + +Para habilitar o acesso ao delegado de GPU com as Task Libraries do TensorFlow usando o Google Play Services, adicione `com.google.android.gms:play-services-tflite-gpu` às dependências do arquivo `build.gradle` do seu aplicativo: + +``` +dependencies { + ... + implementation 'com.google.android.gms:play-services-tflite-gpu:16.0.0' +} +``` + +### Ative a aceleração de GPU + +Em seguida, verifique de maneira assíncrona se o delegado de GPU está disponível para o dispositivo usando a classe [`TfLiteGpu`](https://developers.google.com/android/reference/com/google/android/gms/tflite/gpu/support/TfLiteGpu) e ative a opção de delegado de GPU para sua classe de modelo da API Task com a classe [`BaseOptions`](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/core/BaseOptions.Builder). Por exemplo, você pode configurar a GPU em `ObjectDetector` conforme mostrado nos códigos de exemplo abaixo: + +
+ +
+

Kotlin

+

+
        val useGpuTask = TfLiteGpu.isGpuDelegateAvailable(context)
+
+        lateinit val optionsTask = useGpuTask.continueWith { task ->
+          val baseOptionsBuilder = BaseOptions.builder()
+          if (task.result) {
+            baseOptionsBuilder.useGpu()
+          }
+        ObjectDetectorOptions.builder()
+                  .setBaseOptions(baseOptionsBuilder.build())
+                  .setMaxResults(1)
+                  .build()
+        }
+      
+
+
+

Java

+

+
      Task<Boolean> useGpuTask = TfLiteGpu.isGpuDelegateAvailable(context);
+
+      Task<ObjectDetectorOptions> optionsTask = useGpuTask.continueWith({ task ->
+        BaseOptions baseOptionsBuilder = BaseOptions.builder();
+        if (task.getResult()) {
+          baseOptionsBuilder.useGpu();
+        }
+        return ObjectDetectorOptions.builder()
+                .setBaseOptions(baseOptionsBuilder.build())
+                .setMaxResults(1)
+                .build()
+      });
+      
+
+
+
+ +## Use a GPU com o TensorFlow Lite standalone {:#standalone} + +Se o seu aplicativo segmentar dispositivos que não executam o Google Play, é possível empacotar o delegado de GPU com seu aplicativo e usá-lo com a versão standalone do TensorFlow Lite. + +### Adicione as dependências do projeto + +Para habilitar o acesso ao delegado de GPU com as Task Libraries usando a versão standalone do TensorFlow Lite, adicione `org.tensorflow:tensorflow-lite-gpu-delegate-plugin` às dependências do arquivo `build.gradle`: + +``` +dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite' + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +### Ative a aceleração de GPU + +Em seguida, ative a opção de delegado de GPU para sua classe de modelo da API Task com a classe [BaseOptions](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/core/BaseOptions.Builder). Por exemplo, você pode configurar a GPU em `ObjectDetector` conforme mostrado nos códigos de exemplo a seguir: + +
+ +
+

Kotlin

+

+
    import org.tensorflow.lite.task.core.BaseOptions
+    import org.tensorflow.lite.task.gms.vision.detector.ObjectDetector
+
+    val baseOptions = BaseOptions.builder().useGpu().build()
+
+    val options =
+        ObjectDetector.ObjectDetectorOptions.builder()
+            .setBaseOptions(baseOptions)
+            .setMaxResults(1)
+            .build()
+
+    val objectDetector = ObjectDetector.createFromFileAndOptions(
+      context, model, options)
+      
+
+
+

Java

+

+
    import org.tensorflow.lite.task.core.BaseOptions
+    import org.tensorflow.lite.task.gms.vision.detector.ObjectDetector
+
+    BaseOptions baseOptions = BaseOptions.builder().useGpu().build();
+
+    ObjectDetectorOptions options =
+        ObjectDetectorOptions.builder()
+            .setBaseOptions(baseOptions)
+            .setMaxResults(1)
+            .build();
+
+    val objectDetector = ObjectDetector.createFromFileAndOptions(
+      context, model, options);
+      
+
+
+
diff --git a/site/pt-br/lite/android/delegates/hexagon.md b/site/pt-br/lite/android/delegates/hexagon.md new file mode 100644 index 0000000000..ae253cd778 --- /dev/null +++ b/site/pt-br/lite/android/delegates/hexagon.md @@ -0,0 +1,237 @@ +# Delegado Hexagon do TensorFlow Lite + +Este documento explica como usar o delegado Hexagon do TensorFlow Lite no seu aplicativo usando a API Java e/ou C. O delegado usa a biblioteca Qualcomm Hexagon para executar kernels quantizados no DSP. Observe que o delegado visa *complementar* a funcionalidade NNAPI, principalmente para dispositivos em que a aceleração de DSP NNAPI não está disponível (por exemplo, em dispositivos mais antigos ou que ainda não têm um driver NNAPI de DSP). + +Observação: esse delegado está em fase experimental (beta). + +**Dispositivos compatíveis:** + +No momento, há suporte para a seguinte arquitetura Hexagon, incluindo, sem limitação: + +- Hexagon 680 + - Exemplos de SoC: Snapdragon 821, 820, 660 +- Hexagon 682 + - Exemplo de SoC: Snapdragon 835 +- Hexagon 685 + - Exemplos de SoC: Snapdragon 845, Snapdragon 710, QCS410, QCS610, QCS605, QCS603 +- Hexagon 690 + - Exemplos de SoC: Snapdragon 855, RB5 + +**Modelos compatíveis:** + +O delegado Hexagon é compatível com todos os modelos em conformidade com nossa [especificação de quantização simétrica de 8 bits](https://www.tensorflow.org/lite/performance/quantization_spec), incluindo aqueles gerados usando a [quantização de números inteiros pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_integer_quant). Os modelos UInt8 treinados com o programa legado de [treinamento consciente de quantização](https://github.com/tensorflow/tensorflow/tree/r1.13/tensorflow/contrib/quantize) também são compatíveis, por exemplo, [estas versões quantizadas](https://www.tensorflow.org/lite/guide/hosted_models#quantized_models) na nossa página Modelos hospedados. + +## API Java do delegado Hexagon + +```java +public class HexagonDelegate implements Delegate, Closeable { + + /* + * Creates a new HexagonDelegate object given the current 'context'. + * Throws UnsupportedOperationException if Hexagon DSP delegation is not + * available on this device. + */ + public HexagonDelegate(Context context) throws UnsupportedOperationException + + + /** + * Frees TFLite resources in C runtime. + * + * User is expected to call this method explicitly. + */ + @Override + public void close(); +} +``` + +### Exemplo de uso + +#### Etapa 1. Edite o aplicativo/build.gradle para que use o AAR do delegado Hexagon noturno + +``` +dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT' + implementation 'org.tensorflow:tensorflow-lite-hexagon:0.0.0-nightly-SNAPSHOT' +} +``` + +#### Etapa 2. Adicione as bibliotecas Hexagon ao seu aplicativo Android + +- Baixe e execute hexagon_nn_skel.run. Ele deve fornecer 3 bibliotecas compartilhadas diferentes: "libhexagon_nn_skel.so", "libhexagon_nn_skel_v65.so" e "libhexagon_nn_skel_v66.so" + - [v1.10.3](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_1_10_3_1.run) + - [v1.14](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.14.run) + - [v1.17](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.17.0.0.run) + - [v1.20](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.20.0.0.run) + - [v1.20.0.1](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.20.0.1.run) + +Observação: você precisará aceitar o contrato de licença. + +Observação: desde 02/23/2021, você deve usar a v1.20.0.1. + +Observação: você precisa usar as bibliotecas hexagon_nn com a versão compatível da biblioteca de interface. A biblioteca de interface faz parte do AAR e é buscada pelo bazel através da [configuração](https://github.com/tensorflow/tensorflow/blob/master/third_party/hexagon/workspace.bzl). A versão na configuração do bazel é a que você deve usar. + +- Inclua todas as 3 no seu aplicativo com outras bibliotecas compartilhadas. Confira [Como adicionar a biblioteca compartilhada ao seu aplicativo](#how-to-add-shared-library-to-your-app). O delegado escolherá automaticamente a que tiver o melhor desempenho dependendo do dispositivo. + +Observação: se o seu aplicativo será criado tanto para dispositivos ARM de 32 bits quanto de 64, você precisará adicionar as bibliotecas compartilhadas do Hexagon a ambas as pastas de 32 e 64 bits das bibliotecas. + +#### Etapa 3. Crie um delegado e inicialize um interpretador do TensorFlow Lite + +```java +import org.tensorflow.lite.HexagonDelegate; + +// Create the Delegate instance. +try { + hexagonDelegate = new HexagonDelegate(activity); + tfliteOptions.addDelegate(hexagonDelegate); +} catch (UnsupportedOperationException e) { + // Hexagon delegate is not supported on this device. +} + +tfliteInterpreter = new Interpreter(tfliteModel, tfliteOptions); + +// Dispose after finished with inference. +tfliteInterpreter.close(); +if (hexagonDelegate != null) { + hexagonDelegate.close(); +} +``` + +## API C do delegado Hexagon + +```c +struct TfLiteHexagonDelegateOptions { + // This corresponds to the debug level in the Hexagon SDK. 0 (default) + // means no debug. + int debug_level; + // This corresponds to powersave_level in the Hexagon SDK. + // where 0 (default) means high performance which means more power + // consumption. + int powersave_level; + // If set to true, performance information about the graph will be dumped + // to Standard output, this includes cpu cycles. + // WARNING: Experimental and subject to change anytime. + bool print_graph_profile; + // If set to true, graph structure will be dumped to Standard output. + // This is usually beneficial to see what actual nodes executed on + // the DSP. Combining with 'debug_level' more information will be printed. + // WARNING: Experimental and subject to change anytime. + bool print_graph_debug; +}; + +// Return a delegate that uses Hexagon SDK for ops execution. +// Must outlive the interpreter. +TfLiteDelegate* +TfLiteHexagonDelegateCreate(const TfLiteHexagonDelegateOptions* options); + +// Do any needed cleanup and delete 'delegate'. +void TfLiteHexagonDelegateDelete(TfLiteDelegate* delegate); + +// Initializes the DSP connection. +// This should be called before doing any usage of the delegate. +// "lib_directory_path": Path to the directory which holds the +// shared libraries for the Hexagon NN libraries on the device. +void TfLiteHexagonInitWithPath(const char* lib_directory_path); + +// Same as above method but doesn't accept the path params. +// Assumes the environment setup is already done. Only initialize Hexagon. +Void TfLiteHexagonInit(); + +// Clean up and switch off the DSP connection. +// This should be called after all processing is done and delegate is deleted. +Void TfLiteHexagonTearDown(); +``` + +### Exemplo de uso + +#### Etapa 1. Edite o aplicativo/build.gradle para que use o AAR do delegado Hexagon noturno + +``` +dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT' + implementation 'org.tensorflow:tensorflow-lite-hexagon:0.0.0-nightly-SNAPSHOT' +} +``` + +#### Etapa 2. Adicione as bibliotecas Hexagon ao seu aplicativo Android + +- Baixe e execute hexagon_nn_skel.run. Ele deve fornecer 3 bibliotecas compartilhadas diferentes: "libhexagon_nn_skel.so", "libhexagon_nn_skel_v65.so" e "libhexagon_nn_skel_v66.so" + - [v1.10.3](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_1_10_3_1.run) + - [v1.14](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.14.run) + - [v1.17](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.17.0.0.run) + - [v1.20](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.20.0.0.run) + - [v1.20.0.1](https://storage.cloud.google.com/download.tensorflow.org/tflite/hexagon_nn_skel_v1.20.0.1.run) + +Observação: você precisará aceitar o contrato de licença. + +Observação: desde 02/23/2021, você deve usar a v1.20.0.1. + +Observação: você precisa usar as bibliotecas hexagon_nn com a versão compatível da biblioteca de interface. A biblioteca de interface faz parte do AAR e é buscada pelo bazel através da [configuração](https://github.com/tensorflow/tensorflow/blob/master/third_party/hexagon/workspace.bzl). A versão na configuração do bazel é a que você deve usar. + +- Inclua todas as 3 no seu aplicativo com outras bibliotecas compartilhadas. Confira [Como adicionar a biblioteca compartilhada ao seu aplicativo](#how-to-add-shared-library-to-your-app). O delegado escolherá automaticamente a que tiver o melhor desempenho dependendo do dispositivo. + +Observação: se o seu aplicativo será criado tanto para dispositivos ARM de 32 bits quanto de 64, você precisará adicionar as bibliotecas compartilhadas do Hexagon a ambas as pastas de 32 e 64 bits das bibliotecas. + +#### Etapa 3. Inclua o cabeçalho C + +- O arquivo de cabeçalho "hexagon_delegate.h" pode ser baixado do [GitHub](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/hexagon/hexagon_delegate.h) ou extraído do AAR do delegado Hexagon. + +#### Etapa 4. Crie um delegado e inicialize um interpretador do TensorFlow Lite + +- No seu código, verifique se a biblioteca Hexagon nativa está carregada. Isso pode ser feito ao chamar `System.loadLibrary("tensorflowlite_hexagon_jni");`
na sua Atividade ou ponto de entrada Java. + +- Crie um delegado, por exemplo: + +```c +#include "tensorflow/lite/delegates/hexagon/hexagon_delegate.h" + +// Assuming shared libraries are under "/data/local/tmp/" +// If files are packaged with native lib in android App then it +// will typically be equivalent to the path provided by +// "getContext().getApplicationInfo().nativeLibraryDir" +const char[] library_directory_path = "/data/local/tmp/"; +TfLiteHexagonInitWithPath(library_directory_path); // Needed once at startup. +::tflite::TfLiteHexagonDelegateOptions params = {0}; +// 'delegate_ptr' Need to outlive the interpreter. For example, +// If use case will need to resize input or anything that can trigger +// re-applying delegates then 'delegate_ptr' need to outlive the interpreter. +auto* delegate_ptr = ::tflite::TfLiteHexagonDelegateCreate(¶ms); +Interpreter::TfLiteDelegatePtr delegate(delegate_ptr, + [](TfLiteDelegate* delegate) { + ::tflite::TfLiteHexagonDelegateDelete(delegate); + }); +interpreter->ModifyGraphWithDelegate(delegate.get()); +// After usage of delegate. +TfLiteHexagonTearDown(); // Needed once at end of app/DSP usage. +``` + +## Adicione a biblioteca compartilhada ao seu aplicativo + +- Crie a pasta “app/src/main/jniLibs” e um diretório para cada arquitetura alvo. Por exemplo, + - ARM de 64 bits: `app/src/main/jniLibs/arm64-v8a` + - ARM de 32 bits: `app/src/main/jniLibs/armeabi-v7a` +- Coloque o .so no diretório correspondente à arquitetura. + +Observação: se você estiver usando o App Bundle para publicar seu aplicativo, é recomendável definir android.bundle.enableUncompressedNativeLibs=false no arquivo gradle.properties. + +## Feedback + +Em caso de problemas, crie um issue do [GitHub](https://github.com/tensorflow/tensorflow/issues/new?template=50-other-issues.md) com todos os detalhes necessários para reprodução, incluindo o modelo do smartphone e o board usado (`adb shell getprop ro.product.device` e `adb shell getprop ro.board.platform`). + +## Perguntas frequentes + +- Quais operações são compatíveis com o delegado? + - Veja a lista atual de [operações e restrições compatíveis](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/hexagon/README.md) +- Como posso saber se o modelo está usando o DSP ao ativar o delegado? + - Duas mensagens de log serão impressas quando você ativar o delegado: uma para indicar se o delegado foi criado e outra para indicar quantos nós estão sendo executados com o delegado.
`Created TensorFlow Lite delegate for Hexagon.`
`Hexagon delegate: X nodes delegated out of Y nodes.` +- Todas as operações no modelo precisam ser compatíveis para executar o delegado? + - Não, o modelo será particionado em subgrafos com base nas operações compatíveis. As incompatíveis serão executadas na CPU. +- Como posso criar o AAR do delegado Hexagon a partir da origem? + - Use `bazel build -c opt --config=android_arm64 tensorflow/lite/delegates/hexagon/java:tensorflow-lite-hexagon`. +- Por que o delegado Hexagon falha ao inicializar mesmo que meu dispositivo tenha um SoC compatível? + - Verifique se o seu dispositivo tem mesmo um SoC compatível. Execute `adb shell cat /proc/cpuinfo | grep Hardware` e veja se retorna algo como: "Hardware : Qualcomm Technologies, Inc MSMXXXX". + - Alguns fabricantes de smartphones usam SoCs diferentes para o mesmo modelo. Por isso, o delegado Hexagon pode só funcionar em alguns dispositivos do mesmo modelo de smartphone, e não em todos. + - Alguns fabricantes de smartphones restringem intencionalmente o uso do DSP Hexagon nos aplicativos que não são do sistema Android, tornando o delegado Hexagon incapaz de funcionar. +- Meu smartphone tem o acesso ao DSP bloqueado. Fiz root no smartphone e ainda não consigo executar o delegado. O que eu faço? + - Desative o SELinux enforce ao executar `adb shell setenforce 0` diff --git a/site/pt-br/lite/android/delegates/nnapi.md b/site/pt-br/lite/android/delegates/nnapi.md new file mode 100644 index 0000000000..41a1a0e4a4 --- /dev/null +++ b/site/pt-br/lite/android/delegates/nnapi.md @@ -0,0 +1,121 @@ +# Delegado NNAPI do TensorFlow Lite + +A [API Android Neural Networks (NNAPI)](https://developer.android.com/ndk/guides/neuralnetworks) está disponível em todos os dispositivos Android com o Android 8.1 (nível 27 da API) ou mais recente. Ela fornece aceleração para modelos do TensorFlow em dispositivos Android com aceleradores de hardware compatíveis, incluindo: + +- Unidade de Processamento Gráfico (GPU) +- Processamento de Sinal Digital (DSP) +- Unidade de Processamento Neural (NPU) + +O desempenho varia dependendo do hardware específico disponível no dispositivo. + +Esta página descreve como usar o delegado NNAPI com o Interpretador do TensorFlow Lite no Java e no Kotlin. Para APIs C Android, consulte a [documentação do Kit de desenvolvimento nativo do Android](https://developer.android.com/ndk/guides/neuralnetworks). + +## Testando o delegado NNAPI no seu próprio modelo + +### Importe o gradle + +O delegado NNAPI faz parte do interpretador Android do TensorFlow Lite, versão 1.14.0 ou mais recente. Você pode importá-lo para seu projeto ao adicionar o seguinte código ao arquivo gradle do seu módulo: + +```groovy +dependencies { + implementation 'org.tensorflow:tensorflow-lite:2.0.0' +} +``` + +### Inicialize o delegado NNAPI + +Adicione o código para inicializar o delegado NNAPI antes de inicializar o interpretador do TensorFlow Lite. + +Observação: embora a NNAPI seja compatível com o nível 27 da API (Android Oreo MR1), o suporte para as operações melhorou significativamente a partir do nível 28 da API (Android Pie). Como resultado, recomendamos que os desenvolvedores usem o delegado NNAPI para o Android Pie ou mais recente na maioria dos casos. + +```java +import org.tensorflow.lite.Interpreter; +import org.tensorflow.lite.nnapi.NnApiDelegate; + +Interpreter.Options options = (new Interpreter.Options()); +NnApiDelegate nnApiDelegate = null; +// Initialize interpreter with NNAPI delegate for Android Pie or above +if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + nnApiDelegate = new NnApiDelegate(); + options.addDelegate(nnApiDelegate); +} + +// Initialize TFLite interpreter +try { + tfLite = new Interpreter(loadModelFile(assetManager, modelFilename), options); +} catch (Exception e) { + throw new RuntimeException(e); +} + +// Run inference +// ... + +// Unload delegate +tfLite.close(); +if(null != nnApiDelegate) { + nnApiDelegate.close(); +} +``` + +## Práticas recomendadas + +### Teste o desempenho antes de implantar + +O desempenho do runtime pode variar significativamente devido à arquitetura do modelo, tamanho, operações, disponibilidade de hardware e utilização de hardware de runtime. Por exemplo, se um aplicativo utiliza muito a GPU para renderização, a aceleração de NNAPI pode não melhorar o desempenho devido à contenção de recursos. Recomendamos executar um teste simples de desempenho usando o registro de depuração para medir o tempo de inferência. Execute o teste em vários smartphones com diferentes chipsets (fabricantes ou modelos do mesmo fabricante) que representem sua base de usuários antes de ativar a NNAPI em produção. + +Para desenvolvedores avançados, o TensorFlow Lite também oferece [uma ferramenta de benchmark de modelo para Android](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark). + +### Crie uma lista de exclusão de dispositivos + +Em produção, pode haver casos em que a NNAPI não tenha o desempenho esperado. Recomendamos que os desenvolvedores mantenham uma lista de dispositivos que não devem usar a aceleração de NNAPI em combinação com modelos específicos. É possível criar essa lista com base no valor de `"ro.board.platform"`, que você pode recuperar usando o seguinte fragmento de código: + +```java +String boardPlatform = ""; + +try { + Process sysProcess = + new ProcessBuilder("/system/bin/getprop", "ro.board.platform"). + redirectErrorStream(true).start(); + + BufferedReader reader = new BufferedReader + (new InputStreamReader(sysProcess.getInputStream())); + String currentLine = null; + + while ((currentLine=reader.readLine()) != null){ + boardPlatform = line; + } + sysProcess.destroy(); +} catch (IOException e) {} + +Log.d("Board Platform", boardPlatform); +``` + +Para desenvolvedores avançados, considere manter essa lista através de um sistema de configuração remota. A equipe do TensorFlow está trabalhando ativamente em maneiras de simplificar e automatizar a descoberta e aplicação da configuração de NNAPI ideal. + +### Quantização + +A quantização reduz o tamanho do modelo ao usar números inteiros de 8 bits ou floats de 16 bits em vez de floats de 32 bits para computação. Os tamanhos do modelo de números inteiros de 8 bits são um quarto das versões float de 32 bits. Os floats de 16 bits são metade do tamanho. A quantização pode melhorar o desempenho significativamente, embora o processo possa resultar no trade-off de alguma exatidão do modelo. + +Há vários tipos de técnicas de quantização pós-treinamento disponíveis, mas, para máximo suporte e aceleração no hardware atual, recomendamos a [quantização de números inteiros completa](post_training_quantization#full_integer_quantization_of_weights_and_activations). Essa abordagem converte ambos o peso e as operações em números inteiros. Esse processo de quantização exige um dataset representativo para funcionar. + +### Use modelos e operações compatíveis + +Se o delegado NNAPI não for compatível com algumas das combinações de parâmetros ou operações em um modelo, o framework só executará as partes compatíveis do grafo no acelerador. O restante será executado na CPU, resultando na execução fragmentada. Devido ao alto custo da sincronização de CPU/acelerador, isso pode resultar em um desempenho mais lento comparado à execução da rede inteira só na CPU. + +A NNAPI tem um melhor desempenho quando os modelos usam somente [operações compatíveis](https://developer.android.com/ndk/guides/neuralnetworks#model). Os modelos a seguir são compatíveis com a NNAPI: + +- [Classificação de imagens MobileNet v1 (224x224) (download do modelo float)](https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html) [(download do modelo quantizado)](http://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224_quant.tgz)
*(modelo de classificação de imagens feito para aplicativos de visão móveis e embarcados)* +- [Detecção de objetos MobileNet v2 SSD](https://ai.googleblog.com/2018/07/accelerated-training-and-inference-with.html) [(download)](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobile_ssd_v2_float_coco.tflite)
*(modelo de classificação de imagens que detecta vários objetos com caixas delimitadoras)* +- [Detecção de objetos MobileNet v1(300x300) Single Shot Detector (SSD)](https://ai.googleblog.com/2018/07/accelerated-training-and-inference-with.html) [(download)] (https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip) +- [PoseNet para a estimativa de pose](https://github.com/tensorflow/tfjs-models/tree/master/posenet) [(download)](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/multi_person_mobilenet_v1_075_float.tflite)
*(modelo de visão que estima as poses de uma ou mais pessoas em imagens ou vídeos)* + +A aceleração de NNAPI também não é compatível quando o modelo contém saídas de tamanho dinâmico. Nesse caso, você verá um aviso assim: + +```none +ERROR: Attempting to use a delegate that only supports static-sized tensors \ +with a graph that has dynamic-sized tensors. +``` + +### Ative a implementação da CPU da NNAPI + +Um grafo que não pode ser processado completamente por um acelerador pode reverter à implementação da CPU da NNAPI. No entanto, como geralmente é menos eficaz do que o interpretador do TensorFlow, essa opção é desativada por padrão no delegado NNAPI para o Android 10 (nível 29 da API) ou superior. Para substituir esse comportamento, defina `setUseNnapiCpu` como `true` no objeto `NnApiDelegate.Options`. diff --git a/site/pt-br/lite/android/play_services.md b/site/pt-br/lite/android/play_services.md new file mode 100644 index 0000000000..fca928a9a2 --- /dev/null +++ b/site/pt-br/lite/android/play_services.md @@ -0,0 +1,499 @@ +# TensorFlow Lite no Google Play Services + +O TensorFlow Lite está disponível no runtime do Google Play Services para todos os dispositivos Android com a versão atual do Play Services. Esse runtime permite que você execute modelos de aprendizado de máquina (ML) sem empacotar estaticamente bibliotecas do TensorFlow Lite com seu app. + +Com a API Google Play Services, você pode reduzir o tamanho dos seus apps e melhorar a performance da última versão estável das bibliotecas. O TensorFlow Lite no Google Play Services é a maneira recomendada de usar o TensorFlow Lite no Android. + +Você pode começar com o runtime do Play Services usando o [Guia rápido](../android/quickstart), que oferece um tutorial passo a passo para a implementação de um aplicativo de exemplo. Se você já usa o TensorFlow Lite standalone no seu aplicativo e quer utilizar o runtime do Play Services, consulte a seção [Migrando do TensorFlow Lite standalone](#migrating). Para mais informações sobre o Google Play Services, consulte o site [Google Play Services](https://developers.google.com/android/guides/overview). + + + +## Usando o runtime do Play Services + +O TensorFlow Lite no Google Play Services está disponível pela [API Task do TensorFlow Lite](../api_docs/java/org/tensorflow/lite/task/core/package-summary) e [API Interpreter do TensorFlow Lite](../api_docs/java/org/tensorflow/lite/InterpreterApi). A Biblioteca Task oferece interfaces de modelo prontas para uso e otimizadas para tarefas comuns de aprendizado de máquina usando dados visuais, de áudio e texto. A API Interpreter do TensorFlow Lite, fornecida pelo runtime do TensorFlow e pelas bibliotecas de suporte, oferece uma interface de uso mais geral para criar e executar modelos de ML. + +As seguintes seções apresentam instruções sobre como implementar as APIs Biblioteca Task e Interpreter no Google Play Services. Embora seja possível para um aplicativo usar tanto as APIs Interpreter como as APIs Biblioteca Task, a maioria só usa um conjunto de APIs. + +### Usando as APIs Biblioteca Task + +A API Task do TensorFlow Lite envolve a API Interpreter e fornece uma interface de programação de alto nível para tarefas comuns de aprendizado de máquina que usam dados visuais, de áudio e texto. Utilize a API Task se o seu aplicativo exigir uma das [tarefas compatíveis](../inference_with_metadata/task_library/overview#supported_tasks). + +#### Adicione as dependências do projeto + +A dependência do seu projeto depende do seu caso de uso de aprendizado de máquina. As APIs Task contêm as seguintes bibliotecas: + +- Biblioteca de visão: `org.tensorflow:tensorflow-lite-task-vision-play-services` +- Biblioteca de áudio: `org.tensorflow:tensorflow-lite-task-audio-play-services` +- Biblioteca de texto: `org.tensorflow:tensorflow-lite-task-text-play-services` + +Adicione uma das dependências ao código do projeto do aplicativo para acessar a API Play Services para o TensorFlow Lite. Por exemplo, use o código a seguir para implementar uma tarefa de visão: + +``` +dependencies { +... + implementation 'org.tensorflow:tensorflow-lite-task-vision-play-services:0.4.2' +... +} +``` + +Atenção: o repositório maven da versão 0.4.2 da biblioteca de áudio das tarefas do TensorFlow Lite está incompleto. Em vez disso, use a versão 0.4.2.1 para essa biblioteca: `org.tensorflow:tensorflow-lite-task-audio-play-services:0.4.2.1`. + +#### 2. Adicione a inicialização do TensorFlow Lite + +Inicialize o componente do TensorFlow Lite da API Google Play Services *antes* de usar as APIs do TensorFlow Lite. O exemplo a seguir inicializa a biblioteca de visão: + +
+ +
+

Kotlin

+
init {
+  TfLiteVision.initialize(context)
+    }
+  }
+
+
+
+
+ +Importante: verifique se a tarefa `TfLite.initialize` foi concluída antes de executar código que acesse as APIs do TensorFlow Lite. + +Dica: os módulos do TensorFlow Lite são instalados ao mesmo tempo que seu aplicativo ou atualizados a partir da Play Store. Você pode conferir a disponibilidade dos módulos usando `ModuleInstallClient` das APIs do Google Play Services. Para mais informações sobre a verificação da disponibilidade dos módulos, consulte [Garantindo a disponibilidade da API com ModuleInstallClient](https://developers.google.com/android/guides/module-install-apis). + +#### 3. Realize inferências + +Depois de inicializar o componente do TensorFlow Lite, chame o método `detect()` para gerar inferências. O código exato no método `detect()` varia dependendo da biblioteca e do caso de uso. O código a seguir é para um caso de uso de detecção de objetos simples com a biblioteca `TfLiteVision`: + +
+ +
+

Kotlin

+
fun detect(...) {
+  if (!TfLiteVision.isInitialized()) {
+    Log.e(TAG, "detect: TfLiteVision is not initialized yet")
+    return
+  }
+
+  if (objectDetector == null) {
+    setupObjectDetector()
+  }
+
+  ...
+
+}
+
+
+
+
+ +Dependendo do formato dos dados, talvez você também precise pré-processar e converter seus dados no método `detect()` antes de gerar inferências. Por exemplo, os dados de imagem para um detector de objetos exigem o seguinte: + +```kotlin +val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build() +val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image)) +val results = objectDetector?.detect(tensorImage) +``` + +### Usando as APIs Interpreter + +As APIs Interpreter oferecem mais controle e flexibilidade do que as APIs Biblioteca Task. Você deve usar as APIs Interpreter se a sua tarefa de aprendizado de máquina não for compatível com a Biblioteca Task ou exigir uma interface de uso mais geral para criar e executar modelos de ML. + +#### Adicione as dependências do projeto + +Adicione as seguintes dependências ao código do projeto do aplicativo para acessar a API Play Services para o TensorFlow Lite: + +``` +dependencies { +... + // Tensorflow Lite dependencies for Google Play services + implementation 'com.google.android.gms:play-services-tflite-java:16.0.1' + // Optional: include Tensorflow Lite Support Library + implementation 'com.google.android.gms:play-services-tflite-support:16.0.1' +... +} +``` + +#### 2. Adicione a inicialização do TensorFlow Lite + +Inicialize o componente do TensorFlow Lite da API Google Play Services *antes* de usar as APIs do TensorFlow Lite: + +
+ +
+

Kotlin

+
+val initializeTask: Task<Void> by lazy { TfLite.initialize(this) }
+
+
+
+

Java

+
+Task<Void> initializeTask = TfLite.initialize(context);
+
+
+
+
+ +Observação: verifique se a tarefa `TfLite.initialize` foi concluída antes de executar código que acesse as APIs do TensorFlow Lite. Use o método `addOnSuccessListener()`, conforme mostrado na próxima seção. + +#### 3. Crie um interpretador e defina a opção de runtime {:#step_3_interpreter} + +Crie um interpretador usando `InterpreterApi.create()` e o configure para usar o runtime do Google Play Services, ao chamar `InterpreterApi.Options.setRuntime()`, conforme exibido no código de exemplo a seguir: + +
+ +
+

Kotlin

+
+import org.tensorflow.lite.InterpreterApi
+import org.tensorflow.lite.InterpreterApi.Options.TfLiteRuntime
+...
+private lateinit var interpreter: InterpreterApi
+...
+initializeTask.addOnSuccessListener {
+  val interpreterOption =
+    InterpreterApi.Options().setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+  interpreter = InterpreterApi.create(
+    modelBuffer,
+    interpreterOption
+  )}
+  .addOnFailureListener { e ->
+    Log.e("Interpreter", "Cannot initialize interpreter", e)
+  }
+
+
+
+

Java

+
+import org.tensorflow.lite.InterpreterApi
+import org.tensorflow.lite.InterpreterApi.Options.TfLiteRuntime
+...
+private InterpreterApi interpreter;
+...
+initializeTask.addOnSuccessListener(a -> {
+    interpreter = InterpreterApi.create(modelBuffer,
+      new InterpreterApi.Options().setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY));
+  })
+  .addOnFailureListener(e -> {
+    Log.e("Interpreter", String.format("Cannot initialize interpreter: %s",
+          e.getMessage()));
+  });
+
+
+
+
+ +Você deve usar a implementação acima, porque evita bloquear o thread da interface do usuário Android. Se você precisar gerenciar a execução do thread mais detalhadamente, pode adicionar uma chamada `Tasks.await()` para a criação do interpretador: + +
+ +
+

Kotlin

+
+import androidx.lifecycle.lifecycleScope
+...
+lifecycleScope.launchWhenStarted { // uses coroutine
+  initializeTask.await()
+}
+
+
+
+

Java

+
+@BackgroundThread
+InterpreterApi initializeInterpreter() {
+    Tasks.await(initializeTask);
+    return InterpreterApi.create(...);
+}
+
+
+
+
+ +Aviso: não chame `.await()` no thread da interface do usuário em primeiro plano, porque interrompe a exibição dos elementos da interface do usuário e cria uma má experiência do usuário. + +#### 3. Realize inferências + +Usando o objeto `interpreter` criado, chame o método `run()` para gerar uma inferência. + +
+ +
+

Kotlin

+
+interpreter.run(inputBuffer, outputBuffer)
+
+
+
+

Java

+
+interpreter.run(inputBuffer, outputBuffer);
+
+
+
+
+ +## Aceleração de hardware {:#hardware-acceleration} + +O TensorFlow Lite permite acelerar o desempenho do seu modelo usando processadores de hardware especializados, como unidades de processamento gráfico (GPUs). Você pode aproveitar esses processadores especializados usando drivers de hardware chamados [*delegados*](https://www.tensorflow.org/lite/performance/delegates). É possível usar os seguintes delegados de aceleração de hardware com o TensorFlow Lite no Google Play Services: + +- *[Delegado de GPU](https://www.tensorflow.org/lite/performance/gpu) (recomendado)*: esse delegado é fornecido pelo Google Play Services e é carregado dinamicamente, como as versões do Play Services da API Task e Interpreter. + +- [*Delegado NNAPI*](https://www.tensorflow.org/lite/android/delegates/nnapi): esse delegado está disponível como uma dependência da biblioteca incluída no seu projeto de desenvolvimento Android e é empacotado com seu aplicativo. + +Para mais informações sobre a aceleração de hardware com o TensorFlow Lite, confira a página [Delegados do TensorFlow Lite](https://www.tensorflow.org/lite/performance/delegates). + +### Verificando a compatibilidade do dispositivo + +Nem todos os dispositivos oferecem suporte à aceleração de hardware de GPU com o TFLite. Para mitigar erros e possíveis falhas, use o método `TfLiteGpu.isGpuDelegateAvailable` para verificar se um dispositivo é compatível com o delegado de GPU. + +Use esse método para confirmar se um dispositivo oferece suporte à GPU e use a CPU ou o delegado NNAPI como substituto quando a GPU não for compatível. + +``` +useGpuTask = TfLiteGpu.isGpuDelegateAvailable(context) +``` + +Depois de ter uma variável como `useGpuTask`, você pode usá-la para determinar se os dispositivos usam o delegado de GPU. Os exemplos a seguir mostram como isso pode ser feito com ambas as APIs Interpreter e Biblioteca Task. + +**Com a API Task** + +
+ +
+

Kotlin

+
lateinit val optionsTask = useGpuTask.continueWith { task ->
+  val baseOptionsBuilder = BaseOptions.builder()
+  if (task.result) {
+    baseOptionsBuilder.useGpu()
+  }
+ ObjectDetectorOptions.builder()
+          .setBaseOptions(baseOptionsBuilder.build())
+          .setMaxResults(1)
+          .build()
+}
+    
+
+
+

Java

+
Task<ObjectDetectorOptions> optionsTask = useGpuTask.continueWith({ task ->
+  BaseOptions baseOptionsBuilder = BaseOptions.builder();
+  if (task.getResult()) {
+    baseOptionsBuilder.useGpu();
+  }
+  return ObjectDetectorOptions.builder()
+          .setBaseOptions(baseOptionsBuilder.build())
+          .setMaxResults(1)
+          .build()
+});
+    
+
+
+
+ +**Com a API Interpreter** + +
+ +
+

Kotlin

+
val interpreterTask = useGpuTask.continueWith { task ->
+  val interpreterOptions = InterpreterApi.Options()
+      .setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+  if (task.result) {
+      interpreterOptions.addDelegateFactory(GpuDelegateFactory())
+  }
+  InterpreterApi.create(FileUtil.loadMappedFile(context, MODEL_PATH), interpreterOptions)
+}
+    
+
+
+

Java

+
Task<InterpreterApi.Options> interpreterOptionsTask = useGpuTask.continueWith({ task ->
+  InterpreterApi.Options options =
+      new InterpreterApi.Options().setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY);
+  if (task.getResult()) {
+     options.addDelegateFactory(new GpuDelegateFactory());
+  }
+  return options;
+});
+    
+
+
+
+ +### GPU com APIs Biblioteca Task + +Para usar o delegado de GPU com as APIs Task: + +1. Atualize as dependências do projeto para usar o delegado de GPU a partir do Play Services: + + ``` + implementation 'com.google.android.gms:play-services-tflite-gpu:16.1.0' + ``` + +2. Inicialize o delegado de GPU com `setEnableGpuDelegateSupport`. Por exemplo, você pode inicializar o delegado de GPU para `TfLiteVision` com o seguinte: + +
+ +
+

Kotlin

+
        TfLiteVision.initialize(context, TfLiteInitializationOptions.builder().setEnableGpuDelegateSupport(true).build())
+            
+
+
+

Java

+
        TfLiteVision.initialize(context, TfLiteInitializationOptions.builder().setEnableGpuDelegateSupport(true).build());
+            
+
+
+
+ +3. Ative a opção de delegado de GPU com [`BaseOptions`](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/core/BaseOptions.Builder): + +
+ +
+

Kotlin

+
        val baseOptions = BaseOptions.builder().useGpu().build()
+            
+
+
+

Java

+
        BaseOptions baseOptions = BaseOptions.builder().useGpu().build();
+            
+
+
+
+ +4. Configure as opções usando `.setBaseOptions`. Por exemplo, você pode configurar a GPU em `ObjectDetector` com o código a seguir: + +
+ +
+

Kotlin

+
        val options =
+                ObjectDetectorOptions.builder()
+                    .setBaseOptions(baseOptions)
+                    .setMaxResults(1)
+                    .build()
+            
+
+
+

Java

+
        ObjectDetectorOptions options =
+                ObjectDetectorOptions.builder()
+                    .setBaseOptions(baseOptions)
+                    .setMaxResults(1)
+                    .build();
+            
+
+
+
+ +### GPU com APIs Interpreter + +Para usar o delegado de GPU com as APIs Interpreter: + +1. Atualize as dependências do projeto para usar o delegado de GPU a partir do Play Services: + + ``` + implementation 'com.google.android.gms:play-services-tflite-gpu:16.1.0' + ``` + +2. Ative a opção de delegado de GPU na inicialização do TFlite: + +
+ +
+

Kotlin

+
        TfLite.initialize(context,
+              TfLiteInitializationOptions.builder()
+               .setEnableGpuDelegateSupport(true)
+               .build())
+            
+
+
+

Java

+
        TfLite.initialize(context,
+              TfLiteInitializationOptions.builder()
+               .setEnableGpuDelegateSupport(true)
+               .build());
+            
+
+
+
+ +3. Defina o delegado de GPU nas opções de interpretador para usar `DelegateFactory` ao chamar `addDelegateFactory()` em `InterpreterApi.Options()`: + +
+ +
+

Kotlin

+
+              val interpreterOption = InterpreterApi.Options()
+               .setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+               .addDelegateFactory(GpuDelegateFactory())
+            
+
+
+

Java

+
+              Options interpreterOption = InterpreterApi.Options()
+                .setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)
+                .addDelegateFactory(new GpuDelegateFactory());
+            
+
+
+
+ +## Migrando do TensorFlow Lite standalone {:#migrating} + +Se você planeja migrar seu aplicativo do TensorFlow Lite standalone para a API Play Services, leia as orientações adicionais a seguir para atualizar o código do projeto do aplicativo: + +1. Revise a seção [Limitações](#limitations) desta página para garantir a compatibilidade com o caso de uso. +2. Antes de atualizar seu código, faça verificações de desempenho e exatidão nos seus modelos, especialmente se estiver usando versões do TensorFlow Lite anteriores à versão 2.1. Assim, você tem uma linha de base para comparar com a nova implementação. +3. Se você migrou todo o seu código para usar a API Play Services para o TensorFlow Lite, remova as dependências *runtime library* existentes do TensorFlow Lite (entradas com org.tensorflow:**tensorflow-lite**:*) do seu arquivo build.gradle para reduzir o tamanho do aplicativo. +4. Identifique todas as ocorrências de criação de objetos `new Interpreter` no seu código e modifique isso para usar a chamada InterpreterApi.create(). Essa nova API é assíncrona, ou seja, na maioria dos casos não é uma substituição direta, e você precisa registrar um listener para quando a chamada é concluída. Consulte o fragmento de código na [Etapa 3](#step_3_interpreter). +5. Adicione `import org.tensorflow.lite.InterpreterApi;` e `import org.tensorflow.lite.InterpreterApi.Options.TfLiteRuntime;` a quaisquer arquivos de código-fonte usando as classes `org.tensorflow.lite.Interpreter` ou `org.tensorflow.lite.InterpreterApi`. +6. Se qualquer uma das chamadas resultantes a `InterpreterApi.create()` tiver só um argumento, anexe `new InterpreterApi.Options()` à lista de argumentos. +7. Anexe `.setRuntime(TfLiteRuntime.FROM_SYSTEM_ONLY)` ao último argumento de qualquer chamada a `InterpreterApi.create()`. +8. Substitua todas as outras ocorrências da classe `org.tensorflow.lite.Interpreter` por `org.tensorflow.lite.InterpreterApi`. + +Se você quiser usar o TensorFlow Lite standalone e a API Play Services juntos, precisa usar o TensorFlow Lite 2.9 (ou mais recente). O TensorFlow Lite 2.8 e as versões mais antigas não são compatíveis com a versão da API Play Services. + +## Limitações + +O TensorFlow Lite no Google Play Services tem as seguintes limitações: + +- O suporte aos delegados de aceleração de hardware é limitado aos delegados listados na seção [Aceleração de hardware](#hardware-acceleration). Nenhum outro delegado de aceleração é compatível. +- O acesso ao TensorFlow Lite por [APIs nativas](https://www.tensorflow.org/lite/guide/inference#load_and_run_a_model_in_c) não é suportado. Somente as APIs Java do TensorFlow Lite estão disponíveis pelo Google Play Services. +- As APIs experimentais ou descontinuadas do TensorFlow Lite, incluindo operações personalizadas, não são compatíveis. + +## Suporte e feedback {:#support} + +Você pode fornecer feedback e receber suporte pelo Issue Tracker do TensorFlow. Informe problemas e solicitações de suporte usando o [modelo de issue](https://github.com/tensorflow/tensorflow/issues/new?title=TensorFlow+Lite+in+Play+Services+issue&template=tflite-in-play-services.md) para o TensorFlow Lite no Google Play Services. + +## Termos de serviço {:#tos} + +O uso do TensorFlow Lite nas APIs do Google Play Services está sujeito aos [Termos de Serviço das APIs do Google](https://developers.google.com/terms/). + +### Privacidade e coleta de dados + +Ao usar o TensorFlow Lite nas APIs do Google Play Services, o processamento dos dados de entrada, como imagens, vídeos e textos, ocorre totalmente no dispositivo, e o TensorFlow Lite nas APIs do Google Play Services não envia esses dados aos servidores do Google. Como resultado, você pode usar nossas APIs para processar dados que não devem sair do dispositivo. + +O TensorFlow Lite nas APIs do Google Play Services pode entrar em contato com os servidores do Google eventualmente para receber, por exemplo, correções de bug, modelos atualizados e informações sobre a compatibilidade de aceleradores de hardware. O TensorFlow Lite nas APIs do Google Play Services também pode enviar métricas sobre o desempenho e a utilização de APIs no seu aplicativo para o Google. O Google usa esses dados de métricas para medir o desempenho, depurar, manter e melhorar as APIs e detectar uso indevido ou abuso, conforme detalhado na nossa [Política de Privacidade](https://policies.google.com/privacy). + +**Você é responsável por informar aos usuários do seu aplicativo sobre o processamento que o Google faz dos dados de métricas do TensorFlow Lite nas APIs do Google Play Services conforme exigido pela legislação aplicável.** + +Os dados que coletamos incluem os seguintes: + +- Informações do dispositivo (como fabricante, modelo, versão de SO e build) e aceleradores de hardware de ML disponíveis (GPU e DSP). Usadas para diagnóstico e análise de uso. +- Identificador do dispositivo usado para diagnóstico e análise de uso. +- Informações do aplicativo (nome do pacote, versão do aplicativo). Usadas para diagnóstico e análise de uso. +- Configuração da API (por exemplo, os delegados em uso). Usada para diagnóstico e análise de uso. +- Tipo de evento (como criação de interpretadores, inferência). Usado para diagnóstico e análise de uso. +- Códigos de erro. Usados para diagnóstico. +- Métricas de desempenho. Usadas para diagnóstico. + +## Próximos passos + +Para mais informações sobre como implementar o aprendizado de máquina no seu aplicativo para dispositivos móveis com o TensorFlow Lite, confira o [Guia para desenvolvedores do TensorFlow Lite](https://www.tensorflow.org/lite/guide). Encontre modelos adicionais do TensorFlow Lite para classificação de imagens, detecção de objetos e outros aplicativos no [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite). diff --git a/site/pt-br/lite/android/tutorials/audio_classification.md b/site/pt-br/lite/android/tutorials/audio_classification.md new file mode 100644 index 0000000000..2a09fb9509 --- /dev/null +++ b/site/pt-br/lite/android/tutorials/audio_classification.md @@ -0,0 +1,247 @@ +# Reconhecimento de sons e palavras para Android + +Este tutorial mostra como usar o TensorFlow Lite com modelos de aprendizado de máquina pré-criados para reconhecer sons e palavras faladas em um aplicativo Android. Os modelos de classificação de áudio como os exibidos neste tutorial podem ser usados para detectar atividades, identificar ações ou reconhecer comandos de voz. + +![Demonstração animada de reconhecimento de áudio](https://storage.googleapis.com/download.tensorflow.org/tflite/examples/audio_classification.gif){: .attempt-right} Este tutorial mostra como baixar o código de exemplo e carregar o projeto no [Android Studio](https://developer.android.com/studio/), bem como explica partes essenciais do código de exemplo para você começar a adicionar essa funcionalidade ao seu próprio aplicativo. O aplicativo de exemplo usa a [Biblioteca Task para áudio](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier), que lida com a maior parte da gravação e do pré-processamento dos dados de áudio. Para mais informações sobre como o áudio é pré-processado para o uso com modelos de aprendizado de máquina, consulte [Preparação e ampliação de dados de áudio](https://www.tensorflow.org/io/tutorials/audio). + +## Classificação de áudio com o aprendizado de máquina + +O modelo de aprendizado de máquina neste tutorial reconhece sons ou palavras de amostras de áudio gravadas com um microfone em um dispositivo Android. O aplicativo de exemplo neste tutorial permite que você alterne entre o [YAMNet/classificador](https://tfhub.dev/google/lite-model/yamnet/classification/tflite/1), um modelo que reconhece sons e um modelo que reconhece determinadas palavras faladas, que foi [treinado](https://www.tensorflow.org/lite/models/modify/model_maker/speech_recognition) usando a ferramenta [Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) do TensorFlow Lite. Os modelos executam previsões em clipes de áudio que contêm 15.600 amostras individuais por clipe e têm 1 segundo de duração. + +## Configure e execute o exemplo + +Para a primeira parte deste tutorial, baixe o código de exemplo do GitHub e o execute usando o Android Studio. As seções a seguir deste documento exploram as seções relevantes do exemplo, para você aplicá-las aos seus próprios aplicativos Android. + +### Requisitos do sistema + +- [Android Studio](https://developer.android.com/studio/index.html), versão 2021.1.1 (Bumblebee) ou mais recente. +- SDK do Android, versão 31 ou mais recente. +- Dispositivo Android com uma versão mínima de SO do SDK 24 (Android 7.0 - Nougat) com o modo desenvolvedor ativado. + +### Obtenha o código de exemplo + +Crie uma cópia local do código de exemplo. Você usará esse código para criar um projeto no Android Studio e executar o aplicativo de exemplo. + +Para clonar e configurar o código de exemplo: + +1. Clone o repositório git +
+        git clone https://github.com/tensorflow/examples.git
+        
+2. Opcionalmente, configure sua instância git para usar o sparse checkout e ter somente os arquivos para o aplicativo de exemplo: + ``` + cd examples + git sparse-checkout init --cone + git sparse-checkout set lite/examples/audio_classification/android + ``` + +### Importe e execute o projeto + +Crie um projeto a partir do código de exemplo baixado, compile e depois execute esse projeto. + +Para importar e compilar o projeto do código de exemplo: + +1. Inicie o [Android Studio](https://developer.android.com/studio). +2. No Android Studio, selecione **File > New > Import Project** (Arquivo > Novo > Importar projeto). +3. Acesse o diretório do código de exemplo com o arquivo `build.gradle` (`.../examples/lite/examples/audio_classification/android/build.gradle`) e selecione esse diretório. + +Se você selecionar o diretório correto, o Android Studio cria e compila um novo projeto. Esse processo pode levar alguns minutos, dependendo da velocidade do seu computador e se você usou o Android Studio para outros projetos. Quando o build for concluído, o Android Studio exibirá uma mensagem `BUILD SUCCESSFUL` no painel de status **Build Output**. + +Para executar o projeto: + +1. No Android Studio, execute o projeto ao selecionar **Run > Run 'app'** (Executar > Executar 'app'). +2. Selecione um dispositivo Android conectado com um microfone para testar o aplicativo. + +Observação: se você usar um emulador para executar o aplicativo, [ative a entrada de áudio](https://developer.android.com/studio/releases/emulator#29.0.6-host-audio) na máquina host. + +As próximas seções mostram as modificações necessárias no projeto existente para adicionar essa funcionalidade ao seu próprio aplicativo, usando esse aplicativo de exemplo como um ponto de referência. + +## Adicione as dependências do projeto + +No seu próprio aplicativo, você precisa adicionar as dependências do projeto para executar os modelos de aprendizado de máquina do TensorFlow e acessar funções utilitárias que convertem formatos de dados padrão, como áudio, em um formato de dados de tensor que pode ser processado pelo modelo que você está usando. + +O aplicativo de exemplo usa as seguintes bibliotecas do TensorFlow Lite: + +- [API Biblioteca Task do TensorFlow para áudio:](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/audio/classifier/package-summary) fornece as classes de entrada dos dados de áudio necessárias, a execução do modelo de aprendizado de máquina e os resultados gerados com o processamento do modelo. + +As instruções a seguir mostram como adicionar as dependências necessárias ao seu próprio projeto de aplicativo Android. + +Para adicionar dependências de módulo: + +1. No módulo que usa o TensorFlow Lite, atualize o arquivo `build.gradle` para que inclua as seguintes dependências. No código de exemplo, esse arquivo está localizado aqui: `.../examples/lite/examples/audio_classification/android/build.gradle` + ``` + dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite-task-audio' + } + ``` +2. No Android Studio, sincronize as dependências do projeto ao selecionar: **File > Sync Project with Gradle Files** (Arquivo > Sincronizar projeto com arquivos gradle). + +## Inicialize o modelo de ML + +No seu aplicativo Android, você precisa inicializar o modelo de aprendizado de máquina do TensorFlow com parâmetros antes de realizar previsões com o modelo. Esses parâmetros de inicialização dependem do modelo e podem incluir configurações como limites de exatidão mínima padrão para previsões e rótulos para palavras ou sons que o modelo consegue reconhecer. + +Um modelo do TensorFlow Lite inclui um arquivo `*.tflite` contendo o modelo. O arquivo do modelo contém a lógica de previsão e geralmente inclui [metadados](../../models/convert/metadata) sobre como interpretar resultados de previsão, como nomes de classes de previsão. Os arquivos do modelo devem ser armazenados no diretório `src/main/assets` do seu projeto de desenvolvimento, como no código de exemplo: + +- `/src/main/assets/yamnet.tflite` + +Para conveniência e legibilidade do código, o exemplo declara um objeto complementar que define as configurações para o modelo. + +Para inicializar o modelo no seu aplicativo: + +1. Crie um objeto complementar para definir as configurações para o modelo: + ``` + companion object { + const val DISPLAY_THRESHOLD = 0.3f + const val DEFAULT_NUM_OF_RESULTS = 2 + const val DEFAULT_OVERLAP_VALUE = 0.5f + const val YAMNET_MODEL = "yamnet.tflite" + const val SPEECH_COMMAND_MODEL = "speech.tflite" + } + ``` +2. Crie as configurações para o modelo ao construir um objeto `AudioClassifier.AudioClassifierOptions`: + ``` + val options = AudioClassifier.AudioClassifierOptions.builder() + .setScoreThreshold(classificationThreshold) + .setMaxResults(numOfResults) + .setBaseOptions(baseOptionsBuilder.build()) + .build() + ``` +3. Use as configurações desse objeto para construir um objeto [`AudioClassifier`](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier) do TensorFlow Lite que contém o modelo: + ``` + classifier = AudioClassifier.createFromFileAndOptions(context, "yamnet.tflite", options) + ``` + +### Ative a aceleração de hardware + +Ao inicializar um modelo do TensorFlow Lite no seu aplicativo, você deve considerar usar os recursos de aceleração de hardware para acelerar os cálculos de previsão do modelo. Os [delegados](https://www.tensorflow.org/lite/performance/delegates) do TensorFlow Lite são módulos de software que aceleram a execução dos modelos de aprendizado de máquina usando hardware de processamento especializado em um dispositivo móvel, como unidades de processamento gráfico (GPUs) ou unidades de processamento de tensor (TPUs). O código de exemplo usa o delegado NNAPI para lidar com a aceleração de hardware da execução do modelo: + +``` +val baseOptionsBuilder = BaseOptions.builder() + .setNumThreads(numThreads) +... +when (currentDelegate) { + DELEGATE_CPU -> { + // Default + } + DELEGATE_NNAPI -> { + baseOptionsBuilder.useNnapi() + } +} +``` + +Usar os delegados para executar modelos do TensorFlow é recomendável, mas não obrigatório. Para mais informações sobre como usar os delegados com o TensorFlow Lite, consulte [Delegados do TensorFlow Lite](https://www.tensorflow.org/lite/performance/delegates). + +## Prepare os dados para o modelo + +No seu aplicativo Android, seu código fornece dados ao modelo para interpretação ao transformar dados existentes, como clipes de áudio, em um formato de dados de [Tensor](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Tensor) que pode ser processado pelo modelo. Os dados em um Tensor passados a um modelo precisam ter dimensões específicas, ou um formato, que correspondam ao formato dos dados usados para treinar o modelo. + +O [modelo YAMNet/classificador](https://tfhub.dev/google/lite-model/yamnet/classification/tflite/1) e os modelos de [comandos de voz](https://www.tensorflow.org/lite/models/modify/model_maker/speech_recognition) personalizados usados nesse código de exemplo aceitam objetos de dados de Tensor que representam clipes de áudio de canal único, ou mono, gravados a 16 kHz em clipes de 0,975 segundo (15.600 amostras). Ao realizar previsões em novos dados de áudio, seu aplicativo precisa transformar esses dados de áudio em objetos de dados de Tensor desse tamanho e formato. A [API para áudio](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier) da Biblioteca Task do TensorFlow Lite faz a transformação de dados para você. + +Na classe `AudioClassificationHelper` do código de exemplo, o aplicativo grava o áudio em tempo real dos microfones do dispositivo usando um objeto [AudioRecord](https://developer.android.com/reference/android/media/AudioRecord) Android. O código usa o [AudioClassifier](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/audio/classifier/AudioClassifier) para criar e configurar esse objeto para gravar áudio em uma taxa de amostragem apropriada para o modelo. O código também usa o AudioClassifier para criar um objeto [TensorAudio](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/support/audio/TensorAudio) que armazena os dados de áudio transformados. Em seguida, o objeto TensorAudio é passado a um modelo para análise. + +Para fornecer dados de áudio ao modelo de ML: + +- Use o objeto `AudioClassifier` para criar um objeto `TensorAudio` e um objeto `AudioRecord`: + ``` + fun initClassifier() { + ... + try { + classifier = AudioClassifier.createFromFileAndOptions(context, currentModel, options) + // create audio input objects + tensorAudio = classifier.createInputTensorAudio() + recorder = classifier.createAudioRecord() + } + ``` + +Observação: seu aplicativo precisa solicitar permissão para gravar áudio usando o microfone de um dispositivo Android. Veja a classe `fragments/PermissionsFragment` no projeto, por exemplo. Para mais informações sobre como solicitar permissões, confira [Permissões no Android](https://developer.android.com/guide/topics/permissions/overview). + +## Realize previsões + +No seu aplicativo Android, depois de conectar um objeto [AudioRecord](https://developer.android.com/reference/android/media/AudioRecord) e [TensorAudio](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/support/audio/TensorAudio) a um objeto AudioClassifier, você pode executar o modelo com esses dados para gerar uma previsão ou *inferência*. O código de exemplo deste tutorial realiza previsões com clipes de um stream de entrada de áudio gravado em tempo real a uma taxa específica. + +A execução do modelo consome recursos significativos, então é importante realizar previsões de modelo de ML em um thread em segundo plano separado. O aplicativo de exemplo usa um objeto `[ScheduledThreadPoolExecutor](https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor)` para isolar o processamento do modelo de outras funções do aplicativo. + +Os modelos de classificação de áudio que reconhecem sons com um início e fim claro, como palavras, podem produzir previsões mais exatas em um stream de áudio recebido ao analisar clipes de áudio sobrepostos. Essa abordagem ajuda o modelo a evitar perder previsões para palavras cortadas ao final de um clipe. No aplicativo de exemplo, sempre que você realiza uma previsão, o código pega o último clipe de 0,975 segundo do buffer de gravação de áudio e o analisa. Você pode fazer o modelo analisar clipes de áudio sobrepostos ao definir o valor `interval` do pool de thread em execução da análise do modelo para um comprimento mais curto do que a duração dos clipes analisados. Por exemplo, se o seu modelo analisa clipes de 1 segundo e você define o intervalo como 500 milissegundos, o modelo sempre analisará a última metade do clipe anterior e 500 milissegundos dos novos dados de áudio, criando uma sobreposição de análise de clipes de 50%. + +Para começar a realizar previsões nos dados de áudio: + +1. Use o método `AudioClassificationHelper.startAudioClassification()` para iniciar a gravação de áudio para o modelo: + ``` + fun startAudioClassification() { + if (recorder.recordingState == AudioRecord.RECORDSTATE_RECORDING) { + return + } + recorder.startRecording() + } + ``` +2. Defina com que frequência o modelo gera uma inferência a partir dos clipes de áudio ao configurar um `interval` de taxa fixa no objeto `ScheduledThreadPoolExecutor`: + ``` + executor = ScheduledThreadPoolExecutor(1) + executor.scheduleAtFixedRate( + classifyRunnable, + 0, + interval, + TimeUnit.MILLISECONDS) + ``` +3. O objeto `classifyRunnable` no código acima executa o método `AudioClassificationHelper.classifyAudio()`, que carrega os dados de áudio mais recentes do gravador e realiza uma previsão: + ``` + private fun classifyAudio() { + tensorAudio.load(recorder) + val output = classifier.classify(tensorAudio) + ... + } + ``` + +Cuidado: não realize as previsões do modelo de ML no thread de execução principal do aplicativo. Ao fazer isso, a interface do usuário do seu aplicativo pode ficar lenta ou sem resposta. + +### Interrompa o processamento da previsão + +Garanta que o código do seu aplicativo interrompa a classificação de áudio quando o Fragmento ou a Atividade de processamento de áudio perder o foco. A execução contínua de um modelo de aprendizado de máquina afeta significativamente a duração da bateria de um dispositivo Android. Use o método `onPause()` na atividade ou no fragmento Android associado à classificação de áudio para interromper o processamento da previsão e a gravação de áudio. + +Para interromper a classificação e gravação de áudio: + +- Use o método `AudioClassificationHelper.stopAudioClassification()` para interromper a execução do modelo e a gravação, conforme mostrado abaixo na classe `AudioFragment`: + ``` + override fun onPause() { + super.onPause() + if (::audioHelper.isInitialized ) { + audioHelper.stopAudioClassification() + } + } + ``` + +## Processe a saída do modelo + +No seu aplicativo Android, depois de processar um clipe de áudio, o modelo produz uma lista de previsões com que o código do seu aplicativo precisa lidar ao executar lógica de negócios adicional, exibindo resultados ao usuário ou realizando outras ações. O resultado de qualquer modelo do TensorFlow Lite varia em termos de número de previsões produzidas (uma ou mais) e informações descritivas de cada previsão. No caso dos modelos no aplicativo de exemplo, as previsões são uma lista de sons ou palavras reconhecidas. O objeto de opções AudioClassifier usado no código de exemplo permite definir o número máximo de previsões com o método `setMaxResults()`, conforme mostrado na seção [Inicialize o modelo de ML](#Initialize_the_ML_model). + +Para obter os resultados de previsão do modelo: + +1. Obtenha os resultados do método `classify()`
do objeto [AudioClassifier](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/audio/classifier/AudioClassifier) e os passe ao objeto listener (código de referência): + ``` + private fun classifyAudio() { + ... + val output = classifier.classify(tensorAudio) + listener.onResult(output[0].categories, inferenceTime) + } + ``` +2. Use a função onResult() do listener para processar a saída ao executar a lógica de negócios ou exibir os resultados ao usuário: + ``` + private val audioClassificationListener = object : AudioClassificationListener { + override fun onResult(results: List, inferenceTime: Long) { + requireActivity().runOnUiThread { + adapter.categoryList = results + adapter.notifyDataSetChanged() + fragmentAudioBinding.bottomSheetLayout.inferenceTimeVal.text = + String.format("%d ms", inferenceTime) + } + } + ``` + +O modelo usado nesse exemplo gera uma lista de previsões com um rótulo para o som ou a palavra classificada e uma pontuação entre 0 e 1 como um Float representando a confiança da previsão, sendo 1 a pontuação mais alta. Em geral, as previsões com uma pontuação abaixo de 50% (0,5) são consideradas inconclusivas. No entanto, cabe a você decidir como lida com os resultados de previsão de valores baixos e as necessidades do seu aplicativo. + +Depois que o modelo retornar um conjunto de resultados de previsão, seu aplicativo pode agir em relação a essas previsões ao apresentar o resultado ao seu usuário ou executar lógica adicional. No caso do código de exemplo, o aplicativo lista os sons ou as palavras identificadas na interface do usuário do aplicativo. + +## Próximos passos + +Você pode encontrar mais modelos do TensorFlow Lite para processamento de áudio no [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite&module-type=audio-embedding,audio-pitch-extraction,audio-event-classification,audio-stt) e na página [Guia de modelos pré-treinados](https://www.tensorflow.org/lite/models/trained). Para mais informações sobre como implementar o aprendizado de máquina no seu aplicativo móvel com o TensorFlow Lite, confira o [Guia para desenvolvedores do TensorFlow Lite](https://www.tensorflow.org/lite/guide). diff --git a/site/pt-br/lite/android/tutorials/object_detection.md b/site/pt-br/lite/android/tutorials/object_detection.md new file mode 100644 index 0000000000..c6a74bd86f --- /dev/null +++ b/site/pt-br/lite/android/tutorials/object_detection.md @@ -0,0 +1,343 @@ +# Detecção de objetos com o Android + +Este tutorial mostra como criar um aplicativo Android usando o TensorFlow Lite para detectar objetos continuamente em frames capturados por um dispositivo com câmera. Esse aplicativo foi feito para um dispositivo Android físico. Se você estiver atualizando um projeto existente, pode usar o código de amostra como referência e pular para as instruções sobre [como modificar seu projeto](#add_dependencies). + +![Demonstração animada de detecção de objeto](https://storage.googleapis.com/download.tensorflow.org/tflite/examples/obj_detection_cat.gif){: .attempt-right width="250px"} + +## Visão geral da detecção de objetos + +A *detecção de objetos* é a tarefa de aprendizado de máquina que identifica a presença e o local de várias classes de objetos em uma imagem. Um modelo de detecção de objetos é treinado com um dataset que contém um conjunto de objetos conhecidos. + +O modelo treinado recebe frames de imagens como entrada e tenta categorizar os itens nas imagens a partir do conjunto de classes conhecidas que foi treinado para reconhecer. Para cada frame de imagem, o modelo de detecção de objetos gera uma lista de objetos que detecta, o local de uma caixa delimitadora para cada objeto e uma pontuação que indica a confiança do objeto ser classificado corretamente. + +## Modelos e dataset + +Este tutorial usa modelos que foram treinados usando o [dataset COCO](http://cocodataset.org/). COCO é um dataset de detecção de objetos de grande escala que contém 330 mil imagens, 1,5 milhão de instâncias de objetos e 80 categorias de objetos. + +Você pode usar um dos seguintes modelos pré-treinados: + +- [EfficientDet-Lite0](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite0/detection/metadata/1) *[Recomendado]*: um modelo de detecção de objetos leve com um extrator de características BiFPN, preditor de caixa compartilhado e perda focal. A mAP (precisão média) para o dataset de validação COCO 2017 é 25,69%. + +- [EfficientDet-Lite1](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite1/detection/metadata/1): um modelo de detecção de objetos EfficientDet de tamanho médio. A mAP para o dataset de validação COCO 2017 é 30,55%. + +- [EfficientDet-Lite2](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite2/detection/metadata/1): um modelo maior de detecção de objetos EfficientDet. A mAP para o dataset de validação COCO 2017 é 33,97%. + +- [MobileNetV1-SSD](https://tfhub.dev/tensorflow/lite-model/ssd_mobilenet_v1/1/metadata/2): um modelo extremamente leve e otimizado para a detecção de objetos com o TensorFlow Lite. A mAP para o dataset de validação COCO 2017 é 21%. + +Para este tutorial, o modelo *EfficientDet-Lite0* apresenta um bom equilíbrio entre tamanho e exatidão. + +O download, a extração e a colocação dos modelos na pasta de recursos são gerenciados automaticamente pelo arquivo `download.gradle`, que é executado no tempo de build. Você não precisa baixar modelos TFLite manualmente no projeto. + +## Configure e execute o exemplo + +Para configurar o aplicativo de detecção de objetos, baixe a amostra do [GitHub](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android) e a execute usando o [Android Studio](https://developer.android.com/studio/). As seções a seguir deste tutorial exploram as seções relevantes do código de exemplo, para você aplicá-las aos seus próprios aplicativos Android. + +### Requisitos do sistema + +- **[Android Studio](https://developer.android.com/studio/index.html)**, versão 2021.1.1 (Bumblebee) ou mais recente. +- SDK do Android, versão 31 ou mais recente. +- Dispositivo Android com uma versão mínima de SO do SDK 24 (Android 7.0 - Nougat) com o modo desenvolvedor ativado. + +Observação: este exemplo usa a câmera, então execute-o em um dispositivo Android físico. + +### Obtenha o código de exemplo + +Crie uma cópia local do código de exemplo. Você usará esse código para criar um projeto no Android Studio e executar o aplicativo de exemplo. + +Para clonar e configurar o código de exemplo: + +1. Clone o repositório git +
+        git clone https://github.com/tensorflow/examples.git
+        
+2. Opcionalmente, configure sua instância git para usar o sparse checkout e ter somente os arquivos para o aplicativo de exemplo de detecção de objetos: +
+        cd examples
+        git sparse-checkout init --cone
+        git sparse-checkout set lite/examples/object_detection/android
+        
+ +### Importe e execute o projeto + +Crie um projeto a partir do código de exemplo baixado, compile e depois execute esse projeto. + +Para importar e compilar o projeto do código de exemplo: + +1. Inicie o [Android Studio](https://developer.android.com/studio). +2. No Android Studio, selecione **File > New > Import Project** (Arquivo > Novo > Importar projeto). +3. Acesse o diretório do código de exemplo com o arquivo build.gradle (`.../examples/lite/examples/object_detection/android/build.gradle`) e selecione esse diretório. +4. Se o Android Studio solicitar o Gradle Sync, selecione OK. +5. Garanta que o dispositivo Android esteja conectado ao seu computador e que o modo desenvolvedor esteja ativado. Clique na seta `Run` verde. + +Se você selecionar o diretório correto, o Android Studio cria e compila um novo projeto. Esse processo pode levar alguns minutos, dependendo da velocidade do seu computador e se você usou o Android Studio para outros projetos. Quando o build for concluído, o Android Studio exibirá uma mensagem `BUILD SUCCESSFUL` no painel de status **Build Output**. + +Observação: o código de exemplo foi criado com o Android Studio 4.2.2, mas funciona com versões mais antigas do Studio. Se você estiver usando uma versão mais antiga do Android Studio, pode tentar ajustar o número da versão do plugin Android para que o build seja concluído, em vez de fazer upgrade do Studio. + +**Opcional:** para corrigir erros de build, atualize a versão do plugin Android: + +1. Abra o arquivo build.gradle no diretório do projeto. + +2. Mude a versão das ferramentas Android da seguinte maneira: + + ``` + // from: classpath + 'com.android.tools.build:gradle:4.2.2' + // to: classpath + 'com.android.tools.build:gradle:4.1.2' + ``` + +3. Sincronize o projeto ao selecionar: **File > Sync Project with Gradle Files** (Arquivo > Sincronizar projeto com arquivos gradle). + +Para executar o projeto: + +1. No Android Studio, execute o projeto ao selecionar **Run > Run…**. +2. Selecione um dispositivo Android conectado com uma câmera para testar o aplicativo. + +As próximas seções mostram as modificações necessárias no projeto existente para adicionar essa funcionalidade ao seu próprio aplicativo, usando esse aplicativo de exemplo como um ponto de referência. + +## Adicione as dependências do projeto {:#add_dependencies} + +No seu próprio aplicativo, você precisa adicionar as dependências do projeto para executar os modelos de aprendizado de máquina do TensorFlow e acessar funções utilitárias que convertem dados como imagens em um formato de dados de tensor que pode ser processado pelo modelo que você está usando. + +O aplicativo de exemplo usa a [Biblioteca Task para visão](../../inference_with_metadata/task_library/overview#supported_tasks) do TensorFlow Lite para permitir a execução do modelo de aprendizado de máquina de detecção de objetos. As instruções a seguir explicam como adicionar as dependências de biblioteca necessárias para o seu próprio projeto de aplicativo Android. + +As instruções a seguir explicam como adicionar as dependências de projeto e módulo necessárias ao seu próprio projeto de aplicativo Android. + +Para adicionar dependências de módulo: + +1. No módulo que usa o TensorFlow Lite, atualize o arquivo `build.gradle` para que inclua as seguintes dependências. No código de exemplo, esse arquivo está localizado aqui: `...examples/lite/examples/object_detection/android/app/build.gradle` ([código de referência](https://github.com/tensorflow/examples/blob/master/lite/examples/object_detection/android/app/build.gradle)) + + ``` + dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0' + implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0' + } + ``` + + O projeto precisa incluir a Biblioteca Task para visão (`tensorflow-lite-task-vision`). A biblioteca da unidade de processamento gráfico (GPU) (`tensorflow-lite-gpu-delegate-plugin`) fornece a infraestrutura para executar o aplicativo na GPU e o Delegado (`tensorflow-lite-gpu`) oferece a lista de compatibilidade. + +2. No Android Studio, sincronize as dependências do projeto ao selecionar: **File > Sync Project with Gradle Files** (Arquivo > Sincronizar projeto com arquivos gradle). + +## Inicialize o modelo de ML + +No seu aplicativo Android, você precisa inicializar o modelo de aprendizado de máquina do TensorFlow com parâmetros antes de realizar previsões com o modelo. Esses parâmetros de inicialização são os mesmos em todos os modelos de detecção de objetos e podem incluir configurações como limites de exatidão mínima para previsões. + +Um modelo do TensorFlow Lite inclui um arquivo `.tflite` com o código do modelo e, geralmente, um arquivo de rótulos com o nome das classes previstas pelo modelo. No caso da detecção de objetos, as classes são objetos como pessoa, cachorro, gato ou carro. + +Este exemplo baixa vários modelos especificados em `download_models.gradle`, e a classe `ObjectDetectorHelper` fornece um seletor para os modelos: + +``` +val modelName = + when (currentModel) { + MODEL_MOBILENETV1 -> "mobilenetv1.tflite" + MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite" + MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite" + MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite" + else -> "mobilenetv1.tflite" + } +``` + +Ponto importante: os modelos devem ser armazenados no diretório `src/main/assets` do seu projeto de desenvolvimento. A TensorFlow Lite Task Library verifica automaticamente esse diretório quando você especifica o nome de arquivo do modelo. + +Para inicializar o modelo no seu aplicativo: + +1. Adicione um arquivo de modelo `.tflite` ao diretório `src/main/assets` do seu projeto de desenvolvimento, como: [EfficientDet-Lite0](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite0/detection/metadata/1). + +2. Defina uma variável estática para o nome de arquivo do seu modelo. No aplicativo de exemplo, defina a variável `modelName` como `MODEL_EFFICIENTDETV0` para usar o modelo de detecção EfficientDet-Lite0. + +3. Defina as opções para o modelo, como o limite de previsão, o tamanho do conjunto de resultados e, opcionalmente, delegados de aceleração de hardware: + + ``` + val optionsBuilder = + ObjectDetector.ObjectDetectorOptions.builder() + .setScoreThreshold(threshold) + .setMaxResults(maxResults) + ``` + +4. Use as configurações desse objeto para construir um objeto [`ObjectDetector`](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/vision/detector/ObjectDetector#createFromFile(Context,%20java.lang.String)) do TensorFlow Lite que contém o modelo: + + ``` + objectDetector = + ObjectDetector.createFromFileAndOptions( + context, modelName, optionsBuilder.build()) + ``` + +O `setupObjectDetector` configura os seguintes parâmetros do modelo: + +- Limite de detecção +- Número máximo de resultados de detecção +- Número de threads de processamento para usar (`BaseOptions.builder().setNumThreads(numThreads)`) +- Próprio modelo (`modelName`) +- Objeto ObjectDetector (`objectDetector`) + +### Configure o acelerador de hardware + +Ao inicializar um modelo do TensorFlow Lite no seu aplicativo, você pode usar as características da aceleração de hardware para acelerar os cálculos de previsão do modelo. + +Os *delegados* do TensorFlow Lite são módulos de software que aceleram a execução de modelos de aprendizado de máquina usando hardware de processamento especializado em um dispositivo móvel, como Unidades de processamento gráfico (GPUs), Unidades de processamento de tensor (TPUs) e Processadores de sinal digital (DSPs). O uso de delegados para executar modelos do TensorFlow Lite é recomendado, mas não obrigatório. + +O detector de objetos é inicializado usando as configurações atuais no thread que está o usando. Você pode usar a CPU e os delegados [NNAPI](../../android/delegates/nnapi) com detectores criados no thread principal e usados em um thread em segundo plano, mas o thread que inicializou o detector precisa usar o delegado de GPU. + +Os delegados são definidos na função `ObjectDetectionHelper.setupObjectDetector()`: + +``` +when (currentDelegate) { + DELEGATE_CPU -> { + // Default + } + DELEGATE_GPU -> { + if (CompatibilityList().isDelegateSupportedOnThisDevice) { + baseOptionsBuilder.useGpu() + } else { + objectDetectorListener?.onError("GPU is not supported on this device") + } + } + DELEGATE_NNAPI -> { + baseOptionsBuilder.useNnapi() + } +} +``` + +Para mais informações sobre como usar delegados de aceleração de hardware com o TensorFlow Lite, confira os [Delegados do TensorFlow Lite](../../performance/delegates). + +## Prepare os dados para o modelo + +No seu aplicativo Android, seu código fornece dados ao modelo para interpretação ao transformar dados existentes, como frames de imagem, em um formato de dados de Tensor que pode ser processado pelo modelo. Os dados em um Tensor passados a um modelo precisam ter dimensões específicas, ou um formato, que correspondam ao formato dos dados usados para treinar o modelo. + +O modelo [EfficientDet-Lite0](https://tfhub.dev/tensorflow/lite-model/efficientdet/lite0/detection/metadata/1) usado nesse código de exemplo aceita Tensores que representam imagens com uma dimensão de 320 x 320 e três canais (vermelho, azul e verde) por pixel. Cada valor no tensor é um único byte entre 0 e 255. Então, para realizar previsões com novas imagens, seu aplicativo precisa transformar esses dados de imagem em objetos de dados de Tensor desse tamanho e formato. A API TensorFlow Lite Task Library Vision do TensorFlow Lite faz a transformação dos dados para você. + +O aplicativo usa um objeto [`ImageAnalysis`](https://developer.android.com/training/camerax/analyze) para extrair as imagens da câmera. Esse objeto chama a função `detectObject` com bitmap da câmera. Os dados são automaticamente redimensionados e girados pelo `ImageProcessor`, para que atendam aos requisitos de dados de imagem do modelo. Em seguida, a imagem é traduzida em um objeto [`TensorImage`](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/support/image/TensorImage). + +Para preparar os dados do subsistema da câmera para serem processados pelo modelo de ML: + +1. Crie um objeto `ImageAnalysis` para extrair imagens no formato necessário: + + ``` + imageAnalyzer = + ImageAnalysis.Builder() + .setTargetAspectRatio(AspectRatio.RATIO_4_3) + .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation) + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) + .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888) + .build() + ... + ``` + +2. Conecte o analisador ao subsistema da câmera e crie um buffer de bitmap para conter os dados recebidos da câmera: + + ``` + .also { + it.setAnalyzer(cameraExecutor) { + image -> if (!::bitmapBuffer.isInitialized) + { bitmapBuffer = Bitmap.createBitmap( image.width, image.height, + Bitmap.Config.ARGB_8888 ) } detectObjects(image) + } + } + ``` + +3. Extraia os dados de imagem específicos de que o modelo precisa e passe as informações de rotação da imagem: + + ``` + private fun detectObjects(image: ImageProxy) { + //Copy out RGB bits to the shared bitmap buffer + image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) } + val imageRotation = image.imageInfo.rotationDegrees + objectDetectorHelper.detect(bitmapBuffer, imageRotation) + } + ``` + +4. Conclua quaisquer transformações de dados finais e adicione os dados de imagem a um objeto `TensorImage`, conforme mostrado no método `ObjectDetectorHelper.detect()` do aplicativo de exemplo: + + ``` + val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build() + // Preprocess the image and convert it into a TensorImage for detection. + val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image)) + ``` + +Observação: ao extrair as informações de imagem do subsistema da câmera Android, garanta que a imagem esteja no formato RGB. Esse formato é exigido pela classe ImageProcessor do TensorFlow Lite, que você usará para preparar a imagem para a análise pelo modelo. Se a imagem de formato RGB tiver um canal alfa, esses dados de transparência são ignorados. + +## Realize previsões + +No seu aplicativo Android, depois de criar um objeto TensorImage com dados de imagem no formato correto, você pode executar o modelo com esses dados para gerar uma previsão, ou *inferência*. + +Na classe `fragments/CameraFragment.kt` do aplicativo de exemplo, o objeto `imageAnalyzer` na função `bindCameraUseCases` passa automaticamente os dados ao modelo para previsões quando o aplicativo está conectado à câmera. + +O aplicativo usa o método `cameraProvider.bindToLifecycle()` para lidar com o seletor de câmera, a janela de visualização e o processamento de modelo de ML. A classe `ObjectDetectorHelper.kt` passa os dados de imagem ao modelo. Para executar o modelo e gerar previsões a partir dos dados de imagem: + +- Execute a previsão ao passar os dados de imagem para sua função de previsão: + + ``` + val results = objectDetector?.detect(tensorImage) + ``` + +O objeto Interpreter do TensorFlow Lite recebe esses dados, executa com o modelo e produz uma lista de previsões. Para o processamento contínuo de dados pelo modelo, use o método `runForMultipleInputsOutputs()` para que os objetos Interpreter não sejam criados e depois removidos pelo sistema a cada previsão realizada. + +## Processe a saída do modelo + +No seu aplicativo Android, depois de executar os dados de imagem com o modelo de detecção de objetos, ele produz uma lista de previsões com que o código do aplicativo precisa lidar ao executar lógica de negócios adicional, mostrar os resultados ao usuário ou realizar outras ações. + +A saída de qualquer modelo do TensorFlow Lite varia em termos de número de previsões produzidas (uma ou mais) e informações descritivas de cada previsão. No caso de um modelo de detecção de objetos, as previsões geralmente incluem dados para uma caixa delimitadora que indica onde um objeto é detectado na imagem. No código de exemplo, os resultados são passados à função `onResults` em `CameraFragment.kt`, que atua como um DetectorListener no processo de detecção de objetos. + +``` +interface DetectorListener { + fun onError(error: String) + fun onResults( + results: MutableList?, + inferenceTime: Long, + imageHeight: Int, + imageWidth: Int + ) +} +``` + +Para o modelo usado nesse exemplo, cada previsão inclui um local de caixa delimitadora para o objeto, um rótulo para o objeto e uma pontuação entre 0 e 1 como um Float representando a confiança da previsão, sendo 1 a pontuação mais alta. Em geral, as previsões com uma pontuação abaixo de 50% (0,5) são consideradas inconclusivas. No entanto, cabe a você decidir como lida com os resultados de previsão de valores baixos e as necessidades do seu aplicativo. + +Para lidar com os resultados de previsão do modelo: + +1. Use um padrão listener para passar os resultados ao código do seu aplicativo ou objetos de interface do usuário. O aplicativo de exemplo usa esse padrão para passar os resultados de detecção do objeto `ObjectDetectorHelper` para o objeto `CameraFragment`: + + ``` + objectDetectorListener.onResults( + // instance of CameraFragment + results, + inferenceTime, + tensorImage.height, + tensorImage.width) + ``` + +2. Realize ações em relação aos resultados, como exibir a previsão para o usuário. O exemplo desenha um overlay no objeto CameraPreview para mostrar o resultado: + + ``` + override fun onResults( + results: MutableList?, + inferenceTime: Long, + imageHeight: Int, + imageWidth: Int + ) { + activity?.runOnUiThread { + fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text = + String.format("%d ms", inferenceTime) + + // Pass necessary information to OverlayView for drawing on the canvas + fragmentCameraBinding.overlay.setResults( + results ?: LinkedList(), + imageHeight, + imageWidth + ) + + // Force a redraw + fragmentCameraBinding.overlay.invalidate() + } + } + ``` + +Depois que o modelo retornar um resultado de previsão, seu aplicativo pode agir em relação a ela ao apresentar o resultado ao seu usuário ou executar lógica adicional. No caso do código de exemplo, o aplicativo desenha uma caixa delimitadora em volta do objeto identificado e exibe o nome da classe na tela. + +## Próximos passos + +- Descubra os usos do TensorFlow Lite nos [exemplos](../../examples). +- Saiba mais sobre como usar modelos de aprendizado de máquina com o TensorFlow Lite na seção [Modelos](../../models). +- Saiba mais sobre como implementar o aprendizado de máquina no seu aplicativo para dispositivos móveis no [Guia para desenvolvedores do TensorFlow Lite](../../guide). diff --git a/site/pt-br/lite/android/tutorials/question_answer.md b/site/pt-br/lite/android/tutorials/question_answer.md new file mode 100644 index 0000000000..901ed068b4 --- /dev/null +++ b/site/pt-br/lite/android/tutorials/question_answer.md @@ -0,0 +1,390 @@ +# Respondendo a perguntas com o Android + +![Aplicativo de exemplo de resposta a perguntas no Android](../../examples/bert_qa/images/screenshot.gif){: .attempt-right width="250px"} + +Este tutorial mostra como criar um aplicativo Android usando o TensorFlow Lite para fornecer respostas a perguntas estruturadas em texto de linguagem natural. O [aplicativo de exemplo](https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/android) usa a API *BERT de resposta a perguntas* ([`BertQuestionAnswerer`](../../inference_with_metadata/task_library/bert_question_answerer)), na [Biblioteca Task para linguagem natural (NL)](../../inference_with_metadata/task_library/overview#supported_tasks), para promover modelos de aprendizado de máquina de resposta a perguntas. + +Se você estiver atualizando um projeto existente, pode usar o aplicativo de exemplo como referência ou modelo. Para instruções sobre como adicionar a resposta a perguntas a um aplicativo existente, consulte [Atualizando e modificando seu aplicativo](#modify_applications). + +## Visão geral da resposta a perguntas + +A *resposta a perguntas* é a tarefa de aprendizado de máquina que responde perguntas em linguagem natural. Um modelo desse tipo treinado recebe uma passagem de texto e uma pergunta como entrada e tenta responder com base na interpretação das informações nessa passagem. + +Um modelo de resposta a perguntas é treinado com um dataset correspondente, que consiste em um dataset de compreensão de leitura, além de pares de pergunta-resposta baseados em diferentes segmentos de texto. + +Para mais informações sobre como os modelos neste tutorial são gerados, consulte o tutorial [BERT de resposta a perguntas com o Model Maker do TensorFlow Lite](https://www.tensorflow.org/lite/models/modify/model_maker/question_answer). + +## Modelos e dataset + +O aplicativo de exemplo usa o modelo Mobile BERT Q&A ([`mobilebert`](https://tfhub.dev/tensorflow/lite-model/mobilebert/1/metadata/1)), que é uma versão mais leve e rápida do [BERT](https://arxiv.org/abs/1810.04805) (Bidirectional Encoder Representations from Transformers). Para mais informações sobre `mobilebert`, consulte a pesquisa [MobileBERT: a Compact Task-Agnostic BERT for Resource-Limited Devices](https://arxiv.org/abs/2004.02984) (MobileBERT: um BERT agnóstico de tarefa e compacto para dispositivos de recursos limitados). + +O modelo `mobilebert` foi treinado usando o Stanford Question Answering Dataset ([SQuAD](https://rajpurkar.github.io/SQuAD-explorer/)), ou Dataset de respostas a perguntas da Stanford: um dataset de compreensão de leitura que consiste em artigos da Wikipedia e um conjunto de pares pergunta-resposta para cada artigo. + +## Configure e execute o aplicativo de exemplo + +Para configurar o aplicativo de resposta a perguntas, baixe o aplicativo de exemplo do [GitHub](https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/android) e o execute usando o [Android Studio](https://developer.android.com/studio/). + +### Requisitos do sistema + +- **[Android Studio](https://developer.android.com/studio/index.html)**, versão 2021.1.1 (Bumblebee) ou mais recente. +- SDK do Android, versão 31 ou mais recente. +- Dispositivo Android com uma versão mínima de SO do SDK 21 (Android 7.0 - Nougat) com o [modo desenvolvedor](https://developer.android.com/studio/debug/dev-options) ativado. + +### Obtenha o código de exemplo + +Crie uma cópia local do código de exemplo. Você usará esse código para criar um projeto no Android Studio e executar o aplicativo de exemplo. + +Para clonar e configurar o código de exemplo: + +1. Clone o repositório git +
    git clone https://github.com/tensorflow/examples.git
+        
+2. Opcionalmente, configure sua instância git para usar o sparse checkout e ter somente os arquivos para o aplicativo de exemplo de resposta a perguntas: +
    cd examples
+        git sparse-checkout init --cone
+        git sparse-checkout set lite/examples/bert_qa/android
+        
+ +### Importe e execute o projeto + +Crie um projeto a partir do código de exemplo baixado, compile e depois execute esse projeto. + +Para importar e compilar o projeto do código de exemplo: + +1. Inicie o [Android Studio](https://developer.android.com/studio). +2. No Android Studio, selecione **File > New > Import Project** (Arquivo > Novo > Importar projeto). +3. Acesse o diretório do código de exemplo com o arquivo build.gradle (`.../examples/lite/examples/bert_qa/android/build.gradle`) e selecione esse diretório. +4. Se o Android Studio solicitar o Gradle Sync, selecione OK. +5. Garanta que o dispositivo Android esteja conectado ao seu computador e que o modo desenvolvedor esteja ativado. Clique na seta `Run` verde. + +Se você selecionar o diretório correto, o Android Studio cria e compila um novo projeto. Esse processo pode levar alguns minutos, dependendo da velocidade do seu computador e se você usou o Android Studio para outros projetos. Quando o build for concluído, o Android Studio exibirá uma mensagem `BUILD SUCCESSFUL` no painel de status **Build Output**. + +Para executar o projeto: + +1. No Android Studio, execute o projeto ao selecionar **Run > Run…**. +2. Selecione um dispositivo Android conectado (ou emulador) para testar o aplicativo. + +### Usando o aplicativo + +Depois de executar o projeto no Android Studio, o aplicativo abre automaticamente no dispositivo conectado ou emulador de dispositivo. + +Para usar o aplicativo de exemplo de resposta a perguntas: + +1. Escolha um tópico na lista de assuntos. +2. Escolha uma pergunta sugerida ou insira a sua na caixa de texto. +3. Ative a seta laranja para executar o modelo. + +O aplicativo tenta identificar a resposta à pergunta a partir da passagem de texto. Se o modelo detectar uma resposta na passagem, o aplicativo destaca o trecho de texto relevante para o usuário. + +Agora você tem um aplicativo de resposta a perguntas operacional. Use as seguintes seções para entender melhor como o aplicativo de exemplo funciona e como implementar os recursos de resposta a perguntas nos seus aplicativos em produção: + +- [Como o aplicativo funciona](#how_it_works): um tutorial da estrutura e dos principais arquivos do aplicativo de exemplo. + +- [Modifique seu aplicativo](#modify_applications): instruções sobre como adicionar a resposta a perguntas a um aplicativo existente. + +## Como o aplicativo de exemplo funciona {:#how_it_works} + +O aplicativo usa a API `BertQuestionAnswerer` no pacote da [Biblioteca Task para linguagem natural (NL)](../../inference_with_metadata/task_library/overview#supported_tasks). O modelo MobileBERT foi treinado usando o [Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker/question_answer) do TensorFlow Lite. O aplicativo é executado na CPU por padrão, com a opção de aceleração de hardware usando o delegado GPU ou NNAPI. + +Os seguintes arquivos e diretórios contêm o código fundamental para esse aplicativo: + +- [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt): inicializa a resposta a perguntas e lida com a seleção de delegados e modelo. +- [QaFragment.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/fragments/QaFragment.kt): processa e formata os resultados. +- [MainActivity.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/MainActivity.kt): fornece a lógica de organização do aplicativo. + +## Modifique seu aplicativo {:#modify_applications} + +As seguintes seções explicam os principais passos para modificar seu próprio aplicativo Android e executar o modelo mostrado no aplicativo de exemplo. Essas instruções usam o aplicativo de exemplo anterior como ponto de referência. As mudanças específicas necessárias no seu próprio aplicativo podem diferir do aplicativo de exemplo. + +### Abra ou crie um projeto Android + +Você precisa de um projeto de desenvolvimento Android no Android Studio para acompanhar o resto destas instruções. Siga as instruções abaixo para abrir um projeto existente ou criar um novo. + +Para abrir um projeto de desenvolvimento Android existente: + +- No Android Studio, selecione *File > Open* (Arquivo > Abrir) e escolha um projeto existente. + +Para criar um projeto de desenvolvimento Android básico: + +- Siga as instruções no Android Studio para [Criar um projeto básico](https://developer.android.com/studio/projects/create-project). + +Para mais informações sobre como usar o Android Studio, consulte a [documentação do Android Studio](https://developer.android.com/studio/intro). + +### Adicione as dependências do projeto + +No seu próprio aplicativo, adicione as dependências do projeto para executar os modelos de aprendizado de máquina do TensorFlow Lite e acessar funções utilitárias. Essas funções convertem dados como strings em um formato de dados de tensor que pode ser processado pelo modelo. As seguintes instruções explicam como adicionar as dependências de projeto e módulo necessárias ao seu próprio projeto de app Android. + +Para adicionar dependências de módulo: + +1. No módulo que usa o TensorFlow Lite, atualize o arquivo `build.gradle` para que inclua as seguintes dependências. + + No aplicativo de exemplo, as dependências estão localizadas em [app/build.gradle](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/build.gradle): + + ``` + dependencies { + ... + // Import tensorflow library + implementation 'org.tensorflow:tensorflow-lite-task-text:0.3.0' + + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0' + implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0' + } + ``` + + O projeto precisa incluir a Biblioteca Task para texto (`tensorflow-lite-task-text`). + + Se você quiser modificar esse aplicativo para que seja executado em uma unidade de processamento gráfico (GPU), a biblioteca da GPU (`tensorflow-lite-gpu-delegate-plugin`) fornece a infraestrutura para executar o aplicativo na GPU e o Delegado (`tensorflow-lite-gpu`) oferece a lista de compatibilidade. + +2. No Android Studio, sincronize as dependências do projeto ao selecionar: **File > Sync Project with Gradle Files** (Arquivo > Sincronizar projeto com arquivos gradle). + +### Inicialize os modelos de ML {:#initialize_models} + +No seu aplicativo Android, você precisa inicializar o modelo de aprendizado de máquina do TensorFlow Lite com parâmetros antes de realizar previsões com o modelo. + +Um modelo do TensorFlow Lite é armazenado como um arquivo `*.tflite`. O arquivo do modelo contém a lógica de previsão e geralmente inclui [metadados](../../models/convert/metadata) sobre como interpretar resultados de previsão. Geralmente, os arquivos do modelo são armazenados no diretório `src/main/assets` do seu projeto de desenvolvimento, como no código de exemplo: + +- `/src/main/assets/mobilebert_qa.tflite` + +Observação: o aplicativo de exemplo usa um arquivo [`download_model.gradle`](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/download_models.gradle) para baixar o modelo [mobilebert_qa](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_question_answerer) e a [passagem de texto](https://storage.googleapis.com/download.tensorflow.org/models/tflite/bert_qa/contents_from_squad.json) no tempo de build. Essa abordagem não é necessária para um aplicativo em produção. + +Para conveniência e legibilidade do código, o exemplo declara um objeto complementar que define as configurações para o modelo. + +Para inicializar o modelo no seu aplicativo: + +1. Crie um objeto complementar para definir as configurações para o modelo. No aplicativo de exemplo, esse objeto está localizado em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L100-L106): + + ``` + companion object { + private const val BERT_QA_MODEL = "mobilebert.tflite" + private const val TAG = "BertQaHelper" + const val DELEGATE_CPU = 0 + const val DELEGATE_GPU = 1 + const val DELEGATE_NNAPI = 2 + } + ``` + +2. Crie as configurações para o modelo ao criar um objeto `BertQaHelper` e construir um objeto do TensorFlow Lite com `bertQuestionAnswerer`. + + No aplicativo de exemplo, isso está localizado na função `setupBertQuestionAnswerer()` em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L41-L76): + + ``` + class BertQaHelper( + ... + ) { + ... + init { + setupBertQuestionAnswerer() + } + + fun clearBertQuestionAnswerer() { + bertQuestionAnswerer = null + } + + private fun setupBertQuestionAnswerer() { + val baseOptionsBuilder = BaseOptions.builder().setNumThreads(numThreads) + ... + val options = BertQuestionAnswererOptions.builder() + .setBaseOptions(baseOptionsBuilder.build()) + .build() + + try { + bertQuestionAnswerer = + BertQuestionAnswerer.createFromFileAndOptions(context, BERT_QA_MODEL, options) + } catch (e: IllegalStateException) { + answererListener + ?.onError("Bert Question Answerer failed to initialize. See error logs for details") + Log.e(TAG, "TFLite failed to load model with error: " + e.message) + } + } + ... + } + ``` + +### Ative a aceleração de hardware (opcional) {:#hardware_acceleration} + +Ao inicializar um modelo do TensorFlow Lite no seu aplicativo, você deve considerar usar os recursos de aceleração de hardware para acelerar os cálculos de previsão do modelo. Os [delegados](https://www.tensorflow.org/lite/performance/delegates) do TensorFlow Lite são módulos de software que aceleram a execução dos modelos de aprendizado de máquina usando hardware de processamento especializado em um dispositivo móvel, como unidades de processamento gráfico (GPUs) ou unidades de processamento de tensor (TPUs). + +Para ativar a aceleração de hardware no seu aplicativo: + +1. Crie uma variável para definir o delegado que o aplicativo usará. No aplicativo de exemplo, essa variável está localizada no início em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L31): + + ``` + var currentDelegate: Int = 0 + ``` + +2. Crie um seletor de delegado. No aplicativo de exemplo, esse seletor está localizado na função `setupBertQuestionAnswerer` em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L48-L62): + + ``` + when (currentDelegate) { + DELEGATE_CPU -> { + // Default + } + DELEGATE_GPU -> { + if (CompatibilityList().isDelegateSupportedOnThisDevice) { + baseOptionsBuilder.useGpu() + } else { + answererListener?.onError("GPU is not supported on this device") + } + } + DELEGATE_NNAPI -> { + baseOptionsBuilder.useNnapi() + } + } + ``` + +Usar os delegados para executar modelos do TensorFlow é recomendável, mas não obrigatório. Para mais informações sobre como usar os delegados com o TensorFlow Lite, consulte [Delegados do TensorFlow Lite](https://www.tensorflow.org/lite/performance/delegates). + +### Prepare os dados para o modelo + +No seu aplicativo Android, seu código fornece dados ao modelo para interpretação ao transformar dados existentes, como texto bruto, em um formato de dados de [Tensor](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Tensor) que pode ser processado pelo modelo. Os dados em um Tensor passados a um modelo precisam ter dimensões específicas, ou um formato, que correspondam ao formato dos dados usados para treinar o modelo. Esse aplicativo de resposta a perguntas aceita [strings](https://developer.android.com/reference/java/lang/String.html) como entradas para tanto a passagem de texto como a pergunta. O modelo não reconhece caracteres especiais e palavras que não estiverem em inglês. + +Para fornecer dados de passagem de texto ao modelo: + +1. Use o objeto `LoadDataSetClient` para carregar os dados de passagem de texto no aplicativo. No aplicativo de exemplo, isso está localizado em [LoadDataSetClient.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/dataset/LoadDataSetClient.kt#L25-L45) + + ``` + fun loadJson(): DataSet? { + var dataSet: DataSet? = null + try { + val inputStream: InputStream = context.assets.open(JSON_DIR) + val bufferReader = inputStream.bufferedReader() + val stringJson: String = bufferReader.use { it.readText() } + val datasetType = object : TypeToken() {}.type + dataSet = Gson().fromJson(stringJson, datasetType) + } catch (e: IOException) { + Log.e(TAG, e.message.toString()) + } + return dataSet + } + ``` + +2. Use o objeto `DatasetFragment` para listar os títulos de cada passagem de texto e iniciar a tela **Pergunta e Resposta TFL**. No aplicativo de exemplo, isso está localizado em [DatasetFragment.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/fragments/DatasetFragment.kt): + + ``` + class DatasetFragment : Fragment() { + ... + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val client = LoadDataSetClient(requireActivity()) + client.loadJson()?.let { + titles = it.getTitles() + } + ... + } + ... + } + ``` + +3. Use a função `onCreateViewHolder` no objeto `DatasetAdapter` para apresentar os títulos de cada passagem de texto. No aplicativo de exemplo, isso está localizado em [DatasetAdapter.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/fragments/DatasetAdapter.kt): + + ``` + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemDatasetBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + return ViewHolder(binding) + } + ``` + +Para fornecer perguntas do usuário ao modelo: + +1. Use o objeto `QaAdapter` para fornecer a pergunta ao modelo. No aplicativo de exemplo, esse objeto está localizado em [QaAdapter.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/fragments/QaAdapter.kt): + + ``` + class QaAdapter(private val question: List, private val select: (Int) -> Unit) : + RecyclerView.Adapter() { + + inner class ViewHolder(private val binding: ItemQuestionBinding) : + RecyclerView.ViewHolder(binding.root) { + init { + binding.tvQuestionSuggestion.setOnClickListener { + select.invoke(adapterPosition) + } + } + + fun bind(question: String) { + binding.tvQuestionSuggestion.text = question + } + } + ... + } + ``` + +### Realize previsões + +No seu aplicativo Android, depois de inicializar um objeto [BertQuestionAnswerer](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/text/qa/BertQuestionAnswerer), você pode começar a inserir perguntas em texto de linguagem natural no modelo. O modelo tenta identificar a resposta na passagem de texto. + +Para realizar previsões: + +1. Crie uma função `answer`, que executa o modelo e mede o tempo que leva para identificar a resposta (`inferenceTime`). No aplicativo de exemplo, a função `answer` está localizada em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L78-L98): + + ``` + fun answer(contextOfQuestion: String, question: String) { + if (bertQuestionAnswerer == null) { + setupBertQuestionAnswerer() + } + + var inferenceTime = SystemClock.uptimeMillis() + + val answers = bertQuestionAnswerer?.answer(contextOfQuestion, question) + inferenceTime = SystemClock.uptimeMillis() - inferenceTime + answererListener?.onResults(answers, inferenceTime) + } + ``` + +2. Passe os resultados de `answer` ao objeto listener. + + ``` + interface AnswererListener { + fun onError(error: String) + fun onResults( + results: List?, + inferenceTime: Long + ) + } + ``` + +### Processe a saída do modelo + +Depois de inserir uma pergunta, o modelo fornece no máximo cinco respostas possíveis na passagem. + +Para obter os resultados do modelo: + +1. Crie uma função `onResult` para o objeto listener processar a saída. No aplicativo de exemplo, o objeto listener está localizado em [BertQaHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/BertQaHelper.kt#L92-L98) + + ``` + interface AnswererListener { + fun onError(error: String) + fun onResults( + results: List?, + inferenceTime: Long + ) + } + ``` + +2. Destaque seções da passagem com base nos resultados. No aplicativo de exemplo, isso está localizado em [QaFragment.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/bert_qa/android/app/src/main/java/org/tensorflow/lite/examples/bertqa/fragments/QaFragment.kt#L199-L208): + + ``` + override fun onResults(results: List?, inferenceTime: Long) { + results?.first()?.let { + highlightAnswer(it.text) + } + + fragmentQaBinding.tvInferenceTime.text = String.format( + requireActivity().getString(R.string.bottom_view_inference_time), + inferenceTime + ) + } + ``` + +Depois que o modelo retornar um conjunto de resultados, seu aplicativo pode agir em relação a essas previsões ao apresentar o resultado ao seu usuário ou executar lógica adicional. + +## Próximos passos + +- Treine e implemente os modelos do zero com o tutorial [Resposta a perguntas com o Model Maker do TensorFlow Lite](https://www.tensorflow.org/lite/models/modify/model_maker/question_answer). +- Explore mais [ferramentas de processamento de texto para o TensorFlow](https://www.tensorflow.org/text). +- Baixe outros modelos BERT no [TensorFlow Hub](https://tfhub.dev/google/collections/bert/1). +- Descubra os usos do TensorFlow Lite nos [exemplos](../../examples). diff --git a/site/pt-br/lite/android/tutorials/text_classification.md b/site/pt-br/lite/android/tutorials/text_classification.md new file mode 100644 index 0000000000..ba0a64bee1 --- /dev/null +++ b/site/pt-br/lite/android/tutorials/text_classification.md @@ -0,0 +1,331 @@ +# Classificação de texto com o Android + +Este tutorial mostra como criar um aplicativo Android usando o TensorFlow Lite para classificar texto de linguagem natural. Esse aplicativo foi feito para um dispositivo Android físico, mas também pode ser executado em um emulador de dispositivo. + +O [aplicativo de exemplo](https://github.com/tensorflow/examples/tree/master/lite/examples/text_classification/android) usa o TensorFlow Lite para classificar texto como positivo ou negativo, usando a [Biblioteca Task para linguagem natural (NL)](../../inference_with_metadata/task_library/overview#supported_tasks) para permitir a execução de modelos de aprendizado de máquina de classificação de texto. + +Se você estiver atualizando um projeto existente, pode usar o aplicativo de exemplo como referência ou modelo. Para instruções sobre como adicionar a classificação de texto a um aplicativo existente, consulte [Atualizando e modificando seu aplicativo](#modify_applications). + +## Visão geral da classificação de texto + +A *classificação de texto* é a tarefa de aprendizado de máquina que atribui um conjunto de categorias predefinidas a um texto aberto. Um modelo de classificação de texto é treinado com um corpus de texto de linguagem natural, em que palavras ou frases são classificadas manualmente. + +O modelo treinado recebe texto como entrada e tenta categorizar esse texto de acordo com o conjunto de classes conhecidas que foi treinado para classificar. Por exemplo, o modelo neste exemplo aceita um fragmento de texto e determina se o sentimento do texto é positivo ou negativo. Para cada fragmento, o modelo de classificação gera uma pontuação que indica a confiança do texto ser classificado corretamente como positivo ou negativo. + +Para mais informações sobre como os modelos neste tutorial são gerados, consulte o tutorial [Classificação de texto com o Model Maker do TensorFlow Lite](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification). + +## Modelos e dataset + +Este tutorial usa modelos que foram treinados usando o dataset [SST-2](https://nlp.stanford.edu/sentiment/index.html) (Stanford Sentiment Treebank, ou Treebank de Sentimentos da Stanford). O SST-2 contém 67.349 avaliações de filmes para treinamento e 872 para teste, sendo cada uma categorizada como positiva ou negativa. Os modelos usados neste aplicativo foram treinados usando a ferramenta [Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification) do TensorFlow Lite. + +O aplicativo de exemplo usa os seguintes modelos pré-treinados: + +- [Average Word Vector](https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier) (`NLClassifier`): o `NLClassifier` da Biblioteca Task classifica o texto de entrada em diferentes categorias e consegue lidar com a maioria dos modelos de classificação de texto. + +- [MobileBERT](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier) (`BertNLClassifier`): o `BertNLClassifier` da Biblioteca Task é semelhante ao NLClassifier, mas adaptado a casos que exigem tokenizações por palavra e frase fora do grafo. + +## Configure e execute o aplicativo de exemplo + +Para configurar o aplicativo de classificação de texto, baixe o aplicativo de exemplo do [GitHub](https://github.com/tensorflow/examples/tree/master/lite/examples/text_classification/android) e o execute usando o [Android Studio](https://developer.android.com/studio/). + +### Requisitos do sistema + +- **[Android Studio](https://developer.android.com/studio/index.html)**, versão 2021.1.1 (Bumblebee) ou mais recente. +- SDK do Android, versão 31 ou mais recente. +- Dispositivo Android com uma versão mínima de SO do SDK 21 (Android 7.0 - Nougat) com o [modo desenvolvedor](https://developer.android.com/studio/debug/dev-options) ativado. + +### Obtenha o código de exemplo + +Crie uma cópia local do código de exemplo. Você usará esse código para criar um projeto no Android Studio e executar o aplicativo de exemplo. + +Para clonar e configurar o código de exemplo: + +1. Clone o repositório git +
    git clone https://github.com/tensorflow/examples.git
+        
+2. Opcionalmente, configure sua instância git para usar o sparse checkout e ter somente os arquivos para o aplicativo de exemplo de classificação de texto: +
    cd examples
+        git sparse-checkout init --cone
+        git sparse-checkout set lite/examples/text_classification/android
+        
+ +### Importe e execute o projeto + +Crie um projeto a partir do código de exemplo baixado, compile e depois execute esse projeto. + +Para importar e compilar o projeto do código de exemplo: + +1. Inicie o [Android Studio](https://developer.android.com/studio). +2. No Android Studio, selecione **File > New > Import Project** (Arquivo > Novo > Importar projeto). +3. Acesse o diretório do código de exemplo com o arquivo build.gradle (`.../examples/lite/examples/text_classification/android/build.gradle`) e selecione esse diretório. +4. Se o Android Studio solicitar o Gradle Sync, selecione OK. +5. Garanta que o dispositivo Android esteja conectado ao seu computador e que o modo desenvolvedor esteja ativado. Clique na seta `Run` verde. + +Se você selecionar o diretório correto, o Android Studio cria e compila um novo projeto. Esse processo pode levar alguns minutos, dependendo da velocidade do seu computador e se você usou o Android Studio para outros projetos. Quando o build for concluído, o Android Studio exibirá uma mensagem `BUILD SUCCESSFUL` no painel de status **Build Output**. + +Para executar o projeto: + +1. No Android Studio, execute o projeto ao selecionar **Run > Run…**. +2. Selecione um dispositivo Android conectado (ou emulador) para testar o aplicativo. + +### Usando o aplicativo + +![Aplicativo de exemplo de classificação de texto no Android](../../../images/lite/android/text-classification-screenshot.png){: .attempt-right width="250px"} + +Depois de executar o projeto no Android Studio, o aplicativo abre automaticamente no dispositivo conectado ou emulador de dispositivo. + +Para usar o classificador de texto: + +1. Insira um fragmento de texto na caixa de texto. +2. No menu suspenso **Delegate**, selecione `CPU` ou `NNAPI`. +3. Especifique um modelo ao escolher `AverageWordVec` ou `MobileBERT`. +4. Selecione **Classify** (Classificar). + +O aplicativo gera uma pontuação *positiva* e uma *negativa*. Essas duas pontuações juntas somam 1 e medem a probabilidade de o sentimento do texto inserido ser positivo ou negativo. Um número mais alto indica um maior nível de confiança. + +Agora você tem um aplicativo de classificação de texto. Use as seguintes seções para entender melhor como o aplicativo de exemplo funciona e como implementar os recursos de classificação de texto nos seus aplicativos em produção: + +- [Como o aplicativo funciona](#how_it_works): um tutorial da estrutura e dos principais arquivos do aplicativo de exemplo. + +- [Modifique seu aplicativo](#modify_applications): instruções sobre como adicionar a classificação de texto a um aplicativo existente. + +## Como o aplicativo de exemplo funciona {:#how_it_works} + +O aplicativo usa a [Biblioteca Task para linguagem natural (NL)](../../inference_with_metadata/task_library/overview#supported_tasks) para implementar modelos de classificação de texto. Os dois modelos, Average Word Vector e MobileBERT, foram treinados usando o [Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification) do TensorFlow Lite. O aplicativo é executado na CPU por padrão, com a opção da aceleração de hardware usando o delegado NNAPI. + +Os seguintes arquivos e diretórios contêm o código fundamental para esse aplicativo de classificação de texto: + +- [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): inicializa o classificador de texto e lida com a seleção de delegados e modelo. +- [MainActivity.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/MainActivity.kt): implementa o aplicativo, inclusive chamando `TextClassificationHelper` e `ResultsAdapter`. +- [ResultsAdapter.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/ResultsAdapter.kt): processa e formata os resultados. + +## Modifique seu aplicativo {:#modify_applications} + +As seguintes seções explicam os principais passos para modificar seu próprio aplicativo Android e executar o modelo mostrado no aplicativo de exemplo. Essas instruções usam o aplicativo de exemplo anterior como ponto de referência. As mudanças específicas necessárias no seu próprio aplicativo podem diferir do aplicativo de exemplo. + +### Abra ou crie um projeto Android + +Você precisa de um projeto de desenvolvimento Android no Android Studio para acompanhar o resto destas instruções. Siga as instruções abaixo para abrir um projeto existente ou criar um novo. + +Para abrir um projeto de desenvolvimento Android existente: + +- No Android Studio, selecione *File > Open* (Arquivo > Abrir) e escolha um projeto existente. + +Para criar um projeto de desenvolvimento Android básico: + +- Siga as instruções no Android Studio para [Criar um projeto básico](https://developer.android.com/studio/projects/create-project). + +Para mais informações sobre como usar o Android Studio, consulte a [documentação do Android Studio](https://developer.android.com/studio/intro). + +### Adicione as dependências do projeto + +No seu próprio aplicativo, você precisa adicionar as dependências do projeto para executar os modelos de aprendizado de máquina do TensorFlow e acessar funções utilitárias que convertem dados como strings em um formato de dados de tensor que pode ser processado pelo modelo que você está usando. + +As instruções a seguir explicam como adicionar as dependências de projeto e módulo necessárias ao seu próprio projeto de aplicativo Android. + +Para adicionar dependências de módulo: + +1. No módulo que usa o TensorFlow Lite, atualize o arquivo `build.gradle` para que inclua as seguintes dependências. + + No aplicativo de exemplo, as dependências estão localizadas em [app/build.gradle](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/build.gradle): + + ``` + dependencies { + ... + implementation 'org.tensorflow:tensorflow-lite-task-text:0.4.0' + } + ``` + + O projeto precisa incluir a Biblioteca Task para texto (`tensorflow-lite-task-text`). + + Se você quiser modificar esse aplicativo para que seja executado em uma unidade de processamento gráfico (GPU), a biblioteca da GPU (`tensorflow-lite-gpu-delegate-plugin`) fornece a infraestrutura para executar o aplicativo na GPU e o Delegado (`tensorflow-lite-gpu`) oferece a lista de compatibilidade. A execução desse aplicativo na GPU está fora do escopo deste tutorial. + +2. No Android Studio, sincronize as dependências do projeto ao selecionar: **File > Sync Project with Gradle Files** (Arquivo > Sincronizar projeto com arquivos gradle). + +### Inicialize os modelos de ML {:#initialize_models} + +No seu aplicativo Android, você precisa inicializar o modelo de aprendizado de máquina do TensorFlow Lite com parâmetros antes de realizar previsões com o modelo. + +Um modelo do TensorFlow Lite é armazenado como um arquivo `*.tflite`. O arquivo do modelo contém a lógica de previsão e geralmente inclui [metadados](../../models/convert/metadata) sobre como interpretar resultados de previsão, como nomes de classes de previsão. Geralmente, os arquivos do modelo são armazenados no diretório `src/main/assets` do seu projeto de desenvolvimento, como no código de exemplo: + +- `/src/main/assets/mobilebert.tflite` +- `/src/main/assets/wordvec.tflite` + +Observação: esse aplicativo de exemplo usa um arquivo `[download_model.gradle](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/download_model.gradle)` para baixar os modelos [Average Word Vector](https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier) e [MobileBERT](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier) no tempo de build. Essa abordagem não é necessária nem recomendada para um aplicativo em produção. + +Para conveniência e legibilidade do código, o exemplo declara um objeto complementar que define as configurações para o modelo. + +Para inicializar o modelo no seu aplicativo: + +1. Crie um objeto complementar para definir as configurações para o modelo. No aplicativo de exemplo, esse objeto está localizado em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + companion object { + const val DELEGATE_CPU = 0 + const val DELEGATE_NNAPI = 1 + const val WORD_VEC = "wordvec.tflite" + const val MOBILEBERT = "mobilebert.tflite" + } + ``` + +2. Crie as configurações para o modelo ao criar um objeto classificador e construir um objeto do TensorFlow Lite com `BertNLClassifier` ou `NLClassifier`. + + No aplicativo de exemplo, isso está localizado na função `initClassifier` em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + fun initClassifier() { + ... + if( currentModel == MOBILEBERT ) { + ... + bertClassifier = BertNLClassifier.createFromFileAndOptions( + context, + MOBILEBERT, + options) + } else if (currentModel == WORD_VEC) { + ... + nlClassifier = NLClassifier.createFromFileAndOptions( + context, + WORD_VEC, + options) + } + } + ``` + + Observação: a maioria dos aplicativos em produção que usam a classificação de texto utilizarão `BertNLClassifier` ou `NLClassifier`, e não ambos. + +### Ative a aceleração de hardware (opcional) {:#hardware_acceleration} + +Ao inicializar um modelo do TensorFlow Lite no seu aplicativo, você deve considerar usar os recursos de aceleração de hardware para acelerar os cálculos de previsão do modelo. Os [delegados](https://www.tensorflow.org/lite/performance/delegates) do TensorFlow Lite são módulos de software que aceleram a execução dos modelos de aprendizado de máquina usando hardware de processamento especializado em um dispositivo móvel, como unidades de processamento gráfico (GPUs) ou unidades de processamento de tensor (TPUs). + +Para ativar a aceleração de hardware no seu aplicativo: + +1. Crie uma variável para definir o delegado que o aplicativo usará. No aplicativo de exemplo, essa variável está localizada no início em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + var currentDelegate: Int = 0 + ``` + +2. Crie um seletor de delegado. No aplicativo de exemplo, esse seletor está localizado na função `initClassifier` em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + val baseOptionsBuilder = BaseOptions.builder() + when (currentDelegate) { + DELEGATE_CPU -> { + // Default + } + DELEGATE_NNAPI -> { + baseOptionsBuilder.useNnapi() + } + } + ``` + +Observação: é possível modificar esse aplicativo para usar um delegado de GPU, mas isso exige que o classificador seja criado no mesmo thread que está usando esse classificador. Isso está fora do escopo deste tutorial. + +Usar os delegados para executar modelos do TensorFlow é recomendável, mas não obrigatório. Para mais informações sobre como usar os delegados com o TensorFlow Lite, consulte [Delegados do TensorFlow Lite](https://www.tensorflow.org/lite/performance/delegates). + +### Prepare os dados para o modelo + +No seu aplicativo Android, seu código fornece dados ao modelo para interpretação ao transformar dados existentes, como texto bruto, em um formato de dados de [Tensor](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Tensor) que pode ser processado pelo modelo. Os dados em um Tensor passados a um modelo precisam ter dimensões específicas, ou um formato, que correspondam ao formato dos dados usados para treinar o modelo. + +Esse aplicativo de classificação de texto aceita uma [string](https://developer.android.com/reference/java/lang/String.html) como entrada, e os modelos são treinados exclusivamente com um corpus de língua inglesa. Caracteres especiais e palavras que não estão em inglês são ignoradas durante a inferência. + +Para fornecer dados de texto ao modelo: + +1. Verifique se a função `initClassifier` contém o código para o delegado e os modelos, conforme explicado nas seções [Inicialize os modelos de ML](#initialize_models) e [Ative a aceleração de hardware](#hardware_acceleration). + +2. Use o bloco `init` para chamar a função `initClassifier`. No aplicativo de exemplo, o `init` está localizado em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + init { + initClassifier() + } + ``` + +### Realize previsões + +No seu aplicativo Android, depois de inicializar um objeto [BertNLClassifier](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/text/nlclassifier/BertNLClassifier) ou [NLClassifier](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/text/nlclassifier/NLClassifier), você pode começar a inserir o texto para o modelo categorizar como "positivo" ou "negativo". + +Para realizar previsões: + +1. Crie uma função `classify`, que usa o classificador selecionado (`currentModel`) e mede o tempo que leva para classificar o texto de entrada (`inferenceTime`). No aplicativo de exemplo, a função `classify` está localizada em [TextClassificationHelper.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/TextClassificationHelper.kt): + + ``` + fun classify(text: String) { + executor = ScheduledThreadPoolExecutor(1) + + executor.execute { + val results: List + // inferenceTime is the amount of time, in milliseconds, that it takes to + // classify the input text. + var inferenceTime = SystemClock.uptimeMillis() + + // Use the appropriate classifier based on the selected model + if(currentModel == MOBILEBERT) { + results = bertClassifier.classify(text) + } else { + results = nlClassifier.classify(text) + } + + inferenceTime = SystemClock.uptimeMillis() - inferenceTime + + listener.onResult(results, inferenceTime) + } + } + ``` + +2. Passe os resultados de `classify` ao objeto listener. + + ``` + fun classify(text: String) { + ... + listener.onResult(results, inferenceTime) + } + ``` + +### Processe a saída do modelo + +Depois de inserir uma linha de texto, o modelo produz uma pontuação de previsão, expressa como um Float, entre 0 e 1 para as categorias "positivo" e "negativo". + +Para obter os resultados de previsão do modelo: + +1. Crie uma função `onResult` para o objeto listener processar a saída. No aplicativo de exemplo, o objeto listener está localizado em [MainActivity.kt](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/app/src/main/java/org/tensorflow/lite/examples/textclassification/MainActivity.kt) + + ``` + private val listener = object : TextClassificationHelper.TextResultsListener { + override fun onResult(results: List, inferenceTime: Long) { + runOnUiThread { + activityMainBinding.bottomSheetLayout.inferenceTimeVal.text = + String.format("%d ms", inferenceTime) + + adapter.resultsList = results.sortedByDescending { + it.score + } + + adapter.notifyDataSetChanged() + } + } + ... + } + ``` + +2. Adicione uma função `onError` ao objeto listener para lidar com os erros: + + ``` + private val listener = object : TextClassificationHelper.TextResultsListener { + ... + override fun onError(error: String) { + Toast.makeText(this@MainActivity, error, Toast.LENGTH_SHORT).show() + } + } + ``` + +Depois que o modelo retornar um conjunto de resultados de previsão, seu aplicativo pode agir em relação a essas previsões ao apresentar o resultado ao seu usuário ou executar lógica adicional. O aplicativo de exemplo lista as pontuações de previsão na interface do usuário. + +## Próximos passos + +- Treine e implemente os modelos do zero com o tutorial [Classificação de texto com o Model Maker do TensorFlow Lite](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification). +- Explore mais [ferramentas de processamento de texto para o TensorFlow](https://www.tensorflow.org/text). +- Baixe outros modelos BERT no [TensorFlow Hub](https://tfhub.dev/google/collections/bert/1). +- Descubra os usos do TensorFlow Lite nos [exemplos](../../examples). +- Saiba mais sobre como usar modelos de aprendizado de máquina com o TensorFlow Lite na seção [Modelos](../../models). +- Saiba mais sobre como implementar o aprendizado de máquina no seu aplicativo para dispositivos móveis no [Guia para desenvolvedores do TensorFlow Lite](../../guide). diff --git a/site/pt-br/lite/guide/build_arm.md b/site/pt-br/lite/guide/build_arm.md new file mode 100644 index 0000000000..0c3954c1f3 --- /dev/null +++ b/site/pt-br/lite/guide/build_arm.md @@ -0,0 +1,82 @@ +# Compile o TensorFlow Lite para placas ARM + +Esta página descreve como compilar as bibliotecas do TensorFlow Lite para computadores ARM. + +O TensorFlow Lite tem suporte a dois sistemas de build, mas os recursos de cada sistema de compilação não são idênticos. Confira a tabela abaixo para escolher o sistema de compilação adequado. + +Recurso | Bazel | CMake +--- | --- | --- +Toolchains predefinidas | armhf, aarch64 | armel, armhf, aarch64 +Toolchains personalizadas | Mais difícil de usar | Fácil de usar +[Select TF ops](https://www.tensorflow.org/lite/guide/ops_select) | Com suporte | Sem suporte +[Delegado de GPU](https://www.tensorflow.org/lite/performance/gpu) | Disponível somente para Android | Qualquer plataforma com suporte ao OpenCL +XNNPack | Com suporte | Com suporte +[Wheel do Python](https://www.tensorflow.org/lite/guide/build_cmake_pip) | Com suporte | Com suporte +[API do C](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/README.md) | Com suporte | [Com suporte](https://www.tensorflow.org/lite/guide/build_cmake#build_tensorflow_lite_c_library) +[API do C++](https://www.tensorflow.org/lite/guide/inference#load_and_run_a_model_in_c) | Com suporte para projetos Bazel | Com suporte para projetos CMake + +## Compilação cruzada para ARM com CMake + +Se você tiver um projeto CMake ou se quiser usar uma toolchain personalizada, é melhor usar o CMake para fazer a compilação cruzada. Existe uma página [Compilação cruzada do TensorFlow Lite com o CMake](https://www.tensorflow.org/lite/guide/build_cmake_arm) específica para isso. + +## Compilação cruzada para ARM com Bazel + +Se você tiver um projeto Bazel ou se quiser usar operações do TF, é melhor usar o sistema de build Bazel. Você usará as [toolchains ARM GCC 8.3](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/toolchains/embedded/arm-linux) integradas com o Bazel para compilar uma biblioteca ARM32/64 compartilhada. + +Arquitetura desejada | Configuração do Bazel | Dispositivos compatíveis +--- | --- | --- +armhf (ARM32) | --config=elinux_armhf | RPI3, RPI4 com 32 bits +: : : Raspberry Pi OS : | | +AArch64 (ARM64) | --config=elinux_aarch64 | Coral, RPI4 com Ubuntu 64 +: : : bits : | | + +Observação: a biblioteca compartilhada gerada requer o glibc 2.28 ou superior para ser executada. + +As instruções abaixo foram testadas em um PC (AMD64) com Ubuntu 16.04.3 de 64 bits e na imagem devel docker do TensorFlow [tensorflow/tensorflow:devel](https://hub.docker.com/r/tensorflow/tensorflow/tags/). + +Para fazer a compilação cruzada do TensorFlow Lite com o Bazel, siga estas etapas: + +#### Etapa 1. Instale o Bazel + +O Bazel é o principal sistema de compilação para o TensorFlow. Instale a versão mais recente do [sistema de compilação Bazel](https://bazel.build/versions/master/docs/install.html). + +**Observação:** se você estiver usando a imagem docker do TensorFlow, o Bazel já está disponível. + +#### Etapa 2. Clone o repositório do TensorFlow + +```sh +git clone https://github.com/tensorflow/tensorflow.git tensorflow_src +``` + +**Observação:** se você estiver usando a imagem docker do TensorFlow, o repositório já está disponível em `/tensorflow_src/`. + +#### Etapa 3. Compile o binário ARM + +##### Biblioteca do C + +```bash +bazel build --config=elinux_aarch64 -c opt //tensorflow/lite/c:libtensorflowlite_c.so +``` + +A biblioteca compartilhada está disponível em: `bazel-bin/tensorflow/lite/c/libtensorflowlite_c.so`. + +**Observação:** use `elinux_armhf` para uma compilação [ARM hard-float de 32 bits](https://wiki.debian.org/ArmHardFloatPort). + +Confira mais detalhes na página da [API do C para TensorFlow Lite](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/README.md). + +##### Biblioteca do C++ + +```bash +bazel build --config=elinux_aarch64 -c opt //tensorflow/lite:libtensorflowlite.so +``` + +A biblioteca compartilhada está disponível em: `bazel-bin/tensorflow/lite/libtensorflowlite.so`. + +No momento, não há uma maneira simples de extrair todos os arquivos de cabeçalho necessários, então você precisa incluir todos os arquivos em tensorflow/lite/ a partir do repositório do TensorFlow. Além disso, você precisará dos arquivos de cabeçalho de FlatBuffers e Abseil. + +##### Etc. + +Você também pode compilar outros alvos do Bazel com a toolchain. Veja alguns alvos úteis: + +- //tensorflow/lite/tools/benchmark:benchmark_model +- //tensorflow/lite/examples/label_image:label_image diff --git a/site/pt-br/lite/guide/build_cmake.md b/site/pt-br/lite/guide/build_cmake.md new file mode 100644 index 0000000000..6c46bc4a25 --- /dev/null +++ b/site/pt-br/lite/guide/build_cmake.md @@ -0,0 +1,242 @@ +# Compile o TensorFlow Lite com o CMake + +Esta página descreve como compilar e usar a biblioteca do TensorFlow Lite com a ferramenta [CMake](https://cmake.org/). + +As instruções abaixo foram testadas em um PC (AMD64) com Ubuntu 16.04.3 de 64 bits, macOS Catalina (x86_64), Windows 10 e imagem devel docker do TensorFlow [tensorflow/tensorflow:devel](https://hub.docker.com/r/tensorflow/tensorflow/tags/). + +**Observação:** esse recurso está disponível a partir a versão 2.4. + +### Etapa 1. Instale a ferramenta CMake + +É necessário o CMake 3.16 ou superior. No Ubuntu, basta executar o seguinte comando: + +```sh +sudo apt-get install cmake +``` + +Ou confira [o guia de instalação oficial do CMake](https://cmake.org/install/). + +### Etapa 2. Clone o repositório do TensorFlow + +```sh +git clone https://github.com/tensorflow/tensorflow.git tensorflow_src +``` + +**Observação:** se você estiver usando a imagem docker do TensorFlow, o repositório já está disponível em `/tensorflow_src/`. + +### Etapa 3. Crie o diretório de builds do CMake + +```sh +mkdir tflite_build +cd tflite_build +``` + +### Etapa 4. Execute a ferramenta CMake com configurações + +#### Build de lançamento + +É gerado um binário de lançamento otimizado por padrão. Se você deseja compilar para sua estação de trabalho, basta executar o seguinte comando: + +```sh +cmake ../tensorflow_src/tensorflow/lite +``` + +#### Build de depuração + +Se você precisar gerar uma build de depuração que tenha informações de símbolo, precisa fornecer a opção `-DCMAKE_BUILD_TYPE=Debug`. + +```sh +cmake ../tensorflow_src/tensorflow/lite -DCMAKE_BUILD_TYPE=Debug +``` + +#### Compilação dos testes de unidade do kernel + +Para poder executar os testes do kernel, você precisa fornecer o sinalizador `-DTFLITE_KERNEL_TEST=on`. As especificidades da compilação cruzada dos testes de unidade estão disponíveis na próxima subseção. + +```sh +cmake ../tensorflow_src/tensorflow/lite -DTFLITE_KERNEL_TEST=on +``` + +#### Compile pacotes instaláveis + +Para compilar um pacote instalável que poderá ser usado como dependência por outro projeto do CMake com `find_package(tensorflow-lite CONFIG)`, use a opção `-DTFLITE_ENABLE_INSTALL=ON`. + +Idealmente, você deve fornecer suas próprias versões das dependências de bibliotecas, que também precisarão ser usadas pelo projeto que depende do TF Lite. Você pode usar a variável `-DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON` e definir que a variável `_DIR` aponte para as instalações das suas bibliotecas. + +```sh +cmake ../tensorflow_src/tensorflow/lite -DTFLITE_ENABLE_INSTALL=ON \ + -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \ + -DSYSTEM_FARMHASH=ON \ + -DSYSTEM_PTHREADPOOL=ON \ + -Dabsl_DIR=/lib/cmake/absl \ + -DEigen3_DIR=/share/eigen3/cmake \ + -DFlatBuffers_DIR=/lib/cmake/flatbuffers \ + -Dgemmlowp_DIR=/lib/cmake/gemmlowp \ + -DNEON_2_SSE_DIR=/lib/cmake/NEON_2_SSE \ + -Dcpuinfo_DIR=/share/cpuinfo \ + -Druy_DIR=/lib/cmake/ruy +``` + +**Observação:** Consulte a documentação do CMake sobre [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html) para saber mais sobre como tratar e localizar pacotes. + +#### Compilação cruzada + +Você pode usar o CMake para compilar binários para arquiteturas ARM64 ou Android. + +Para fazer a compilação cruzada do TF Lite, você precisa fornecer o caminho do SDK (por exemplo, ARM64 SDK ou NDK no caso do Android) com o sinalizador `-DCMAKE_TOOLCHAIN_FILE`. + +```sh +cmake -DCMAKE_TOOLCHAIN_FILE= ../tensorflow/lite/ +``` + +##### Especificidades da compilação cruzada para Android + +No caso de compilação cruzada para Android, você precisa instalar o [Android NDK](https://developer.android.com/ndk) e fornecer o caminho do NDK com o sinalizador `-DCMAKE_TOOLCHAIN_FILE` mencionado acima. Além disso, você precisa definir a ABI desejada com o sinalizador `-DANDROID_ABI`. + +```sh +cmake -DCMAKE_TOOLCHAIN_FILE=/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=arm64-v8a ../tensorflow_src/tensorflow/lite +``` + +##### Especificidades da compilação cruzada dos testes (de unidade) do kernel + +A compilação cruzada dos testes de unidade requer o compilador flatc para a arquitetura do host. Para essa finalidade, existe uma CMakeLists localizada em `tensorflow/lite/tools/cmake/native_tools/flatbuffers` para compilar o compilador flatc com o CMake antecipadamente em um diretório de builds separado usando a toolchain do host. + +```sh +mkdir flatc-native-build && cd flatc-native-build +cmake ../tensorflow_src/tensorflow/lite/tools/cmake/native_tools/flatbuffers +cmake --build . +``` + +Também é possível **instalar** o *flatc* em um local de instalação personalizado (por exemplo, um diretório contendo outras ferramentas compiladas nativamente em vez do diretório de builds do CMake): + +```sh +cmake -DCMAKE_INSTALL_PREFIX= ../tensorflow_src/tensorflow/lite/tools/cmake/native_tools/flatbuffers +cmake --build . +``` + +Para a compilação cruzada do TF Lite em si, o parâmetro adicional `-DTFLITE_HOST_TOOLS_DIR=` apontando para o diretório contendo o binário *flatc* nativo precisa ser fornecido, juntamente com o sinalizador `-DTFLITE_KERNEL_TEST=on` mencionado acima. + +```sh +cmake -DCMAKE_TOOLCHAIN_FILE=${OE_CMAKE_TOOLCHAIN_FILE} -DTFLITE_KERNEL_TEST=on -DTFLITE_HOST_TOOLS_DIR= ../tensorflow/lite/ +``` + +##### Execução dos testes (de unidade) do kernel com compilação cruzada no alvo + +Os testes de unidade podem ser executados como executáveis separados ou usando o utilitário CTest. Quanto ao CTest, se pelo menos um dos parâmetros `TFLITE_ENABLE_NNAPI, TFLITE_ENABLE_XNNPACK` ou `TFLITE_EXTERNAL_DELEGATE` estiver ativado na build do TF Lite, os testes resultantes serão gerados com dois **labels** diferentes (utilizando o mesmo executável de teste); *plain* – que denota os testes executados no back-end de CPU; e *delegate* – que denota os testes que esperam argumentos de execução adicionais usados para a especificação do delegado. + +Tanto `CTestTestfile.cmake` quanto `run-tests.cmake` (conforme indicado acima) estão disponíveis em `/kernels`. + +Execução de testes de unidade com back-end de CPU (desde que `CTestTestfile.cmake` esteja presente no diretório atual do alvo): + +```sh +ctest -L plain +``` + +Exemplos de execução de testes de unidade usando delegados (desde que `CTestTestfile.cmake` bem como `run-tests.cmake` estejam presentes no diretório atual do alvo): + +```sh +cmake -E env TESTS_ARGUMENTS=--use_nnapi=true\;--nnapi_accelerator_name=vsi-npu ctest -L delegate +cmake -E env TESTS_ARGUMENTS=--use_xnnpack=true ctest -L delegate +cmake -E env TESTS_ARGUMENTS=--external_delegate_path= ctest -L delegate +``` + +**Uma limitação conhecida** desta forma de fornecer argumentos de execução relacionados a delegados para testes de unidade é que só há suporte para testes em que **o valor de retorno esperado é 0**. Valores de retorno diferentes serão indicados como falha do teste. + +#### Delegado de GPU do OpenCL + +Se a sua máquina escolhida tiver suporte ao OpenCL, você pode usar a [delegado de GPU](https://www.tensorflow.org/lite/performance/gpu), que podem usar o poder das suas GPUs. + +Para configurar o suporte a delegado de CPU do OpenCL: + +```sh +cmake ../tensorflow_src/tensorflow/lite -DTFLITE_ENABLE_GPU=ON +``` + +**Observação:** isso é experimental e está disponível a partir do TensorFlow 2.5. Pode haver problemas de compatibilidade. Isso só é verificado em dispositivos Android e NVidia CUDA OpenCL 1.2. + +### Etapa 5. Compile o TensorFlow Lite + +No diretório `tflite_build`: + +```sh +cmake --build . -j +``` + +**Observação:** é gerada uma biblioteca estática `libtensorflow-lite.a` no diretório atual, mas a biblioteca não é autocontida, já que todas as dependências transitivas não estão incluídas. Para usar a biblioteca corretamente, você precisa criar um projeto do CMake. Confira a seção [Crie um projeto do CMake que use o TensorFlow Lite](#create_a_cmake_project_which_uses_tensorflow_lite). + +### Etapa 6. Compile a ferramenta de benchmark do TensorFlow Lite e o exemplo de imagem de rótulos (opcional) + +No diretório `tflite_build`: + +```sh +cmake --build . -j -t benchmark_model +``` + +```sh +cmake --build . -j -t label_image +``` + +## Opções disponíveis para compilar o TensorFlow Lite + +Veja a lista de opções disponíveis. Você pode sobrescrever com `-D=[ON|OFF]`. Por exemplo, use `-DTFLITE_ENABLE_XNNPACK=OFF` para desativar o XNNPACK, que é ativado por padrão. + +Nome da opção | Recurso | Android | Linux | macOS | Windows +--- | --- | --- | --- | --- | --- +`TFLITE_ENABLE_RUY` | Ativa o RUY | ON | OFF | OFF | OFF +: : matriz : : : : : | | | | | +: : multiplicação : : : : : | | | | | +: : biblioteca : : : : : | | | | | +`TFLITE_ENABLE_NNAPI` | Ativa o NNAPI | ON | OFF | N.D. | N.D. +: : delegado : : : : : | | | | | +`TFLITE_ENABLE_GPU` | Ativa a GPU | OFF | OFF | N.D. | N.D. +: : delegado : : : : : | | | | | +`TFLITE_ENABLE_XNNPACK` | Ativa o XNNPACK | ON | ON | ON | ON +: : delegado : : : : : | | | | | +`TFLITE_ENABLE_MMAP` | Ativa o MMAP | ON | ON | ON | N.D. + +## Crie um projeto do CMake que use o TensorFlow Lite + +Aqui está o arquivo CMakeLists.txt do [exemplo mínimo do TF Lite](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/examples/minimal). + +Você precisa adicionar add_subdirectory() para o diretório do TensorFlow Lite e vincular `tensorflow-lite` com target_link_libraries(). + +``` +cmake_minimum_required(VERSION 3.16) +project(minimal C CXX) + +set(TENSORFLOW_SOURCE_DIR "" CACHE PATH + "Directory that contains the TensorFlow project" ) +if(NOT TENSORFLOW_SOURCE_DIR) + get_filename_component(TENSORFLOW_SOURCE_DIR + "${CMAKE_CURRENT_LIST_DIR}/../../../../" ABSOLUTE) +endif() + +add_subdirectory( + "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" + "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL) + +add_executable(minimal minimal.cc) +target_link_libraries(minimal tensorflow-lite) +``` + +## Compile a biblioteca C do TensorFlow Lite + +Se você quiser compilar a biblioteca compartilhada do TensorFlow Lite para a [API do C](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/README.md), primeiro siga a [etapa 1](#step-1-install-cmake-tool) até a [etapa 3](#step-3-create-cmake-build-directory). Em seguida, execute os comandos abaixo: + +```sh +cmake ../tensorflow_src/tensorflow/lite/c +cmake --build . -j +``` + +Esses comandos geram a seguinte biblioteca compartilhada no diretório atual. + +**Observaçao:** em sistemas Windows, você encontra `tensorflowlite_c.dll` no diretório `debug`. + +Plataforma | Nome da biblioteca +--- | --- +Linux | `libtensorflowlite_c.so` +macOS | `libtensorflowlite_c.dylib` +Windows | `tensorflowlite_c.dll` + +**Observação:** você precisa dos cabeçalhos públicos (`tensorflow/lite/c_api.h`, `tensorflow/lite/c_api_experimental.h`, `tensorflow/lite/c_api_types.h` e `tensorflow/lite/common.h`) e dos cabeçalhos privados que esses cabeçalhos públicos incluem (`tensorflow/lite/core/builtin_ops.h`, `tensorflow/lite/core/c/*.h` e `tensorflow/lite/core/async/c/*.h`) para usar a biblioteca compartilhada gerada. diff --git a/site/pt-br/lite/guide/build_cmake_arm.md b/site/pt-br/lite/guide/build_cmake_arm.md new file mode 100644 index 0000000000..800af065b6 --- /dev/null +++ b/site/pt-br/lite/guide/build_cmake_arm.md @@ -0,0 +1,153 @@ +# Compilação cruzada do TensorFlow com o CMake + +Esta página descreve como compilar a biblioteca do TensorFlow Lite para diversos dispositivos ARM. + +As instruções abaixo foram testadas em um PC (AMD64) com Ubuntu 16.04.3 de 64 bits, na imagem devel docker do TensorFlow [tensorflow/tensorflow:devel](https://hub.docker.com/r/tensorflow/tensorflow/tags/). + +**Observação:** esse recurso está disponível a partir a versão 2.4. + +### Pré-requisitos + +Você precisa instalar o CMake e baixar o código fonte do TensorFlow. Confira mais detalhes na página [Compile o TensorFlow Lite com o CMake](https://www.tensorflow.org/lite/guide/build_cmake). + +### Confira o ambiente desejado + +Os exemplos abaixo foram testados no Raspberry Pi OS, Ubuntu Server 20.04 LTS e Mendel Linux 4.0. Dependendo a versão do glibc desejada e dos recursos de CPU, talvez você precise usar uma versão diferente da toolchain e parâmetros de compilação diferentes. + +#### Verifique a versão do glibc + +```sh +ldd --version +``` + +
+ldd (Debian GLIBC 2.28-10) 2.28
+Copyright (C) 2018 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+Written by Roland McGrath and Ulrich Drepper.
+
+ +#### Verifique a compatibilidade do ABI + +Se você deseja compilar para ARM de 32 bits, existem duas ABIs, dependendo da disponibilidade de VFP: [armhf](https://wiki.debian.org/ArmHardFloatPort) e [armel](https://wiki.debian.org/ArmEabiPort). Este documento mostra um exemplo para armhf. Você precisa usar uma toolchain diferente para compilar para armel. + +#### Verifique a capacidade de CPU + +Para o ARMv7, você precisa saber a versão com suporte a VFP e a disponibilidade de NEON da plataforma desejada. + +```sh +cat /proc/cpuinfo +``` + +
+processor   : 0
+model name  : ARMv7 Processor rev 3 (v7l)
+BogoMIPS    : 108.00
+Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part    : 0xd08
+CPU revision    : 3
+
+ +## Compile para AArch64 (ARM64) + +Estas instruções mostram como compilar o binário AArch64 que é compatível com [Coral Mendel Linux 4.0](https://coral.ai/), Raspberry Pi (com o [Ubuntu Server 20.04.01 LTS de 64 bits](https://ubuntu.com/download/raspberry-pi) instalado). + +#### Baixe a toolchain + +Estes comandos instalam a toolchain `gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu` em ${HOME}/toolchains. + +```sh +curl -LO https://storage.googleapis.com/mirror.tensorflow.org/developer.arm.com/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz +mkdir -p ${HOME}/toolchains +tar xvf gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu.tar.xz -C ${HOME}/toolchains +``` + +**Observação:** os binários compilados com GCC 8.3 requerem o glibc 2.28 ou superior. Se a plataforma desejada tiver uma versão inferior do glibc, você precisa usar a toolchain GCC mais antiga. + +#### Execute o CMake + +```sh +ARMCC_PREFIX=${HOME}/toolchains/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu- +ARMCC_FLAGS="-funsafe-math-optimizations" +cmake -DCMAKE_C_COMPILER=${ARMCC_PREFIX}gcc \ + -DCMAKE_CXX_COMPILER=${ARMCC_PREFIX}g++ \ + -DCMAKE_C_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_CXX_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ + ../tensorflow/lite/ +``` + +**Observação:** você pode ativar o delegado de GPU com `-DTFLITE_ENABLE_GPU=ON` se o dispositivo desejado tiver suporte ao OpenCL 1.2 ou superior. + +## Compile para ARMv7 com NEON + +Estas instruções mostram como compilar o binário ARMv7 com VFPv4 e NEON que é compatível com o Raspberry Pi 3 e 4. + +#### Baixe a toolchain + +Estes comandos instalam a toolchain `gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf` em ${HOME}/toolchains. + +```sh +curl -LO https://storage.googleapis.com/mirror.tensorflow.org/developer.arm.com/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz +mkdir -p ${HOME}/toolchains +tar xvf gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz -C ${HOME}/toolchains +``` + +**Observação:** os binários compilados com GCC 8.3 requerem o glibc 2.28 ou superior. Se a plataforma desejada tiver uma versão inferior do glibc, você precisa usar a toolchain GCC mais antiga. + +#### Execute o CMake + +```sh +ARMCC_FLAGS="-march=armv7-a -mfpu=neon-vfpv4 -funsafe-math-optimizations -mfp16-format=ieee" +ARMCC_PREFIX=${HOME}/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf- +cmake -DCMAKE_C_COMPILER=${ARMCC_PREFIX}gcc \ + -DCMAKE_CXX_COMPILER=${ARMCC_PREFIX}g++ \ + -DCMAKE_C_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_CXX_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=armv7 \ + ../tensorflow/lite/ +``` + +**Observação:** como a arquitetura ARMv7 é muito diversa, talvez você precise atualizar `ARMCC_FLAGS` para os perfis de dispositivos desejados. Por exemplo, ao compilar com XNNPACK ativado (ou seja, `XNNPACK=ON`) no Tensorflow Lite 2.8, adicione `-mfp16-format=ieee` a `ARMCC_FLAGS`. + +## Compile para o Raspberry Pi Zero (ARMv6) + +Estas instruções mostram como compilar o binário ARMv6 que é compatível com o Raspberry Pi Zero. + +#### Baixe a toolchain + +Estes comandos instalam a toolchain `gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf` em ${HOME}/toolchains. + +```sh +curl -LO https://storage.googleapis.com/mirror.tensorflow.org/developer.arm.com/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz +mkdir -p ${HOME}/toolchains +tar xvf gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz -C ${HOME}/toolchains +``` + +**Observação:** os binários compilados com GCC 8.3 requerem o glibc 2.28 ou superior. Se a plataforma desejada tiver uma versão inferior do glibc, você precisa usar a toolchain GCC mais antiga. + +#### Execute o CMake + +```sh +ARMCC_FLAGS="-march=armv6 -mfpu=vfp -mfloat-abi=hard -funsafe-math-optimizations" +ARMCC_PREFIX=${HOME}/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf- +cmake -DCMAKE_C_COMPILER=${ARMCC_PREFIX}gcc \ + -DCMAKE_CXX_COMPILER=${ARMCC_PREFIX}g++ \ + -DCMAKE_C_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_CXX_FLAGS="${ARMCC_FLAGS}" \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=armv6 \ + -DTFLITE_ENABLE_XNNPACK=OFF \ + ../tensorflow/lite/ +``` + +**Observação:** o XNNPACK está desativado, já que não há suporte ao NEON. diff --git a/site/pt-br/lite/guide/build_cmake_pip.md b/site/pt-br/lite/guide/build_cmake_pip.md new file mode 100644 index 0000000000..2db7100612 --- /dev/null +++ b/site/pt-br/lite/guide/build_cmake_pip.md @@ -0,0 +1,73 @@ +# Compile o pacote Wheel do Python do TensorFlow Lite + +Esta página descreve como compilar a biblioteca do Python `tflite_runtime` do TensorFlow Lite para dispositivos x86_64 e diversos dispositivos ARM. + +As instruções abaixo foram testadas em um PC (AMD64) com Ubuntu 16.04.3 de 64 bits, macOS Catalina (x86_64) e imagem devel docker do TensorFlow [tensorflow/tensorflow:devel](https://hub.docker.com/r/tensorflow/tensorflow/tags/). + +**Observação:** esse recurso está disponível a partir a versão 2.4. + +#### Pré-requisitos + +Você precisa instalar o CMake e de uma cópia do código fonte do TensorFlow. Confira mais detalhes na página [Compile o TensorFlow Lite com o CMake](https://www.tensorflow.org/lite/guide/build_cmake). + +Para compilar o pacote PIP para sua estação de trabalho, você pode executar os seguintes comandos: + +```sh +PYTHON=python3 tensorflow/lite/tools/pip_package/build_pip_package_with_cmake.sh native +``` + +**Observação:** se você tiver vários interpretadores do Python disponíveis, especifique a versão do Python exata pela variável `PYTHON` (atualmente, há suporte ao Python 3.7 e superiores). + +## Compilação cruzada para ARM + +No caso de compilação cruzada para ARM, recomenda-se usar o Docker, pois facilita a configuração do ambiente de compilação cruzada. Além disso, você precisa de uma opção `target` para descobrir a arquitetura alvo. + +Existe uma ferramenta helper no Makefile `tensorflow/lite/tools/pip_package/Makefile` disponível para invocar um comando de compilação usando um container Docker predefinido. Em uma máquina host Docker, você pode executar um comando de compilação da seguinte forma: + +```sh +make -C tensorflow/lite/tools/pip_package docker-build \ + TENSORFLOW_TARGET= PYTHON_VERSION= +``` + +**Observação:** há suporte ao Python versão 3.7 e superiores. + +### Nomes de alvos disponíveis + +O script `tensorflow/lite/tools/pip_package/build_pip_package_with_cmake.sh` requer um nome de alvo para descobrir a arquitetura alvo. Veja a lista de alvos com suporte: + +Alvo | Arquitetura alvo | Comentários +--- | --- | --- +armhf | ARMv7 VFP com Neon | Compatível com Raspberry Pi 3 e 4 +rpi0 | ARMv6 | Compatível com Raspberry Pi Zero +aarch64 | aarch64 (ARM de 64 bits) | [Coral Mendel Linux 4.0](https://coral.ai/)
Raspberry Pi com [Ubuntu Server 20.04.01 LTS de 64 bits](https://ubuntu.com/download/raspberry-pi) +native | Sua estação de trabalho | Compila com a otimização "-mnative" + | Sua estação de trabalho | Alvo padrão + +### Exemplos de builds + +Veja alguns comandos que você pode usar. + +#### Alvo armhf para Python 3.7 + +```sh +make -C tensorflow/lite/tools/pip_package docker-build \ + TENSORFLOW_TARGET=armhf PYTHON_VERSION=3.7 +``` + +#### Alvo aarch64 para Python 3.8 + +```sh +make -C tensorflow/lite/tools/pip_package docker-build \ + TENSORFLOW_TARGET=aarch64 PYTHON_VERSION=3.8 +``` + +#### Como usar uma toolchain personalizada? + +Se os binários gerados não forem compatíveis com seu alvo, você precisa usar sua própria toolchain e fornecer sinalizadores de compilação personalizados (confira [aqui](https://www.tensorflow.org/lite/guide/build_cmake_arm#check_your_target_environment) para entender seu ambiente alvo). Nesse caso, você precisa modificar `tensorflow/lite/tools/cmake/download_toolchains.sh` para usar sua própria toolchain. O script da toolchain define as duas variáveis abaixo para o script `build_pip_package_with_cmake.sh`. + +Variável | Finalidade | Exemplo +--- | --- | --- +`ARMCC_PREFIX` | Define o prefixo da toolchain | arm-linux-gnueabihf- +`ARMCC_FLAGS` | Sinalizadores de compilação | -march=armv7-a -mfpu=neon-vfpv4 + +**Observação:** pode ser que `ARMCC_FLAGS` precise conter o caminho de inclusão da biblioteca do Python. Confira a referência em `download_toolchains.sh`. diff --git a/site/pt-br/lite/guide/build_ios.md b/site/pt-br/lite/guide/build_ios.md new file mode 100644 index 0000000000..4a9d91c9ef --- /dev/null +++ b/site/pt-br/lite/guide/build_ios.md @@ -0,0 +1,147 @@ +# Compile o TensorFlow Lite para iOS + +This document describes how to build TensorFlow Lite iOS library on your own. Normally, you do not need to locally build TensorFlow Lite iOS library. If you just want to use it, the easiest way is using the prebuilt stable or nightly releases of the TensorFlow Lite CocoaPods. See [iOS quickstart](ios.md) for more details on how to use them in your iOS projects.

Este documento descreve como compilar a biblioteca iOS do TensorFlow Lite por conta própria. Normalmente, você não precisa compilar localmente a biblioteca iOS do TensorFlow Lite. Se você só quiser usá-la, a forma mais fácil é utilizar as versões estáveis ou noturnas pré-compiladas do CocoaPods do TensorFlow Lite. Confira mais detalhes de como usá-las nos seus projetos para iOS no [Guia de início rápido para iOS](ios.md). + +## Compilando localmente + +Em alguns casos, talvez você queria usar uma build local do TensorFlow Lite, por exemplo, quando precisar fazer alterações locais no TensorFlow Lite e testá-las em seu aplicativo para iOS, ou quando preferir usar uma framework estática em vez da dinâmica que fornecemos. Para criar um framework iOS universal para o TensorFlow Lite localmente, você precisa compilá-lo usando o Bazel em um computador macOS. + +### Instale o Xcode + +Você precisa instalar o Xcode8 ou posteriores e as ferramentas usando `xcode-select`, caso ainda não o tenha feito: + +```sh +xcode-select --install +``` + +Se for uma nova instalação, você precisa aceitar o contrato de licença para todos os usuários com o seguinte comando: + +```sh +sudo xcodebuild -license accept +``` + +### Instale o Bazel + +O Bazel é o principal sistema de build para o TensorFlow. Instale o Brazel conforme as [instruções no site do Bazel](https://docs.bazel.build/versions/master/install-os-x.html). Você deve escolher uma versão entre `_TF_MIN_BAZEL_VERSION` e `_TF_MAX_BAZEL_VERSION` no arquivo [`configure.py`](https://github.com/tensorflow/tensorflow/blob/master/configure.py), na raiz do repositório `tensorflow`. + +### Configure WORKSPACE e .bazelrc + +Execute o script `./configure` no diretório de checkout raiz do TensorFlow e responda "Yes" (Sim) quando o script perguntar se você deseja compilar o TensorFlow com suporte ao iOS. + +### Compile o framework dinâmico TensorFlowLiteC (recomendado) + +Observação: esta etapa não é necessária se (1) você estiver usando o Bazel para seu aplicativo ou (2) você só quiser testar as alterações locais nas APIs do Swift ou do Objective-C. Nesses casos, prossiga para a seção [Use em seu próprio aplicativo](#use_in_your_own_application) abaixo. + +Quando o Bazel estiver configurado corretamente com suporte ao iOS, você pode compilar o framework `TensorFlowLiteC` com o seguinte comando: + +```sh +bazel build --config=ios_fat -c opt --cxxopt=--std=c++17 \ + //tensorflow/lite/ios:TensorFlowLiteC_framework +``` + +Esse comando vai gerar o arquivo `TensorFlowLiteC_framework.zip` no diretório `bazel-bin/tensorflow/lite/ios/` dentro do seu diretório raiz do TensorFlow. Por padrão, o framework gerado contém um binário "fat", contendo armv7, arm64 e x86_64 (mas sem i386). Para ver a lista completa de sinalizadores de compilação usados ao especificar `--config=ios_fat`, confira a seção de configurações do iOS no arquivo [`.bazelrc`](https://github.com/tensorflow/tensorflow/blob/master/.bazelrc). + +### Compile o framework estático TensorFlowLiteC + +Por padrão, distribuímos o framework dinâmico somente via CocoaPods. Se você deseja usar o framework estático, pode compilar o framework estático `TensorFlowLiteC` com o seguinte comando: + +``` +bazel build --config=ios_fat -c opt --cxxopt=--std=c++17 \ + //tensorflow/lite/ios:TensorFlowLiteC_static_framework +``` + +O comando vai gerar um arquivo chamado `TensorFlowLiteC_static_framework.zip` no diretório `bazel-bin/tensorflow/lite/ios/` dentro do seu diretório raiz do TensorFlow. Esse framework estático pode ser usado da mesma forma que o dinâmico. + +### Compile os frameworks do TF Lite seletivamente + +Você pode compilar frameworks menores ao escolher como alvo somente um conjunto de modelos usando a compilação seletiva, que vai ignorar operações não usadas em seu modelo e incluir somente os kernels de operações necessários para executar o conjunto específico de modelos. Veja o comando: + +```sh +bash tensorflow/lite/ios/build_frameworks.sh \ + --input_models=model1.tflite,model2.tflite \ + --target_archs=x86_64,armv7,arm64 +``` + +O comando acima vai gerar o framework estático `bazel-bin/tensorflow/lite/ios/tmp/TensorFlowLiteC_framework.zip` para as operações integradas e personalizadas do TensorFlow Lite. Opcionalmente, vai gerar o framework estático `bazel-bin/tensorflow/lite/ios/tmp/TensorFlowLiteSelectTfOps_framework.zip` se os seus modelos contiverem operações específicas do TensorFlow. O sinalizador `--target_archs` pode ser usado para especificar as arquiteturas de implantação. + +## Use em seu próprio aplicativo + +### Desenvolvedores que usam o CocoaPods + +Existem três CocoaPods para o TensorFlow Lite: + +- `TensorFlowLiteSwift`: fornece APIs do Swift para o TensorFlow Lite. +- `TensorFlowLiteObjC`: fornece APIs do Objective-C para o TensorFlow Lite. +- `TensorFlowLiteC`: pod base comum, que incorpora o runtime core do TensorFlow Lite e expressa as APIs C base usadas pelos dois pods acima. Não deve ser usado diretamente pelos usuários. + +Como desenvolvedor, você deve escolher o pod `TensorFlowLiteSwift` ou `TensorFlowLiteObjC` de acordo com a linguagem de programação do seu aplicativo, mas não ambos. As etapas exatas para usar builds locais do TensorFlow Lite diferem, dependendo de qual parte exata você deseja compilar. + +#### Usando as APIs do Swift ou do Objective-C locais + +Se você estiver usando o CocoaPods e quiser apenas testar algumas alterações locais nas [APIs do Swift](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/swift) ou nas [APIs do Objective-C](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/objc) do TensorFlow Lite, siga estas etapas: + +1. Faça alterações nas APIs do Swift ou do Objective-C APIs em seu checkout `tensorflow`. + +2. Abra o arquivo `TensorFlowLite(Swift|ObjC).podspec` e atualize esta linha:
`s.dependency 'TensorFlowLiteC', "#{s.version}"`
para:
`s.dependency 'TensorFlowLiteC', "~> 0.0.1-nightly"`
Isso é feito para garantir que você esteja compilando suas APIs do Swift e do Objective-C com a versão noturna mais recente disponível das APIs do `TensorFlowLiteC` (compilada todas as noites entre 1 a 4 horas da manhã, Horário do Pacífico) em vez da versão estável, que pode estar desatualizada em comparação ao seu checkout `tensorflow` local. Outra opção é publicar sua própria versão do `TensorFlowLiteC` e usá-la (confira a seção [Como usar o TensorFlow lite core local](#using_local_tensorflow_lite_core) abaixo). + +3. No `Podfile` do seu projeto para iOS, altere a dependência da seguinte forma para apontar para o caminho local do seu diretório raiz do `tensorflow`:
Para Swift:
`pod 'TensorFlowLiteSwift', :path => ''`
Para Objective-C:
`pod 'TensorFlowLiteObjC', :path => ''` + +4. Atualize sua instalação do pod em seu diretório raiz do projeto para iOS.
`$ pod update` + +5. Reabra o workspace gerado (`.xcworkspace`) e compile novamente o aplicativo no Xcode. + +#### Como usar o TensorFlow Lite core local + +Você pode configurar um repositório privado de especificações do CocoaPods e publicar seu framework `TensorFlowLiteC` personalizado nesse repositório privado. Você pode copiar este [arquivo podspec](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/ios/TensorFlowLiteC.podspec) e modificar alguns valores: + +```ruby + ... + s.version = + ... + # Note the `///`, two from the `file://` and one from the `/path`. + s.source = { :http => "file:///path/to/TensorFlowLiteC_framework.zip" } + ... + s.vendored_frameworks = 'TensorFlowLiteC.framework' + ... +``` + +Após criar seu próprio arquivo `TensorFlowLiteC.podspec`, você pode seguir as [instruções de como usar CocoaPods privados](https://guides.cocoapods.org/making/private-cocoapods.html) para usá-lo em seu próprio projeto. Além disso, pode modificar `TensorFlowLite(Swift|ObjC).podspec` para apontar para seu pod `TensorFlowLiteC` personalizado e usar o pod do Swift ou do Objective-C no seu projeto de aplicativo. + +### Desenvolvedores que usam o Bazel + +Se você estiver usando o Bazel como ferramenta principal de compilação, basta adicionar a dependência `TensorFlowLite` ao seu alvo no arquivo `BUILD`. + +Para Swift: + +```python +swift_library( + deps = [ + "//tensorflow/lite/swift:TensorFlowLite", + ], +) +``` + +Para Objective-C: + +```python +objc_library( + deps = [ + "//tensorflow/lite/objc:TensorFlowLite", + ], +) +``` + +Quando você compilar seu projeto de aplicativo, qualquer mudança feita na biblioteca do TensorFlow Lite será capturada e incorporada ao seu aplicativo. + +### Modifique as configurações de projeto do Xcode diretamente + +É altamente recomendável usar o CocoaPods ou o Bazel para adicionar a dependência do TensorFlow Lite ao seu projeto. Se ainda assim você desejar adicionar o framework `TensorFlowLiteC` manualmente, precisará adicionar o framework `TensorFlowLiteC` como um framework integrado ao seu projeto de aplicativo. Descompacte o arquivo `TensorFlowLiteC_framework.zip` gerado pela compilação acima para obter o diretório `TensorFlowLiteC.framework`. Esse diretório é o framework em si que o Xcode consegue entender. + +Após preparar o diretório `TensorFlowLiteC.framework`, primeiro você precisa adicioná-lo como um binário integrado ao alvo do seu aplicativo. A seção específica de configurações de projeto pode diferir, dependendo da versão do Xcode. + +- Xcode 11: acesse a aba "General" (Geral) do editor do projeto para o alvo do seu aplicativo e adicione `TensorFlowLiteC.framework` na seção "Frameworks, Libraries, and Embedded Content" (Frameworks, bibliotecas e conteúdo integrado). +- Xcode 10 e inferiores : acesse a aba "General" (Geral) do editor do projeto para o alvo do seu aplicativo e adicione `TensorFlowLiteC.framework` em "Embedded Binaries" (Binários integrados). O framework também deverá ser adicionado automaticamente na seção "Linked Frameworks and Libraries" (Frameworks e bibliotecas vinculados). + +Quando você adiciona o framework como binário integrado, o Xcode também atualiza a entrada "Framework Search Paths" (Caminhos de pesquisa do framework) na aba "Build Settings" (Configurações da build) para incluir o diretório pai do seu framework. Caso isso não ocorra automaticamente, você precisará adicionar o diretório pai do diretório `TensorFlowLiteC.framework` manualmente. + +Após fazer essas duas configurações, você deverá conseguir importar e chamar a API do C do TensorFlow Lite, definida pelos arquivos de cabeçalho no diretório `TensorFlowLiteC.framework/Headers`. diff --git a/site/pt-br/lite/guide/faq.md b/site/pt-br/lite/guide/faq.md new file mode 100644 index 0000000000..05e24f8f16 --- /dev/null +++ b/site/pt-br/lite/guide/faq.md @@ -0,0 +1,77 @@ +# Perguntas frequentes + +Se você não encontrar uma resposta para sua pergunta aqui, confira nossa documentação detalhada sobre o tópico ou crie um [issue no GitHub](https://github.com/tensorflow/tensorflow/issues). + +## Conversão de modelos + +#### Quais são os formatos disponíveis para conversão do TensorFlow para o TensorFlow Lite? + +Os formatos disponíveis estão indicados [aqui](../models/convert/index#python_api). + +#### Por que algumas operações não são implementadas no TensorFlow Lite? + +Para manter o TF Lite leve, somente alguns operadores do TF (indicados na [lista de permissões](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/guide/op_select_allowlist.md)) têm suporte no TF Lite. + +#### Por que meu modelo não está sendo convertido? + +Como o número de operações no TensorFlow Lite é menor do que no TensorFlow, não é possível converter alguns modelos. Alguns erros comuns são indicados [aqui](../models/convert/index#conversion-errors). + +Para problemas de conversão não relacionados a operações ausentes ou operações de fluxo de controle, confira os [issues do GitHub](https://github.com/tensorflow/tensorflow/issues?q=label%3Acomp%3Alite+) ou crie um [novo](https://github.com/tensorflow/tensorflow/issues). + +#### Como faço para testar se um modelo do TensorFlow Lite se comporta da mesma forma que o modelo original do TensorFlow? + +A melhor forma de fazer esse teste é comparando as saídas dos modelos do TensorFlow e do TensorFlow Lite dadas as mesmas entradas (dados de teste ou entradas aleatórias), conforme mostrado [aqui](inference#load-and-run-a-model-in-python). + +#### Como faço para determinar as entradas/saídas do buffer do protocolo GraphDef? + +A forma mais fácil de inspecionar um grafo de um arquivo `.pb` é usando o [Netron](https://github.com/lutzroeder/netron), um visualizador de código aberto para modelos de aprendizado de máquina. + +Se o Netron não conseguir abrir o grafo, você pode tentar usar a ferramenta [summarize_graph](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/graph_transforms/README.md#inspecting-graphs). + +Se a ferramenta summarize_graph gerar um erro, você pode visualizar o GraphDef no [TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard) e procurar as entradas e saídas no grafo. Para visualizar um arquivo `.pb`, use o script [`import_pb_to_tensorboard.py`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/tools/import_pb_to_tensorboard.py) da seguinte forma: + +```shell +python import_pb_to_tensorboard.py --model_dir --log_dir +``` + +#### Como faço para inspecionar um arquivo `.tflite`? + +O [Netron](https://github.com/lutzroeder/netron) é a forma mais fácil de visualizar um modelo do TensorFlow Lite. + +Se o Netron não conseguir abrir seu modelo do TensorFlow Lite, você pode tentar o script [visualize.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/visualize.py) em nosso repositório. + +Se você estiver usando o TF 2.5 ou superior: + +```shell +python -m tensorflow.lite.tools.visualize model.tflite visualized_model.html +``` + +Caso contrário, execute este script com o Bazel: + +- [Clone o repositório do TensorFlow](https://www.tensorflow.org/install/source) +- Execute o script `visualize.py` com o Bazel: + +```shell +bazel run //tensorflow/lite/tools:visualize model.tflite visualized_model.html +``` + +## Otimização + +#### Como faço para reduzir o tamanho do meu modelo convertido para TensorFlow Lite? + +É possível usar [quantização pós-treinamento](../performance/post_training_quantization) durante a conversão para o TensorFlow Lite a fim de reduzir o tamanho do modelo. A quantização pós-treinamento quantiza os pesos de ponto flutuante para 8 bits de precisão e desfaz a quantização durante o tempo de execução para fazer computações com pontos flutuantes. Porém, isso pode impactar a exatidão. + +Se treinar novamente o modelo for uma opção, considere fazer o [treinamento com reconhecimento de quantização](https://github.com/tensorflow/tensorflow/tree/r1.13/tensorflow/contrib/quantize). Porém, esse tipo de treinamento só está disponível para um subconjunto das arquiteturas de redes neurais convolucionais. + +Para compreender melhor os diferentes métodos de otimização, confira [Otimização de modelos](../performance/model_optimization). + +#### Como faço para otimizar o desempenho do TensorFlow Lite para minha tarefa de aprendizado de máquina? + +Confira o processo geral para otimizar o desempenho do TensorFlow Lite: + +- *Confirme se você tem o modelo certo para a tarefa.* Para classificação de imagens, confira o [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite&module-type=image-classification). +- *Ajuste o número de threads.* Diversos operadores do TensorFlow Lite têm suporte a kernels multithread. Você pode usar `SetNumThreads()` da [API do C++](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/core/interpreter_builder.h#L110) para fazer isso. Porém, aumentar o número de threads faz o desempenho variar, dependendo do ambiente. +- *Use aceleradores de hardware.* O TensorFlow Lite tem suporte à aceleração de modelos para hardwares específicos usando delegados. Confira nosso guia sobre [delegados](../performance/delegates) para ver mais informações sobre quais aceleradores têm suporte e como usá-los em seu modelo nos dispositivos. +- *(Avançado) Profiling de modelos.* A [ferramenta de benchmark](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark) do Tensorflow Lite tem um profiler integrado que mostra estatísticas por operador. Se você souber como otimizar o desempenho de um operador para sua plataforma específica, pode implementar um [operador personalizado](ops_custom). + +Confira mais detalhes sobre como otimizar o desempenho nas [Práticas recomendadas](../performance/best_practices). diff --git a/site/pt-br/lite/guide/inference.md b/site/pt-br/lite/guide/inference.md new file mode 100644 index 0000000000..ca6df4a634 --- /dev/null +++ b/site/pt-br/lite/guide/inference.md @@ -0,0 +1,517 @@ +# Inferência com o TensorFlow Lite + +O termo *inferência* refere-se ao processo de executar um modelo do TensdorFlow Lite em um dispositivo para fazer previsões com base nos dados de entrada. Para fazer a inferência de um modelo do TensorFlow Lite, você precisa executá-lo por meio de um *interpretador*. O interpretador do TensorFlow Lite é leve, rápido e usa uma ordenação estática de grafos e um alocador personalizado (menos dinâmico) de memória para garantir uma latência mínima de carga, inicialização e execução. + +Esta página descreve como acessar o interpretador do TensorFlow Lite e fazer inferência usando o C++, Java e Python, além de incluir links para outros recursos para cada [plataforma com suporte](#supported-platforms). + +[TOC] + +## Conceitos importantes + +Tipicamente, a inferência com o TensorFlow Lite segue estas etapas: + +1. **Carregamento do modelo** + + Você precisa adicionar o modelo `.tflite` à memória, que contém o grafo de execução do modelo. + +2. **Transformação dos dados** + + Geralmente, os dados de entrada brutos do modelo não coincidem com o formato de dados de entrada esperado por ele. Por exemplo: talvez você precise redimensionar uma imagem ou alterar o formato da imagem para que fique compatível com o modelo. + +3. **Execução da inferência** + + Esta etapa envolve o uso da API do TensorFlow Lite para executar o modelo, além de envolver algumas etapas como compilar o interpretador e alocar tensores, conforme descrito nas próximas seções. + +4. **Interpretação da saída** + + Ao receber os resultados de inferência do modelo, você precisa interpretar os tensores de uma forma que faça sentido e seja útil para sua aplicação. + + Por exemplo, talvez um modelo retorne somente uma lista de probabilidades. Cabe a você mapeá-las para categorias relevantes e apresentar os resultados ao usuário final. + +## Plataformas com suporte + +São fornecidas APIs de inferência do TensorFlow para a maioria das plataformas comuns de dispositivos móveis/embarcadas, como [Android](#android-platform), [iOS](#ios-platform) e [Linux](#linux-platform), em diversas linguagens de programação. + +Na maioria dos casos, o design da API reflete a preferência por desempenho em vez de facilidade de uso. O TensorFlow Lite foi criado para fazer uma inferência rápida em dispositivos pequenos, então não é surpresa nenhuma que as APIs tentem evitar cópias desnecessárias apenas por questões de conveniência. De maneira similar, a consistência com as APIs do TensorFlow não era um objetivo explícito, e deve-se esperar algumas variações entre as linguagens. + +Dentre todas as bibliotecas, a API do TensorFlow Lite permite carregar modelos, alimentar entradas e buscar saídas de inferência. + +### Plataforma Android + +No Android, a inferência com o TensorFlow Lite pode ser realizada usando APIs do Java ou C++. As APIs do Java são convenientes e podem ser usadas diretamente nas classes de Activity do Android. As APIs do C++ oferecem mais flexibilidade e velocidade, mas podem exigir a programação de encapsuladores JNI para mover dados entre as camadas do Java e do C++. + +Confira detalhes sobre o uso do [C++](#load-and-run-a-model-in-c) e do [Java](#load-and-run-a-model-in-java) abaixo ou confira um tutorial e exemplo de código no [Guia de início rápido para Android](../android). + +#### Gerador de código do encapsulador Android para o TensorFlow Lite + +Observação: o gerador de código do encapsulador para o TensorFlow Lite está em fase experimental (beta) e, no momento, só tem suporte ao Android. + +Para o modelo do TensorFlow Lite aprimorado com [metadados](../inference_with_metadata/overview), os desenvolvedores podem usar o gerador de código do encapsulador Android para o TensorFlow Lite para criar o código do encapsulador específico para a plataforma. O código do encapsulador remove a necessidade de interagir diretamente com o `ByteBuffer` no Android. Em vez disso, os desenvolvedores podem interagir com o modelo do TensorFlow Lite usando objetos tipados, como `Bitmap` e `Rect`. Confira mais informações em [Gerador de código do encapsulador Android para o TensorFlow Lite](../inference_with_metadata/codegen.md). + +### Plataforma iOS + +No iOS, o TensorFlow Lite está disponível com bibliotecas nativas do iOS no [Swift](https://www.tensorflow.org/code/tensorflow/lite/swift) e no [Objective-C](https://www.tensorflow.org/code/tensorflow/lite/objc). Além disso, você pode usar a [API do C](https://www.tensorflow.org/code/tensorflow/lite/c/c_api.h) diretamente em código do Objective-C. + +Confira detalhes sobre o uso do [Swift](#load-and-run-a-model-in-swift), do [Objective-C](#load-and-run-a-model-in-objective-c) e da [API do C](#using-c-api-in-objective-c-code) abaixo ou confira um tutorial e exemplo de código no [Guia rápido para iOS](ios.md). + +### Plataforma Linux + +Em plataformas Linux (incluindo [Raspberry Pi](build_arm)), você pode executar inferência usando as APIs do TensorFlow Lite disponíveis no [C++](#load-and-run-a-model-in-c) e no [Python](#load-and-run-a-model-in-python), conforme exibido nas seções abaixo. + +## Como executar um modelo + +Para executar um modelo do TensorFlow Lite, é preciso seguir algumas etapas: + +1. Carregue o modelo na memória. +2. Compile um `Interpreter` com base em um modelo existente. +3. Defina os valores dos tensores de entrada (opcionalmente, redimensione os tensores de entrada se os tamanhos predefinidos não forem desejáveis). +4. Invoque a inferência. +5. Leia os valores dos tensores de saída. + +As próximas seções descrevem como essas etapas podem ser feitas em cada linguagem. + +## Carregue e execute um modelo no Java + +*Plataforma: Android* + +A API do Java para executar inferência com o TensorFlow Lite foi criada principalmente para uso com o Android, então ela está disponível como uma dependência de biblioteca do Android: `org.tensorflow:tensorflow-lite`. + +No Java, você usará a classe `Interpreter` para carregar um modelo e fazer a inferência. Em diversos casos, essa poderá ser a única API que você precisará utilizar. + +Você pode inicializar um `Interpreter` usando um arquivo `.tflite`: + +```java +public Interpreter(@NotNull File modelFile); +``` + +Ou com um `MappedByteBuffer`: + +```java +public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer); +``` + +Nos dois casos, você precisa fornecer um modelo válido do TensorFlow Lite, ou então a API vai gerar a exceção `IllegalArgumentException`. Se você utilizar `MappedByteBuffer` para inicializar um `Interpreter`, ele precisará permanecer inalterado durante todo o ciclo de vida do `Interpreter`. + +A melhor forma de executar a inferência em um modelo é usando assinaturas, disponíveis para modelos convertidos a partir do Tensorflow 2.5. + +```Java +try (Interpreter interpreter = new Interpreter(file_of_tensorflowlite_model)) { + Map inputs = new HashMap<>(); + inputs.put("input_1", input1); + inputs.put("input_2", input2); + Map outputs = new HashMap<>(); + outputs.put("output_1", output1); + interpreter.runSignature(inputs, outputs, "mySignature"); +} +``` + +O método `runSignature` recebe três argumentos: + +- **Inputs** (entradas): faz o mapeamento de entradas do nome de entradas na assinatura para um objeto de entrada. + +- **Outputs** (saídas): faz o mapeamento de saídas do nome de saída na assinatura para os dados de saída. + +- **Signature Name** (nome da assinatura) [opcional]: nome da assinatura (pode ser deixado em branco se o modelo tiver uma única assinatura). + +Outra forma de executar a inferência quando o modelo não tiver assinaturas definidas: basta chamar `Interpreter.run()`. Por exemplo: + +```java +try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) { + interpreter.run(input, output); +} +``` + +O método `run()` recebe somente uma entrada e retorna somente uma saída. Portanto, se o seu modelo tiver diversas entradas ou diversas saídas, use: + +```java +interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs); +``` + +Neste caso, cada entrada em `inputs` corresponde a um tensor de entrada, e `map_of_indices_to_outputs` mapeia índices de tensores de saída para os dados de saída correspondentes. + +Nos dois casos, os índices dos tensores correspondem aos valores que você forneceu ao [TensorFlow Lite Converter](../models/convert/) (conversor do TF Lite) ao criar o modelo. É importante salientar que a ordem dos tensores em `input` precisa coincidir com a ordem fornecida para o conversor do TensorFlow Lite. + +A classe `Interpreter` também conta com funções convenientes para obter o índice de qualquer entrada ou saída do modelo usando um nome de operação: + +```java +public int getInputIndex(String opName); +public int getOutputIndex(String opName); +``` + +Se `opName` não for uma operação válida no modelo, é gerada a exceção `IllegalArgumentException`. + +Também é importante salientar que o `Interpreter` é proprietário de recursos. Para evitar vazamento de memória, os recursos precisam ser liberados após o uso da seguinte forma: + +```java +interpreter.close(); +``` + +Confira um exemplo de projeto com Java no [exemplo de classificação de imagens no Android](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/android). + +### Tipos de dados permitidos (no Java) + +Para usar o TensorFlow Lite, os tipos de dados dos tensores de entrada e saída precisam ser um dos tipos primitivos abaixo: + +- `float` +- `int` +- `long` +- `byte` + +Também há suporte aos tipos `String`, mas eles são codificados de forma diferente do que os tipos primitivos. Especificamente, o formato de um tensor String determina o número e a organização das strings no tensor, em que cada elemento é um string de tamanho variável. Nesse sentido, o tamanho (byte) do tensor não pode ser computado somente a partir do formato e do tipo e, consequentemente, as strings não podem ser fornecidas como um único argumento simples `ByteBuffer`. Confira alguns exemplos nesta [página](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/Interpreter). + +Se forem usados outros tipos de dados, incluindo tipos boxed, como `Integer` e `Float`, será gerada a exceção `IllegalArgumentException`. + +#### Entradas + +Cada entrada deve ser um array ou um array multidimensional dos tipos primitivos permitidos, ou um `ByteBuffer` bruto do tamanho adequado. Se a entrada for um array ou um array multidimensional, o tensor de entrada associado será redimensionado implicitamente para as dimensões do array no momento da inferência. Se a entrada for um ByteBuffer, o chamador deverá primeiro redimensionar manualmente o tensor de entrada associado (via `Interpreter.resizeInput()`) antes de executar a inferência. + +Ao usar `ByteBuffer`, é melhor usar buffers de byte diretos, pois assim o `Interpreter` poderá evitar cópias desnecessárias. Se o `ByteBuffer` for um buffer de byte direto, sua ordem deve ser `ByteOrder.nativeOrder()`. Após ser usado para inferência do modelo, ele deve permanecer inalterado até a conclusão da inferência. + +#### Saídas + +Cada saída deve ser um array ou um array multidimensional dos tipos primitivos permitidos, ou um ByteBuffer do tamanho adequado. Alguns modelos têm saídas dinâmicas, em que o formato dos tensores de saída pode variar, dependendo da entrada. Não há uma única forma direta de tratar esse problema com a API atual de inferência do Java, mas extensões futuras deverão permitir isso. + +## Carregue e execute um modelo no Swift + +*Plataforma: iOS* + +A [API do Swift](https://www.tensorflow.org/code/tensorflow/lite/swift) está disponível no pod `TensorFlowLiteSwift` do CocoaPods. + +Primeiro, você precisa importar o módulo `TensorFlowLite`. + +```swift +import TensorFlowLite +``` + +```swift +// Getting model path +guard + let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") +else { + // Error handling... +} + +do { + // Initialize an interpreter with the model. + let interpreter = try Interpreter(modelPath: modelPath) + + // Allocate memory for the model's input `Tensor`s. + try interpreter.allocateTensors() + + let inputData: Data // Should be initialized + + // input data preparation... + + // Copy the input data to the input `Tensor`. + try self.interpreter.copy(inputData, toInputAt: 0) + + // Run inference by invoking the `Interpreter`. + try self.interpreter.invoke() + + // Get the output `Tensor` + let outputTensor = try self.interpreter.output(at: 0) + + // Copy output to `Data` to process the inference results. + let outputSize = outputTensor.shape.dimensions.reduce(1, {x, y in x * y}) + let outputData = + UnsafeMutableBufferPointer.allocate(capacity: outputSize) + outputTensor.data.copyBytes(to: outputData) + + if (error != nil) { /* Error handling... */ } +} catch error { + // Error handling... +} +``` + +## Carregue e execute um modelo no Objective-C + +*Plataforma: iOS* + +A [API do Objective-C](https://www.tensorflow.org/code/tensorflow/lite/objc) está disponível no pod `TensorFlowLiteObjC` do CocoaPods. + +Primeiro, você precisa importar o módulo `TensorFlowLite`. + +```objc +@import TensorFlowLite; +``` + +```objc +NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" + ofType:@"tflite"]; +NSError *error; + +// Initialize an interpreter with the model. +TFLInterpreter *interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath + error:&error]; +if (error != nil) { /* Error handling... */ } + +// Allocate memory for the model's input `TFLTensor`s. +[interpreter allocateTensorsWithError:&error]; +if (error != nil) { /* Error handling... */ } + +NSMutableData *inputData; // Should be initialized +// input data preparation... + +// Get the input `TFLTensor` +TFLTensor *inputTensor = [interpreter inputTensorAtIndex:0 error:&error]; +if (error != nil) { /* Error handling... */ } + +// Copy the input data to the input `TFLTensor`. +[inputTensor copyData:inputData error:&error]; +if (error != nil) { /* Error handling... */ } + +// Run inference by invoking the `TFLInterpreter`. +[interpreter invokeWithError:&error]; +if (error != nil) { /* Error handling... */ } + +// Get the output `TFLTensor` +TFLTensor *outputTensor = [interpreter outputTensorAtIndex:0 error:&error]; +if (error != nil) { /* Error handling... */ } + +// Copy output to `NSData` to process the inference results. +NSData *outputData = [outputTensor dataWithError:&error]; +if (error != nil) { /* Error handling... */ } +``` + +### Como usar a API do C em código do Objective-C + +Atualmente, a API do Objective-C não tem suporte a delegados. Para usar delegados em código do Objective-C, você precisa chamar diretamente a [API do C](https://www.tensorflow.org/code/tensorflow/lite/c/c_api.h) subjacente. + +```c +#include "tensorflow/lite/c/c_api.h" +``` + +```c +TfLiteModel* model = TfLiteModelCreateFromFile([modelPath UTF8String]); +TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate(); + +// Create the interpreter. +TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options); + +// Allocate tensors and populate the input tensor data. +TfLiteInterpreterAllocateTensors(interpreter); +TfLiteTensor* input_tensor = + TfLiteInterpreterGetInputTensor(interpreter, 0); +TfLiteTensorCopyFromBuffer(input_tensor, input.data(), + input.size() * sizeof(float)); + +// Execute inference. +TfLiteInterpreterInvoke(interpreter); + +// Extract the output tensor data. +const TfLiteTensor* output_tensor = + TfLiteInterpreterGetOutputTensor(interpreter, 0); +TfLiteTensorCopyToBuffer(output_tensor, output.data(), + output.size() * sizeof(float)); + +// Dispose of the model and interpreter objects. +TfLiteInterpreterDelete(interpreter); +TfLiteInterpreterOptionsDelete(options); +TfLiteModelDelete(model); +``` + +## Carregue e execute um modelo no C++ + +*Plataformas: Android, iOS e Linux* + +Observação: a API do C++ no iOS está disponível somente ao usar o Bazel. + +No C++, o modelo é armazenado na classe [`FlatBufferModel`](https://www.tensorflow.org/lite/api_docs/cc/class/tflite/flat-buffer-model.html). Ele encapsula um modelo do TensorFlow Lite, e você pode compilá-lo de diferentes formas, dependendo de onde o modelo é armazenado: + +```c++ +class FlatBufferModel { +  // Build a model based on a file. Return a nullptr in case of failure. +  static std::unique_ptr BuildFromFile( +      const char* filename, +      ErrorReporter* error_reporter); + +  // Build a model based on a pre-loaded flatbuffer. The caller retains +  // ownership of the buffer and should keep it alive until the returned object +  // is destroyed. Return a nullptr in case of failure. +  static std::unique_ptr BuildFromBuffer( +      const char* buffer, +      size_t buffer_size, +      ErrorReporter* error_reporter); +}; +``` + +Observação: se o TensorFlow Lite detectar a presença da [NNAPI do Android](https://developer.android.com/ndk/guides/neuralnetworks), vai tentar automaticamente usar a memória compartilhada para armazenar o `FlatBufferModel`. + +Agora que você tem o modelo como um objeto `FlatBufferModel`, pode executá-lo com um [`Interpreter`](https://www.tensorflow.org/lite/api_docs/cc/class/tflite/interpreter.html). Um único `FlatBufferModel` pode ser usado simultaneamente por mais de um `Interpreter`. + +Atenção: o objeto `FlatBufferModel` precisa permanecer válido até todas as instâncias do `Interpreter` que o utilizem serem destruídas. + +As partes importantes da API do `Interpreter` são exibidas no trecho de código abaixo. Deve-se observar que: + +- Os tensores são representados por inteiros para evitar comparações entre strings (e qualquer dependência fixa nas bibliotecas de strings). +- Um interpretador não pode ser acessado em threads simultâneos. +- A alocação de memória para os tensores de entrada e saída precisa ser acionada chamando `AllocateTensors()` logo após o redimensionamento dos tensores. + +Veja o uso mais simples do TensorFlow Lite com C++: + +```c++ +// Load the model +std::unique_ptr model = + tflite::FlatBufferModel::BuildFromFile(filename); + +// Build the interpreter +tflite::ops::builtin::BuiltinOpResolver resolver; +std::unique_ptr interpreter; +tflite::InterpreterBuilder(*model, resolver)(&interpreter); + +// Resize input tensors, if desired. +interpreter->AllocateTensors(); + +float* input = interpreter->typed_input_tensor(0); +// Fill `input`. + +interpreter->Invoke(); + +float* output = interpreter->typed_output_tensor(0); +``` + +Confira mais códigos de exemplo em [`minimal.cc`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/examples/minimal/minimal.cc) e [`label_image.cc`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/examples/label_image/label_image.cc). + +## Carregue e execute um modelo no Python + +*Plataforma: Linux* + +A API do Python para executar inferência é fornecida no módulo `tf.lite`. Basicamente, você só precisa do [`tf.lite.Interpreter`](https://www.tensorflow.org/api_docs/python/tf/lite/Interpreter) para carregar um modelo e executar a inferência. + +O exemplo abaixo mostra como usar o interpretador do Python para carregar um arquivo `.tflite` e executar a inferência com dados de entrada aleatórios: + +Este exemplo é recomendado se você estiver convertendo um SavedModel com uma SignatureDef definida. Disponível a partir do TensorFlow 2.5. + +```python +class TestModel(tf.Module): + def __init__(self): + super(TestModel, self).__init__() + + @tf.function(input_signature=[tf.TensorSpec(shape=[1, 10], dtype=tf.float32)]) + def add(self, x): + ''' + Simple method that accepts single input 'x' and returns 'x' + 4. + ''' + # Name the output 'result' for convenience. + return {'result' : x + 4} + + +SAVED_MODEL_PATH = 'content/saved_models/test_variable' +TFLITE_FILE_PATH = 'content/test_variable.tflite' + +# Save the model +module = TestModel() +# You can omit the signatures argument and a default signature name will be +# created with name 'serving_default'. +tf.saved_model.save( + module, SAVED_MODEL_PATH, + signatures={'my_signature':module.add.get_concrete_function()}) + +# Convert the model using TFLiteConverter +converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_PATH) +tflite_model = converter.convert() +with open(TFLITE_FILE_PATH, 'wb') as f: + f.write(tflite_model) + +# Load the TFLite model in TFLite Interpreter +interpreter = tf.lite.Interpreter(TFLITE_FILE_PATH) +# There is only 1 signature defined in the model, +# so it will return it by default. +# If there are multiple signatures then we can pass the name. +my_signature = interpreter.get_signature_runner() + +# my_signature is callable with input as arguments. +output = my_signature(x=tf.constant([1.0], shape=(1,10), dtype=tf.float32)) +# 'output' is dictionary with all outputs from the inference. +# In this case we have single output 'result'. +print(output['result']) +``` + +Outro exemplo se o modelo não tiver SignatureDefs definidas. + +```python +import numpy as np +import tensorflow as tf + +# Load the TFLite model and allocate tensors. +interpreter = tf.lite.Interpreter(model_path="converted_model.tflite") +interpreter.allocate_tensors() + +# Get input and output tensors. +input_details = interpreter.get_input_details() +output_details = interpreter.get_output_details() + +# Test the model on random input data. +input_shape = input_details[0]['shape'] +input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32) +interpreter.set_tensor(input_details[0]['index'], input_data) + +interpreter.invoke() + +# The function `get_tensor()` returns a copy of the tensor data. +# Use `tensor()` in order to get a pointer to the tensor. +output_data = interpreter.get_tensor(output_details[0]['index']) +print(output_data) +``` + +Como alternativa para carregar o modelo como um arquivo `.tflite` pré-convertido, você pode combinar seu código com a [API do Python do conversor do TensorFlow Lite](https://www.tensorflow.org/lite/api_docs/python/tf/lite/TFLiteConverter) (`tf.lite.TFLiteConverter`), permitindo converter seu modelo do Keras para o formato do TensorFlow Lite e depois executar a inferência: + +```python +import numpy as np +import tensorflow as tf + +img = tf.keras.Input(shape=(64, 64, 3), name="img") +const = tf.constant([1., 2., 3.]) + tf.constant([1., 4., 4.]) +val = img + const +out = tf.identity(val, name="out") + +# Convert to TF Lite format +converter = tf.lite.TFLiteConverter.from_keras_model(tf.keras.models.Model(inputs=[img], outputs=[out])) +tflite_model = converter.convert() + +# Load the TFLite model and allocate tensors. +interpreter = tf.lite.Interpreter(model_content=tflite_model) +interpreter.allocate_tensors() + +# Continue to get tensors and so forth, as shown above... +``` + +Confira mais exemplos de código do Python em [`label_image.py`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/examples/python/label_image.py). + +Dica: execute `help(tf.lite.Interpreter)` no terminal do Python para ver a documentação detalhada sobre o interpretador. + +## Execute a inferência com um modelo de formato dinâmico + +Se você deseja executar um modelo com formato de entrada dinâmico, *redimensione o formato da entrada* antes de executar a inferência. Caso contrário, o formato `None` em modelos do Tensorflow será substituído pelo padrão `1` nos modelos do TF Lite. + +Os exemplos abaixo mostram como redimensionar o formato da entrada antes de executar a inferência em diferentes linguagens. Todos os exemplos pressupõem que o formato da entrada é definido como `[1/None, 10]` e precisa ser redimensionado para `[3, 10]`. + +Exemplo no C++: + +```c++ +// Resize input tensors before allocate tensors +interpreter->ResizeInputTensor(/*tensor_index=*/0, std::vector{3,10}); +interpreter->AllocateTensors(); +``` + +Exemplo no Python: + +```python +# Load the TFLite model in TFLite Interpreter +interpreter = tf.lite.Interpreter(model_path=TFLITE_FILE_PATH) + +# Resize input shape for dynamic shape model and allocate tensor +interpreter.resize_tensor_input(interpreter.get_input_details()[0]['index'], [3, 10]) +interpreter.allocate_tensors() + +# Get input and output tensors. +input_details = interpreter.get_input_details() +output_details = interpreter.get_output_details() +``` + + + + +## Operações permitidas + +O TensorFlow Lite tem suporte a um subconjunto das operações do TensorFlow, com algumas limitações. Veja a lista completa de operações e limitações na [página de operações do TF Lite](https://www.tensorflow.org/mlir/tfl_ops). diff --git a/site/pt-br/lite/guide/ios.md b/site/pt-br/lite/guide/ios.md new file mode 100644 index 0000000000..3a842f5106 --- /dev/null +++ b/site/pt-br/lite/guide/ios.md @@ -0,0 +1,126 @@ +# Guia de início rápido para iOS + +Para começar a usar o TensorFlow Lite no iOS, recomendamos ver o seguinte exemplo: + +Exemplo de classificação de imagens no iOS + +Confira a explicação do código fonte em [Classificação de imagens com o TensorFlow Lite no iOS](https://github.com/tensorflow/examples/blob/master/lite/examples/image_classification/ios/README.md). + +Esse aplicativo de exemplo usa [classificação de imagens](https://www.tensorflow.org/lite/examples/image_classification/overview) para classificar continuamente o que é exibido pela câmera frontal do dispositivo, mostrando as classificações mais prováveis. Esse aplicativo permite que o usuário escolha entre um modelo de ponto flutuante ou [quantizado](https://www.tensorflow.org/lite/performance/post_training_quantization) e permite também selecionar o número de threads usados para fazer a inferência. + +Observação: confira outros aplicativos para iOS que demonstram o uso do TensorFlow Lite em diversos casos de uso nos [Exemplos](https://www.tensorflow.org/lite/examples). + +## Adicione o TensorFlow Lite ao seu projeto Swift ou Objective-C + +O TensorFlow Lite conta com bibliotecas do iOS nativas para [Swift](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/swift) e [Objective-C](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/objc). Comece a escrever seu próprio código iOS usando o [exemplo de classificação de imagens com o Swift](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/ios) como ponto de partida. + +As seções abaixo demonstram como adicionar o Swift ou o Objective-C para TensorFlow Lite ao seu projeto: + +### Desenvolvedores que usam o CocoaPods + +No `Podfile`, adicione o pod do TensorFlow . Em seguida, execute `pod install`. + +#### Swift + +```ruby +use_frameworks! +pod 'TensorFlowLiteSwift' +``` + +#### Objective-C + +```ruby +pod 'TensorFlowLiteObjC' +``` + +#### Especificação de versões + +Há versões estáveis e versões noturnas disponíveis para pods `TensorFlowLiteSwift` e `TensorFlowLiteObjC`. Se você não especificar uma restrição de versão como nos exemplos acima, o CocoaPods buscará a versão estável mais recente por padrão. + +Além disso, você pode especificar uma restrição de versão. Por exemplo: se quiser usar a versão 2.10.0, pode escrever a dependência como: + +```ruby +pod 'TensorFlowLiteSwift', '~> 2.10.0' +``` + +Dessa forma, você vai garantir que a versão 2.x.y mais recente disponível do pod `TensorFlowLiteSwift` seja usada em seu aplicativo. Já se você quiser usar as versões noturnas, pode escrever: + +```ruby +pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly' +``` + +A partir da versão noturna 2.4.0, por padrão, [delegados de GPU](https://www.tensorflow.org/lite/performance/gpu) e [delegados de Core ML](https://www.tensorflow.org/lite/performance/coreml_delegate) são excluídos do pod para reduzir o tamanho do binário. É possível incluí-los especificando as subspecs: + +```ruby +pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['CoreML', 'Metal'] +``` + +Dessa forma, você poderá usar os recursos mais recentes adicionados ao TensorFlow Lite. Quando o arquivo `Podfile.lock` for criado ao executar o comando `pod install` pela primeira vez, a versão da biblioteca noturna será mantida na versão da data atual. Se você quiser atualizar a biblioteca noturna para uma versão mais nova, precisa executar o comando `pod update`. + +Confira mais informações sobre as diferentes maneiras de especificar restrições de versão em [Como especificar versões de pods](https://guides.cocoapods.org/using/the-podfile.html#specifying-pod-versions). + +### Desenvolvedores que usam o Bazel + +No arquivo`BUILD`, adicione a dependência `TensorFlowLite` ao seu alvo. + +#### Swift + +```python +swift_library( + deps = [ + "//tensorflow/lite/swift:TensorFlowLite", + ], +) +``` + +#### Objective-C + +```python +objc_library( + deps = [ + "//tensorflow/lite/objc:TensorFlowLite", + ], +) +``` + +#### API do C/C++ + +Ou então você pode usar a [API do C](https://www.tensorflow.org/code/tensorflow/lite/c/c_api.h) ou a [API do C++](https://tensorflow.org/lite/api_docs/cc) + +```python +# Using C API directly +objc_library( + deps = [ + "//tensorflow/lite/c:c_api", + ], +) + +# Using C++ API directly +objc_library( + deps = [ + "//tensorflow/lite:framework", + ], +) +``` + +### Importe a biblioteca + +Para arquivos Swift, importe o módulo TensorFlow Lite: + +```swift +import TensorFlowLite +``` + +Para arquivos Objective-C, importe o cabeçalho guarda-chuva: + +```objectivec +#import "TFLTensorFlowLite.h" +``` + +Ou importe o módulo se você definir `CLANG_ENABLE_MODULES = YES` em seu projeto do Xcode: + +```objectivec +@import TFLTensorFlowLite; +``` + +Observação: para desenvolvedores que usam o CocoaPods e desejam importar o módulo TensorFlow Lite para Objective-C, é preciso incluir `use_frameworks!` no `Podfile`. diff --git a/site/pt-br/lite/guide/model_analyzer.ipynb b/site/pt-br/lite/guide/model_analyzer.ipynb new file mode 100644 index 0000000000..dd48e5170b --- /dev/null +++ b/site/pt-br/lite/guide/model_analyzer.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "g_nWetWWd_ns" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "2pHVBk_seED1" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M7vSdG6sAIQn" + }, + "source": [ + "# Analisador de modelos do TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fwc5GKHBASdc" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9ee074e4" + }, + "source": [ + "A API TensorFlow Lite Model Analyzer (analisador de modelos do TF Lite) ajuda a analisar modelos no formato do TensorFlow Lite por meio da listagem da estrutura do modelo.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JKwW0VfDKMWS" + }, + "source": [ + "## API Model Analyzer\n", + "\n", + "A seguinte API está disponível para o TensorFlow Lite Model Analyzer.\n", + "\n", + "```\n", + "tf.lite.experimental.Analyzer.analyze(model_path=None,\n", + " model_content=None,\n", + " gpu_compatibility=False)\n", + "```\n", + "\n", + "Confira os detalhes da API em https://www.tensorflow.org/api_docs/python/tf/lite/experimental/Analyzer ou executando `help(tf.lite.experimental.Analyzer.analyze)` em um terminal Python.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qi8Vk4_065jN" + }, + "source": [ + "## Uso básico com um modelo simples do Keras\n", + "\n", + "O código abaixo mostra o uso básico do Model Analyzer, indicando o conteúdo do modelo do Keras convertido para o conteúdo de modelo do TF Lite, formatado como um objeto flatbuffer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_jkg6UNtdz8c" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "\n", + "model = tf.keras.models.Sequential([\n", + " tf.keras.layers.Flatten(input_shape=(128, 128)),\n", + " tf.keras.layers.Dense(256, activation='relu'),\n", + " tf.keras.layers.Dropout(0.2),\n", + " tf.keras.layers.Dense(10)\n", + "])\n", + "\n", + "fb_model = tf.lite.TFLiteConverter.from_keras_model(model).convert()\n", + "\n", + "tf.lite.experimental.Analyzer.analyze(model_content=fb_model)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pe_ZU5Zy7PeH" + }, + "source": [ + "## Uso básico com o modelo MobileNetV3Large do Keras\n", + "\n", + "Essa API funciona com modelos grandes, como o MobileNetV3Large. Como a saída é grande, talvez seja melhor explorá-la com seu editor de texto favorito." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QFywJ_g56VW5" + }, + "outputs": [ + + ], + "source": [ + "model = tf.keras.applications.MobileNetV3Large()\n", + "fb_model = tf.lite.TFLiteConverter.from_keras_model(model).convert()\n", + "\n", + "tf.lite.experimental.Analyzer.analyze(model_content=fb_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4BGqG2j9yqRf" + }, + "source": [ + "## Verifique a compatibilidade com delegado de GPU\n", + "\n", + "A API ModelAnalyzer conta com uma maneira de verificar a compatibilidade com [delegado de GPU](https://www.tensorflow.org/lite/performance/gpu) do modelo fornecido por meio da opção `gpu_compatibility=True`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sVGC1oX33RkV" + }, + "source": [ + "### Caso 1 – Quando o modelo é incompatível\n", + "\n", + "O código abaixo mostra uma maneira de usar a opção `gpu_compatibility=True` para uma tf.function simples que usa `tf.slice` com um tensor bidimensional e `tf.cosh`, que não são compatíveis com delegado de GPU.\n", + "\n", + "Será exibido o aviso `GPU COMPATIBILITY WARNING` para cada nó com problemas de compatibilidade." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9GEg5plIzD-3" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "\n", + "@tf.function(input_signature=[\n", + " tf.TensorSpec(shape=[4, 4], dtype=tf.float32)\n", + "])\n", + "def func(x):\n", + " return tf.cosh(x) + tf.slice(x, [1, 1], [1, 1])\n", + "\n", + "converter = tf.lite.TFLiteConverter.from_concrete_functions(\n", + " [func.get_concrete_function()], func)\n", + "converter.target_spec.supported_ops = [\n", + " tf.lite.OpsSet.TFLITE_BUILTINS,\n", + " tf.lite.OpsSet.SELECT_TF_OPS,\n", + "]\n", + "fb_model = converter.convert()\n", + "\n", + "tf.lite.experimental.Analyzer.analyze(model_content=fb_model, gpu_compatibility=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BFU7HYb_2a8M" + }, + "source": [ + "### Caso 2 – Quando o modelo é compatível\n", + "\n", + "Neste exemplo, o model fornecido é compatível com delegado de GPU.\n", + "\n", + "**Observação:** embora a ferramenta não encontre nenhum problema de compatibilidade, ela não garante que seu modelo funcione bem com delegado de GPU em todos os dispositivos. Pode haver incompatibilidade em tempo de execução, como ausência do recurso `CL_DEVICE_IMAGE_SUPPORT` no back-end OpenGL alvo.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "85RgG6tQ3ABT" + }, + "outputs": [ + + ], + "source": [ + "model = tf.keras.models.Sequential([\n", + " tf.keras.layers.Flatten(input_shape=(128, 128)),\n", + " tf.keras.layers.Dense(256, activation='relu'),\n", + " tf.keras.layers.Dropout(0.2),\n", + " tf.keras.layers.Dense(10)\n", + "])\n", + "\n", + "fb_model = tf.lite.TFLiteConverter.from_keras_model(model).convert()\n", + "\n", + "tf.lite.experimental.Analyzer.analyze(model_content=fb_model, gpu_compatibility=True)" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "model_analyzer.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/guide/op_select_allowlist.md b/site/pt-br/lite/guide/op_select_allowlist.md new file mode 100644 index 0000000000..5428086fd0 --- /dev/null +++ b/site/pt-br/lite/guide/op_select_allowlist.md @@ -0,0 +1,888 @@ +# Operadores específicos do TensorFlow com suporte + +Atenção: a lista de operadores é atualizada com frequência. + +## Operadores core do TensorFlow + +Confira abaixo a lista completa de operações core do TensorFlow com suporte pelo runtime do TensorFlow Lite com o recurso de operações específicas do TensorFlow. + +- `raw_ops.Abort` +- `raw_ops.Abs` +- `raw_ops.Add` +- `raw_ops.AddN` +- `raw_ops.AddV2` +- `raw_ops.AdjustContrast` +- `raw_ops.AdjustContrastv2` +- `raw_ops.AdjustHue` +- `raw_ops.AdjustSaturation` +- `raw_ops.All` +- `raw_ops.Angle` +- `raw_ops.Any` +- `raw_ops.ApplyAdadelta` +- `raw_ops.ApplyAdagrad` +- `raw_ops.ApplyAdagradDA` +- `raw_ops.ApplyAdagradV2` +- `raw_ops.ApplyAdam` +- `raw_ops.ApplyAdaMax` +- `raw_ops.ApplyAddSign` +- `raw_ops.ApplyCenteredRMSProp` +- `raw_ops.ApplyFtrl` +- `raw_ops.ApplyFtrlV2` +- `raw_ops.ApplyGradientDescent` +- `raw_ops.ApplyMomentum` +- `raw_ops.ApplyPowerSign` +- `raw_ops.ApplyProximalAdagrad` +- `raw_ops.ApplyProximalGradientDescent` +- `raw_ops.ApplyRMSProp` +- `raw_ops.ApproximateEqual` +- `raw_ops.ArgMax` +- `raw_ops.ArgMin` +- `raw_ops.AsString` +- `raw_ops.Assert` +- `raw_ops.Assign` +- `raw_ops.AssignAdd` +- `raw_ops.AssignAddVariableOp` +- `raw_ops.AssignSub` +- `raw_ops.AssignSubVariableOp` +- `raw_ops.AssignVariableOp` +- `raw_ops.Atan` +- `raw_ops.Atan2` +- `raw_ops.AudioSpectrogram` +- `raw_ops.AvgPool` +- `raw_ops.AvgPool3D` +- `raw_ops.AvgPool3DGrad` +- `raw_ops.AvgPoolGrad` +- `raw_ops.BatchCholesky` +- `raw_ops.BatchDatasetV2` +- `raw_ops.BatchMatMul` +- `raw_ops.BatchMatMulV2` +- `raw_ops.BatchMatrixBandPart` +- `raw_ops.BatchMatrixDiag` +- `raw_ops.BatchMatrixDiagPart` +- `raw_ops.BatchMatrixInverse` +- `raw_ops.BatchMatrixSetDiag` +- `raw_ops.BatchMatrixTriangularSolve` +- `raw_ops.BatchNormWithGlobalNormalization` +- `raw_ops.BatchNormWithGlobalNormalizationGrad` +- `raw_ops.BatchToSpace` +- `raw_ops.BatchToSpaceND` +- `raw_ops.BiasAdd` +- `raw_ops.BiasAddGrad` +- `raw_ops.BiasAddV1` +- `raw_ops.Bincount` +- `raw_ops.Bitcast` +- `raw_ops.BitwiseAnd` +- `raw_ops.BitwiseOr` +- `raw_ops.BitwiseXor` +- `raw_ops.BroadcastArgs` +- `raw_ops.BroadcastGradientArgs` +- `raw_ops.BroadcastTo` +- `raw_ops.Bucketize` +- `raw_ops.CTCBeamSearchDecoder` +- `raw_ops.CTCGreedyDecoder` +- `raw_ops.Case` +- `raw_ops.Cast` +- `raw_ops.Ceil` +- `raw_ops.CheckNumerics` +- `raw_ops.CheckNumericsV2` +- `raw_ops.Cholesky` +- `raw_ops.ClipByValue` +- `raw_ops.CombinedNonMaxSuppression` +- `raw_ops.Complex` +- `raw_ops.ComplexAbs` +- `raw_ops.Concat` +- `raw_ops.ConcatOffset` +- `raw_ops.ConcatV2` +- `raw_ops.Conj` +- `raw_ops.ConjugateTranspose` +- `raw_ops.Const` +- `raw_ops.ControlTrigger` +- `raw_ops.Conv2D` +- `raw_ops.Conv2DBackpropFilter` +- `raw_ops.Conv2DBackpropInput` +- `raw_ops.Conv3D` +- `raw_ops.Conv3DBackpropFilter` +- `raw_ops.Conv3DBackpropFilterV2` +- `raw_ops.Conv3DBackpropInput` +- `raw_ops.Conv3DBackpropInputV2` +- `raw_ops.Cos` +- `raw_ops.Cosh` +- `raw_ops.CropAndResize` +- `raw_ops.CropAndResizeGradBoxes` +- `raw_ops.CropAndResizeGradImage` +- `raw_ops.CTCBeamSearchDecoder` +- `raw_ops.CTCGreedyDecoder` +- `raw_ops.Cumprod` +- `raw_ops.Cumsum` +- `raw_ops.CumulativeLogsumexp` +- `raw_ops.DataFormatDimMap` +- `raw_ops.DataFormatVecPermute` +- `raw_ops.DebugGradientIdentity` +- `raw_ops.DebugGradientRefIdentity` +- `raw_ops.DecodeAndCropJpeg` +- `raw_ops.DecodeBase64` +- `raw_ops.DecodeBmp` +- `raw_ops.DecodeGif` +- `raw_ops.DecodeImage` +- `raw_ops.DecodeJpeg` +- `raw_ops.DecodePaddedRaw` +- `raw_ops.DecodePng` +- `raw_ops.DecodeRaw` +- `raw_ops.DecodeWav` +- `raw_ops.DeepCopy` +- `raw_ops.DeleteSessionTensor` +- `raw_ops.DenseBincount` +- `raw_ops.DenseToDenseSetOperation` +- `raw_ops.DenseToSparseSetOperation` +- `raw_ops.DepthToSpace` +- `raw_ops.DepthwiseConv2dNative` +- `raw_ops.DepthwiseConv2dNativeBackpropFilter` +- `raw_ops.DepthwiseConv2dNativeBackpropInput` +- `raw_ops.Dequantize` +- `raw_ops.DestroyResourceOp` +- `raw_ops.DestroyTemporaryVariable` +- `raw_ops.Diag` +- `raw_ops.DiagPart` +- `raw_ops.Dilation2D` +- `raw_ops.Dilation2DBackpropFilter` +- `raw_ops.Dilation2DBackpropInput` +- `raw_ops.Div` +- `raw_ops.DivNoNan` +- `raw_ops.DynamicPartition` +- `raw_ops.DynamicStitch` +- `raw_ops.Einsum` +- `raw_ops.Elu` +- `raw_ops.EluGrad` +- `raw_ops.Empty` +- `raw_ops.EmptyTensorList` +- `raw_ops.EmptyTensorMap` +- `raw_ops.EncodeBase64` +- `raw_ops.EncodeJpeg` +- `raw_ops.EncodeJpegVariableQuality` +- `raw_ops.EncodePng` +- `raw_ops.EncodeWav` +- `raw_ops.EnsureShape` +- `raw_ops.Enter` +- `raw_ops.Equal` +- `raw_ops.Erf` +- `raw_ops.Exit` +- `raw_ops.Exp` +- `raw_ops.ExpandDims` +- `raw_ops.ExtractImagePatches` +- `raw_ops.FakeQuantWithMinMaxArgs` +- `raw_ops.FakeQuantWithMinMaxArgsGradient` +- `raw_ops.FakeQuantWithMinMaxVars` +- `raw_ops.FakeQuantWithMinMaxVarsGradient` +- `raw_ops.FakeQuantWithMinMaxVarsPerChannel` +- `raw_ops.FakeQuantWithMinMaxVarsPerChannelGradient` +- `raw_ops.FakeQueue` +- `raw_ops.FFT` +- `raw_ops.FFT2D` +- `raw_ops.FFT3D` +- `raw_ops.FIFOQueue` +- `raw_ops.FIFOQueueV2` +- `raw_ops.Fill` +- `raw_ops.FilterDataset` +- `raw_ops.FinalizeDataset` +- `raw_ops.Fingerprint` +- `raw_ops.FlatMapDataset` +- `raw_ops.Floor` +- `raw_ops.FloorDiv` +- `raw_ops.FloorMod` +- `raw_ops.FusedBatchNorm` +- `raw_ops.FusedBatchNormGrad` +- `raw_ops.FusedBatchNormGradV2` +- `raw_ops.FusedBatchNormGradV3` +- `raw_ops.FusedBatchNormV2` +- `raw_ops.FusedBatchNormV3` +- `raw_ops.FusedPadConv2D` +- `raw_ops.FusedResizeAndPadConv2D` +- `raw_ops.Gather` +- `raw_ops.GatherNd` +- `raw_ops.GatherV2` +- `raw_ops.GetSessionHandle` +- `raw_ops.GetSessionHandleV2` +- `raw_ops.GetSessionTensor` +- `raw_ops.Greater` +- `raw_ops.GreaterEqual` +- `raw_ops.HSVToRGB` +- `raw_ops.HashTable` +- `raw_ops.HashTableV2` +- `raw_ops.HistogramSummary` +- `raw_ops.Identity` +- `raw_ops.IdentityN` +- `raw_ops.IFFT` +- `raw_ops.IFFT2D` +- `raw_ops.IFFT3D` +- `raw_ops.Imag` +- `raw_ops.ImageProjectiveTransformV2` +- `raw_ops.ImageProjectiveTransformV3` +- `raw_ops.ImmutableConst` +- `raw_ops.InplaceAdd` +- `raw_ops.InplaceSub` +- `raw_ops.InplaceUpdate` +- `raw_ops.InTopK` +- `raw_ops.InTopKV2` +- `raw_ops.InitializeTable` +- `raw_ops.InitializeTableFromDataset` +- `raw_ops.InitializeTableFromTextFile` +- `raw_ops.InitializeTableFromTextFileV2` +- `raw_ops.InitializeTableV2` +- `raw_ops.Inv` +- `raw_ops.Invert` +- `raw_ops.InvertPermutation` +- `raw_ops.InvGrad` +- `raw_ops.IRFFT` +- `raw_ops.IRFFT2D` +- `raw_ops.IRFFT3D` +- `raw_ops.IsFinite` +- `raw_ops.IsNan` +- `raw_ops.IsVariableInitialized` +- `raw_ops.LRN` +- `raw_ops.LeakyRelu` +- `raw_ops.LeakyReluGrad` +- `raw_ops.LeftShift` +- `raw_ops.Less` +- `raw_ops.LessEqual` +- `raw_ops.LinSpace` +- `raw_ops.ListDiff` +- `raw_ops.Log` +- `raw_ops.LogMatrixDeterminant` +- `raw_ops.LogSoftmax` +- `raw_ops.LogicalAnd` +- `raw_ops.LogicalNot` +- `raw_ops.LogicalOr` +- `raw_ops.LookupTableExport` +- `raw_ops.LookupTableExportV2` +- `raw_ops.LookupTableFind` +- `raw_ops.LookupTableFindV2` +- `raw_ops.LookupTableImport` +- `raw_ops.LookupTableImportV2` +- `raw_ops.LookupTableInsert` +- `raw_ops.LookupTableInsertV2` +- `raw_ops.LookupTableRemoveV2` +- `raw_ops.LookupTableSize` +- `raw_ops.LookupTableSizeV2` +- `raw_ops.LoopCond` +- `raw_ops.LRN` +- `raw_ops.MapDataset` +- `raw_ops.MatMul` +- `raw_ops.MatrixBandPart` +- `raw_ops.MatrixDiag` +- `raw_ops.MatrixDiagPart` +- `raw_ops.MatrixDiagPartV2` +- `raw_ops.MatrixDiagPartV3` +- `raw_ops.MatrixDiagV2` +- `raw_ops.MatrixDiagV3` +- `raw_ops.MatrixInverse` +- `raw_ops.MatrixSetDiag` +- `raw_ops.MatrixSetDiagV2` +- `raw_ops.MatrixSetDiagV3` +- `raw_ops.MatrixTriangularSolve` +- `raw_ops.Max` +- `raw_ops.Maximum` +- `raw_ops.MaxPool` +- `raw_ops.MaxPool3D` +- `raw_ops.MaxPool3DGrad` +- `raw_ops.MaxPool3DGradGrad` +- `raw_ops.MaxPoolGrad` +- `raw_ops.MaxPoolGradGrad` +- `raw_ops.MaxPoolGradGradV2` +- `raw_ops.MaxPoolGradV2` +- `raw_ops.MaxPoolGradWithArgmax` +- `raw_ops.MaxPoolV2` +- `raw_ops.MaxPoolWithArgmax` +- `raw_ops.Mean` +- `raw_ops.Merge` +- `raw_ops.MergeSummary` +- `raw_ops.MergeV2Checkpoints` +- `raw_ops.Mfcc` +- `raw_ops.Min` +- `raw_ops.Minimum` +- `raw_ops.MirrorPad` +- `raw_ops.MirrorPadGrad` +- `raw_ops.ModelDataset` +- `raw_ops.Mul` +- `raw_ops.MulNoNan` +- `raw_ops.Multinomial` +- `raw_ops.MutableDenseHashTable` +- `raw_ops.MutableDenseHashTableV2` +- `raw_ops.MutableHashTable` +- `raw_ops.MutableHashTableOfTensors` +- `raw_ops.MutableHashTableOfTensorsV2` +- `raw_ops.MutableHashTableV2` +- `raw_ops.Neg` +- `raw_ops.NextIteration` +- `raw_ops.NonMaxSuppression` +- `raw_ops.NonMaxSuppressionV2` +- `raw_ops.NonMaxSuppressionV3` +- `raw_ops.NonMaxSuppressionV4` +- `raw_ops.NonMaxSuppressionV5` +- `raw_ops.NonMaxSuppressionWithOverlaps` +- `raw_ops.NoOp` +- `raw_ops.NotEqual` +- `raw_ops.OneHot` +- `raw_ops.OnesLike` +- `raw_ops.OptimizeDatasetV2` +- `raw_ops.OptionalFromValue` +- `raw_ops.OptionalGetValue` +- `raw_ops.OptionalHasValue` +- `raw_ops.OptionalNone` +- `raw_ops.Pack` +- `raw_ops.Pad` +- `raw_ops.PadV2` +- `raw_ops.PaddingFIFOQueue` +- `raw_ops.PaddingFIFOQueueV2` +- `raw_ops.PadV2` +- `raw_ops.ParallelConcat` +- `raw_ops.ParallelDynamicStitch` +- `raw_ops.ParseExample` +- `raw_ops.ParseExampleV2` +- `raw_ops.ParseSequenceExample` +- `raw_ops.ParseSequenceExampleV2` +- `raw_ops.ParseSingleExample` +- `raw_ops.ParseSingleSequenceExample` +- `raw_ops.Placeholder` +- `raw_ops.PlaceholderV2` +- `raw_ops.PlaceholderWithDefault` +- `raw_ops.PopulationCount` +- `raw_ops.Pow` +- `raw_ops.PreventGradient` +- `raw_ops.Print` +- `raw_ops.PrintV2` +- `raw_ops.Prod` +- `raw_ops.Qr` +- `raw_ops.QuantizedAdd` +- `raw_ops.QuantizedAvgPool` +- `raw_ops.QuantizedBatchNormWithGlobalNormalization` +- `raw_ops.QuantizedBiasAdd` +- `raw_ops.QuantizedConcat` +- `raw_ops.QuantizedConv2D` +- `raw_ops.QuantizedInstanceNorm` +- `raw_ops.QuantizedMatMul` +- `raw_ops.QuantizedMaxPool` +- `raw_ops.QuantizedMul` +- `raw_ops.QuantizeDownAndShrinkRange` +- `raw_ops.QuantizedRelu` +- `raw_ops.QuantizedRelu6` +- `raw_ops.QuantizedReshape` +- `raw_ops.QuantizedResizeBilinear` +- `raw_ops.QuantizeV2` +- `raw_ops.QueueClose` +- `raw_ops.QueueCloseV2` +- `raw_ops.QueueDequeue` +- `raw_ops.QueueDequeueMany` +- `raw_ops.QueueDequeueManyV2` +- `raw_ops.QueueDequeueUpTo` +- `raw_ops.QueueDequeueUpToV2` +- `raw_ops.QueueDequeueV2` +- `raw_ops.QueueEnqueue` +- `raw_ops.QueueEnqueueMany` +- `raw_ops.QueueEnqueueManyV2` +- `raw_ops.QueueEnqueueV2` +- `raw_ops.QueueIsClosed` +- `raw_ops.QueueIsClosedV2` +- `raw_ops.QueueSize` +- `raw_ops.QueueSizeV2` +- `raw_ops.RFFT` +- `raw_ops.RFFT2D` +- `raw_ops.RFFT3D` +- `raw_ops.RGBToHSV` +- `raw_ops.RaggedBincount` +- `raw_ops.RaggedGather` +- `raw_ops.RaggedRange` +- `raw_ops.RaggedTensorFromVariant` +- `raw_ops.RaggedTensorToSparse` +- `raw_ops.RaggedTensorToTensor` +- `raw_ops.RaggedTensorToVariant` +- `raw_ops.RaggedTensorToVariantGradient` +- `raw_ops.RandomGamma` +- `raw_ops.RandomPoisson` +- `raw_ops.RandomPoissonV2` +- `raw_ops.RandomShuffle` +- `raw_ops.RandomStandardNormal` +- `raw_ops.RandomUniform` +- `raw_ops.RandomUniformInt` +- `raw_ops.Range` +- `raw_ops.Rank` +- `raw_ops.ReadFile` +- `raw_ops.ReadVariableOp` +- `raw_ops.Real` +- `raw_ops.RealDiv` +- `raw_ops.Reciprocal` +- `raw_ops.ReciprocalGrad` +- `raw_ops.Recv` +- `raw_ops.ReduceDataset` +- `raw_ops.ReduceJoin` +- `raw_ops.RefEnter` +- `raw_ops.RefExit` +- `raw_ops.RefIdentity` +- `raw_ops.RefMerge` +- `raw_ops.RefNextIteration` +- `raw_ops.RefSelect` +- `raw_ops.RefSwitch` +- `raw_ops.RegexFullMatch` +- `raw_ops.RegexReplace` +- `raw_ops.Relu` +- `raw_ops.Relu6` +- `raw_ops.Relu6Grad` +- `raw_ops.ReluGrad` +- `raw_ops.RemoteCall` +- `raw_ops.RepeatDataset` +- `raw_ops.RequantizationRange` +- `raw_ops.Requantize` +- `raw_ops.Reshape` +- `raw_ops.ResizeBicubic` +- `raw_ops.ResizeBicubicGrad` +- `raw_ops.ResizeBilinear` +- `raw_ops.ResizeBilinearGrad` +- `raw_ops.ResizeNearestNeighbor` +- `raw_ops.ResizeNearestNeighborGrad` +- `raw_ops.ResourceApplyAdadelta` +- `raw_ops.ResourceApplyAdagrad` +- `raw_ops.ResourceApplyAdagradDA` +- `raw_ops.ResourceApplyAdagradV2` +- `raw_ops.ResourceApplyAdam` +- `raw_ops.ResourceApplyAdaMax` +- `raw_ops.ResourceApplyAdamWithAmsgrad` +- `raw_ops.ResourceApplyAddSign` +- `raw_ops.ResourceApplyCenteredRMSProp` +- `raw_ops.ResourceApplyFtrl` +- `raw_ops.ResourceApplyFtrlV2` +- `raw_ops.ResourceApplyGradientDescent` +- `raw_ops.ResourceApplyKerasMomentum` +- `raw_ops.ResourceApplyMomentum` +- `raw_ops.ResourceApplyPowerSign` +- `raw_ops.ResourceApplyProximalAdagrad` +- `raw_ops.ResourceApplyProximalGradientDescent` +- `raw_ops.ResourceApplyRMSProp` +- `raw_ops.ResourceGather` +- `raw_ops.ResourceGatherNd` +- `raw_ops.ResourceScatterAdd` +- `raw_ops.ResourceScatterDiv` +- `raw_ops.ResourceScatterMax` +- `raw_ops.ResourceScatterMin` +- `raw_ops.ResourceScatterMul` +- `raw_ops.ResourceScatterNdAdd` +- `raw_ops.ResourceScatterNdMax` +- `raw_ops.ResourceScatterNdMin` +- `raw_ops.ResourceScatterNdSub` +- `raw_ops.ResourceScatterNdUpdate` +- `raw_ops.ResourceScatterSub` +- `raw_ops.ResourceScatterUpdate` +- `raw_ops.ResourceSparseApplyAdadelta` +- `raw_ops.ResourceSparseApplyAdagrad` +- `raw_ops.ResourceSparseApplyAdagradDA` +- `raw_ops.ResourceSparseApplyAdagradV2` +- `raw_ops.ResourceSparseApplyCenteredRMSProp` +- `raw_ops.ResourceSparseApplyFtrl` +- `raw_ops.ResourceSparseApplyFtrlV2` +- `raw_ops.ResourceSparseApplyKerasMomentum` +- `raw_ops.ResourceSparseApplyMomentum` +- `raw_ops.ResourceSparseApplyProximalAdagrad` +- `raw_ops.ResourceSparseApplyProximalGradientDescent` +- `raw_ops.ResourceSparseApplyRMSProp` +- `raw_ops.ResourceStridedSliceAssign` +- `raw_ops.Restore` +- `raw_ops.RestoreSlice` +- `raw_ops.RestoreV2` +- `raw_ops.Reverse` +- `raw_ops.ReverseSequence` +- `raw_ops.ReverseV2` +- `raw_ops.RightShift` +- `raw_ops.Roll` +- `raw_ops.Round` +- `raw_ops.Rsqrt` +- `raw_ops.RsqrtGrad` +- `raw_ops.SampleDistortedBoundingBox` +- `raw_ops.SampleDistortedBoundingBoxV2` +- `raw_ops.Save` +- `raw_ops.SaveSlices` +- `raw_ops.SaveV2` +- `raw_ops.ScalarSummary` +- `raw_ops.ScatterNd` +- `raw_ops.ScatterNdAdd` +- `raw_ops.ScatterNdMax` +- `raw_ops.ScatterNdMin` +- `raw_ops.ScatterNdNonAliasingAdd` +- `raw_ops.ScatterNdSub` +- `raw_ops.ScatterNdUpdate` +- `raw_ops.SegmentMax` +- `raw_ops.SegmentMean` +- `raw_ops.SegmentMin` +- `raw_ops.SegmentProd` +- `raw_ops.SegmentSum` +- `raw_ops.Select` +- `raw_ops.SelectV2` +- `raw_ops.Selu` +- `raw_ops.SeluGrad` +- `raw_ops.Send` +- `raw_ops.SerializeTensor` +- `raw_ops.Shape` +- `raw_ops.ShapeN` +- `raw_ops.ShardedFilename` +- `raw_ops.ShardedFilespec` +- `raw_ops.Sigmoid` +- `raw_ops.SigmoidGrad` +- `raw_ops.Sign` +- `raw_ops.Sin` +- `raw_ops.Sinh` +- `raw_ops.Size` +- `raw_ops.Slice` +- `raw_ops.Softmax` +- `raw_ops.SoftmaxCrossEntropyWithLogits` +- `raw_ops.Softplus` +- `raw_ops.SoftplusGrad` +- `raw_ops.Softsign` +- `raw_ops.SoftsignGrad` +- `raw_ops.SpaceToBatch` +- `raw_ops.SpaceToBatchND` +- `raw_ops.SpaceToDepth` +- `raw_ops.SparseAdd` +- `raw_ops.SparseApplyAdadelta` +- `raw_ops.SparseApplyAdagrad` +- `raw_ops.SparseApplyAdagradDA` +- `raw_ops.SparseApplyAdagradV2` +- `raw_ops.SparseApplyCenteredRMSProp` +- `raw_ops.SparseApplyFtrl` +- `raw_ops.SparseApplyFtrlV2` +- `raw_ops.SparseApplyMomentum` +- `raw_ops.SparseApplyProximalAdagrad` +- `raw_ops.SparseApplyProximalGradientDescent` +- `raw_ops.SparseApplyRMSProp` +- `raw_ops.SparseBincount` +- `raw_ops.SparseCross` +- `raw_ops.SparseCrossHashed` +- `raw_ops.SparseCrossV2` +- `raw_ops.SparseFillEmptyRows` +- `raw_ops.SparseFillEmptyRowsGrad` +- `raw_ops.SparseReduceSum` +- `raw_ops.SparseReshape` +- `raw_ops.SparseReorder` +- `raw_ops.SparseSegmentMean` +- `raw_ops.SparseSegmentMeanGrad` +- `raw_ops.SparseSegmentMeanWithNumSegments` +- `raw_ops.SparseSegmentSqrtN` +- `raw_ops.SparseSegmentSqrtNGrad` +- `raw_ops.SparseSegmentSqrtNWithNumSegments` +- `raw_ops.SparseSegmentSum` +- `raw_ops.SparseSegmentSumGrad` +- `raw_ops.SparseSegmentSumWithNumSegments` +- `raw_ops.SparseSlice` +- `raw_ops.SparseSoftmaxCrossEntropyWithLogits` +- `raw_ops.SparseTensorDenseMatMul` +- `raw_ops.SparseToDense` +- `raw_ops.SparseToSparseSetOperation` +- `raw_ops.Split` +- `raw_ops.SplitV` +- `raw_ops.Sqrt` +- `raw_ops.SqrtGrad` +- `raw_ops.Square` +- `raw_ops.SquaredDifference` +- `raw_ops.Squeeze` +- `raw_ops.Stack` +- `raw_ops.StackClose` +- `raw_ops.StackCloseV2` +- `raw_ops.StackPop` +- `raw_ops.StackPopV2` +- `raw_ops.StackPush` +- `raw_ops.StackPushV2` +- `raw_ops.StackV2` +- `raw_ops.StatelessMultinomial` +- `raw_ops.StatelessRandomGammaV2` +- `raw_ops.StatelessRandomGammaV3` +- `raw_ops.StatelessRandomGetAlg` +- `raw_ops.StatelessRandomGetKeyCounter` +- `raw_ops.StatelessRandomGetKeyCounterAlg` +- `raw_ops.StatelessRandomNormal` +- `raw_ops.StatelessRandomNormalV2` +- `raw_ops.StatelessRandomPoisson` +- `raw_ops.StatelessRandomUniform` +- `raw_ops.StatelessRandomUniformFullInt` +- `raw_ops.StatelessRandomUniformFullIntV2` +- `raw_ops.StatelessRandomUniformInt` +- `raw_ops.StatelessRandomUniformIntV2` +- `raw_ops.StatelessRandomUniformV2` +- `raw_ops.StatelessSampleDistortedBoundingBox` +- `raw_ops.StatelessTruncatedNormal` +- `raw_ops.StatelessTruncatedNormalV2` +- `raw_ops.StaticRegexFullMatch` +- `raw_ops.StaticRegexReplace` +- `raw_ops.StopGradient` +- `raw_ops.StridedSlice` +- `raw_ops.StridedSliceAssign` +- `raw_ops.StridedSliceGrad` +- `raw_ops.StringFormat` +- `raw_ops.StringJoin` +- `raw_ops.StringLength` +- `raw_ops.StringLower` +- `raw_ops.StringSplit` +- `raw_ops.StringSplitV2` +- `raw_ops.StringStrip` +- `raw_ops.StringToHashBucket` +- `raw_ops.StringToHashBucketFast` +- `raw_ops.StringToHashBucketStrong` +- `raw_ops.StringToNumber` +- `raw_ops.Sub` +- `raw_ops.Substr` +- `raw_ops.Sum` +- `raw_ops.Switch` +- `raw_ops.SymbolicGradient` +- `raw_ops.TakeDataset` +- `raw_ops.TakeWhileDataset` +- `raw_ops.Tan` +- `raw_ops.Tanh` +- `raw_ops.TanhGrad` +- `raw_ops.TemporaryVariable` +- `raw_ops.TensorArray` +- `raw_ops.TensorArrayClose` +- `raw_ops.TensorArrayCloseV2` +- `raw_ops.TensorArrayCloseV3` +- `raw_ops.TensorArrayConcat` +- `raw_ops.TensorArrayConcatV2` +- `raw_ops.TensorArrayConcatV3` +- `raw_ops.TensorArrayGather` +- `raw_ops.TensorArrayGatherV2` +- `raw_ops.TensorArrayGatherV3` +- `raw_ops.TensorArrayGrad` +- `raw_ops.TensorArrayGradV2` +- `raw_ops.TensorArrayGradV3` +- `raw_ops.TensorArrayGradWithShape` +- `raw_ops.TensorArrayPack` +- `raw_ops.TensorArrayRead` +- `raw_ops.TensorArrayReadV2` +- `raw_ops.TensorArrayReadV3` +- `raw_ops.TensorArrayScatter` +- `raw_ops.TensorArrayScatterV2` +- `raw_ops.TensorArrayScatterV3` +- `raw_ops.TensorArraySize` +- `raw_ops.TensorArraySizeV2` +- `raw_ops.TensorArraySizeV3` +- `raw_ops.TensorArraySplit` +- `raw_ops.TensorArraySplitV2` +- `raw_ops.TensorArraySplitV3` +- `raw_ops.TensorArrayUnpack` +- `raw_ops.TensorArrayV2` +- `raw_ops.TensorArrayV3` +- `raw_ops.TensorArrayWrite` +- `raw_ops.TensorArrayWriteV2` +- `raw_ops.TensorArrayWriteV3` +- `raw_ops.TensorListConcat` +- `raw_ops.TensorListConcatLists` +- `raw_ops.TensorListConcatV2` +- `raw_ops.TensorListElementShape` +- `raw_ops.TensorListFromTensor` +- `raw_ops.TensorListGather` +- `raw_ops.TensorListGetItem` +- `raw_ops.TensorListLength` +- `raw_ops.TensorListPopBack` +- `raw_ops.TensorListPushBack` +- `raw_ops.TensorListPushBackBatch` +- `raw_ops.TensorListReserve` +- `raw_ops.TensorListResize` +- `raw_ops.TensorListScatter` +- `raw_ops.TensorListScatterIntoExistingList` +- `raw_ops.TensorListScatterV2` +- `raw_ops.TensorListSetItem` +- `raw_ops.TensorListSplit` +- `raw_ops.TensorListStack` +- `raw_ops.TensorMapErase` +- `raw_ops.TensorMapHasKey` +- `raw_ops.TensorMapInsert` +- `raw_ops.TensorMapLookup` +- `raw_ops.TensorMapSize` +- `raw_ops.TensorMapStackKeys` +- `raw_ops.TensorScatterAdd` +- `raw_ops.TensorScatterMax` +- `raw_ops.TensorScatterMin` +- `raw_ops.TensorScatterSub` +- `raw_ops.TensorScatterUpdate` +- `raw_ops.TensorSliceDataset` +- `raw_ops.TensorStridedSliceUpdate` +- `raw_ops.Tile` +- `raw_ops.TileGrad` +- `raw_ops.Timestamp` +- `raw_ops.TokenizerFromLogits` +- `raw_ops.TopK` +- `raw_ops.TopKV2` +- `raw_ops.Transpose` +- `raw_ops.TruncateDiv` +- `raw_ops.TruncatedNormal` +- `raw_ops.UnicodeDecode` +- `raw_ops.UnicodeDecodeWithOffsets` +- `raw_ops.UnicodeEncode` +- `raw_ops.UnicodeTranscode` +- `raw_ops.Unique` +- `raw_ops.UniqueV2` +- `raw_ops.UniqueWithCounts` +- `raw_ops.UniqueWithCountsV2` +- `raw_ops.Unpack` +- `raw_ops.UnsortedSegmentJoin` +- `raw_ops.UnsortedSegmentMax` +- `raw_ops.UnsortedSegmentMin` +- `raw_ops.UnsortedSegmentProd` +- `raw_ops.UnsortedSegmentSum` +- `raw_ops.UnwrapDatasetVariant` +- `raw_ops.UpperBound` +- `raw_ops.VarHandleOp` +- `raw_ops.Variable` +- `raw_ops.VariableShape` +- `raw_ops.VariableV2` +- `raw_ops.VarIsInitializedOp` +- `raw_ops.Where` +- `raw_ops.WrapDatasetVariant` +- `raw_ops.WriteFile` +- `raw_ops.Xdivy` +- `raw_ops.Xlog1py` +- `raw_ops.Xlogy` +- `raw_ops.ZerosLike` + +## Operadores TensorFlow Text e SentencePiece + +Os seguintes operadores [TensorFlow Text](https://www.tensorflow.org/tutorials/tensorflow_text/intro) e [SentencePiece](https://github.com/google/sentencepiece) têm suporte se você usar a API do Python para converter e importar essas bibliotecas. + +Operadores TF.Text: + +- `CaseFoldUTF8` +- `ConstrainedSequence` +- `MaxSpanningTree` +- `NormalizeUTF8` +- `NormalizeUTF8WithOffsetsMap` +- `RegexSplitWithOffsets` +- `RougeL` +- `SentenceFragments` +- `SentencepieceOp` +- `SentencepieceTokenizeOp` +- `SentencepieceTokenizeWithOffsetsOp` +- `SentencepieceDetokenizeOp` +- `SentencepieceVocabSizeOp` +- `SplitMergeTokenizeWithOffsets` +- `UnicodeScriptTokenizeWithOffsets` +- `WhitespaceTokenizeWithOffsets` +- `WordpieceTokenizeWithOffsets` + +Operadores SentencePiece: + +- `SentencepieceGetPieceSize` +- `SentencepiecePieceToId` +- `SentencepieceIdToPiece` +- `SentencepieceEncodeDense` +- `SentencepieceEncodeSparse` +- `SentencepieceDecode` + +O trecho de código abaixo mostra como converter modelos com os operadores acima: + +```python +import tensorflow as tf +# These imports are required to load operators' definition. +import tensorflow_text as tf_text +import sentencepiece as spm + +converter = tf.lite.TFLiteConverter.from_keras_model(your_model) +converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS +] +model_data = converter.convert() +``` + +No runtime, também é preciso vincular a biblioteca TensorFlow Text ou SentencePiece ao aplicativo ou binário final. + +## Operadores definidos pelo usuário + +*Observação: esse recurso está disponível somente a partir do TensorFlow 2.5.* + +Se você [tiver criado seus próprios operadores do TensorFlow](https://www.tensorflow.org/guide/create_op), também pode converter modelos que contenham esses operadores para o TensorFlow Lite indicando os operadores necessários em `experimental_select_user_tf_ops` da seguinte forma: + +```python +import tensorflow as tf + +ops_module = tf.load_op_library('./your_ops_library.so') + +converter = tf.lite.TFLiteConverter.from_saved_model(your_model) +converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS +] +converter.target_spec.experimental_select_user_tf_ops = [ + 'your_op_name1', + 'your_op_name2' +] +model_data = converter.convert() +``` + +No runtime, também é preciso vincular sua biblioteca de operadores ao aplicativo ou binário final. + +## Adicione operadores core do TensorFlow à lista de permissões + +Se você se deparar com um caso em que os operadores core do TensorFlow não estão na [lista](https://www.tensorflow.org/lite/guide/op_select_allowlist#tensorflow_core_operators) de permissões acima, pode comunicar a solicitação de recurso [aqui](https://github.com/tensorflow/tensorflow/issues), indicando os nomes dos operadores core do TensorFlow não incluídos na lista de permissão. + +Além disso, você pode escrever seu próprio pull request no código fonte. Por exemplo: se você quiser adicionar a operação `raw_ops.StringToNumber` à lista de permissões, pode atualizar em três lugares, como este [commit](https://github.com/tensorflow/tensorflow/commit/02e691329517eb5e76522ed8d8bef79ceb082ff8). + +(1) Adicione o código fonte do kernel do operador à regra BUILD de `portable_extended_ops_group2`. + +``` +filegroup( + name = "portable_extended_ops_group2", + srcs = [ + ... ++ "string_to_number_op.cc", + + ... + ], +) +``` + +Para encontrar o arquivo fonte do kernel do operador relevante no diretório `tensorflow/core/kernels`, você pode pesquisar o local do código fonte, que contém a seguinte declaração de kernel com o nome do operador: + +``` +REGISTER_KERNEL_BUILDER(Name("StringToNumber") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("out_type"), \ + StringToNumberOp) +``` + +Se houver algum arquivo de cabeçalho no diretório `tensorflow/core/kernels` exigido no código fonte do kernel do operador, você precisa adicioná-lo à regra BUILD de `portable_extended_ops_headers` da seguinte forma: + +``` +filegroup( + name = "portable_extended_ops_headers", + srcs = [ + ... ++ "string_util.h", + + ... + ], +) +``` + +(2) Adicione o nome do operador à lista de permissões. + +A lista de permissões é definida em `tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc`. O nome do operador core do TensorFlow precisa ser indicado para que seja permitido pela opção de operações específicas do TF. + +``` +static const std::set* allowlisted_flex_ops = + new std::set({ + ... ++ "StringToNumber", + + ... + }); +``` + +Como a lista acima está em ordem alfabética, coloque o nome no lugar certo. + +(3) Adicione o nome do operador à página deste guia. + +Para mostrar a inclusão do operador para outros desenvolvedores, a página deste guia também deve ser atualizada. Esta página fica localizada em `tensorflow/lite/g3doc/guide/op_select_allowlist.md`. + +``` +## TensorFlow core operators + +The following is an exhaustive list of TensorFlow core operations that are +supported by TensorFlow Lite runtime with the Select TensorFlow Ops feature. + +... ++* `raw_ops.StringToNumber` +... +``` + +Como a lista acima está em ordem alfabética, coloque o nome no lugar certo. diff --git a/site/pt-br/lite/guide/ops_compatibility.md b/site/pt-br/lite/guide/ops_compatibility.md new file mode 100644 index 0000000000..d740c864a0 --- /dev/null +++ b/site/pt-br/lite/guide/ops_compatibility.md @@ -0,0 +1,82 @@ +# Compatibilidade de operadores do TensorFlow Lite e TensorFlow + +Os operadores de aprendizado de máquina (ML) que você usa em seu modelo podem impactar o processo de conversão de um modelo do TensorFlow para o formato do TensorFlow Lite. O conversor do TF Lite tem suporte a um número limitado de operações do TensorFlow usadas em modelos comuns de inferência, ou seja, nem todo modelo pode ser convertido diretamente. A ferramenta de conversão permite incluir operadores adicionais, mas, para converter um modelo dessa forma, é preciso modificar o ambiente de runtime do TensorFlow Lite que você usa para executar seu modelo, o que pode limitar a capacidade de usar as opções padrão de implantação do runtime, como os [serviços do Google Play](../android/play_services). + +O conversor do TensorFlow Lite foi criado para analisar a estrutura do modelo e aplicar otimizações a fim de torná-lo compatível com os operações com suporte nativo. Por exemplo: dependendo dos operadores de ML em seu modelo, o conversor poderá [eliminar ou fundir](../models/convert/operation_fusion) esses operadores para mapeá-los para suas contrapartes no TensorFlow Lite. + +Mesmo para as operações com suporte, às vezes são esperados padrões de uso específicos por questões de desempenho. A melhor forma de entender como criar um modelo do TensorFlow que possa ser usado no TensorFlow Lite é considerar cuidadosamente como as operações serão convertidas e otimizadas, além das limitações decorrentes desse processo. + +## Operadores com suporte + +Os operadores integrados do TensorFlow Lite são um subconjunto dos operadores que fazem parte da biblioteca principal do TensorFlow. Seu modelo do TensorFlow também pode incluir operadores personalizados, como operadores compostos ou novos operadores definidos por você. O diagrama abaixo mostra as relações entre esses operadores. + +![TensorFlow operators](../images/convert/tf_operators_relationships.png) + +De todos esses operadores de modelos de ML, existem 3 tipos de modelos com suporte a esse processo de conversão: + +1. Modelos com apenas operadores integrados do TensorFlow Lite (**recomendado**). +2. Modelos com operadores integrados e operadores core específicos do TensorFlow. +3. Modelos com os operadores integrados, operadores core do TensorFlow e/ou operadores personalizados. + +Se o seu modelo tiver apenas operações com suporte nativo do TensorFlow Lite, você não precisa de nenhum sinalizador adicional para convertê-lo. Essa é a forma recomendada, pois esse tipo de modelo terá uma conversão tranquila e é mais simples de otimizar e executar utilizando o runtime padrão do TensorFlow Lite. Além disso, você tem mais opções de implantação do modelo, como os [serviços do Google Play](../android/play_services). Comece conferindo o [guia do conversor do TensorFlow Lite](../models/convert/convert_models). Veja a lista de operadores integrados na [página de operações do TensorFlow Lite](https://www.tensorflow.org/mlir/tfl_ops). + +Se você precisar incluir operações específicas do TensorFlow da biblioteca core, precisa especificar na conversão e garantir que o runtime inclua essas operações. Confira mais detalhes no tópico [operadores específicos do TensorFlow](ops_select.md). + +Sempre que possível, evite a última opção, a de incluir operadores personalizados em seu modelo convertido. Os [operadores personalizados](https://www.tensorflow.org/guide/create_op) são operadores criados pela combinação de diversos operadores primitivos core do TensorFlow ou pela definição de um operador totalmente novo. Quando operadores personalizados são convertidos, podem aumentar o tamanho do modelo de forma geral devido à inclusão de dependências fora da biblioteca integrada do TensorFlow Lite. Se as operações personalizadas não forem criadas para implantação em dispositivos móveis ou outros dispositivos, o desempenho pode piorar ao implantar em dispositivos com restrição de recursos em comparação a um ambiente de servidor. Por fim, assim como ao incluir os operadores específicos core do TensorFlow, é preciso [modificar o ambiente de runtime](ops_custom#create_and_register_the_operator) ao incluir os operadores personalizados, o que limita o uso de serviços padrão do runtime, como os [serviços do Google Play](../android/play_services). + +## Tipos permitidos + +A maioria das operações do TensorFlow Lite tem como objetivo inferência em ponto flutuante (`float32`) e também quantizada (`uint8` e `int8`), mas diversas outras operações ainda não contam com esse objetivo para outros tipos, como `tf.float16` e strings. + +Além do uso de uma versão diferente das operações, as outras diferenças entre os modelos de ponto flutuante e quantizados é a forma como são convertidos. A conversão quantizada requer informações de intervalo dinâmico para os tensores, o que exige uma "quantização falsa" durante o treinamento do modelo, obtendo as informações de intervalo por um dataset de calibração ou fazendo a estimativa do intervalo em tempo real. Confira mais detalhes em [quantização](../performance/model_optimization.md). + +## Conversões diretas, constant-folding e fusão + +Diversas operações do TensorFlow podem ser processadas pelo TensorFlow Lite, mesmo que não tenham um equivalente direto. Esse é o caso de operações que podem ser simplesmente removidas do grafo (`tf.identity`), substituídas por tensores (`tf.placeholder`) ou fundidas em operações mais complexas (`tf.nn.bias_add`). Porém, algumas operações com suporte podem ser removidas por um desses processos, às vezes. + +Confira abaixo uma lista não exaustiva de operações do TensorFlow que geralmente são removidas do grafo: + +- `tf.add` +- `tf.debugging.check_numerics` +- `tf.constant` +- `tf.div` +- `tf.divide` +- `tf.fake_quant_with_min_max_args` +- `tf.fake_quant_with_min_max_vars` +- `tf.identity` +- `tf.maximum` +- `tf.minimum` +- `tf.multiply` +- `tf.no_op` +- `tf.placeholder` +- `tf.placeholder_with_default` +- `tf.realdiv` +- `tf.reduce_max` +- `tf.reduce_min` +- `tf.reduce_sum` +- `tf.rsqrt` +- `tf.shape` +- `tf.sqrt` +- `tf.square` +- `tf.subtract` +- `tf.tile` +- `tf.nn.batch_norm_with_global_normalization` +- `tf.nn.bias_add` +- `tf.nn.fused_batch_norm` +- `tf.nn.relu` +- `tf.nn.relu6` + +Observação: diversas dessas operações não têm equivalentes no TensorFlow Lite, e o modelo correspondente não poderá ser convertido se elas não puderem ser eliminadas ou fundidas. + +## Operações experimentais + +As operações do TensorFlow Lite abaixo estão presentes, mas não estão prontas para modelos personalizados: + +- `CALL` +- `CONCAT_EMBEDDINGS` +- `CUSTOM` +- `EMBEDDING_LOOKUP_SPARSE` +- `HASHTABLE_LOOKUP` +- `LSH_PROJECTION` +- `SKIP_GRAM` +- `SVDF` diff --git a/site/pt-br/lite/guide/ops_custom.md b/site/pt-br/lite/guide/ops_custom.md new file mode 100644 index 0000000000..af3426e592 --- /dev/null +++ b/site/pt-br/lite/guide/ops_custom.md @@ -0,0 +1,245 @@ +# Operadores personalizados + +Como a biblioteca de operadores integrados do TensorFlow Lite só tem suporte a um número limitado de operadores do TensorFlow, nem todo modelo pode ser convertido. Confira mais detalhes em [Compatibilidade de operadores](ops_compatibility.md). + +Para possibilitar a conversão, os usuários precisam fornecer sua própria implementação personalizada de um operador do TensorFlow sem suporte no TensorFlow Lite, conhecido como operador personalizado. *Se em vez disso você quiser combinar uma série de operadores do TensorFlow sem suporte (ou com suporte) em um único operador personalizado, otimizado e fundido, confira [Fusão de operadores](https://www.tensorflow.org/lite/models/convert/operation_fusion).* + +Para usar operadores personalizados, é preciso seguir quatro etapas: + +- [Crie um modelo do TensorFlow.](#create-a-tensorflow-model) O SavedModel (ou GraphDef) precisa referenciar o nome correto do operador do TensorFlow Lite. + +- [Converta para um modelo do TensorFlow Lite.](#convert-to-a-tensorflow-lite-model) Defina o atributo correto do conversor do TensorFlow Lite para converter o modelo corretamente. + +- [Crie e registre o operador.](#create-and-register-the-operator) Isso é necessário para que o runtime do TensorFlow Lite saiba como mapear o operador e os parâmetros em seu grafo para código executável do C/C++. + +- [Teste e faça o profiling do seu operador.](#test-and-profile-your-operator) Se você deseja testar somente seu operador personalizado, é melhor criar um modelo com somente seu operador e usar o programa [benchmark_model](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/benchmark/benchmark_model.cc). + +Vamos ver um exemplo completo de execução de um modelo com um operador personalizado `tf.atan` (chamado de `Atan`, confira a seção Crie um modelo do TensorFlow), que tem suporte no TensorFlow, mas não tem suporte no TensorFlow Lite. + +Observação: a função `tf.atan` **não** é um operador personalizado. É um operador comum com suporte tanto no TensorFlow quanto no TensorFlow Lite. Porém, vamos **pressupor** que ele seja um operador personalizado no exemplo abaixo para demonstrar um workflow simples. + +O operador TensorFlow Text é um exemplo de operador personalizado. Confira um exemplo de código no tutorial Converta TF Text para o TF Lite. + +## Exemplo: operador personalizado `Atan` + +Vamos ver um exemplo de como adicionar suporte a um operador do TensorFlow não disponível no TensorFlow Lite. Vamos supor que estejamos usando o operador `Atan` e que estejamos criando um modelo muito simples para a função `y = atan(x + offset)`, em que `offset` é treinável. + +### Crie um modelo do TensorFlow + +O trecho de código abaixo treina um modelo simples do TensorFlow. Esse modelo contém somente um operador personalizado chamado `Atan`, que é a função `y = atan(x + offset)`, em que `offset` é treinável. + +```python +import tensorflow as tf + +# Define training dataset and variables +x = [-8, 0.5, 2, 2.2, 201] +y = [-1.4288993, 0.98279375, 1.2490457, 1.2679114, 1.5658458] +offset = tf.Variable(0.0) + +# Define a simple model which just contains a custom operator named `Atan` +@tf.function(input_signature=[tf.TensorSpec.from_tensor(tf.constant(x))]) +def atan(x): + return tf.atan(x + offset, name="Atan") + +# Train model +optimizer = tf.optimizers.Adam(0.01) +def train(x, y): + with tf.GradientTape() as t: + predicted_y = atan(x) + loss = tf.reduce_sum(tf.square(predicted_y - y)) + grads = t.gradient(loss, [offset]) + optimizer.apply_gradients(zip(grads, [offset])) + +for i in range(1000): + train(x, y) + +print("The actual offset is: 1.0") +print("The predicted offset is:", offset.numpy()) +``` + +```python +The actual offset is: 1.0 +The predicted offset is: 0.99999905 +``` + +Neste momento, se você tentar gerar um modelo do TensorFlow Lite com os sinalizadores padrão do conversor, verá a seguinte mensagem de erro: + +```none +Error: +error: 'tf.Atan' op is neither a custom op nor a flex op. +``` + +### Converta para um modelo do TensorFlow Lite + +Crie um modelo do TensorFlow Lite com operadores personalizados definindo o atributo `allow_custom_ops` do conversor, conforme exibido abaixo: + +
converter = tf.lite.TFLiteConverter.from_concrete_functions([atan.get_concrete_function()], atan)
+<b>converter.allow_custom_ops = True</b>
+tflite_model = converter.convert()
+
+ +Neste momento, se você executá-lo com o interpretador padrão usando comandos como os seguintes: + +```python +interpreter = tf.lite.Interpreter(model_content=tflite_model) +interpreter.allocate_tensors() +``` + +Será exibido o erro: + +```none +Encountered unresolved custom op: Atan. +``` + +### Crie e registre o operador + +Todos os operadores do TensorFlow Lite (tanto personalizados quanto integrados) são definidos usando-se uma interface simples em C puro que é composta por quatro funções: + +```c++ +typedef struct { + void* (*init)(TfLiteContext* context, const char* buffer, size_t length); + void (*free)(TfLiteContext* context, void* buffer); + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node); + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node); +} TfLiteRegistration; +``` + +Confira [`common.h`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/c/common.h) para ver detalhes sobre `TfLiteContext` e `TfLiteNode`. O primeiro conta com recursos de relatórios de erros e acesso a objetos globais, incluindo todos os tensores. O segundo permite implementações para acessar suas entradas e saídas. + +Quando o interpretador carrega um modelo, ele chama `init()` uma vez em cada nó do grafo. Um determinado `init()` será chamado mais de uma vez se a operação for usada diversas vezes no grafo. Para operações personalizadas, será concedido um buffer de configuração contendo um flexbuffer que mapeia os nomes de parâmetros para seus valores. O buffer fica vazio para operações integradas, pois o interpretador já processou seus parâmetros. Implementações de kernels que exijam estado deverão inicializá-lo aqui e transferir a titularidade para o chamador. Para cada chamada a `init()`, haverá uma chamada correspondente a `free()`, o que permite às implementações descartar o buffer que possam ter alocado em `init()`. + +Sempre que os tensores de entrada são redimensionados, o interpretador percorre o grafo, notificando as implementações que houve uma mudança. Dessa forma, elas terão a oportunidade de redimensionar o buffer interno, verificar a validade dos formatos e tipos de entrada, além de recalcular os formatos de saída. Isso tudo é feito por meio de `prepare()`, e as implementações podem acessar seu estado utilizando `node->user_data`. + +Por fim, a cada execução da inferência, o interpretador percorre o grafo, chamando `invoke()`, e o estado também fica disponível utilizando `node->user_data`. + +As operações personalizadas podem ser implementadas exatamente da mesma forma que as operações integradas, basta definir essas quatro funções e uma função global de registro que geralmente é feita da seguinte forma: + +```c++ +namespace tflite { +namespace ops { +namespace custom { + TfLiteRegistration* Register_MY_CUSTOM_OP() { + static TfLiteRegistration r = {my_custom_op::Init, + my_custom_op::Free, + my_custom_op::Prepare, + my_custom_op::Eval}; + return &r; + } +} // namespace custom +} // namespace ops +} // namespace tflite +``` + +Note que o registro não é automático, e uma chamada explícita a `Register_MY_CUSTOM_OP` precisa ser feita. Embora o `BuiltinOpResolver` padrão (disponível no alvo `:builtin_ops`) trate o registro de operações integradas, as operações personalizadas precisarão ser coletadas em bibliotecas personalizadas separadas. + +### Definição do kernel no runtime do TensorFlow Lite + +Para a usar a operação no TensorFlow Lite, basta definir duas funções (`Prepare` e `Eval`) e criar um `TfLiteRegistration`: + +```cpp +TfLiteStatus AtanPrepare(TfLiteContext* context, TfLiteNode* node) { + using namespace tflite; + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + const TfLiteTensor* input = GetInput(context, node, 0); + TfLiteTensor* output = GetOutput(context, node, 0); + + int num_dims = NumDimensions(input); + + TfLiteIntArray* output_size = TfLiteIntArrayCreate(num_dims); + for (int i=0; idata[i] = input->dims->data[i]; + } + + return context->ResizeTensor(context, output, output_size); +} + +TfLiteStatus AtanEval(TfLiteContext* context, TfLiteNode* node) { + using namespace tflite; + const TfLiteTensor* input = GetInput(context, node, 0); + TfLiteTensor* output = GetOutput(context, node, 0); + + float* input_data = GetTensorData(input); + float* output_data = GetTensorData(output); + + size_t count = 1; + int num_dims = NumDimensions(input); + for (int i = 0; i < num_dims; ++i) { + count *= input->dims->data[i]; + } + + for (size_t i=0; i(node->user_data); + TfLiteIntArrayFree(node->temporaries); + node->temporaries = TfLiteIntArrayCreate(1); + node->temporaries->data[0] = op_data->temp_tensor_index; + TfLiteTensor* temp_tensor = &context->tensors[op_data->temp_tensor_index]; + temp_tensor->type = kTfLiteFloat32; + temp_tensor->allocation_type = kTfLiteArenaRw; + ``` + +3. Se não houver muito desperdício de memória, opte por usar um array de tamanho fixo estático (ou um `std::vector` pré-alocado em `Resize`) em vez de usar um `std::vector` alocado dinamicamente em cada iteração da execução. + +4. Evite instanciar modelos do container da biblioteca padrão que ainda não existam, pois isso afeta o tamanho do binário. Por exemplo: se você precisar de um `std::map` em sua operação que não exista em outros kernels, usar um `std::vector` com mapeamento de indexação direta pode funcionar, mantendo o binário pequeno. Confira quais outros kernels usar para entender melhor (ou pergunte). + +5. Confira o ponteiro para a memória retornado por `malloc`. Se esse ponteiro for `nullptr`, nenhuma operação deve ser realizada utilizando-o. Se você fizer a alocação de memória (`malloc`) em uma função e houver um erro na saída, desaloque a memória antes de sair. + +6. Use `TF_LITE_ENSURE(context, condition)` para verificar uma condição específica. Seu código não pode deixar memória perdida quando `TF_LITE_ENSURE` é usado, ou seja, essas macros devem ser usadas antes de qualquer recurso que cause vazamento seja alocado. diff --git a/site/pt-br/lite/guide/ops_select.md b/site/pt-br/lite/guide/ops_select.md new file mode 100644 index 0000000000..eeeab722a6 --- /dev/null +++ b/site/pt-br/lite/guide/ops_select.md @@ -0,0 +1,220 @@ +# Operadores específicos do TensorFlow + +Como a biblioteca de operadores integrados do TensorFlow Lite só tem suporte a um número limitado de operadores do TensorFlow, nem todo modelo pode ser convertido. Confira mais detalhes em [Compatibilidade de operadores](ops_compatibility.md). + +Para permitir a conversão, os usuários podem ativar o uso de [operações específicas do TensorFlow](op_select_allowlist.md) em seu modelo do TensorFlow Lite. Porém, para executar modelos do TensorFlow Lite com operações do TensorFlow, é preciso buscar o runtime core do TensorFlow, o que aumenta o tamanho do binário do interpretador do TensorFlow Lite. No caso do Android, é possível evitar isso compilando seletivamente somente as operações do Tensorflow necessárias. Confira mais detalhes em [Reduza o tamanho do binário](../guide/reduce_binary_size.md). + +Este documento descreve como [converter](#convert_a_model) e [executar](#run_inference) um modelo do TensorFlow Lite contendo operações do TensorFlow em uma plataforma da sua escolha. Além disso, são discutidas [métricas de tamanho e desempenho](#metrics), além das [limitações conhecidas](#known_limitations). + +## Converta um modelo + +O exemplo a seguir mostra como gerar um modelo do TensorFlow Lite com operações específicas do TensorFlow. + +```python +import tensorflow as tf + +converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) +converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS, # enable TensorFlow Lite ops. + tf.lite.OpsSet.SELECT_TF_OPS # enable TensorFlow ops. +] +tflite_model = converter.convert() +open("converted_model.tflite", "wb").write(tflite_model) +``` + +## Execute a inferência + +Ao usar um modelo do TensorFlow Lite que foi convertido com suporte a operações específicas do TensorFlow, o cliente também precisa usar um runtime do TensorFlow Lite que inclua a biblioteca necessária de operações do TensorFlow. + +### AAR do Android + +Para reduzir o tamanho do binário, compile seus próprios arquivos AAR personalizados conforme orientado na [próxima seção](#building-the-android-aar). Se o tamanho do binário não for uma grande preocupação, recomendamos usar o [AAR pré-compilado com operações do TensorFlow hospedado em MavenCentral](https://search.maven.org/artifact/org.tensorflow/tensorflow-lite-select-tf-ops). + +Você pode especificá-lo nas dependências do `build.gradle`, adicionando-o junto com o AAR padrão do TensorFlow Lite da seguinte forma: + +```build +dependencies { + implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT' + // This dependency adds the necessary TF op support. + implementation 'org.tensorflow:tensorflow-lite-select-tf-ops:0.0.0-nightly-SNAPSHOT' +} +``` + +Para usar instantâneos noturnos, você deve adicionar o [repositório de instantâneo Sonatype](../android/lite_build.md#use_nightly_snapshots). + +Após adicionar a dependência, o delegado necessário para tratar as operações de grafo do TensorFlow deve ser instalado automaticamente para os grafos que precisem dele. + +*Observação*: a dependência de operações do TensorFlow é relativamente grande, então é uma boa ideia retirar as ABIs x86 desnecessárias do seu arquivo `.gradle` configurando seus `abiFilters`. + +```build +android { + defaultConfig { + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a' + } + } +} +``` + +#### Compilação do AAR do Android + +Para reduzir o tamanho do binário ou para outros casos mais avançados, você também pode compilar a biblioteca manualmente. Pressupondo um [ambiente de compilação funcional do TensorFlow Lite](../android/quickstart.md), compile o AAR do Android com operações específicas do TensorFlow da seguinte maneira: + +```sh +sh tensorflow/lite/tools/build_aar.sh \ + --input_models=/a/b/model_one.tflite,/c/d/model_two.tflite \ + --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a +``` + +Dessa forma, será gerado o arquivo AAR `bazel-bin/tmp/tensorflow-lite.aar` para as operações integradas e personalizadas do TensorFlow Lite; e será gerado o arquivo `bazel-bin/tmp/tensorflow-lite-select-tf-ops.aar` para operações do TensorFlow. Se você não tiver um ambiente de compilação funcional, pode [compilar os arquivos acima com o Docker](../guide/reduce_binary_size.md#selectively_build_tensorflow_lite_with_docker). + +Em seguida, você pode importar os arquivos AAR diretamente para o seu projeto ou publicar os arquivos AAR personalizados em seu repositório Maven local: + +```sh +mvn install:install-file \ + -Dfile=bazel-bin/tmp/tensorflow-lite.aar \ + -DgroupId=org.tensorflow \ + -DartifactId=tensorflow-lite -Dversion=0.1.100 -Dpackaging=aar +mvn install:install-file \ + -Dfile=bazel-bin/tmp/tensorflow-lite-select-tf-ops.aar \ + -DgroupId=org.tensorflow \ + -DartifactId=tensorflow-lite-select-tf-ops -Dversion=0.1.100 -Dpackaging=aar +``` + +Por fim, no `build.gradle` do app, confira se você tem a dependência `mavenLocal()` e troque a dependência padrão do TensorFlow Lite por uma compatível com operações específicas do TensorFlow: + +```build +allprojects { + repositories { + mavenCentral() + maven { // Only for snapshot artifacts + name 'ossrh-snapshot' + url 'https://oss.sonatype.org/content/repositories/snapshots' + } + mavenLocal() + } +} + +dependencies { + implementation 'org.tensorflow:tensorflow-lite:0.1.100' + implementation 'org.tensorflow:tensorflow-lite-select-tf-ops:0.1.100' +} +``` + +### iOS + +#### Como usar o CocoaPods + +O TensorFlow Lite conta com CocoaPods noturnos pré-compilados com operações específicas do TF para `arm64`, que você pode utilizar juntamente com CocoaPods `TensorFlowLiteSwift` ou `TensorFlowLiteObjC`. + +*Observação*: se você precisar usar operações específicas do TF em um simulador `x86_64`, pode compilar o framework com operações específicas por conta própria. Confira mais detalhes na seção [Como usar o Bazel + Xcode](#using_bazel_xcode). + +```ruby +# In your Podfile target: + pod 'TensorFlowLiteSwift' # or 'TensorFlowLiteObjC' + pod 'TensorFlowLiteSelectTfOps', '~> 0.0.1-nightly' +``` + +Após executar `pod install`, você precisa fornecer um sinalizador de vinculação adicional para forçar o carregamento do framework com operações específicas do TF em seu projeto. Em seu projeto do Xcode, acesse `Build Settings` (Configurações de compilação) -> `Other Linker Flags` (Outros sinalizadores de vinculação) e acrescente: + +Para versões >= 2.9.0: + +```text +-force_load $(SRCROOT)/Pods/TensorFlowLiteSelectTfOps/Frameworks/TensorFlowLiteSelectTfOps.xcframework/ios-arm64/TensorFlowLiteSelectTfOps.framework/TensorFlowLiteSelectTfOps +``` + +Para versões < 2.9.0: + +```text +-force_load $(SRCROOT)/Pods/TensorFlowLiteSelectTfOps/Frameworks/TensorFlowLiteSelectTfOps.framework/TensorFlowLiteSelectTfOps +``` + +Em seguida, você poderá executar qualquer modelo convertido com `SELECT_TF_OPS` em seu aplicativo para iOS. Por exemplo: você pode modificar o [aplicativo de classificação de imagens para iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/ios) a fim de testar o recurso de operações específicas do TF. + +- Substitua o arquivo do modelo pelo convertido com `SELECT_TF_OPS` ativado. +- Adicione a dependência `TensorFlowLiteSelectTfOps` ao `Podfile` conforme orientado. +- Adicione o sinalizador de vinculação adicional conforme indicado acima. +- Execute o aplicativo de exemplo e veja se o modelo funciona corretamente. + +#### Como usar o Bazel + Xcode + +É possível compilar o TensorFlow Lite com operações específicas do TensorFlow para iOS usando o Bazel. Primeiro, siga as [instruções de compilação para iOS](build_ios.md) a fim de configurar o workspace do Bazel e o arquivo `.bazelrc` corretamente. + +Após configurar o workspace com suporte ao iOS, você pode usar o comando abaixo para compilar o framework com operações específicas do TF, que pode ser adicionado juntamente com o `TensorFlowLiteC.framework` comum. O framework com operações específicas do TF não pode ser compilado para a arquitetura `i386`, então você precisa fornecer explicitamente a lista de arquiteturas desejadas, exceto `i386`. + +```sh +bazel build -c opt --config=ios --ios_multi_cpus=arm64,x86_64 \ + //tensorflow/lite/ios:TensorFlowLiteSelectTfOps_framework +``` + +Dessa forma, será gerado o framework no diretório `bazel-bin/tensorflow/lite/ios/`. Você pode adicionar esse novo framework ao seu projeto do Xcode seguindo etapas similares às descritas na seção [Configurações do projeto do Xcode](./build_ios.md#modify_xcode_project_settings_directly) no guia de compilação para iOS. + +Após adicionar o framework ao seu projeto de aplicativo, um sinalizador de vinculação adicional deve ser especificado em seu projeto para forçar o carregamento do framework com operações específicas do TF. Em seu projeto do Xcode, acesse `Build Settings` (Configurações de compilação) -> Other Linker Flags (Outros sinalizadores de vinculação) e acrescente: + +```text +-force_load +``` + +### C/C++ + +Se você estiver usando o Bazel ou o [CMake](https://www.tensorflow.org/lite/guide/build_cmake) para compilar o interpretador do TensorFlow Lite, pode ativar o delegado Flex fazendo a vinculação a uma biblioteca compartilhada de delegado Flex do TensorFlow Lite. Você pode compilar usando o Bazel com o seguinte comando: + +``` +bazel build -c opt --config=monolithic tensorflow/lite/delegates/flex:tensorflowlite_flex +``` + +Esse comando gera a seguinte biblioteca compartilhada em `bazel-bin/tensorflow/lite/delegates/flex`. + +Plataforma | Nome da biblioteca +--- | --- +Linux | `libtensorflowlite_flex.so` +macOS | `libtensorflowlite_flex.dylib` +Windows | `tensorflowlite_flex.dll` + +O `TfLiteDelegate` necessário será instalado automaticamente ao criar o interpretador no runtime, desde que a biblioteca compartilhada esteja vinculada. Não é necessário instalar explicitamente a instância do delegado como costuma ser necessário para outros tipos de delegado. + +**Observação:** esse recurso está disponível a partir a versão 2.7. + +### Python + +O TensorFlow Lite com operações específicas do TensorFlow será instalado automaticamente com o [pacote pip do TensorFlow](https://www.tensorflow.org/install/pip). Você também pode optar por instalar somente o [pacote pip do interpretador do TensorFlow Lite](https://www.tensorflow.org/lite/guide/python#install_just_the_tensorflow_lite_interpreter). + +Observação: o TensorFlow Lite com operações específicas do TensorFlow está disponível no pacote pip do TensorFlow desde a versão 2.3 para Linux e 2.4 para outros ambientes. + +## Métricas + +### Desempenho + +Ao usar uma combinação de operações integradas e específicas do TensorFlow, todas as mesmas otimizações do TensorFlow Lite e operações integradas otimizadas estarão disponíveis e poderão ser usadas pelo modelo convertido. + +A tabela abaixo indica o tempo médio de execução da inferência na MobileNet em um dispositivo Pixel 2. Os tempos indicados são uma média de 100 execuções. Esses alvos foram compilados para o Android usando os sinalizadores: `--config=android_arm64 -c opt`. + +Build | Tempo (em ms) +--- | --- +Somente operações integradas (`TFLITE_BUILTIN`) | 260,7 +Somente operações do TF (`SELECT_TF_OPS`) | 264,5 + +### Tamanho do binário + +A tabela abaixo indica o tamanho do binário do TensorFlow Lite para cada build. Esses alvos foram compilados para o Android usando `--config=android_arm -c opt`. + +Build | Tamanho do binário em C++ | Tamanho do APK para Android +--- | --- | --- +Somente operações integradas | 796 KB | 561 KB +Operações integradas + operações do TF | 23 MB | 8 MB +Operações integradas + operações do TF (1) | 4,1 MB | 1,8 MB + +(1) Estas bibliotecas são compiladas seletivamente para o [modelo i3d-kinetics-400](https://tfhub.dev/deepmind/i3d-kinetics-400/1), com 8 operações integradas do TF Lite e 3 operações do TensorFlow. Confira mais detalhes na seção [Reduza o tamanho do binário do TensorFlow Lite](../guide/reduce_binary_size.md). + +## Limitações conhecidas + +- Tipos sem suporte: determinadas operações do TensorFlow poderão não ter suporte ao conjunto total de tipos de entrada/saída que costumam estar disponíveis no TensorFlow. + +## Atualizações + +- Versão 2.6 + - Suporte a operadores baseados em atributos GraphDef e melhoria das inicializações de recursos HashTable. +- Versão 2.5 + - É possível aplicar uma otimização conhecida como [quantização pós-treinamento](../performance/post_training_quantization.md). +- Versão 2.4 + - Melhoria da compatibilidade com delegados acelerados por hardware. diff --git a/site/pt-br/lite/guide/ops_version.md b/site/pt-br/lite/guide/ops_version.md new file mode 100644 index 0000000000..6aa625e89a --- /dev/null +++ b/site/pt-br/lite/guide/ops_version.md @@ -0,0 +1,208 @@ +# Versões dos operadores do TensorFlow Lite + +Este documento descreve o esquema de versionamento dos operadores do TensorFlow Lite. Com o versionamento de operações, os desenvolvedores podem adicionar novas funcionalidades e parâmetros aos operadores existentes. Além disso, garante o seguinte: + +- Compatibilidade com versões anteriores: novas implementações do TensorFlow Lite devem funcionar com arquivos de modelos antigos. +- Compatibilidade com versões posteriores: implementações antigas do TensorFlow Lite devem funcionar com novos arquivos de modelos gerados pela nova versão do conversor, desde que nenhum novo recurso tenha sido usado. +- Detecção de compatibilidade com versões posteriores: se uma implementação antiga do TensorFlow Lite ler um novo modelo que contenha uma nova versão de uma operação sem suporte, deve comunicar o erro. + +## Exemplo: como adicionar limitação a uma convolução com reconhecimento de profundidade + +O restante deste documento explica o versionamento de operações no TF Lite ao mostrar como adicionar parâmetros de dilatação a uma operação de convolução com reconhecimento de profundidade. + +Não é necessário conhecer conceitos de dilatação para entender este documento. Observe que: + +- Dois novos parâmetros inteiros serão adicionados: `dilation_width_factor` e `dilation_height_factor`. +- Kernels antigos de convolução com reconhecimento de profundidade que não tenham suporte a dilatação são equivalentes a definir os fatores de dilatação como 1. + +### Altere o esquema do FlatBuffer + +Para adicionar novos parâmetros a uma operação, altere a tabela de opções em `lite/schema/schema.fbs`. + +Por exemplo: a tabela de opções de convolução com reconhecimento de profundidade deve ser assim: + +``` +table DepthwiseConv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; +} +``` + +Ao adicionar novos parâmetros: + +- Adicione comentários indicando quais parâmetros têm suporte em quais versões. +- Quando a nova implementação obtiver os valores padrão dos parâmetros recém-adicionados, deve funcionar exatamente da mesma forma que a implementação antiga. + +Após adicionar os parâmetros, a tabela deverá ser: + +``` +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} +``` + +O arquivo `lite/schema/schema_generated.h` deve ser gerado novamente para o novo esquema. + +### Altere as estruturas do C e a implementação do kernel + +No TensorFlow Lite, a implementação do kernel está desacoplada da definição do FlatBuffer. Os kernels leem o parâmetro das estruturas do C definidas em `lite/c/builtin_op_data.h`. + +O parâmetro original de convolução com reconhecimento de profundidade é o seguinte: + +``` +typedef struct { + TfLitePadding padding; + int stride_width; + int stride_height; + int depth_multiplier; + TfLiteFusedActivation activation; +} TfLiteDepthwiseConvParams; +``` + +Tal como no esquema do FlatBuffer, adicione comentários indicando quais parâmetros têm suporte a partir de qual versão. Confira o resultado abaixo: + +``` +typedef struct { + // Parameters for DepthwiseConv version 1 or above. + TfLitePadding padding; + int stride_width; + int stride_height; + int depth_multiplier; + TfLiteFusedActivation activation; + // Parameters for DepthwiseConv version 2 or above. + int dilation_width_factor; + int dilation_height_factor; +} TfLiteDepthwiseConvParams; +``` + +Altere também a implementação do kernel para ler os parâmetros recém-adicionados das estruturas do C. Os detalhes foram omitidos aqui. + +### Altere o código de leitura do FlatBuffer + +A lógica para ler o FlatBuffer e gerar a estrutura do C está em `lite/core/api/flatbuffer_conversions.cc`. + +Atualize o arquivo para tratar os novos parâmetros, conforme mostrado abaixo: + +``` +TfLiteStatus ParseDepthwiseConv2D(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const DepthwiseConv2DOptions* schema_params = + op->builtin_options_as_DepthwiseConv2DOptions(); + + if (schema_params != nullptr) { + params->padding = ConvertPadding(schema_params->padding()); + params->stride_width = schema_params->stride_w(); + params->stride_height = schema_params->stride_h(); + params->depth_multiplier = schema_params->depth_multiplier(); + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + + params->dilation_width_factor = schema_params->dilation_w_factor(); + params->dilation_height_factor = schema_params->dilation_h_factor(); + } + + *builtin_data = params.release(); + return kTfLiteOk; +} +``` + +Não é obrigatório verificar a versão da operação aqui. Quando a nova implementação ler um arquivo de modelo antigo, em que os fatores de dilatação estão ausentes, ela usará 1 como o valor padrão, e o novo kernel funcionará de forma consistente com o kernel antigo. + +### Altere o registro do kernel + +O MutableOpResolver (definido em `lite/mutable_op_resolver.h`) fornece algumas funções para registrar kernels de operações. A versão mínima e a versão máxima são 1 por padrão. + +``` +void AddBuiltin(tflite::BuiltinOperator op, TfLiteRegistration* registration, + int min_version = 1, int max_version = 1); +void AddCustom(const char* name, TfLiteRegistration* registration, + int min_version = 1, int max_version = 1); +``` + +As operações integradas são registradas em `lite/kernels/register.cc`. Neste exemplo, implementamos um novo kernel de operação que pode tratar as versões 1 e 2 de `DepthwiseConv2D` e, portanto, precisamos alterar esta linha: + +``` +AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D()); +``` + +para: + +``` +AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(), + /* min_version = */ 1, + /* max_version = */ 2); +``` + +### Altere a versão da operação do TF Lite + +A próxima etapa é fazer o TF Lite preencher a versão mínima necessária para executar a operação. Neste exemplo, isso significa: + +- Preencher version=1 quando todos os fatores de dilatação forem iguais a 1. +- Caso contrário, preencher version=2. + +Modifique a função `GetBuiltinOperatorVersion` para o operador em `lite/tools/versioning/op_version.cc` adicionando a nova versão ao caso `DepthwiseConv2D`: + +``` +case BuiltinOperator_DEPTHWISE_CONV_2D: + auto depthwise_conv_params = + reinterpret_cast(op_sig.builtin_data); + TFLITE_DCHECK(depthwise_conv_params != nullptr); + if (depthwise_conv_params->dilation_width_factor != 1 || + depthwise_conv_params->dilation_height_factor != 1) { + return 2; + } + return 1; +``` + +### Atualize o mapeamento de versões do operador + +A última etapa é adicionar as informações da nova versão ao mapeamento de versões do operador. Essa etapa é necessária porque precisamos gerar a versão mínima do runtime exigida pelo modelo com base nesse mapeamento de versões. + +Para fazer isso, você precisa adicionar uma nova entrada ao mapeamento em `lite/tools/versioning/runtime_version.cc`. + +Neste exemplo, você precisa adicionar a entrada abaixo a `op_version_map`: + +``` +{{BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%} +``` + +em que `%CURRENT_RUNTIME_VERSION%` corresponde à versão atual do runtime definida em [tensorflow/core/public/version.h](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/public/version.h). + +### Implementação de delegação + +O TensorFlow Lite conta com uma API de delegação que permite delegar operações a back-ends de hardware. Na função `Prepare` do delegado, verifique se a versão tem suporte para cada nó do código de delegação. + +``` +const int kMaxVersion = 1; +TfLiteNode* node; +TfLiteRegistration* registration = nullptr; +TF_LITE_ENSURE_STATUS(context->GetNodeAndRegistration(context, node_index, &node, ®istration)); + +if (registration->version > kMaxVersion) { + // Reject the node if the version isn't supported. +} +``` + +Isso é necessário mesmo se a delegação tiver suporte somente a operações da versão 1 para que a delegação possa detectar incompatibilidade quando receber uma operação de versão superior. diff --git a/site/pt-br/lite/guide/python.md b/site/pt-br/lite/guide/python.md new file mode 100644 index 0000000000..dbfd596669 --- /dev/null +++ b/site/pt-br/lite/guide/python.md @@ -0,0 +1,79 @@ +# Guia de início rápido para dispositivos Linux com Python + +Usar o TensorFlow Lite com o Python é excelente para dispositivos Linux embarcados, como [Raspberry Pi](https://www.raspberrypi.org/){:.external} e [dispositivos Coral com Edge TPU](https://coral.withgoogle.com/){:.external}, entre muitos outros + +Esta página mostra como começar a executar modelos do TensorFlow Lite com o Python em questão de minutos. Você só precisa de um modelo do TensorFlow [convertido para o TensorFlow Lite](../models/convert/) (caso você ainda não tenha um modelo convertido, pode usar o modelo fornecido no exemplo indicado abaixo). + +## Sobre o pacote de runtime do TensorFlow Lite + +Para começar rapidamente a executar modelos do TensorFlow Lite com o Python, você pode instalar apenas o interpretador do TensorFlow Lite, em vez de todos os pacotes do TensorFlow. Esse pacote Python simplificado é chamado de `tflite_runtime`. + +O pacote `tflite_runtime` tem uma fração do tamanho do pacote completo `tensorflow` e inclui o código mínimo necessário para executar inferências com o TensorFlow Lite, principalmente a classe do Python [`Interpreter`](https://www.tensorflow.org/api_docs/python/tf/lite/Interpreter). Esse pacote pequeno é ideal quando você só quer executar modelos `.tflite` e evitar o desperdício de espaço em disco com a biblioteca grande do TensorFlow. + +Observação: se você precisar de acesso a outras APIs do Python, como [TensorFlow Lite Converter](../models/convert/) (conversor do TF Lite), precisa instalar o [pacote completo do TensorFlow](https://www.tensorflow.org/install/). Por exemplo: as operações específicas do TF (https://www.tensorflow.org/lite/guide/ops_select) não estão incluídas no pacote `tflite_runtime`. Se os seus modelos tiverem dependências para alguma operação específica do TF, você precisará usar o pacote completo do TensorFlow. + +## Instale o TensorFlow Lite para Python + +É possível instalar no Linux pelo pip: + +
+python3 -m pip install tflite-runtime
+
+ +## Plataformas com suporte + +Os Wheels do Python `tflite-runtime` são pré-compilados e fornecidos para estas plataformas: + +- Linux armv7l (por exemplo: Raspberry Pi 2, 3, 4 e Zero 2 com Raspberry Pi OS de 32 bits) +- Linux aarch64 (por exemplo: Raspberry Pi 3, com Debian ARM64) +- Linux x86_64 + +Se você quiser executar modelos do TensorFlow Lite em outras plataformas, deve usar o [pacote completo do TensorFlow](https://www.tensorflow.org/install/) ou [compilar o pacote tflite-runtime a partir do código-fonte](build_cmake_pip.md). + +Se você estiver usando o TensorFlow com Coral Edge TPU, deve seguir a [documentação de configuração do Coral](https://coral.ai/docs/setup). + +Observação: não atualizamos mais o pacote Debian `python3-tflite-runtime`. O último pacote Debian é para o TF versão 2.5, que você pode instalar seguindo [estas instruções antigas](https://github.com/tensorflow/tensorflow/blob/v2.5.0/tensorflow/lite/g3doc/guide/python.md#install-tensorflow-lite-for-python). + +Observação: não lançamos mais Wheels `tflite-runtime` pré-compilados para Windows e macOS. Para essas plataformas, você deve usar o [pacote completo do TensorFlow](https://www.tensorflow.org/install/) ou [compilar o pacote tflite-runtime a partir do código-fonte](build_cmake_pip.md). + +## Execute uma inferência usando o tflite_runtime + +Em vez de importar `Interpreter` do módulo `tensorflow`, agora você precisa importá-lo do `tflite_runtime`. + +Por exemplo: após instalar o pacote acima, copie e execute o arquivo [`label_image.py`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/examples/python/). Provavelmente, haverá uma falha, pois a biblioteca `tensorflow` não está instalada. Para corrigir esse problema, edite esta linha do arquivo: + +```python +import tensorflow as tf +``` + +Para: + +```python +import tflite_runtime.interpreter as tflite +``` + +E altere esta linha + +```python +interpreter = tf.lite.Interpreter(model_path=args.model_file) +``` + +Para: + +```python +interpreter = tflite.Interpreter(model_path=args.model_file) +``` + +Agora, execute `label_image.py` novamente. Pronto! Agora, você está executando modelos do TensorFlow Lite. + +## Saiba mais + +- Para saber mais sobre a API `Interpreter`, leia [Carregue e execute um modelo no Python](inference.md#load-and-run-a-model-in-python). + +- Se você tiver um Raspberry Pi, confira uma [série de vídeos](https://www.youtube.com/watch?v=mNjXEybFn98&list=PLQY2H8rRoyvz_anznBg6y3VhuSMcpN9oe) sobre como executar detecção de objetos no Raspberry Pi usando o TensorFlow Lite. + +- Se você estiver usando um acelerador Coral ML, confira os [exemplos do Coral no GitHub](https://github.com/google-coral/tflite/tree/master/python/examples). + +- Para converter outros modelos do TensorFlow para TensorFlow Lite, leia mais sobre o [TensorFlow Lite Converter](../models/convert/) (conversor do TF Lite). + +- Se você quiser compilar o Wheel `tflite_runtime`, leia [Compile o pacote Wheel do Python para TensorFlow Lite](build_cmake_pip.md) diff --git a/site/pt-br/lite/guide/reduce_binary_size.md b/site/pt-br/lite/guide/reduce_binary_size.md new file mode 100644 index 0000000000..fcb47c6d23 --- /dev/null +++ b/site/pt-br/lite/guide/reduce_binary_size.md @@ -0,0 +1,379 @@ +# Reduza o tamanho do binário do TensorFlow Lite + +## Visão geral + +Ao implantar modelos para aplicativos de aprendizado de máquina no dispositivo (ODML, na sigla em inglês), é importante saber que a memória disponível em dispositivos móveis é limitada. O tamanho do binário dos modelos está intimamente relacionado ao número de operações usadas no modelo. O TensorFlow Lite permite reduzir o tamanho do binário do modelo por meio do uso de builds seletivas, que ignoram operações não usadas em seu conjunto de modelos e geram uma biblioteca compacta, apenas com o runtime e os kernels das operações necessárias para que o modelo seja executado em seu dispositivo móvel. + +As builds seletivas se aplicam às três bibliotecas de operações abaixo: + +1. [Operações integradas do TensorFlow Lite](https://www.tensorflow.org/lite/guide/ops_compatibility) +2. [Operações personalizadas do TensorFlow Lite](https://www.tensorflow.org/lite/guide/ops_custom) +3. [Operações específicas do TensorFlow](https://www.tensorflow.org/lite/guide/ops_select) + +A tabela abaixo indica o impacto de builds seletivas para alguns casos de uso comuns: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nome do modeloDomínioArquitetura alvoTamanho do arquivo AAR
Mobilenet_1.0_224(float) +Classificação de imagensarmeabi-v7atensorflow-lite.aar (296.635 bytes)
arm64-v8atensorflow-lite.aar (382.892 bytes)
SPICE +Extração de tons sonorosarmeabi-v7atensorflow-lite.aar (375.813 bytes)
tensorflow-lite-select-tf-ops.aar (1.676.380 bytes)
arm64-v8atensorflow-lite.aar (421.826 bytes)
tensorflow-lite-select-tf-ops.aar (2.298.630 bytes)
i3d-kinetics-400 +Classificação de vídeosarmeabi-v7atensorflow-lite.aar (240.085 bytes)
tensorflow-lite-select-tf-ops.aar (1.708.597 bytes)
arm64-v8atensorflow-lite.aar (273.713 bytes)
tensorflow-lite-select-tf-ops.aar (2.339.697 bytes)
+ +Observação: este recurso está em fase experimental, disponível desde a versão 2.4, e sujeito a alterações. + +## Compile o TensorFlow Lite seletivamente com o Bazel + +Esta seção pressupõe que você tenha baixado os códigos-fonte do TensorFlow e [configurado o ambiente de desenvolvimento local](https://www.tensorflow.org/lite/android/lite_build#set_up_build_environment_without_docker) no Bazel. + +### Compile arquivos AAR para projetos do Android + +Para compilar os AARs personalizados do TensorFlow Lite, basta fornecer os caminhos de arquivo abaixo ao seu modelo. + +```sh +sh tensorflow/lite/tools/build_aar.sh \ + --input_models=/a/b/model_one.tflite,/c/d/model_two.tflite \ + --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a +``` + +O comando acima vai gerar o arquivo AAR `bazel-bin/tmp/tensorflow-lite.aar` para as operações personalizadas e integradas do TensorFlow. Opcionalmente, vai gerar o arquivo AAR `bazel-bin/tmp/tensorflow-lite-select-tf-ops.aar` se os seus modelos tiverem operações específicas do TensorFlow. Observe que é gerado um AAR "fat", com diversas arquiteturas diferentes. Se você não precisar de todas elas, use um subconjunto apropriado para seu ambiente de desenvolvimento. + +### Compile com operações personalizadas + +Se você tiver implantado modelos do Tensorflow Lite com operações personalizadas, pode compilá-los adicionando os sinalizadores abaixo ao comando build: + +```sh +sh tensorflow/lite/tools/build_aar.sh \ + --input_models=/a/b/model_one.tflite,/c/d/model_two.tflite \ + --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a \ + --tflite_custom_ops_srcs=/e/f/file1.cc,/g/h/file2.h \ + --tflite_custom_ops_deps=dep1,dep2 +``` + +O sinalizador `tflite_custom_ops_srcs` contém os arquivos fonte das operações personalizadas, e o sinalizador `tflite_custom_ops_deps` contém as dependências para compilar esses arquivos fonte. Atenção: essas dependências precisam existir no repositório do TensorFlow. + +### Usos avançados – Regras personalizadas do Bazel + +Se o seu projeto estiver usando o Bazel e você quiser definir dependências personalizadas do TF Lite para um determinado conjunto de modelos, pode definir as regras abaixo no repositório do projeto: + +Para modelos com apenas operações integradas: + +```bazel +load( + "@org_tensorflow//tensorflow/lite:build_def.bzl", + "tflite_custom_android_library", + "tflite_custom_c_library", + "tflite_custom_cc_library", +) + +# A selectively built TFLite Android library. +tflite_custom_android_library( + name = "selectively_built_android_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +# A selectively built TFLite C library. +tflite_custom_c_library( + name = "selectively_built_c_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +# A selectively built TFLite C++ library. +tflite_custom_cc_library( + name = "selectively_built_cc_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) +``` + +Para modelos com [operações específicas do TF](../guide/ops_select.md): + +```bazel +load( + "@org_tensorflow//tensorflow/lite/delegates/flex:build_def.bzl", + "tflite_flex_android_library", + "tflite_flex_cc_library", +) + +# A Select TF ops enabled selectively built TFLite Android library. +tflite_flex_android_library( + name = "selective_built_tflite_flex_android_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +# A Select TF ops enabled selectively built TFLite C++ library. +tflite_flex_cc_library( + name = "selective_built_tflite_flex_cc_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) +``` + +### Usos avançados – Compile bibliotecas compartilhadas do C/C++ personalizadas + +Se você quiser compilar seus próprios objetos compartilhados do C/C++ para TF Lite personalizados referentes aos modelos determinados, pode seguir as etapas abaixo: + +Crie um arquivo BUILD temporário executando o comando abaixo no diretório raiz do código-fonte do TensorFlow: + +```sh +mkdir -p tmp && touch tmp/BUILD +``` + +#### Compilando objetos compartilhados do C personalizados + +Se você quiser compilar um objeto compartilhado do C para TF Lite personalizado, adicione o seguinte ao arquivo `tmp/BUILD`: + +```bazel +load( + "//tensorflow/lite:build_def.bzl", + "tflite_custom_c_library", + "tflite_cc_shared_object", +) + +tflite_custom_c_library( + name = "selectively_built_c_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +# Generates a platform-specific shared library containing the TensorFlow Lite C +# API implementation as define in `c_api.h`. The exact output library name +# is platform dependent: +# - Linux/Android: `libtensorflowlite_c.so` +# - Mac: `libtensorflowlite_c.dylib` +# - Windows: `tensorflowlite_c.dll` +tflite_cc_shared_object( + name = "tensorflowlite_c", + linkopts = select({ + "//tensorflow:ios": [ + "-Wl,-exported_symbols_list,$(location //tensorflow/lite/c:exported_symbols.lds)", + ], + "//tensorflow:macos": [ + "-Wl,-exported_symbols_list,$(location //tensorflow/lite/c:exported_symbols.lds)", + ], + "//tensorflow:windows": [], + "//conditions:default": [ + "-z defs", + "-Wl,--version-script,$(location //tensorflow/lite/c:version_script.lds)", + ], + }), + per_os_targets = True, + deps = [ + ":selectively_built_c_lib", + "//tensorflow/lite/c:exported_symbols.lds", + "//tensorflow/lite/c:version_script.lds", + ], +) +``` + +O alvo recém-adicionado pode ser compilado da seguinte forma: + +```sh +bazel build -c opt --cxxopt=--std=c++17 \ + //tmp:tensorflowlite_c +``` + +Para Android, substitua `android_arm` por `android_arm64` para 64 bits: + +```sh +bazel build -c opt --cxxopt=--std=c++17 --config=android_arm \ + //tmp:tensorflowlite_c +``` + +#### Compilando objetos compartilhados do C++ personalizados + +Se você quiser compilar um objeto compartilhado do C++ para TF Lite personalizado, adicione o seguinte ao arquivo `tmp/BUILD`: + +```bazel +load( + "//tensorflow/lite:build_def.bzl", + "tflite_custom_cc_library", + "tflite_cc_shared_object", +) + +tflite_custom_cc_library( + name = "selectively_built_cc_lib", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +# Shared lib target for convenience, pulls in the core runtime and builtin ops. +# Note: This target is not yet finalized, and the exact set of exported (C/C++) +# APIs is subject to change. The output library name is platform dependent: +# - Linux/Android: `libtensorflowlite.so` +# - Mac: `libtensorflowlite.dylib` +# - Windows: `tensorflowlite.dll` +tflite_cc_shared_object( + name = "tensorflowlite", + # Until we have more granular symbol export for the C++ API on Windows, + # export all symbols. + features = ["windows_export_all_symbols"], + linkopts = select({ + "//tensorflow:macos": [ + "-Wl,-exported_symbols_list,$(location //tensorflow/lite:tflite_exported_symbols.lds)", + ], + "//tensorflow:windows": [], + "//conditions:default": [ + "-Wl,-z,defs", + "-Wl,--version-script,$(location //tensorflow/lite:tflite_version_script.lds)", + ], + }), + per_os_targets = True, + deps = [ + ":selectively_built_cc_lib", + "//tensorflow/lite:tflite_exported_symbols.lds", + "//tensorflow/lite:tflite_version_script.lds", + ], +) +``` + +O alvo recém-adicionado pode ser compilado da seguinte forma: + +```sh +bazel build -c opt --cxxopt=--std=c++17 \ + //tmp:tensorflowlite +``` + +Para Android, substitua `android_arm` por `android_arm64` para 64 bits: + +```sh +bazel build -c opt --cxxopt=--std=c++17 --config=android_arm \ + //tmp:tensorflowlite +``` + +Para modelos com operações específicas do TF, você também precisa compartilhar a seguinte biblioteca compartilhada: + +```bazel +load( + "@org_tensorflow//tensorflow/lite/delegates/flex:build_def.bzl", + "tflite_flex_shared_library" +) + +# Shared lib target for convenience, pulls in the standard set of TensorFlow +# ops and kernels. The output library name is platform dependent: +# - Linux/Android: `libtensorflowlite_flex.so` +# - Mac: `libtensorflowlite_flex.dylib` +# - Windows: `libtensorflowlite_flex.dll` +tflite_flex_shared_library( + name = "tensorflowlite_flex", + models = [ + ":model_one.tflite", + ":model_two.tflite", + ], +) + +``` + +O alvo recém-adicionado pode ser compilado da seguinte forma: + +```sh +bazel build -c opt --cxxopt='--std=c++17' \ + --config=monolithic \ + --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ + //tmp:tensorflowlite_flex +``` + +Para Android, substitua `android_arm` por `android_arm64` para 64 bits: + +```sh +bazel build -c opt --cxxopt='--std=c++17' \ + --config=android_arm \ + --config=monolithic \ + --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ + //tmp:tensorflowlite_flex +``` + +## Compile o TensorFlow Lite seletivamente com o Docker + +Esta seção pressupõe que você tenha instalado o [Docker](https://docs.docker.com/get-docker/) em sua máquina local e baixado o Dockerfile do TensorFlow Lite [aqui](https://www.tensorflow.org/lite/android/lite_build#set_up_build_environment_using_docker). + +Após baixar o Dockerfile acima, você pode compilar a imagem docker executando: + +```shell +docker build . -t tflite-builder -f tflite-android.Dockerfile +``` + +### Compile arquivos AAR para projetos do Android + +Baixe o script para compilar com o Docker executando: + +```sh +curl -o build_aar_with_docker.sh \ + https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/lite/tools/build_aar_with_docker.sh && +chmod +x build_aar_with_docker.sh +``` + +Em seguida, para compilar os AARs personalizados do TensorFlow Lite, basta fornecer os caminhos de arquivo abaixo ao seu modelo. + +```sh +sh build_aar_with_docker.sh \ + --input_models=/a/b/model_one.tflite,/c/d/model_two.tflite \ + --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a \ + --checkpoint=master \ + [--cache_dir=] +``` + +O sinalizador `checkpoint` é um commit, um branch ou uma tag do repositório do TensorFlow do qual você deseja fazer o checkout antes de compilar as bibliotecas. Por padrão, é o branch da versão mais recente. O comando acima vai gerar o arquivo AAR `tensorflow-lite.aar` para as operações personalizadas e integradas do TensorFlow Lite e, opcionalmente, vai gerar o arquivo AAR `tensorflow-lite-select-tf-ops.aar` para operações específicas do TensorFlow no diretório atual. + +O argumento --cache_dir especifica o diretório de cache. Caso não seja fornecido, o script vai criar um diretório chamado `bazel-build-cache` no diretório de trabalho atual para fazer o cache. + +## Adicione arquivos AAR ao projeto + +Adicione arquivos AAR [importando diretamente o AAR ao projeto](https://www.tensorflow.org/lite/android/lite_build#add_aar_directly_to_project) ou [publicando o AAR personalizado em seu repositório Maven atual](https://www.tensorflow.org/lite/android/lite_build#install_aar_to_local_maven_repository). Atenção: você também precisa adicionar os arquivos AAR para `tensorflow-lite-select-tf-ops.aar`, se for gerá-lo. + +## Compile seletivamente para iOS + +Confira a [seção Compilando localmente](../guide/build_ios.md#building_locally) para configurar o ambiente de compilação e o workspace do TensorFlow. Depois, siga o [guia](../guide/build_ios.md#selectively_build_tflite_frameworks) para usar o script de builds seletivas para iOS. diff --git a/site/pt-br/lite/guide/roadmap.md b/site/pt-br/lite/guide/roadmap.md new file mode 100644 index 0000000000..c553b6c53a --- /dev/null +++ b/site/pt-br/lite/guide/roadmap.md @@ -0,0 +1,79 @@ +# Desenvolvimentos futuros do TensorFlow Lite + +**Atualizado em: maio de 2021** + +Esta é uma visão geral dos desenvolvimentos futuros, que podem ser alterados a qualquer momento. A ordem abaixo não indica nenhum tipo de prioridade. + +Detalhamos os desenvolvimentos futuros em quatro segmentos principais: usabilidade, desempenho, otimização e portabilidade. Recomendamos que faça comentários sobre os desenvolvimentos futuros e forneça feedback no [grupo de discussão do TensorFlow Lite](https://groups.google.com/a/tensorflow.org/g/tflite). + +## Usabilidade + +- **Expansão da cobertura de operações** + - Inclusão de operações seletas com base em feedback dos usuários. + - Inclusão de conjuntos seletos de operações para domínios e áreas específicos, incluindo operações aleatórias, operações de camadas do Keras base, tabelas de hash, operações seletas de treinamento. +- **Conjunto de ferramentas mais assistivas** + - Fornecimento de ferramentas de compatibilidade e anotação de grafos ao TensorFlow para validar a compatibilidade entre o TF Lite e o acelerador de hardware durante o treinamento e após a conversão. + - Possibilidade de escolha e otimização para aceleradores específicos durante a conversão. +- **Treinamento no dispositivo** + - Suporte ao treinamento no dispositivo para personalização e aprendizado por transferência, incluindo um Colab demonstrando o uso do início ao fim. + - Suporte a tipos de variável/recurso (tanto para inferência quanto treinamento). + - Suporte à conversão e execução de grafos com diversos pontos de entrada de função (ou assinatura). +- **Integração aprimorada com o Android Studio** + - Arraste e solte modelos do TF Lite no Android Studio para gerar interfaces do modelo. + - Melhoria do suporte ao profiling do Android Studio, incluindo profiling de memória. +- **Model Maker (criador de modelos)** + - Suporte a novas tarefas, incluindo detecção de objetos, recomendações e classificação de áudio, abrangendo uma grande gama de usos comuns. + - Suporte a mais datasets para facilitar o aprendizado por transferência. +- **Biblioteca Task** + - Suporte a mais tipos de modelo (por exemplo: áudio, NLP) com funcionalidades de pré e pós-processamento. + - Atualização de mais exemplos de referência com APIs de tarefas. + - Suporte integrado à aceleração para todas as tarefas. +- **Mais modelos e exemplos de última geração** + - Inclusão de mais exemplos (como áudio, NLP e relacionados a dados estruturados) para demonstrar o uso do modelo, além de novos recursos e APIs, abrangendo diferentes plataformas. + - Criação de modelos backbone compartilháveis para ML no dispositivo a fim de reduzir os custos de treinamento e implantação. +- **Implantação simplificada em múltiplas plataformas** + - Execução de modelos do TensorFlow Lite na web. +- **Melhoria do suporte interplataforma** + - Melhoria e expansão de APIs para Java no Android, Swift no iOS, Python no RPi. + - Melhoria de suporte ao CMake (como suporte mais amplo a aceleradores). +- **Suporte melhor ao front-end** + - Melhoria da compatibilidade com diversos front-ends de autoração, incluindo Keras e tf.numpy. + +## Desempenho + +- **Conjunto de ferramentas melhores** + - Painel de ferramentas público para acompanhar os ganhos de desempenho a cada versão. + - Conjunto de ferramentas para entender melhor a compatibilidade do grafo com os aceleradores desejados. +- **Melhor desempenho em CPUs** + - XNNPack ativado por padrão para inferência mais rápida com ponto flutuante. + - Suporte à meia precisão (float16) fim a fim com kernels otimizados. +- **Atualização do suporte à NNAPI** + - Suporte completo aos recursos, operações e tipos mais novos da NNAPI para Android. +- **Otimizações para GPUs** + - Melhoria do tempo de inicialização, com suporte à serialização de delegados. + - Interoperabilidade de buffer de hardware para inferência sem cópias (zero-copy). + - Maior disponibilidade de aceleração no dispositivo. + - Maior cobertura de operações. + +## Otimização + +- **Quantização** + + - Quantização pós-treinamento seletiva para excluir determinadas camadas da quantização. + - Depurador de quantização para inspecionar as perdas de erro de quantização por camada. + - Aplicação de treinamento com reconhecimento de quantização em mais modelos, como o TensorFlow Model Garden. + - Melhorias de qualidade e desempenho para quantização pós-treinamento de intervalo dinâmico. + - API Tensor Compression (compressão de tensores) para permitir algoritmos de compressão, como SVD. + +- **Pruning/esparsividade** + + - Combinação de APIs de tempo de treinamento configuráveis (pruning + treinamento com reconhecimento de quantização). + - Aumento da aplicação de esparsividade nos modelos do TF Model Garden. + - Suporte à execução de modelos esparsos no TensorFlow Lite. + +## Portabilidade + +- **Suporte a microcontroladores** + - Inclusão de suporte para diversos casos de uso com arquitetura de 32 bits para classificação de fala e imagem. + - Front-end de áudio: suporte à aceleração e ao pré-processamento de áudio no grafo. + - Modelos e código de exemplo para dados de visão e áudio. diff --git a/site/pt-br/lite/guide/signatures.ipynb b/site/pt-br/lite/guide/signatures.ipynb new file mode 100644 index 0000000000..f2ec01f81e --- /dev/null +++ b/site/pt-br/lite/guide/signatures.ipynb @@ -0,0 +1,491 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "g_nWetWWd_ns", + "metadata": { + "id": "g_nWetWWd_ns" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2pHVBk_seED1", + "metadata": { + "cellView": "form", + "id": "2pHVBk_seED1" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "id": "M7vSdG6sAIQn", + "metadata": { + "id": "M7vSdG6sAIQn" + }, + "source": [ + "# Assinaturas no TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "id": "fwc5GKHBASdc", + "metadata": { + "id": "fwc5GKHBASdc" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "9ee074e4", + "metadata": { + "id": "9ee074e4" + }, + "source": [ + "O TensorFlow Lite tem suporte à conversão das especificações de entrada/saída de modelos do TensorFlow para o TensorFlow Lite. As especificações de entrada/saída são chamadas de \"assinaturas\", que podem ser especificadas ao compilar um SavedModel ou ao criar funções concretas.\n", + "\n", + "As assinaturas no TensorFlow Lite contam com os seguintes recursos:\n", + "\n", + "- Especificam entradas e saídas do modelo convertido para TensorFlow Lite, respeitando as assinaturas do modelo do TensorFlow.\n", + "- Permitem que um único modelo do TensorFlow Lite tenha suporte a diversos pontos de entrada.\n", + "\n", + "A assinatura é composta por três componentes:\n", + "\n", + "- Inputs (entradas): faz o mapeamento de entradas do nome de entradas na assinatura para um tensor de entrada.\n", + "- Outputs (saídas): faz o mapeamento de saídas do nome de saída na assinatura para um tensor de saída.\n", + "- Signature Key (chave de assinatura): nome que identifica um ponto de entrada do grafo.\n" + ] + }, + { + "cell_type": "markdown", + "id": "UaWdLA3fQDK2", + "metadata": { + "id": "UaWdLA3fQDK2" + }, + "source": [ + "## Configuração" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9j4MGqyKQEo4", + "metadata": { + "id": "9j4MGqyKQEo4" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf" + ] + }, + { + "cell_type": "markdown", + "id": "FN2N6hPEP-Ay", + "metadata": { + "id": "FN2N6hPEP-Ay" + }, + "source": [ + "## Modelo de exemplo\n", + "\n", + "Vamos supor que tenhamos duas tarefas, como codificação e decodificação, em um modelo do TensorFlow:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8577c80", + "metadata": { + "id": "d8577c80" + }, + "outputs": [ + + ], + "source": [ + "class Model(tf.Module):\n", + "\n", + " @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.float32)])\n", + " def encode(self, x):\n", + " result = tf.strings.as_string(x)\n", + " return {\n", + " \"encoded_result\": result\n", + " }\n", + "\n", + " @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.string)])\n", + " def decode(self, x):\n", + " result = tf.strings.to_number(x)\n", + " return {\n", + " \"decoded_result\": result\n", + " }" + ] + }, + { + "cell_type": "markdown", + "id": "9c814c6e", + "metadata": { + "id": "9c814c6e" + }, + "source": [ + "Pela perspectiva de assinatura, o modelo do TensorFlow acima pode ser resumido da seguinte forma:\n", + "\n", + "- Assinatura\n", + "\n", + " - Chave: encode\n", + " - Entradas: {\"x\"}\n", + " - Saída: {\"encoded_result\"}\n", + "\n", + "- Assinatura\n", + "\n", + " - Chave: decode\n", + " - Entradas: {\"x\"}\n", + " - Saída: {\"decoded_result\"}" + ] + }, + { + "cell_type": "markdown", + "id": "c4099f20", + "metadata": { + "id": "c4099f20" + }, + "source": [ + "## Conversão de modelos com assinaturas\n", + "\n", + "As APIs de conversão do TensorFlow Lite levam as informações de assinatura acima ao modelo convertido para TensorFlow Lite.\n", + "\n", + "Essa funcionalidade de conversão está disponível em todas as APIs de conversão a partir do TensorFlow versão 2.7.0. Confira os exemplos de uso abaixo.\n" + ] + }, + { + "cell_type": "markdown", + "id": "Qv0WwFQkQgnO", + "metadata": { + "id": "Qv0WwFQkQgnO" + }, + "source": [ + "### Usando um SavedModel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96c8fc79", + "metadata": { + "id": "96c8fc79" + }, + "outputs": [ + + ], + "source": [ + "model = Model()\n", + "\n", + "# Save the model\n", + "SAVED_MODEL_PATH = 'content/saved_models/coding'\n", + "\n", + "tf.saved_model.save(\n", + " model, SAVED_MODEL_PATH,\n", + " signatures={\n", + " 'encode': model.encode.get_concrete_function(),\n", + " 'decode': model.decode.get_concrete_function()\n", + " })\n", + "\n", + "# Convert the saved model using TFLiteConverter\n", + "converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_PATH)\n", + "converter.target_spec.supported_ops = [\n", + " tf.lite.OpsSet.TFLITE_BUILTINS, # enable TensorFlow Lite ops.\n", + " tf.lite.OpsSet.SELECT_TF_OPS # enable TensorFlow ops.\n", + "]\n", + "tflite_model = converter.convert()\n", + "\n", + "# Print the signatures from the converted model\n", + "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + "signatures = interpreter.get_signature_list()\n", + "print(signatures)" + ] + }, + { + "cell_type": "markdown", + "id": "5baa9f17", + "metadata": { + "id": "5baa9f17" + }, + "source": [ + "### Usando um modelo do Keras" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71f29229", + "metadata": { + "id": "71f29229" + }, + "outputs": [ + + ], + "source": [ + "# Generate a Keras model.\n", + "keras_model = tf.keras.Sequential(\n", + " [\n", + " tf.keras.layers.Dense(2, input_dim=4, activation='relu', name='x'),\n", + " tf.keras.layers.Dense(1, activation='relu', name='output'),\n", + " ]\n", + ")\n", + "\n", + "# Convert the keras model using TFLiteConverter.\n", + "# Keras model converter API uses the default signature automatically.\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(keras_model)\n", + "tflite_model = converter.convert()\n", + "\n", + "# Print the signatures from the converted model\n", + "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + "\n", + "signatures = interpreter.get_signature_list()\n", + "print(signatures)" + ] + }, + { + "cell_type": "markdown", + "id": "e4d30f85", + "metadata": { + "id": "e4d30f85" + }, + "source": [ + "### De funções concretas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9e8a742", + "metadata": { + "id": "c9e8a742" + }, + "outputs": [ + + ], + "source": [ + "model = Model()\n", + "\n", + "# Convert the concrete functions using TFLiteConverter\n", + "converter = tf.lite.TFLiteConverter.from_concrete_functions(\n", + " [model.encode.get_concrete_function(),\n", + " model.decode.get_concrete_function()], model)\n", + "converter.target_spec.supported_ops = [\n", + " tf.lite.OpsSet.TFLITE_BUILTINS, # enable TensorFlow Lite ops.\n", + " tf.lite.OpsSet.SELECT_TF_OPS # enable TensorFlow ops.\n", + "]\n", + "tflite_model = converter.convert()\n", + "\n", + "# Print the signatures from the converted model\n", + "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + "signatures = interpreter.get_signature_list()\n", + "print(signatures)" + ] + }, + { + "cell_type": "markdown", + "id": "b5e85934", + "metadata": { + "id": "b5e85934" + }, + "source": [ + "## Execução de assinaturas\n", + "\n", + "As APIs de inferência do TensorFlow têm suporte a execuções baseadas em assinatura:\n", + "\n", + "- Acesso aos tensores de entrada/saída por meio dos nomes das entradas e saídas, especificadas pela assinatura.\n", + "- Execução de cada ponto de entrada do grafo separadamente, identificado pela chave de assinatura.\n", + "- Suporte ao procedimento de inicialização do SavedModel.\n", + "\n", + "As vinculações das linguagens Java, C++ e Python já estão disponíveis. Confira os exemplos nas seções abaixo.\n" + ] + }, + { + "cell_type": "markdown", + "id": "ZRBMFciMQmiB", + "metadata": { + "id": "ZRBMFciMQmiB" + }, + "source": [ + "### Java" + ] + }, + { + "cell_type": "markdown", + "id": "04c5a4fc", + "metadata": { + "id": "04c5a4fc" + }, + "source": [ + "```\n", + "try (Interpreter interpreter = new Interpreter(file_of_tensorflowlite_model)) {\n", + " // Run encoding signature.\n", + " Map<String, Object> inputs = new HashMap<>();\n", + " inputs.put(\"x\", input);\n", + " Map<String, Object> outputs = new HashMap<>();\n", + " outputs.put(\"encoded_result\", encoded_result);\n", + " interpreter.runSignature(inputs, outputs, \"encode\");\n", + "\n", + " // Run decoding signature.\n", + " Map<String, Object> inputs = new HashMap<>();\n", + " inputs.put(\"x\", encoded_result);\n", + " Map<String, Object> outputs = new HashMap<>();\n", + " outputs.put(\"decoded_result\", decoded_result);\n", + " interpreter.runSignature(inputs, outputs, \"decode\");\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "5ba86c64", + "metadata": { + "id": "5ba86c64" + }, + "source": [ + "### C++" + ] + }, + { + "cell_type": "markdown", + "id": "397ad6fd", + "metadata": { + "id": "397ad6fd" + }, + "source": [ + "```\n", + "SignatureRunner* encode_runner =\n", + " interpreter->GetSignatureRunner(\"encode\");\n", + "encode_runner->ResizeInputTensor(\"x\", {100});\n", + "encode_runner->AllocateTensors();\n", + "\n", + "TfLiteTensor* input_tensor = encode_runner->input_tensor(\"x\");\n", + "float* input = GetTensorData(input_tensor);\n", + "// Fill `input`.\n", + "\n", + "encode_runner->Invoke();\n", + "\n", + "const TfLiteTensor* output_tensor = encode_runner->output_tensor(\n", + " \"encoded_result\");\n", + "float* output = GetTensorData(output_tensor);\n", + "// Access `output`.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "0f4c6ad4", + "metadata": { + "id": "0f4c6ad4" + }, + "source": [ + "### Python" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab7b1963", + "metadata": { + "id": "ab7b1963" + }, + "outputs": [ + + ], + "source": [ + "# Load the TFLite model in TFLite Interpreter\n", + "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + "\n", + "# Print the signatures from the converted model\n", + "signatures = interpreter.get_signature_list()\n", + "print('Signature:', signatures)\n", + "\n", + "# encode and decode are callable with input as arguments.\n", + "encode = interpreter.get_signature_runner('encode')\n", + "decode = interpreter.get_signature_runner('decode')\n", + "\n", + "# 'encoded' and 'decoded' are dictionaries with all outputs from the inference.\n", + "input = tf.constant([1, 2, 3], dtype=tf.float32)\n", + "print('Input:', input)\n", + "encoded = encode(x=input)\n", + "print('Encoded result:', encoded)\n", + "decoded = decode(x=encoded['encoded_result'])\n", + "print('Decoded result:', decoded)" + ] + }, + { + "cell_type": "markdown", + "id": "81b42e5b", + "metadata": { + "id": "81b42e5b" + }, + "source": [ + "## Limitações conhecidas\n", + "\n", + "- Como o interpretador do TF Lite não garante a segurança de threads, os executadores de assinaturas do mesmo interpretador não serão executados simultaneamente.\n", + "- Ainda não há suporte ao C/iOS/Swift.\n" + ] + }, + { + "cell_type": "markdown", + "id": "3032Iof6QqmJ", + "metadata": { + "id": "3032Iof6QqmJ" + }, + "source": [ + "## Atualizações\n", + "\n", + "- Versão 2.7\n", + " - Recurso de múltiplas assinaturas implementado.\n", + " - Todas as APIs de conversão a partir da versão 2 geram modelos do TensorFlow Lite com assinaturas.\n", + "- Versão 2.5\n", + " - O recurso de assinaturas está disponível por meio da API de conversão `from_saved_model`." + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "signatures.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/inference_with_metadata/codegen.md b/site/pt-br/lite/inference_with_metadata/codegen.md new file mode 100644 index 0000000000..b803f1b4f6 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/codegen.md @@ -0,0 +1,214 @@ +# Gere interfaces de modelos usando metadados + +Utilizando os [metadados do TensorFlow Lite](../models/convert/metadata), os desenvolvedores podem gerar código encapsulador para permitir a integração com o Android. Para a maioria dos desenvolvedores, a interface gráfica do [Android Studio ML Model Binding](#mlbinding) (vinculação de modelos de ML do Android Studio) é a mais fácil de usar. Se você deseja mais personalização ou estiver usando uma ferramenta de linha de comando, o [TensorFlow Lite Codegen](#codegen) também está disponível. + +## Use o Android Studio ML Model Binding {:#mlbinding} + +Para modelos do TensorFlow Lite aprimorados com [metadados](../models/convert/metadata.md), os desenvolvedores podem usar o Android Studio ML Model Binding para definir automaticamente as configurações do projeto e gerar classes encapsuladoras com base nos metadados do modelo. O código encapsulador remove a necessidade de interagir diretamente com o `ByteBuffer`. Em vez disso, os desenvolvedores podem interagir com objetos tipados, como `Bitmap` e `Rect`. + +Observação: é necessário ter o [Android Studio 4.1](https://developer.android.com/studio) ou superiores. + +### Importe um modelo do TensorFlow Lite no Android Studio + +1. Clique com o botão direito no módulo onde você quer usar o modelo do TF Lite ou clique em `File` > `New` > `Other` > `TensorFlow Lite Model` (Arquivo > Novo > Outro > Modelo do TensorFlow Lite). ![Right-click menus to access the TensorFlow Lite import functionality](../images/android/right_click_menu.png) + +2. Selecione o local do seu arquivo do TF Lite. Observe que a ferramenta configura a dependência do modelo com o ML Model Binding, e todas as dependências são incluídas automaticamente no arquivo `build.gradle` do seu módulo para Android. + + Opcional: marque a segunda caixa de seleção para importar a GPU do TensorFlow se você quiser usar a aceleração de GPU. ![Import dialog for TFLite model](../images/android/import_dialog.png) + +3. Clique em `Finish` (Finalizar). + +4. A tela abaixo será exibida após a importação ser concluída com êxito. Para começar a usar o modelo, selecione Kotlin ou Java, e copie e cole o código abaixo da seção `Sample Code` (Código de exemplo). Para voltar a essa tela, basta clicar duas vezes no modelo do TF Lite sob o diretório `ml` no Android Studio. ![Model details page in Android Studio](../images/android/model_details.png) + +### Como acelerar a inferência do modelo {:#acceleration} + +O ML Model Binding conta com uma maneira de os desenvolvedores acelerarem o código por meio do uso de delegados e do número de threads. + +Observação: o interpretador do TensorFlow Lite precisa ser criado no mesmo thread em que é executado. Caso contrário, pode ocorrer o seguinte erro: TfLiteGpuDelegate Invoke: GpuDelegate must run on the same thread where it was initialized (GpuDelegate precisa ser executado no mesmo thread em que foi inicializado). + +Etapa 1 – Verifique se o arquivo `build.gradle` do modelo contém a seguinte dependência: + +```java + dependencies { + ... + // TFLite GPU delegate 2.3.0 or above is required. + implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0' + } +``` + +Etapa 2 – Detecte se a GPU sendo executada no dispositivo é compatível com o delegado GPU do TensorFlow. Caso não seja, execute o modelo usando diversos threads de CPU: + +
+ +
+

Kotlin

+

+
+    import org.tensorflow.lite.gpu.CompatibilityList
+    import org.tensorflow.lite.gpu.GpuDelegate
+
+    val compatList = CompatibilityList()
+
+    val options = if(compatList.isDelegateSupportedOnThisDevice) {
+        // if the device has a supported GPU, add the GPU delegate
+        Model.Options.Builder().setDevice(Model.Device.GPU).build()
+    } else {
+        // if the GPU is not supported, run on 4 threads
+        Model.Options.Builder().setNumThreads(4).build()
+    }
+
+    // Initialize the model as usual feeding in the options object
+    val myModel = MyModel.newInstance(context, options)
+
+    // Run inference per sample code
+      
+
+
+

Java

+

+
+    import org.tensorflow.lite.support.model.Model
+    import org.tensorflow.lite.gpu.CompatibilityList;
+    import org.tensorflow.lite.gpu.GpuDelegate;
+
+    // Initialize interpreter with GPU delegate
+    Model.Options options;
+    CompatibilityList compatList = CompatibilityList();
+
+    if(compatList.isDelegateSupportedOnThisDevice()){
+        // if the device has a supported GPU, add the GPU delegate
+        options = Model.Options.Builder().setDevice(Model.Device.GPU).build();
+    } else {
+        // if the GPU is not supported, run on 4 threads
+        options = Model.Options.Builder().setNumThreads(4).build();
+    }
+
+    MyModel myModel = new MyModel.newInstance(context, options);
+
+    // Run inference per sample code
+      
+
+
+
+ +## Gere interfaces de modelos com o gerador de código do TensorFlow Lite {:#codegen} + +Observação: o gerador de código do encapsulador para o TensorFlow Lite só tem suporte ao Android no momento. + +Para o modelo do TensorFlow Lite aprimorado com [metadados](../models/convert/metadata.md), os desenvolvedores podem usar o gerador de código do encapsulador Android para o TensorFlow Lite para criar o código do encapsulador específico para a plataforma. O código do encapsulador remove a necessidade de interagir diretamente com o `ByteBuffer`. Em vez disso, os desenvolvedores podem interagir com o modelo do TensorFlow Lite usando objetos tipados, como `Bitmap` e `Rect`. + +O nível de utilidade do gerador de código depende do nível de completude da entrada de metadados do modelo do TensorFlow Lite. Confira a seção `` abaixo dos campos relevantes em [metadata_schema.fbs](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/metadata_schema.fbs) para ver como a ferramenta codegen processa cada campo. + +### Gere código encapsulador + +Você precisará instalar a seguinte ferramenta em seu terminal: + +```sh +pip install tflite-support +``` + +Após a conclusão, o gerador de código poderá ser utilizado por meio da seguinte sintaxe: + +```sh +tflite_codegen --model=./model_with_metadata/mobilenet_v1_0.75_160_quantized.tflite \ + --package_name=org.tensorflow.lite.classify \ + --model_class_name=MyClassifierModel \ + --destination=./classify_wrapper +``` + +O código resultante ficará localizado no diretório de destino. Se você estiver usando o [Google Colab](https://colab.research.google.com/) ou outro ambiente remoto, pode ser mais fácil colocar o resultado em um arquivo ZIP e baixá-lo para seu projeto do Android Studio: + +```python +# Zip up the generated code +!zip -r classify_wrapper.zip classify_wrapper/ + +# Download the archive +from google.colab import files +files.download('classify_wrapper.zip') +``` + +### Uso do código gerado + +#### Etapa 1 – Importe o código gerado + +Se necessário, descompacte o código gerado em uma estrutura de diretórios. Pressupõe-se que a raiz do código gerado seja `SRC_ROOT`. + +Abra o projeto do Android Studio no qual deseja usar o modelo do TensorFlow Lite e importe o módulo gerado em: File -> New -> Import Module (Arquivo -> Novo -> Importar módulo) e selecione `SRC_ROOT` + +Usando o exemplo acima, o diretório e o módulo importado seriam chamados de `classify_wrapper`. + +#### Etapa 2 – Atualize o arquivo `build.gradle` do aplicativo + +No módulo do aplicativo que consumirá o módulo da biblioteca gerado: + +Abaixo da seção "android", adicione o seguinte: + +```build +aaptOptions { + noCompress "tflite" +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +Abaixo da seção "dependencies" (dependências), adicione o seguinte: + +```build +implementation project(":classify_wrapper") +``` + +#### Etapa 3 – Use o modelo + +```java +// 1. Initialize the model +MyClassifierModel myImageClassifier = null; + +try { + myImageClassifier = new MyClassifierModel(this); +} catch (IOException io){ + // Error reading the model +} + +if(null != myImageClassifier) { + + // 2. Set the input with a Bitmap called inputBitmap + MyClassifierModel.Inputs inputs = myImageClassifier.createInputs(); + inputs.loadImage(inputBitmap)); + + // 3. Run the model + MyClassifierModel.Outputs outputs = myImageClassifier.run(inputs); + + // 4. Retrieve the result + Map labeledProbability = outputs.getProbability(); +} +``` + +### Como acelerar a inferência do modelo + +O código gerado proporciona ao desenvolvedores uma forma de acelerar o código por meio do uso de [delegados](../performance/delegates.md) e do número de threads, que podem ser definidos ao inicializar o objeto do modelo, que aceita três parâmetros: + +- **`Context`**: contexto de Atividade ou Serviço do Android. +- (Opcional) **`Device`**: delegado de aceleração do TF Lite, como GPUDelegate ou NNAPIDelegate, por exemplo. +- (Opcional) **`numThreads`**: número de threads usados para executar o modelo. O padrão é 1. + +Por exemplo: para usar um delegado NNAPI e até três threads, você pode inicializar o modelo da seguinte forma: + +```java +try { + myImageClassifier = new MyClassifierModel(this, Model.Device.NNAPI, 3); +} catch (IOException io){ + // Error reading the model +} +``` + +### Solução de problemas + +Se for exibido o erro "java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed" (Este arquivo não pode ser aberto como descritor de arquivo; provavelmente está compactado), insira as linhas abaixo sob a seção "android" do módulo do aplicativo que usará o módulo da biblioteca: + +```build +aaptOptions { + noCompress "tflite" +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. diff --git a/site/pt-br/lite/inference_with_metadata/lite_support.md b/site/pt-br/lite/inference_with_metadata/lite_support.md new file mode 100644 index 0000000000..0236ab0cc1 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/lite_support.md @@ -0,0 +1,238 @@ +# Processe dados de entrada e gere dados de saída com a TensorFlow Lite Support Library + +Observação: no momento, a TensorFlow Lite Support Library só oferece suporte ao Android. + +A maioria dos desenvolvedores de aplicativos para dispositivos móveis interagem com objetos tipados, como bitmaps, ou primitivos, como inteiros. Entretanto, a API do interpretador do TensorFlow Lite que executa o modelo de aprendizado de máquina no dispositivo usa tensores no formato ByteBuffer, que podem ser difíceis de depurar e manipular. A [TensorFlow Lite Android Support Library](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/java) (biblioteca de suporte para Android do TensorFlow Lite) foi criada para ajudar a processar as entradas e saídas de modelos do TensorFlow Lite e para facilitar o uso do interpretador do TF Lite. + +## Como começar + +### Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import tflite dependencies + implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT' + // The GPU delegate library is optional. Depend on it as needed. + implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly-SNAPSHOT' + implementation 'org.tensorflow:tensorflow-lite-support:0.0.0-nightly-SNAPSHOT' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +Confira o [AAR da TensorFlow Lite Support Library hospedado no MavenCentral](https://search.maven.org/artifact/org.tensorflow/tensorflow-lite-support) para ver as diferentes versões da biblioteca de suporte. + +### Manipulação e conversão básicas de imagem + +A TensorFlow Lite Support Library conta com um conjunto de métodos básicos de manipulação de imagem, como recorte e redimensionamento. Para usá-lo, crie um `ImagePreprocessor` e adicione as operações necessárias. Para converter a imagem para o formato de tensor exigido pelo interpretador do TensorFlow Lite, crie uma `TensorImage` a ser usada como entrada: + +```java +import org.tensorflow.lite.DataType; +import org.tensorflow.lite.support.image.ImageProcessor; +import org.tensorflow.lite.support.image.TensorImage; +import org.tensorflow.lite.support.image.ops.ResizeOp; + +// Initialization code +// Create an ImageProcessor with all ops required. For more ops, please +// refer to the ImageProcessor Architecture section in this README. +ImageProcessor imageProcessor = + new ImageProcessor.Builder() + .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR)) + .build(); + +// Create a TensorImage object. This creates the tensor of the corresponding +// tensor type (uint8 in this case) that the TensorFlow Lite interpreter needs. +TensorImage tensorImage = new TensorImage(DataType.UINT8); + +// Analysis code for every frame +// Preprocess the image +tensorImage.load(bitmap); +tensorImage = imageProcessor.process(tensorImage); +``` + +O `DataType` de um tensor, bem como outras informações do modelo, pode ser lido por meio da [biblioteca de extração de metadados](../models/convert/metadata.md#read-the-metadata-from-models). + +### Processamento básico de dados de áudio + +A TensorFlow Lite Support Library também define uma classe `TensorAudio` que encapsula alguns métodos básicos de processamento de dados de áudio. Ela é usada principalmente junto com [AudioRecord](https://developer.android.com/reference/android/media/AudioRecord) e captura amostras de áudio em um buffer circular. + +```java +import android.media.AudioRecord; +import org.tensorflow.lite.support.audio.TensorAudio; + +// Create an `AudioRecord` instance. +AudioRecord record = AudioRecord(...) + +// Create a `TensorAudio` object from Android AudioFormat. +TensorAudio tensorAudio = new TensorAudio(record.getFormat(), size) + +// Load all audio samples available in the AudioRecord without blocking. +tensorAudio.load(record) + +// Get the `TensorBuffer` for inference. +TensorBuffer buffer = tensorAudio.getTensorBuffer() +``` + +### Crie objetos de saída e execute o modelo + +Antes de executar o modelo, precisamos criar os objetos container que armazenarão o resultado: + +```java +import org.tensorflow.lite.DataType; +import org.tensorflow.lite.support.tensorbuffer.TensorBuffer; + +// Create a container for the result and specify that this is a quantized model. +// Hence, the 'DataType' is defined as UINT8 (8-bit unsigned integer) +TensorBuffer probabilityBuffer = + TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8); +``` + +Carregue o modelo e execute a inferência: + +```java +import java.nio.MappedByteBuffer; +import org.tensorflow.lite.InterpreterFactory; +import org.tensorflow.lite.InterpreterApi; + +// Initialise the model +try{ + MappedByteBuffer tfliteModel + = FileUtil.loadMappedFile(activity, + "mobilenet_v1_1.0_224_quant.tflite"); + InterpreterApi tflite = new InterpreterFactory().create( + tfliteModel, new InterpreterApi.Options()); +} catch (IOException e){ + Log.e("tfliteSupport", "Error reading model", e); +} + +// Running inference +if(null != tflite) { + tflite.run(tImage.getBuffer(), probabilityBuffer.getBuffer()); +} +``` + +### Como acessar o resultado + +Os desenvolvedores podem acessar a saída diretamente por meio de `probabilityBuffer.getFloatArray()`. Se o modelo gerar uma saída quantizada, lembre-se de converter o resultado. Para o modelo MobileNet quantizado, o desenvolvedor precisa dividir cada valor da saída por 255 para obter a probabilidade, que vai de 0 (menos provável) a 1 (mais provável) para cada categoria. + +### Opcional: mapeamento dos resultados em rótulos + +Opcionalmente, os desenvolvedores podem mapear os resultados em rótulos. Primeiro, copie o arquivo de texto que contém os rótulos para o diretório de ativos do módulo. Em seguida, carregue o arquivo de rótulos por meio do seguinte código: + +```java +import org.tensorflow.lite.support.common.FileUtil; + +final String ASSOCIATED_AXIS_LABELS = "labels.txt"; +List associatedAxisLabels = null; + +try { + associatedAxisLabels = FileUtil.loadLabels(this, ASSOCIATED_AXIS_LABELS); +} catch (IOException e) { + Log.e("tfliteSupport", "Error reading label file", e); +} +``` + +O seguinte trecho de código demonstra como associar as probabilidades aos rótulos de categoria: + +```java +import java.util.Map; +import org.tensorflow.lite.support.common.TensorProcessor; +import org.tensorflow.lite.support.common.ops.NormalizeOp; +import org.tensorflow.lite.support.label.TensorLabel; + +// Post-processor which dequantize the result +TensorProcessor probabilityProcessor = + new TensorProcessor.Builder().add(new NormalizeOp(0, 255)).build(); + +if (null != associatedAxisLabels) { + // Map of labels and their corresponding probability + TensorLabel labels = new TensorLabel(associatedAxisLabels, + probabilityProcessor.process(probabilityBuffer)); + + // Create a map to access the result based on label + Map floatMap = labels.getMapWithFloatValue(); +} +``` + +## Casos de uso possíveis no momento + +A versão atual da TensorFlow Lite Support Library abrange os seguintes casos de uso: + +- Tipos de dado comuns (float, uint8, imagens, áudios e array desses objetos) como entradas e saídas de modelos tflite. +- Operações básicas com imagens (recortar, redimensionar e girar). +- Normalização e quantização. +- Utilitários de arquivos + +Versões futuras melhorarão o suporte a aplicativos relacionados a texto. + +## Arquitetura de ImageProcessor + +A concepção do `ImageProcessor` possibilitou que as operações de manipulação de imagens sejam definidas de antemão e otimizadas durante o processo de criação. No momento, o `ImageProcessor` oferece suporte a três operações básicas de pré-processamento, conforme descrito nos três comentários do trecho de código abaixo: + +```java +import org.tensorflow.lite.support.common.ops.NormalizeOp; +import org.tensorflow.lite.support.common.ops.QuantizeOp; +import org.tensorflow.lite.support.image.ops.ResizeOp; +import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp; +import org.tensorflow.lite.support.image.ops.Rot90Op; + +int width = bitmap.getWidth(); +int height = bitmap.getHeight(); + +int size = height > width ? width : height; + +ImageProcessor imageProcessor = + new ImageProcessor.Builder() + // Center crop the image to the largest square possible + .add(new ResizeWithCropOrPadOp(size, size)) + // Resize using Bilinear or Nearest neighbour + .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR)); + // Rotation counter-clockwise in 90 degree increments + .add(new Rot90Op(rotateDegrees / 90)) + .add(new NormalizeOp(127.5, 127.5)) + .add(new QuantizeOp(128.0, 1/128.0)) + .build(); +``` + +Confira mais detalhes sobre normalização e quantização [aqui](../models/convert/metadata.md#normalization-and-quantization-parameters). + +O grande objetivo da biblioteca de suporte é oferecer suporte a todas as transformações de [`tf.image`](https://www.tensorflow.org/api_docs/python/tf/image). Dessa forma, a transformação será a mesma que do TensorFlow, e a implementação será independente do sistema operacional. + +Os desenvolvedores também podem criar processadores personalizados. Nesses casos, é importante se alinhar ao processo de treinamento, ou seja, o mesmo pré-processamento deve ser aplicado tanto ao treinamento quanto à inferência para aumentar a capacidade de reprodução. + +## Quantização + +Ao inicializar objetos de entrada ou saída, como `TensorImage` ou `TensorBuffer`, você precisa especificar seus tipos como `DataType.UINT8` ou `DataType.FLOAT32`. + +```java +TensorImage tensorImage = new TensorImage(DataType.UINT8); +TensorBuffer probabilityBuffer = + TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8); +``` + +O `TensorProcessor` pode ser usado para quantizar tensores de entrada ou fazer a dequantização de tensores de saída. Por exemplo: ao processar uma saída `TensorBuffer` quantizada, o desenvolvedor pode usar `DequantizeOp` para fazer a dequantização do resultado para uma probabilidade de ponto flutuante entre 0 e 1: + +```java +import org.tensorflow.lite.support.common.TensorProcessor; + +// Post-processor which dequantize the result +TensorProcessor probabilityProcessor = + new TensorProcessor.Builder().add(new DequantizeOp(0, 1/255.0)).build(); +TensorBuffer dequantizedBuffer = probabilityProcessor.process(probabilityBuffer); +``` + +Os parâmetros de quantização de um tensor podem ser lidos por meio da [biblioteca de extração de metadados](../models/convert/metadata.md#read-the-metadata-from-models). diff --git a/site/pt-br/lite/inference_with_metadata/overview.md b/site/pt-br/lite/inference_with_metadata/overview.md new file mode 100644 index 0000000000..166017a887 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/overview.md @@ -0,0 +1,31 @@ +# Inferência com o TensorFlow Lite usando metadados + +Fazer a inferência em [modelos com metadados](../models/convert/metadata.md) pode ser fácil, bastando algumas linhas de código. Os metadados do TensorFlow Lite contêm uma boa descrição do que o modelo faz e de como usá-lo. Com eles, os geradores de código podem gerar automaticamente o código de inferência para você, como ao usar o [recurso Android Studio ML Binding](codegen.md#mlbinding) ou o [gerador de código do TensorFlow Lite para Android](codegen.md#codegen). Além disso, podem ser usados para configurar seu pipeline de inferência personalizado. + +## Ferramentas e bibliotecas + +O TensorFlow Lite conta com diversas ferramentas e bibliotecas para atender a diferentes requisitos de implantação: + +### Gere a interface do modelo com os geradores de código para Android + +Existem duas formas de gerar automaticamente o código encapsulador para Android necessário para um modelo do TensorFlow Lite com metadados: + +1. [Android Studio ML Model Binding](codegen.md#mlbinding) é uma ferramenta disponível no Android Studio para importar um modelo do TensorFlow Lite por meio de uma interface gráfica. O Android Studio vai definir automaticamente as configurações do projeto e gerar classes encapsuladoras com base nos metadados do modelo. + +2. O [gerador de código do TensorFlow Lite](codegen.md#codegen) é um arquivo executável que gera automaticamente a interface do modelo com base nos metadados. No momento, oferece suporte apenas ao Android em Java. O código encapsulador remove a necessidade de interagir diretamente com o `ByteBuffer`. Em vez disso, os desenvolvedores podem interagir com o modelo do TensorFlow Lite com objetos tipados, como `Bitmap` e `Rect`. Além disso, os usuários do Android Studio também têm acesso ao recurso codegen por meio do [Android Studio ML Binding](codegen.md#mlbinding). + +### Use as APIs integradas da TensorFlow Lite Task Library + +A [TensorFlow Lite Task Library](task_library/overview.md) fornece interfaces de modelo prontas para uso e otimizadas para tarefas de aprendizado de máquina populares, como classificação de imagens, pergunta e resposta, etc. As interfaces de modelo são criadas especialmente para cada tarefa alcançar o melhor desempenho e usabilidade. A biblioteca de tarefas funciona em várias plataformas e é compatível com o Java, C++ e Swift. + +### Crie pipelines de inferência personalizados com a TensorFlow Lite Support Library + +A [TensorFlow Lite Support Library](lite_support.md) é uma biblioteca interplataforma que ajuda a personalizar a interface do modelo e a criar pipelines de inferência. Ela contém diversos métodos utilitários e estruturas de dados para fazer pré e pós-processamento, além de conversão de dados. Além disso, tem o mesmo comportamento de módulos do TensorFlow, como TF.Image e TF.Text, garantindo a consistência do treinamento à inferência. + +## Confira modelos pré-treinados com metadados + +Navegue pelos [modelos hospedados do TensorFlow Lite](https://www.tensorflow.org/lite/guide/hosted_models) e pelo [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite) para baixar modelos pré-treinados com metadados para tarefas de visão e texto. Além disso, veja diferentes opções de [visualização dos metadados](../models/convert/metadata.md#visualize-the-metadata). + +## Repositório da TensorFlow Lite Support no GitHub + +Acesse o [repositório da TensorFlow Lite Support no GitHub](https://github.com/tensorflow/tflite-support) para ver mais exemplos e código-fonte. Para fornecer feedback, crie um [novo issue no GitHub](https://github.com/tensorflow/tflite-support/issues/new). diff --git a/site/pt-br/lite/inference_with_metadata/task_library/audio_classifier.md b/site/pt-br/lite/inference_with_metadata/task_library/audio_classifier.md new file mode 100644 index 0000000000..7639ae0f9e --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/audio_classifier.md @@ -0,0 +1,281 @@ +# Integração de classificadores de áudio + +A classificação de áudio é um caso de uso comum de aprendizado de máquina para classificar tipos de sons. Por exemplo: é possível identificar espécies de pássaro por meio de seus cantos. + +A API `AudioClassifier` da biblioteca Task pode ser usada para implantar classificadores de áudio personalizados ou pré-treinados em seu aplicativo para dispositivos móveis. + +## Principais recursos da API AudioClassifier + +- Pré-processamento do áudio de entrada, como a conversão de codificação PCM de 16 bits para codificação PCM de ponto flutuante e a manipulação do buffer circular de áudio. + +- Idioma do mapa de rótulos. + +- Suporte à classificação multi-head. + +- Suporte à classificação com um e vários rótulos. + +- Limite de pontuação para filtrar resultados. + +- Resultados de classificação top-k. + +- Lista de permissão e proibição de rótulos. + +## Modelos de classificador de áudio com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `AudioClassifier`. + +- Modelos criados pelo [Model Maker do TensorFlow Lite para classificação de áudio](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier). + +- [Modelos pré-treinados de classificação de eventos de áudio no TensorFlow Hub](https://tfhub.dev/google/lite-model/yamnet/classification/tflite/1). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +Confira o [aplicativo de referência para classificação de áudio](https://github.com/tensorflow/examples/tree/master/lite/examples/audio_classification/android) para ver um exemplo de como usar o `AudioClassifier` em um aplicativo para Android. + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify that the tflite file should not be compressed when building the APK package. + aaptOptions { + noCompress "tflite" + } +} + +dependencies { + // Other dependencies + + // Import the Audio Task Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-audio:0.4.4' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.4' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Use o modelo + +```java +// Initialization +AudioClassifierOptions options = + AudioClassifierOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setMaxResults(1) + .build(); +AudioClassifier classifier = + AudioClassifier.createFromFileAndOptions(context, modelFile, options); + +// Start recording +AudioRecord record = classifier.createAudioRecord(); +record.startRecording(); + +// Load latest audio samples +TensorAudio audioTensor = classifier.createInputTensorAudio(); +audioTensor.load(record); + +// Run inference +List results = audioClassifier.classify(audioTensor); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/audio/classifier/AudioClassifier.java) para ver mais opções de configuração do `AudioClassifier`. + +## Execute a inferência no iOS + +### Etapa 1 – Instale as dependências + +A biblioteca Task oferece suporte à instalação usando o CocoaPods, que precisa estar instalado em seu sistema. Confira as instruções no [guia de instalação do CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +Confira os detalhes de como adicionar pods a um projeto do Xcode no [guia do CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html). + +Adicione o pod `TensorFlowLiteTaskAudio` ao Podfile. + +``` +target 'MyAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskAudio' +end +``` + +Confirme se o modelo `.tflite` que você usará para inferência está presente no pacote do aplicativo. + +### Etapa 2 – Use o modelo + +#### Swift + +```swift +// Imports +import TensorFlowLiteTaskAudio +import AVFoundation + +// Initialization +guard let modelPath = Bundle.main.path(forResource: "sound_classification", + ofType: "tflite") else { return } + +let options = AudioClassifierOptions(modelPath: modelPath) + +// Configure any additional options: +// options.classificationOptions.maxResults = 3 + +let classifier = try AudioClassifier.classifier(options: options) + +// Create Audio Tensor to hold the input audio samples which are to be classified. +// Created Audio Tensor has audio format matching the requirements of the audio classifier. +// For more details, please see: +// https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/audio/core/audio_tensor/sources/TFLAudioTensor.h +let audioTensor = classifier.createInputAudioTensor() + +// Create Audio Record to record the incoming audio samples from the on-device microphone. +// Created Audio Record has audio format matching the requirements of the audio classifier. +// For more details, please see: +https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/audio/core/audio_record/sources/TFLAudioRecord.h +let audioRecord = try classifier.createAudioRecord() + +// Request record permissions from AVAudioSession before invoking audioRecord.startRecording(). +AVAudioSession.sharedInstance().requestRecordPermission { granted in + if granted { + DispatchQueue.main.async { + // Start recording the incoming audio samples from the on-device microphone. + try audioRecord.startRecording() + + // Load the samples currently held by the audio record buffer into the audio tensor. + try audioTensor.load(audioRecord: audioRecord) + + // Run inference + let classificationResult = try classifier.classify(audioTensor: audioTensor) + } + } +} +``` + +#### Objective-C + +```objc +// Imports +#import +#import + +// Initialization +NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"sound_classification" ofType:@"tflite"]; + +TFLAudioClassifierOptions *options = + [[TFLAudioClassifierOptions alloc] initWithModelPath:modelPath]; + +// Configure any additional options: +// options.classificationOptions.maxResults = 3; + +TFLAudioClassifier *classifier = [TFLAudioClassifier audioClassifierWithOptions:options + error:nil]; + +// Create Audio Tensor to hold the input audio samples which are to be classified. +// Created Audio Tensor has audio format matching the requirements of the audio classifier. +// For more details, please see: +// https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/audio/core/audio_tensor/sources/TFLAudioTensor.h +TFLAudioTensor *audioTensor = [classifier createInputAudioTensor]; + +// Create Audio Record to record the incoming audio samples from the on-device microphone. +// Created Audio Record has audio format matching the requirements of the audio classifier. +// For more details, please see: +https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/audio/core/audio_record/sources/TFLAudioRecord.h +TFLAudioRecord *audioRecord = [classifier createAudioRecordWithError:nil]; + +// Request record permissions from AVAudioSession before invoking -[TFLAudioRecord startRecordingWithError:]. +[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { + if (granted) { + dispatch_async(dispatch_get_main_queue(), ^{ + // Start recording the incoming audio samples from the on-device microphone. + [audioRecord startRecordingWithError:nil]; + + // Load the samples currently held by the audio record buffer into the audio tensor. + [audioTensor loadAudioRecord:audioRecord withError:nil]; + + // Run inference + TFLClassificationResult *classificationResult = + [classifier classifyWithAudioTensor:audioTensor error:nil]; + + }); + } +}]; +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/audio/sources/TFLAudioClassifier.h) para ver mais opções de configuração do `TFLAudioClassifier`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +Observação: as APIs de áudio da biblioteca Task dependem do [PortAudio](http://www.portaudio.com/docs/v19-doxydocs/index.html) para gravar áudio usando o microfone do dispositivo. Se você deseja usar o [AudioRecord](/lite/api_docs/python/tflite_support/task/audio/AudioRecord) da biblioteca Task para gravação de áudio, precisa instalar o PortAudio em seu sistema. + +- Linux: execute `sudo apt-get update && apt-get install libportaudio2` +- Mac e Windows: o PortAudio é instalado automaticamente ao instalar o pacote `tflite-support` via pip. + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import audio +from tflite_support.task import core +from tflite_support.task import processor + +# Initialization +base_options = core.BaseOptions(file_name=model_path) +classification_options = processor.ClassificationOptions(max_results=2) +options = audio.AudioClassifierOptions(base_options=base_options, classification_options=classification_options) +classifier = audio.AudioClassifier.create_from_options(options) + +# Alternatively, you can create an audio classifier in the following manner: +# classifier = audio.AudioClassifier.create_from_file(model_path) + +# Run inference +audio_file = audio.TensorAudio.create_from_wav_file(audio_path, classifier.required_input_buffer_size) +audio_result = classifier.classify(audio_file) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/audio/audio_classifier.py) para ver mais opções de configuração do `AudioClassifier`. + +## Execute a inferência no C++ + +```c++ +// Initialization +AudioClassifierOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr audio_classifier = AudioClassifier::CreateFromOptions(options).value(); + +// Create input audio buffer from your `audio_data` and `audio_format`. +// See more information here: tensorflow_lite_support/cc/task/audio/core/audio_buffer.h +int input_size = audio_classifier->GetRequiredInputBufferSize(); +const std::unique_ptr audio_buffer = + AudioBuffer::Create(audio_data, input_size, audio_format).value(); + +// Run inference +const ClassificationResult result = audio_classifier->Classify(*audio_buffer).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/audio/audio_classifier.h) para ver mais opções de configuração do `AudioClassifier`. + +## Requisitos de compatibilidade de modelos + +A API `AudioClassifier` espera um modelo do TF Lite com os [metadados de modelo do TF Lite](../../models/convert/metadata.md) obrigatórios. Confira exemplos de criação dos metadados para classificadores de áudio na [API de gravação de metadados do TensorFlow Lite](../../models/convert/metadata_writer_tutorial.ipynb#audio_classifiers). + +Os modelos compatíveis de classificador de áudio devem atender aos seguintes requisitos: + +- Tensor de áudio de entrada (kTfLiteFloat32) + + - Clipe de áudio de tamanho `[batch x samples]` (lote x amostras). + - Não há suporte à inferência de lote (`batch` precisa ser igual a 1). + - Para modelos multicanais, os canais precisam ser intercalados. + +- Tensor de pontuação de saída (kTfLiteFloat32) + + - Array `[1 x N]`, em que `N` representa o número de classes. + - Mapa(s) de rótulos (opcionais, mas recomendados), como AssociatedFiles com tipo TENSOR_AXIS_LABELS, contendo um rótulo por linha. O primeiro AssociatedFile (se houver) é usado para preencher o campo `label` (com nome igual a `class_name` no C++) dos resultados. O campo `display_name` é preenchido a partir do AssociatedFile (se houver) cujo idioma coincida com o campo `display_names_locale` das opções `AudioClassifierOptions` usadas no momento da criação ("en" por padrão, ou seja, inglês). Se nenhum estiver disponível, somente o campo `index` dos resultados será preenchido. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/bert_nl_classifier.md b/site/pt-br/lite/inference_with_metadata/task_library/bert_nl_classifier.md new file mode 100644 index 0000000000..953ccf3da8 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/bert_nl_classifier.md @@ -0,0 +1,151 @@ +# Integração do classificador de linguagem natural BERT + +A API `BertNLClassifier` da biblioteca Task é muito similar à API `NLClassifier`, que classifica texto de entrada em diferentes categorias, exceto pelo fato de essa API ter sido personalizada para modelos relacionados a BERT que exigem as tokenizações Wordpiece e Sentencepiece fora do modelo do TF Lite. + +## Principais recursos da API BertNLClassifier + +- Recebe uma única string como entrada, faz a classificação com a string e gera como saída pares <Label, Score> (rótulo, pontuação) como resultados da classificação. + +- Faz as tokenizações [Wordpiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/bert_tokenizer.h) ou [Sentencepiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/sentencepiece_tokenizer.h) do texto de entrada fora do grafo. + +## Modelos de BertNLClassifier com suporte + +Os modelos abaixo são compatíveis com a API `BertNLClassifier`. + +- Modelos BERT criados pelo [Model Maker do TensorFlow Lite para classificação de texto](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import the Task Text Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-text:0.4.4' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Execute a inferência usando a API + +```java +// Initialization +BertNLClassifierOptions options = + BertNLClassifierOptions.builder() + .setBaseOptions(BaseOptions.builder().setNumThreads(4).build()) + .build(); +BertNLClassifier classifier = + BertNLClassifier.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = classifier.classify(input); +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/text/nlclassifier/BertNLClassifier.java). + +## Execute a inferência no Swift + +### Etapa 1 – Importe o CocoaPods + +Adicione o pod TensorFlowLiteTaskText ao Podfile. + +``` +target 'MySwiftAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskText', '~> 0.4.4' +end +``` + +### Etapa 2 – Execute a inferência usando a API + +```swift +// Initialization +let bertNLClassifier = TFLBertNLClassifier.bertNLClassifier( + modelPath: bertModelPath) + +// Run inference +let categories = bertNLClassifier.classify(text: input) +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/text/nlclassifier/Sources/TFLBertNLClassifier.h). + +## Execute a inferência no C++ + +```c++ +// Initialization +BertNLClassifierOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr classifier = BertNLClassifier::CreateFromOptions(options).value(); + +// Run inference with your input, `input_text`. +std::vector categories = classifier->Classify(input_text); +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/bert_nl_classifier.h). + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import text + +# Initialization +classifier = text.BertNLClassifier.create_from_file(model_path) + +# Run inference +text_classification_result = classifier.classify(text) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/text/bert_nl_classifier.py) para ver mais opções de configuração do `BertNLClassifier`. + +## Exemplo de resultados + +Veja um exemplo dos resultados da classificação de avaliações de filmes usando o modelo [MobileBert](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification) do Model Maker (criador de modelos). + +Entrada (em inglês): "it's a charming and often affecting journey" (é uma jornada encantadora e, às vezes, comovente). + +Saída: + +``` +category[0]: 'negative' : '0.00006' +category[1]: 'positive' : '0.99994' +``` + +Experimente a [ferramenta CLI simples de demonstração para BertNLClassifier](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/examples/task/text/desktop/README.md#bertnlclassifier) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `BertNLClassifier` espera um modelo do TF Lite com os [metadados de modelo do TF Lite](../../models/convert/metadata.md) obrigatórios. + +Os metadados devem atender aos seguintes requisitos: + +- input_process_units para o tokenizador Wordpiece/Sentencepiece. + +- Três tensores de entrada com nomes "ids", "mask" e "segment_ids" para a saída do tokenizador. + +- Um tensor de saída do tipo float32, com um arquivo de rótulos opcional, que deve ser um arquivo de texto sem formatação com um rótulo por linha. O número de rótulos precisa coincidir com o número de categorias da saída do modelo. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/bert_question_answerer.md b/site/pt-br/lite/inference_with_metadata/task_library/bert_question_answerer.md new file mode 100644 index 0000000000..6dcff2393d --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/bert_question_answerer.md @@ -0,0 +1,166 @@ +# Integração do respondedor de perguntas BERT + +A API `BertQuestionAnswerer` da biblioteca Task carrega um modelo BERT e responde a perguntas com base no conteúdo de um determinado trecho. Confira mais informações na documentação do modelo Question-Answer aqui. + +## Principais recursos da API BertQuestionAnswerer + +- Recebe duas entradas de texto como pergunta e contexto, e gera como saída uma lista de possíveis respostas. + +- Faz as tokenizações Wordpiece ou Sentencepiece do texto de entrada fora do grafo. + +## Modelos de BertQuestionAnswerer com suporte + +Os modelos abaixo são compatíveis com a API `BertNLClassifier`. + +- Modelos criados pelo [Model Maker do TensorFlow Lite para o Question-Answer BERT](https://www.tensorflow.org/lite/models/modify/model_maker/question_answer). + +- [Modelos BERT pré-treinados no TensorFlow Hub](https://tfhub.dev/tensorflow/collections/lite/task-library/bert-question-answerer/1). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import the Task Text Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-text:0.4.4' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Execute a inferência usando a API + +```java +// Initialization +BertQuestionAnswererOptions options = + BertQuestionAnswererOptions.builder() + .setBaseOptions(BaseOptions.builder().setNumThreads(4).build()) + .build(); +BertQuestionAnswerer answerer = + BertQuestionAnswerer.createFromFileAndOptions( + androidContext, modelFile, options); + +// Run inference +List answers = answerer.answer(contextOfTheQuestion, questionToAsk); +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/text/qa/BertQuestionAnswerer.java). + +## Execute a inferência no Swift + +### Etapa 1 – Importe o CocoaPods + +Adicione o pod TensorFlowLiteTaskText ao Podfile. + +``` +target 'MySwiftAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskText', '~> 0.4.4' +end +``` + +### Etapa 2 – Execute a inferência usando a API + +```swift +// Initialization +let mobileBertAnswerer = TFLBertQuestionAnswerer.questionAnswerer( + modelPath: mobileBertModelPath) + +// Run inference +let answers = mobileBertAnswerer.answer( + context: context, question: question) +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/text/qa/Sources/TFLBertQuestionAnswerer.h). + +## Execute a inferência no C++ + +```c++ +// Initialization +BertQuestionAnswererOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr answerer = BertQuestionAnswerer::CreateFromOptions(options).value(); + +// Run inference with your inputs, `context_of_question` and `question_to_ask`. +std::vector positive_results = answerer->Answer(context_of_question, question_to_ask); +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/bert_question_answerer.h). + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import text + +# Initialization +answerer = text.BertQuestionAnswerer.create_from_file(model_path) + +# Run inference +bert_qa_result = answerer.answer(context, question) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/text/bert_question_answerer.py) para ver mais opções de configuração do `BertQuestionAnswerer`. + +## Exemplo de resultados + +Veja um exemplo dos resultados de resposta do [modelo ALBERT](https://tfhub.dev/tensorflow/lite-model/albert_lite_base/squadv1/1). + +Contexto: "The Amazon rainforest, alternatively, the Amazon Jungle, also known in English as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that covers most of the Amazon basin of South America. This basin encompasses 7,000,000 km2 (2,700,000 sq mi), of which 5,500,000 km2 (2,100,000 sq mi) are covered by the rainforest. This region includes territory belonging to nine nations."

(A Amazônia, também chamada de Floresta/Selva Amazônica, é uma floresta latifoliada úmida que cobre a maior parte da Bacia Amazônica da América do Sul. Esta bacia abrange 7 milhões de quilômetros quadrados, dos quais 5 milhões e meio de quilômetros quadrados são cobertos pela floresta tropical. Esta região inclui territórios pertencentes a nove nações). + +Pergunta: "Where is Amazon rainforest?"

(Onde fica a Floresta Amazônica?) + +Respostas: + +``` +answer[0]: 'South America.' +logit: 1.84847, start_index: 39, end_index: 40 +answer[1]: 'most of the Amazon basin of South America.' +logit: 1.2921, start_index: 34, end_index: 40 +answer[2]: 'the Amazon basin of South America.' +logit: -0.0959535, start_index: 36, end_index: 40 +answer[3]: 'the Amazon biome that covers most of the Amazon basin of South America.' +logit: -0.498558, start_index: 28, end_index: 40 +answer[4]: 'Amazon basin of South America.' +logit: -0.774266, start_index: 37, end_index: 40 + +``` + +Experimente a [ferramenta CLI simples de demonstração para BertQuestionAnswerer](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/examples/task/text/desktop/README.md#bert-question-answerer) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `BertQuestionAnswerer` espera um modelo do TF Lite com os [metadados de modelo do TF Lite](../../models/convert/metadata) obrigatórios. + +Os metadados devem atender aos seguintes requisitos: + +- `input_process_units` para o tokenizador Wordpiece/Sentencepiece. + +- Três tensores de entrada com nomes "ids", "mask" e "segment_ids" para a saída do tokenizador. + +- Dois tensores de saída com nomes "end_logits" e "start_logits" para indicar a posição relativa da resposta no contexto. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/customized_task_api.md b/site/pt-br/lite/inference_with_metadata/task_library/customized_task_api.md new file mode 100644 index 0000000000..915b3b63f7 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/customized_task_api.md @@ -0,0 +1,360 @@ +# Crie sua própria API de tarefas + +A biblioteca Task do TensorFlow Lite conta com APIs pré-compiladas nativas/para Android/para iOS usando a mesma infraestrutura de abstração do TensorFlow. Você pode estender a infraestrutura da API de tarefas para criar APIs personalizadas caso as bibliotecas de tarefas existentes não sejam compatíveis com seu modelo. + +## Visão geral + +A infraestrutura da API de tarefas tem uma estrutura de duas camadas: a camada C++ inferior, que encapsula o runtime nativo do TF Lite, e a camada Java/Obj-C superior, que se comunica com a camada C++ por meio da JNI ou do encapsulador nativo. + +Implementar toda a lógica do TensorFlow apenas no C++ minimiza o custo, maximiza o desempenho de inferência e simplifica o workflow geral entre as plataformas. + +Para criar uma classe de tarefas, estenda a [BaseTaskApi](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/base_task_api.h) para fornecer uma lógica de conversão entre a interface de modelo do TF Lite e a interface da API de tarefas. Depois, use utilitários Java/ObjC para criar as APIs correspondentes. Com todos os detalhes do TensorFlow ocultos, você pode implantar o modelo do TF Lite em seus aplicativos sem qualquer conhecimento sobre aprendizado de máquina. + +O TensorFlow Lite conta com algumas APIs pré-compiladas para a maioria das tarefas comuns de visão e NLP. Você pode compilar suas próprias APIs para outras tarefas usando a infraestrutura da API de tarefas. + +
![prebuilt_task_apis](images/prebuilt_task_apis.svg)
+
Figura 1 – APIs de tarefas pré-compiladas
+
+ +## Compile sua própria API com a infraestrutura da API de tarefas + +### API do C++ + +Todos os detalhes do TF Lite são implementados na API nativa. Crie um objeto de API usando uma das funções de fábrica e obtenha os resultados do modelo chamando as funções definidas na interface. + +#### Exemplo de uso + +Veja um exemplo de uso de [`BertQuestionAnswerer`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/qa/bert_question_answerer.h) em C++ para [MobileBert](https://tfhub.dev/tensorflow/lite-model/mobilebert/1/default/1). + +```cpp + char kBertModelPath[] = "path/to/model.tflite"; + // Create the API from a model file + std::unique_ptr question_answerer = + BertQuestionAnswerer::CreateFromFile(kBertModelPath); + + char kContext[] = ...; // context of a question to be answered + char kQuestion[] = ...; // question to be answered + // ask a question + std::vector answers = question_answerer.Answer(kContext, kQuestion); + // answers[0].text is the best answer +``` + +#### Compilação da API + +
![native_task_api](images/native_task_api.svg)
+
Figura 2 – API de tarefas nativa
+
+ +Para compilar um objeto de API, você precisa estender [`BaseTaskApi`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/base_task_api.h) para fornecer as seguintes informações: + +- **Determine o I/O da API** – Sua API deve expor entradas/saídas similares nas diferentes plataformas. Por exemplo: `BertQuestionAnswerer` recebe duas strings `(std::string& context, std::string& question)` como entrada e gera como saída um vetor de possíveis respostas e probabilidades como `std::vector`. Isso é feito por meio da especificação dos tipos correspondentes no [parâmetro template](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/base_task_api.h?q="template <class OutputType, class... InputTypes>") de `BaseTaskApi`. Com os parâmetros template especificados, a função [`BaseTaskApi::Infer`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/base_task_api.h?q="Infer(InputTypes... args)") terá os tipos corretos de entrada/saída. Essa função pode ser chamada diretamente pelos clientes da API, mas é uma boa prática encapsulá-la dentro de uma função específica do modelo; neste caso, é `BertQuestionAnswerer::Answer`. + + ```cpp + class BertQuestionAnswerer : public BaseTaskApi< + std::vector, // OutputType + const std::string&, const std::string& // InputTypes + > { + // Model specific function delegating calls to BaseTaskApi::Infer + std::vector Answer(const std::string& context, const std::string& question) { + return Infer(context, question).value(); + } + } + ``` + +- **Forneça lógica de conversão entre o I/O da API e o tensor de entrada/saída do modelo** – Com os tipos de entrada e saída especificados, as subclasses também precisam implementar as funções tipadas [`BaseTaskApi::Preprocess`](https://github.com/tensorflow/tflite-support/blob/5cea306040c40b06d6e0ed4e5baf6c307db7bd00/tensorflow_lite_support/cc/task/core/base_task_api.h#L74) e [`BaseTaskApi::Postprocess`](https://github.com/tensorflow/tflite-support/blob/5cea306040c40b06d6e0ed4e5baf6c307db7bd00/tensorflow_lite_support/cc/task/core/base_task_api.h#L80). As duas funções fornecem [entradas](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/qa/bert_question_answerer.cc) e [saídas](https://github.com/tensorflow/tensorflow/blob/1b84e5af78f85b8d3c4687b7dee65b78113f81cc/tensorflow/lite/schema/schema.fbs#L1008) do `FlatBuffer` do TF Lite. A subclasse é responsável por atribuir valores do I/O da API aos tensores de I/O. Confira um exemplo completo de implementação em [`BertQuestionAnswerer`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/qa/bert_question_answerer.cc). + + ```cpp + class BertQuestionAnswerer : public BaseTaskApi< + std::vector, // OutputType + const std::string&, const std::string& // InputTypes + > { + // Convert API input into tensors + absl::Status BertQuestionAnswerer::Preprocess( + const std::vector& input_tensors, // input tensors of the model + const std::string& context, const std::string& query // InputType of the API + ) { + // Perform tokenization on input strings + ... + // Populate IDs, Masks and SegmentIDs to corresponding input tensors + PopulateTensor(input_ids, input_tensors[0]); + PopulateTensor(input_mask, input_tensors[1]); + PopulateTensor(segment_ids, input_tensors[2]); + return absl::OkStatus(); + } + + // Convert output tensors into API output + StatusOr> // OutputType + BertQuestionAnswerer::Postprocess( + const std::vector& output_tensors, // output tensors of the model + ) { + // Get start/end logits of prediction result from output tensors + std::vector end_logits; + std::vector start_logits; + // output_tensors[0]: end_logits FLOAT[1, 384] + PopulateVector(output_tensors[0], &end_logits); + // output_tensors[1]: start_logits FLOAT[1, 384] + PopulateVector(output_tensors[1], &start_logits); + ... + std::vector orig_results; + // Look up the indices from vocabulary file and build results + ... + return orig_results; + } + } + ``` + +- **Crie funções de fábrica da API** – São necessários um arquivo de modelo e um [`OpResolver`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/core/api/op_resolver.h) para inicializar o [`tflite::Interpreter`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/interpreter.h). [`TaskAPIFactory`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/task_api_factory.h) conta com funções utilitárias para criar instâncias da BaseTaskApi. + + Observação: por padrão, [`TaskAPIFactory`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/core/task_api_factory.h) conta com um [`BuiltInOpResolver`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/kernels/register.h). Caso o seu modelo precise de operações personalizadas ou um subconjunto de operações integradas, você criar um [`MutableOpResolver`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/mutable_op_resolver.h) para registrá-las. + + Você também precisa fornecer qualquer arquivo associado ao modelo. Por exemplo: `BertQuestionAnswerer` também pode ter um arquivo adicional para o vocabulário do tokenizador. + + ```cpp + class BertQuestionAnswerer : public BaseTaskApi< + std::vector, // OutputType + const std::string&, const std::string& // InputTypes + > { + // Factory function to create the API instance + StatusOr> + BertQuestionAnswerer::CreateBertQuestionAnswerer( + const std::string& path_to_model, // model to passed to TaskApiFactory + const std::string& path_to_vocab // additional model specific files + ) { + // Creates an API object by calling one of the utils from TaskAPIFactory + std::unique_ptr api_to_init; + ASSIGN_OR_RETURN( + api_to_init, + core::TaskAPIFactory::CreateFromFile( + path_to_model, + absl::make_unique(), + kNumLiteThreads)); + + // Perform additional model specific initializations + // In this case building a vocabulary vector from the vocab file. + api_to_init->InitializeVocab(path_to_vocab); + return api_to_init; + } + } + ``` + +### API do Android + +Crie APIs do Android definindo a interface Java/Kotlin e delegando a lógica para a camada C++ por meio da JNI. No caso da API do Android, é preciso compilar a API nativa primeiro. + +#### Exemplo de uso + +Veja um exemplo de uso de [`BertQuestionAnswerer`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/text/qa/BertQuestionAnswerer.java) em Java para [MobileBert](https://tfhub.dev/tensorflow/lite-model/mobilebert/1/default/1). + +```java + String BERT_MODEL_FILE = "path/to/model.tflite"; + String VOCAB_FILE = "path/to/vocab.txt"; + // Create the API from a model file and vocabulary file + BertQuestionAnswerer bertQuestionAnswerer = + BertQuestionAnswerer.createBertQuestionAnswerer( + ApplicationProvider.getApplicationContext(), BERT_MODEL_FILE, VOCAB_FILE); + + String CONTEXT = ...; // context of a question to be answered + String QUESTION = ...; // question to be answered + // ask a question + List answers = bertQuestionAnswerer.answer(CONTEXT, QUESTION); + // answers.get(0).text is the best answer +``` + +#### Compilação da API + +
![android_task_api](images/android_task_api.svg)
+
Figura 3 – API de tarefas para Android
+
+ +Similar às APIs nativas, para compilar um objeto de API, o cliente precisa estender a [`BaseTaskApi`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/core/BaseTaskApi.java) para fornecer as informações abaixo, o que fornece manipulações de JNI para todas as APIs de tarefas para Java. + +- **Determine o I/O da API** – Geralmente, espelha as interfaces nativas. Por exemplo: `BertQuestionAnswerer` recebe `(String context, String question)` como entrada e gera como saída `List`. A implementação chama uma função nativa privada com assinatura similar, exceto pelo parâmetro adicional `long nativeHandle`, que é o ponteiro retornado pelo C++. + + ```java + class BertQuestionAnswerer extends BaseTaskApi { + public List answer(String context, String question) { + return answerNative(getNativeHandle(), context, question); + } + + private static native List answerNative( + long nativeHandle, // C++ pointer + String context, String question // API I/O + ); + + } + ``` + +- **Crie funções de fábrica da API** – Também espelham as funções de fábrica nativas, exceto pelas funções de fábrica do Android, que também precisam receber o [`Context`](https://developer.android.com/reference/android/content/Context) para acesso aos arquivos. A implementação chama um dos utilitários em [`TaskJniUtils`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/core/TaskJniUtils.java) para compilar o objeto de API C++ correspondente e passar seu ponteiro ao construtor da `BaseTaskApi`. + + ```java + class BertQuestionAnswerer extends BaseTaskApi { + private static final String BERT_QUESTION_ANSWERER_NATIVE_LIBNAME = + "bert_question_answerer_jni"; + + // Extending super constructor by providing the + // native handle(pointer of corresponding C++ API object) + private BertQuestionAnswerer(long nativeHandle) { + super(nativeHandle); + } + + public static BertQuestionAnswerer createBertQuestionAnswerer( + Context context, // Accessing Android files + String pathToModel, String pathToVocab) { + return new BertQuestionAnswerer( + // The util first try loads the JNI module with name + // BERT_QUESTION_ANSWERER_NATIVE_LIBNAME, then opens two files, + // converts them into ByteBuffer, finally ::initJniWithBertByteBuffers + // is called with the buffer for a C++ API object pointer + TaskJniUtils.createHandleWithMultipleAssetFilesFromLibrary( + context, + BertQuestionAnswerer::initJniWithBertByteBuffers, + BERT_QUESTION_ANSWERER_NATIVE_LIBNAME, + pathToModel, + pathToVocab)); + } + + // modelBuffers[0] is tflite model file buffer, and modelBuffers[1] is vocab file buffer. + // returns C++ API object pointer casted to long + private static native long initJniWithBertByteBuffers(ByteBuffer... modelBuffers); + + } + ``` + +- **Implemente o módulo JNI para funções nativas** – Todos os métodos Java nativos são implementados chamando uma função nativa correspondente do módulo de JNI. As funções de fábrica criam um objeto da API nativa e retornam seu ponteiro como um tipo long para o Java. Em chamadas posteriores à API do Java, o ponteiro de tipo long é passado de volta à JNI e convertido de volta no objeto da API nativa. Os resultados da API nativa são então convertidos de volta para resultados Java. + + Por exemplo, [bert_question_answerer_jni](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/native/task/text/qa/bert_question_answerer_jni.cc) é implementado assim. + + ```cpp + // Implements BertQuestionAnswerer::initJniWithBertByteBuffers + extern "C" JNIEXPORT jlong JNICALL + Java_org_tensorflow_lite_task_text_qa_BertQuestionAnswerer_initJniWithBertByteBuffers( + JNIEnv* env, jclass thiz, jobjectArray model_buffers) { + // Convert Java ByteBuffer object into a buffer that can be read by native factory functions + absl::string_view model = + GetMappedFileBuffer(env, env->GetObjectArrayElement(model_buffers, 0)); + + // Creates the native API object + absl::StatusOr> status = + BertQuestionAnswerer::CreateFromBuffer( + model.data(), model.size()); + if (status.ok()) { + // converts the object pointer to jlong and return to Java. + return reinterpret_cast(status->release()); + } else { + return kInvalidPointer; + } + } + + // Implements BertQuestionAnswerer::answerNative + extern "C" JNIEXPORT jobject JNICALL + Java_org_tensorflow_lite_task_text_qa_BertQuestionAnswerer_answerNative( + JNIEnv* env, jclass thiz, jlong native_handle, jstring context, jstring question) { + // Convert long to native API object pointer + QuestionAnswerer* question_answerer = reinterpret_cast(native_handle); + + // Calls the native API + std::vector results = question_answerer->Answer(JStringToString(env, context), + JStringToString(env, question)); + + // Converts native result(std::vector) to Java result(List) + jclass qa_answer_class = + env->FindClass("org/tensorflow/lite/task/text/qa/QaAnswer"); + jmethodID qa_answer_ctor = + env->GetMethodID(qa_answer_class, "", "(Ljava/lang/String;IIF)V"); + return ConvertVectorToArrayList( + env, results, + [env, qa_answer_class, qa_answer_ctor](const QaAnswer& ans) { + jstring text = env->NewStringUTF(ans.text.data()); + jobject qa_answer = + env->NewObject(qa_answer_class, qa_answer_ctor, text, ans.pos.start, + ans.pos.end, ans.pos.logit); + env->DeleteLocalRef(text); + return qa_answer; + }); + } + + // Implements BaseTaskApi::deinitJni by delete the native object + extern "C" JNIEXPORT void JNICALL Java_task_core_BaseTaskApi_deinitJni( + JNIEnv* env, jobject thiz, jlong native_handle) { + delete reinterpret_cast(native_handle); + } + ``` + +### API do iOS + +Crie APIs do iOS encapsulando um objeto da API nativa em um objeto da API do ObjC. O objeto da API criado pode ser usado no ObjC ou no Swift. No caso da API do iOS, é preciso compilar a API nativa primeiro. + +#### Exemplo de uso + +Veja um exemplo de uso de [`BertQuestionAnswerer`](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/text/qa/Sources/TFLBertQuestionAnswerer.h) em ObjC para [MobileBert](https://tfhub.dev/tensorflow/lite-model/mobilebert/1/default/1). + +```swift + static let mobileBertModelPath = "path/to/model.tflite"; + // Create the API from a model file and vocabulary file + let mobileBertAnswerer = TFLBertQuestionAnswerer.mobilebertQuestionAnswerer( + modelPath: mobileBertModelPath) + + static let context = ...; // context of a question to be answered + static let question = ...; // question to be answered + // ask a question + let answers = mobileBertAnswerer.answer( + context: TFLBertQuestionAnswererTest.context, question: TFLBertQuestionAnswererTest.question) + // answers.[0].text is the best answer +``` + +#### Compilação da API + +
![ios_task_api](images/ios_task_api.svg)
+
Figura 4 – API de tarefas para iOS
+
+ +A API do iOS é um encapsulador ObjC simples que usa a API nativa. Para compilar a API, siga as etapas abaixo: + +- **Defina o encapsulador ObjC** – Defina uma classe ObjC e delegue as implementações para o objeto da API nativa correspondente. Atenção: as dependências nativas só podem aparecer em um arquivo .mm devido à incapacidade de o Swift fazer a interoperabilidade com o C++. + + - Arquivo .h + + ```objc + @interface TFLBertQuestionAnswerer : NSObject + + // Delegate calls to the native BertQuestionAnswerer::CreateBertQuestionAnswerer + + (instancetype)mobilebertQuestionAnswererWithModelPath:(NSString*)modelPath + vocabPath:(NSString*)vocabPath + NS_SWIFT_NAME(mobilebertQuestionAnswerer(modelPath:vocabPath:)); + + // Delegate calls to the native BertQuestionAnswerer::Answer + - (NSArray*)answerWithContext:(NSString*)context + question:(NSString*)question + NS_SWIFT_NAME(answer(context:question:)); + } + ``` + + - Arquivo .mm + + ```objc + using BertQuestionAnswererCPP = ::tflite::task::text::BertQuestionAnswerer; + + @implementation TFLBertQuestionAnswerer { + // define an iVar for the native API object + std::unique_ptr _bertQuestionAnswerwer; + } + + // Initialize the native API object + + (instancetype)mobilebertQuestionAnswererWithModelPath:(NSString *)modelPath + vocabPath:(NSString *)vocabPath { + absl::StatusOr> cQuestionAnswerer = + BertQuestionAnswererCPP::CreateBertQuestionAnswerer(MakeString(modelPath), + MakeString(vocabPath)); + _GTMDevAssert(cQuestionAnswerer.ok(), @"Failed to create BertQuestionAnswerer"); + return [[TFLBertQuestionAnswerer alloc] + initWithQuestionAnswerer:std::move(cQuestionAnswerer.value())]; + } + + // Calls the native API and converts C++ results into ObjC results + - (NSArray *)answerWithContext:(NSString *)context question:(NSString *)question { + std::vector results = + _bertQuestionAnswerwer->Answer(MakeString(context), MakeString(question)); + return [self arrayFromVector:results]; + } + } + ``` diff --git a/site/pt-br/lite/inference_with_metadata/task_library/image_classifier.md b/site/pt-br/lite/inference_with_metadata/task_library/image_classifier.md new file mode 100644 index 0000000000..9c3a012de4 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/image_classifier.md @@ -0,0 +1,254 @@ +# Integração de classificadores de imagem + +A classificação de imagens é um uso comum de aprendizado de máquina para identificar o que uma imagem representa. Por exemplo: talvez a gente queira saber que tipo de animal aparece em uma determinada imagem. A tarefa de prever o que uma imagem representa é chamada de *classificação de imagem*. Um classificador de imagem é treinado para reconhecer diversas classes de imagens. Por exemplo: um modelo pode ser treinado para reconhecer fotos que representem três tipos diferentes de animais: coelhos, hamsters e cachorros. Veja mais informações sobre classificadores de imagem na [visão geral da classificação de imagens](https://www.tensorflow.org/lite/examples/image_classification/overview). + +Use a API `ImageClassifier` da biblioteca Task para implantar classificadores de imagem personalizados ou pré-treinados em seus aplicativos para dispositivos móveis. + +## Principais recursos da API ImageClassifier + +- Processamento da imagem de entrada, incluindo rotação, redimensionamento e conversão do espaço de cores. + +- Região de interesse da imagem de entrada. + +- Idioma do mapa de rótulos. + +- Limite de pontuação para filtrar resultados. + +- Resultados de classificação top-k. + +- Lista de permissão e proibição de rótulos. + +## Modelos de classificador de imagem com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `ImageClassifier`. + +- Modelos criados pelo [Model Maker do TensorFlow Lite para classificação de imagem](https://www.tensorflow.org/lite/models/modify/model_maker/image_classification). + +- [Modelos pré-treinados de classificação de imagens no TensorFlow Hub](https://tfhub.dev/tensorflow/collections/lite/task-library/image-classifier/1). + +- Modelos criados pela [classificação de imagens do AutoML Vision Edge](https://cloud.google.com/vision/automl/docs/edge-quickstart). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +Confira o [aplicativo de referência para classificação de imagens](https://github.com/tensorflow/examples/blob/master/lite/examples/image_classification/android/README.md) para ver um exemplo de como usar o `ImageClassifier` em um aplicativo para Android. + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-vision' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +### Etapa 2 – Use o modelo + +```java +// Initialization +ImageClassifierOptions options = + ImageClassifierOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setMaxResults(1) + .build(); +ImageClassifier imageClassifier = + ImageClassifier.createFromFileAndOptions( + context, modelFile, options); + +// Run inference +List results = imageClassifier.classify(image); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/vision/classifier/ImageClassifier.java) para ver mais opções de configuração do `ImageClassifier`. + +## Execute a inferência no iOS + +### Etapa 1 – Instale as dependências + +A biblioteca Task oferece suporte à instalação usando o CocoaPods, que precisa estar instalado em seu sistema. Confira as instruções no [guia de instalação do CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +Confira os detalhes de como adicionar pods a um projeto do Xcode no [guia do CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html). + +Adicione o pod `TensorFlowLiteTaskVision` ao Podfile. + +``` +target 'MyAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskVision' +end +``` + +Confirme se o modelo `.tflite` que você usará para inferência está presente no pacote do aplicativo. + +### Etapa 2 – Use o modelo + +#### Swift + +```swift +// Imports +import TensorFlowLiteTaskVision + +// Initialization +guard let modelPath = Bundle.main.path(forResource: "birds_V1", + ofType: "tflite") else { return } + +let options = ImageClassifierOptions(modelPath: modelPath) + +// Configure any additional options: +// options.classificationOptions.maxResults = 3 + +let classifier = try ImageClassifier.classifier(options: options) + +// Convert the input image to MLImage. +// There are other sources for MLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +guard let image = UIImage (named: "sparrow.jpg"), let mlImage = MLImage(image: image) else { return } + +// Run inference +let classificationResults = try classifier.classify(mlImage: mlImage) +``` + +#### Objective-C + +```objc +// Imports +#import + +// Initialization +NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"birds_V1" ofType:@"tflite"]; + +TFLImageClassifierOptions *options = + [[TFLImageClassifierOptions alloc] initWithModelPath:modelPath]; + +// Configure any additional options: +// options.classificationOptions.maxResults = 3; + +TFLImageClassifier *classifier = [TFLImageClassifier imageClassifierWithOptions:options + error:nil]; + +// Convert the input image to MLImage. +UIImage *image = [UIImage imageNamed:@"sparrow.jpg"]; + +// There are other sources for GMLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +GMLImage *gmlImage = [[GMLImage alloc] initWithImage:image]; + +// Run inference +TFLClassificationResult *classificationResult = + [classifier classifyWithGMLImage:gmlImage error:nil]; +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/vision/sources/TFLImageClassifier.h) para ver mais opções de configuração do `TFLImageClassifier`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import vision +from tflite_support.task import core +from tflite_support.task import processor + +# Initialization +base_options = core.BaseOptions(file_name=model_path) +classification_options = processor.ClassificationOptions(max_results=2) +options = vision.ImageClassifierOptions(base_options=base_options, classification_options=classification_options) +classifier = vision.ImageClassifier.create_from_options(options) + +# Alternatively, you can create an image classifier in the following manner: +# classifier = vision.ImageClassifier.create_from_file(model_path) + +# Run inference +image = vision.TensorImage.create_from_file(image_path) +classification_result = classifier.classify(image) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/vision/image_classifier.py) para ver mais opções de configuração do `ImageClassifier`. + +## Execute a inferência no C++ + +```c++ +// Initialization +ImageClassifierOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr image_classifier = ImageClassifier::CreateFromOptions(options).value(); + +// Create input frame_buffer from your inputs, `image_data` and `image_dimension`. +// See more information here: tensorflow_lite_support/cc/task/vision/utils/frame_buffer_common_utils.h + +std::unique_ptr frame_buffer = CreateFromRgbRawBuffer( + image_data, image_dimension); + +// Run inference +const ClassificationResult result = image_classifier->Classify(*frame_buffer).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/vision/image_classifier.h) para ver mais opções de configuração do `ImageClassifier`. + +## Exemplo de resultados + +Veja um exemplo dos resultados de classificação do [classificador de pássaros](https://tfhub.dev/google/lite-model/aiy/vision/classifier/birds_V1/3). + +sparrow + +``` +Results: + Rank #0: + index : 671 + score : 0.91406 + class name : /m/01bwb9 + display name: Passer domesticus + Rank #1: + index : 670 + score : 0.00391 + class name : /m/01bwbt + display name: Passer montanus + Rank #2: + index : 495 + score : 0.00391 + class name : /m/0bwm6m + display name: Passer italiae +``` + +Experimente a [ferramenta CLI simples de demonstração para ImageClassifier](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop#image-classifier) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `ImageClassifier` espera um modelo do TF Lite com os [metadados de modelo do TF Lite](https://www.tensorflow.org/lite/models/convert/metadata) obrigatórios. Confira exemplos de criação dos metadados para classificadores de imagem na [API de gravação de metadados do TensorFlow Lite](../../models/convert/metadata_writer_tutorial.ipynb#image_classifiers). + +Os modelos compatíveis de classificador de imagem devem atender aos seguintes requisitos: + +- Um tensor de imagem de entrada (kTfLiteUInt8/kTfLiteFloat32). + + - Imagem de entrada de tamanho `[batch x height x width x channels]` (lote x altura x largura x canais). + - Não há suporte à inferência de lote (`batch` precisa ser igual a 1). + - Só há suporte a entradas RGB (`channels` precisa ser igual a 3). + - Se o tipo for kTfLiteFloat32, as opções NormalizationOptions precisam ser adicionadas aos metadados para a normalização da entrada. + +- Tensor de pontuação de saída (kTfLiteUInt8/kTfLiteFloat32). + + - Com `N` classes e 2 ou 4 dimensões, ou seja, `[1 x N]` ou `[1 x 1 x 1 x N]` + - Mapa(s) de rótulos (opcionais, mas recomendados), como AssociatedFiles com tipo TENSOR_AXIS_LABELS, contendo um rótulo por linha. Confira o [arquivo de rótulos de exemplo](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt). O primeiro AssociatedFile (se houver) é usado para preencher o campo `label` (com nome igual a `class_name` no C++) dos resultados. O campo `display_name` é preenchido a partir do AssociatedFile (se houver) cujo idioma coincida com o campo `display_names_locale` das opções `ImageClassifierOptions` usadas no momento da criação ("en" por padrão, ou seja, inglês). Se nenhum estiver disponível, somente o campo `index` dos resultados será preenchido. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/image_embedder.md b/site/pt-br/lite/inference_with_metadata/task_library/image_embedder.md new file mode 100644 index 0000000000..66a04813c8 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/image_embedder.md @@ -0,0 +1,112 @@ +# Integração de incorporadores de imagem + +Os incorporadores de imagem permitem incorporar imagens a um vetor de características de alta dimensão que representa o significado semântico de uma imagem. Em seguida, esse vetor pode ser comparado ao vetor de características de outras imagens para avaliar a similaridade semântica. + +Ao contrário da [pesquisa de imagens](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_searcher), o incorporador de imagem permite computar a similaridade entre imagens em tempo real em vez de pesquisar em um índice predefinido criado a partir de um corpus de imagens. + +Use a API `ImageEmbedder` da biblioteca Task para implantar seu incorporador de imagem personalizado em seus aplicativos para dispositivos móveis. + +## Principais recursos da API ImageEmbedder + +- Processamento da imagem de entrada, incluindo rotação, redimensionamento e conversão do espaço de cores. + +- Região de interesse da imagem de entrada. + +- Função utilitária integrada para computar a [similaridade por cosseno](https://en.wikipedia.org/wiki/Cosine_similarity) entre os vetores de características. + +## Modelos de incorporador de imagem com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `ImageEmbedder`. + +- Modelos de vetores de características da [coleção de módulos do Google Imagens no TensorFlow Hub](https://tfhub.dev/google/collections/image/1). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no C++ + +```c++ +// Initialization +ImageEmbedderOptions options: +options.mutable_model_file_with_metadata()->set_file_name(model_path); +options.set_l2_normalize(true); +std::unique_ptr image_embedder = ImageEmbedder::CreateFromOptions(options).value(); + +// Create input frame_buffer_1 and frame_buffer_2 from your inputs `image_data1`, `image_data2`, `image_dimension1` and `image_dimension2`. +// See more information here: tensorflow_lite_support/cc/task/vision/utils/frame_buffer_common_utils.h +std::unique_ptr frame_buffer_1 = CreateFromRgbRawBuffer( + image_data1, image_dimension1); +std::unique_ptr frame_buffer_2 = CreateFromRgbRawBuffer( + image_data2, image_dimension2); + +// Run inference on two images. +const EmbeddingResult result_1 = image_embedder->Embed(*frame_buffer_1); +const EmbeddingResult result_2 = image_embedder->Embed(*frame_buffer_2); + +// Compute cosine similarity. +double similarity = ImageEmbedder::CosineSimilarity( + result_1.embeddings[0].feature_vector(), + result_2.embeddings[0].feature_vector()); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/vision/image_embedder.h) para ver mais opções de configuração do `ImageEmbedder`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote Pypi do TensorFlow Lite Support + +É possível instalar o pacote Pypi do TensorFlow Lite Support usando o seguinte comando: + +```sh +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +from tflite_support.task import vision + +# Initialization. +image_embedder = vision.ImageEmbedder.create_from_file(model_path) + +# Run inference on two images. +image_1 = vision.TensorImage.create_from_file('/path/to/image1.jpg') +result_1 = image_embedder.embed(image_1) +image_2 = vision.TensorImage.create_from_file('/path/to/image2.jpg') +result_2 = image_embedder.embed(image_2) + +# Compute cosine similarity. +feature_vector_1 = result_1.embeddings[0].feature_vector +feature_vector_2 = result_2.embeddings[0].feature_vector +similarity = image_embedder.cosine_similarity( + result_1.embeddings[0].feature_vector, result_2.embeddings[0].feature_vector) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/vision/image_embedder.py) para ver mais opções de configuração do `ImageEmbedder`. + +## Exemplo de resultados + +A similaridade por cosseno entre os vetores de características normalizados retorna uma pontuação entre -1 e 1. Quanto maior, melhor; uma similaridade por cosseno igual a 1 significa que os dois vetores são idênticos. + +``` +Cosine similarity: 0.954312 +``` + +Experimente a [ferramenta CLI simples de demonstração para ImageEmbedder](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop#imageembedder) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `ImageEmbedder` espera um modelo do TF Lite com os [metadados de modelo do TFLite](https://www.tensorflow.org/lite/models/convert/metadata), que são opcionais, mas extremamente recomendados. + +Os modelos compatíveis de incorporador de imagem devem atender aos seguintes requisitos: + +- Um tensor de imagem de entrada (kTfLiteUInt8/kTfLiteFloat32). + + - Imagem de entrada de tamanho `[batch x height x width x channels]` (lote x altura x largura x canais). + - Não há suporte à inferência de lote (`batch` precisa ser igual a 1). + - Só há suporte a entradas RGB (`channels` precisa ser igual a 3). + - Se o tipo for kTfLiteFloat32, as opções NormalizationOptions precisam ser adicionadas aos metadados para a normalização da entrada. + +- Pelo menos um tensor de saída (kTfLiteUInt8/kTfLiteFloat32). + + - Com `N` componentes que correspondem às `N` dimensões do vetor de características retornado para essa camada de saída. + - Duas ou quatro dimensões, ou seja, `[1 x N]` ou `[1 x 1 x 1 x N]`. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/image_searcher.md b/site/pt-br/lite/inference_with_metadata/task_library/image_searcher.md new file mode 100644 index 0000000000..4146354d5b --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/image_searcher.md @@ -0,0 +1,140 @@ +# Integração de pesquisadores de imagem + +A pesquisa de imagens permite procurar imagens similares em um banco de dados de imagens. Funciona pela incorporação de uma consulta em um vetor de alta dimensão que representa o significado semântico da consulta, seguida por pesquisa de similaridade em um índice personalizado e predefinido usando [ScaNN](https://github.com/google-research/google-research/tree/master/scann) (Scalable Nearest Neighbors). + +Ao contrário da [classificação de imagem](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier), expandir o número de itens que podem ser reconhecidos não requer treinar novamente todo o modelo. Novos itens podem ser adicionados simplesmente recriando o índice, o que permite trabalhar com bancos de imagens maiores (mais de 100 mil itens). + +Use a API `ImageSearcher` da biblioteca Task para implantar seu pesquisador de imagem personalizado em seus aplicativos para dispositivos móveis. + +## Principais recursos da API ImageSearcher + +- Recebe uma única imagem como entrada, realiza a extração de embeddings e procura o vizinho mais próximo no índice. + +- Processamento da imagem de entrada, incluindo rotação, redimensionamento e conversão do espaço de cores. + +- Região de interesse da imagem de entrada. + +## Pré-requisitos + +Antes de usar a API `ImageSearcher`, é preciso criar um índice com base no corpus personalizado de imagens que será pesquisado. Para fazer isso, basta usar a [API Model Maker Searcher](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/searcher) seguindo e adaptando o [tutorial](https://www.tensorflow.org/lite/models/modify/model_maker/text_searcher). + +Para isso, você precisará de: + +- Um modelo de incorporador de imagem do TF Lite, como [mobilenet v3](https://tfhub.dev/google/lite-model/imagenet/mobilenet_v3_small_100_224/feature_vector/5/metadata/1). Confira mais modelos de incorporador pré-treinados (também conhecidos como modelos de vetores) na [coleção Google Image Modules do TensorFlow Hub](https://tfhub.dev/google/collections/image/1). +- Seu corpus de imagens. + +Após essa etapa, você terá um modelo de pesquisador do TF Lite independente (por exemplo: `mobilenet_v3_searcher.tflite`), que é o modelo de incorporador de imagem original, com o índice incluído nos [metadados do modelo do TF Lite](https://www.tensorflow.org/lite/models/convert/metadata). + +## Execute a inferência no Java + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo de pesquisador `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite index file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.4' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.4' +} +``` + +### Etapa 2 – Use o modelo + +```java +// Initialization +ImageSearcherOptions options = + ImageSearcherOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setSearcherOptions( + SearcherOptions.builder().setL2Normalize(true).build()) + .build(); +ImageSearcher imageSearcher = + ImageSearcher.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = imageSearcher.search(image); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/vision/searcher/ImageSearcher.java) para ver mais opções de configuração do `ImageSearcher`. + +## Execute a inferência no C++ + +```c++ +// Initialization +ImageSearcherOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +options.mutable_embedding_options()->set_l2_normalize(true); +std::unique_ptr image_searcher = ImageSearcher::CreateFromOptions(options).value(); + +// Create input frame_buffer from your inputs, `image_data` and `image_dimension`. +// See more information here: tensorflow_lite_support/cc/task/vision/utils/frame_buffer_common_utils.h +std::unique_ptr frame_buffer = CreateFromRgbRawBuffer( + image_data, image_dimension); + +// Run inference +const SearchResult result = image_searcher->Search(*frame_buffer).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/vision/image_searcher.h) para ver mais opções de configuração do `ImageSearcher`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote Pypi do TensorFlow Lite Support + +É possível instalar o pacote Pypi do TensorFlow Lite Support usando o seguinte comando: + +```sh +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +from tflite_support.task import vision + +# Initialization +image_searcher = vision.ImageSearcher.create_from_file(model_path) + +# Run inference +image = vision.TensorImage.create_from_file(image_file) +result = image_searcher.search(image) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/vision/image_searcher.py) para ver mais opções de configuração do `ImageSearcher`. + +## Exemplo de resultados + +``` +Results: + Rank#0: + metadata: burger + distance: 0.13452 + Rank#1: + metadata: car + distance: 1.81935 + Rank#2: + metadata: bird + distance: 1.96617 + Rank#3: + metadata: dog + distance: 2.05610 + Rank#4: + metadata: cat + distance: 2.06347 +``` + +Experimente a [ferramenta CLI simples de demonstração para ImageSearcher](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop#imagesearcher) com seu próprio modelo e dados de teste. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/image_segmenter.md b/site/pt-br/lite/inference_with_metadata/task_library/image_segmenter.md new file mode 100644 index 0000000000..9dca84522f --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/image_segmenter.md @@ -0,0 +1,251 @@ +# Integração de segmentadores de imagem + +Os segmentadores de imagens preveem se cada pixel de uma imagem está associado a uma determinada classe. Isso é diferente da detecção de objetos, que detecta objetos em regiões retangulares, e da classificação de imagens, que classifica a imagem de forma geral. Confira mais informações sobre segmentadores de imagem na [visão geral da segmentação de imagens](../../examples/segmentation/overview). + +Use a API `ImageSegmenter` da biblioteca Task para implantar segmentadores de imagem personalizados ou pré-treinados em seus aplicativos para dispositivos móveis. + +## Principais recursos da API ImageSegmenter + +- Processamento da imagem de entrada, incluindo rotação, redimensionamento e conversão do espaço de cores. + +- Idioma do mapa de rótulos. + +- Dois tipos de saída, máscara de categoria e máscaras de confiança. + +- Rótulo colorido para fins de exibição. + +## Modelos de segmentador de imagem com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `ImageSegmenter`. + +- [Modelos pré-treinados de segmentação de imagens no TensorFlow Hub](https://tfhub.dev/tensorflow/collections/lite/task-library/image-segmenter/1). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +Confira o [aplicativo de referência para segmentação de imagens](https://github.com/tensorflow/examples/tree/master/lite/examples/image_segmentation/android/) para ver um exemplo de como usar o `ImageSegmenter` em um aplicativo para Android. + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-vision' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Use o modelo + +```java +// Initialization +ImageSegmenterOptions options = + ImageSegmenterOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setOutputType(OutputType.CONFIDENCE_MASK) + .build(); +ImageSegmenter imageSegmenter = + ImageSegmenter.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = imageSegmenter.segment(image); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/vision/segmenter/ImageSegmenter.java) para ver mais opções de configuração do `ImageSegmenter`. + +## Execute a inferência no iOS + +### Etapa 1 – Instale as dependências + +A biblioteca Task oferece suporte à instalação usando o CocoaPods, que precisa estar instalado em seu sistema. Confira as instruções no [guia de instalação do CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +Confira os detalhes de como adicionar pods a um projeto do Xcode no [guia do CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html). + +Adicione o pod `TensorFlowLiteTaskVision` ao Podfile. + +``` +target 'MyAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskVision' +end +``` + +Confirme se o modelo `.tflite` que você usará para inferência está presente no pacote do aplicativo. + +### Etapa 2 – Use o modelo + +#### Swift + +```swift +// Imports +import TensorFlowLiteTaskVision + +// Initialization +guard let modelPath = Bundle.main.path(forResource: "deeplabv3", + ofType: "tflite") else { return } + +let options = ImageSegmenterOptions(modelPath: modelPath) + +// Configure any additional options: +// options.outputType = OutputType.confidenceMasks + +let segmenter = try ImageSegmenter.segmenter(options: options) + +// Convert the input image to MLImage. +// There are other sources for MLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +guard let image = UIImage (named: "plane.jpg"), let mlImage = MLImage(image: image) else { return } + +// Run inference +let segmentationResult = try segmenter.segment(mlImage: mlImage) +``` + +#### Objective-C + +```objc +// Imports +#import + +// Initialization +NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"deeplabv3" ofType:@"tflite"]; + +TFLImageSegmenterOptions *options = + [[TFLImageSegmenterOptions alloc] initWithModelPath:modelPath]; + +// Configure any additional options: +// options.outputType = TFLOutputTypeConfidenceMasks; + +TFLImageSegmenter *segmenter = [TFLImageSegmenter imageSegmenterWithOptions:options + error:nil]; + +// Convert the input image to MLImage. +UIImage *image = [UIImage imageNamed:@"plane.jpg"]; + +// There are other sources for GMLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +GMLImage *gmlImage = [[GMLImage alloc] initWithImage:image]; + +// Run inference +TFLSegmentationResult *segmentationResult = + [segmenter segmentWithGMLImage:gmlImage error:nil]; +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/vision/sources/TFLImageSegmenter.h) para ver mais opções de configuração do `TFLImageSegmenter`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import vision +from tflite_support.task import core +from tflite_support.task import processor + +# Initialization +base_options = core.BaseOptions(file_name=model_path) +segmentation_options = processor.SegmentationOptions( + output_type=processor.SegmentationOptions.OutputType.CATEGORY_MASK) +options = vision.ImageSegmenterOptions(base_options=base_options, segmentation_options=segmentation_options) +segmenter = vision.ImageSegmenter.create_from_options(options) + +# Alternatively, you can create an image segmenter in the following manner: +# segmenter = vision.ImageSegmenter.create_from_file(model_path) + +# Run inference +image_file = vision.TensorImage.create_from_file(image_path) +segmentation_result = segmenter.segment(image_file) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/vision/image_segmenter.py) para ver mais opções de configuração do `ImageSegmenter`. + +## Execute a inferência no C++ + +```c++ +// Initialization +ImageSegmenterOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr image_segmenter = ImageSegmenter::CreateFromOptions(options).value(); + +// Create input frame_buffer from your inputs, `image_data` and `image_dimension`. +// See more information here: tensorflow_lite_support/cc/task/vision/utils/frame_buffer_common_utils.h +std::unique_ptr frame_buffer = CreateFromRgbRawBuffer( + image_data, image_dimension); + +// Run inference +const SegmentationResult result = image_segmenter->Segment(*frame_buffer).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/vision/image_segmenter.h) para ver mais opções de configuração do `ImageSegmenter`. + +## Exemplo de resultados + +Veja abaixo um exemplo dos resultados de segmentação de [deeplab_v3](https://tfhub.dev/tensorflow/lite-model/deeplabv3/1/metadata/1), um modelo genérico de segmentação disponível no TensorFlow Hub. + +plane + +``` +Color Legend: + (r: 000, g: 000, b: 000): + index : 0 + class name : background + (r: 128, g: 000, b: 000): + index : 1 + class name : aeroplane + +# (omitting multiple lines for conciseness) ... + + (r: 128, g: 192, b: 000): + index : 19 + class name : train + (r: 000, g: 064, b: 128): + index : 20 + class name : tv +Tip: use a color picker on the output PNG file to inspect the output mask with +this legend. +``` + +A máscara de categoria de segmentação deve ficar assim: + +segmentation-output + +Experimente a [ferramenta CLI simples de demonstração para ImageSegmenter](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop#image-segmenter) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `ImageSegmenter` espera um modelo do TF Lite com os [TF Lite Model Metadata](../../models/convert/metadata) (metadados do modelo) obrigatórios. Confira exemplos de criação dos metadados para segmentadores de imagem na [API Metadata Writer do TensorFlow Lite](../../models/convert/metadata_writer_tutorial.ipynb#image_segmenters) (gravação de metadados). + +- Um tensor de imagem de entrada (kTfLiteUInt8/kTfLiteFloat32). + + - Imagem de entrada de tamanho `[batch x height x width x channels]` (lote x altura x largura x canais). + - Não há suporte à inferência de lote (`batch` precisa ser igual a 1). + - Só há suporte a entradas RGB (`channels` precisa ser igual a 3). + - Se o tipo for kTfLiteFloat32, as opções NormalizationOptions precisam ser adicionadas aos metadados para a normalização da entrada. + +- Tensor de máscara de saída (kTfLiteUInt8/kTfLiteFloat32). + + - Tensor de tamanho `[batch x mask_height x mask_width x num_classes]`, em que `batch` precisa ser igual a 1, `mask_width` e `mask_height` são as dimensões das máscaras de segmentação geradas pelo modelo, e `num_classes` é o número de classes permitidas pelo modelo. + - Mapa(s) de rótulos (opcionais, mas recomendados), como AssociatedFiles com tipo TENSOR_AXIS_LABELS, contendo um rótulo por linha. O primeiro AssociatedFile (se houver) é usado para preencher o campo `label` (com nome igual a `class_name` no C++) dos resultados. O campo `display_name` é preenchido a partir do AssociatedFile (se houver) cujo idioma coincida com o campo `display_names_locale` das opções `ImageSegmenterOptions` usadas no momento da criação ("en" por padrão, ou seja, inglês). Se nenhum estiver disponível, somente o campo `index` dos resultados será preenchido. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/nl_classifier.md b/site/pt-br/lite/inference_with_metadata/task_library/nl_classifier.md new file mode 100644 index 0000000000..ea32c93cbc --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/nl_classifier.md @@ -0,0 +1,179 @@ +# Integração do classificador de linguagem natural + +A API `NLClassifier` da biblioteca Task classifica texto de entrada em diferentes categorias. É uma API versátil e configurável que pode lidar com a maioria dos modelos de classificação de texto. + +## Principais recursos da API NLClassifier + +- Recebe uma única string como entrada, faz a classificação com a string e gera como saída pares <Label, Score> (rótulo, pontuação) como resultados da classificação. + +- Tokenização opcional de expressão regular disponível para texto de entrada. + +- Configurável para se adaptar a diferentes modelos de classificação. + +## Modelos de NLClassifier com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `NLClassifier`. + +- Modelo de classificação do sentimento de avaliações de filmes. + +- Modelos com a especificação `average_word_vec` criados pelo [Model Maker do TensorFlow Lite para classificação de texto](https://www.tensorflow.org/lite/models/modify/model_maker/text_classification). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +Confira o [aplicativo de referência para classificação de texto](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/lib_task_api/src/main/java/org/tensorflow/lite/examples/textclassification/client/TextClassificationClient.java) para ver um exemplo de como usar o `NLClassifier` em um aplicativo para Android. + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-text:0.4.4' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.4' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Execute a inferência usando a API + +```java +// Initialization, use NLClassifierOptions to configure input and output tensors +NLClassifierOptions options = + NLClassifierOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setInputTensorName(INPUT_TENSOR_NAME) + .setOutputScoreTensorName(OUTPUT_SCORE_TENSOR_NAME) + .build(); +NLClassifier classifier = + NLClassifier.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = classifier.classify(input); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/text/nlclassifier/NLClassifier.java) para ver mais opções de configuração do `NLClassifier`. + +## Execute a inferência no Swift + +### Etapa 1 – Importe o CocoaPods + +Adicione o pod TensorFlowLiteTaskText ao Podfile. + +``` +target 'MySwiftAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskText', '~> 0.4.4' +end +``` + +### Etapa 2 – Execute a inferência usando a API + +```swift +// Initialization +var modelOptions:TFLNLClassifierOptions = TFLNLClassifierOptions() +modelOptions.inputTensorName = inputTensorName +modelOptions.outputScoreTensorName = outputScoreTensorName +let nlClassifier = TFLNLClassifier.nlClassifier( + modelPath: modelPath, + options: modelOptions) + +// Run inference +let categories = nlClassifier.classify(text: input) +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/text/nlclassifier/Sources/TFLNLClassifier.h). + +## Execute a inferência no C++ + +```c++ +// Initialization +NLClassifierOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr classifier = NLClassifier::CreateFromOptions(options).value(); + +// Run inference with your input, `input_text`. +std::vector categories = classifier->Classify(input_text); +``` + +Confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/nlclassifier/nl_classifier.h). + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import text + +# Initialization +classifier = text.NLClassifier.create_from_file(model_path) + +# Run inference +text_classification_result = classifier.classify(text) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/text/nl_classifier.py) para ver mais opções de configuração do `NLClassifier`. + +## Exemplo de resultados + +Veja um exemplo dos resultados da classificação do [modelo de avaliações de filmes](https://www.tensorflow.org/lite/examples/text_classification/overview). + +Input: "What a waste of my time." ("Que desperdício de tempo.") + +Saída: + +``` +category[0]: 'Negative' : '0.81313' +category[1]: 'Positive' : '0.18687' +``` + +Experimente a [ferramenta CLI simples de demonstração para NLClassifier](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/examples/task/text/desktop/README.md#nlclassifier) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +Dependendo do caso de uso, a API `NLClassifier` pode carregar um modelo do TF Lite com ou sem os [TF Lite Model Metadata](../../models/convert/metadata) (metadados de modelo). Confira exemplos de criação dos metadados para classificadores de linguagem natural na [API Metadata Writer do TensorFlow Lite](../../models/convert/metadata_writer_tutorial.ipynb#nl_classifiers) (gravação de metadados). + +Os modelos compatíveis devem atender aos seguintes requisitos: + +- Tensor de entrada: (kTfLiteString/kTfLiteInt32) + + - A entrada do modelo deve ser um tensor kTfLiteString de string de entrada não tratada ou um tensor kTfLiteInt32 para índices tokenizados de expressão regular de string de entrada não tratada. + - Se o tipo de entrada for kTfLiteString, não são necessários [metadados](../../models/convert/metadata) para o modelo. + - Se o tipo de entrada for kTfLiteInt32, um `RegexTokenizer` precisa ser configurado nos [metadados](https://www.tensorflow.org/lite/models/convert/metadata_writer_tutorial#natural_language_classifiers) do tensor de entrada. + +- Tensor de pontuações de saída: (kTfLiteUInt8/kTfLiteInt8/kTfLiteInt16/kTfLiteFloat32/kTfLiteFloat64) + + - Tensor de saída obrigatório para a pontuação de cada categoria classificada. + + - Se o tipo for um dos tipos Int, faça a dequantização para double/float para as plataformas correspondentes. + + - Pode ter um arquivo associado opcional nos [metadados](../../models/convert/metadata) correspondentes do tensor de saída para rótulos de categoria. O arquivo deve ser sem formação, com um rótulo por linha, e o número de rótulos deve coincidir com o número de categorias das saídas do modelo. Confira o [arquivo de rótulos de exemplo](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/labels.txt). + +- Tensor de rótulos de saída: (kTfLiteString/kTfLiteInt32) + + - Tensor de saída opcional para o rótulo de cada categoria. Deve ter o mesmo tamanho que o tensor de pontuações de saída. Se este tensor não estiver presente, a API usará alguns índices como nomes de classe. + + - Será ignorado se o arquivo de rótulos associado estiver presente nos metadados do tensor de pontuações de saída. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/object_detector.md b/site/pt-br/lite/inference_with_metadata/task_library/object_detector.md new file mode 100644 index 0000000000..bd34baab1b --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/object_detector.md @@ -0,0 +1,267 @@ +# Integração de detectores de objetos + +Os detectores de objetos conseguem identificar qual objeto dentre um conjunto conhecido de objetos pode estar presente e fornecem informações sobre suas posições na imagem ou stream de vídeo fornecido. Um detector de objetos é treinado para detectar a presença e a localização de diversas classes de objetos. Por exemplo: um modelo pode ser treinado com imagens que contenham diversos pedaços de frutas, junto com um *rótulo* que especifica a classe da fruta representada (como maçã, banana ou morango), além de dados especificando onde cada objeto aparece na imagem. Confira mais informações sobre detectores de objetos na [introdução à detecção de objetos](../../examples/object_detection/overview). + +Use a API `ObjectDetector` da biblioteca Task para implantar detectores de objetos personalizados ou pré-treinados em seus aplicativos para dispositivos móveis. + +## Principais recursos da API ObjectDetector + +- Processamento da imagem de entrada, incluindo rotação, redimensionamento e conversão do espaço de cores. + +- Idioma do mapa de rótulos. + +- Limite de pontuação para filtrar resultados. + +- Resultados de detecção top-k. + +- Lista de permissão e proibição de rótulos. + +## Modelos de detectores de objetos com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `ObjectDetector`. + +- [Modelos de detecção de objetos pré-treinados no TensorFlow Hub](https://tfhub.dev/tensorflow/collections/lite/task-library/object-detector/1). + +- Modelos criados pela [detecção de objetos do AutoML Vision Edge](https://cloud.google.com/vision/automl/object-detection/docs). + +- Modelos criados pelo [Model Maker do TensorFlow Lite para detecção de objetos](https://www.tensorflow.org/lite/guide/model_maker). + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no Java + +Confira o [aplicativo de referência para detecção de objetos](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android/) para ver um exemplo de como usar o `ObjectDetector` em um aplicativo para Android. + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-vision' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +Observação: a partir da versão 4.1 do plug-in do Gradle para Android, o arquivo .tflite será adicionado à lista noCompress (não compacte) por padrão, e a opção aaptOptions acima não é mais necessária. + +### Etapa 2 – Use o modelo + +```java +// Initialization +ObjectDetectorOptions options = + ObjectDetectorOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setMaxResults(1) + .build(); +ObjectDetector objectDetector = + ObjectDetector.createFromFileAndOptions( + context, modelFile, options); + +// Run inference +List results = objectDetector.detect(image); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/vision/detector/ObjectDetector.java) para ver mais opções de configuração do `ObjectDetector`. + +## Execute a inferência no iOS + +### Etapa 1 – Instale as dependências + +A biblioteca Task oferece suporte à instalação usando o CocoaPods, que precisa estar instalado em seu sistema. Confira as instruções no [guia de instalação do CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started). + +Confira os detalhes de como adicionar pods a um projeto do Xcode no [guia do CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html). + +Adicione o pod `TensorFlowLiteTaskVision` ao Podfile. + +``` +target 'MyAppWithTaskAPI' do + use_frameworks! + pod 'TensorFlowLiteTaskVision' +end +``` + +Confirme se o modelo `.tflite` que você usará para inferência está presente no pacote do aplicativo. + +### Etapa 2 – Use o modelo + +#### Swift + +```swift +// Imports +import TensorFlowLiteTaskVision + +// Initialization +guard let modelPath = Bundle.main.path(forResource: "ssd_mobilenet_v1", + ofType: "tflite") else { return } + +let options = ObjectDetectorOptions(modelPath: modelPath) + +// Configure any additional options: +// options.classificationOptions.maxResults = 3 + +let detector = try ObjectDetector.detector(options: options) + +// Convert the input image to MLImage. +// There are other sources for MLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +guard let image = UIImage (named: "cats_and_dogs.jpg"), let mlImage = MLImage(image: image) else { return } + +// Run inference +let detectionResult = try detector.detect(mlImage: mlImage) +``` + +#### Objective-C + +```objc +// Imports +#import + +// Initialization +NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"ssd_mobilenet_v1" ofType:@"tflite"]; + +TFLObjectDetectorOptions *options = [[TFLObjectDetectorOptions alloc] initWithModelPath:modelPath]; + +// Configure any additional options: +// options.classificationOptions.maxResults = 3; + +TFLObjectDetector *detector = [TFLObjectDetector objectDetectorWithOptions:options + error:nil]; + +// Convert the input image to MLImage. +UIImage *image = [UIImage imageNamed:@"dogs.jpg"]; + +// There are other sources for GMLImage. For more details, please see: +// https://developers.google.com/ml-kit/reference/ios/mlimage/api/reference/Classes/GMLImage +GMLImage *gmlImage = [[GMLImage alloc] initWithImage:image]; + +// Run inference +TFLDetectionResult *detectionResult = [detector detectWithGMLImage:gmlImage error:nil]; +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/task/vision/sources/TFLObjectDetector.h) para ver mais opções de configuração do `TFLObjectDetector`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote via pip + +``` +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +# Imports +from tflite_support.task import vision +from tflite_support.task import core +from tflite_support.task import processor + +# Initialization +base_options = core.BaseOptions(file_name=model_path) +detection_options = processor.DetectionOptions(max_results=2) +options = vision.ObjectDetectorOptions(base_options=base_options, detection_options=detection_options) +detector = vision.ObjectDetector.create_from_options(options) + +# Alternatively, you can create an object detector in the following manner: +# detector = vision.ObjectDetector.create_from_file(model_path) + +# Run inference +image = vision.TensorImage.create_from_file(image_path) +detection_result = detector.detect(image) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/vision/object_detector.py) para ver mais opções de configuração do `ObjectDetector`. + +## Execute a inferência no C++ + +```c++ +// Initialization +ObjectDetectorOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr object_detector = ObjectDetector::CreateFromOptions(options).value(); + +// Create input frame_buffer from your inputs, `image_data` and `image_dimension`. +// See more information here: tensorflow_lite_support/cc/task/vision/utils/frame_buffer_common_utils.h +std::unique_ptr frame_buffer = CreateFromRgbRawBuffer( + image_data, image_dimension); + +// Run inference +const DetectionResult result = object_detector->Detect(*frame_buffer).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/vision/object_detector.h) para ver mais opções de configuração do `ObjectDetector`. + +## Exemplo de resultados + +Veja abaixo um exemplo dos resultados de detecção de [ssd mobilenet v1](https://tfhub.dev/tensorflow/lite-model/ssd_mobilenet_v1/1/metadata/1) do TensorFlow Hub. + +dogs + +``` +Results: + Detection #0 (red): + Box: (x: 355, y: 133, w: 190, h: 206) + Top-1 class: + index : 17 + score : 0.73828 + class name : dog + Detection #1 (green): + Box: (x: 103, y: 15, w: 138, h: 369) + Top-1 class: + index : 17 + score : 0.73047 + class name : dog +``` + +Renderize os retângulos limítrofes na imagem de entrada: + +detection output + +Experimente a [ferramenta CLI simples de demonstração para ObjectDetector](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop#object-detector) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `ObjectDetector` espera um modelo do TF Lite com os [TF Lite Model Metadata](../../models/convert/metadata) (metadados de modelo) obrigatórios. Confira exemplos de criação dos metadados para detectores de objetos na [API Metadata Writer do TensorFlow Lite](../../models/convert/metadata_writer_tutorial.ipynb#object_detectors) (gravação de metadados). + +Os modelos compatíveis de detecção de objetos devem atender aos seguintes requisitos: + +- Tensor de imagem de entrada: (kTfLiteUInt8/kTfLiteFloat32). + + - Imagem de entrada de tamanho `[batch x height x width x channels]` (lote x altura x largura x canais). + - Não há suporte à inferência de lote (`batch` precisa ser igual a 1). + - Só há suporte a entradas RGB (`channels` precisa ser igual a 3). + - Se o tipo for kTfLiteFloat32, as opções NormalizationOptions precisam ser adicionadas aos metadados para a normalização da entrada. + +- Os tensores de saída devem ser as 4 saídas de uma operação `DetectionPostProcess`: + + - Tensor de localizações (kTfLiteFloat32) + + - Tensor de tamanho `[1 x num_results x 4]`, em que o array interno representa os retângulos limítrofes no formato [top, left, right, bottom] (superior, esquerda, direita, inferior). + - É preciso incluir BoundingBoxProperties nos metadados e especificar `type=BOUNDARIES` e `coordinate_type=RATIO. + + - Tensor de classes (kTfLiteFloat32) + + - Tensor de tamanho `[1 x num_results]`, em que cada valor representa o índice Int de uma classe. + - Mapa(s) de rótulos (opcionais, mas recomendados), podem ser incluídos como AssociatedFiles com tipo TENSOR_VALUE_LABELS, contendo um rótulo por linha. Confira o [arquivo de rótulos de exemplo](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/labelmap.txt). O primeiro AssociatedFile (se houver) é usado para preencher o campo `class_name` dos resultados. O campo `display_name` é preenchido a partir do AssociatedFile (se houver) cujo idioma coincida com o campo `display_names_locale` das opções `ObjectDetectorOptions` usadas no momento da criação ("en" por padrão, ou seja, inglês). Se nenhum estiver disponível, somente o campo `index` dos resultados será preenchido. + + - Tensor de pontuações (kTfLiteFloat32) + + - Tensor de tamanho `[1 x num_results]`, em que cada valor representa a pontuação do objeto detectado. + + - Número de tensores de detecção (kTfLiteFloat32) + + - num_results Int como um tensor de tamanho `[1]`. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/overview.md b/site/pt-br/lite/inference_with_metadata/task_library/overview.md new file mode 100644 index 0000000000..6cb0558cae --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/overview.md @@ -0,0 +1,242 @@ +# Biblioteca Task do TensorFlow Lite + +A biblioteca Task do TensorFlow Lite contém um conjunto de bibliotecas específicas a tarefas poderoso e fácil de usar para os desenvolvedores de apps criarem experiências de aprendizado de máquina com o TF Lite. Ela fornece interfaces de modelo prontas para uso e otimizadas para tarefas de aprendizado de máquina populares, como classificação de imagens, pergunta e resposta, etc. As interfaces de modelo são criadas especialmente para cada tarefa alcançar o melhor desempenho e usabilidade. A biblioteca de tarefas funciona em várias plataformas e é compatível com o Java, C++ e Swift. + +## O que esperar da Task Library + +- **APIs organizadas e bem definidas, que podem ser utilizadas por quem não é especialista em aprendizado de máquina**
A inferência pode ser feita com apenas 5 linhas de código. Utilize as APIs avançadas e fáceis de usar da biblioteca Task como blocos de construção para desenvolver aprendizado de máquina com o TF Lite facilmente em dispositivos móveis. + +- **Processamento de dados complexo, mas comum**
A biblioteca oferece suporte a lógicas comuns de processamento de linguagem natural e visão para converter entre seus dados e o formato de dados exigido pelo modelo. Oferece a mesma lógica de processamento compartilhável para treinamento e inferência. + +- **Alto ganho de desempenho**
O processamento dos dados pode levar apena alguns milissegundos, garantindo uma inferência rápida ao usar o TensorFlow Lite. + +- **Extensibilidade e personalização**
Você pode aproveitar todos os benefícios oferecidos pela infraestrutura da biblioteca de tarefas e compilar facilmente suas próprias APIs de inferência para Android e iOS. + +## Tarefas com suporte + +Veja abaixo a lista de tarefas com suporte. Essa lista deverá crescer à medida que adicionarmos mais casos de uso. + +- **APIs de visão** + + - [ImageClassifier](image_classifier.md) + - [ObjectDetector](object_detector.md) + - [ImageSegmenter](image_segmenter.md) + - [ImageSearcher](image_searcher.md) + - [ImageEmbedder](image_embedder.md) + +- **APIs de linguagem natural (NL)** + + - [NLClassifier](nl_classifier.md) + - [BertNLClassifier](bert_nl_classifier.md) + - [BertQuestionAnswerer](bert_question_answerer.md) + - [TextSearcher](text_searcher.md) + - [TextEmbedder](text_embedder.md) + +- **APIs de áudio** + + - [AudioClassifier](audio_classifier.md) + +- **APIs personalizadas** + + - Estenda a infraestrutura da API de tarefas e crie [APIs personalizadas](customized_task_api.md). + +## Execute a biblioteca Task com delegados + +Os [delegados](https://www.tensorflow.org/lite/performance/delegates) possibilitam a aceleração de hardware para modelos do TensorFlow Lite por meio do uso de aceleradores no dispositivo, como [GPU](https://www.tensorflow.org/lite/performance/gpu) e [Coral Edge TPU](https://coral.ai/). Ao usá-los para operações de redes neurais, há diversos benefícios com relação à latência e à eficiência energética. Por exemplo: as GPUs podem oferecer uma [melhoria de até 5 vezes](https://blog.tensorflow.org/2020/08/faster-mobile-gpu-inference-with-opencl.html) da latência em dispositivos móveis e inferência em Coral Edge TPUs [10 vezes mais rápida](https://coral.ai/docs/edgetpu/benchmarks/) do que em CPUs de computadores. + +A biblioteca Task conta com fácil configuração e opções de fallback para o uso de delegados. Atualmente, a API de tarefas oferece suporte aos seguintes aceleradores: + +- Android + - [GPU](https://www.tensorflow.org/lite/performance/gpu): Java/C++ + - [NNAPI](https://www.tensorflow.org/lite/android/delegates/nnapi): Java/C++ + - [Hexagon](https://www.tensorflow.org/lite/android/delegates/hexagon): C++ +- Linux/Mac + - [Coral Edge TPU](https://coral.ai/): C++ +- iOS + - [Delegado Core ML](https://www.tensorflow.org/lite/performance/coreml_delegate): C++ + +Em breve, teremos suporte à aceleração na API de tarefas para Swift/Web. + +### Exemplo de uso de GPU no Android no Java + +Etapa 1 – Adicione a biblioteca de plug-in de delegado GPU ao arquivo `build.gradle` do seu módulo: + +```java +dependencies { + // Import Task Library dependency for vision, text, or audio. + + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin' +} +``` + +Observação: por padrão, a NNAPI vem com os alvos da biblioteca Task para visão, texto e áudio. + +Etapa 2 – Configure o delegado nas opções da tarefa com as [BaseOptions](https://www.tensorflow.org/lite/api_docs/java/org/tensorflow/lite/task/core/BaseOptions.Builder). Por exemplo: você pode configurar a GPU em `ObjectDetector` da seguinte forma: + +```java +// Turn on GPU delegation. +BaseOptions baseOptions = BaseOptions.builder().useGpu().build(); +// Configure other options in ObjectDetector +ObjectDetectorOptions options = + ObjectDetectorOptions.builder() + .setBaseOptions(baseOptions) + .setMaxResults(1) + .build(); + +// Create ObjectDetector from options. +ObjectDetector objectDetector = + ObjectDetector.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = objectDetector.detect(image); +``` + +### Exemplo de uso de GPU no Android no C++ + +Etapa 1 – Adicione a dependência do plug-in de delegado GPU ao alvo da build do Bazel da seguinte forma: + +``` +deps = [ + "//tensorflow_lite_support/acceleration/configuration:gpu_plugin", # for GPU +] +``` + +Observação: o alvo `gpu_plugin` fica separado do [alvo de delegado GPU](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/gpu). `gpu_plugin` encapsula o alvo de delegado GPU e pode proporcionar uma proteção, ou seja, fazer o fallback para o caminho de CPU do TF Lite em caso de erros de delegação. + +Confira outras opções de delegado: + +``` +"//tensorflow_lite_support/acceleration/configuration:nnapi_plugin", # for NNAPI +"//tensorflow_lite_support/acceleration/configuration:hexagon_plugin", # for Hexagon +``` + +Etapa 2 – Configure o delegado nas opções da tarefa. Por exemplo: você pode configurar a GPU em `BertQuestionAnswerer` da seguinte forma: + +```c++ +// Initialization +BertQuestionAnswererOptions options; +// Load the TFLite model. +auto base_options = options.mutable_base_options(); +base_options->mutable_model_file()->set_file_name(model_file); +// Turn on GPU delegation. +auto tflite_settings = base_options->mutable_compute_settings()->mutable_tflite_settings(); +tflite_settings->set_delegate(Delegate::GPU); +// (optional) Turn on automatical fallback to TFLite CPU path on delegation errors. +tflite_settings->mutable_fallback_settings()->set_allow_automatic_fallback_on_execution_error(true); + +// Create QuestionAnswerer from options. +std::unique_ptr answerer = BertQuestionAnswerer::CreateFromOptions(options).value(); + +// Run inference on GPU. +std::vector results = answerer->Answer(context_of_question, question_to_ask); +``` + +Veja configurações de acelerador mais avançadas [aqui](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/acceleration/configuration/configuration.proto). + +### Exemplo de uso do Coral Edge TPU no Python + +Configure o Coral Edge TPU nas opções base da tarefa. Por exemplo: você pode configurar o Coral Edge TPU em `ImageClassifier` da seguinte forma: + +```python +# Imports +from tflite_support.task import vision +from tflite_support.task import core + +# Initialize options and turn on Coral Edge TPU delegation. +base_options = core.BaseOptions(file_name=model_path, use_coral=True) +options = vision.ImageClassifierOptions(base_options=base_options) + +# Create ImageClassifier from options. +classifier = vision.ImageClassifier.create_from_options(options) + +# Run inference on Coral Edge TPU. +image = vision.TensorImage.create_from_file(image_path) +classification_result = classifier.classify(image) +``` + +### Exemplo de uso do Coral Edge TPU no C++ + +Etapa 1 – Adicione a dependência do plug-in de delegado Coral Edge TPU ao alvo da build do Bazel da seguinte forma: + +``` +deps = [ + "//tensorflow_lite_support/acceleration/configuration:edgetpu_coral_plugin", # for Coral Edge TPU +] +``` + +Configure o Coral Edge TPU nas opções da tarefa. Por exemplo: você pode configurar o Coral Edge TPU em `ImageClassifier` da seguinte forma: + +```c++ +// Initialization +ImageClassifierOptions options; +// Load the TFLite model. +options.mutable_base_options()->mutable_model_file()->set_file_name(model_file); +// Turn on Coral Edge TPU delegation. +options.mutable_base_options()->mutable_compute_settings()->mutable_tflite_settings()->set_delegate(Delegate::EDGETPU_CORAL); +// Create ImageClassifier from options. +std::unique_ptr image_classifier = ImageClassifier::CreateFromOptions(options).value(); + +// Run inference on Coral Edge TPU. +const ClassificationResult result = image_classifier->Classify(*frame_buffer).value(); +``` + +Etapa 3 – Instale o pacote `libusb-1.0-0-dev` conforme indicado abaixo. Caso já esteja instalado, prossiga para a próxima etapa. + +```bash +# On the Linux +sudo apt-get install libusb-1.0-0-dev + +# On the macOS +port install libusb +# or +brew install libusb +``` + +Etapa 4 – Compile com as configurações abaixo no comando do Bazel: + +```bash +# On the Linux +--define darwinn_portable=1 --linkopt=-lusb-1.0 + +# On the macOS, add '--linkopt=-lusb-1.0 --linkopt=-L/opt/local/lib/' if you are +# using MacPorts or '--linkopt=-lusb-1.0 --linkopt=-L/opt/homebrew/lib' if you +# are using Homebrew. +--define darwinn_portable=1 --linkopt=-L/opt/local/lib/ --linkopt=-lusb-1.0 + +# Windows is not supported yet. +``` + +Experimente a [ferramenta CLI de demonstração da biblioteca Task](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/vision/desktop) em seus dispositivos Coral Edge TPU. Veja mais detalhes nos [modelos pré-treinados para Edge TPU](https://coral.ai/models/) e nas [configurações avançadas de Edge TPU](https://github.com/tensorflow/tensorflow/blob/4d999fda8d68adfdfacd4d0098124f1b2ea57927/tensorflow/lite/acceleration/configuration/configuration.proto#L594). + +### Exemplo de uso de delegado Core ML no C++ + +Veja um exemplo completo no [teste de delegado Core ML para classificador de imagem](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/ios/test/task/vision/image_classifier/TFLImageClassifierCoreMLDelegateTest.mm). + +Etapa 1 – Adicione a dependência do plug-in de delegado Core ML ao alvo da build do Bazel da seguinte forma: + +``` +deps = [ + "//tensorflow_lite_support/acceleration/configuration:coreml_plugin", # for Core ML Delegate +] +``` + +Etapa 2 – Configure o delegado Core ML nas opções da tarefa. Por exemplo: você pode configurar o delegado Core ML em `ImageClassifier` da seguinte forma: + +```c++ +// Initialization +ImageClassifierOptions options; +// Load the TFLite model. +options.mutable_base_options()->mutable_model_file()->set_file_name(model_file); +// Turn on Core ML delegation. +options.mutable_base_options()->mutable_compute_settings()->mutable_tflite_settings()->set_delegate(::tflite::proto::Delegate::CORE_ML); +// Set DEVICES_ALL to enable Core ML delegation on any device (in contrast to +// DEVICES_WITH_NEURAL_ENGINE which creates Core ML delegate only on devices +// with Apple Neural Engine). +options.mutable_base_options()->mutable_compute_settings()->mutable_tflite_settings()->mutable_coreml_settings()->set_enabled_devices(::tflite::proto::CoreMLSettings::DEVICES_ALL); +// Create ImageClassifier from options. +std::unique_ptr image_classifier = ImageClassifier::CreateFromOptions(options).value(); + +// Run inference on Core ML. +const ClassificationResult result = image_classifier->Classify(*frame_buffer).value(); +``` diff --git a/site/pt-br/lite/inference_with_metadata/task_library/text_embedder.md b/site/pt-br/lite/inference_with_metadata/task_library/text_embedder.md new file mode 100644 index 0000000000..a7127b550a --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/text_embedder.md @@ -0,0 +1,127 @@ +# Integração de incorporadores de texto + +Os incorporadores de texto permitem incorporar texto a um vetor de características de alta dimensão que representa seu significado semântico. Em seguida, esse vetor pode ser comparado ao vetor de características de outros textos para avaliar a similaridade semântica. + +Ao contrário da [pesquisa de texto](https://www.tensorflow.org/lite/inference_with_metadata/task_library/text_searcher), o incorporador de texto permite computar a similaridade entre textos em tempo real em vez de pesquisar em um índice predefinido criado a partir de um corpus. + +Use a API `TextEmbedder` da biblioteca Task para implantar seu incorporador de texto personalizado em seus aplicativos para dispositivos móveis. + +## Principais recursos da API TextEmbedder + +- Processamento do texto de entrada, incluindo as tokenizações [Wordpiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/bert_tokenizer.h) ou [Sentencepiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/sentencepiece_tokenizer.h) do texto de entrada fora do grafo. + +- Função utilitária integrada para computar a [similaridade por cosseno](https://en.wikipedia.org/wiki/Cosine_similarity) entre os vetores de características. + +## Modelos de incorporador de texto com suporte + +Temos garantias de que os modelos abaixo são compatíveis com a API `TextEmbedder`. + +- [Modelo Universal Sentence Encoder do TF Lite no TensorFlow Hub](https://tfhub.dev/google/lite-model/universal-sentence-encoder-qa-ondevice/1) + +- Modelos personalizados que atendam aos [requisitos de compatibilidade de modelos](#model-compatibility-requirements). + +## Execute a inferência no C++ + +```c++ +// Initialization. +TextEmbedderOptions options: +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +std::unique_ptr text_embedder = TextEmbedder::CreateFromOptions(options).value(); + +// Run inference with your two inputs, `input_text1` and `input_text2`. +const EmbeddingResult result_1 = text_embedder->Embed(input_text1); +const EmbeddingResult result_2 = text_embedder->Embed(input_text2); + +// Compute cosine similarity. +double similarity = TextEmbedder::CosineSimilarity( + result_1.embeddings[0].feature_vector() + result_2.embeddings[0].feature_vector()); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/text_embedder.h) para ver mais opções de configuração do `TextEmbedder`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote Pypi do TensorFlow Lite Support + +É possível instalar o pacote Pypi do TensorFlow Lite Support usando o seguinte comando: + +```sh +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +from tflite_support.task import text + +# Initialization. +text_embedder = text.TextEmbedder.create_from_file(model_path) + +# Run inference on two texts. +result_1 = text_embedder.embed(text_1) +result_2 = text_embedder.embed(text_2) + +# Compute cosine similarity. +feature_vector_1 = result_1.embeddings[0].feature_vector +feature_vector_2 = result_2.embeddings[0].feature_vector +similarity = text_embedder.cosine_similarity( + result_1.embeddings[0].feature_vector, result_2.embeddings[0].feature_vector) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/text/text_embedder.py) para ver mais opções de configuração do `TextEmbedder`. + +## Exemplo de resultados + +A similaridade por cosseno entre os vetores de características normalizados retorna uma pontuação entre -1 e 1. Quanto maior, melhor; uma similaridade por cosseno igual a 1 significa que os dois vetores são idênticos. + +``` +Cosine similarity: 0.954312 +``` + +Experimente a [ferramenta CLI simples de demonstração para TextEmbedder](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/text/desktop#textembedder) com seu próprio modelo e dados de teste. + +## Requisitos de compatibilidade de modelos + +A API `TextEmbedder` espera um modelo do TF Lite com os [TF Lite Model Metadata](https://www.tensorflow.org/lite/models/convert/metadata) (metadados de modelo) obrigatórios. + +Há suporte a três tipos principais de modelos: + +- Modelos baseados em BERT (confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/utils/bert_utils.h)): + + - Exatamente 3 tensores de entrada (kTfLiteString): + + - Tensor de IDs, com nome de metadados "ids". + - Tensor de máscara, com nome de metadados "mask". + - Tensor de IDs de segmentos, com nome de metadados "segment_ids". + + - Exatamente um tensor de saída (kTfLiteUInt8/kTfLiteFloat32): + + - Com `N` componentes que correspondem às `N` dimensões do vetor de características retornado para essa camada de saída. + - Duas ou quatro dimensões, ou seja, `[1 x N]` ou `[1 x 1 x 1 x N]`. + + - input_process_units para o tokenizador Wordpiece/Sentencepiece. + +- Modelos baseados em Universal Sentence Encoder (confira mais detalhes no [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/utils/universal_sentence_encoder_utils.h)): + + - Exatamente 3 tensores de entrada (kTfLiteString): + + - Tensor de texto da consulta, com nome de metadados "inp_text". + - Tensor de contexto da resposta, com nome de metadados "res_context". + - Tensor de texto da resposta, com nome de metadados "res_text". + + - Exatamente dois tensores de saída (kTfLiteUInt8/kTfLiteFloat32): + + - Tensor de codificação da consulta, com nome de metadados "query_encoding". + - Tensor de codificação da resposta, com nome de metadados "response_encoding". + - Ambos com `N` componentes que correspondem às `N` dimensões do vetor de características retornado para essa camada de saída. + - Ambos com duas ou quatro dimensões, ou seja, `[1 x N]` ou `[1 x 1 x 1 x N]`. + +- Qualquer modelo de incorporador de texto com: + + - Um tensor de texto de entrada (kTfLiteString) + + - Pelo menos um tensor de embedding de saída (kTfLiteUInt8/kTfLiteFloat32) + + - Com `N` componentes que correspondem às `N` dimensões do vetor de características retornado para essa camada de saída. + - Duas ou quatro dimensões, ou seja, `[1 x N]` ou `[1 x 1 x 1 x N]`. diff --git a/site/pt-br/lite/inference_with_metadata/task_library/text_searcher.md b/site/pt-br/lite/inference_with_metadata/task_library/text_searcher.md new file mode 100644 index 0000000000..0c65fde0d0 --- /dev/null +++ b/site/pt-br/lite/inference_with_metadata/task_library/text_searcher.md @@ -0,0 +1,134 @@ +# Integração de pesquisadores de texto + +A pesquisa de texto permite procurar textos semanticamente similares em um corpus. Funciona pela incorporação de uma consulta em um vetor de alta dimensão que representa o significado semântico da consulta, seguida por pesquisa de similaridade em um índice personalizado e predefinido usando [ScaNN](https://github.com/google-research/google-research/tree/master/scann) (Scalable Nearest Neighbors). + +Ao contrário da classificação de texto (como o [classificador de linguagem natural BERT](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier)), expandir o número de itens que podem ser reconhecidos não requer treinar novamente todo o modelo. Novos itens podem ser adicionados simplesmente recriando o índice, o que permite trabalhar com corpus maiores (mais de 100 mil itens). + +Use a API `TextSearcher` da biblioteca Task para implantar seu pesquisador de texto personalizado em seus aplicativos para dispositivos móveis. + +## Principais recursos da API TextSearcher + +- Recebe um único texto como entrada, realiza a extração de embeddings e procura o vizinho mais próximo no índice. + +- Processamento do texto de entrada, incluindo as tokenizações [Wordpiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/bert_tokenizer.h) ou [Sentencepiece](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/text/tokenizers/sentencepiece_tokenizer.h) do texto de entrada fora do grafo. + +## Pré-requisitos + +Antes de usar a API `TextSearcher`, é preciso criar um índice com base no corpus personalizado de texto que será pesquisado. Para fazer isso, basta usar a [API Model Maker Searcher](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/searcher) seguindo e adaptando o [tutorial](https://www.tensorflow.org/lite/models/modify/model_maker/text_searcher). + +Para isso, você precisará de: + +- Um modelo de incorporador de texto do TF Lite, como Universal Sentence Encoder. Por exemplo: + - O [modelo](https://storage.googleapis.com/download.tensorflow.org/models/tflite_support/searcher/text_to_image_blogpost/text_embedder.tflite) treinado novamente neste [Colab](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/examples/colab/on_device_text_to_image_search_tflite.ipynb), que é otimizado para inferência no dispositivo. Ele leva somente 6 milissegundos para consultar uma string de texto no Pixel 6. + - O modelo [quantizado](https://tfhub.dev/google/lite-model/universal-sentence-encoder-qa-ondevice/1), que é menor do que o acima, mas leva 38 milissegundos para cada embedding. +- Seu corpus de texto. + +Após essa etapa, você terá um modelo de pesquisador do TF Lite independente (por exemplo: `mobilenet_v3_searcher.tflite`), que é o modelo de incorporador de texto original, com o índice incluído nos [TF Lite Model Metadata](https://www.tensorflow.org/lite/models/convert/metadata) (metadados do modelo). + +## Execute a inferência no Java + +### Etapa 1 – Importe a dependência e outras configurações do Gradle + +Copie o arquivo do modelo de pesquisador `.tflite` para o diretório de ativos do módulo para Android no qual o modelo será executado. Especifique que o arquivo não deve ser compactado e adicione a biblioteca do TensorFlow Lite ao arquivo `build.gradle` do modelo: + +```java +android { + // Other settings + + // Specify tflite index file should not be compressed for the app apk + aaptOptions { + noCompress "tflite" + } + +} + +dependencies { + // Other dependencies + + // Import the Task Vision Library dependency (NNAPI is included) + implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.4' + // Import the GPU delegate plugin Library for GPU inference + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.4' +} +``` + +### Etapa 2 – Use o modelo + +```java +// Initialization +TextSearcherOptions options = + TextSearcherOptions.builder() + .setBaseOptions(BaseOptions.builder().useGpu().build()) + .setSearcherOptions( + SearcherOptions.builder().setL2Normalize(true).build()) + .build(); +TextSearcher textSearcher = + textSearcher.createFromFileAndOptions(context, modelFile, options); + +// Run inference +List results = textSearcher.search(text); +``` + +Confira o [código-fonte e o javadoc](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/java/src/java/org/tensorflow/lite/task/text/searcher/TextSearcher.java) para ver mais opções de configuração do `TextSearcher`. + +## Execute a inferência no C++ + +```c++ +// Initialization +TextSearcherOptions options; +options.mutable_base_options()->mutable_model_file()->set_file_name(model_path); +options.mutable_embedding_options()->set_l2_normalize(true); +std::unique_ptr text_searcher = TextSearcher::CreateFromOptions(options).value(); + +// Run inference with your input, `input_text`. +const SearchResult result = text_searcher->Search(input_text).value(); +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/cc/task/text/text_searcher.h) para ver mais opções de configuração do `TextSearcher`. + +## Execute a inferência no Python + +### Etapa 1 – Instale o pacote Pypi do TensorFlow Lite Support + +É possível instalar o pacote Pypi do TensorFlow Lite Support usando o seguinte comando: + +```sh +pip install tflite-support +``` + +### Etapa 2 – Use o modelo + +```python +from tflite_support.task import text + +# Initialization +text_searcher = text.TextSearcher.create_from_file(model_path) + +# Run inference +result = text_searcher.search(text) +``` + +Confira o [código-fonte](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/python/task/text/text_searcher.py) para ver mais opções de configuração do `TextSearcher`. + +## Exemplo de resultados + +``` +Results: + Rank#0: + metadata: The sun was shining on that day. + distance: 0.04618 + Rank#1: + metadata: It was a sunny day. + distance: 0.10856 + Rank#2: + metadata: The weather was excellent. + distance: 0.15223 + Rank#3: + metadata: The cat is chasing after the mouse. + distance: 0.34271 + Rank#4: + metadata: He was very happy with his newly bought car. + distance: 0.37703 +``` + +Experimente a [ferramenta CLI simples de demonstração para TextSearcher](https://github.com/tensorflow/tflite-support/tree/master/tensorflow_lite_support/examples/task/text/desktop#textsearcher) com seu próprio modelo e dados de teste. diff --git a/site/pt-br/lite/ios/delegates/gpu.md b/site/pt-br/lite/ios/delegates/gpu.md new file mode 100644 index 0000000000..1f996c6c34 --- /dev/null +++ b/site/pt-br/lite/ios/delegates/gpu.md @@ -0,0 +1,303 @@ +# Delegado de aceleração de GPU para iOS + +O uso de unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho do modelo e a experiência do usuário dos seus aplicativos com tecnologia de ML. Nos dispositivos iOS, você pode ativar a execução dos seus modelos com a aceleração de GPU usando um [*delegado*](../../performance/delegates). Os delegados atuam como drivers de hardware para o TensorFlow Lite, permitindo que você execute o código do modelo em processadores com GPU. + +Esta página descreve como ativar a aceleração de GPU para os modelos do TensorFlow Lite nos apps para iOS. Confira mais informações sobre como usar o delegado de GPU para o TensorFlow Lite, incluindo práticas recomendadas e técnicas avançadas, na página [delegados de GPU](../../performance/gpu). + +## Use o GPU com a API Interpreter + +A [API Interpreter](../../api_docs/swift/Classes/Interpreter) do TensorFlow Lite conta com um conjunto de APIs de finalidade geral para criar aplicativos de aprendizado de máquina. As instruções abaixo mostram como adicionar suporte a GPUs em um aplicativo para iOS. Este guia pressupõe que você já tenha um aplicativo para iOS que consiga executar um modelo de ML com o TensorFlow Lite. + +Observação: caso você ainda não tenha um aplicativo para iOS que use o TensorFlow Lite, confira o [Guia de início rápido para iOS](https://www.tensorflow.org/lite/guide/ios) e compile o aplicativo de demonstração. Após concluir o tutorial, você pode seguir as instruções aqui para acrescentar suporte a GPUs. + +### Modifique o Podfile para incluir suporte a GPUs + +A partir do TensorFlow Lite versão 2.3.0, o delegado de GPU é excluído do pod para reduzir o tamanho do binário. Você pode incluí-lo especificando uma subespecificação do pod `TensorFlowLiteSwift`: + +```ruby +pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly', +``` + +OU + +```ruby +pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal'] +``` + +Você também pode usar `TensorFlowLiteObjC` ou `TensorFlowLiteC` se quiser utilizar a API do Objective-C, que está disponível nas versões 2.4.0 e posteriores, ou a API do C. + +Observação: para o TensorFlow Lite versões 2.1.0 a 2.2.0, o delegado de GPU está *incluído* no pod `TensorFlowLiteC`. Você pode escolher entre `TensorFlowLiteC` e `TensorFlowLiteSwift`, dependendo da linguagem de programação utilizada. + +### Inicialize e use o delegado de GPU + +Você pode usar o delegado de GPU com a [API Interpreter](../../api_docs/swift/Classes/Interpreter) do TensorFlow Lite com diversas linguagens de programação. É recomendável utilizar Swift e Objective-C, mas também é possível usar C++ e C. É obrigatório usar o C se você estiver utilizando uma versão do TensorFlow Lite abaixo da 2.4. Os exemplos de código abaixo mostram como usar o delegado com cada uma dessas linguagens. + +
+ +
+

Swift

+

+
import TensorFlowLite
+
+// Load model ...
+
+// Initialize TensorFlow Lite interpreter with the GPU delegate.
+let delegate = MetalDelegate()
+if let interpreter = try Interpreter(modelPath: modelPath,
+                                      delegates: [delegate]) {
+  // Run inference ...
+}
+      
+
+
+

Objective-C

+

+
// Import module when using CocoaPods with module support
+@import TFLTensorFlowLite;
+
+// Or import following headers manually
+#import "tensorflow/lite/objc/apis/TFLMetalDelegate.h"
+#import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h"
+
+// Initialize GPU delegate
+TFLMetalDelegate* metalDelegate = [[TFLMetalDelegate alloc] init];
+
+// Initialize interpreter with model path and GPU delegate
+TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init];
+NSError* error = nil;
+TFLInterpreter* interpreter = [[TFLInterpreter alloc]
+                                initWithModelPath:modelPath
+                                          options:options
+                                        delegates:@[ metalDelegate ]
+                                            error:&error];
+if (error != nil) { /* Error handling... */ }
+
+if (![interpreter allocateTensorsWithError:&error]) { /* Error handling... */ }
+if (error != nil) { /* Error handling... */ }
+
+// Run inference ...
+      
+
+
+

C++

+

+
// Set up interpreter.
+auto model = FlatBufferModel::BuildFromFile(model_path);
+if (!model) return false;
+tflite::ops::builtin::BuiltinOpResolver op_resolver;
+std::unique_ptr<Interpreter> interpreter;
+InterpreterBuilder(*model, op_resolver)(&interpreter);
+
+// Prepare GPU delegate.
+auto* delegate = TFLGpuDelegateCreate(/*default options=*/nullptr);
+if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
+
+// Run inference.
+WriteToInputTensor(interpreter->typed_input_tensor<float>(0));
+if (interpreter->Invoke() != kTfLiteOk) return false;
+ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0));
+
+// Clean up.
+TFLGpuDelegateDelete(delegate);
+      
+
+
+

C (antes da versão 2.4.0)

+

+
#include "tensorflow/lite/c/c_api.h"
+#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
+
+// Initialize model
+TfLiteModel* model = TfLiteModelCreateFromFile(model_path);
+
+// Initialize interpreter with GPU delegate
+TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
+TfLiteDelegate* delegate = TFLGPUDelegateCreate(nil);  // default config
+TfLiteInterpreterOptionsAddDelegate(options, metal_delegate);
+TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
+TfLiteInterpreterOptionsDelete(options);
+
+TfLiteInterpreterAllocateTensors(interpreter);
+
+NSMutableData *input_data = [NSMutableData dataWithLength:input_size * sizeof(float)];
+NSMutableData *output_data = [NSMutableData dataWithLength:output_size * sizeof(float)];
+TfLiteTensor* input = TfLiteInterpreterGetInputTensor(interpreter, 0);
+const TfLiteTensor* output = TfLiteInterpreterGetOutputTensor(interpreter, 0);
+
+// Run inference
+TfLiteTensorCopyFromBuffer(input, inputData.bytes, inputData.length);
+TfLiteInterpreterInvoke(interpreter);
+TfLiteTensorCopyToBuffer(output, outputData.mutableBytes, outputData.length);
+
+// Clean up
+TfLiteInterpreterDelete(interpreter);
+TFLGpuDelegateDelete(metal_delegate);
+TfLiteModelDelete(model);
+      
+
+
+
+ +#### Notas de uso das linguagens de API de GPU + +- Versões do TensorFlow Lite anteriores à 2.4.0 só podem usar a API do C para Objective-C. +- A API do C++ está disponível somente ao usar o Bazel ou se você compilar o TensorFlow Lite. A API do C++ não pode ser usada com CocoaPods. +- Ao usar o TensorFlow Lite com o delegado de GPU e C++, obtenha o delegado de GPU pela função `TFLGpuDelegateCreate()` e depois passe-o para `Interpreter::ModifyGraphWithDelegate()` em vez de chamar `Interpreter::AllocateTensors()`. + +### Compile e teste com o modo de release + +Altere para uma build de release com as configurações apropriadas do acelerador da API Metal para obter um maior desempenho e para testes finais. Esta seção explica como ativar uma build de release e definir as configurações de aceleração Metal. + +Observação: para acompanhar estas instruções, é necessário ter o XCode v.10.1 ou posterior. + +Para mudar para uma build de release: + +1. Para editar as configurações da build, selecione **Product > Scheme > Edit Scheme...** (Produto > Esquema > Editar esquema...) e depois selecione **Run** (Executar). +2. Na guia **Info** (Informações), altere **Build Configuration** (Configuração da build) para **Release** e desmarque **Debug executable** (Depurar executável). ![setting up release](../../../images/lite/ios/iosdebug.png) +3. Clique na guia **Options** (Opções) e altere **GPU Frame Capture** (Captura de quadro de GPU) para **Disabled** (Desativada) e **Metal API Validation** (Validação da API Metal) para **Disabled** (Desativada).
![setting up metal options](../../../images/lite/ios/iosmetal.png) +4. Você deve selecionar Release-only builds on 64-bit architecture (Builds somente release em arquitetura de 64 bits). Em **Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings** (Navegador do projeto > tflite_camera_example > PROJETO > nome_do_seu_projeto > Configurações da build), defina **Build Active Architecture Only > Release** (Compilar somente arquitetura ativa > Release) como **Yes** (Sim). ![setting up release options](../../../images/lite/ios/iosrelease.png) + +## Suporte avançado à GPU + +Esta seção fala sobre usos avançados de delegado de GPU para iOS, incluindo opções de delegado, buffers de entrada e saída e uso de modelos quantizados. + +### Opções de delegado para iOS + +O construtor do delegado de GPU recebe uma `struct` de opções na [API da Swift](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/swift/Sources/MetalDelegate.swift), na [API do Objective-C](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/objc/apis/TFLMetalDelegate.h) e na [API do C](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/gpu/metal_delegate.h). Ao passar `nullptr` (API do C) ou nada (APIs do Objective-C e da Swift) ao inicializador, as opções padrão são definidas (o que é explicado no exemplo Uso básico acima). + +
+ +
+

Swift

+

+
// THIS:
+var options = MetalDelegate.Options()
+options.isPrecisionLossAllowed = false
+options.waitType = .passive
+options.isQuantizationEnabled = true
+let delegate = MetalDelegate(options: options)
+
+// IS THE SAME AS THIS:
+let delegate = MetalDelegate()
+      
+
+
+

Objective-C

+

+
// THIS:
+TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
+options.precisionLossAllowed = false;
+options.waitType = TFLMetalDelegateThreadWaitTypePassive;
+options.quantizationEnabled = true;
+
+TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] initWithOptions:options];
+
+// IS THE SAME AS THIS:
+TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] init];
+      
+
+
+

C

+

+
// THIS:
+const TFLGpuDelegateOptions options = {
+  .allow_precision_loss = false,
+  .wait_type = TFLGpuDelegateWaitType::TFLGpuDelegateWaitTypePassive,
+  .enable_quantization = true,
+};
+
+TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
+
+// IS THE SAME AS THIS:
+TfLiteDelegate* delegate = TFLGpuDelegateCreate(nullptr);
+      
+
+
+
+ +Dica: embora seja conveniente usar `nullptr` ou os construtores padrão, você deve definir explicitamente as opções para evitar qualquer comportamento inesperado se os valores padrão forem alterados no futuro. + +### Buffers de entrada/saída usando a API do C++ + +Fazer computação na GPU requer que os dados estejam disponíveis para a GPU. Em geral, este requisito exige que você faça uma cópia da memória. Se possível, você deve evitar que os dados cruzem a fronteira de memória entre CPU/GPU, pois isso pode levar um tempo considerável. Geralmente, esse cruzamento é inevitável, mas, em alguns casos, um ou o outro pode ser omitido. + +Observação: a técnica abaixo está disponível somente ao usar o Bazel ou se você compilar o TensorFlow Lite. A API do C++ não pode ser usada com CocoaPods. + +Se a entrada da rede for uma imagem já carregada na memória da GPU (por exemplo: uma textura de GPU contendo o feed da câmera), ela pode permanecer na memória da GPU sem nunca entrar na memória da CPU. De maneira similar, se a saída da rede estiver na forma de uma imagem renderizável, como a operação de [transferência de estilo de imagem](https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Gatys_Image_Style_Transfer_CVPR_2016_paper.pdf), você pode exibir o resultado diretamente na tela. + +Para obter o melhor desempenho, o TensorFlow Lite possibilita que os usuários leiam e escrevam diretamente no buffer de hardware do TensorFlow, evitando cópias de memória desnecessárias. + +Supondo que a entrada de imagem esteja na memória da GPU, primeiro você precisa convertê-la em um objeto `MTLBuffer` para a API Metal. Você pode associar um `TfLiteTensor` a um `MTLBuffer` preparado pelo usuário por meio da função `TFLGpuDelegateBindMetalBufferToTensor()`. Atenção: essa função *precisa* ser chamada após `Interpreter::ModifyGraphWithDelegate()`. Além disso, a saída da inferência é, por padrão, copiada da memória da GPU para a memória da CPU. Para desativar esse comportamento, basta chamar `Interpreter::SetAllowBufferHandleOutput(true)` durante a inicialização. + +
+ +
+

C++

+

+
#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
+#include "tensorflow/lite/delegates/gpu/metal_delegate_internal.h"
+
+// ...
+
+// Prepare GPU delegate.
+auto* delegate = TFLGpuDelegateCreate(nullptr);
+
+if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
+
+interpreter->SetAllowBufferHandleOutput(true);  // disable default gpu->cpu copy
+if (!TFLGpuDelegateBindMetalBufferToTensor(
+        delegate, interpreter->inputs()[0], user_provided_input_buffer)) {
+  return false;
+}
+if (!TFLGpuDelegateBindMetalBufferToTensor(
+        delegate, interpreter->outputs()[0], user_provided_output_buffer)) {
+  return false;
+}
+
+// Run inference.
+if (interpreter->Invoke() != kTfLiteOk) return false;
+      
+
+
+
+ +Quando o comportamento padrão é desativado, copiar a saída da inferência da memória da GPU para a memória da CPU requer uma chamada explícita a `Interpreter::EnsureTensorDataIsReadable()` para cada tensor de saída. Essa estratégia também funciona para modelos quantizados, mas você ainda precisa usar um **buffer float32 com dados float32**, pois esse buffer é vinculado ao buffer interno dequantizado. + +### Modelos quantizados {:#quantized-models} + +As bibliotecas de delegados de GPU do iOS *são compatíveis com os modelos quantizados por padrão*. Você não precisa fazer nenhuma alteração no código para usar modelos quantizados com o delegado de GPU. A seção a seguir explica como desativar o suporte quantizado para testes ou fins experimentais. + +#### Desative o suporte a modelos quantizados + +O código a seguir mostra como ***desativar*** o suporte a modelos quantizados. + +
+ +
+

Swift

+

+
    var options = MetalDelegate.Options()
+    options.isQuantizationEnabled = false
+    let delegate = MetalDelegate(options: options)
+      
+
+
+

Objective-C

+

+
    TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
+    options.quantizationEnabled = false;
+      
+
+
+

C

+

+
    TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault();
+    options.enable_quantization = false;
+
+    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
+      
+
+
+
+ +Para mais informações sobre como executar modelos quantizados com a aceleração de GPU, confira a visão geral do [delegado de GPU](../../performance/gpu#quantized-models). diff --git a/site/pt-br/lite/microcontrollers/build_convert.md b/site/pt-br/lite/microcontrollers/build_convert.md new file mode 100644 index 0000000000..44d5f0e291 --- /dev/null +++ b/site/pt-br/lite/microcontrollers/build_convert.md @@ -0,0 +1,61 @@ +# Compile e converta modelos + +Os microcontroladores têm RAM e armazenamento limitados, o que restringe o tamanho dos modelos de aprendizado de máquina. Além disso, no momento, o TensorFlow Lite para Microcontroladores oferece suporte a um subconjunto limitado de operações e, portanto, nem todas as arquiteturas de modelo são possíveis. + +Este documento explica o processo de converter um modelo do TensorFlow para ser executado em microcontroladores, além de descrever as operações com suporte e oferecer orientações sobre como conceber e treinar um modelo de forma que caiba na memória limitada. + +Para ver um exemplo executável completo de compilação e conversão de um modelo, confira o seguinte Colab, que faz parte do exemplo *Hello World* (Olá, mundo): + +train_hello_world_model.ipynb + +## Conversão do modelo + +Para converter um modelo do TensorFlow de forma que possa ser executado em microcontroladores, você deve usar a [API do Python de conversão para o TensorFlow Lite](https://www.tensorflow.org/lite/models/convert/), que vai converter o modelo em um [`FlatBuffer`](https://google.github.io/flatbuffers/), reduzindo o tamanho do modelo, e modificá-lo para usar as operações do TensorFlow Lite. + +Para conseguir o menor tamanho possível para o modelo, considere usar [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization). + +### Converta em um array do C + +Diversas plataformas de microcontroladores não têm suporte a sistemas de arquivo nativos. A maneira mais fácil de usar um modelo do seu programa é incluí-lo como um array do C e compilá-lo em seu programa. + +O comando UNIX abaixo gera um arquivo fonte do C que contém o modelo do TensorFlow Lite como um array `char`: + +```bash +xxd -i converted_model.tflite > model_data.cc +``` + +A saída será parecida com a seguinte: + +```c +unsigned char converted_model_tflite[] = { + 0x18, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x0e, 0x00, + // +}; +unsigned int converted_model_tflite_len = 18200; +``` + +Após gerar o arquivo, você pode incluí-lo em seu programa. É importante alterar a declaração do array para `const` a fim de conseguir uma eficiência de memória melhor em plataformas embarcadas. + +Para ver um exemplo de como incluir e usar um modelo em seu programa, confira [`evaluate_test.cc`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world/evaluate_test.cc) no exemplo *Hello World*. + +## Arquitetura do modelo e treinamento + +Ao conceber um modelo para uso em microcontroladores, é importante considerar o tamanho do modelo, a carga de trabalho e as operações que serão usadas. + +### Tamanho do modelo + +O modelo precisa ser pequeno o suficiente para caber na memória do dispositivo escolhido juntamente com o restante do programa, tanto como binário quanto no runtime. + +Para criar um modelo menor, você pode usar menos camadas e camadas menores em sua arquitetura. Porém, modelos menores estão mais propensos a sofrer underfitting. Portanto, para muitos problemas, faz sentido tentar usar o maior modelo possível que caiba na memória. Entretanto, usar modelos maiores também levará a um aumento da carga de trabalho dos processadores. + +Observação: o runtime core do TensorFlow Lite para Microcontroladores cabe em 16 KB em um Cortex M3. + +### Carga de trabalho + +O tamanho e a complexidade do modelo impactam a carga de trabalho. Modelos maiores e mais complexos resultam em um ciclo de trabalho maior e, portanto, o processador do dispositivo passa mais tempo trabalhando e menos tempo ocioso, o que aumenta o consumo de energia e a geração de calor, o que pode ser um problema, dependendo da aplicação. + +### Suporte a operações + +No momento, o TensorFlow Lite para Microcontroladores tem suporte a um subconjunto limitado de operações do TensorFlow, impactando as possíveis arquiteturas do modelo que podem ser usadas. Estamos trabalhando na expansão do suporte às operações, tanto em termos das implementações de referência quanto otimizações para arquiteturas específicas. + +Confira as operações com suporte no arquivo [`micro_mutable_ops_resolver.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/micro_mutable_op_resolver.h). diff --git a/site/pt-br/lite/microcontrollers/get_started_low_level.md b/site/pt-br/lite/microcontrollers/get_started_low_level.md new file mode 100644 index 0000000000..d83ad2f358 --- /dev/null +++ b/site/pt-br/lite/microcontrollers/get_started_low_level.md @@ -0,0 +1,268 @@ +# Introdução aos microcontroladores + +Este documento explica como treinar um modelo e executar a inferência usando um microcontrolador. + +## Exemplo Hello World + +O objetivo do exemplo [Hello World](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/hello_world) (Olá, mundo) é demonstrar o uso básico do TensorFlow Lite para Microcontroladores. Treinamos e executamos um modelo que replica uma função de seno, ou seja, recebe um único número como entrada e gera como saída o valor [seno](https://en.wikipedia.org/wiki/Sine) do número. Quando implantado no microcontrolador, suas previsões são usadas para piscar luzes LED ou controlar uma animação. + +O workflow completo é composto pelas seguintes etapas: + +1. [Treine um modelo](#train_a_model) (no Python): um arquivo do Python para treinar, converter e otimizar um modelo para uso em dispositivos. +2. [Execute a inferência](#run_inference) (no C++ 17): um teste de unidade fim a fim que executa a inferência no modelo usando a [biblioteca do C++](library.md). + +## Use um dispositivo com suporte + +O aplicativo de exemplo que usaremos foi testado nos seguintes dispositivos: + +- [Arduino Nano 33 BLE Sense](https://store-usa.arduino.cc/products/arduino-nano-33-ble-sense-with-headers) (usando Arduino IDE) +- [SparkFun Edge](https://www.sparkfun.com/products/15170) (compilando diretamente a partir do código-fonte) +- [STM32F746 Discovery kit](https://www.st.com/en/evaluation-tools/32f746gdiscovery.html) (usando Mbed) +- [Adafruit EdgeBadge](https://www.adafruit.com/product/4400) (usando Arduino IDE) +- [Adafruit TensorFlow Lite for Microcontrollers Kit](https://www.adafruit.com/product/4317) (usando Arduino IDE) +- [Adafruit Circuit Playground Bluefruit](https://learn.adafruit.com/tensorflow-lite-for-circuit-playground-bluefruit-quickstart?view=all) (usando Arduino IDE) +- [Espressif ESP32-DevKitC](https://www.espressif.com/en/products/hardware/esp32-devkitc/overview) (usando ESP IDF) +- [Espressif ESP-EYE](https://www.espressif.com/en/products/hardware/esp-eye/overview) (usando ESP IDF) + +Saiba mais sofre as plataformas com suporte no [TensorFlow Lite para Microcontroladores](index.md). + +## Treine um modelo + +Observação: você pode pular esta seção e usar o modelo treinado incluído no código de exemplo. + +Use [train.py](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world/train.py) para treinamento do modelo Hello World de reconhecimento de senoides. + +Execute: `bazel build tensorflow/lite/micro/examples/hello_world:train` `bazel-bin/tensorflow/lite/micro/examples/hello_world/train --save_tf_model --save_dir=/tmp/model_created/` + +## Execute a inferência + +Para executar o modelo em seu dispositivo, falaremos sobre as instruções no arquivo `README.md`: + +Hello World README.md + +As próximas seções falam sobre o teste de unidade [`evaluate_test.cc`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/hello_world/evaluate_test.cc) do exemplo, que demonstra como executar a inferência usando o TensorFlow Lite para Microcontroladores. Ele carrega o modelo e executa a inferência diversas vezes. + +### 1. Inclua os cabeçalhos da biblioteca + +Para usar a biblioteca do TensorFlow Lite para Microcontroladores, precisamos incluir os seguintes arquivos de cabeçalho: + +```C++ +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "tensorflow/lite/version.h" +``` + +- [`micro_mutable_op_resolver.h`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/micro_mutable_op_resolver.h) – fornece as operações usadas pelo interpretador para executar o modelo. +- [`micro_error_reporter.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.h) – gera como saída informações de depuração. +- [`micro_interpreter.h`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/micro_interpreter.h) – contém código para carregar e executar modelos. +- [`schema_generated.h`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/schema/schema_generated.h) – contém o esquema do formato de arquivo de modelo [`FlatBuffer`](https://google.github.io/flatbuffers/) do TensorFlow Lite. +- [`version.h`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/version.h) – fornece informações de versionamento do esquema do TensorFlow Lite. + +### 2. Inclua o cabeçalho do modelo + +O interpretador do TensorFlow Lite para Microcontroladores espera que o modelo seja fornecido como um array do C++. O modelo é definido nos arquivos `model.h` e `model.cc`. O cabeçalho é incluído com a seguinte linha: + +```C++ +#include "tensorflow/lite/micro/examples/hello_world/model.h" +``` + +### 3. Inclua o cabeçalho do framework de teste de unidade + +Para criar um teste de unidade, incluímos o framework de teste de unidade do TensorFlow Lite para Microcontroladores com a seguinte linha: + +```C++ +#include "tensorflow/lite/micro/testing/micro_test.h" +``` + +O teste é definido usando-se as seguintes macros: + +```C++ +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(LoadModelAndPerformInference) { + . // add code here + . +} + +TF_LITE_MICRO_TESTS_END +``` + +Agora, vamos falar sobre o código incluído na macro acima. + +### 4. Configure a gravação de logs + +Para configurar a gravação de logs, um ponteiro `tflite::ErrorReporter` é criado usando-se um ponteiro para uma instância de `tflite::MicroErrorReporter`: + +```C++ +tflite::MicroErrorReporter micro_error_reporter; +tflite::ErrorReporter* error_reporter = µ_error_reporter; +``` + +Essa variável será passada ao interpretador, o que permite a ele escrever logs. Como os microcontroladores costumam ter uma variedade de mecanismos de gravação de logs, a implementação de `tflite::MicroErrorReporter` foi criada de forma que possa ser personalizada para seu dispositivo específico. + +### 5. Carregue um modelo + +No código abaixo, o modelo é instanciado usando dados de um array `char`, `g_model`, que é declarado em `model.h`. Em seguida, verificamos o modelo para garantir que a versão do esquema seja compatível com a versão que estamos usando. + +```C++ +const tflite::Model* model = ::tflite::GetModel(g_model); +if (model->version() != TFLITE_SCHEMA_VERSION) { + TF_LITE_REPORT_ERROR(error_reporter, + "Model provided is schema version %d not equal " + "to supported version %d.\n", + model->version(), TFLITE_SCHEMA_VERSION); +} +``` + +### 6. Instancie o resolvedor de operações + +Uma instância de [`MicroMutableOpResolver`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/micro_mutable_op_resolver.h) é declarada, que será usada pelo interpretador para registrar e acessar as operações usadas pelo modelo: + +```C++ +using HelloWorldOpResolver = tflite::MicroMutableOpResolver<1>; + +TfLiteStatus RegisterOps(HelloWorldOpResolver& op_resolver) { + TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected()); + return kTfLiteOk; + +``` + +`MicroMutableOpResolver` requer um parâmetro de template que indique o número de operações que serão registradas. A função `RegisterOps` registra as operações no resolvedor. + +```C++ +HelloWorldOpResolver op_resolver; +TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver)); + +``` + +### 7. Aloque memória + +Precisamos pré-alocar uma determinada quantidade de memória para os arrays de entrada, saída e intermediários. Isso é fornecido como um array `uint8_t` de tamanho `tensor_arena_size`: + +```C++ +const int tensor_arena_size = 2 * 1024; +uint8_t tensor_arena[tensor_arena_size]; +``` + +O tamanho necessário dependerá do modelo que você estiver usando e talvez precise ser determinado fazendo experimentos. + +### 8. Instancie o interpretador + +Criamos uma instância de `tflite::MicroInterpreter` passando as variáveis criadas anteriormente: + +```C++ +tflite::MicroInterpreter interpreter(model, resolver, tensor_arena, + tensor_arena_size, error_reporter); +``` + +### 9. Aloque tensores + +Dizemos ao interpretador para alocar memória de `tensor_arena` para os tensores do modelo: + +```C++ +interpreter.AllocateTensors(); +``` + +### 10. Valide o formato da entrada + +A instância de `MicroInterpreter` pode nos fornecer um ponteiro para o tensor de entrada do modelo, basta chamar `.input(0)`, em que `0` representa o primeiro (e único) tensor de entrada: + +```C++ + // Obtain a pointer to the model's input tensor + TfLiteTensor* input = interpreter.input(0); +``` + +Em seguida, inspecionamos esse tensor para confirmar que o formato e o tipo sejam os esperados: + +```C++ +// Make sure the input has the properties we expect +TF_LITE_MICRO_EXPECT_NE(nullptr, input); +// The property "dims" tells us the tensor's shape. It has one element for +// each dimension. Our input is a 2D tensor containing 1 element, so "dims" +// should have size 2. +TF_LITE_MICRO_EXPECT_EQ(2, input->dims->size); +// The value of each element gives the length of the corresponding tensor. +// We should expect two single element tensors (one is contained within the +// other). +TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]); +TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]); +// The input is a 32 bit floating point value +TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, input->type); +``` + +O valor enum `kTfLiteFloat32` é uma referência a um dos tipos de dados do TensorFlow Lite e é definido em [`common.h`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/c/common.h). + +### 11. Forneça um valor de entrada + +Para fornecer um valor de entrada ao modelo, definimos o conteúdo do tensor de entrada da seguinte forma: + +```C++ +input->data.f[0] = 0.; +``` + +Neste caso, fornecemos como entrada um valor de ponto flutuante que representa `0`. + +### 12. Execute o modelo + +Para executar o modelo, chamamos `Invoke()` na instância de `tflite::MicroInterpreter`: + +```C++ +TfLiteStatus invoke_status = interpreter.Invoke(); +if (invoke_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed\n"); +} +``` + +Podemos verificar o valor retornado, um `TfLiteStatus`, para determinar se a execução foi bem-sucedida. Os valores possíveis de `TfLiteStatus`, definidos em [`common.h`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/c/common.h), são `kTfLiteOk` e `kTfLiteError`. + +O código abaixo indica que o valor é `kTfLiteOk`, ou seja, a inferência foi executada com êxito. + +```C++ +TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status); +``` + +### 13. Obtenha a saída + +O tensor de saída do modelo pode ser obtido chamando-se `output(0)` em `tflite::MicroInterpreter`, em que `0` representa o primeiro (e único) tensor de saída. + +Neste exemplo, a saída do modelo é um único valor de ponto flutuante contido dentro de um tensor bidimensional: + +```C++ +TfLiteTensor* output = interpreter.output(0); +TF_LITE_MICRO_EXPECT_EQ(2, output->dims->size); +TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]); +TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]); +TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, output->type); +``` + +Podemos ler o valor diretamente no tensor de saída e confirmar que é o esperado: + +```C++ +// Obtain the output value from the tensor +float value = output->data.f[0]; +// Check that the output value is within 0.05 of the expected value +TF_LITE_MICRO_EXPECT_NEAR(0., value, 0.05); +``` + +### 14. Execute a inferência novamente + +O restante do código executa a inferência diversas outras vezes. Em cada execução, atribuímos um valor ao tensor de entrada, chamamos o interpretador e lemos o resultado no tensor de saída: + +```C++ +input->data.f[0] = 1.; +interpreter.Invoke(); +value = output->data.f[0]; +TF_LITE_MICRO_EXPECT_NEAR(0.841, value, 0.05); + +input->data.f[0] = 3.; +interpreter.Invoke(); +value = output->data.f[0]; +TF_LITE_MICRO_EXPECT_NEAR(0.141, value, 0.05); + +input->data.f[0] = 5.; +interpreter.Invoke(); +value = output->data.f[0]; +TF_LITE_MICRO_EXPECT_NEAR(-0.959, value, 0.05); +``` diff --git a/site/pt-br/lite/microcontrollers/library.md b/site/pt-br/lite/microcontrollers/library.md new file mode 100644 index 0000000000..fa5060973c --- /dev/null +++ b/site/pt-br/lite/microcontrollers/library.md @@ -0,0 +1,124 @@ +# Sobre a biblioteca do C++ + +A biblioteca do C++ do TensorFlow Lite para Microcontroladores faz parte do [repositório do TensorFlow](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro). Ela é fácil ler, de modificar, bem testada e fácil de integrar, além de ser compatível com o TensorFlow Lite comum. + +Este documento descreve a estrutura básica da biblioteca do C++ e apresenta informações sobre como criar seu próprio projeto. + +## Estrutura do arquivo + +O diretório raiz [`micro`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro) tem uma estrutura relativamente simples. Porém, como fica localizado dentro do extenso repositório do TensorFlow, criamos scripts e arquivos de projeto pré-gerados que fornecem os arquivos fonte relevantes isoladamente dentro de diversos ambientes de desenvolvimento embarcados. + +### Principais arquivos + +Os arquivos mais importantes para usar o interpretador do TensorFlow Lite para Microcontroladores ficam localizados na raiz do projeto, acompanhados de testes: + +``` +[`micro_mutable_op_resolver.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/micro_mutable_op_resolver.h) +can be used to provide the operations used by the interpreter to run the +model. +``` + +- [`micro_error_reporter.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.h) – gera como saída informações de depuração. +- [`micro_interpreter.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/micro_interpreter.h) – contém código para testar e executar modelos. + +Confira detalhes do uso geral em [Introdução aos microcontroladores](get_started_low_level.md). + +O sistema de compilação fornece implementações de determinados arquivos para plataformas específicas, que ficam localizadas no diretório com o nome da plataforma. Por exemplo: [`cortex-m`](https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/cortex_m_generic). + +Diversos outros diretórios existem, incluindo: + +- [`kernel`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/kernels), que contém implementações de operações e o código subjacente. +- [`tools`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/tools), que contém ferramentas de compilação e suas saídas. +- [`examples`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples), que contém exemplos de código. + +## Comece um novo projeto + +Recomendamos usar o exemplo *Hello World* (Olá, mundo) como template para novos projetos. Para obter uma versão para a plataforma escolhida, basta seguir as instruções desta seção. + +### Use a biblioteca do Arduino + +Se você estiver usando o Arduino, o exemplo *Hello World* está incluído na biblioteca `Arduino_TensorFlowLite` do Arduino, que você pode instalar manualmente no Arduino IDE e no [Arduino Create](https://create.arduino.cc/). + +Após adicionar a biblioteca, acesse `File -> Examples` (Arquivo -> Exemplos). Você deverá ver um exemplo perto da parte inferior da lista com nome `TensorFlowLite:hello_world`. Selecione-o e clique em `hello_world` para carregar o exemplo. Em seguida, você pode salvar uma cópia do exemplo e usá-lo como base do seu próprio projeto. + +### Gere projetos para outras plataformas + +O TensorFlow Lite para Microcontroladores consegue gerar projetos standalone que contêm todos os arquivos fonte necessário usando um `Makefile`. No momento, os ambientes com suporte são Keil, Make e Mbed. + +Para gerar esses projetos com o Make, clone o [repositório TensorFlow/tflite-micro](https://github.com/tensorflow/tflite-micro) e execute o seguinte comando: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile generate_projects +``` + +Vai levar alguns minutos, já que é preciso baixar algumas toolchains grandes para as dependências. Após o término, você verá algumas pastas criadas dentro de um caminho como `gen/linux_x86_64/prj/` (o caminho exato depende do sistema operacional do host). Essas pastas contêm o projeto gerado e os arquivos fonte. + +Após executar o comando, você encontrará os projetos de *Hello World* em `gen/linux_x86_64/prj/hello_world`. Por exemplo: `hello_world/keil` conterá o projeto para Keil. + +## Execute os testes + +Para compilar a biblioteca e executar todos os testes de unidade, use o seguinte comando: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile test +``` + +Para executar um teste específico, use o comando abaixo, substituindo `` pelo nome do teste: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile test_ +``` + +Os nomes dos testes estão disponíveis nos Makefiles do projeto. Por exemplo: `examples/hello_world/Makefile.inc` especifica os nomes de testes para o exemplo *Hello World*. + +## Compile os binários + +Para compilar um binário executável para um determinado projeto (como uma aplicação de exemplo), use o comando abaixo, substituindo `` pelo projeto que deseja compilar: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile _bin +``` + +Por exemplo: o comando abaixo compilará um binário para a aplicação *Hello World*: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile hello_world_bin +``` + +Por padrão, o projeto será compilado para o sistema operacional do host. Para especificar um arquitetura alvo diferente, use `TARGET=` e `TARGET_ARCH=`. O exemplo abaixo mostra como compilar o exemplo *Hello World* para um cortex-m0 genérico: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile TARGET=cortex_m_generic TARGET_ARCH=cortex-m0 hello_world_bin +``` + +Quando um alvo é especificado, todos os arquivos fonte específicos para o alvo disponíveis serão usados no lugar do código original. Por exemplo: o subdiretório `examples/hello_world/cortex_m_generic` contém implementações dos arquivos `constants.cc` e `output_handler.cc` para SparkFun Edge, que serão usados quando o alvo `cortex_m_generic` for especificado. + +Os nomes dos projetos estão disponíveis nos Makefiles do projeto. Por exemplo: `examples/hello_world/Makefile.inc` especifica os nomes dos binários para o exemplo *Hello World*. + +## Kernels otimizados + +Os kernels de referência na raiz de `tensorflow/lite/micro/kernels` são implementados em C/C++ puro e não incluem otimizações de hardware de plataformas específicas. + +São fornecidas versões otimizadas dos kernels nos subdiretórios. Por exemplo: `kernels/cmsis-nn` contém diversos kernels otimizados que usam a biblioteca CMSIS-NN do Arm. + +Para gerar projetos usando kernels otimizados, use o comando abaixo, substituindo `` pelo nome do subdiretório que contém as otimizações: + +```bash +make -f tensorflow/lite/micro/tools/make/Makefile TAGS= generate_projects +``` + +Para adicionar suas próprias otimizações, basta criar uma nova subpasta para elas. Sugerimos que sejam usados pull requests para novas implementações otimizadas. + +## Gere a biblioteca do Arduino + +Se você precisar gerar uma nova build da biblioteca, pode usar o seguinte script do repositório do TensorFlow: + +```bash +./tensorflow/lite/micro/tools/ci_build/test_arduino.sh +``` + +A biblioteca resultante está disponível em `gen/arduino_x86_64/prj/tensorflow_lite.zip`. + +## Portabilidade para novos dispositivos + +Confira as orientações sobre como fazer a portabilidade do TensorFlow Lite para Microcontroladores para novas plataformas e dispositivos em [`micro/docs/new_platform_support.md`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/docs/new_platform_support.md). diff --git a/site/pt-br/lite/models/convert/api_updates.md b/site/pt-br/lite/models/convert/api_updates.md new file mode 100644 index 0000000000..e83fbfdb98 --- /dev/null +++ b/site/pt-br/lite/models/convert/api_updates.md @@ -0,0 +1,25 @@ +# Atualizações da API + +Esta página fornece informações sobre as atualizações feita na [API do Python](index.md) `tf.lite.TFLiteConverter` no TensorFlow 2.x. + +Observação: se alguma das alterações gerar preocupações, crie um [issue no GitHub](https://github.com/tensorflow/tensorflow/issues/new?template=60-tflite-converter-issue.md). + +- TensorFlow 2.3 + + - Suporte ao tipo de saída/entrada inteiro (antes, só havia suporte a ponto flutuante) para modelos quantizados com inteiros usando os novos atributos `inference_input_type` e `inference_output_type`. Confira este [exemplo de uso](../../performance/post_training_quantization.md#integer_only). + - Suporte à conversão e ao redimensionamento de modelos com dimensões dinâmicas. + - Inclusão de um novo modo de quantização experimental com ativações de 16 bits e pesos de 8 bits. + +- TensorFlow 2.2 + + - Por padrão, use a [conversão baseada em MLIR](https://mlir.llvm.org/), uma tecnologia de compilação de ponta do Google para aprendizado de máquina que permite fazer a conversão de novas classes de modelos, incluindo Mask R-CNN, Mobile BERT, etc., além de oferecer suporte a modelos com fluxo de controle funcional. + +- TensorFlow 2.0 versus TensorFlow 1.x + + - O atributo `target_ops` foi renomeado para `target_spec.supported_ops` + - Os seguintes atributos foram removidos: + - *Quantização*: `inference_type`, `quantized_input_stats`, `post_training_quantize`, `default_ranges_stats`, `reorder_across_fake_quant`, `change_concat_input_ranges`, `get_input_arrays()`. Em vez disso, há suporte ao [treinamento com reconhecimento de quantização](https://www.tensorflow.org/model_optimization/guide/quantization/training) por meio da API `tf.keras`, e a [quantização pós-treinamento](../../performance/post_training_quantization.md) usa menos atributos. + - *Visualização*: `output_format`, `dump_graphviz_dir`, `dump_graphviz_video`. Em vez disso, a estratégia recomendável para visualizar um modelo do TensorFlow lite é o uso de [visualize.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/visualize.py). + - *Grafos congelados*: `drop_control_dependency`, pois não há suporte a grafos congelados no TensorFlow 2.x. + - Foram removidas outras APIs de conversão, como `tf.lite.toco_convert` e `tf.lite.TocoConverter`. + - Foram removidas outras APIs relacionadas, como `tf.lite.OpHint` e `tf.lite.constants` (os tipos `tf.lite.constants.*` foram mapeados para tipos de dados `tf.*` do TensorFlow para reduzir a duplicação). diff --git a/site/pt-br/lite/models/convert/convert_models.md b/site/pt-br/lite/models/convert/convert_models.md new file mode 100644 index 0000000000..aa54f4e4b7 --- /dev/null +++ b/site/pt-br/lite/models/convert/convert_models.md @@ -0,0 +1,168 @@ +# Converta modelos do TensorFlow + +Esta página descreve como converter um modelo do TensorFlow para um do TensorFlow Lite (um formato [FlatBuffer](https://google.github.io/flatbuffers/) otimizado, indicado pela extensão de arquivo `.tflite`) usando o conversor do TensorFlow Lite. + +Observação: este guia pressupõe que você [tenha instalado o TensorFlow 2.x](https://www.tensorflow.org/install/pip#tensorflow-2-packages-are-available) e treinado modelos no TensorFlow 2.x. Caso o seu modelo tenha sido treinado no TensorFlow 1.x, considere [migrar para o TensorFlow 2.x](https://www.tensorflow.org/guide/migrate/tflite). Para identificar a versão do TensorFlow instalada, execute `print(tf.__version__)`. + +## Workflow de conversão + +O diagrama abaixo ilustra o workflow geral para converter um modelo: + +![TFLite converter workflow](../../images/convert/convert.png) + +**Figura 1.** Workflow do conversor + +É possível converter um modelo por uma das seguintes opções: + +1. [API do Python](#python_api) (***opção recomendada***): permite integrar a conversão ao seu pipeline de desenvolvimento, aplicar otimizações, adicionar metadados e realizar diversas outras tarefas que simplificam o processo de conversão. +2. [Linha de comando](#cmdline): tem suporte somente à conversão básica de modelos. + +Observação: caso haja problemas durante a conversão do modelo, crie um [issue no GitHub](https://github.com/tensorflow/tensorflow/issues/new?template=60-tflite-converter-issue.md). + +## API do Python + +*Código auxiliar: para saber mais sobre a API do conversor do TensorFlow Lite, execute `print(help(tf.lite.TFLiteConverter))`.* + +Converta um modelo do TensorFlow usando [`tf.lite.TFLiteConverter`](https://www.tensorflow.org/api_docs/python/tf/lite/TFLiteConverter). Um modelo do TensorFlow é armazenado usando o formato SavedModel e é gerado usando as APIs de alto nível `tf.keras.*` (um modelo do Keras) ou as APIs de baixo nível `tf.*` (a partir das quais você gera funções concretas). Consequentemente, você tem as três opções abaixo (confira os exemplos nas próximas seções): + +- `tf.lite.TFLiteConverter.from_saved_model()` (**opção recomendada**): converte um [SavedModel](https://www.tensorflow.org/guide/saved_model). +- `tf.lite.TFLiteConverter.from_keras_model()`: converte um modelo do [Keras](https://www.tensorflow.org/guide/keras/overview). +- `tf.lite.TFLiteConverter.from_concrete_functions()`: converte [funções concretas](https://www.tensorflow.org/guide/intro_to_graphs). + +### Converta um SavedModel (recomendado) + +O exemplo abaixo mostra como converter um [SavedModel](https://www.tensorflow.org/guide/saved_model) em um modelo do TensorFlow Lite. + +```python +import tensorflow as tf + +# Convert the model +converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) # path to the SavedModel directory +tflite_model = converter.convert() + +# Save the model. +with open('model.tflite', 'wb') as f: + f.write(tflite_model) +``` + +### Converta um modelo do Keras + +O exemplo abaixo mostra como converter um modelo do [Keras](https://www.tensorflow.org/guide/keras/overview) em um modelo do TensorFlow Lite. + +```python +import tensorflow as tf + +# Create a model using high-level tf.keras.* APIs +model = tf.keras.models.Sequential([ + tf.keras.layers.Dense(units=1, input_shape=[1]), + tf.keras.layers.Dense(units=16, activation='relu'), + tf.keras.layers.Dense(units=1) +]) +model.compile(optimizer='sgd', loss='mean_squared_error') # compile the model +model.fit(x=[-1, 0, 1], y=[-3, -1, 1], epochs=5) # train the model +# (to generate a SavedModel) tf.saved_model.save(model, "saved_model_keras_dir") + +# Convert the model. +converter = tf.lite.TFLiteConverter.from_keras_model(model) +tflite_model = converter.convert() + +# Save the model. +with open('model.tflite', 'wb') as f: + f.write(tflite_model) +``` + +### Converta funções concretas + +O exemplo abaixo mostra como converter [funções concretas](https://www.tensorflow.org/guide/intro_to_graphs) em um modelo do TensorFlow Lite. + +```python +import tensorflow as tf + +# Create a model using low-level tf.* APIs +class Squared(tf.Module): + @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.float32)]) + def __call__(self, x): + return tf.square(x) +model = Squared() +# (ro run your model) result = Squared(5.0) # This prints "25.0" +# (to generate a SavedModel) tf.saved_model.save(model, "saved_model_tf_dir") +concrete_func = model.__call__.get_concrete_function() + +# Convert the model. + +converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func], + model) +tflite_model = converter.convert() + +# Save the model. +with open('model.tflite', 'wb') as f: + f.write(tflite_model) +``` + +### Outros recursos + +- Aplique [otimizações](../../performance/model_optimization.md). Uma otimização usada com frequência é a [quantização pós-treinamento](../../performance/post_training_quantization.md), que pode reduzir a latência e o tamanho do modelo, com perda mínima da exatidão. + +- Adicione [metadados](metadata.md), que facilitam a criação de código encapsulador para plataformas específicas ao implantar modelos em dispositivos. + +### Erros de conversão + +Veja abaixo os erros de conversão comuns e suas respectivas soluções: + +- Erro: `Some ops are not supported by the native TFLite runtime, you can enable TF kernels fallback using TF Select. See instructions: https://www.tensorflow.org/lite/guide/ops_select. TF Select ops: ..., .., ...` (Algumas operações não têm suporte do runtime nativo do TFLite. Você pode ativar o fallback para kernels do TF usando TF Select. Confira as instruções: https://www.tensorflow.org/lite/guide/ops_select. Operações específicas do TF: ..., .., ...) + + Solução: esse erro ocorre quando seu modelo usa operações do TF que não têm uma implementação correspondente no TF Lite. Para resolver esse problema, basta [usar a operação do TF no modelo do TF Lite](../../guide/ops_select.md) (recomendado). Se você quiser gerar um modelo somente com operações do TF Lite, pode adicionar uma solicitação para a operação do TF Lite ausente no [issue 21526 do GitHub](https://github.com/tensorflow/tensorflow/issues/21526) (deixe um comentário caso sua solicitação ainda não tenha sido mencionada) ou [pode criar a operação do TF Lite](../../guide/ops_custom#create_and_register_the_operator) por conta própria. + +- Erro: `.. is neither a custom op nor a flex op` (... não é uma operação personalizada nem uma operação flex). + + Solução: se essa operação do TF: + + - Tiver suporte no TF: o erro ocorre porque a operação do TF está ausente na [lista de permissão](../../guide/op_select_allowlist.md) (uma lista completa das operações do TF com suporte no TF Lite). Você pode resolver da seguinte forma: + + 1. [Adicione as operações ausentes à lista de permissão](../../guide/op_select_allowlist.md#add_tensorflow_core_operators_to_the_allowed_list). + 2. [Converta o modelo do TF em um modelo do TF Lite e execute a inferência](../../guide/ops_select.md). + + - Não tiver suporte no TF: o erro ocorre porque o TF Lite não conhece o operador do TF personalizado definido por você. É possível resolver da seguinte forma: + + 1. [Crie a operação do TF](https://www.tensorflow.org/guide/create_op). + 2. [Converta o modelo do TF em um do TF Lite](../../guide/op_select_allowlist.md#users_defined_operators). + 3. [Crie e a operação do TF Lite](../../guide/ops_custom.md#create_and_register_the_operator) e execute a inferência fazendo sua vinculação ao runtime do TF Lite. + +## Ferramenta de linha de comando + +**Observação:** é altamente recomendável usar a [API do Python](#python_api) indicada acima, se possível. + +Se você [tiver instalado o TensorFlow 2.x via pip](https://www.tensorflow.org/install/pip), use o comando `tflite_convert`. Para ver todos os sinalizadores disponíveis, use o seguinte comando: + +```sh +$ tflite_convert --help + +`--output_file`. Type: string. Full path of the output file. +`--saved_model_dir`. Type: string. Full path to the SavedModel directory. +`--keras_model_file`. Type: string. Full path to the Keras H5 model file. +`--enable_v1_converter`. Type: bool. (default False) Enables the converter and flags used in TF 1.x instead of TF 2.x. + +You are required to provide the `--output_file` flag and either the `--saved_model_dir` or `--keras_model_file` flag. +``` + +Se você tiver baixado o [código-fonte do TensorFlow 2.x](https://www.tensorflow.org/install/source) e quiser executar o conversor a partir dele sem compilar e instalar o pacote, pode substituir '`tflite_convert`' por '`bazel run tensorflow/lite/python:tflite_convert --`' no comando. + +### Como converter um SavedModel + +```sh +tflite_convert \ + --saved_model_dir=/tmp/mobilenet_saved_model \ + --output_file=/tmp/mobilenet.tflite +``` + +### Como converter um modelo H5 do Keras + +```sh +tflite_convert \ + --keras_model_file=/tmp/mobilenet_keras_model.h5 \ + --output_file=/tmp/mobilenet.tflite +``` + +## Próximos passos + +Use o [interpretador do TensorFlow Lite](../../guide/inference.md) para executar a inferência em um dispositivo cliente (como um dispositivo móvel ou embarcado, por exemplo). diff --git a/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb b/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb new file mode 100644 index 0000000000..aeb1da8a5a --- /dev/null +++ b/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb @@ -0,0 +1,885 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Mq-riZs-TJGt" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "LEvnopDoTC4M" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QSRG6qmtTRSk" + }, + "source": [ + "# API TensorFlow Lite Metadata Writer\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JlzjEt4Txr0x" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b0gwEhfRYat6" + }, + "source": [ + "Os [metadados de modelos do TensorFlow Lite](https://www.tensorflow.org/lite/models/convert/metadata) são um formato padrão de descrição de modelos. Eles contêm uma semântica rica para informações gerais do modelo, entradas/saídas e arquivos associados, o que deixa o modelo mais autodescritivo e intercambiável.\n", + "\n", + "Atualmente, os metadados de modelos são usados nestes dois casos de uso principais:\n", + "\n", + "1. **Permitir fácil inferência do modelo usando a [biblioteca Task](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview) do TensorFlow Lite e as [ferramentas de geração de código](https://www.tensorflow.org/lite/inference_with_metadata/codegen)**. Os metadados do modelo contêm as informações obrigatórias exigidas durante a inferência, como os arquivos de rótulos em classificação de imagens, a taxa de amostragem de entrada de áudio em classificação de áudio e o tipo de tokenizador para processar a string de entrada em modelos de linguagem natural.\n", + "\n", + "2. **Permitir que os criadores de modelos incluam documentações**, como a descrição das entradas/saídas do modelo ou como usar o modelo. Os usuários podem ver essas documentações usando ferramentas de visualização, como o [Netron](https://netron.app/).\n", + "\n", + "A API de gravação de metadados do TensorFlow Lite conta com uma API fácil de usar para criar metadados de modelos para tarefas populares de aprendizado de máquina compatíveis com a biblioteca Task do TF Lite. Este notebook mostra exemplos de como os metadados devem ser preenchidos para as seguintes tarefas:\n", + "\n", + "- [Classificadores de imagem](#image_classifiers)\n", + "- [Detectores de objeto](#object_detectors)\n", + "- [Segmentadores de imagem](#image_segmenters)\n", + "- [Classificadores de linguagem natural](#nl_classifiers)\n", + "- [Classificadores de áudio](#audio_classifiers)\n", + "\n", + "Os gravadores de metadados para classificadores de linguagem natural BERT e para modelos de resposta a perguntas BERT serão disponibilizados em breve.\n", + "\n", + "Se você quiser adicionar metadados para casos de uso ainda não disponíveis, use a [API Flatbuffers do Python](https://www.tensorflow.org/lite/models/convert/metadata#adding_metadata). Confira os tutoriais [aqui](https://www.tensorflow.org/lite/models/convert/metadata#adding_metadata).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GVRIGdA4T6tO" + }, + "source": [ + "## Pré-requisitos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bVTD2KSyotBK" + }, + "source": [ + "Instale o pacote Pypi do TensorFlow Lite Support." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "m-8xSrSvUg-6" + }, + "outputs": [ + + ], + "source": [ + "!pip install tflite-support-nightly" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hyYS87Odpxef" + }, + "source": [ + "## Crie metadados do modelo para a biblioteca Task e o gerador de código" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uLxv541TqTim" + }, + "source": [ + "\n", + "\n", + "### Classificadores de imagem" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s41TjCGlsyEF" + }, + "source": [ + "Confira mais detalhes sobre o formato de modelo permitido nos [requisitos de compatibilidade de modelos de classificador de imagem](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier#model_compatibility_requirements)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_KsPKmg8T9-8" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hhgNqEtWrwB3" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import image_classifier\n", + "from tflite_support.metadata_writers import writer_utils" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "o9WBgiFdsiIQ" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de classificador de imagem, [mobilenet_v2_1.0_224.tflite](https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite) e o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6WgSBbNet-Tt" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite -o mobilenet_v2_1.0_224.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt -o mobilenet_labels.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ALtlz7woweHe" + }, + "source": [ + "Etapa 3 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_SMEBBt2r-W6" + }, + "outputs": [ + + ], + "source": [ + "ImageClassifierWriter = image_classifier.MetadataWriter\n", + "_MODEL_PATH = \"mobilenet_v2_1.0_224.tflite\"\n", + "# Task Library expects label files that are in the same format as the one below.\n", + "_LABEL_FILE = \"mobilenet_labels.txt\"\n", + "_SAVE_TO_PATH = \"mobilenet_v2_1.0_224_metadata.tflite\"\n", + "# Normalization parameters is required when reprocessing the image. It is\n", + "# optional if the image pixel values are in range of [0, 255] and the input\n", + "# tensor is quantized to uint8. See the introduction for normalization and\n", + "# quantization parameters below for more details.\n", + "# https://www.tensorflow.org/lite/models/convert/metadata#normalization_and_quantization_parameters)\n", + "_INPUT_NORM_MEAN = 127.5\n", + "_INPUT_NORM_STD = 127.5\n", + "\n", + "# Create the metadata writer.\n", + "writer = ImageClassifierWriter.create_for_inference(\n", + " writer_utils.load_file(_MODEL_PATH), [_INPUT_NORM_MEAN], [_INPUT_NORM_STD],\n", + " [_LABEL_FILE])\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GhhTDkr-uf0n" + }, + "source": [ + "\n", + "\n", + "### Detectores de objeto" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EL9GssnTuf0n" + }, + "source": [ + "Confira mais detalhes sobre o formato de modelo permitido nos [requisitos de compatibilidade de modelos de detector de objeto](https://www.tensorflow.org/lite/inference_with_metadata/task_library/object_detector#model_compatibility_requirements)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r-HUTEtHuf0n" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2_NIROeouf0o" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import object_detector\n", + "from tflite_support.metadata_writers import writer_utils" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UM6jijiUuf0o" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de detector de objeto, [ssd_mobilenet_v1.tflite](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/ssd_mobilenet_v1.tflite) e o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/labelmap.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4i_BBfGzuf0o" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/ssd_mobilenet_v1.tflite -o ssd_mobilenet_v1.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/labelmap.txt -o ssd_mobilenet_labels.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DG9T3eSDwsnd" + }, + "source": [ + "Etapa 3 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vMGGeJfCuf0p" + }, + "outputs": [ + + ], + "source": [ + "ObjectDetectorWriter = object_detector.MetadataWriter\n", + "_MODEL_PATH = \"ssd_mobilenet_v1.tflite\"\n", + "# Task Library expects label files that are in the same format as the one below.\n", + "_LABEL_FILE = \"ssd_mobilenet_labels.txt\"\n", + "_SAVE_TO_PATH = \"ssd_mobilenet_v1_metadata.tflite\"\n", + "# Normalization parameters is required when reprocessing the image. It is\n", + "# optional if the image pixel values are in range of [0, 255] and the input\n", + "# tensor is quantized to uint8. See the introduction for normalization and\n", + "# quantization parameters below for more details.\n", + "# https://www.tensorflow.org/lite/models/convert/metadata#normalization_and_quantization_parameters)\n", + "_INPUT_NORM_MEAN = 127.5\n", + "_INPUT_NORM_STD = 127.5\n", + "\n", + "# Create the metadata writer.\n", + "writer = ObjectDetectorWriter.create_for_inference(\n", + " writer_utils.load_file(_MODEL_PATH), [_INPUT_NORM_MEAN], [_INPUT_NORM_STD],\n", + " [_LABEL_FILE])\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QT0Oa0SU6uGS" + }, + "source": [ + "\n", + "\n", + "### Segmentadores de imagem" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XaFQmg-S6uGW" + }, + "source": [ + "Confira mais detalhes sobre o formato de modelo permitido nos [requisitos de compatibilidade de modelos de segmentador de imagem](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_segmenter#model_compatibility_requirements)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DiktANhj6uGX" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "H6Lrw3op6uGX" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import image_segmenter\n", + "from tflite_support.metadata_writers import writer_utils" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9EFs8Oyi6uGX" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de segmentador de imagem, [deeplabv3.tflite](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/deeplabv3.tflite) e o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/labelmap.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "feQDH0bN6uGY" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/deeplabv3.tflite -o deeplabv3.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/labelmap.txt -o deeplabv3_labels.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8LhiAbJM6uGY" + }, + "source": [ + "Etapa 3 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yot8xLI46uGY" + }, + "outputs": [ + + ], + "source": [ + "ImageSegmenterWriter = image_segmenter.MetadataWriter\n", + "_MODEL_PATH = \"deeplabv3.tflite\"\n", + "# Task Library expects label files that are in the same format as the one below.\n", + "_LABEL_FILE = \"deeplabv3_labels.txt\"\n", + "_SAVE_TO_PATH = \"deeplabv3_metadata.tflite\"\n", + "# Normalization parameters is required when reprocessing the image. It is\n", + "# optional if the image pixel values are in range of [0, 255] and the input\n", + "# tensor is quantized to uint8. See the introduction for normalization and\n", + "# quantization parameters below for more details.\n", + "# https://www.tensorflow.org/lite/models/convert/metadata#normalization_and_quantization_parameters)\n", + "_INPUT_NORM_MEAN = 127.5\n", + "_INPUT_NORM_STD = 127.5\n", + "\n", + "# Create the metadata writer.\n", + "writer = ImageSegmenterWriter.create_for_inference(\n", + " writer_utils.load_file(_MODEL_PATH), [_INPUT_NORM_MEAN], [_INPUT_NORM_STD],\n", + " [_LABEL_FILE])\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NnvM80e7AG-h" + }, + "source": [ + " ###Classificadores de linguagem natural" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dfOPhFwOAG-k" + }, + "source": [ + "Confira mais detalhes sobre o formato de modelo permitido nos [requisitos de compatibilidade de modelos de classificador de linguagem natural](https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier#model_compatibility_requirements)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WMJ7tvuwAG-k" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_FGVyb2iAG-k" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import nl_classifier\n", + "from tflite_support.metadata_writers import metadata_info\n", + "from tflite_support.metadata_writers import writer_utils" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iIg7rATpAG-l" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de classificador de linguagem natural, [movie_review.tflite](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/movie_review.tflite), o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/labels.txt) e o [arquivo de vocabulário](https://storage.googleapis.com/download.tensorflow.org/models/tflite_support/nl_classifier/vocab.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TzuQcti2AG-l" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/movie_review.tflite -o movie_review.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/labels.txt -o movie_review_labels.txt\n", + "!curl -L https://storage.googleapis.com/download.tensorflow.org/models/tflite_support/nl_classifier/vocab.txt -o movie_review_vocab.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BWxUtHdeAG-m" + }, + "source": [ + "Etapa 3 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NGPWzRuHAG-m" + }, + "outputs": [ + + ], + "source": [ + "NLClassifierWriter = nl_classifier.MetadataWriter\n", + "_MODEL_PATH = \"movie_review.tflite\"\n", + "# Task Library expects label files and vocab files that are in the same formats\n", + "# as the ones below.\n", + "_LABEL_FILE = \"movie_review_labels.txt\"\n", + "_VOCAB_FILE = \"movie_review_vocab.txt\"\n", + "# NLClassifier supports tokenize input string using the regex tokenizer. See\n", + "# more details about how to set up RegexTokenizer below:\n", + "# https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/metadata_writers/metadata_info.py#L130\n", + "_DELIM_REGEX_PATTERN = r\"[^\\w\\']+\"\n", + "_SAVE_TO_PATH = \"moview_review_metadata.tflite\"\n", + "\n", + "# Create the metadata writer.\n", + "writer = nl_classifier.MetadataWriter.create_for_inference(\n", + " writer_utils.load_file(_MODEL_PATH),\n", + " metadata_info.RegexTokenizerMd(_DELIM_REGEX_PATTERN, _VOCAB_FILE),\n", + " [_LABEL_FILE])\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qv0WDnzW711f" + }, + "source": [ + "\n", + "\n", + "### Classificadores de áudio" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xqP7X8jww8pL" + }, + "source": [ + "Confira mais detalhes sobre o formato de modelo permitido nos [requisitos de compatibilidade de modelos de classificador de áudio](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier#model_compatibility_requirements)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7RToKepxw8pL" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JjddvTXKw8pL" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import audio_classifier\n", + "from tflite_support.metadata_writers import metadata_info\n", + "from tflite_support.metadata_writers import writer_utils" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ar418rH6w8pL" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de classificador de áudio, [yamnet.tflite](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_wavin_quantized_mel_relu6.tflite) e o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/blob/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_521_labels.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5eQY6znmw8pM" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_wavin_quantized_mel_relu6.tflite -o yamnet.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_521_labels.txt -o yamnet_labels.txt\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1TYP5w0Ew8pM" + }, + "source": [ + "Etapa 3 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MDlSczBQw8pM" + }, + "outputs": [ + + ], + "source": [ + "AudioClassifierWriter = audio_classifier.MetadataWriter\n", + "_MODEL_PATH = \"yamnet.tflite\"\n", + "# Task Library expects label files that are in the same format as the one below.\n", + "_LABEL_FILE = \"yamnet_labels.txt\"\n", + "# Expected sampling rate of the input audio buffer.\n", + "_SAMPLE_RATE = 16000\n", + "# Expected number of channels of the input audio buffer. Note, Task library only\n", + "# support single channel so far.\n", + "_CHANNELS = 1\n", + "_SAVE_TO_PATH = \"yamnet_metadata.tflite\"\n", + "\n", + "# Create the metadata writer.\n", + "writer = AudioClassifierWriter.create_for_inference(\n", + " writer_utils.load_file(_MODEL_PATH), _SAMPLE_RATE, _CHANNELS, [_LABEL_FILE])\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YoRLs84yNAJR" + }, + "source": [ + "## Crie os metadados do modelo com informações semânticas" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cxXsOBknOGJ2" + }, + "source": [ + "Você pode preencher informações mais descritivas sobre o modelo e cada tensor por meio da API Metadata Writer (gravação de metadados) para ajudar a melhorar a compreensão do modelo. Isso pode ser feito pelo método 'create_from_metadata_info' em cada gravador de metadados. De forma geral, você pode preencher os dados por meio dos parâmetros de 'create_from_metadata_info', por exemplo: `general_md`, `input_md` e `output_md`. Confira o exemplo abaixo para criar metadados completos de modelos de classificadores de imagem." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Q-LW6nrcQ9lv" + }, + "source": [ + "Etapa 1 – Importe os pacotes obrigatórios." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KsL_egYcRGw3" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support.metadata_writers import image_classifier\n", + "from tflite_support.metadata_writers import metadata_info\n", + "from tflite_support.metadata_writers import writer_utils\n", + "from tflite_support import metadata_schema_py_generated as _metadata_fb" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0UWck_8uRboF" + }, + "source": [ + "Etapa 2 – Baixe o exemplo de classificador de imagem, [mobilenet_v2_1.0_224.tflite](https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite) e o [arquivo de rótulos](https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TqJ-jh-PRVdk" + }, + "outputs": [ + + ], + "source": [ + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite -o mobilenet_v2_1.0_224.tflite\n", + "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt -o mobilenet_labels.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r4I5wJMQRxzb" + }, + "source": [ + "Etapa 3 – Crie as informações do modelo e dos tensores." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "urd7HDuaR_HC" + }, + "outputs": [ + + ], + "source": [ + "model_buffer = writer_utils.load_file(\"mobilenet_v2_1.0_224.tflite\")\n", + "\n", + "# Create general model information.\n", + "general_md = metadata_info.GeneralMd(\n", + " name=\"ImageClassifier\",\n", + " version=\"v1\",\n", + " description=(\"Identify the most prominent object in the image from a \"\n", + " \"known set of categories.\"),\n", + " author=\"TensorFlow Lite\",\n", + " licenses=\"Apache License. Version 2.0\")\n", + "\n", + "# Create input tensor information.\n", + "input_md = metadata_info.InputImageTensorMd(\n", + " name=\"input image\",\n", + " description=(\"Input image to be classified. The expected image is \"\n", + " \"128 x 128, with three channels (red, blue, and green) per \"\n", + " \"pixel. Each element in the tensor is a value between min and \"\n", + " \"max, where (per-channel) min is [0] and max is [255].\"),\n", + " norm_mean=[127.5],\n", + " norm_std=[127.5],\n", + " color_space_type=_metadata_fb.ColorSpaceType.RGB,\n", + " tensor_type=writer_utils.get_input_tensor_types(model_buffer)[0])\n", + "\n", + "# Create output tensor information.\n", + "output_md = metadata_info.ClassificationTensorMd(\n", + " name=\"probability\",\n", + " description=\"Probabilities of the 1001 labels respectively.\",\n", + " label_files=[\n", + " metadata_info.LabelFileMd(file_path=\"mobilenet_labels.txt\",\n", + " locale=\"en\")\n", + " ],\n", + " tensor_type=writer_utils.get_output_tensor_types(model_buffer)[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "N5aL5Uxkf4aO" + }, + "source": [ + "Etapa 4 – Crie o gravador de metadados e preencha os metadados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_iWIwdqEf_mr" + }, + "outputs": [ + + ], + "source": [ + "ImageClassifierWriter = image_classifier.MetadataWriter\n", + "# Create the metadata writer.\n", + "writer = ImageClassifierWriter.create_from_metadata_info(\n", + " model_buffer, general_md, input_md, output_md)\n", + "\n", + "# Verify the metadata generated by metadata writer.\n", + "print(writer.get_metadata_json())\n", + "\n", + "# Populate the metadata into the model.\n", + "writer_utils.save_file(writer.populate(), _SAVE_TO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "z78vuu6np5sb" + }, + "source": [ + "## Leia os metadados preenchidos em seu modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DnWt-4oOselo" + }, + "source": [ + "É possível exibir os metadados e arquivos associados em um modelo do TF Lite por meio do seguinte código:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5D13YPUsp5VT" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support import metadata\n", + "\n", + "displayer = metadata.MetadataDisplayer.with_model_file(\"mobilenet_v2_1.0_224_metadata.tflite\")\n", + "print(\"Metadata populated:\")\n", + "print(displayer.get_metadata_json())\n", + "\n", + "print(\"Associated file(s) populated:\")\n", + "for file_name in displayer.get_packed_associated_file_list():\n", + " print(\"file name: \", file_name)\n", + " print(\"file content:\")\n", + " print(displayer.get_associated_file_buffer(file_name))" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "Mq-riZs-TJGt" + ], + "name": "metadata_writer_tutorial.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/convert/operation_fusion.md b/site/pt-br/lite/models/convert/operation_fusion.md new file mode 100644 index 0000000000..9a28dcaf1f --- /dev/null +++ b/site/pt-br/lite/models/convert/operation_fusion.md @@ -0,0 +1,256 @@ +# Combinação de operações do TensorFlow + +## Visão geral + +Esta etapa descreve o design e as etapas necessárias para converter operações compostas no TensorFlow em fused operations (operações combinadas) no TensorFlow Lite. Essa infraestrutura tem uma finalidade geral e oferece suporte à conversão de qualquer operação composta no TensorFlow em uma operação combinada correspondente no TensorFlow Lite. + +Um exemplo de uso dessa infraestrutura é a combinação de operações de RNN do TensorFlow no TensorFlow Lite, conforme detalhado [aqui](https://www.tensorflow.org/lite/models/convert/rnn). + +### O que são operações combinadas + +![drawing](../../images/convert/op_fusion_banner.jpg) + +As operações do TensorFlow podem ser primitivas, como [tf.add](https://www.tensorflow.org/api_docs/python/tf/math/add), ou podem ser compostas a partir de outras operações primitivas, como [tf.einsum](https://www.tensorflow.org/api_docs/python/tf/einsum). Uma operação primitiva é exibida como um único nó no grafo do TensorFlow, enquanto uma operação composta é uma coleção de nós no grafo do TensorFlow. Executar uma operação composta é equivalente a executar cada uma de suas operações primitivas. + +Uma operação combinada corresponde a uma única operação que agrupa toda a computação realizada por cada operação primitiva dentro da operação composta correspondente. + +### Vantagens das operações combinadas + +As operações combinadas existem para maximizar o desempenho das implementações de kernel subjacentes por meio da otimização das computações gerais e da redução do volume de memória. Isso traz muitas vantagens, especialmente para cargas de trabalho de inferência de baixa latência e para plataformas móveis com restrição de recursos. + +As operações combinadas também oferecem uma interface de alto nível para definir transformações complexas, como quantização, que seriam impraticáveis ou muito difíceis de fazer em um nível mais granular. + +O TensorFlow Lite tem diversas instâncias de operações combinadas pelos motivos indicados acima. Geralmente, essas operações combinadas correspondem a operações compostas no programa fonte do TensorFlow. Exemplos de operações compostas no TensorFlow que são implementadas como uma única operação combinada no TensorFlow Lite incluem diversas operações de RNN, como LSTM de sequência unidirecional ou bidirecional, convolução (conv2d, bias add, relu), totalmente conectadas (matmul, bias add, relu) e muitas outras. No TensorFlow Lite, a quantização de LSTM só é implementada nas operações de LSTM combinadas, no momento. + +### Desafios das operações combinadas + +Converter operações compostas do TensorFlow em operações combinadas do TensorFlow Lite é um problema difícil, pois: + +1. As operações compostas são representadas no grafo do TensorFlow como um conjunto de operações primitivas sem uma fronteira bem definida. Pode ser desafiador identificar (por exemplo, pela correspondência de padrões) o subgrafo correspondente a uma operação composta. + +2. Pode haver mais de uma implementação do TensorFlow usando uma operação combinada do TensorFlow Lite. Por exemplo: existem diversas implementações de LSTM no TensorFlow (Keras, Babelfish/lingvo, etc.), e cada uma delas é composta por diferentes operações primitivas, mas todas podem ser convertidas na mesma operação de LSTM combinada no TensorFlow Lite. + +Portanto, a conversão de operações combinadas se mostrou bastante desafiadora. + +## Como converter uma operação composta em uma operação personalizada do TF Lite (recomendado) + +### Encapsule a operação composta em uma `tf.function` + +Em diversos casos, uma parte do modelo pode ser mapeada em uma única operação no TF Lite, o que pode ajudar com o desempenho ao criar uma implementação otimizada de operações específicas. Para poder criar uma operação combinada no TF Lite, identifique a parte do grafo que representa uma operação combinada e encapsule-a em uma `tf.function` com o atributo "experimental_implements" para uma `tf.function`, que tem o atributo `tfl_fusable_op` com valor `true`. Se a operação personalizada aceitar atributos, passe-os como parte do mesmo "experimental_implements". + +Exemplo: + +```python +def get_implements_signature(): + implements_signature = [ + # 'name' will be used as a name for the operation. + 'name: "my_custom_fused_op"', + # attr "tfl_fusable_op" is required to be set with true value. + 'attr {key: "tfl_fusable_op" value { b: true } }', + # Example attribute "example_option" that the op accepts. + 'attr {key: "example_option" value { i: %d } }' % 10 + ] + return ' '.join(implements_signature) + +@tf.function(experimental_implements=get_implements_signature()) +def my_custom_fused_op(input_1, input_2): + # An empty function that represents pre/post processing example that + # is not represented as part of the Tensorflow graph. + output_1 = tf.constant(0.0, dtype=tf.float32, name='first_output') + output_2 = tf.constant(0.0, dtype=tf.float32, name='second_output') + return output_1, output_2 + +class TestModel(tf.Module): + def __init__(self): + super(TestModel, self).__init__() + self.conv_1 = tf.keras.layers.Conv2D(filters=1, kernel_size=(3, 3)) + self.conv_2 = tf.keras.layers.Conv2D(filters=1, kernel_size=(3, 3)) + + @tf.function(input_signature=[ + tf.TensorSpec(shape=[1, 28, 28, 3], dtype=tf.float32), + tf.TensorSpec(shape=[1, 28, 28, 3], dtype=tf.float32), + ]) + def simple_eval(self, input_a, input_b): + return my_custom_fused_op(self.conv_1(input_a), self.conv_2(input_b)) +``` + +Você não precisa definir `allow_custom_ops` no conversor, pois o atributo `tfl_fusable_op` já pressupõe isso. + +### Implemente a operação personalizada e registre no interpretador do TFLite + +Implemente a operação combinada como uma operação personalizada do TF Lite – confira as [instruções](https://www.tensorflow.org/lite/guide/ops_custom). + +O nome para registrar a operação deve ser similar ao nome especificado no atributo `name` na assinatura implements. + +Veja um exemplo dessa operação: + +```c++ + TfLiteRegistration reg = {}; + // This name must match the name specified in the implements signature. + static constexpr char kOpName[] = "my_custom_fused_op"; + reg.custom_name = kOpName; + reg.prepare = [](TfLiteContext* context, TfLiteNode* node) -> TfLiteStatus { + // Add your code. + return kTfLiteOk; + }; + reg.invoke = [](TfLiteContext* context, TfLiteNode* node) -> TfLiteStatus { + // Add your code. + return kTfLiteOk; + }; + reg.builtin_code = kTfLiteCustom; + resolver->AddCustom(kOpName, ®); +``` + +## Como converter uma operação composta em uma combinada (avançado) + +Veja abaixo a arquitetura geral para converter operações compostas do TensorFlow em operações combinadas do TensorFlow Lite. + +![drawing](../../images/convert/op_fusion.png) + +### Encapsule a operação composta em uma `tf.function` + +No código-fonte do modelo do TensorFlow, identifique e abstraia a operação personalizada em uma `tf.function` com a anotação de função [experimental_implements](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/python/eager/def_function.py#L470). Confira um exemplo de [pesquisa de embedding](#composing_ops). A função define a interface, e seus argumentos devem ser usados para implementar a lógica de conversão. + +### Escreva o código de conversão + +O código de conversão é escrito para cada interface da função com a anotação `implements`. Confira um exemplo de combinação para [pesquisa de embedding](#fusion_code). Conceitualmente, o código de conversão substitui a implementação composta dessa interface pela combinada. + +Na etapa prepare-composite-functions "preparar funções compostas", adicione seu [código de conversão](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L115). + +Em casos mais avançados, é possível implementar transformações complexas dos operandos da operação composta para derivar os operandos da operação combinada. Confira o código de conversão de [LSTM do Keras](https://github.com/tensorflow/tensorflow/blob/1099faa8d6a941ef44d09ed8c372ff0ffda94112/tensorflow/compiler/mlir/lite/utils/lstm_utils.cc#L627) como exemplo. + +### Converta para o TensorFlow Lite + +Use a API [TFLiteConverter.from_saved_model](https://www.tensorflow.org/api_docs/python/tf/lite/TFLiteConverter#from_saved_model) para converter para o TensorFlow Lite. + +## Nos bastidores + + + +Agora vamos descrever os detalhes de alto nível do design geral da conversão em operações combinadas no TensorFlow Lite. + +### Como compor operações no TensorFlow + + + +Ao usar `tf.function` com o atributo de função [experimental_implements](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/python/eager/def_function.py#L470), os usuários podem compor explicitamente novas operações usando as operações primitivas do TensorFlow e especificar a interface que a operação composta relevante implementa. Isso é muito útil, pois: + +1. Fornece uma fronteira bem definida para a operação composta no grafo do TensorFlow subjacente. +2. Especifica explicitamente a interface que essa operação implementa. Os argumentos de `tf.function` correspondem aos argumentos dessa interface. + +Para fins de exemplo, vamos considerar uma operação composta definida para implementar pesquisa de embedding. Ela é mapeada para uma operação combinada no TensorFlow Lite. + +```python + @tf.function( + experimental_implements="embedding_lookup") + def EmbFprop(embs, ids_vec): + """Embedding forward prop. + + Effectively, it computes: + num = size of ids_vec + rets = zeros([num, embedding dim]) + for i in range(num): + rets[i, :] = embs[ids_vec[i], :] + return rets + + Args: + embs: The embedding matrix. + ids_vec: A vector of int32 embedding ids. + + Returns: + The result of embedding lookups. A matrix of shape + [num ids in ids_vec, embedding dims]. + """ + num = tf.shape(ids_vec)[0] + rets = inplace_ops.empty([num] + emb_shape_suf, py_utils.FPropDtype(p)) + + def EmbFpropLoop(i, embs, ids_vec, rets): + # row_id = ids_vec[i] + row_id = tf.gather(ids_vec, i) + # row = embs[row_id] + row = tf.reshape(tf.gather(embs, row_id), [1] + emb_shape_suf) + # rets[i] = row + rets = inplace_ops.alias_inplace_update(rets, [i], row) + return embs, ids_vec, rets + + _, _, rets = functional_ops.For( + start=0, + limit=num, + delta=1, + inputs=[embs, ids_vec, rets], + body=EmbFpropLoop, + rewrite_with_while=compiled) + if len(weight_shape) > 2: + rets = tf.reshape(rets, [num, symbolic.ToStatic(p.embedding_dim)]) + return rets +``` + +Ao fazer os modelos usarem operações compostas via `tf.function` conforme ilustrado acima, é possível criar uma estrutura geral para **identificar e converter** essas operações em operações combinadas do TensorFlow Lite. + +### Como estender o conversor do TensorFlow Lite + +O conversor do TensorFlow Lite lançado anteriormente neste ano só oferecia suporte à importação de modelos do TensorFlow como um grafo com todas as variáveis substituídas por seus valores constantes correspondentes, o que não funciona para a combinação de operações, já que esses grafos têm todas as funções embutidas para que as variáveis possam ser transformadas em constantes. + +Para poder usar `tf.function` com o recurso `experimental_implements` durante o processo de conversão, as funções precisam ser preservadas até as etapas posteriores do processo de conversão. + +Dessa forma, implementamos um novo workflow de importação e conversão de modelos do TensorFlow no conversor para oferecer suporte à combinação de operações compostas. Especificamente, os novos recursos adicionados são: + +1. Importação de [SavedModels do TensorFlow na MLIR](https://github.com/tensorflow/tensorflow/blob/1099faa8d6a941ef44d09ed8c372ff0ffda94112/tensorflow/compiler/mlir/tensorflow/translate/import_model.cc#L3748) +2. [Combinação de operações compostas](https://github.com/tensorflow/tensorflow/blob/1099faa8d6a941ef44d09ed8c372ff0ffda94112/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L103) +3. [Análise de mutabilidade variável](https://github.com/tensorflow/tensorflow/blob/1099faa8d6a941ef44d09ed8c372ff0ffda94112/tensorflow/compiler/mlir/tensorflow/transforms/optimize_global_tensors.cc#L43) +4. [Congelamento de todas as variáveis somente leitura](https://github.com/tensorflow/tensorflow/blob/1099faa8d6a941ef44d09ed8c372ff0ffda94112/tensorflow/compiler/mlir/tensorflow/transforms/freeze_global_tensors.cc#L44) + +Dessa forma, podemos fazer a combinação de operações usando as funções que representam as operações compostas antes de as funções serem embutidas e de as variáveis serem congeladas. + +### Como implementar a combinação de operações + +Vamos avaliar a etapa de combinação de operações com maiores detalhes. Essa etapa faz o seguinte: + +1. Percorre em um loop todas as funções no módulo MLIR. +2. Se uma função tiver o atributo tf._implements – com base no valor do atributo, chama o utilitário de combinação de operações apropriado. +3. O utilitário de combinação de operações trabalha com os operandos e atributos da função (que servem como a interface para a conversão) e substitui o corpo da função por um corpo de função equivalente que contém a operação combinada. +4. Em diversos casos, o corpo substituído conterá operações diferentes da operação combinada, que correspondem a algumas transformações estáticas dos operandos da função para obter os operandos da operação combinada. Como essas computações podem sofrer constant-folding, não estariam presentes no Flatbuffer exportado, em que somente a operação combinada existiria. + +Aqui está o trecho de código da etapa, mostrando o workflow principal: + +``` +void PrepareCompositeFunctionsPass::ConvertTFImplements(FuncOp func, + StringAttr attr) { + if (attr.getValue() == "embedding_lookup") { + func.eraseBody(); + func.addEntryBlock(); + // Convert the composite embedding_lookup function body to a + // TFLite fused embedding_lookup op. + ConvertEmbeddedLookupFunc convert_embedded_lookup(func); + if (failed(convert_embedded_lookup.VerifySignature())) { + return signalPassFailure(); + } + convert_embedded_lookup.RewriteFunc(); + } else if (attr.getValue() == mlir::TFL::kKerasLstm) { + func.eraseBody(); + func.addEntryBlock(); + OpBuilder builder(func.getBody()); + if (failed(ConvertKerasLSTMLayer(func, &builder))) { + return signalPassFailure(); + } + } else if (.....) /* Other fusions can plug in here */ +} +``` + +Aqui está o trecho de código mostrando o mapeamento dessa operação composta para uma operação combinada no TensorFlow Lite usando a função como uma interface de conversão. + + + +```c++ +void RewriteFunc() { + Value lookup = func_.getArgument(1); + Value value = func_.getArgument(0); + auto output_type = func_.getType().getResult(0); + + OpBuilder builder(func_.getBody()); + auto op = builder.create( + func_.getLoc(), output_type, lookup, value); + + builder.create(func_.getLoc(), op.getResult()); + } +``` diff --git a/site/pt-br/lite/models/convert/rnn.md b/site/pt-br/lite/models/convert/rnn.md new file mode 100644 index 0000000000..6ad6211da6 --- /dev/null +++ b/site/pt-br/lite/models/convert/rnn.md @@ -0,0 +1,113 @@ +# Conversão de RNN do TensorFlow para o TensorFlow Lite + +## Visão geral + +O TensorFlow Lite oferece suporte à conversão de modelos de RNN do TensorFlow em operações de LSTM combinadas do TensorFlow Lite. As operações combinadas existem para maximizar o desempenho das implementações de kernel subjacentes, bem como para fornecer uma interface de alto nível para definir transformações complexas, como quantização. + +Como existem diversas variantes das APIs de RNN no TensorFlow, temos duas estratégias: + +1. Oferecer **suporte nativo às APIs padrão de RNN do TensorFlow**, como LSTM do Keras. Essa é a opção recomendada. +2. Oferecer uma **interface** **para a infraestrutura de conversão para ** **implementações de RNN** **definidas pelo usuário** a fim de incluir e converter para o TensorFlow Lite. Fornecemos alguns exemplos prontos dessa conversão usando [LSTMCellSimple](https://github.com/tensorflow/tensorflow/blob/82abf0dbf316526cd718ae8cd7b11cfcb805805e/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L130) do Lingvo e as interfaces de RNN [LayerNormalizedLSTMCellSimple](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L137). + +## API de conversão + +Esse recurso faz parte do TensorFlow versão 2.3 e também está disponível via pip [tf-nightly](https://pypi.org/project/tf-nightly/) ou pelo head. + +Essa funcionalidade de conversão está disponível ao converter para o TensorFlow Lite usando um SavedModel ou um modelo do Keras diretamente. Veja os exemplos de uso. + +### Usando um SavedModel + + + +``` +# build a saved model. Here concrete_function is the exported function +# corresponding to the TensorFlow model containing one or more +# Keras LSTM layers. +saved_model, saved_model_dir = build_saved_model_lstm(...) +saved_model.save(saved_model_dir, save_format="tf", signatures=concrete_func) + +# Convert the model. +converter = TFLiteConverter.from_saved_model(saved_model_dir) +tflite_model = converter.convert() +``` + +### Usando um modelo do Keras + +``` +# build a Keras model +keras_model = build_keras_lstm(...) + +# Convert the model. +converter = TFLiteConverter.from_keras_model(keras_model) +tflite_model = converter.convert() + +``` + +## Exemplo + +O [Colab](https://colab.research.google.com/github/tensorflow/tensorflow/blob/master/tensorflow/lite/examples/experimental_new_converter/Keras_LSTM_fusion_Codelab.ipynb) LSTM do Keras para TensorFlow Lite ilustra um exemplo completo usando o interpretador do TensorFlow Lite. + +## APIs de RNN do TensorFlow com suporte + + + +### Conversão de LSTM do Keras (recomendado) + +Temos suporte integrado à conversão de LSTM do Keras para o TensorFlow Lite. Confira os detalhes de funcionamento na [interface de LSTM do Keras](https://github.com/tensorflow/tensorflow/blob/35a3ab91b42503776f428bda574b74b9a99cd110/tensorflow/python/keras/layers/recurrent_v2.py#L1238) e sua lógica de conversão [aqui](https://github.com/tensorflow/tensorflow/blob/35a3ab91b42503776f428bda574b74b9a99cd110/tensorflow/compiler/mlir/lite/utils/lstm_utils.cc#L627). + +Também é importante ressaltar o contrato da LSTM do TensorFlow Lite em relação à definição de operações do Keras: + +1. A dimensão 0 do tensor **input** é o tamanho do lote. +2. A dimensão 0 do tensor **recurrent_weight** é o número de saídas. +3. Os tensores **weight** e **recurrent_kernel** são transpostos. +4. Os tensores weight transposto, recurrent_kernel transposto e **bias** são divididos em 4 tensores de tamanho igual ao longo da dimensão 0. Eles correspondem a **input gate, forget gate, cell e output gate**. + +#### Variantes de LSTM do Keras + +##### Time major + +Os usuários podem optar por usar ou não time-major. A LSTM do Keras adiciona um atributo time-major aos atributos da definição da função. Para LSTM de sequência unidirecional, podemos simplesmente mapear para [atributo time major](https://github.com/tensorflow/tensorflow/blob/35a3ab91b42503776f428bda574b74b9a99cd110/tensorflow/compiler/mlir/lite/ir/tfl_ops.td#L3902) da unidirecional_sequence_lstm. + +##### LSTM bidirecional + +A LSTM bidirecional pode ser implementada com duas camadas LSTM do Keras, uma para frente e uma para trás. Confira alguns exemplos [aqui](https://github.com/tensorflow/tensorflow/blob/35a3ab91b42503776f428bda574b74b9a99cd110/tensorflow/python/keras/layers/wrappers.py#L382). Quando há o atributo go_backward, reconhecemos como LSTM para trás e agrupamos a LSTM para trás e para frente. **Isso ainda será desenvolvido.** No momento, são criadas duas operações UnidirectionalSequenceLSTM no modelo do TensorFlow Lite. + +### Exemplos de conversão de LSTM definida pelo usuário + +O TensorFlow Lite também conta com uma forma de converter implementações de LSTM definidas pelo usuário. Aqui, usamos a LSTM do Lingvo como exemplo de implementação. Confira mais detalhes na [interface lingvo.LSTMCellSimple](https://github.com/tensorflow/lingvo/blob/91a4609dbc2579748a95110eda59c66d17c594c5/lingvo/core/rnn_cell.py#L228) e sua lógica de conversão [aqui](https://github.com/tensorflow/tensorflow/blob/82abf0dbf316526cd718ae8cd7b11cfcb805805e/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L130). Também oferecemos um exemplo de outra definição de LSTM do Lingvo na [interface lingvo.LayerNormalizedLSTMCellSimple](https://github.com/tensorflow/lingvo/blob/91a4609dbc2579748a95110eda59c66d17c594c5/lingvo/core/rnn_cell.py#L1173) e sua lógica de conversão [aqui](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L137). + +## “Traga sua própria RNN do TensorFlow” para o TensorFlow Lite + +Se a interface da RNN de um usuário for diferente das interfaces padrão com suporte, existem algumas opções: + +**Opção 1:** escreva o código adaptador no Python do TensorFlow para adaptar a interface da RNN à interface da RNN do Keras. Portanto, é preciso ter uma tf.function com a [anotação tf_implements](https://github.com/tensorflow/community/pull/113) na função da interface da RNN gerada que seja idêntica à gerada pela camada de LSTM do Keras. Em seguida, a mesma API de conversão usada para a LSTM do Keras funcionará. + +**Opção 2:** se não for possível seguir a instrução acima (por exemplo, se a LSTM do Keras não tiver alguma funcionalidade exposta atualmente pela operação de LSTM combinada do TensorFlow Lite, como normalização de camadas), é preciso estender o conversor do TensorFlow Lite: basta escrever um código de conversão personalizado e incluí-lo no passo da MLIR prepare-composite-functions (preparar funções compostas) [aqui](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L115). A interface da função deve ser tratada como um contrato de API e deve conter os argumentos necessários para converter para operações de LSTM combinadas do TensorFlow Lite, como entrada, bias, pesos, projeção, normalização de camadas, etc. É preferível que os tensores passados como argumentos para essa função tenham um posto conhecido (por exemplo, RankedTensorType na MLIR). Dessa forma, fica muito mais fácil escrever código de conversão que possa presumir que esses tensores sejam RankedTensorType, além de ser possível transformá-los em tensores com posto correspondentes aos operandos da operação combinada do TensorFlow Lite. + +Um exemplo completo desse workflow de conversão é o LSTMCellSimple do Lingvo para conversão para o TensorFlow Lite. + +O LSTMCellSimple do Lingvo está definido [aqui](https://github.com/tensorflow/lingvo/blob/91a4609dbc2579748a95110eda59c66d17c594c5/lingvo/core/rnn_cell.py#L228). Os modelos treinados com essa célula de LSTM podem ser convertidos para o TensorFlow Lite da seguinte forma: + +1. Encapsule todos os usos de LSTMCellSimple em uma tf.function com a anotação tf_implements que seja rotulada dessa forma (por exemplo, lingvo.LSTMCellSimple seria um bom nome de anotação nesse caso). A tf.function gerada precisa coincidir com a interface da função esperada pelo código de conversão. Isso é um contrato entre o autor do modelo que adiciona a anotação e o código de conversão. + +2. Estenda o passo prepare-composite-functions para incluir uma operação composta personalizada para a conversão em operação de LSTM combinada do TensorFlow Lite. Confira o código de conversão [LSTMCellSimple](https://github.com/tensorflow/tensorflow/blob/82abf0dbf316526cd718ae8cd7b11cfcb805805e/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L130). + + Contrato de conversão: + +3. Os tensores **weight** e **projection** são transpostos. + +4. **{input, recurrent}** de **{cell, input gate, forget gate, output gate}** são extraídos por meio do fatiamento do tensor de pesos transposto. + +5. **{bias}** de **{cell, input gate, forget gate, output gate}** é extraído pelo fatiamento do tensor bias. + +6. **projection** é extraída pelo fatiamento do tensor de projeção transposto. + +7. Uma conversão similar é escrita para [LayerNormalizedLSTMCellSimple](https://github.com/tensorflow/tensorflow/blob/c11d5d8881fd927165eeb09fd524a80ebaf009f2/tensorflow/compiler/mlir/lite/transforms/prepare_composite_functions_tf.cc#L137). + +8. É possível reutilizar o restante da infraestrutura de conversão do TensorFlow Lite, incluindo todos os [passos da MLIR](https://github.com/tensorflow/tensorflow/blob/35a3ab91b42503776f428bda574b74b9a99cd110/tensorflow/compiler/mlir/lite/tf_tfl_passes.cc#L57), bem como a exportação final para Flatbuffer do TensorFlow Lite. + +## Limitações/problemas conhecidos + +1. No momento, há suporte somente à conversão de LSTM stateless do Keras (comportamento padrão do Keras). A conversão de LSTM stateful do Keras ainda será desenvolvida. +2. Ainda é possível modelar uma camada de LSTM stateful do Keras usando a camada de LSTM stateless do Keras subjacente e gerenciando o estado explicitamente no programa do usuário. Um programa do TensorFlow como esse ainda pode ser convertido para o TensorFlow Lite usando o recurso descrito aqui. +3. No momento, a LSTM bidirecional é modelada como duas operações UnidirectionalSequenceLSTM no TensorFlow Lite. Isso será substituído por uma única operação BidirectionalSequenceLSTM. diff --git a/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb new file mode 100644 index 0000000000..38c470412d --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb @@ -0,0 +1,661 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "3XX46cTrh6iD" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "sKrlWr6Kh-mF" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hST65kOHXpiL" + }, + "source": [ + "# Aprendizado por transferência para áudio com o TensorFlow Lite Model Maker\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + " Ver modelo do TF Hub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BB5k6xNKJ5Xe" + }, + "source": [ + "Neste notebook do Colab, você verá como usar o [TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) para treinar um modelo personalizado de classificação de áudio.\n", + "\n", + "A biblioteca Model Maker usa aprendizado por transferência para simplificar o processo de treinar um modelo do TensorFlow Lite usando um dataset personalizado. Retreinar um modelo do TensorFlow Lite com seu próprio dataset personalizado reduz a quantidade necessária de dados de treinamento e tempo.\n", + "\n", + "Este notebook faz parte do [Codelab para personalizar um modelo de áudio e implantar no Android](https://codelabs.developers.google.com/codelabs/tflite-audio-classification-custom-model-android).\n", + "\n", + "Você usará um dataset personalizado de pássaros e exportará um modelo do TF Lite que pode ser usado em um celular, um modelo TensorFlow.JS que pode ser usado para inferência no navegador e também uma versão SavedModel que pode ser usada como serviço.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AeZZ_cSsZfPx" + }, + "source": [ + "## Instale as dependências\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wbMc4vHjaYdQ" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install tflite-model-maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "z2ck_Ghdcgt9" + }, + "source": [ + "## Importe o TensorFlow, o Model Maker e outras bibliotecas\n", + "\n", + "Dentre as dependências necessárias, você usará o TensorFlow e o Model Maker. Além delas, as outras são para manipulação e reprodução de áudio, além de visualização." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rwUA9u4oWoCR" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "import tflite_model_maker as mm\n", + "from tflite_model_maker import audio_classifier\n", + "import os\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "import itertools\n", + "import glob\n", + "import random\n", + "\n", + "from IPython.display import Audio, Image\n", + "from scipy.io import wavfile\n", + "\n", + "print(f\"TensorFlow Version: {tf.__version__}\")\n", + "print(f\"Model Maker Version: {mm.__version__}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HIfm2TxKZAuA" + }, + "source": [ + "## Dataset Birds\n", + "\n", + "O dataset Birds é uma coleção educativa do canto de cinco pássaros:\n", + "\n", + "- White-breasted Wood-Wren (Uirapuru-de-peito-branco)\n", + "- House Sparrow (Pardal-doméstico)\n", + "- Red Crossbill (Cruza-bico)\n", + "- Chestnut-crowned Antpitta (Grallaria ruficapilla)\n", + "- Azara's Spinetail (Synallaxis azarae)\n", + "\n", + "O áudio original vem de [Xeno-canto](https://www.xeno-canto.org/), um site dedicado ao compartilhamento de cantos de pássaros de todo o mundo.\n", + "\n", + "Vamos começar pelo download dos dados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "upNRfilkNSmr" + }, + "outputs": [ + + ], + "source": [ + "birds_dataset_folder = tf.keras.utils.get_file('birds_dataset.zip',\n", + " 'https://storage.googleapis.com/laurencemoroney-blog.appspot.com/birds_dataset.zip',\n", + " cache_dir='./',\n", + " cache_subdir='dataset',\n", + " extract=True)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "441bbzZ5d6oq" + }, + "source": [ + "## Explore os dados\n", + "\n", + "Os áudios já estão divididos em pastas de teste e treinamento. Dentro de cada pasta, há uma pasta para cada pássaro, usando `bird_code` como nome.\n", + "\n", + "Todos os áudios são mono, com taxa de amostragem de 16 kHz.\n", + "\n", + "Confira mais informações sobre cada arquivo no arquivo `metadata.csv`, que contém todos os autores, licenças e informações adicionais. Para este tutorial, não é preciso ler esse arquivo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ayd7UqCfQQFU" + }, + "outputs": [ + + ], + "source": [ + "# @title [Run this] Util functions and data structures.\n", + "\n", + "data_dir = './dataset/small_birds_dataset'\n", + "\n", + "bird_code_to_name = {\n", + " 'wbwwre1': 'White-breasted Wood-Wren',\n", + " 'houspa': 'House Sparrow',\n", + " 'redcro': 'Red Crossbill', \n", + " 'chcant2': 'Chestnut-crowned Antpitta',\n", + " 'azaspi1': \"Azara's Spinetail\", \n", + "}\n", + "\n", + "birds_images = {\n", + " 'wbwwre1': 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Henicorhina_leucosticta_%28Cucarachero_pechiblanco%29_-_Juvenil_%2814037225664%29.jpg/640px-Henicorhina_leucosticta_%28Cucarachero_pechiblanco%29_-_Juvenil_%2814037225664%29.jpg', # \tAlejandro Bayer Tamayo from Armenia, Colombia \n", + " 'houspa': 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/House_Sparrow%2C_England_-_May_09.jpg/571px-House_Sparrow%2C_England_-_May_09.jpg', # \tDiliff\n", + " 'redcro': 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/Red_Crossbills_%28Male%29.jpg/640px-Red_Crossbills_%28Male%29.jpg', # Elaine R. Wilson, www.naturespicsonline.com\n", + " 'chcant2': 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Chestnut-crowned_antpitta_%2846933264335%29.jpg/640px-Chestnut-crowned_antpitta_%2846933264335%29.jpg', # \tMike's Birds from Riverside, CA, US\n", + " 'azaspi1': 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Synallaxis_azarae_76608368.jpg/640px-Synallaxis_azarae_76608368.jpg', # https://www.inaturalist.org/photos/76608368\n", + "}\n", + "\n", + "test_files = os.path.abspath(os.path.join(data_dir, 'test/*/*.wav'))\n", + "\n", + "def get_random_audio_file():\n", + " test_list = glob.glob(test_files)\n", + " random_audio_path = random.choice(test_list)\n", + " return random_audio_path\n", + "\n", + "\n", + "def show_bird_data(audio_path):\n", + " sample_rate, audio_data = wavfile.read(audio_path, 'rb')\n", + "\n", + " bird_code = audio_path.split('/')[-2]\n", + " print(f'Bird name: {bird_code_to_name[bird_code]}')\n", + " print(f'Bird code: {bird_code}')\n", + " display(Image(birds_images[bird_code]))\n", + "\n", + " plttitle = f'{bird_code_to_name[bird_code]} ({bird_code})'\n", + " plt.title(plttitle)\n", + " plt.plot(audio_data)\n", + " display(Audio(audio_data, rate=sample_rate))\n", + "\n", + "print('functions and data structures created')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Yrv0uD7aXYl4" + }, + "source": [ + "### Reproduza alguns áudios\n", + "\n", + "Para entender melhor os dados, vamos ouvir arquivos de áudio aleatórios do dataset de teste.\n", + "\n", + "Observação: posteriormente neste notebook, você executará a inferência nestes áudios para teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tEeMZh-VQy97" + }, + "outputs": [ + + ], + "source": [ + "random_audio = get_random_audio_file()\n", + "show_bird_data(random_audio)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pQj1Mf7YZELS" + }, + "source": [ + "## Treine o modelo\n", + "\n", + "Ao usar o Model Maker para áudio, você precisa começar pela especificação do modelo, que será o modelo base do qual o novo modelo extrairá informações para aprender sobre as novas classes. Além disso, ele afeta como o dataset será transformado para respeitar os parâmetros de especificação dos modelos, como taxa de amostragem e número de canais.\n", + "\n", + "[YAMNet](https://tfhub.dev/google/yamnet/1) é um classificador de eventos de áudio treinado com o dataset AudioSet para prever eventos de áudios da ontologia AudioSet.\n", + "\n", + "É esperado que a entrada esteja em 16 kHz e tenha 1 canal.\n", + "\n", + "Você não precisa fazer novas amostragens, pois o Model Maker cuida dessa tarefa.\n", + "\n", + "- `frame_length` decide o tamanho de cada amostra de treinamento. Neste caso, EXPECTED_WAVEFORM_LENGTH * 3s\n", + "\n", + "- `frame_steps` indica a distância entre as amostras de treinamento. Neste caso, a amostra i começará EXPECTED_WAVEFORM_LENGTH * 6s após a amostra (i-1).\n", + "\n", + "O motivo de definir esses valores é poder contornar algumas limitações de datasets do mundo real.\n", + "\n", + "Por exemplo: no dataset Birds, os pássaros não cantam o tempo todo. Eles cantam, descansam, cantam novamente, e há ruídos nesses períodos. Usar um quadro longo ajuda a capturar o canto, mas, se for longo demais, reduz o número de amostras de treinamento.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tUcxtfHXY7XS" + }, + "outputs": [ + + ], + "source": [ + "spec = audio_classifier.YamNetSpec(\n", + " keep_yamnet_and_custom_heads=True,\n", + " frame_step=3 * audio_classifier.YamNetSpec.EXPECTED_WAVEFORM_LENGTH,\n", + " frame_length=6 * audio_classifier.YamNetSpec.EXPECTED_WAVEFORM_LENGTH)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EF185yZ_M7zu" + }, + "source": [ + "## Carregue os dados\n", + "\n", + "O Model Maker tem uma API para carregar os dados a partir de uma pasta e colocá-los no formato esperado pela especificação do modelo.\n", + "\n", + "Os datasets de treinamento e teste são baseados nas pastas. O dataset de validação será criado como 20% do de treinamento.\n", + "\n", + "Observação: é importante usar `cache=True` para deixar o treinamento posterior mais rápido, mas isso exigirá mais RAM para armazenar os dados. Para o dataset Birds, não é um problema, já que são apenas 300 MB, mas, se você usar seus próprios dados, tenha cuidado com isso.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cX0RqETqZgzo" + }, + "outputs": [ + + ], + "source": [ + "train_data = audio_classifier.DataLoader.from_folder(\n", + " spec, os.path.join(data_dir, 'train'), cache=True)\n", + "train_data, validation_data = train_data.split(0.8)\n", + "test_data = audio_classifier.DataLoader.from_folder(\n", + " spec, os.path.join(data_dir, 'test'), cache=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ziMghju-Rts2" + }, + "source": [ + "## Treine o modelo\n", + "\n", + "O classificador de áudio audio_classifier conta com o método [`create`](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier/create), que cria um modelo e já começa a treiná-lo.\n", + "\n", + "Você pode personalizar diversos parâmetros. Confira mais informações na documentação.\n", + "\n", + "Neste primeiro teste, você usará as configurações padrão e fará o treinamento com 100 épocas.\n", + "\n", + "Observação: a primeira época leva mais tempo do que todas as outras porque é quando o cache é criado. Depois disso, cada época leva aproximadamente 1 segundo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8r6Awvl4ZkIv" + }, + "outputs": [ + + ], + "source": [ + "batch_size = 128\n", + "epochs = 100\n", + "\n", + "print('Training the model')\n", + "model = audio_classifier.create(\n", + " train_data,\n", + " spec,\n", + " validation_data,\n", + " batch_size=batch_size,\n", + " epochs=epochs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oXMEHZkAxJTl" + }, + "source": [ + "A exatidão está boa, mas é importante executar o passo de avaliação com os dados de teste para verificar se o modelo tem bons resultados com dados independentes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GDoQACMrZnOx" + }, + "outputs": [ + + ], + "source": [ + "print('Evaluating the model')\n", + "model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8QRRAM39aOxS" + }, + "source": [ + "## Sobre o modelo\n", + "\n", + "Ao treinar um classificador, é útil conferir a [matriz de confusão](https://en.wikipedia.org/wiki/Confusion_matrix), que fornece detalhes sobre o desempenho do classificador para os dados de teste.\n", + "\n", + "O Model Maker já cria a matriz de confusão para você." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zqB3c0368iH3" + }, + "outputs": [ + + ], + "source": [ + "def show_confusion_matrix(confusion, test_labels):\n", + " \"\"\"Compute confusion matrix and normalize.\"\"\"\n", + " confusion_normalized = confusion.astype(\"float\") / confusion.sum(axis=1)\n", + " axis_labels = test_labels\n", + " ax = sns.heatmap(\n", + " confusion_normalized, xticklabels=axis_labels, yticklabels=axis_labels,\n", + " cmap='Blues', annot=True, fmt='.2f', square=True)\n", + " plt.title(\"Confusion matrix\")\n", + " plt.ylabel(\"True label\")\n", + " plt.xlabel(\"Predicted label\")\n", + "\n", + "confusion_matrix = model.confusion_matrix(test_data)\n", + "show_confusion_matrix(confusion_matrix.numpy(), test_data.index_to_label)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7gr1s7juBy7H" + }, + "source": [ + "## Teste o modelo (opcional)\n", + "\n", + "Você pode testar o modelo com uma amostra de áudio do dataset de teste apenas para ver os resultados.\n", + "\n", + "Primeiro, obtenha o modelo de serviço." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PmlmTl42Bq_u" + }, + "outputs": [ + + ], + "source": [ + "serving_model = model.create_serving_model()\n", + "\n", + "print(f'Model\\'s input shape and type: {serving_model.inputs}')\n", + "print(f'Model\\'s output shape and type: {serving_model.outputs}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eQsZFO2mrYhx" + }, + "source": [ + "Use o áudio aleatório que você carregou anteriormente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8dv5ViK0reXc" + }, + "outputs": [ + + ], + "source": [ + "# if you want to try another file just uncoment the line below\n", + "random_audio = get_random_audio_file()\n", + "show_bird_data(random_audio)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uixOfKSUj_9m" + }, + "source": [ + "O modelo criado tem uma janela de entrada fixa.\n", + "\n", + "Para um determinado arquivo de áudio, você precisará dividi-lo em janelas de dados do tamanho esperado. Talvez a última janela precise ser preenchida com zeros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YAvGKQL0lNty" + }, + "outputs": [ + + ], + "source": [ + "sample_rate, audio_data = wavfile.read(random_audio, 'rb')\n", + "\n", + "audio_data = np.array(audio_data) / tf.int16.max\n", + "input_size = serving_model.input_shape[1]\n", + "\n", + "splitted_audio_data = tf.signal.frame(audio_data, input_size, input_size, pad_end=True, pad_value=0)\n", + "\n", + "print(f'Test audio path: {random_audio}')\n", + "print(f'Original size of the audio data: {len(audio_data)}')\n", + "print(f'Number of windows for inference: {len(splitted_audio_data)}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PLxKd0eFkMcR" + }, + "source": [ + "Você fará um loop percorrendo todos os áudios divididos e aplicará o modelo em cada um deles.\n", + "\n", + "O modelo que você acabou de treinar tem duas saídas: a saída original do YAMNet e a que você treinou. Isso é importante, pois ambientes reais são mais complicados do que sons de pássaros. Você pode usar a saída do YAMNet para filtrar os áudios não relevantes. Por exemplo: para o dataset Birds, se o YAMNet não estiver classificando pássaros ou animais, isso pode mostrar que a saída do seu modelo pode ter uma classificação irrelevante.\n", + "\n", + "Veja abaixo as duas saídas para entender melhor a relação entre elas. A maioria dos erros que seu modelo comete são quando a previsão do YAMNet não estará relacionada à sua área (como pássaros)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4-8fJLrxGwYT" + }, + "outputs": [ + + ], + "source": [ + "print(random_audio)\n", + "\n", + "results = []\n", + "print('Result of the window ith: your model class -> score, (spec class -> score)')\n", + "for i, data in enumerate(splitted_audio_data):\n", + " yamnet_output, inference = serving_model(data)\n", + " results.append(inference[0].numpy())\n", + " result_index = tf.argmax(inference[0])\n", + " spec_result_index = tf.argmax(yamnet_output[0])\n", + " t = spec._yamnet_labels()[spec_result_index]\n", + " result_str = f'Result of the window {i}: ' \\\n", + " f'\\t{test_data.index_to_label[result_index]} -> {inference[0][result_index].numpy():.3f}, ' \\\n", + " f'\\t({spec._yamnet_labels()[spec_result_index]} -> {yamnet_output[0][spec_result_index]:.3f})'\n", + " print(result_str)\n", + "\n", + "\n", + "results_np = np.array(results)\n", + "mean_results = results_np.mean(axis=0)\n", + "result_index = mean_results.argmax()\n", + "print(f'Mean result: {test_data.index_to_label[result_index]} -> {mean_results[result_index]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yASrikBgZ9ZO" + }, + "source": [ + "## Exporte o modelo\n", + "\n", + "A última etapa é exportar o modelo que será usado em dispositivos embarcados ou no navegador.\n", + "\n", + "O método `export` exporta os dois formatos." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Xw_ehPxAdQlz" + }, + "outputs": [ + + ], + "source": [ + "models_path = './birds_models'\n", + "print(f'Exporing the TFLite model to {models_path}')\n", + "\n", + "model.export(models_path, tflite_filename='my_birds_model.tflite')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jjZRKmurA3y_" + }, + "source": [ + "Além disso, você pode exportar a versão SavedModel para uso em serviço ou em um ambiente Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "veBwppOsA-kn" + }, + "outputs": [ + + ], + "source": [ + "model.export(models_path, export_format=[mm.ExportFormat.SAVED_MODEL, mm.ExportFormat.LABEL])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5xr0idac6xfi" + }, + "source": [ + "## Próximos passos\n", + "\n", + "Você conseguiu.\n", + "\n", + "Agora, seu modelo pode ser implantado em dispositivos móveis usando a [API de tarefas AudioClassifier do TF Lite](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier).\n", + "\n", + "Além disso, você pode fazer o mesmo processo com seus próprios dados e classes diferentes. Confira a documentação do [Model Maker para classificação de áudio](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier).\n", + "\n", + "Para saber mais, confira os aplicativos completos de referência para [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/sound_classification/android/) e [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/sound_classification/ios)." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "audio_classification.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb new file mode 100644 index 0000000000..430e1b6355 --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb @@ -0,0 +1,969 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "h2q27gKz1H20" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "TUfAcER1oUS6" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gb7qyhNL1yWt" + }, + "source": [ + "# Classificação de imagem com o TensorFlow Lite Model Maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nDABAblytltI" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + " Ver modelo do TF Hub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "m86-Nh4pMHqY" + }, + "source": [ + "A [biblioteca TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) simplifica o processo de adaptar e converter um modelo de rede neural do TensorFlow para dados de entrada específicos ao implantar esse modelo em aplicativos de aprendizado de máquina em dispositivos.\n", + "\n", + "Este notebook apresenta um exemplo completo que utiliza a biblioteca Model Maker para ilustrar a adaptação e conversão de um modelo de classificação de imagens usado com frequência para classificar flores em um dispositivo móvel." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bcLF2PKkSbV3" + }, + "source": [ + "## Pré-requisitos\n", + "\n", + "Para executar este exemplo, primeiro precisamos instalar diversos pacotes exigidos, incluindo o pacote do Model Maker que está no [repositório](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker) do GitHub." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6cv3K3oaksJv" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install -q tflite-model-maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gx1HGRoFQ54j" + }, + "source": [ + "Importe os pacotes necessários." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XtxiUeZEiXpt" + }, + "outputs": [ + + ], + "source": [ + "import os\n", + "\n", + "import numpy as np\n", + "\n", + "import tensorflow as tf\n", + "assert tf.__version__.startswith('2')\n", + "\n", + "from tflite_model_maker import model_spec\n", + "from tflite_model_maker import image_classifier\n", + "from tflite_model_maker.config import ExportFormat\n", + "from tflite_model_maker.config import QuantizationConfig\n", + "from tflite_model_maker.image_classifier import DataLoader\n", + "\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KKRaYHABpob5" + }, + "source": [ + "## Exemplo completo simples" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SiZZ5DHXotaW" + }, + "source": [ + "### Obtenha o caminho dos dados\n", + "\n", + "Vamos obter alguns imagens para este exemplo completo simples. Algumas centenas de imagens são um bom ponto de partida para o Model Maker, enquanto mais dados poderão trazer uma exatidão maior." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "3jz5x0JoskPv" + }, + "outputs": [ + + ], + "source": [ + "image_path = tf.keras.utils.get_file(\n", + " 'flower_photos.tgz',\n", + " 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',\n", + " extract=True)\n", + "image_path = os.path.join(os.path.dirname(image_path), 'flower_photos')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a55MR6i6nuDm" + }, + "source": [ + "Você pode substituir `image_path` pelas duas pastas de imagens. Para carregar os dados no Colab, use o botão de upload disponível na barra lateral esquerda, conforme mostrado na imagem abaixo – o botão Upload está destacado com um retângulo vermelho. Tente carregar um arquivo ZIP e descompactá-lo. O caminho do arquivo raiz é o caminho atual.\n", + "\n", + "\"Upload" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NNRNv_mloS89" + }, + "source": [ + "Se você preferir não carregar suas imagens na nuvem, pode tentar executar a biblioteca localmente de acordo com este [guia](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker) no GitHub." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "w-VDriAdsowu" + }, + "source": [ + "### Execute o exemplo\n", + "\n", + "O exemplo tem apenas quatro linhas de código, conforme mostrado abaixo, em que cada uma representa uma etapa do processo geral.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6ahtcO86tZBL" + }, + "source": [ + "Etapa 1 – Carregue os dados específicos para um aplicativo de aprendizado de máquina em dispositivos. Divida-os em dados de treinamento e de teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lANoNS_gtdH1" + }, + "outputs": [ + + ], + "source": [ + "data = DataLoader.from_folder(image_path)\n", + "train_data, test_data = data.split(0.9)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y_9IWyIztuRF" + }, + "source": [ + "Etapa 2 – Personalize o modelo do TensorFlow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yRXMZbrwtyRD" + }, + "outputs": [ + + ], + "source": [ + "model = image_classifier.create(train_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oxU2fDr-t2Ya" + }, + "source": [ + "Etapa 3 – Avalie o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wQr02VxJt6Cs" + }, + "outputs": [ + + ], + "source": [ + "loss, accuracy = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eVZw9zU8t84y" + }, + "source": [ + "Etapa 4 – Exporte para um modelo do TensorFlow Lite.\n", + "\n", + "Aqui, exportamos para um modelo do TensorFlow Lite com [metadados](https://www.tensorflow.org/lite/models/convert/metadata), que fornecem um padrão para descrição de modelos. O arquivo de rótulos é incorporado aos metadados. Para a tarefa de classificação de imagens, a técnica padrão de quantização pós-treinamento é a quantização completa em inteiros.\n", + "\n", + "Você pode baixá-lo pela barra lateral esquerda da mesma forma que fez para carregar os dados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Zb-eIzfluCoa" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pyju1qc_v-wy" + }, + "source": [ + "Após essas quatro etapas simples, podemos usar o modelo do TensorFlow Lite em aplicativos em dispositivos, como no aplicativo de referência de [classificação de imagens](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "R1QG32ivs9lF" + }, + "source": [ + "## Processo detalhado\n", + "\n", + "No momento, temos suporte a diversos métodos, como EfficientNet-Lite*, MobileNetV2, ResNet50, como modelos pré-treinados para classificação de imagens, o que é muito flexível, pois é possível adicionar novos modelos pré-treinados a esta biblioteca com apenas algumas linhas de código.\n", + "\n", + "Veja abaixo as etapas mais detalhadas deste exemplo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ygEncJxtl-nQ" + }, + "source": [ + "### Etapa 1 – Carregue dados de entrada específicos em um aplicativo de aprendizado de máquina em dispositivos\n", + "\n", + "O dataset Flower contém 3.670 imagens de 5 classes. Baixe a versão do arquivo do dataset e descompacte-a via tar.\n", + "\n", + "O dataset tem a seguinte estrutura de diretórios:\n", + "\n", + "
\n",
+        "<b>flower_photos</b>\n",
+        "|__ <b>daisy</b>\n",
+        "    |______ 100080576_f52e8ee070_n.jpg\n",
+        "    |______ 14167534527_781ceb1b7a_n.jpg\n",
+        "    |______ ...\n",
+        "|__ <b>dandelion</b>\n",
+        "    |______ 10043234166_e6dd915111_n.jpg\n",
+        "    |______ 1426682852_e62169221f_m.jpg\n",
+        "    |______ ...\n",
+        "|__ <b>roses</b>\n",
+        "    |______ 102501987_3cdb8e5394_n.jpg\n",
+        "    |______ 14982802401_a3dfb22afb.jpg\n",
+        "    |______ ...\n",
+        "|__ <b>sunflowers</b>\n",
+        "    |______ 12471791574_bb1be83df4.jpg\n",
+        "    |______ 15122112402_cafa41934f.jpg\n",
+        "    |______ ...\n",
+        "|__ <b>tulips</b>\n",
+        "    |______ 13976522214_ccec508fe7.jpg\n",
+        "    |______ 14487943607_651e8062a1_m.jpg\n",
+        "    |______ ...\n",
+        "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7tOfUr2KlgpU" + }, + "outputs": [ + + ], + "source": [ + "image_path = tf.keras.utils.get_file(\n", + " 'flower_photos.tgz',\n", + " 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',\n", + " extract=True)\n", + "image_path = os.path.join(os.path.dirname(image_path), 'flower_photos')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E051HBUM5owi" + }, + "source": [ + "Use a classe `DataLoader` para carregar dados.\n", + "\n", + "O método `from_folder()` pode carregar dados a partir da pasta. Ele pressupõe que os dados de imagem da mesma classe estejam no mesmo subdiretório e que o nome da subpasta seja o nome da classe. No momento, há suporte a imagens em JPEG e em PNG." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "I_fOlZsklmlL" + }, + "outputs": [ + + ], + "source": [ + "data = DataLoader.from_folder(image_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "u501eT4koURB" + }, + "source": [ + "Divida o dataset em dados de treinamento (80%), de validação (10%, opcional) e de teste (10%)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cY4UU5SUobtJ" + }, + "outputs": [ + + ], + "source": [ + "train_data, rest_data = data.split(0.8)\n", + "validation_data, test_data = rest_data.split(0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Z9_MYPie3EMO" + }, + "source": [ + "Mostre 25 imagens de exemplo com seus respectivos rótulos." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ih4Wx44I482b" + }, + "outputs": [ + + ], + "source": [ + "plt.figure(figsize=(10,10))\n", + "for i, (image, label) in enumerate(data.gen_dataset().unbatch().take(25)):\n", + " plt.subplot(5,5,i+1)\n", + " plt.xticks([])\n", + " plt.yticks([])\n", + " plt.grid(False)\n", + " plt.imshow(image.numpy(), cmap=plt.cm.gray)\n", + " plt.xlabel(data.index_to_label[label.numpy()])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AWuoensX4vDA" + }, + "source": [ + "### Etapa 2 – Personalize o modelo do TensorFlow\n", + "\n", + "Crie um modelo de classificador de imagens personalizado com base nos dados carregados. O modelo padrão é EfficientNet-Lite0.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TvYSUuJY3QxR" + }, + "outputs": [ + + ], + "source": [ + "model = image_classifier.create(train_data, validation_data=validation_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JFOKWnH9x8_" + }, + "source": [ + "Confira a estrutura detalhada do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QNXAfjl192dC" + }, + "outputs": [ + + ], + "source": [ + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LP5FPk_tOxoZ" + }, + "source": [ + "### Etapa 3 – Avalie o modelo\n", + "\n", + "Avalie o resultado do modelo; obtenha a perda e a exatidão do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A8c2ZQ0J3Riy" + }, + "outputs": [ + + ], + "source": [ + "loss, accuracy = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6ZCrYOWoCt05" + }, + "source": [ + "Podemos plotar os resultados previstos em 100 imagens de teste. Os rótulos previstos com a cor vermelha são os resultados previstos incorretamente, enquanto os outros são os previstos corretamente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "n9O9Kx7nDQWD" + }, + "outputs": [ + + ], + "source": [ + "# A helper function that returns 'red'/'black' depending on if its two input\n", + "# parameter matches or not.\n", + "def get_label_color(val1, val2):\n", + " if val1 == val2:\n", + " return 'black'\n", + " else:\n", + " return 'red'\n", + "\n", + "# Then plot 100 test images and their predicted labels.\n", + "# If a prediction result is different from the label provided label in \"test\"\n", + "# dataset, we will highlight it in red color.\n", + "plt.figure(figsize=(20, 20))\n", + "predicts = model.predict_top_k(test_data)\n", + "for i, (image, label) in enumerate(test_data.gen_dataset().unbatch().take(100)):\n", + " ax = plt.subplot(10, 10, i+1)\n", + " plt.xticks([])\n", + " plt.yticks([])\n", + " plt.grid(False)\n", + " plt.imshow(image.numpy(), cmap=plt.cm.gray)\n", + "\n", + " predict_label = predicts[i][0][0]\n", + " color = get_label_color(predict_label,\n", + " test_data.index_to_label[label.numpy()])\n", + " ax.xaxis.label.set_color(color)\n", + " plt.xlabel('Predicted: %s' % predict_label)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "S3H0rkbLUZAG" + }, + "source": [ + "Se a exatidão não atender aos requisitos do aplicativo, consulte a seção [Uso avançado](#scrollTo=zNDBP2qA54aK) para ver alternativas, como alterar para um modelo maior, ajustar os parâmetros de retreinamento, etc." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aeHoGAceO2xV" + }, + "source": [ + "### Etapa 4 – Exporte para um modelo do TensorFlow Lite\n", + "\n", + "Converta o modelo treinado para o formato de modelos do TensorFlow Lite com [metadados](https://www.tensorflow.org/lite/models/convert/metadata) para poder usá-lo posteriormente em um aplicativo de aprendizado de máquina em dispositivos. O arquivo de rótulos e o arquivo de vocabulário são incorporados aos metadados. O nome de arquivo padrão do TF Lite é `model.tflite`.\n", + "\n", + "Em diversos aplicativos de aprendizado de máquina em dispositivos, o tamanho do modelo é um fator importante. Portanto, recomendamos aplicar quantização no modelo para deixá-lo menor e possivelmente mais rápido. Para a tarefa de classificação de imagens, a técnica padrão de quantização pós-treinamento é a quantização completa em inteiros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Im6wA9lK3TQB" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ROS2Ay2jMPCl" + }, + "source": [ + "Confira mais detalhes sobre como integrar o modelo do TensorFlow Lite aos aplicativos para dispositivos móveis nos [exemplos do guia](https://www.tensorflow.org/lite/examples/image_classification/overview) de classificação de imagens.\n", + "\n", + "Este modelo pode ser integrado a um aplicativo para Android ou iOS usando a [API ImageClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier) da [biblioteca Task do TensorFlow Lite](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "habFnvRxxQ4A" + }, + "source": [ + "Confira abaixo os formatos de exportação permitidos:\n", + "\n", + "- `ExportFormat.TFLITE`\n", + "- `ExportFormat.LABEL`\n", + "- `ExportFormat.SAVED_MODEL`\n", + "\n", + "Por padrão, só é exportado o modelo do TensorFlow Lite com metadados. Você também pode exportar diferentes arquivos seletivamente. Por exemplo: exporte somente o arquivo de rótulos da seguinte forma:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BvxWsOTmKG4P" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.', export_format=ExportFormat.LABEL)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-4jQaxyT5_KV" + }, + "source": [ + "E você pode avaliar o modelo do TF Lite com o método `evaluate_tflite`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "S1YoPX5wOK-u" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate_tflite('model.tflite', test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zNDBP2qA54aK" + }, + "source": [ + "## Uso avançado\n", + "\n", + "A função `create` é uma parte essencial dessa biblioteca e usa aprendizado por transferência com um modelo pré-treinado similar ao do [tutorial](https://www.tensorflow.org/tutorials/images/transfer_learning).\n", + "\n", + "A função `create` consiste nas seguintes etapas:\n", + "\n", + "1. Divide os dados em dados de treinamento, validação e teste de acordo com os parâmetros `validation_ratio` e `test_ratio`. O valor padrão de `validation_ratio` e `test_ratio` é `0.1` e `0.1`.\n", + "2. Baixa um [vetor de características de imagens](https://www.tensorflow.org/hub/common_signatures/images#image_feature_vector) como modelo base no TensorFlow Hub. O modelo pré-treinado padrão é EfficientNet-Lite0.\n", + "3. Adiciona um head de classificador com uma camada de dropout, com `dropout_rate` entre a camada do head e o modelo pré-treinado. O `dropout_rate` padrão é o valor `dropout_rate` padrão de [make_image_classifier_lib](https://github.com/tensorflow/hub/blob/master/tensorflow_hub/tools/make_image_classifier/make_image_classifier_lib.py#L55) do TensorFlow Hub.\n", + "4. Faz o pré-processamento dos dados de entrada não tratados. No momento, as etapas de pré-processamento incluem a normalização do valor de cada pixel da imagem para a escala da entrada do modelo e o redimensionamento para o tamanho da entrada do modelo. EfficientNet-Lite0 tem escala de entrada igual a `[0, 1]` e tamanho da imagem de entrada igual a `[224, 224, 3]`.\n", + "5. Alimenta o modelo do classificador com dados. Por padrão, os parâmetros de treinamento, como épocas de treinamento, tamanho do lote, taxa de aprendizado e momento, são os valores padrão de [make_image_classifier_lib](https://github.com/tensorflow/hub/blob/master/tensorflow_hub/tools/make_image_classifier/make_image_classifier_lib.py#L55) do TensorFlow Hub. Somente o head do classificador é treinado.\n", + "\n", + "Nesta seção, descreveremos diversos tópicos avançados, incluindo como alterar para um modelo de classificação de imagens diferente, como mudar os hiperparâmetros de treinamento, etc.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gc4Jk8TvBQfm" + }, + "source": [ + "## Personalize a quantização pós-treinamento em um modelo do TensorFlow Lite\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tD8BOYrHBiDt" + }, + "source": [ + "A [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization) é uma técnica de conversão que pode reduzir o tamanho do modelo e a latência de inferência, além de aumentar a velocidade de inferência da CPU e do acelerador de hardware com uma pequena redução da exatidão do modelo. A quantização é amplamente utilizada para otimizar o modelo.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iyIo0d5TCzE2" + }, + "source": [ + "A biblioteca Model Maker aplica uma técnica padrão de quantização pós-treinamento ao exportar o modelo. Se você quiser personalizar a quantização pós-treinamento, o Model Maker oferece suporte a diversas opções usando [QuantizationConfig](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/config/QuantizationConfig). Vejamos a quantização de float16 como exemplo. Primeiro, definimos a configuração de quantização." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "k8hL2mstCxQl" + }, + "outputs": [ + + ], + "source": [ + "config = QuantizationConfig.for_float16()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K1gzx_rmFMOA" + }, + "source": [ + "Em seguida, exportamos o modelo do TensorFlow Lite com essa configuração." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WTJzFQnJFMjr" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Safo0e40wKZW" + }, + "source": [ + "No Colab, você pode baixar o modelo com nome `model_fp16.tflite` pela barra lateral esquerda da mesma forma que fez para carregar dados anteriormente." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A4kiTJtZ_sDm" + }, + "source": [ + "## Altere o modelo\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "794vgj6ud7Ep" + }, + "source": [ + "### Altere para o modelo compatível com essa biblioteca.\n", + "\n", + "No momento, a biblioteca oferece suporte a modelos EfficientNet-Lite, MobileNetV2, ResNet50. [EfficientNet-Lite](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet/lite) é uma família de modelos de classificação de imagens que atingem uma exatidão excepcional e são adequadas para dispositivos Edge. O modelo padrão é EfficientNet-Lite0.\n", + "\n", + "Para mudar o modelo para MobileNetV2, basta definir o parâmetro `model_spec` como a especificação do modelo MobileNetV2 no método `create`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7JKsJ6-P6ae1" + }, + "outputs": [ + + ], + "source": [ + "model = image_classifier.create(train_data, model_spec=model_spec.get('mobilenet_v2'), validation_data=validation_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gm_B1Wv08AxR" + }, + "source": [ + "Avalie o modelo MobileNetV2 retreinado recentemente para ver a exatidão e a perda com os dados de teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lB2Go3HW8X7_" + }, + "outputs": [ + + ], + "source": [ + "loss, accuracy = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vAciGzVWtmWp" + }, + "source": [ + "### Altere para o modelo do TensorFlow Hub\n", + "\n", + "Além disso, também podemos alterar para outros modelos novos que recebem uma imagem como entrada e geram como saída um vetor de características no formato do TensorFlow Hub.\n", + "\n", + "Usando o modelo [Inception V3](https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1) como exemplo, podemos definir `inception_v3_spec`, que é um objeto de [image_classifier.ModelSpec](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/image_classifier/ModelSpec) e contém a especificação do modelo Inception V3.\n", + "\n", + "Precisamos especificar o nome `name` e a URL `uri` do modelo do TensorFlow Hub. O valor padrão de `input_image_shape` é `[224, 224]`. Precisamos alterá-lo para `[299, 299]` para o modelo Inception V3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xdiMF2WMfAR4" + }, + "outputs": [ + + ], + "source": [ + "inception_v3_spec = image_classifier.ModelSpec(\n", + " uri='https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1')\n", + "inception_v3_spec.input_image_shape = [299, 299]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "T_GGIoXZCs5F" + }, + "source": [ + "Em seguida, ao definir o parâmetro `model_spec` como `inception_v3_spec` no método `create`, podemos retreinar o modelo Inception V3.\n", + "\n", + "As etapas restantes são exatamente iguais, e poderemos ter um modelo InceptionV3 personalizado do TensorFlow Lite no final." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UhZ5IRKdeex3" + }, + "source": [ + "### Altere seu próprio modelo personalizado" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "svTjlZhrCrcV" + }, + "source": [ + "Se quisermos usar um modelo personalizado que não esteja no TensorFlow Hub, precisamos criar e exportar [ModelSpec](https://www.tensorflow.org/hub/api_docs/python/hub/ModuleSpec) no TensorFlow Hub.\n", + "\n", + "Começamos definindo o objeto `ModelSpec` conforme o processo acima." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4M9bn703AHt2" + }, + "source": [ + "## Altere os hiperparâmetros de treinamento\n", + "\n", + "Também podemos alterar os hiperparâmetros de treinamento, como `epochs`, `dropout_rate` e `batch_size`, o que pode afetar a exatidão do modelo. Veja quais parâmetros do modelo podem ser ajustados:\n", + "\n", + "- `epochs`: mais épocas podem alcançar uma exatidão melhor até a convergência, mas treinar com épocas demais pode causar overfitting.\n", + "- `dropout_rate`: taxa de dropout, evita overfitting. É igual a none (nenhuma) por padrão.\n", + "- `batch_size`: número de amostras a serem usadas em um passo de treinamento. É igual a none (nenhum) por padrão.\n", + "- `validation_data`: dados de validação. Se igual a none (nenhum), pula o processo de validação. É igual a none por padrão.\n", + "- `train_whole_model`: se verdadeiro, o módulo do Hub é treinado junto com a camada de classificação superior. Caso contrário, treina somente a camada de classificação superior. É igual a none (nenhum) por padrão.\n", + "- `learning_rate`: Taxa de aprendizado base. É igual a none (nenhuma) por padrão.\n", + "- `momentum`: float do Python encaminhado ao otimizador. É usado somente quando `use_hub_library` é true (verdadeiro). É igual a none (nenhum) por padrão.\n", + "- `shuffle`: booleano, indica se os dados devem ser misturados. É igual a false (falso) por padrão.\n", + "- `use_augmentation`: booleano, indica o uso de ampliação de dados no pré-processamento. É igual a false (falso) por padrão.\n", + "- `use_hub_library`: booleano, usa `make_image_classifier_lib` do TensorFlow Hub para retreinar o modelo. Este pipeline de treinamento pode alcançar um desempenho melhor para datasets complicados com muitas categorias. É igual a true (verdadeiro) por padrão.\n", + "- `warmup_steps`: número de etapas de preparação para o cronograma de preparação da taxa de aprendizado. Se igual a none (nenhum), o warmup_steps padrão é usado, que é o total de passos de treinamento em duas épocas. É usado somente quando `use_hub_library` é false (falso). É igual a none (nenhum) por padrão.\n", + "- `model_dir`: opcional, é o local dos arquivos de checkpoint do modelo. É usado somente quando `use_hub_library` é false (falso). É igual a none (nenhum) por padrão.\n", + "\n", + "Os parâmetros que são iguais a none (nenhum) por padrão, como `epochs`, obterão os parâmetros concretos padrão em [make_image_classifier_lib](https://github.com/tensorflow/hub/blob/02ab9b7d3455e99e97abecf43c5d598a5528e20c/tensorflow_hub/tools/make_image_classifier/make_image_classifier_lib.py#L54) da biblioteca do TensorFlow Hub ou em [train_image_classifier_lib](https://github.com/tensorflow/examples/blob/f0260433d133fd3cea4a920d1e53ecda07163aee/tensorflow_examples/lite/model_maker/core/task/train_image_classifier_lib.py#L61).\n", + "\n", + "Por exemplo: podemos treinar com mais épocas.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A3k7mhH54QcK" + }, + "outputs": [ + + ], + "source": [ + "model = image_classifier.create(train_data, validation_data=validation_data, epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VaYBQymQDsXU" + }, + "source": [ + "Avalie o modelo retreinado recentemente com 10 épocas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VafIYpKWD4Sw" + }, + "outputs": [ + + ], + "source": [ + "loss, accuracy = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dhBU5NCy5Ji2" + }, + "source": [ + "# Saiba mais\n", + "\n", + "Leia o exemplo de [classificação de imagens](https://www.tensorflow.org/lite/examples/image_classification/overview) para aprender os detalhes técnicos. Confira mais informações em:\n", + "\n", + "- [Guia](https://www.tensorflow.org/lite/models/modify/model_maker) e [referência da API](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker) do TensorFlow Lite Model Maker.\n", + "- Task Library: [ImageClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier) para implantação.\n", + "- Aplicativos de referência completos para [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/android), [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/ios) e [Raspberry PI](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/raspberry_pi).\n" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "image_classification.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb b/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb new file mode 100644 index 0000000000..6c250110a2 --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb @@ -0,0 +1,872 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "h2q27gKz1H20" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "TUfAcER1oUS6" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gb7qyhNL1yWt" + }, + "source": [ + "# Detecção de objetos com o TensorFlow Lite Model Maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Fw5Y7snSuG51" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sr3q-gvm3cI8" + }, + "source": [ + "Neste notebook do Colab, você verá como usar o [TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) para treinar um modelo personalizado de detecção de objetos para detectar saladas em imagens em um dispositivo móvel.\n", + "\n", + "A biblioteca Model Maker usa *aprendizado por transferência* para simplificar o processo de treinar um modelo do TensorFlow Lite usando um dataset personalizado. Retreinar um modelo do TensorFlow Lite com seu próprio dataset personalizado reduz a quantidade necessária de dados de treinamento e diminui o tempo de treinamento.\n", + "\n", + "Você usará o dataset *Salads*, disponível publicamente, que foi criado usando o [Dataset Open Images V4](https://storage.googleapis.com/openimages/web/index.html).\n", + "\n", + "Cada imagem do dataset contém objetos rotulados como uma das seguintes classes:\n", + "\n", + "- Baked Good (Assado)\n", + "- Cheese (Queijo)\n", + "- Salad (Salada)\n", + "- Seafood (Fruto do mar)\n", + "- Tomato (Tomate)\n", + "\n", + "O dataset contém os retângulos limítrofes que especificam onde cada objeto está localizado, juntamente com o rótulo do objeto.\n", + "\n", + "Veja abaixo uma imagem de exemplo do dataset:\n", + "\n", + "
\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bcLF2PKkSbV3" + }, + "source": [ + "## Pré-requisitos\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2vvAObmTqglq" + }, + "source": [ + "### Instale os pacotes obrigatórios\n", + "\n", + "Comece instalando os pacotes obrigatórios, incluindo o pacote do Model Maker disponível no [repositório do GitHub](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker) e a biblioteca pycocotools, que será usada para avaliação." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qhl8lqVamEty" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install -q --use-deprecated=legacy-resolver tflite-model-maker\n", + "!pip install -q pycocotools\n", + "!pip install -q opencv-python-headless==4.1.2.30\n", + "!pip uninstall -y tensorflow && pip install -q tensorflow==2.8.0" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l6lRhVK9Q_0U" + }, + "source": [ + "Importe os pacotes necessários." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XtxiUeZEiXpt" + }, + "outputs": [ + + ], + "source": [ + "import numpy as np\n", + "import os\n", + "\n", + "from tflite_model_maker.config import QuantizationConfig\n", + "from tflite_model_maker.config import ExportFormat\n", + "from tflite_model_maker import model_spec\n", + "from tflite_model_maker import object_detector\n", + "\n", + "import tensorflow as tf\n", + "assert tf.__version__.startswith('2')\n", + "\n", + "tf.get_logger().setLevel('ERROR')\n", + "from absl import logging\n", + "logging.set_verbosity(logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BRd13bfetO7B" + }, + "source": [ + "### Prepare o dataset\n", + "\n", + "Você usará o mesmo dataset que o usado no [Guia de início rápido](https://cloud.google.com/vision/automl/object-detection/docs/edge-quickstart#preparing_a_dataset) do AutoML.\n", + "\n", + "O dataset *Salads* está disponível em: `gs://cloud-ml-data/img/openimage/csv/salads_ml_use.csv`.\n", + "\n", + "Ele contém 175 imagens para treinamento, 25 para validação e 25 para teste. O dataset tem cinco classes: `Salad` (Salada), `Seafood` (Fruto do mar), `Tomato` (Tomate), `Baked goods` (Assado), `Cheese` (Queijo).\n", + "\n", + "
\n", + "\n", + "O dataset é fornecido no formato CSV:\n", + "\n", + "```\n", + "TRAINING,gs://cloud-ml-data/img/openimage/3/2520/3916261642_0a504acd60_o.jpg,Salad,0.0,0.0954,,,0.977,0.957,,\n", + "VALIDATION,gs://cloud-ml-data/img/openimage/3/2520/3916261642_0a504acd60_o.jpg,Seafood,0.0154,0.1538,,,1.0,0.802,,\n", + "TEST,gs://cloud-ml-data/img/openimage/3/2520/3916261642_0a504acd60_o.jpg,Tomato,0.0,0.655,,,0.231,0.839,,\n", + "```\n", + "\n", + "- Cada linha corresponde a um objeto localizado dentro de uma imagem maior, em que cada objeto é designado especificamente como dados de teste, treinamento ou validação. Você entenderá melhor o que isso significa posteriormente neste notebook.\n", + "- As três linhas incluídas aqui indicam **três objetos distintos localizados dentro da mesma imagem** disponível em `gs://cloud-ml-data/img/openimage/3/2520/3916261642_0a504acd60_o.jpg`.\n", + "- Cada linha tem um rótulo diferente: `Salad`, `Seafood`, `Tomato`, etc.\n", + "- Os retângulos limítrofes são especificados para cada imagem usando os vértices superior esquerdo e inferior direito.\n", + "\n", + "Veja abaixo essas três linhas:\n", + "\n", + "
\n", + "\n", + "\n", + "\n", + "Se você quiser saber mais sobre como preparar seu próprio arquivo CSV e quais são os requisitos mínimos para criar um dataset válido, confira mais detalhes no guia [Como preparar seus dados de treinamento](https://cloud.google.com/vision/automl/object-detection/docs/prepare).\n", + "\n", + "Se você for iniciante no Google Cloud, talvez se pergunte o que a URL `gs://` significa. É uma URL de arquivos armazenados no [Google Cloud Storage](https://cloud.google.com/storage) (GCS). Se você tornar públicos seus arquivos do GCS ou se [autenticar seu cliente](https://cloud.google.com/storage/docs/authentication#libauth), o Model Maker poderá ler esses arquivos de maneira similar a arquivos locais.\n", + "\n", + "Mas você não precisa manter as imagens no Google Cloud para usar o Model Maker. É possível usar um caminho local no arquivo CSV, e o Model Maker funcionará normalmente." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xushUyZXqP59" + }, + "source": [ + "## Início rápido" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vn61LJ9QbOPi" + }, + "source": [ + "Há seis etapas para treinar um modelo de detecção de objetos:\n", + "\n", + "**Etapa 1 – Escolha uma arquitetura de modelo de detecção de objetos**\n", + "\n", + "O modelo usado neste tutorial é EfficientDet-Lite0. EfficientDet-Lite[0-4] é uma família de modelos de detecção de objetos para dispositivos móveis/otimizados para IoT, derivados da arquitetura [EfficientDet](https://arxiv.org/abs/1911.09070).\n", + "\n", + "Veja abaixo a comparação do desempenho entre os modelos de EfficientDet-Lite.\n", + "\n", + "Arquitetura do modelo | Tamanho (em MB)* | Latência (em ms)** | Precisão média***\n", + "--- | --- | --- | ---\n", + "EfficientDet-Lite0 | 4,4 | 37 | 25,69%\n", + "EfficientDet-Lite1 | 5,8 | 49 | 30,55%\n", + "EfficientDet-Lite2 | 7,2 | 69 | 33,97%\n", + "EfficientDet-Lite3 | 11,4 | 116 | 37,70%\n", + "EfficientDet-Lite4 | 19,9 | 260 | 41,96%\n", + "\n", + " *Tamanho dos modelos quantizados em inteiros.
**Latência medida no Pixel 4 usando 4 threads da CPU.
***A precisão média é a mAP no dataset de validação COCO 2017.
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CtdZ-JDwMimd" + }, + "outputs": [ + + ], + "source": [ + "spec = model_spec.get('efficientdet_lite0')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s5U-A3tw6Y27" + }, + "source": [ + "**Etapa 2 – Carregue o dataset**\n", + "\n", + "O Model Maker recebe os dados de entrada no formato CSV. Use o método `object_detector.DataLoader.from_csv` para carregar o dataset e dividi-lo em imagens de treinamento, validação e teste.\n", + "\n", + "- Imagens de treinamento: são usadas para treinar o modelo de detecção de objetos para reconhecer ingredientes de saladas.\n", + "- Imagens de validação: são as imagens que o modelo não viu durante o processo de treinamento. Elas serão usadas para decidir quando interromper o treinamento para evitar o [overfitting](https://en.wikipedia.org/wiki/Overfitting).\n", + "- Imagens de teste: são usadas para avaliar o desempenho do modelo final.\n", + "\n", + "Você pode carregar o arquivo CSV diretamente do Google Cloud Storage, mas não precisa manter as imagens no Google Cloud para usar o Model Maker. É possível especificar um arquivo CSV local em seu computador, e o Model Maker funcionará normalmente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HD5BvzWe6YKa" + }, + "outputs": [ + + ], + "source": [ + "train_data, validation_data, test_data = object_detector.DataLoader.from_csv('gs://cloud-ml-data/img/openimage/csv/salads_ml_use.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2uZkLR6N6gDR" + }, + "source": [ + "**Etapa 3 – Treine o modelo do TensorFlow com os dados de treinamento**\n", + "\n", + "- O modelo EfficientDet-Lite0 usa `epochs = 50` por padrão, ou seja, ele percorre o dataset de treinamento 50 vezes. Você pode avaliar a exatidão de validação durante o treinamento e interromper antecipadamente para evitar o overfitting.\n", + "- Defina `batch_size = 8` aqui para ver que demora 21 passos para percorrer as 175 imagens no dataset de treinamento.\n", + "- Defina `train_whole_model=True` para fazer os ajustes finos do modelo inteiro em vez de apenas treinar a camada head para aumentar a exatidão. A contrapartida é que pode demorar mais tempo para treinar o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kwlYdTcg63xy" + }, + "outputs": [ + + ], + "source": [ + "model = object_detector.create(train_data, model_spec=spec, batch_size=8, train_whole_model=True, validation_data=validation_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-BzCHLWJ6h7q" + }, + "source": [ + "**Etapa 4 – Avalie o modelo com os dados de teste**\n", + "\n", + "Após treinar o modelo de detecção de objetos usando as imagens do dataset de treinamento, use as 25 imagens restantes no dataset de teste para avaliar o desempenho do modelo com os novos dados que ele nunca viu.\n", + "\n", + "Como o tamanho padrão do lote é 64, vai demorar 1 passo para percorrer as 25 imagens do dataset de teste.\n", + "\n", + "As métricas de avaliação são as mesmas que as de [COCO](https://cocodataset.org/#detection-eval)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8xmnl6Yy7ARn" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CgCDMe0e6jlT" + }, + "source": [ + "**Etapa 5 – Exporte para um modelo do TensorFlow Lite**\n", + "\n", + "Para exportar o modelo treinado de detecção de objetos para o formato do TensorFlow Lite, basta especificar para qual pasta você deseja exportar o modelo quantizado. A técnica padrão de quantização pós-treinamento é a quantização completa em inteiros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hm_UULdW7A9T" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZQpahAIBqBPp" + }, + "source": [ + "**Etapa 6 – Avalie o modelo do TensorFlow Lite**\n", + "\n", + "Diversos fatores podem afetar a exatidão do modelo ao exportar para o TF Lite:\n", + "\n", + "- A [quantização](https://www.tensorflow.org/lite/performance/model_optimization) ajuda a reduzir o tamanho do modelo em até quatro vezes, e o custo é uma pequena redução da exatidão.\n", + "- O modelo original do TensorFlow usa [supressão não máxima (NMS, na sigla em inglês)](https://www.coursera.org/lecture/convolutional-neural-networks/non-max-suppression-dvrjH) por classe para pós-processamento, enquanto o modelo do TF Lite usa NMS global, que é muito mais rápido, mas menos exato. O Keras gera no máximo 100 detecções, enquanto o tflite gera no máximo 25 detecções.\n", + "\n", + "Portanto, você precisará avaliar o modelo do TF Lite exportado e comparar a exatidão com o modelo original do TensorFlow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RS3Ell_lqH4e" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate_tflite('model.tflite', test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rVxaf3x_7OfB" + }, + "source": [ + "Você pode baixar o arquivo do modelo do TensorFlow Lite pela barra lateral esquerda do Colab. Clique com o botão direito no arquivo `model.tflite` e selecione `Download` (Baixar) para baixá-lo para seu computador local.\n", + "\n", + "Este modelo pode ser integrado a um aplicativo para Android ou iOS usando a [API ObjectDetector](https://www.tensorflow.org/lite/inference_with_metadata/task_library/object_detector) da [biblioteca Task TensorFlow Lite](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview).\n", + "\n", + "Confira mais detalhes de como o modelo é usado em um aplicativo funcional no [exemplo de aplicativo para detecção de objetos do TF Lite](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android).\n", + "\n", + "*Observação: o Android Studio Model Binding ainda não oferece suporte à detecção de objetos, então use a TensorFlow Lite Task Library.*" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "me6_RwPZqNhX" + }, + "source": [ + "## Teste o modelo do TF Lite com suas imagens (opcional)\n", + "\n", + "Você pode testar o modelo do TF Lite treinado usando imagens da Internet.\n", + "\n", + "- Substitua `INPUT_IMAGE_URL` abaixo pela imagem de entrada desejada.\n", + "- Ajuste `DETECTION_THRESHOLD` para alterar a sensibilidade do modelo. Com um limiar mais baixo, o modelo identificará mais objetos, mas também haverá mais falsos positivos. Já com um limiar mais alto, o modelo só identificará objetos que detectou com alta confiança.\n", + "\n", + "Embora seja necessário código boilerplate para executar o modelo no Python atualmente, só são necessárias algumas linhas de código para integrar o modelo a um aplicativo para dispositivos móveis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "XqS0rFCrqM1o" + }, + "outputs": [ + + ], + "source": [ + "#@title Load the trained TFLite model and define some visualization functions\n", + "\n", + "import cv2\n", + "\n", + "from PIL import Image\n", + "\n", + "model_path = 'model.tflite'\n", + "\n", + "# Load the labels into a list\n", + "classes = ['???'] * model.model_spec.config.num_classes\n", + "label_map = model.model_spec.config.label_map\n", + "for label_id, label_name in label_map.as_dict().items():\n", + " classes[label_id-1] = label_name\n", + "\n", + "# Define a list of colors for visualization\n", + "COLORS = np.random.randint(0, 255, size=(len(classes), 3), dtype=np.uint8)\n", + "\n", + "def preprocess_image(image_path, input_size):\n", + " \"\"\"Preprocess the input image to feed to the TFLite model\"\"\"\n", + " img = tf.io.read_file(image_path)\n", + " img = tf.io.decode_image(img, channels=3)\n", + " img = tf.image.convert_image_dtype(img, tf.uint8)\n", + " original_image = img\n", + " resized_img = tf.image.resize(img, input_size)\n", + " resized_img = resized_img[tf.newaxis, :]\n", + " resized_img = tf.cast(resized_img, dtype=tf.uint8)\n", + " return resized_img, original_image\n", + "\n", + "\n", + "def detect_objects(interpreter, image, threshold):\n", + " \"\"\"Returns a list of detection results, each a dictionary of object info.\"\"\"\n", + "\n", + " signature_fn = interpreter.get_signature_runner()\n", + "\n", + " # Feed the input image to the model\n", + " output = signature_fn(images=image)\n", + "\n", + " # Get all outputs from the model\n", + " count = int(np.squeeze(output['output_0']))\n", + " scores = np.squeeze(output['output_1'])\n", + " classes = np.squeeze(output['output_2'])\n", + " boxes = np.squeeze(output['output_3'])\n", + "\n", + " results = []\n", + " for i in range(count):\n", + " if scores[i] >= threshold:\n", + " result = {\n", + " 'bounding_box': boxes[i],\n", + " 'class_id': classes[i],\n", + " 'score': scores[i]\n", + " }\n", + " results.append(result)\n", + " return results\n", + "\n", + "\n", + "def run_odt_and_draw_results(image_path, interpreter, threshold=0.5):\n", + " \"\"\"Run object detection on the input image and draw the detection results\"\"\"\n", + " # Load the input shape required by the model\n", + " _, input_height, input_width, _ = interpreter.get_input_details()[0]['shape']\n", + "\n", + " # Load the input image and preprocess it\n", + " preprocessed_image, original_image = preprocess_image(\n", + " image_path,\n", + " (input_height, input_width)\n", + " )\n", + "\n", + " # Run object detection on the input image\n", + " results = detect_objects(interpreter, preprocessed_image, threshold=threshold)\n", + "\n", + " # Plot the detection results on the input image\n", + " original_image_np = original_image.numpy().astype(np.uint8)\n", + " for obj in results:\n", + " # Convert the object bounding box from relative coordinates to absolute\n", + " # coordinates based on the original image resolution\n", + " ymin, xmin, ymax, xmax = obj['bounding_box']\n", + " xmin = int(xmin * original_image_np.shape[1])\n", + " xmax = int(xmax * original_image_np.shape[1])\n", + " ymin = int(ymin * original_image_np.shape[0])\n", + " ymax = int(ymax * original_image_np.shape[0])\n", + "\n", + " # Find the class index of the current object\n", + " class_id = int(obj['class_id'])\n", + "\n", + " # Draw the bounding box and label on the image\n", + " color = [int(c) for c in COLORS[class_id]]\n", + " cv2.rectangle(original_image_np, (xmin, ymin), (xmax, ymax), color, 2)\n", + " # Make adjustments to make the label visible for all objects\n", + " y = ymin - 15 if ymin - 15 > 15 else ymin + 15\n", + " label = \"{}: {:.0f}%\".format(classes[class_id], obj['score'] * 100)\n", + " cv2.putText(original_image_np, label, (xmin, y),\n", + " cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)\n", + "\n", + " # Return the final image\n", + " original_uint8 = original_image_np.astype(np.uint8)\n", + " return original_uint8" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "GkXtipXKqXp4" + }, + "outputs": [ + + ], + "source": [ + "#@title Run object detection and show the detection results\n", + "\n", + "INPUT_IMAGE_URL = \"https://storage.googleapis.com/cloud-ml-data/img/openimage/3/2520/3916261642_0a504acd60_o.jpg\" #@param {type:\"string\"}\n", + "DETECTION_THRESHOLD = 0.3 #@param {type:\"number\"}\n", + "\n", + "TEMP_FILE = '/tmp/image.png'\n", + "\n", + "!wget -q -O $TEMP_FILE $INPUT_IMAGE_URL\n", + "im = Image.open(TEMP_FILE)\n", + "im.thumbnail((512, 512), Image.ANTIALIAS)\n", + "im.save(TEMP_FILE, 'PNG')\n", + "\n", + "# Load the TFLite model\n", + "interpreter = tf.lite.Interpreter(model_path=model_path)\n", + "interpreter.allocate_tensors()\n", + "\n", + "# Run inference and draw detection result on the local copy of the original file\n", + "detection_result_image = run_odt_and_draw_results(\n", + " TEMP_FILE,\n", + " interpreter,\n", + " threshold=DETECTION_THRESHOLD\n", + ")\n", + "\n", + "# Show the detection result\n", + "Image.fromarray(detection_result_image)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oxgWQyYOqZha" + }, + "source": [ + "## Compile para o Edge TPU (opcional)\n", + "\n", + "Agora que você tem um modelo de EfficientDet-Lite quantizado, é possível compilar e implantar em um [Coral EdgeTPU](https://coral.ai/).\n", + "\n", + "**Etapa 1 – Instale o EdgeTPU Compiler**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Oy3QIn_YqaRP" + }, + "outputs": [ + + ], + "source": [ + "! curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -\n", + "\n", + "! echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list\n", + "\n", + "! sudo apt-get update\n", + "\n", + "! sudo apt-get install edgetpu-compiler" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qRWewhqFqeL_" + }, + "source": [ + "**Etapa 2 – Selecione o número de Edge TPUs e compile**\n", + "\n", + "O EdgeTPU tem 8 MB de SRAM para fazer cache dos parâmetros do modelo ([confira mais informações](https://coral.ai/docs/edgetpu/compiler/#parameter-data-caching)). Portanto, para modelos maiores do que 8 MB, o tempo de inferência aumentará para que os parâmetros do modelo sejam transferidos. Uma forma de evitar isso é criar [pipelines do modelo](https://coral.ai/docs/edgetpu/pipeline/), ou seja, dividir o modelo em segmentos que podem ter um Edge TPU dedicado, o que pode melhorar a latência consideravelmente.\n", + "\n", + "A tabela abaixo pode ser usada como referência para o número de Edge TPUs a serem usadas. Modelos maiores não serão compilados para uma única TPU, pois os tensores intermediários não cabem na memória do chip.\n", + "\n", + "Arquitetura do modelo | Nº mínimo de TPUs | Nº recomendado de TPUs\n", + "--- | --- | ---\n", + "EfficientDet-Lite0 | 1 | 1\n", + "EfficientDet-Lite1 | 1 | 1\n", + "EfficientDet-Lite2 | 1 | 2\n", + "EfficientDet-Lite3 | 2 | 2\n", + "EfficientDet-Lite4 | 2 | 3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "LZdonJGCqieU" + }, + "outputs": [ + + ], + "source": [ + "NUMBER_OF_TPUS = 1#@param {type:\"number\"}\n", + "\n", + "!edgetpu_compiler model.tflite --num_segments=$NUMBER_OF_TPUS" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-g6_KQXnqlTC" + }, + "source": [ + "**Etapa 3 – Baixe e execute o modelo**\n", + "\n", + "Com os modelos compilados, agora eles podem ser executados em Edge TPUs para detecção de objetos. Primeiro, baixe o arquivo do modelo do TensorFlow Lite compilado pela barra lateral esquerda do Colab. Clique com o botão direito no arquivo `model_edgetpu.tflite` e selecione `Download` (Baixar) para baixá-lo para seu computador local." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VkQFz_qzqrrA" + }, + "source": [ + "Agora você pode executar o modelo da maneira que desejar. Veja alguns exemplos de detecção:\n", + "\n", + "- [Detecção com Pycoral](https://github.com/google-coral/pycoral/blob/master/examples/detect_image.py)\n", + "- [Detecção básica com o TF Lite](https://github.com/google-coral/tflite/tree/master/python/examples/detection)\n", + "- [Exemplo de detecção de vídeo](https://github.com/google-coral/examples-camera)\n", + "- [API libcoral do C++](https://github.com/google-coral/libcoral)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EoWiA_zX8rxE" + }, + "source": [ + "## Uso avançado\n", + "\n", + "Esta seção abrange tópicos de uso avançado, como ajustar o modelo e os hiperparâmetros de treinamento." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p79NHCx0xFqb" + }, + "source": [ + "### Carregue o dataset\n", + "\n", + "#### Carregue seus próprios dados\n", + "\n", + "Você pode carregar seu próprio dataset neste tutorial. Para carregá-lo, use a barra lateral esquerda no Colab.\n", + "\n", + "\"Upload\n", + "\n", + "Se você preferir não carregar o dataset na nuvem, pode executar a biblioteca localmente de acordo com este [guia](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker).\n", + "\n", + "#### Carregue seus dados com um formato de dados diferente\n", + "\n", + "A biblioteca do Model Maker também oferece suporte ao método `object_detector.DataLoader.from_pascal_voc` para carregar dados com o formato [PASCAL VOC](https://towardsdatascience.com/coco-data-format-for-object-detection-a4c5eaf518c5#:~:text=Pascal%20VOC%20is%20an%20XML,for%20training%2C%20testing%20and%20validation). [makesense.ai](https://www.makesense.ai/) e [LabelImg](https://github.com/tzutalin/labelImg) são as ferramentas que podem fazer anotações na imagem e salvá-las como arquivos XML no formato de dados PASCAL VOC:\n", + "\n", + "```python\n", + "object_detector.DataLoader.from_pascal_voc(image_dir, annotations_dir, label_map={1: \"person\", 2: \"notperson\"})\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E8VxPiOLy4Gv" + }, + "source": [ + "### Personalize os hiperparâmetros do modelo EfficientDet\n", + "\n", + "Os parâmetros do modelo e do pipeline de treinamento que podem ser ajustados são:\n", + "\n", + "- `model_dir`: local onde salvar os arquivos de checkpoint do modelo. Caso não seja definido, será usado um diretório temporário.\n", + "- `steps_per_execution`: número de passos por execução de treinamento.\n", + "- `moving_average_decay`: Float. Decaimento a ser usado para manter as médias móveis dos parâmetros treinados.\n", + "- `var_freeze_expr`: expressão regular para mapear o nome prefixo das variáveis a serem congeladas, ou seja, que não mudam durante o treinamento. Mais especificamente, use `re.match(var_freeze_expr, variable_name)` no codebase para mapear as variáveis a serem congeladas.\n", + "- `tflite_max_detections`: inteiro, 25 por padrão. Número máximo de detecções de saída no modelo do TF Lite.\n", + "- `strategy`: string que especifica qual estratégia de distribuição será usada. Aceita valores como 'tpu', 'gpus', None (nenhuma). tpu' significa que será usada TPUStrategy. 'gpus' significa que será usada MirroredStrategy para várias GPUs. Em caso de None, será usado o padrão do TF com OneDeviceStrategy.\n", + "- `tpu`: Cloud TPU a ser usada para treinamento. Deve ser o nome usado ao criar a Cloud TPU ou uma URL grpc://ip.address.of.tpu:8470.\n", + "- `use_xla`: usa XLA mesmo se a estratégia não for TPU. Se a estratégia for TPU, sempre usa XLA, e este sinalizador não tem efeito nenhum.\n", + "- `profile`: ativa o modo de profiling.\n", + "- `debug`: ativa o modo de depuração.\n", + "\n", + "Outros parâmetros que podem ser ajustados são exibidos em [hparams_config.py](https://github.com/google/automl/blob/df451765d467c5ed78bbdfd632810bc1014b123e/efficientdet/hparams_config.py#L170).\n", + "\n", + "Por exemplo: você pode definir `var_freeze_expr='efficientnet'`, que congela as variáveis com o prefixo de nome `efficientnet` (o padrão é `'(efficientnet|fpn_cells|resample_p6)')`. Isso permite que o modelo congele variáveis não treináveis e mantenha seus valores inalterados durante o treinamento.\n", + "\n", + "```python\n", + "spec = model_spec.get('efficientdet_lite0')\n", + "spec.config.var_freeze_expr = 'efficientnet'\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4J2qre1fwXsi" + }, + "source": [ + "### Altere a arquitetura do modelo\n", + "\n", + "Para alterar a arquitetura do modelo, basta mudar `model_spec`. Por exemplo: altere `model_spec` para o modelo EfficientDet-Lite4.\n", + "\n", + "```python\n", + "spec = model_spec.get('efficientdet_lite4')\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LvQuy7RSDir3" + }, + "source": [ + "### Ajuste os hiperparâmetros de treinamento\n", + "\n", + "A função `create` é a função que a biblioteca Model Maker usa para criar modelos. O parâmetro `model_spec` define a especificação do modelo. No momento, há suporte à classe `object_detector.EfficientDetSpec`. A função `create` consiste nas seguintes etapas:\n", + "\n", + "1. Cria o modelo para detecção de objetos de acordo com `model_spec`.\n", + "2. Treina o modelo. O número padrão de épocas e do tamanho do lote é definido pelas variáveis `epochs` e `batch_size` no objeto `model_spec`. Além disso, você pode ajustar os hiperparâmetros de treinamento, como `epochs` e `batch_size`, que afetam a exatidão do modelo. Por exemplo:\n", + "\n", + "- `epochs`: inteiro, 50 por padrão. Mais épocas podem levar a uma exatidão melhor, mas podem causar overfitting.\n", + "- `batch_size`: inteiro, 64 por padrão. Número de amostras a serem usadas em um passo de treinamento.\n", + "- `train_whole_model`: booleano, false (falso) por padrão. Se for igual a true (verdadeiro), treina o modelo inteiro. Caso contrário, treina somente as camadas que não coincidem com `var_freeze_expr`.\n", + "\n", + "Por exemplo: você pode treinar com menos épocas e apenas a camada head. É possível aumentar o número de épocas para obter resultados melhores.\n", + "\n", + "```python\n", + "model = object_detector.create(train_data, model_spec=spec, epochs=10, validation_data=validation_data)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3vPyZInPxJBT" + }, + "source": [ + "### Exporte para diferentes formatos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0xqNIcBM-4YR" + }, + "source": [ + "Confira abaixo os formatos de exportação permitidos:\n", + "\n", + "- `ExportFormat.TFLITE`\n", + "- `ExportFormat.LABEL`\n", + "- `ExportFormat.SAVED_MODEL`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "enhsZhW3ApcX" + }, + "source": [ + "Por padrão, é exportado somente o arquivo de modelo do TensorFlow Lite que contém [metadados](https://www.tensorflow.org/lite/models/convert/metadata) para que você possa usá-lo posteriormente em um aplicativo de aprendizado de máquina em dispositivos. O arquivo de rótulos é incorporado aos metadados.\n", + "\n", + "Em diversos aplicativos de aprendizado de máquina em dispositivos, o tamanho do modelo é um fator importante. Portanto, recomendamos aplicar quantização no modelo para deixá-lo menor e possivelmente mais rápido. Quanto aos modelos EfficientDet-Lite, a quantização completa em inteiros é usada para quantizar o modelo por padrão. Confira mais detalhes em [Quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization).\n", + "\n", + "```python\n", + "model.export(export_dir='.')\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RLGZs6InAnP5" + }, + "source": [ + "Você também pode optar por exportar outros arquivos relacionados ao modelo para avaliá-los melhor. Por exemplo: você pode exportar tanto o SavedModel quanto o arquivo de rótulos da seguinte forma:\n", + "\n", + "```python\n", + "model.export(export_dir='.', export_format=[ExportFormat.SAVED_MODEL, ExportFormat.LABEL])\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W5q_McchQ2C4" + }, + "source": [ + "### Personalize a quantização pós-treinamento em um modelo do TensorFlow Lite\n", + "\n", + "A [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization) é uma técnica de conversão que pode reduzir o tamanho do modelo e a latência de inferência, além de aumentar a velocidade de inferência da CPU e do acelerador de hardware com uma pequena redução da exatidão do modelo. A quantização é amplamente utilizada para otimizar o modelo.\n", + "\n", + "A biblioteca Model Maker aplica uma técnica padrão de quantização pós-treinamento ao exportar o modelo. Se você quiser personalizar a quantização pós-treinamento, o Model Maker oferece suporte a diversas opções usando [QuantizationConfig](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/config/QuantizationConfig). Vejamos a quantização de float 16 como exemplo. Primeiro, definimos a configuração de quantização.\n", + "\n", + "```python\n", + "config = QuantizationConfig.for_float16()\n", + "```\n", + "\n", + "Em seguida, exportamos o modelo do TensorFlow Lite com essa configuração.\n", + "\n", + "```python\n", + "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HS4u77W5gnzQ" + }, + "source": [ + "# Saiba mais\n", + "\n", + "Leia o exemplo de [detecção de objetos](https://www.tensorflow.org/lite/examples/object_detection/overview) para aprender os detalhes técnicos. Confira mais informações em:\n", + "\n", + "- [Guia](https://www.tensorflow.org/lite/models/modify/model_maker) e [referência da API](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker) do TensorFlow Lite Model Maker.\n", + "- Task Library: [ObjectDetector](https://www.tensorflow.org/lite/inference_with_metadata/task_library/object_detector) para implantação.\n", + "- Aplicativos de referência completos para [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android), [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/ios) e [Raspberry PI](https://github.com/tensorflow/examples/tree/master/lite/examples/object_detection/raspberry_pi).\n" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "object_detection.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb b/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb new file mode 100644 index 0000000000..bf5dbf2aaa --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb @@ -0,0 +1,653 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "h2q27gKz1H20" + }, + "source": [ + "##### Copyright 2020 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "TUfAcER1oUS6" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gb7qyhNL1yWt" + }, + "source": [ + "# Resposta a perguntas BERT com o TensorFlow Lite Model Maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Fw5Y7snSuG51" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sr3q-gvm3cI8" + }, + "source": [ + "A [biblioteca TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) simplifica o processo de adaptar e converter um modelo do TensorFlow para dados de entrada específicos ao implantar esse modelo em aplicativos de aprendizado de máquina em dispositivos.\n", + "\n", + "Este notebook apresenta um exemplo completo que utiliza a biblioteca Model Maker para ilustrar a adaptação e conversão de um modelo de resposta a perguntas usado com frequência para tarefas de resposta a perguntas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UxEHFTk755qw" + }, + "source": [ + "# Introdução à tarefa de resposta a perguntas BERT" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cFbKTCF25-SG" + }, + "source": [ + "A tarefa com suporte nesta biblioteca é uma tarefa de extrair a resposta a uma pergunta: dado um trecho e uma pergunta, a resposta está presente no trecho. A imagem abaixo mostra um exemplo de resposta a uma pergunta.\n", + "\n", + "

\n", + "\n", + "

\n", + " As respostas estão presentes no trecho (crédito da imagem: blog SQuAD)\n", + "

\n", + "\n", + "Quanto ao modelo de tarefa de resposta a perguntas, as entradas devem ser o par trecho/pergunta que já foram pré-processadas, e as saídas devem ser os logits de início e fim para cada token do trecho. O tamanho da entrada pode ser definido e ajustado de acordo com o tamanho do trecho e da pergunta." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gb7P4WQta8Ub" + }, + "source": [ + "## Visão geral completa\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "w7cIHjIfbDlG" + }, + "source": [ + "O trecho de código abaixo demonstra como obter o modelo com algumas linhas de código. O processo geral inclui 5 etapas: (1) escolher um modelo, (2) carregar dados, (3) retreinar o modelo, (4) avaliar e (5) exportá-lo para o formato do TensorFlow Lite." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xQPdlxZBYuZG" + }, + "source": [ + "```python\n", + "# Chooses a model specification that represents the model.\n", + "spec = model_spec.get('mobilebert_qa')\n", + "\n", + "# Gets the training data and validation data.\n", + "train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)\n", + "validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)\n", + "\n", + "# Fine-tunes the model.\n", + "model = question_answer.create(train_data, model_spec=spec)\n", + "\n", + "# Gets the evaluation result.\n", + "metric = model.evaluate(validation_data)\n", + "\n", + "# Exports the model to the TensorFlow Lite format with metadata in the export directory.\n", + "model.export(export_dir)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "exScAdvBbNEi" + }, + "source": [ + "As próximas seções explicam o código com maiores detalhes." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bcLF2PKkSbV3" + }, + "source": [ + "## Pré-requisitos\n", + "\n", + "Para executar este exemplo, instale os pacotes exigidos, incluindo o pacote do Model Maker no [repositório do GitHub](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qhl8lqVamEty" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install -q tflite-model-maker-nightly" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l6lRhVK9Q_0U" + }, + "source": [ + "Importe os pacotes necessários." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XtxiUeZEiXpt" + }, + "outputs": [ + + ], + "source": [ + "import numpy as np\n", + "import os\n", + "\n", + "import tensorflow as tf\n", + "assert tf.__version__.startswith('2')\n", + "\n", + "from tflite_model_maker import model_spec\n", + "from tflite_model_maker import question_answer\n", + "from tflite_model_maker.config import ExportFormat\n", + "from tflite_model_maker.question_answer import DataLoader" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l65ctmtW7_FF" + }, + "source": [ + "A \"Visão geral completa\" demonstra um exemplo completo simples. A próxima seção mostra mais detalhes do exemplo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kJ_B8fMDOhMR" + }, + "source": [ + "## Escolha um model_spec que represente um modelo de resposta a perguntas\n", + "\n", + "Cada objeto `model_spec` representa um modelo específico de resposta a perguntas. Atualmente, o Model Maker tem suporte a modelos MobileBERT e BERT-Base.\n", + "\n", + "Modelo com suporte | Nome de model_spec | Descrição do modelo\n", + "--- | --- | ---\n", + "[MobileBERT](https://arxiv.org/pdf/2004.02984.pdf) | 'mobilebert_qa' | 4,3 vezes menor e 5,5 vezes mais rápido do que o BERT-Base, alcançando resultados competitivos, adequados para aplicativos em dispositivos.\n", + "[MobileBERT-SQuAD](https://arxiv.org/pdf/2004.02984.pdf) | 'mobilebert_qa_squad' | Mesma arquitetura de modelo do MobileBERT, e o modelo inicial já é retreinado com [SQuAD1.1](https://rajpurkar.github.io/SQuAD-explorer/).\n", + "[BERT-Base](https://arxiv.org/pdf/1810.04805.pdf) | 'bert_qa' | Modelo BERT padrão amplamente usado em tarefas de NLP.\n", + "\n", + "Neste tutorial, [MobileBERT-SQuAD](https://arxiv.org/pdf/2004.02984.pdf) é usado como exemplo. Como o modelo já foi retreinado com [SQuAD1.1](https://rajpurkar.github.io/SQuAD-explorer/), pode convergir mais rapidamente em tarefas de resposta a perguntas.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vEAWuZQ1PFiX" + }, + "outputs": [ + + ], + "source": [ + "spec = model_spec.get('mobilebert_qa_squad')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ygEncJxtl-nQ" + }, + "source": [ + "## Carregue dados de entrada específicos em um aplicativo de aprendizado de máquina em dispositivo e pré-processe os dados\n", + "\n", + "[TriviaQA](https://nlp.cs.washington.edu/triviaqa/) é um dataset de compreensão de leitura que contém mais de 650 mil tuplas pergunta-resposta-evidência. Neste tutorial, você usará um subconjunto desse dataset para aprender a usar a biblioteca Model Maker.\n", + "\n", + "Para carregar os dados, converta o dataset TriviaQA para o formato [SQuAD1.1](https://rajpurkar.github.io/SQuAD-explorer/) executando o [script conversor do Python](https://github.com/mandarjoshi90/triviaqa#miscellaneous) com `--sample_size=8000` e um conjunto de dados `web`. Modifique ligeiramente o código de conversão:\n", + "\n", + "- Ignore as amostras que não conseguiram encontrar uma resposta no documento do contexto.\n", + "- Obtenha a resposta original no contexto sem diferenciar letras maiúsculas ou minúsculas.\n", + "\n", + "Baixe a versão arquivada do dataset já convertido." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7tOfUr2KlgpU" + }, + "outputs": [ + + ], + "source": [ + "train_data_path = tf.keras.utils.get_file(\n", + " fname='triviaqa-web-train-8000.json',\n", + " origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-web-train-8000.json')\n", + "validation_data_path = tf.keras.utils.get_file(\n", + " fname='triviaqa-verified-web-dev.json',\n", + " origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-verified-web-dev.json')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UfZk8GNr_1nc" + }, + "source": [ + "Você também pode treinar o modelo MobileBERT com seu próprio dataset. Se você estiver executando este notebook no Colab, carregue os dados pela barra lateral esquerda.\n", + "\n", + "\"Upload\n", + "\n", + "Se você preferir não carregar os dados na nuvem, pode executar a biblioteca offline de acordo com este [guia](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E051HBUM5owi" + }, + "source": [ + "Use o método `DataLoader.from_squad` para carregar e pré-processar os dados no [formato SQuAD](https://rajpurkar.github.io/SQuAD-explorer/) para um `model_spec` específico. Você pode usar o formato SQuAD2.0 ou SQuAD1.1. Ao definir o parâmetro `version_2_with_negative` como `True` (verdadeiro), o formato será SQuAD2.0. Caso contrário, será SQuAD1.1. Por padrão, `version_2_with_negative` é `False` (falso)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "I_fOlZsklmlL" + }, + "outputs": [ + + ], + "source": [ + "train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)\n", + "validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AWuoensX4vDA" + }, + "source": [ + "## Personalize o modelo do TensorFlow\n", + "\n", + "Crie um modelo personalizado de resposta a perguntas com base nos dados carregados. A função `create` consiste nas seguintes etapas:\n", + "\n", + "1. Cria o modelo de resposta a perguntas de acordo com `model_spec`.\n", + "2. Treina o modelo de resposta a perguntas. As épocas padrão e o tamanho de lote padrão são definidos pelas duas variáveis `default_training_epochs` e `default_batch_size` no objeto `model_spec`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TvYSUuJY3QxR" + }, + "outputs": [ + + ], + "source": [ + "model = question_answer.create(train_data, model_spec=spec)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0JKI-pNc8idH" + }, + "source": [ + "Confira a estrutura detalhada do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gd7Hs8TF8n3H" + }, + "outputs": [ + + ], + "source": [ + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LP5FPk_tOxoZ" + }, + "source": [ + "## Avalie o modelo personalizado\n", + "\n", + "Avalie o modelo e os dados de validação e obtenha um dicionário das métricas, incluindo a pontuação `f1` e `exact match`, etc. Observe que as métricas de SQuAD1.1 e SQuAD2.0 são diferentes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A8c2ZQ0J3Riy" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate(validation_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aeHoGAceO2xV" + }, + "source": [ + "## Exporte para um modelo do TensorFlow Lite\n", + "\n", + "Converta o modelo treinado para o formato de modelos do TensorFlow Lite com [metadados](https://www.tensorflow.org/lite/models/convert/metadata) para poder usá-lo posteriormente em um aplicativo de aprendizado de máquina em dispositivos. O arquivo de vocabulário é incorporado aos metadados. O nome de arquivo padrão do TF Lite é `model.tflite`.\n", + "\n", + "Em diversos aplicativos de aprendizado de máquina em dispositivos, o tamanho do modelo é um fator importante. Portanto, recomendamos aplicar quantização no modelo para deixá-lo menor e possivelmente mais rápido. Para modelos BERT e MobileBERT, a técnica padrão de quantização pós-treinamento é a quantização de intervalo dinâmico." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Im6wA9lK3TQB" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "w12kvDdHJIGH" + }, + "source": [ + "Você pode usar o arquivo de modelo do TensorFlow Lite no aplicativo de referência [bert_qa](https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/android) utilizando a [API BertQuestionAnswerer](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_question_answerer) na [biblioteca Task do TensorFlow Lite](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview), basta baixá-lo na barra lateral esquerda do Colab." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VFnJPvq3VGh3" + }, + "source": [ + "Confira abaixo os formatos de exportação permitidos:\n", + "\n", + "- `ExportFormat.TFLITE`\n", + "- `ExportFormat.VOCAB`\n", + "- `ExportFormat.SAVED_MODEL`\n", + "\n", + "Por padrão, só é exportado o modelo do TensorFlow Lite com metadados. Você também pode exportar diferentes arquivos seletivamente. Por exemplo: exporte somente o arquivo de vocabulário da seguinte forma:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ro2hz4kXVImY" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='.', export_format=ExportFormat.VOCAB)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HZKYthlVrTos" + }, + "source": [ + "E você pode avaliar o modelo do TF Lite com o método `evaluate_tflite`. É esperado que essa etapa demore um tempo longo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ochbq95ZrVFX" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate_tflite('model.tflite', validation_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EoWiA_zX8rxE" + }, + "source": [ + "## Uso avançado\n", + "\n", + "A função `create` é uma parte essencial dessa biblioteca, em que o parâmetro `model_spec` define a especificação do modelo. Atualmente, há suporte à classe `BertQASpec`. Há dois modelos: MobileBERT e BERT-Base. A função `create` consiste nas seguintes etapas:\n", + "\n", + "1. Cria o modelo de resposta a perguntas de acordo com `model_spec`.\n", + "2. Treina o modelo de resposta a perguntas.\n", + "\n", + "Nesta seção, descreveremos diversos tópicos avançados, incluindo como alterar o modelo, ajustar os hiperparâmetros de treinamento, etc." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mwtiksguDfhl" + }, + "source": [ + "### Ajuste o modelo\n", + "\n", + "Você pode ajustar a infraestrutura do modelo, como os parâmetros `seq_len` e `query_len`, na classe `BertQASpec`.\n", + "\n", + "Parâmetros do modelo ajustáveis:\n", + "\n", + "- `seq_len`: tamanho do trecho a ser alimentado no modelo.\n", + "- `query_len`: tamanho da pergunta a ser alimentada no modelo.\n", + "- `doc_stride`: stride ao usar a estratégia de janela deslizante para pegar partes do documento.\n", + "- `initializer_range`: desvio padrão do truncated_normal_initializer para inicializar as matrizes de pesos.\n", + "- `trainable`: booleano, indica se a camada pré-treinada é treinável.\n", + "\n", + "Parâmetros do pipeline de treinamento ajustáveis:\n", + "\n", + "- `model_dir`: local dos arquivos de checkpoint do modelo. Caso não seja definido, será usado um diretório temporário.\n", + "- `dropout_rate`: taxa de dropout.\n", + "- `learning_rate`: taxa de aprendizado inicial para Adam.\n", + "- `predict_batch_size`: tamanho do lote para previsão.\n", + "- `tpu`: endereço da TPU à qual se conectar. Usado somente ao utilizar TPU.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cAOd5_bzH9AQ" + }, + "source": [ + "Por exemplo: você pode treinar o modelo com um tamanho de sequência maior. Se você alterar o modelo, primeiro precisa construir um novo `model_spec`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "e9WBN0UTQoMN" + }, + "outputs": [ + + ], + "source": [ + "new_spec = model_spec.get('mobilebert_qa')\n", + "new_spec.seq_len = 512" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6LSTdghTP0Cv" + }, + "source": [ + "As outras etapas são as mesmas. Observação: você precisa executar novamente tanto `dataloader` quanto `create`, pois especificações diferentes de modelos podem ter etapas de pré-processamento diferentes.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LvQuy7RSDir3" + }, + "source": [ + "### Ajuste os hiperparâmetros de treinamento\n", + "\n", + "Você também pode ajustar os hiperparâmetros de treinamento, como `epochs` e `batch_size`, o que impacta o desempenho do modelo. Por exemplo:\n", + "\n", + "- `epochs`: mais épocas podem levar a um desempenho melhor, mas podem causar overfitting.\n", + "- `batch_size`: número de amostras a serem usadas em um passo de treinamento.\n", + "\n", + "Por exemplo, você pode treinar com mais épocas e um tamanho de lote maior:\n", + "\n", + "```python\n", + "model = question_answer.create(train_data, model_spec=spec, epochs=5, batch_size=64)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Eq6B9lKMfhS6" + }, + "source": [ + "### Altere a arquitetura do modelo\n", + "\n", + "É possível alterar o modelo base usado para treinar os dados mudando `model_spec`. Por exemplo, para alterar para o modelo BERT-Base, execute:\n", + "\n", + "```python\n", + "spec = model_spec.get('bert_qa')\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L2d7yycrgu6L" + }, + "source": [ + "As outras etapas são as mesmas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wFQrDMXzOVoB" + }, + "source": [ + "### Personalize a quantização pós-treinamento em um modelo do TensorFlow Lite\n", + "\n", + "A [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization) é uma técnica de conversão que pode reduzir o tamanho do modelo e a latência de inferência, além de aumentar a velocidade de inferência da CPU e do acelerador de hardware com uma pequena redução da exatidão do modelo. A quantização é amplamente utilizada para otimizar o modelo.\n", + "\n", + "A biblioteca Model Maker aplica uma técnica padrão de quantização pós-treinamento ao exportar o modelo. Se você quiser personalizar a quantização pós-treinamento, o Model Maker oferece suporte a diversas opções usando [QuantizationConfig](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/config/QuantizationConfig). Vejamos a quantização de float16 como exemplo. Primeiro, definimos a configuração de quantização.\n", + "\n", + "```python\n", + "config = QuantizationConfig.for_float16()\n", + "```\n", + "\n", + "Em seguida, exportamos o modelo do TensorFlow Lite com essa configuração.\n", + "\n", + "```python\n", + "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wPVopCeB6LV6" + }, + "source": [ + "# Saiba mais\n", + "\n", + "Leia o exemplo de [pergunta e resposta BERT](https://www.tensorflow.org/lite/examples/bert_qa/overview) para aprender os detalhes técnicos. Confira mais informações em:\n", + "\n", + "- [Guia](https://www.tensorflow.org/lite/models/modify/model_maker) e [referência da API](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker) do TensorFlow Lite Model Maker.\n", + "- Task Library: [BertQuestionAnswerer](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_question_answerer) para implantação.\n", + "- Aplicativos de referência completos para [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/android) e [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/bert_qa/ios)." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "question_answer.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb b/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb new file mode 100644 index 0000000000..2084e0686b --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb @@ -0,0 +1,948 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "3XX46cTrh6iD" + }, + "source": [ + "##### Copyright 2022 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "sKrlWr6Kh-mF" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hST65kOHXpiL" + }, + "source": [ + "# Retreine um modelo de reconhecimento de fala com o TensorFlow Lite Model Maker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nShlCXGkbRVA" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BB5k6xNKJ5Xe" + }, + "source": [ + "Neste notebook do Colab, você aprenderá a usar o [TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) para treinar um modelo de reconhecimento de fala que consegue classificar palavras ou frases curtas faladas usando amostras de som de um segundo. A biblioteca Model Maker usa aprendizado por transferência para retreinar um modelo do TensorFlow com um novo dataset, reduzindo a quantidade de dados de amostra e o tempo necessários para o treinamento.\n", + "\n", + "Por padrão, este notebook retreina o modelo (BrowserFft, do [TFJS Speech Command Recognizer](https://github.com/tensorflow/tfjs-models/tree/master/speech-commands#speech-command-recognizer)) usando um subconjunto de palavras do [dataset de comandos de voz](https://www.tensorflow.org/datasets/catalog/speech_commands) (como \"up\" – cima, \"down\" – baixo, \"left\" – esquerda e \"right\" – direita). Em seguida, ele exporta um modelo do TF Lite que você pode executar em um dispositivo móvel ou sistema embarcado (como o Raspberry Pi). Além disso, exporta o modelo treinado como um SavedModel do TensorFlow.\n", + "\n", + "Este notebook também aceita um dataset personalizado de arquivos WAV, carregados no Colab em um arquivo ZIP. Quanto mais amostras você tiver para cada classe, maior será a exatidão, mas, como o processo de aprendizado por transferência usa embeddings de características do modelo pré-treinado, você ainda pode conseguir um modelo bastante exato com apenas algumas dezenas de amostras para cada uma das classes.\n", + "\n", + "**Observação:** o modelo que vamos treinar é otimizado para reconhecimento de fala com amostras de um segundo. Se você quiser fazer uma classificação de áudio mais genérica (como detectar diferentes tipos de música), sugerimos que confira [este Colab para retreinar um classificador de áudio](https://colab.sandbox.google.com/github/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/models/modify/model_maker/audio_classification.ipynb).\n", + "\n", + "Se você quiser executar o notebook com o dataset de falas padrão, pode executar agora mesmo clicando em **Runtime > Run all** (Runtime > Executar tudo) na barra de ferramentas do Colab. Porém, se você quiser usar seu próprio dataset, prossiga para a seção [Prepare o dataset](#scrollTo=cBsSAeYLkc1Z) e siga as instruções.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AeZZ_cSsZfPx" + }, + "source": [ + "### Importe os pacotes necessários\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MelHQlE7FVue" + }, + "source": [ + "Você precisará do TensorFlow, TF Lite Model Maker e alguns módulos para manipulação e reprodução de áudio, além de visualização." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wbMc4vHjaYdQ" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install tflite-model-maker" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rwUA9u4oWoCR" + }, + "outputs": [ + + ], + "source": [ + "import os\n", + "import glob\n", + "import random\n", + "import shutil\n", + "\n", + "import librosa\n", + "import soundfile as sf\n", + "from IPython.display import Audio\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "import tensorflow as tf\n", + "import tflite_model_maker as mm\n", + "from tflite_model_maker import audio_classifier\n", + "from tflite_model_maker.config import ExportFormat\n", + "\n", + "print(f\"TensorFlow Version: {tf.__version__}\")\n", + "print(f\"Model Maker Version: {mm.__version__}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cBsSAeYLkc1Z" + }, + "source": [ + "## Prepare o dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NTTSXJxJq2Bz" + }, + "source": [ + "Para treinar com o dataset de falas padrão, basta executar todo o código abaixo, sem fazer alterações.\n", + "\n", + "Porém, se você quiser treinar com seu próprio dataset de falas, siga estas etapas:\n", + "\n", + "**Observação:** o modelo que você vai retreinar espera que os dados de entrada sejam áudios de cerca de um segundo com 44,1 kHz. O Model Maker faz a reamostragem automática do dataset de treinamento, então você não precisa fazer a reamostragem do dataset se ele tiver uma taxa de amostragem diferente de 44,1 kHz. Mas saiba que as amostras de áudio com mais de um segundo serão divididas em diversos pedaços de um segundo, e o pedaço final será descartado se tiver duração menor do que um segundo.\n", + "\n", + "1. Confirme se cada amostra do seu dataset está no **formato de arquivo WAV com cerca de um segundo de duração**. Em seguida, crie um arquivo ZIP com todos os arquivos WAV organizados em subpastas separadas para cada classificação. Por exemplo: cada amostra de um comando de voz \"yes\" (sim) deve estar em uma subpasta chamada \"yes\". Mesmo se você tiver somente uma classe, as amostras precisam ser salvas em um subdiretório cujo nome seja o nome da classe (esse script pressupõe que seu dataset **não esteja dividido** em conjuntos de treinamento/validação/teste e faz a divisão para você).\n", + "2. Clique na guia **Files** (Arquivos) no painel esquerdo e arraste seu arquivo ZIP para lá para carregá-lo.\n", + "3. Use a seguinte opção do menu suspenso para definir **`use_custom_dataset`** como True (verdadeiro).\n", + "4. Em seguida, vá à seção [Prepare um dataset de áudio personalizado](#scrollTo=EobYerLQkiF1) para especificar seu nome de arquivo ZIP e nome do diretório do dataset.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "AK9o98X7qyhU" + }, + "outputs": [ + + ], + "source": [ + "use_custom_dataset = False #@param [\"False\", \"True\"] {type:\"raw\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "D2sNXbYVHjjy" + }, + "source": [ + "### Gere um dataset de ruídos de fundo" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gBVClNMwHtMD" + }, + "source": [ + "Não importa se você esteja usando o dataset de falas padrão ou um personalizado, precisa ter um bom conjunto de ruídos de fundo para que o modelo consiga distinguir falas de outros ruídos (incluindo silêncio).\n", + "\n", + "Como as amostras de fundo abaixo são fornecidas em arquivos WAV com um minuto ou mais, precisamos dividi-las em amostras menores, de um segundo, para reservarmos alguns para o dataset de teste. Também vamos combinar algumas fontes de amostra diferentes para criar um conjunto abrangente de ruídos de fundo e silêncio:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qvJd9VfmHu29" + }, + "outputs": [ + + ], + "source": [ + "tf.keras.utils.get_file('speech_commands_v0.01.tar.gz',\n", + " 'http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz',\n", + " cache_dir='./',\n", + " cache_subdir='dataset-speech',\n", + " extract=True)\n", + "tf.keras.utils.get_file('background_audio.zip',\n", + " 'https://storage.googleapis.com/download.tensorflow.org/models/tflite/sound_classification/background_audio.zip',\n", + " cache_dir='./',\n", + " cache_subdir='dataset-background',\n", + " extract=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7CAVFc3woB3_" + }, + "source": [ + "**Observação:** embora exista uma versão mais nova disponível, estamos usando a v0.01 do dataset de comandos de voz porque é menor. A v0.01 inclui 30 comandos, enquanto a v0.02 adiciona mais cinco (\"backward\" – para trás, \"forward\" – para frente, \"follow\" – siga, \"learn\" – aprenda e \"visual\")." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xgwWNifGL-3b" + }, + "outputs": [ + + ], + "source": [ + "# Create a list of all the background wav files\n", + "files = glob.glob(os.path.join('./dataset-speech/_background_noise_', '*.wav'))\n", + "files = files + glob.glob(os.path.join('./dataset-background', '*.wav'))\n", + "\n", + "background_dir = './background'\n", + "os.makedirs(background_dir, exist_ok=True)\n", + "\n", + "# Loop through all files and split each into several one-second wav files\n", + "for file in files:\n", + " filename = os.path.basename(os.path.normpath(file))\n", + " print('Splitting', filename)\n", + " name = os.path.splitext(filename)[0]\n", + " rate = librosa.get_samplerate(file)\n", + " length = round(librosa.get_duration(filename=file))\n", + " for i in range(length - 1):\n", + " start = i * rate\n", + " stop = (i * rate) + rate\n", + " data, _ = sf.read(file, start=start, stop=stop)\n", + " sf.write(os.path.join(background_dir, name + str(i) + '.wav'), data, rate)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bVlvVq-SkeeO" + }, + "source": [ + "### Prepare o dataset de comandos de voz" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "q_q22T5UHbJG" + }, + "source": [ + "Já baixamos o dataset de comandos de voz, então agora só precisamos eliminar um determinado número de classes para nosso modelo.\n", + "\n", + "Esse dataset inclui mais de 30 classificações de comando de voz, e a maioria delas tem mais de 2.000 amostras. Porém, como estamos usando aprendizado por transferência, não precisamos de tantas amostras assim. Dessa forma, o código abaixo faz o seguinte:\n", + "\n", + "- Especifica quais classificações queremos usar e exclui as restantes.\n", + "- Mantém somente 150 amostras de cada classe para treinamento (para comprovar que o aprendizado por transferência funciona bem mesmo com datasets menores e reduz o tempo de treinamento).\n", + "- Cria um diretório separado para um dataset de teste para que possamos executar a inferência posteriormente com facilidade." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zUSRpw2nOp8p" + }, + "outputs": [ + + ], + "source": [ + "if not use_custom_dataset:\n", + " commands = [ \"up\", \"down\", \"left\", \"right\", \"go\", \"stop\", \"on\", \"off\", \"background\"]\n", + " dataset_dir = './dataset-speech'\n", + " test_dir = './dataset-test'\n", + "\n", + " # Move the processed background samples\n", + " shutil.move(background_dir, os.path.join(dataset_dir, 'background')) \n", + "\n", + " # Delete all directories that are not in our commands list\n", + " dirs = glob.glob(os.path.join(dataset_dir, '*/'))\n", + " for dir in dirs:\n", + " name = os.path.basename(os.path.normpath(dir))\n", + " if name not in commands:\n", + " shutil.rmtree(dir)\n", + "\n", + " # Count is per class\n", + " sample_count = 150\n", + " test_data_ratio = 0.2\n", + " test_count = round(sample_count * test_data_ratio)\n", + "\n", + " # Loop through child directories (each class of wav files)\n", + " dirs = glob.glob(os.path.join(dataset_dir, '*/'))\n", + " for dir in dirs:\n", + " files = glob.glob(os.path.join(dir, '*.wav'))\n", + " random.seed(42)\n", + " random.shuffle(files)\n", + " # Move test samples:\n", + " for file in files[sample_count:sample_count + test_count]:\n", + " class_dir = os.path.basename(os.path.normpath(dir))\n", + " os.makedirs(os.path.join(test_dir, class_dir), exist_ok=True)\n", + " os.rename(file, os.path.join(test_dir, class_dir, os.path.basename(file)))\n", + " # Delete remaining samples\n", + " for file in files[sample_count + test_count:]:\n", + " os.remove(file)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EobYerLQkiF1" + }, + "source": [ + "### Prepare um dataset personalizado" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f3xTvDP3knMd" + }, + "source": [ + "Se você quiser treinar o modelo com seu próprio dataset de falas, precisa carregar suas amostras como arquivos WAV em um arquivo ZIP ([conforme descrito acima](#scrollTo=cBsSAeYLkc1Z)) e modificar as seguintes variáveis para especificar seu dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "77PsQAKA4Arx" + }, + "outputs": [ + + ], + "source": [ + "if use_custom_dataset:\n", + " # Specify the ZIP file you uploaded:\n", + " !unzip YOUR-FILENAME.zip\n", + " # Specify the unzipped path to your custom dataset\n", + " # (this path contains all the subfolders with classification names):\n", + " dataset_dir = './YOUR-DIRNAME'" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hwp6EQqvttgf" + }, + "source": [ + "Após alterar o nome do arquivo e o caminho acima, você já pode treinar o modelo com seu dataset personalizado. Na barra de ferramentas do Colab, selecione **Runtime > Run all** (Runtime > Executar tudo) para executar todo o notebook.\n", + "\n", + "O código abaixo integra nossas novas amostras de ruídos de fundo ao dataset e depois separa uma parte de todas as amostras para criar um dataset de teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tMQ6cpw_B9e_" + }, + "outputs": [ + + ], + "source": [ + "def move_background_dataset(dataset_dir):\n", + " dest_dir = os.path.join(dataset_dir, 'background')\n", + " if os.path.exists(dest_dir):\n", + " files = glob.glob(os.path.join(background_dir, '*.wav'))\n", + " for file in files:\n", + " shutil.move(file, dest_dir)\n", + " else:\n", + " shutil.move(background_dir, dest_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "45iru8OdliG3" + }, + "outputs": [ + + ], + "source": [ + "if use_custom_dataset:\n", + " # Move background samples into custom dataset\n", + " move_background_dataset(dataset_dir)\n", + "\n", + " # Now we separate some of the files that we'll use for testing:\n", + " test_dir = './dataset-test'\n", + " test_data_ratio = 0.2\n", + " dirs = glob.glob(os.path.join(dataset_dir, '*/'))\n", + " for dir in dirs:\n", + " files = glob.glob(os.path.join(dir, '*.wav'))\n", + " test_count = round(len(files) * test_data_ratio)\n", + " random.seed(42)\n", + " random.shuffle(files)\n", + " # Move test samples:\n", + " for file in files[:test_count]:\n", + " class_dir = os.path.basename(os.path.normpath(dir))\n", + " os.makedirs(os.path.join(test_dir, class_dir), exist_ok=True)\n", + " os.rename(file, os.path.join(test_dir, class_dir, os.path.basename(file)))\n", + " print('Moved', test_count, 'images from', class_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "myPa1dfEoagz" + }, + "source": [ + "### Reproduza uma amostra" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1jecBYREgMk6" + }, + "source": [ + "Para confirmar se o dataset parece correto, vamos reproduzir uma amostra aleatória do dataset de teste:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gLC3ayJsoeNw" + }, + "outputs": [ + + ], + "source": [ + "def get_random_audio_file(samples_dir):\n", + " files = os.path.abspath(os.path.join(samples_dir, '*/*.wav'))\n", + " files_list = glob.glob(files)\n", + " random_audio_path = random.choice(files_list)\n", + " return random_audio_path\n", + "\n", + "def show_sample(audio_path):\n", + " audio_data, sample_rate = sf.read(audio_path)\n", + " class_name = os.path.basename(os.path.dirname(audio_path))\n", + " print(f'Class: {class_name}')\n", + " print(f'File: {audio_path}')\n", + " print(f'Sample rate: {sample_rate}')\n", + " print(f'Sample length: {len(audio_data)}')\n", + "\n", + " plt.title(class_name)\n", + " plt.plot(audio_data)\n", + " display(Audio(audio_data, rate=sample_rate))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "todbtEWFy0mj" + }, + "outputs": [ + + ], + "source": [ + "random_audio = get_random_audio_file(test_dir)\n", + "show_sample(random_audio)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f-jRIWcQv7xt" + }, + "source": [ + "## Defina o modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pQj1Mf7YZELS" + }, + "source": [ + "Ao usar o Model Maker para retreinar qualquer modelo, você precisa começar pela definição de uma especificação do modelo. A especificação define o modelo base do qual o novo modelo extrairá os embeddings de características para começar a aprender novas classes. A especificação para este reconhecedor de fala é baseado no [modelo BrowserFft pré-treinado do TFJS](https://github.com/tensorflow/tfjs-models/tree/master/speech-commands#speech-command-recognizer).\n", + "\n", + "O modelo espera que a entrada seja uma amostra de áudio com 44,1 kHz e com menos de um segundo: o tamanho exato da amostra deve ser de 44.034 quadros.\n", + "\n", + "Você não precisa fazer reamostragem do dataset de treinamento, pois o Model Maker cuida dessa tarefa. Mas, quando você executar a inferência posteriormente, deve garantir que a entrada tenha o formato esperado.\n", + "\n", + "Você só precisa instanciar [`BrowserFftSpec`](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier/BrowserFftSpec):\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tUcxtfHXY7XS" + }, + "outputs": [ + + ], + "source": [ + "spec = audio_classifier.BrowserFftSpec()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "maTOoRvAwI9l" + }, + "source": [ + "## Carregue seu dataset " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UASCEHoVwQ1q" + }, + "source": [ + "Agora você precisa carregar seu dataset de acordo com as especificações do modelo. O Model Maker inclui a API [`DataLoader`](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier/DataLoader), que carrega seu dataset a partir de uma pasta e garante que ele esteja no formato esperado segundo a especificação do modelo.\n", + "\n", + "Já reservamos alguns arquivos de teste quando os movemos para um diretório separado, o que facilita a execução da inferência posteriormente. Agora, vamos criar um `DataLoader` para cada divisão: o dataset de treinamento, validação e teste." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bAhAfHwiw2_F" + }, + "source": [ + "#### Carregue o dataset de comandos de voz\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cX0RqETqZgzo" + }, + "outputs": [ + + ], + "source": [ + "if not use_custom_dataset:\n", + " train_data_ratio = 0.8\n", + " train_data = audio_classifier.DataLoader.from_folder(\n", + " spec, dataset_dir, cache=True)\n", + " train_data, validation_data = train_data.split(train_data_ratio)\n", + " test_data = audio_classifier.DataLoader.from_folder(\n", + " spec, test_dir, cache=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2OWQ_O9_t-C-" + }, + "source": [ + "#### Carregue um dataset personalizado" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IPiwaJwMt7yo" + }, + "source": [ + "**Observação:** é importante definir `cache=True` para acelerar o treinamento (principalmente quando o dataset for reamostrado), mas isso exige mais RAM para armazenar os dados. Se você estiver utilizando um dataset personalizado muito grande, é possível que o cache exceda a capacidade de RAM." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "code", + "id": "e86Ej-ZmuCzy" + }, + "outputs": [ + + ], + "source": [ + "if use_custom_dataset:\n", + " train_data_ratio = 0.8\n", + " train_data = audio_classifier.DataLoader.from_folder(\n", + " spec, dataset_dir, cache=True)\n", + " train_data, validation_data = train_data.split(train_data_ratio)\n", + " test_data = audio_classifier.DataLoader.from_folder(\n", + " spec, test_dir, cache=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hh1P_zfzwbfE" + }, + "source": [ + "## Treine o modelo\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ziMghju-Rts2" + }, + "source": [ + "Agora vamos usar a função [`create()`](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/audio_classifier/create) do Model Maker para criar um modelo baseado na nossa especificação de modelo e dataset de treinamento. Em seguida, vamos começar o treinamento.\n", + "\n", + "Se você estiver utilizando um dataset personalizado, talvez queira alterar o tamanho do lote para o número de amostras em seu dataset de treinamento, conforme apropriado.\n", + "\n", + "**Observação:** a primeira época demora mais tempo porque é preciso criar o cache. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GYaZvaOPgLUC" + }, + "outputs": [ + + ], + "source": [ + "# If your dataset has fewer than 100 samples per class,\n", + "# you might want to try a smaller batch size\n", + "batch_size = 25\n", + "epochs = 25\n", + "model = audio_classifier.create(train_data, spec, validation_data, batch_size, epochs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mtLuRA2xweZA" + }, + "source": [ + "## Avalie o desempenho do modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oXMEHZkAxJTl" + }, + "source": [ + "Mesmo que a exatidão e a perda pareçam boas na saída do treinamento acima, é importante executar o modelo usando os dados de teste que o modelo nunca viu. É isso que o método `evaluate()` faz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "n_4MGpzhWVhr" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HqvpAnqsVExO" + }, + "source": [ + "### Confira a matriz de confusão" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8QRRAM39aOxS" + }, + "source": [ + "Ao treinar um modelo de classificação como este, também vale a pena inspecionar a [matriz de confusão](https://en.wikipedia.org/wiki/Confusion_matrix), que fornece uma representação visual detalhada do desempenho do classificador para cada classificação nos dados de teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zqB3c0368iH3" + }, + "outputs": [ + + ], + "source": [ + "def show_confusion_matrix(confusion, test_labels):\n", + " \"\"\"Compute confusion matrix and normalize.\"\"\"\n", + " confusion_normalized = confusion.astype(\"float\") / confusion.sum(axis=1)\n", + " sns.set(rc = {'figure.figsize':(6,6)})\n", + " sns.heatmap(\n", + " confusion_normalized, xticklabels=test_labels, yticklabels=test_labels,\n", + " cmap='Blues', annot=True, fmt='.2f', square=True, cbar=False)\n", + " plt.title(\"Confusion matrix\")\n", + " plt.ylabel(\"True label\")\n", + " plt.xlabel(\"Predicted label\")\n", + "\n", + "confusion_matrix = model.confusion_matrix(test_data)\n", + "show_confusion_matrix(confusion_matrix.numpy(), test_data.index_to_label)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yASrikBgZ9ZO" + }, + "source": [ + "## Exporte o modelo\n", + "\n", + "A última etapa é exportar seu modelo para o formato do TensorFlow Lite para execução em dispositivos embarcados/para dispositivos móveis e para o [formato SavedModel](https://www.tensorflow.org/guide/saved_model) para execução em outros lugares.\n", + "\n", + "Ao exportar um arquivo do `.tflite` pelo Model Maker, ele inclui [metadados do modelo](https://www.tensorflow.org/lite/inference_with_metadata/overview), que descrevem diversos detalhes que podem ajudar posteriormente durante a inferência. Ele inclui até mesmo uma cópia do arquivo de rótulos de classificação e, portanto, você não precisa de um arquivo `labels.txt` separado (na próxima seção, mostraremos como usar esses metadados para executar a inferência)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4gEf59NfGWjq" + }, + "outputs": [ + + ], + "source": [ + "TFLITE_FILENAME = 'browserfft-speech.tflite'\n", + "SAVE_PATH = './models'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Xw_ehPxAdQlz" + }, + "outputs": [ + + ], + "source": [ + "print(f'Exporing the model to {SAVE_PATH}')\n", + "model.export(SAVE_PATH, tflite_filename=TFLITE_FILENAME)\n", + "model.export(SAVE_PATH, export_format=[mm.ExportFormat.SAVED_MODEL, mm.ExportFormat.LABEL])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lIC1ddGq6xQX" + }, + "source": [ + "## Execute a inferência com o modelo do TF Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5xr0idac6xfi" + }, + "source": [ + "Agora seu modelo do TF Lite pode ser implantado e executado usando qualquer uma das [bibliotecas de inferência](https://www.tensorflow.org/lite/guide/inference) disponíveis ou com a nova [API TFLite AudioClassifier Task](https://www.tensorflow.org/lite/inference_with_metadata/task_library/audio_classifier). O código abaixo mostra como executar a inferência com um modelo `.tflite` no Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nR5zV53YbCIQ" + }, + "outputs": [ + + ], + "source": [ + "# This library provides the TFLite metadata API\n", + "! pip install -q tflite_support" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1AC7PRyiayU5" + }, + "outputs": [ + + ], + "source": [ + "from tflite_support import metadata\n", + "import json\n", + "\n", + "def get_labels(model):\n", + " \"\"\"Returns a list of labels, extracted from the model metadata.\"\"\"\n", + " displayer = metadata.MetadataDisplayer.with_model_file(model)\n", + " labels_file = displayer.get_packed_associated_file_list()[0]\n", + " labels = displayer.get_associated_file_buffer(labels_file).decode()\n", + " return [line for line in labels.split('\\n')]\n", + "\n", + "def get_input_sample_rate(model):\n", + " \"\"\"Returns the model's expected sample rate, from the model metadata.\"\"\"\n", + " displayer = metadata.MetadataDisplayer.with_model_file(model)\n", + " metadata_json = json.loads(displayer.get_metadata_json())\n", + " input_tensor_metadata = metadata_json['subgraph_metadata'][0][\n", + " 'input_tensor_metadata'][0]\n", + " input_content_props = input_tensor_metadata['content']['content_properties']\n", + " return input_content_props['sample_rate']" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yC7TEvQ9o4mu" + }, + "source": [ + "Para observar o desempenho do modelo com amostras reais, execute o bloco de código abaixo várias vezes. A cada vez, ele vai buscar uma nova amostra de teste e executar a inferência, e você pode ouvir a amostra de áudio abaixo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "loU6PleipSPf" + }, + "outputs": [ + + ], + "source": [ + "# Get a WAV file for inference and list of labels from the model\n", + "tflite_file = os.path.join(SAVE_PATH, TFLITE_FILENAME)\n", + "labels = get_labels(tflite_file)\n", + "random_audio = get_random_audio_file(test_dir)\n", + "\n", + "# Ensure the audio sample fits the model input\n", + "interpreter = tf.lite.Interpreter(tflite_file)\n", + "input_details = interpreter.get_input_details()\n", + "output_details = interpreter.get_output_details()\n", + "input_size = input_details[0]['shape'][1]\n", + "sample_rate = get_input_sample_rate(tflite_file)\n", + "audio_data, _ = librosa.load(random_audio, sr=sample_rate)\n", + "if len(audio_data) < input_size:\n", + " audio_data.resize(input_size)\n", + "audio_data = np.expand_dims(audio_data[:input_size], axis=0)\n", + "\n", + "# Run inference\n", + "interpreter.allocate_tensors()\n", + "interpreter.set_tensor(input_details[0]['index'], audio_data)\n", + "interpreter.invoke()\n", + "output_data = interpreter.get_tensor(output_details[0]['index'])\n", + "\n", + "# Display prediction and ground truth\n", + "top_index = np.argmax(output_data[0])\n", + "label = labels[top_index]\n", + "score = output_data[0][top_index]\n", + "print('---prediction---')\n", + "print(f'Class: {label}\\nScore: {score}')\n", + "print('----truth----')\n", + "show_sample(random_audio)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VtmfoJW6G2fd" + }, + "source": [ + "## Baixe o modelo do TF Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8zLDeiQ_z2Vj" + }, + "source": [ + "Agora você pode implantar o modelo do TF Lite em seu dispositivo móvel ou embarcado. Você não precisa baixar o arquivo de rótulos, pois pode recuperar os rótulos usando os metadados do arquivo `.tflite`, conforme demonstrado no exemplo de inferência anterior." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cNuQoqtjG4zu" + }, + "outputs": [ + + ], + "source": [ + "try:\n", + " from google.colab import files\n", + "except ImportError:\n", + " pass\n", + "else:\n", + " files.download(tflite_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iERuGZz4z6rB" + }, + "source": [ + "Confira os aplicativos de exemplo completos que realizam a inferência com modelos de áudio do TF Lite no [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/sound_classification/android/) e no [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/sound_classification/ios)." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "speech_recognition.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb new file mode 100644 index 0000000000..ea30b8aeda --- /dev/null +++ b/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb @@ -0,0 +1,1062 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "h2q27gKz1H20" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "TUfAcER1oUS6" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Gb7qyhNL1yWt" + }, + "source": [ + "# Classificação de texto com o TensorFlow Lite Model Maker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Fw5Y7snSuG51" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sr3q-gvm3cI8" + }, + "source": [ + "A [biblioteca TensorFlow Lite Model Maker](https://www.tensorflow.org/lite/models/modify/model_maker) (criador de modelos do TF Lite) simplifica o processo de adaptar e converter um modelo do TensorFlow para dados de entrada específicos ao implantar esse modelo em aplicativos de aprendizado de máquina em dispositivos.\n", + "\n", + "Este notebook apresenta um exemplo completo que utiliza a biblioteca Model Maker para ilustrar a adaptação e conversão de um modelo de classificação de texto usado com frequência para classificar avaliações de filmes em um dispositivo móvel. O modelo classifica textos em categorias predefinidas. As entradas devem ser texto pré-processado, e as saídas são as probabilidades das categorias. O dataset usado neste tutorial é composto por avaliações de filmes positivas e negativas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bcLF2PKkSbV3" + }, + "source": [ + "## Pré-requisitos\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2vvAObmTqglq" + }, + "source": [ + "### Instale os pacotes obrigatórios\n", + "\n", + "Para executar este exemplo, instale os pacotes exigidos, incluindo o pacote do Model Maker no [repositório do GitHub](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qhl8lqVamEty" + }, + "outputs": [ + + ], + "source": [ + "!sudo apt -y install libportaudio2\n", + "!pip install -q tflite-model-maker\n", + "!pip uninstall tflite_support_nightly\n", + "!pip install tflite_support_nightly" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l6lRhVK9Q_0U" + }, + "source": [ + "Importe os pacotes necessários." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XtxiUeZEiXpt" + }, + "outputs": [ + + ], + "source": [ + "import numpy as np\n", + "import os\n", + "\n", + "from tflite_model_maker import model_spec\n", + "from tflite_model_maker import text_classifier\n", + "from tflite_model_maker.config import ExportFormat\n", + "from tflite_model_maker.text_classifier import AverageWordVecSpec\n", + "from tflite_model_maker.text_classifier import DataLoader\n", + "\n", + "from tflite_support.task import core\n", + "from tflite_support.task import processor\n", + "from tflite_support.task import text\n", + "\n", + "import tensorflow as tf\n", + "assert tf.__version__.startswith('2')\n", + "tf.get_logger().setLevel('ERROR')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BRd13bfetO7B" + }, + "source": [ + "### Baixe os dados de treinamento de amostra\n", + "\n", + "Neste tutorial, usaremos o [SST-2](https://nlp.stanford.edu/sentiment/index.html) (Stanford Sentiment Treebank), uma das tarefas no referencial [GLUE](https://gluebenchmark.com/). Ele contém 67.349 avaliações de filme para treinamento e 872 avaliações de filmes para teste. O dataset tem duas classes: avaliações de filmes positivas e negativas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "R2BSkxWg6Rhx" + }, + "outputs": [ + + ], + "source": [ + "data_dir = tf.keras.utils.get_file(\n", + " fname='SST-2.zip',\n", + " origin='https://dl.fbaipublicfiles.com/glue/data/SST-2.zip',\n", + " extract=True)\n", + "data_dir = os.path.join(os.path.dirname(data_dir), 'SST-2')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gPYTbGrizcTC" + }, + "source": [ + "O dataset SST-2 é armazenado no formato TSV. A única diferença entre TSV e CSV é que o TSV usa o caractere de tabulação `\\t` como delimitador em vez da vírgula `,` usada no formato CSV.\n", + "\n", + "Veja abaixo as 5 primeiras linhas do dataset de treinamento. label=0 significa negativo, e label=1 significa positivo.\n", + "\n", + "Frase | Label (rótulo) | | |\n", + "--- | --- | --- | --- | ---\n", + "hide new secretions from the parental units (oculta novas secreções das unidades parentais) | 0 | | |\n", + "contains no wit , only labored gags (não contém sabedoria, só piadas cansativas) | 0 | | |\n", + "that loves its characters and communicates something rather beautiful about human nature (que ama seus personagens e comunica algo lindo sobre a natureza humana) | 1 | | |\n", + "remains utterly satisfied to remain the same throughout (permanece totalmente satisfeito para permanecer igual o filme todo) | 0 | | |\n", + "on the worst revenge-of-the-nerds clichés the filmmakers could dredge up (nos piores clichês de vingança dos nerds que os cineastas puderam criar) | 0 | | |\n", + "\n", + "Agora, vamos carregar o dataset em um dataframe do Pandas e alterar os nomes de rótulos atuais (`0` e `1`) para rótulos mais legíveis por humanos (`negative` – negativa e `positive` – positiva) e usá-los para o treinamento do modelo.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iLNaOXnl3JQB" + }, + "outputs": [ + + ], + "source": [ + "import pandas as pd\n", + "\n", + "def replace_label(original_file, new_file):\n", + " # Load the original file to pandas. We need to specify the separator as\n", + " # '\\t' as the training data is stored in TSV format\n", + " df = pd.read_csv(original_file, sep='\\t')\n", + "\n", + " # Define how we want to change the label name\n", + " label_map = {0: 'negative', 1: 'positive'}\n", + "\n", + " # Excute the label change\n", + " df.replace({'label': label_map}, inplace=True)\n", + "\n", + " # Write the updated dataset to a new file\n", + " df.to_csv(new_file)\n", + "\n", + "# Replace the label name for both the training and test dataset. Then write the\n", + "# updated CSV dataset to the current folder.\n", + "replace_label(os.path.join(os.path.join(data_dir, 'train.tsv')), 'train.csv')\n", + "replace_label(os.path.join(os.path.join(data_dir, 'dev.tsv')), 'dev.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xushUyZXqP59" + }, + "source": [ + "## Início rápido\n", + "\n", + "Existem cinco etapas para treinar um modelo de classificação de texto:\n", + "\n", + "**Etapa 1 – Escolha uma arquitetura de modelo de classificação de texto**\n", + "\n", + "Usaremos a arquitetura de modelo de média de embedding de palavra, que vai gerar um modelo pequeno e rápido, com uma exatidão razoável." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CtdZ-JDwMimd" + }, + "outputs": [ + + ], + "source": [ + "spec = model_spec.get('average_word_vec')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yug6gR9qyHui" + }, + "source": [ + "O Model Maker também oferece suporte a outras arquiteturas de modelo, como [BERT](https://arxiv.org/abs/1810.04805). Se você tiver interesse em aprender outras arquiteturas, confira a seção [Escolha uma arquitetura de modelo para classificador de texto](#scrollTo=kJ_B8fMDOhMR) abaixo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s5U-A3tw6Y27" + }, + "source": [ + "**Etapa 2 – Carregue os dados de treinamento e teste, depois pré-processe-os de acordo com um `model_spec` específico.**\n", + "\n", + "O Model Maker recebe dados de entrada no formato CSV. Vamos carregar o dataset de treinamento e teste com o nome de rótulos legível por humanos que criamos anteriormente.\n", + "\n", + "Cada arquitetura de modelo requer que os dados de entrada sejam processados de uma forma específica. `DataLoader` lê os requisitos em `model_spec` e executa o pré-processamento necessário automaticamente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HD5BvzWe6YKa" + }, + "outputs": [ + + ], + "source": [ + "train_data = DataLoader.from_csv(\n", + " filename='train.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=spec,\n", + " is_training=True)\n", + "test_data = DataLoader.from_csv(\n", + " filename='dev.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=spec,\n", + " is_training=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2uZkLR6N6gDR" + }, + "source": [ + "**Etapa 3 – Treine o modelo do TensorFlow com os dados de treinamento**\n", + "\n", + "O modelo de média de embedding de palavra usa `batch_size = 32` por padrão. Portanto, você verá que ele leva 2.104 passos para percorrer as 67.349 frases do dataset de treinamento. Vamos treinar o modelo com 10 épocas, ou seja, percorrer todo o dataset de treinamento 10 vezes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kwlYdTcg63xy" + }, + "outputs": [ + + ], + "source": [ + "model = text_classifier.create(train_data, model_spec=spec, epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-BzCHLWJ6h7q" + }, + "source": [ + "**Etapa 4 – Avalie o modelo com os dados de teste**\n", + "\n", + "Após treinar o modelo de classificação de texto usando as frases do dataset de treinamento, usaremos as 872 frases restantes no dataset de teste para avaliar o desempenho do modelo com os novos dados que ele nunca viu.\n", + "\n", + "Como o tamanho padrão do lote é 32, vai demorar 28 passos para percorrer as 872 frases do dataset de teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8xmnl6Yy7ARn" + }, + "outputs": [ + + ], + "source": [ + "loss, acc = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CgCDMe0e6jlT" + }, + "source": [ + "**Etapa 5 – Exporte para um modelo do TensorFlow Lite**\n", + "\n", + "Vamos exportar o classificador de texto que treinamos para o formato do TensorFlow Lite. Especificaremos para qual pasta o modelo deverá ser exportado. Por padrão, o modelo float do TF Lite é exportado para a arquitetura de modelo de média de embedding de palavra." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hm_UULdW7A9T" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='average_word_vec')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rVxaf3x_7OfB" + }, + "source": [ + "Você pode baixar o arquivo do modelo do TensorFlow Lite pela barra lateral esquerda do Colab. Acesse a pasta `average_word_vec` que especificamos no parâmetro `export_dir` acima, clique com o botão direito no arquivo `model.tflite` e selecione `Download` (Baixar) para baixá-lo para seu computador local.\n", + "\n", + "Este modelo pode ser integrado a um aplicativo para Android ou iOS usando a [API NLClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier) da [biblioteca Task do TensorFlow Lite](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview).\n", + "\n", + "Confira mais detalhes de como o modelo é usado em um aplicativo funcional no [exemplo de aplicativo para classificação de texto do TF Lite](https://github.com/tensorflow/examples/blob/master/lite/examples/text_classification/android/lib_task_api/src/main/java/org/tensorflow/lite/examples/textclassification/client/TextClassificationClient.java#L54).\n", + "\n", + "*Observação: o Android Studio Model Binding ainda não oferece suporte à classificação de texto, então use a TensorFlow Lite Task Library.*\n", + "\n", + "*Observação 2: há um arquivo `model.json` na mesma pasta que do modelo do TF Lite. Ele contém a representação em JSON dos [metadados](https://www.tensorflow.org/lite/models/convert/metadata) empacotados dentro do modelo do TensorFlow Lite. Os metadados do modelo ajudam a TF Lite Task Library a saber o que o modelo faz e como pré/pós-processar os dados para o modelo. Você não precisa baixar o arquivo `model.json`, pois ele tem apenas fins informativos, e seu conteúdo já está dentro do arquivo do TF Lite.*\n", + "\n", + "*Observação 3: se você treinar um modelo de classificação de texto usando a arquitetura MobileBERT ou BERT-Base, precisará usar a [API BertNLClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier) para integrar o modelo treinado a um aplicativo para dispositivos móveis.*" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l65ctmtW7_FF" + }, + "source": [ + "As próximas seções explicam o exemplo passo a passo para mostrar mais detalhes." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "izO7NU7unYot" + }, + "source": [ + "**Etapa 6 – Use a `TFLite Task Library` para demonstrar como utilizar os modelos treinados**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VDov6P4wppHO" + }, + "source": [ + "Leia o arquivo dev.csv nos dados de frase para fazer previsões com o modelo treinado." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XWwvHmIltQC2" + }, + "outputs": [ + + ], + "source": [ + "sentence_data = pd.read_csv('/content/dev.csv', index_col=0)\n", + "sentence_data" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "y_-bejm5vRBf" + }, + "source": [ + "Parâmetro de configuração do modelo:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IAEEs3_3vPz5" + }, + "outputs": [ + + ], + "source": [ + "# Name of the TFLite text classification model.\n", + "_MODEL = '/content/average_word_vec/model.tflite'\n", + "# Whether to run the model on EdgeTPU.\n", + "_ENABLE_EDGETPU = False\n", + "# Number of CPU threads to run the model.\n", + "_NUM_THREADS = 4" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bInGjRcOtQbn" + }, + "source": [ + "Inicialize o modelo\n", + "\n", + "Também podemos alterar parâmetros como `file_name`, `use_coral` e `num_threads`, o que pode afetar os resultados do modelo. Veja quais parâmetros podem ser ajustados.\n", + "\n", + "- `file_name`: nome do modelo de classificação de texto do TF Lite.\n", + "- `use_coral`: se for true (verdadeiro), a inferência será delegada a um dispositivo Coral Edge TPU conectado.\n", + "- `num_threads`: número de threads de CPU que executarão o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Haham4qT8hmV" + }, + "outputs": [ + + ], + "source": [ + "# Initialize the text classification model.\n", + "base_options = core.BaseOptions(file_name=_MODEL, use_coral=_ENABLE_EDGETPU, num_threads=_NUM_THREADS)\n", + "options = text.NLClassifierOptions(base_options)\n", + "\n", + "# Create NLClassifier from options.\n", + "classifier = text.NLClassifier.create_from_options(options)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9HLl9LC9oA3G" + }, + "source": [ + "Faça a previsão usando a `TF Lite Task Library`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pAQDHFs5tTxZ" + }, + "outputs": [ + + ], + "source": [ + "for idx in range(20):\n", + " sentence = sentence_data['sentence'].iloc[idx]\n", + " label = sentence_data['label'].iloc[idx]\n", + " text_classification_result = classifier.classify(sentence)\n", + " classification_list = text_classification_result.classifications[0].categories\n", + "\n", + " # Sort output by probability descending.\n", + " predict_label = sorted(\n", + " classification_list, key=lambda item: item.score, reverse=True)[0]\n", + "\n", + " print('truth_label: {} -----> predict_label: {}'.format(label, predict_label.category_name))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kJ_B8fMDOhMR" + }, + "source": [ + "## Escolha uma arquitetura de modelo para classificador de texto\n", + "\n", + "Cada objeto `model_spec` representa um modelo específico de classificador de texto.. Atualmente, o TensorFlow Lite Model Maker tem suporte a modelos [MobileBERT](https://arxiv.org/pdf/2004.02984.pdf), média de embedding de palavra e modelos [BERT-Base](https://arxiv.org/pdf/1810.04805.pdf).\n", + "\n", + "Modelo com suporte | Nome de model_spec | Descrição do modelo | Tamanho do modelo\n", + "--- | --- | --- | ---\n", + "Média de embedding de palavra | 'average_word_vec' | Média de embedding de palavra de texto com ativação RELU. | < 1 MB\n", + "MobileBERT | 'mobilebert_classifier' | 4,3 vezes menor e 5,5 vezes mais rápido do que o BERT-Base, alcançando resultados competitivos, adequados para aplicativos em dispositivos. | 25 MB com quantização
100 MB sem quantização\n", + "BERT-Base | 'bert_classifier' | Modelo BERT padrão amplamente usado em tarefas de NLP. | 300 MB\n", + "\n", + "No início rápido, usamos o modelo de média de embedding de palavras. Vamos alterar para [MobileBERT](https://arxiv.org/pdf/2004.02984.pdf) para treinar um modelo com exatidão maior." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vEAWuZQ1PFiX" + }, + "outputs": [ + + ], + "source": [ + "mb_spec = model_spec.get('mobilebert_classifier')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ygEncJxtl-nQ" + }, + "source": [ + "## Carregue os dados de treinamento\n", + "\n", + "Você pode carregar seu próprio dataset neste tutorial. Para carregá-lo, use a barra lateral esquerda no Colab.\n", + "\n", + "\"Upload\n", + "\n", + "Se você preferir não carregar o dataset na nuvem, pode executar a biblioteca localmente de acordo com este [guia](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mWAusqz-WD5i" + }, + "source": [ + "Para simplificar, vamos reutilizar o dataset SST-2 baixado anteriormente. Vamos usar o método `DataLoader.from_csv` para carregar os dados.\n", + "\n", + "Observação: como alteramos a arquitetura do modelo, vamos precisar recarregar o dataset de treinamento e de teste para aplicar a nova lógica de pré-processamento." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "I_fOlZsklmlL" + }, + "outputs": [ + + ], + "source": [ + "train_data = DataLoader.from_csv(\n", + " filename='train.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=mb_spec,\n", + " is_training=True)\n", + "test_data = DataLoader.from_csv(\n", + " filename='dev.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=mb_spec,\n", + " is_training=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MlHvVvv2hw4H" + }, + "source": [ + "A biblioteca Model Maker também oferece suporte ao método `from_folder()` para carregar dados. Ele pressupõe que os dados de texto da mesma classe estejam no mesmo subdiretório e que o nome da subpasta seja o nome da classe. Cada arquivo de texto contém uma amostra de avaliação de filme. O parâmetro `class_labels` é usado para especificar quais são as subpastas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AWuoensX4vDA" + }, + "source": [ + "## Treine um modelo do TensorFlow\n", + "\n", + "Treine um modelo de classificação de texto usando os dados de treinamento.\n", + "\n", + "*Observação: como o MobileBERT é um modelo complexo, cada época de treinamento demora cerca de 10 minutos em uma GPU do Colab. Você deve usar um runtime de GPU.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TvYSUuJY3QxR" + }, + "outputs": [ + + ], + "source": [ + "model = text_classifier.create(train_data, model_spec=mb_spec, epochs=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0JKI-pNc8idH" + }, + "source": [ + "Confira a estrutura detalhada do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gd7Hs8TF8n3H" + }, + "outputs": [ + + ], + "source": [ + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LP5FPk_tOxoZ" + }, + "source": [ + "## Avalie o modelo\n", + "\n", + "Avalie o modelo que acabamos de treinar usando os dados de teste e mensure os valores de perda e precisão." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A8c2ZQ0J3Riy" + }, + "outputs": [ + + ], + "source": [ + "loss, acc = model.evaluate(test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "esBGwHE2QxE8" + }, + "source": [ + "## Exporte para um modelo do TensorFlow Lite\n", + "\n", + "Converta o modelo treinado para o formato de modelos do TensorFlow Lite com [metadados](https://www.tensorflow.org/lite/models/convert/metadata) para poder usá-lo posteriormente em um aplicativo de aprendizado de máquina em dispositivos. O arquivo de rótulos e o arquivo de vocabulário são incorporados aos metadados. O nome de arquivo padrão do TF Lite é `model.tflite`.\n", + "\n", + "Em diversos aplicativos de aprendizado de máquina em dispositivos, o tamanho do modelo é um fator importante. Portanto, recomendamos aplicar quantização no modelo para deixá-lo menor e possivelmente mais rápido. Para modelos BERT e MobileBERT, a técnica padrão de quantização pós-treinamento é a quantização de intervalo dinâmico." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Im6wA9lK3TQB" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='mobilebert/')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "w12kvDdHJIGH" + }, + "source": [ + "O arquivo do modelo do TensorFlow Lite pode ser integrado a um aplicativo para dispositivos móveis usando a [API BertNLClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier) na [TensorFlow Lite Task Library](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview). Observação: isso é **diferente** da API `NLClassifier` usada para integrar um classificador de texto treinado com a arquitetura de modelo de média do vetor de palavras." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AVy0ormoMZwL" + }, + "source": [ + "Confira abaixo os formatos de exportação permitidos:\n", + "\n", + "- `ExportFormat.TFLITE`\n", + "- `ExportFormat.LABEL`\n", + "- `ExportFormat.VOCAB`\n", + "- `ExportFormat.SAVED_MODEL`\n", + "\n", + "Por padrão, ele exporta somente o modelo do TensorFlow Lite contendo os metadados do modelo. Você também pode optar por exportar outros arquivos relacionados ao modelo para avaliá-los melhor. Por exemplo, é possível exportar somente o arquivo de rótulos e o arquivo de vocabulário da seguinte forma:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nbK7nzK_Mfx4" + }, + "outputs": [ + + ], + "source": [ + "model.export(export_dir='mobilebert/', export_format=[ExportFormat.LABEL, ExportFormat.VOCAB])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HZKYthlVrTos" + }, + "source": [ + "Você pode avaliar o modelo do TF Lite com o método `evaluate_tflite` para mensurar a exatidão. Ao converter o modelo do TensorFlow treinado para o formato do TF Lite e aplicar quantização, a exatidão pode ser afetada, então é recomendável avaliar a exatidão do modelo do TF Lite antes da implantação." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ochbq95ZrVFX" + }, + "outputs": [ + + ], + "source": [ + "accuracy = model.evaluate_tflite('mobilebert/model.tflite', test_data)\n", + "print('TFLite model accuracy: ', accuracy)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EoWiA_zX8rxE" + }, + "source": [ + "## Uso avançado\n", + "\n", + "A função `create` é a função que a biblioteca Model Maker usa para criar modelos. O parâmetro `model_spec` define a especificação do modelo. No momento, há suporte às classes `AverageWordVecSpec` e `BertClassifierSpec`. A função `create` consiste nas seguintes etapas:\n", + "\n", + "1. Cria o modelo de classificação de texto de acordo com `model_spec`.\n", + "2. Treina o modelo de classificador. As épocas padrão e o tamanho de lote padrão são definidos pelas duas variáveis `default_training_epochs` e `default_batch_size` no objeto `model_spec`.\n", + "\n", + "Esta seção abrange tópicos de uso avançado, como ajustar o modelo e os hiperparâmetros de treinamento." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E8VxPiOLy4Gv" + }, + "source": [ + "### Personalize os hiperparâmetros do modelo MobileBERT\n", + "\n", + "Os parâmetros do modelo que podem ser ajustados são:\n", + "\n", + "- `seq_len`: tamanho da sequência a ser alimentada no modelo.\n", + "- `initializer_range`: desvio padrão do `truncated_normal_initializer` para inicializar as matrizes de pesos.\n", + "- `trainable`: booleano que especifica se a camada pré-treinada é treinável.\n", + "\n", + "Os parâmetros do pipeline de treinamento que podem ser ajustados são:\n", + "\n", + "- `model_dir`: local dos arquivos de checkpoint do modelo. Caso não seja definido, será usado um diretório temporário.\n", + "- `dropout_rate`: taxa de dropout.\n", + "- `learning_rate`: taxa de aprendizado inicial para o otimizador Adam.\n", + "- `tpu`: endereço da TPU à qual se conectar.\n", + "\n", + "Por exemplo: você pode definir `seq_len=256` (o padrão é 128), o que permite ao modelo classificar textos maiores." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4tr9BLcjy4Sh" + }, + "outputs": [ + + ], + "source": [ + "new_model_spec = model_spec.get('mobilebert_classifier')\n", + "new_model_spec.seq_len = 256" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mwtiksguDfhl" + }, + "source": [ + "### Personalize os hiperparâmetros do modelo de média de embedding de palavra\n", + "\n", + "Você pode ajustar a infraestrutura do modelo, como as variáveis `wordvec_dim` e `seq_len` na classe `AverageWordVecSpec`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cAOd5_bzH9AQ" + }, + "source": [ + "Por exemplo: você pode treinar o modelo com um valor maior de `wordvec_dim`. Observação: você precisa construir um novo `model_spec` se modificar o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "e9WBN0UTQoMN" + }, + "outputs": [ + + ], + "source": [ + "new_model_spec = AverageWordVecSpec(wordvec_dim=32)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6LSTdghTP0Cv" + }, + "source": [ + "Obtenha os dados pré-processados." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DVZurFBORG3J" + }, + "outputs": [ + + ], + "source": [ + "new_train_data = DataLoader.from_csv(\n", + " filename='train.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=new_model_spec,\n", + " is_training=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tD7QVVHeRZoM" + }, + "source": [ + "Treine o novo modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PzpV246_JGEu" + }, + "outputs": [ + + ], + "source": [ + "model = text_classifier.create(new_train_data, model_spec=new_model_spec)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LvQuy7RSDir3" + }, + "source": [ + "### Ajuste os hiperparâmetros de treinamento\n", + "\n", + "Você também pode ajustar os hiperparâmetros de treinamento, como `epochs` e `batch_size`, o que impacta a exatidão do modelo. Por exemplo:\n", + "\n", + "- `epochs`: mais épocas podem levar a uma exatidão melhor, mas podem causar overfitting.\n", + "- `batch_size`: número de amostras a serem usadas em um passo de treinamento.\n", + "\n", + "Por exemplo: você pode treinar com mais épocas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rnWFaYZBG6NW" + }, + "outputs": [ + + ], + "source": [ + "model = text_classifier.create(new_train_data, model_spec=new_model_spec, epochs=20)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nUaKQZBQHBQR" + }, + "source": [ + "Avalie o modelo retreinado recentemente com 20 épocas de treinamento" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BMPi1xflHDSY" + }, + "outputs": [ + + ], + "source": [ + "new_test_data = DataLoader.from_csv(\n", + " filename='dev.csv',\n", + " text_column='sentence',\n", + " label_column='label',\n", + " model_spec=new_model_spec,\n", + " is_training=False)\n", + "\n", + "loss, accuracy = model.evaluate(new_test_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Eq6B9lKMfhS6" + }, + "source": [ + "### Altere a arquitetura do modelo\n", + "\n", + "É possível alterar o modelo mudando `model_spec`. O exemplo abaixo mostra como alterar para o modelo BERT-Base.\n", + "\n", + "Altere `model_spec` para o modelo BERT-Base para o classificador de texto." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QfFCWrwyggrT" + }, + "outputs": [ + + ], + "source": [ + "spec = model_spec.get('bert_classifier')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L2d7yycrgu6L" + }, + "source": [ + "As outras etapas são as mesmas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GgiD_tkyQn7l" + }, + "source": [ + "### Personalize a quantização pós-treinamento em um modelo do TensorFlow Lite\n", + "\n", + "A [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization) é uma técnica de conversão que pode reduzir o tamanho do modelo e a latência de inferência, além de aumentar a velocidade de inferência da CPU e do acelerador de hardware com uma pequena redução da exatidão do modelo. A quantização é amplamente utilizada para otimizar o modelo.\n", + "\n", + "A biblioteca Model Maker aplica uma técnica padrão de quantização pós-treinamento ao exportar o modelo. Se você quiser personalizar a quantização pós-treinamento, o Model Maker oferece suporte a diversas opções usando [QuantizationConfig](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/config/QuantizationConfig). Vejamos a quantização de float 16 como exemplo. Primeiro, definimos a configuração de quantização.\n", + "\n", + "```python\n", + "config = QuantizationConfig.for_float16()\n", + "```\n", + "\n", + "Em seguida, exportamos o modelo do TensorFlow Lite com essa configuração.\n", + "\n", + "```python\n", + "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qkJGvMEx6VD-" + }, + "source": [ + "# Saiba mais\n", + "\n", + "Leia o exemplo de [classificação de texto](https://www.tensorflow.org/lite/examples/text_classification/overview) para aprender os detalhes técnicos. Confira mais informações em:\n", + "\n", + "- [Guia](https://www.tensorflow.org/lite/models/modify/model_maker) e [referência da API](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker) do TensorFlow Lite Model Maker.\n", + "- Task Library: [NLClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier) e [BertNLClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/bert_nl_classifier) para implantação.\n", + "- Aplicativos de referência completos para [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/text_classification/android) e [iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/text_classification/ios)." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "text_classification.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/models/smart_reply/overview.md b/site/pt-br/lite/models/smart_reply/overview.md new file mode 100644 index 0000000000..a9fa92793b --- /dev/null +++ b/site/pt-br/lite/models/smart_reply/overview.md @@ -0,0 +1,49 @@ +# Resposta inteligente + + + +## Como começar + +Nosso modelo de resposta inteligente gera sugestões de resposta com base em mensagens de bate-papo. O objetivo é que as respostas sejam relevantes para o contexto e ajudem o usuário a responder rapidamente a uma mensagem recebida. + +Baixar modelo inicial + +### Aplicativo de exemplo + +Este é um aplicativo de exemplo do TensorFlow que demonstra o modelo de resposta inteligente no Android. + +Ver exemplo do Android + +Leia a [página no GitHub](https://github.com/tensorflow/examples/tree/master/lite/examples/smart_reply/android/) para saber como o aplicativo funciona. Dentro do projeto, você também verá como compilar um aplicativo com operações personalizadas do C++. + +## Como funciona + +O modelo gera sugestões de respostas a mensagens de conversa no bate-papo. + +O modelo para uso em dispositivos tem diversos benefícios. Ele: + +
    +
  • É rápido – o modelo fica no dispositivo e não requer uma conexão com a Internet. Portanto, a inferência é muito rápida, com uma latência média de apenas alguns milissegundos.
  • +
  • É eficiente no uso de recursos – o modelo usa uma pequena quantidade de memória do dispositivo.
  • +
  • Mantém a privacidade – os dados do usuário nunca saem do dispositivo.
  • +
+ +## Exemplo de saída + +Animation showing smart reply + +## Saiba mais + + + +## Usuários + + diff --git a/site/pt-br/lite/performance/best_practices.md b/site/pt-br/lite/performance/best_practices.md new file mode 100644 index 0000000000..957db88ab6 --- /dev/null +++ b/site/pt-br/lite/performance/best_practices.md @@ -0,0 +1,60 @@ +# Práticas recomendadas de desempenho + +Dispositivos móveis e embarcados têm recursos computacionais limitados, então é importante manter a eficiência de recursos do seu aplicativo. Reunimos uma lista de práticas recomendadas e estratégias que você pode usar para melhorar o desempenho do seu modelo do TensorFlow Lite. + +## Escolha o melhor modelo para a tarefa + +Dependendo da tarefa, você precisará fazer um trade-off entre a complexidade e o tamanho do modelo. Caso sua tarefa exija alta exatidão, talvez seja necessário um modelo maior e complexo. Para tarefas que exigem menos exatidão, é melhor usar um modelo menor, já que ocupa menos espaço em disco e memória, além de ser mais rápido e ter mais eficiência energética. Por exemplo, os grafos abaixo mostram trade-offs de exatidão e latência para alguns modelos comuns de classificação de imagens. + +![Grafo de tamanho x precisão do modelo](../images/performance/model_size_vs_accuracy.png "Model Size vs Accuracy") + +![Grafo de exatidão x latência](../images/performance/accuracy_vs_latency.png "Accuracy vs Latency") + +Um exemplo de modelo otimizado para dispositivos móveis são os [MobileNets](https://arxiv.org/abs/1704.04861), específicos para aplicativos de visão. O [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite) lista vários outros modelos que foram otimizados especialmente para dispositivos móveis e embarcados. + +Você pode treinar novamente os modelos listados com seu próprio dataset ao usar o aprendizado por transferência. Confira os tutoriais de aprendizado por transferência usando o [Model Maker](../models/modify/model_maker/) do TensorFlow Lite. + +## Analise o perfil do seu modelo + +Depois de selecionar uma opção de modelo ideal para sua tarefa, é recomendável analisar o perfil e fazer o benchmarking do modelo. A [ferramenta de benchmarking](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark) do TensorFlow Lite tem um profiler integrado que mostra estatísticas de profiling por operador. Isso pode ajudar a entender gargalos de desempenho e saber quais operadores dominam o tempo computacional. + +Você também pode usar o [tracing do TensorFlow Lite](measurement#trace_tensorflow_lite_internals_in_android) para analisar o perfil do modelo no seu aplicativo Android, com o tracing do sistema Android padrão, e para visualizar as invocações de operador por tempo com ferramentas de profiling baseadas na GUI. + +## Otimize operadores após analisar o perfil deles no grafo + +Se um operador específico aparecer com frequência no modelo e, com base no profiling, você achar que esse operador consome a maior parte do tempo, considere otimizá-lo. Essa situação deve ser rara, porque o TensorFlow Lite tem versões otimizadas para a maioria dos operadores. No entanto, talvez você consiga escrever uma versão mais rápida de uma operação personalizada se souber as restrições da execução do operador. Consulte o [guia de operadores personalizados](../guide/ops_custom). + +## Otimize seu modelo + +A otimização do modelo visa criar modelos menores, que geralmente são mais rápidos e têm mais eficiência energética, para que sejam implantados em dispositivos móveis. O TensorFlow Lite é compatível com várias técnicas de otimização, como quantização. + +Confira mais detalhes na [documentação sobre a otimização de modelo](model_optimization). + +## Ajuste o número de threads + +O TensorFlow Lite aceita kernels de vários threads para vários operadores. Você pode aumentar o número de threads e acelerar a execução dos operadores. No entanto, ao aumentar o número de threads, o modelo usará mais recursos e energia. + +Para alguns aplicativos, a latência pode ser mais importante do que a eficiência energética. Você pode aumentar o número de threads ao configurar o número de [threads](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/interpreter.h#L346) do interpretador. Porém, a desvantagem da execução de vários threads é que ela aumenta a variabilidade do desempenho dependendo do que está sendo executado ao mesmo tempo. Esse é o caso especialmente para aplicativos móveis. Por exemplo, testes isolados podem mostrar o dobro de velocidade em comparação com um único thread, mas, se outro aplicativo estiver sendo executado simultaneamente, pode resultar em um desempenho inferior a um único thread. + +## Elimine cópias redundantes + +Se o seu aplicativo não for projetado com cuidado, pode haver cópias redundantes ao alimentar a entrada e ler a saída do modelo. Não deixe de eliminar as cópias redundantes. Se você estiver usando APIs de nível superior, como Java, verifique cuidadosamente as ressalvas de desempenho na documentação. Por exemplo, a API Java é muito mais rápida ao usar `ByteBuffers` como [entradas](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/java/src/main/java/org/tensorflow/lite/Interpreter.java#L175). + +## Analise o perfil do seu aplicativo com ferramentas da plataforma + +As ferramentas específicas da plataforma, como [Android profiler](https://developer.android.com/studio/profile/android-profiler) e [Instruments](https://help.apple.com/instruments/mac/current/), fornecem uma abundância de informações de profiling que podem ser usadas para depurar seu aplicativo. Às vezes, o bug de desempenho pode não estar no modelo, e sim em partes do código do aplicativo que interagem com o modelo. Familiarize-se com as ferramentas de profiling específicas e as práticas recomendadas para sua plataforma. + +## Avalie se o modelo pode obter proveito de aceleradores de hardware disponíveis no dispositivo + +O TensorFlow Lite adicionou novas maneiras de acelerar modelos com hardware mais rápido, como GPUs, DSPs e aceleradores neurais. Geralmente, esses aceleradores são expostos por submódulos de [delegados](delegates) que assumem partes da execução do interpretador. O TensorFlow Lite pode usar delegados: + +- Ao utilizar a [API Neural Networks](https://developer.android.com/ndk/guides/neuralnetworks/) do Android. Você pode usar esses back-ends de acelerador de hardware para melhorar a velocidade e eficiência do seu modelo. Para habilitar a API Neural Networks, consulte o guia [delegado NNAPI](https://www.tensorflow.org/lite/android/delegates/nnapi). +- O delegado de GPU está disponível no Android e no iOS, usando OpenGL/OpenCL e Metal, respectivamente. Para testar, confira o [tutorial](gpu) e a [documentação sobre o delegado de GPU](gpu_advanced). +- O delegado Hexagon está disponível no Android. Ele aproveita o DSP Qualcomm Hexagon, caso esteja disponível no dispositivo. Veja mais informações no [tutorial do delegado Hexagon](https://www.tensorflow.org/lite/android/delegates/hexagon). +- É possível criar seu próprio delegado se você tiver acesso a hardware não padrão. Saiba mais em [delegados do TensorFlow Lite](delegates). + +Tenha em mente que alguns aceleradores funcionam melhor para diferentes tipos de modelos. Alguns delegados só aceitam modelos float ou otimizados de maneira específica. É importante fazer o [benchmarking](measurement) de cada delegado para ver se é uma boa escolha para seu aplicativo. Por exemplo, se você tiver um modelo muito pequeno, pode não valer a pena delegar o modelo à API NN ou GPU. Por outro lado, os aceleradores são uma ótima opção para modelos grandes com uma alta intensidade aritmética. + +## Precisa de mais ajuda? + +A equipe do TensorFlow fica feliz em ajudar a diagnosticar e resolver os problemas específicos de desempenho que você estiver enfrentando. Crie um issue no [GitHub](https://github.com/tensorflow/tensorflow/issues) com detalhes sobre o problema. diff --git a/site/pt-br/lite/performance/coreml_delegate.md b/site/pt-br/lite/performance/coreml_delegate.md new file mode 100644 index 0000000000..d70c2ae116 --- /dev/null +++ b/site/pt-br/lite/performance/coreml_delegate.md @@ -0,0 +1,275 @@ +# Delegado Core ML do TensorFlow Lite + +O delegado Core ML do TensorFlow Lite permite executar os modelos do TensorFlow Lite no [framework Core ML](https://developer.apple.com/documentation/coreml), o que resulta em uma inferência de modelo mais rápida em dispositivos iOS. + +Observação: esse delegado está em fase experimental (beta). Ele está disponível a partir do TensorFlow Lite 2.4.0 e nas versões noturnas mais recentes. + +Observação: o delegado Core ML é compatível com a versão 2 ou mais recente do Core ML. + +**Versões e dispositivos iOS compatíveis:** + +- iOS 12 e mais recente. Nas versões mais antigas do iOS, o delegado Core ML usará automaticamente a CPU. +- Por padrão, o delegado Core ML só é ativado em dispositivos com SoC A12 e mais recente (a partir do iPhone Xs) para usar o Neural Engine para uma inferência mais rápida. Se você também quiser usar o delegado Core ML em dispositivos mais antigos, veja as [práticas recomendadas](#best-practices). + +**Modelos compatíveis** + +No momento, o delegado Core ML é compatível com modelos float (FP32 e FP16). + +## Teste o delegado Core ML no seu próprio modelo + +O delegado Core ML já está incluso na versão noturna do TensorFlow Lite CocoaPods. Para usar o delegado Core ML, altere seu pod do TensorFlow Lite para incluir a subspec `CoreML` no seu `Podfile`. + +Observação: se você quiser usar a API C em vez da API Objective-C, é possível incluir o pod `TensorFlowLiteC/CoreML` para fazer isso. + +``` +target 'YourProjectName' + pod 'TensorFlowLiteSwift/CoreML', '~> 2.4.0' # Or TensorFlowLiteObjC/CoreML +``` + +OU + +``` +# Particularily useful when you also want to include 'Metal' subspec. +target 'YourProjectName' + pod 'TensorFlowLiteSwift', '~> 2.4.0', :subspecs => ['CoreML'] +``` + +Observação: o delegado Core ML também pode usar a API C para código da Objective-C. Antes da versão 2.4.0 do TensorFlow Lite, essa era a única opção. + +
+ +
+

Swift

+

+
+    let coreMLDelegate = CoreMLDelegate()
+    var interpreter: Interpreter
+
+    // Core ML delegate will only be created for devices with Neural Engine
+    if coreMLDelegate != nil {
+      interpreter = try Interpreter(modelPath: modelPath,
+                                    delegates: [coreMLDelegate!])
+    } else {
+      interpreter = try Interpreter(modelPath: modelPath)
+    }
+  
+
+
+

Objective-C

+

+
+
+    // Import module when using CocoaPods with module support
+    @import TFLTensorFlowLite;
+
+    // Or import following headers manually
+    # import "tensorflow/lite/objc/apis/TFLCoreMLDelegate.h"
+    # import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h"
+
+    // Initialize Core ML delegate
+    TFLCoreMLDelegate* coreMLDelegate = [[TFLCoreMLDelegate alloc] init];
+
+    // Initialize interpreter with model path and Core ML delegate
+    TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init];
+    NSError* error = nil;
+    TFLInterpreter* interpreter = [[TFLInterpreter alloc]
+                                    initWithModelPath:modelPath
+                                              options:options
+                                            delegates:@[ coreMLDelegate ]
+                                                error:&error];
+    if (error != nil) { /* Error handling... */ }
+
+    if (![interpreter allocateTensorsWithError:&error]) { /* Error handling... */ }
+    if (error != nil) { /* Error handling... */ }
+
+    // Run inference ...
+  
+
+
+

C (até 2.3.0)

+

+
+    #include "tensorflow/lite/delegates/coreml/coreml_delegate.h"
+
+    // Initialize interpreter with model
+    TfLiteModel* model = TfLiteModelCreateFromFile(model_path);
+
+    // Initialize interpreter with Core ML delegate
+    TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
+    TfLiteDelegate* delegate = TfLiteCoreMlDelegateCreate(NULL);  // default config
+    TfLiteInterpreterOptionsAddDelegate(options, delegate);
+    TfLiteInterpreterOptionsDelete(options);
+
+    TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
+
+    TfLiteInterpreterAllocateTensors(interpreter);
+
+    // Run inference ...
+
+    /* ... */
+
+    // Dispose resources when it is no longer used.
+    // Add following code to the section where you dispose of the delegate
+    // (e.g. `dealloc` of class).
+
+    TfLiteInterpreterDelete(interpreter);
+    TfLiteCoreMlDelegateDelete(delegate);
+    TfLiteModelDelete(model);
+      
+
+
+
+ +## Práticas recomendadas + +### Use o delegado Core ML em dispositivos sem Neural Engine + +Por padrão, o delegado Core ML só será criado se o dispositivo tiver Neural Engine, e ele retornará `null` se o delegado não for criado. Se você quiser executar o delegado Core ML em outros ambientes (por exemplo, simulador), passe `.all` como uma opção ao criar o delegado em Swift. Em C++ (e Objective-C). Você pode passar `TfLiteCoreMlDelegateAllDevices`. O exemplo a seguir mostra como fazer isso: + +
+ +
+

Swift

+

+
+    var options = CoreMLDelegate.Options()
+    options.enabledDevices = .all
+    let coreMLDelegate = CoreMLDelegate(options: options)!
+    let interpreter = try Interpreter(modelPath: modelPath,
+                                      delegates: [coreMLDelegate])
+      
+
+
+

Objective-C

+

+
+    TFLCoreMLDelegateOptions* coreMLOptions = [[TFLCoreMLDelegateOptions alloc] init];
+    coreMLOptions.enabledDevices = TFLCoreMLDelegateEnabledDevicesAll;
+    TFLCoreMLDelegate* coreMLDelegate = [[TFLCoreMLDelegate alloc]
+                                          initWithOptions:coreMLOptions];
+
+    // Initialize interpreter with delegate
+  
+
+
+

C

+

+
+    TfLiteCoreMlDelegateOptions options;
+    options.enabled_devices = TfLiteCoreMlDelegateAllDevices;
+    TfLiteDelegate* delegate = TfLiteCoreMlDelegateCreate(&options);
+    // Initialize interpreter with delegate
+      
+
+
+
+ +### Use o delegado Metal (GPU) como fallback + +Quando o delegado Core ML não for criado, como alternativa, você ainda poderá usar o [delegado Metal](https://www.tensorflow.org/lite/performance/gpu#ios) para melhorar o desempenho. O exemplo a seguir mostra como fazer isso: + +
+ +
+

Swift

+

+
+    var delegate = CoreMLDelegate()
+    if delegate == nil {
+      delegate = MetalDelegate()  // Add Metal delegate options if necessary.
+    }
+
+    let interpreter = try Interpreter(modelPath: modelPath,
+                                      delegates: [delegate!])
+  
+
+
+

Objective-C

+

+
+    TFLDelegate* delegate = [[TFLCoreMLDelegate alloc] init];
+    if (!delegate) {
+      // Add Metal delegate options if necessary
+      delegate = [[TFLMetalDelegate alloc] init];
+    }
+    // Initialize interpreter with delegate
+      
+
+
+

C

+

+
+    TfLiteCoreMlDelegateOptions options = {};
+    delegate = TfLiteCoreMlDelegateCreate(&options);
+    if (delegate == NULL) {
+      // Add Metal delegate options if necessary
+      delegate = TFLGpuDelegateCreate(NULL);
+    }
+    // Initialize interpreter with delegate
+      
+
+
+
+ +A lógica de criação de delegado lê o id da máquina do dispositivo (por exemplo, iPhone11,1) para determinar a disponibilidade do Neural Engine. Veja mais detalhes no [código](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/coreml/coreml_delegate.mm). Como alternativa, você pode implementar seu próprio conjunto de dispositivos bloqueados usando outras bibliotecas como [DeviceKit](https://github.com/devicekit/DeviceKit). + +### Use uma versão mais antiga do Core ML + +Embora o iOS 13 seja compatível com o Core ML 3, o modelo pode funcionar melhor quando convertido com a especificação de modelo do Core ML 2. A versão de destino da conversão é definida como a mais recente por padrão, mas você pode alterar isso ao definir `coreMLVersion` (em Swift, `coreml_version` na API C) na opção de delegado como uma versão mais antiga. + +## Ops compatíveis + +As seguintes ops são compatíveis com o delegado Core ML. + +- Add + - Somente determinados formatos podem fazer o broadcasting. No layout de tensor do Core ML, os seguintes formatos de tensor podem fazer o broadcasting: `[B, C, H, W]`, `[B, C, 1, 1]`, `[B, 1, H, W]`, `[B, 1, 1, 1]`. +- AveragePool2D +- Concat + - A concatenação deve ser feita ao longo do eixo do canal. +- Conv2D + - Os pesos e bias devem ser constantes. +- DepthwiseConv2D + - Os pesos e bias devem ser constantes. +- FullyConnected (também conhecida como Dense ou InnerProduct) + - Os pesos e bias (se presentes) devem ser constantes. + - Só aceita casos de um único lote. As dimensões de entrada devem ser 1, exceto para a última dimensão. +- Hardswish +- Logistic (também conhecida como Sigmoid) +- MaxPool2D +- MirrorPad + - Só aceita uma entrada 4D com o modo `REFLECT`. O preenchimento deve ser constante e é permitido somente para dimensões H e W. +- Mul + - Somente determinados formatos podem fazer o broadcasting. No layout de tensor do Core ML, os seguintes formatos de tensor podem fazer o broadcasting: `[B, C, H, W]`, `[B, C, 1, 1]`, `[B, 1, H, W]`, `[B, 1, 1, 1]`. +- Pad e PadV2 + - Só aceita uma entrada 4D. O preenchimento deve ser constante e é permitido somente para dimensões H e W. +- Relu +- ReluN1To1 +- Relu6 +- Reshape + - Só é compatível se a versão Core ML de destino for 2, e não ao segmentar o Core ML 3. +- ResizeBilinear +- SoftMax +- Tanh +- TransposeConv + - Os pesos devem ser constantes. + +## Feedback + +Em caso de problemas, crie um issue do [GitHub](https://github.com/tensorflow/tensorflow/issues/new?template=50-other-issues.md) com todos os detalhes necessários para reprodução. + +## Perguntas frequentes + +- O delegado Core ML aceita fallback de CPU se um grafo contiver ops incompatíveis? + - Sim. +- O delegado Core ML funciona no Simulador de iOS? + - Sim. A biblioteca inclui destinos x86 e x86_64 para que possa ser executada em um simulador, mas você não verá melhoria no desempenho pela CPU. +- O TensorFlow Lite e o delegado Core ML são compatíveis com o MacOS? + - O TensorFlow Lite só foi testado no iOS, não no MacOS. +- São compatíveis ops do TF Lite personalizadas? + - Não, o delegado Core ML não é compatível com ops personalizadas e será usada a CPU. + +## APIs + +- [API Swift do delegado Core ML](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/swift/Sources/CoreMLDelegate.swift) +- [API C do delegado Core ML](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/coreml/coreml_delegate.h) + - Pode ser usada para códigos Objective-C. ~~~ diff --git a/site/pt-br/lite/performance/delegates.md b/site/pt-br/lite/performance/delegates.md new file mode 100644 index 0000000000..f959a8c90d --- /dev/null +++ b/site/pt-br/lite/performance/delegates.md @@ -0,0 +1,140 @@ +# Delegados do TensorFlow Lite + +## Introdução + +Os **delegados** permitem a aceleração de hardware de modelos do TensorFlow Lite ao usar aceleradores no dispositivo, como GPU e [Processador de Sinal Digital (DSP)](https://en.wikipedia.org/wiki/Digital_signal_processor). + +Por padrão, o TensorFlow Lite usa kernels de CPU otimizados para o conjunto de instruções [ARM Neon](https://developer.arm.com/documentation/dht0002/a/Introducing-NEON/NEON-architecture-overview/NEON-instructions). No entanto, a CPU é um processador multiuso que não é necessariamente otimizado para a aritmética pesada geralmente encontrada em modelos de aprendizado de máquina (por exemplo, a matemática de matriz envolvida em camadas densas e de convolução). + +Por outro lado, a maioria dos smartphones modernos contém chips que lidam melhor com essas operações pesadas. Utilizá-los para as operações de redes neurais oferece grandes benefícios em termos de latência e eficiência energética. Por exemplo, as GPUs podem fornecer até [5x mais velocidade](https://blog.tensorflow.org/2020/08/faster-mobile-gpu-inference-with-opencl.html) na latência, enquanto o [DSP Qualcomm® Hexagon](https://developer.qualcomm.com/software/hexagon-dsp-sdk/dsp-processor) reduziu o consumo de energia em até 75% em nossos experimentos. + +Cada um desses aceleradores tem APIs associadas que permitem computações personalizadas, como [OpenCL](https://www.khronos.org/opencl/) ou [OpenGL ES](https://www.khronos.org/opengles/) para GPU móvel e [SDK Qualcomm® Hexagon](https://developer.qualcomm.com/software/hexagon-dsp-sdk) para DSP. Normalmente, você precisaria escrever muito código personalizado para executar uma rede neural por essas interfaces. As coisas se complicam ainda mais quando você considera que cada acelerador tem prós e contras e não pode executar todas as operações em uma rede neural. A API Delegate do TensorFlow Lite resolve esse problema ao servir como uma ponte entre o runtime do TFLite e essas APIs de nível inferior. + +![runtime com delegados](images/delegate_runtime.png) + +## Escolha um delegado + +O TensorFlow Lite é compatível com vários delegados, sendo que cada um é otimizado para determinadas plataformas e tipos específicos de modelos. Geralmente, há vários delegados aplicáveis ao seu caso de uso, dependendo de dois critérios principais: a *Plataforma* (Android ou iOS?) segmentada e o *Tipo de modelo* (ponto flutuante ou quantizado?) que você está tentando acelerar. + +### Delegados por plataforma + +#### Multiplataforma (Android e iOS) + +- **Delegado de GPU**: pode ser usado em ambos o Android e o iOS. É otimizado para executar modelos baseados em float de 32 e 16 bits com uma GPU disponível. Também é compatível com modelos quantizados de 8 bits e fornece um desempenho de GPU equivalente às versões de float. Para mais detalhes sobre o delegado de GPU, confira [TensorFlow Lite na GPU](gpu_advanced.md). Para tutoriais passo a passo sobre como usar o delegado de GPU com o Android e o iOS, confira o [Tutorial do delegado de GPU do TensorFlow Lite](gpu.md). + +#### Android + +- **Delegado NNAPI para dispositivos Android mais recentes**: pode ser usado para acelerar modelos em dispositivos Android com GPU, DSP e/ou NPU disponível. Está disponível no Android 8.1 (API 27+) ou mais recente. Para uma visão geral do delegado NNAPI, instruções passo a passo e práticas recomendadas, confira [delegado NNAPI do TensorFlow Lite](nnapi.md). +- **Delegado Hexagon para dispositivos Android mais antigos**: o delegado Hexagon pode ser usado para acelerar modelos em dispositivos Android com o DSP Qualcomm Hexagon. Ele pode ser usado em dispositivos com versões mais antigas do Android que não são compatíveis com a NNAPI. Confira mais detalhes em [delegado Hexagon do TensorFlow Lite](hexagon_delegate.md). + +#### iOS + +- **Delegado Core ML para iPhones e iPads mais recentes**: para iPhones e iPads mais recentes em que o Neural Engine estiver disponível, você pode usar o delegado Core para acelerar a inferência para modelos de ponto flutuante de 32 ou 16 bits. O Neural Engine está disponível em dispositivos móveis Apple com SoC A12 e mais recente. Para uma visão geral do delegado Core ML e instruções passo a passo, confira [delegado Core ML do TensorFlow Lite](coreml_delegate.md). + +### Delegados por tipo de modelo + +Cada acelerador é criado com uma determinada largura de bits de dados em mente. Se você fornecer um modelo de ponto flutuante a um delegado que só é compatível com operações quantizadas de 8 bits (como o [delegado Hexagon](hexagon_delegate.md)), ele rejeitará todas as operações, e o modelo será executado totalmente na CPU. Para evitar surpresas, a tabela abaixo oferece uma visão geral da compatibilidade de delegados com base no tipo de modelo: + +**Tipo de modelo** | **GPU** | **NNAPI** | **Hexagon** | **Core ML** +--- | --- | --- | --- | --- +Ponto flutuante (32 bits) | Sim | Sim | Não | Sim +[Quantização float16 pós-treinamento](post_training_float16_quant.ipynb) | Sim | Não | Não | Sim +[Quantização de intervalo dinâmico pós-treinamento](post_training_quant.ipynb) | Sim | Sim | Não | Não +[Quantização de números inteiros pós-treinamento](post_training_integer_quant.ipynb) | Sim | Sim | Sim | Não +[Treinamento consciente de quantização](http://www.tensorflow.org/model_optimization/guide/quantization/training) | Sim | Sim | Sim | Não + +### Valide o desempenho + +As informações nesta seção servem como uma diretriz aproximada para selecionar os delegados que podem melhorar seu aplicativo. Porém, é importante observar que cada delegado tem um conjunto predefinido de operações compatíveis e pode apresentar desempenhos diferentes dependendo do modelo e dispositivo. Por exemplo, o [delegado NNAPI](nnapi.md) pode escolher usar o Edge-TPU do Google em um smartphone Pixel e utilizar o DSP em outro dispositivo. Portanto, é geralmente recomendável realizar benchmarking para avaliar a utilidade de um delegado para suas necessidades. Isso também ajuda a justificar o aumento no tamanho do binário associado à atribuição de um delegado ao runtime do TensorFlow Lite. + +O TensorFlow Lite tem vastas ferramentas de avaliação do desempenho e da exatidão que podem dar confiança aos desenvolvedores para usar os delegados nos seus aplicativos. Essas ferramentas são abordadas na próxima seção. + +## Ferramentas para avaliação + +### Latência e consumo de memória + +A [ferramenta de benchmarking](https://www.tensorflow.org/lite/performance/measurement) do TensorFlow Lite pode ser usada com parâmetros adequados para estimar o desempenho do modelo, incluindo a latência de inferência média, a sobrecarga de inicialização, o consumo de memória etc. Essa ferramenta é compatível com várias flags para encontrar a melhor configuração de delegado para seu modelo. Por exemplo, `--gpu_backend=gl` pode ser especificado com `--use_gpu` para medir a execução de GPU com o OpenGL. A lista completa de parâmetros de delegados compatíveis está definida na [documentação detalhada](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/delegates/README.md#tflite-delegate-registrar). + +Confira um exemplo de execução para um modelo quantizado com GPU por `adb`: + +``` +adb shell /data/local/tmp/benchmark_model \ + --graph=/data/local/tmp/mobilenet_v1_224_quant.tflite \ + --use_gpu=true +``` + +Você pode baixar a versão pré-criada dessa ferramenta para a arquitetura ARM de 64 bits do Android [aqui](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model.apk) ([mais detalhes](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/android)). + +### Exatidão e precisão + +Os delegados geralmente realizam computações com uma precisão diferente do que a CPU. Como resultado, há um trade-off de exatidão (geralmente pequeno) associado ao uso de um delegado para a aceleração de hardware. Observe que isso *nem sempre* é verdade. Por exemplo, como a GPU usa a precisão de ponto flutuante para executar modelos quantizados, pode haver uma leve melhoria na precisão (por exemplo, melhoria top-5 de <1% na classificação de imagens ILSVRC). + +O TensorFlow Lite tem dois tipos de ferramentas para avaliar a exatidão do comportamento de um delegado para um modelo específico: *baseada na tarefa* e *agnóstica à tarefa*. Todas as ferramentas descritas nesta seção aceitam os [parâmetros de delegação avançados](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/delegates/README.md#tflite-delegate-registrar) usados pela ferramenta de benchmarking na seção anterior. Observe que as subseções abaixo focam na *avaliação do delegado* (o delegado tem o mesmo desempenho que a CPU?), e não na avaliação do modelo (o próprio modelo é bom para a tarefa?). + +#### Avaliação baseada na tarefa + +O TensorFlow Lite tem ferramentas para avaliar a exatidão de duas tarefas baseadas em imagens: + +- [ILSVRC 2012](http://image-net.org/challenges/LSVRC/2012/) (classificação de imagens) com [exatidão top-K](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Precision_at_K) + +- [Detecção de objetos COCO (com caixas delimitadoras)](https://cocodataset.org/#detection-2020) com [mean Average Precision (mAP)](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Mean_average_precision) + +Binários pré-criados dessas ferramentas (arquitetura ARM de 64 bits do Android), além de documentação, podem ser encontrados aqui: + +- [Classificação de imagens ImageNet](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_eval_imagenet_image_classification) ([mais detalhes](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification)) +- [Detecção de objetos COCO](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_eval_coco_object_detection) ([mais detalhes](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks/coco_object_detection)) + +O exemplo abaixo demonstra a [avaliação da classificação de imagens](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification) com NNAPI utilizando o Edge-TPU do Google em um Pixel 4: + +``` +adb shell /data/local/tmp/run_eval \ + --model_file=/data/local/tmp/mobilenet_quant_v1_224.tflite \ + --ground_truth_images_path=/data/local/tmp/ilsvrc_images \ + --ground_truth_labels=/data/local/tmp/ilsvrc_validation_labels.txt \ + --model_output_labels=/data/local/tmp/model_output_labels.txt \ + --output_file_path=/data/local/tmp/accuracy_output.txt \ + --num_images=0 # Run on all images. \ + --use_nnapi=true \ + --nnapi_accelerator_name=google-edgetpu +``` + +A saída esperada é uma lista de métricas top-K de 1 a 10: + +``` +Top-1 Accuracy: 0.733333 +Top-2 Accuracy: 0.826667 +Top-3 Accuracy: 0.856667 +Top-4 Accuracy: 0.87 +Top-5 Accuracy: 0.89 +Top-6 Accuracy: 0.903333 +Top-7 Accuracy: 0.906667 +Top-8 Accuracy: 0.913333 +Top-9 Accuracy: 0.92 +Top-10 Accuracy: 0.923333 +``` + +#### Avaliação agnóstica à tarefa + +Para as tarefas em que não há uma ferramenta de avaliação no dispositivo estabelecida, ou se você estiver testando modelos personalizados, o TensorFlow Lite tem a ferramenta [Diff da inferência](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks/inference_diff) (binário da arquitetura ARM de 64 bits do Android [aqui](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_eval_inference_diff)). + +A Diff da inferência compara a execução do TensorFlow Lite (em termos de desvio do valor de saída e latência) em duas configurações: + +- Inferência de CPU de thread único +- Inferência definida pelo usuário: definida por [estes parâmetros](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/delegates/README.md#tflite-delegate-registrar) + +Para fazer isso, a ferramenta gera dados gaussianos aleatórios, que são passados por dois interpretadores do TFLite: um que executa kernels de CPU de thread único e outro que é parametrizado pelos argumentos do usuário. + +Ela mede a latência de ambos, além da diferença absoluta entre os tensores de saída de cada interpretador, com base em cada elemento. + +Para um modelo com um único tensor de saída, o resultado será algo assim: + +``` +Num evaluation runs: 50 +Reference run latency: avg=84364.2(us), std_dev=12525(us) +Test run latency: avg=7281.64(us), std_dev=2089(us) +OutputDiff[0]: avg_error=1.96277e-05, std_dev=6.95767e-06 +``` + +Isso significa que, para o tensor de saída no índice `0`, os elementos da saída da CPU diferem da saída do delegado em uma média de `1.96e-05`. + +Observe que a interpretação desses números exige conhecimento mais aprofundado sobre o modelo e o significado de cada tensor de saída. Se uma regressão simples determinar algum tipo de pontuação ou embedding, a diferença deve ser baixa (caso contrário, é um erro com o delegado). No entanto, saídas como a "classe de detecção" de modelos SSD são um pouco mais difíceis de interpretar. Por exemplo, ao usar essa ferramenta, pode indicar uma diferença, mas isso não significa necessariamente que há algo muito errado com o delegado: considere duas classes (falsas): "TV (ID: 10)" e "Monitor (ID: 20)" — se um delegado estiver um pouco fora da verdade absoluta e mostrar "monitor" em vez de "TV", a diferença da saída para esse tensor pode ser de até 20-10 = 10. diff --git a/site/pt-br/lite/performance/gpu.md b/site/pt-br/lite/performance/gpu.md new file mode 100644 index 0000000000..776ff34032 --- /dev/null +++ b/site/pt-br/lite/performance/gpu.md @@ -0,0 +1,139 @@ +# Delegados de GPU para o TensorFlow Lite + +Usar unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho do seu modelo e a experiência do usuário dos seus aplicativos com ML. O TensorFlow Lite permite o uso de GPUs e outros processadores especializados pelo driver de hardware chamados [*delegados*](./delegates). O uso de GPUs com seus aplicativos de ML do TensorFlow Lite pode oferecer os seguintes benefícios: + +- **Velocidade**: as GPUs são criadas para o alto desempenho de workloads maciçamente paralelas. Esse design faz com que sejam adequadas para redes neurais profundas, que consistem em um grande número de operadores, cada um trabalhando em tensores de entrada que podem ser processados em paralelo, o que geralmente resulta em menor latência. No melhor dos casos, a execução do seu modelo em uma GPU pode ser rápida o suficiente para permitir aplicativos em tempo real que antes não eram possíveis. +- **Eficiência energética**: as GPUs podem realizar computações de ML de maneira bastante eficiente e otimizada, geralmente consumindo menos energia e gerando menos calor do que a mesma tarefa executada em CPUs. + +Este documento fornece uma visão geral da compatibilidade com GPUs no TensorFlow Lite e alguns usos avançados para os processadores de GPU. Para informações mais específicas sobre como implementar o suporte à GPU em plataformas específicas, veja os seguintes guias: + +- [Suporte à GPU para Android](../android/delegates/gpu) +- [Suporte à GPU para iOS](../ios/delegates/gpu) + +## Suporte a operações de ML de GPU {:#supported_ops} + +Há algumas limitações em relação às operações de ML do TensorFlow, *ops*, que podem ser aceleradas pelo delegado de GPU do TensorFlow Lite. O delegado é compatível com as seguintes ops na precisão de float de 16 e 32 bits: + +- `ADD` +- `AVERAGE_POOL_2D` +- `CONCATENATION` +- `CONV_2D` +- `DEPTHWISE_CONV_2D v1-2` +- `EXP` +- `FULLY_CONNECTED` +- `LOGICAL_AND` +- `LOGISTIC` +- `LSTM v2 (Basic LSTM only)` +- `MAX_POOL_2D` +- `MAXIMUM` +- `MINIMUM` +- `MUL` +- `PAD` +- `PRELU` +- `RELU` +- `RELU6` +- `RESHAPE` +- `RESIZE_BILINEAR v1-3` +- `SOFTMAX` +- `STRIDED_SLICE` +- `SUB` +- `TRANSPOSE_CONV` + +Por padrão, todas as ops só são compatíveis com a versão 1. Ao habilitar o [suporte à quantização](#quantized-models), são permitidas as versões apropriadas, por exemplo, ADD v2. + +### Solução de problemas de suporte à GPU + +Se algumas das ops não forem compatíveis com o delegado de GPU, o framework só executará uma parte do grafo na GPU e o restante na CPU. Devido ao alto custo da sincronização de CPU/GPU, um modo de execução dividida como esse geralmente resulta em um desempenho inferior em relação à execução da rede inteira só na CPU. Nesse caso, o aplicativo gera um aviso, como este: + +```none +WARNING: op code #42 cannot be handled by this delegate. +``` + +Não há callback para falhas desse tipo, já que não é uma falha de runtime real. Ao testar a execução do seu modelo com o delegado de GPU, você deve ficar alerta a esses avisos. Um grande número de avisos assim pode indicar que o seu modelo não é o mais adequado para uso com a aceleração de GPU e talvez exija a refatoração do modelo. + +## Modelos de exemplo + +Os seguintes modelos de exemplo foram criados para aproveitar a aceleração de GPU com o TensorFlow Lite e são fornecidos para referência e testes: + +- [Classificação de imagens MobileNet v1 (224x224)](https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html): um modelo de classificação de imagens criado para aplicativos de visão baseados em dispositivos móveis e embarcados. ([modelo](https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/5)) +- [Segmentação DeepLab (257x257)](https://ai.googleblog.com/2018/03/semantic-image-segmentation-with.html): modelo de segmentação de imagens que atribui rótulos semânticos, como cachorro, gato e carro, a todos os pixels na imagem de entrada. ([modelo](https://tfhub.dev/tensorflow/lite-model/deeplabv3/1/default/1)) +- [Detecção de objetos MobileNet SSD](https://ai.googleblog.com/2018/07/accelerated-training-and-inference-with.html): um modelo de classificação de imagens que detecta vários objetos com caixas delimitadoras. ([modelo](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobile_ssd_v2_float_coco.tflite)) +- [PoseNet para a estimativa de pose](https://github.com/tensorflow/tfjs-models/tree/master/pose-detection): um modelo de visão que estima as poses de pessoas em imagens ou vídeos. ([modelo](https://tfhub.dev/tensorflow/lite-model/posenet/mobilenet/float/075/1/default/1)) + +## Otimização para GPUs + +As seguintes técnicas podem ajudar você a obter o melhor desempenho ao executar modelos em hardware de GPU usando o delegado de GPU do TensorFlow Lite: + +- **Operações de reformulação**: algumas operações que são rápidas em uma CPU podem ter um alto custo para a GPU em dispositivos móveis. As operações de reformulação são especialmente caras para executar, incluindo `BATCH_TO_SPACE`, `SPACE_TO_BATCH`, `SPACE_TO_DEPTH` e assim por diante. Você deve examinar com cuidado o uso dessas operações e considerar que só devem ser aplicadas para a exploração de dados ou para iterações iniciais do seu modelo. A remoção delas pode melhorar significativamente o desempenho. + +- **Canais de dados de imagens**: na GPU, os dados de tensor são divididos em 4 canais. Portanto, uma computação em um tensor de formato `[B,H,W,5]` tem praticamente o mesmo desempenho em um tensor de formato `[B,H,W,8]`, mas um desempenho significativamente inferior em `[B,H,W,4]`. Se o hardware da câmera que você estiver usando for compatível com frames de imagens em RGBA, é muito mais rápido alimentar essa entrada de 4 canais, já que evita uma cópia na memória do RGB de 3 canais para o RGBX de 4 canais. + +- **Modelos otimizados para dispositivos móveis**: para melhor desempenho, considere treinar novamente seu classificador com uma arquitetura de rede otimizada para dispositivos móveis. A otimização para a inferência no dispositivo pode reduzir consideravelmente a latência e o consumo de energia ao aproveitar recursos de hardware de dispositivos móveis. + +## Suporte à GPU avançado + +Você pode usar técnicas adicionais avançadas com processamento de GPU para melhorar ainda mais o desempenho dos seus modelos, incluindo a quantização e serialização. As seguintes seções descrevem essas técnicas em mais detalhes. + +### Usando modelos quantizados {:#quantized-models} + +Esta seção explica como o delegado de GPU acelera modelos quantizados de 8 bits, incluindo o seguinte: + +- Modelos treinados com o [treinamento consciente de quantização](https://www.tensorflow.org/model_optimization/guide/quantization/training) +- [Quantização de intervalo dinâmico](https://www.tensorflow.org/lite/performance/post_training_quant) pós-treinamento +- [Quantização de números inteiros](https://www.tensorflow.org/lite/performance/post_training_integer_quant) pós-treinamento + +Para otimizar o desempenho, use modelos com tensores de saída e entrada de ponto flutuante. + +#### Como isso funciona? + +Como o back-end da GPU só aceita a execução de ponto flutuante, executamos modelos quantizados ao dar uma "visão de ponto flutuante" do modelo original. Em um nível superior, isso envolve os seguintes passos: + +- Os *tensores constantes* (como pesos/biases) são desquantizados uma vez na memória de GPU. Essa operação acontece quando o delegado é ativado para o TensorFlow Lite. + +- As *entradas e saídas* do programa de GPU, se forem quantizadas de 8 bits, são desquantizadas e quantizadas (respectivamente) para cada inferência. Essa operação é realizada na CPU usando os kernels otimizados do TensorFlow Lite. + +- Os *simuladores de quantização* são inseridos entre as operações para imitar o comportamento quantizado. Essa abordagem é necessária para modelos em que as ops esperam ativações para seguir limites aprendidos durante a quantização. + +Para mais informações sobre como ativar esse recurso com o delegado de GPU, veja o seguinte: + +- Usando [modelos quantizados com a GPU no Android](../android/delegates/gpu#quantized-models) +- Usando [modelos quantizados com a GPU no iOS](../ios/delegates/gpu#quantized-models) + +### Reduzindo o tempo de inicialização com a serialização {:#delegate_serialization} + +O recurso de delegado de GPU permite o carregamento a partir de código de kernels pré-compilados e dados de modelo serializados e salvos no disco de execuções anteriores. Essa abordagem evita uma nova compilação e pode reduzir o tempo de inicialização em até 90%. Essa melhoria é obtida ao trocar o espaço em disco pela economia de tempo. Você pode ativar esse recurso com algumas opções de configurações, conforme mostrado nos exemplos de código a seguir: + +
+ +
+

C++

+

+
    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
+    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
+    options.serialization_dir = kTmpDir;
+    options.model_token = kModelToken;
+
+    auto* delegate = TfLiteGpuDelegateV2Create(options);
+    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
+      
+
+
+

Java

+

+
    GpuDelegate delegate = new GpuDelegate(
+      new GpuDelegate.Options().setSerializationParams(
+        /* serializationDir= */ serializationDir,
+        /* modelToken= */ modelToken));
+
+    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
+      
+
+
+
+ +Ao usar o recurso de serialização, confira se o seu código segue estas regras de implementação: + +- Armazene os dados de serialização em um diretório que não seja acessível a outros apps. Em dispositivos Android, use [`getCodeCacheDir()`](https://developer.android.com/reference/android/content/Context#getCacheDir()), que aponta a um local privado para o aplicativo atual. +- O token do modelo precisa ser exclusivo ao dispositivo para o modelo específico. Você pode computar um token de modelo ao gerar uma impressão digital a partir dos dados do modelo usando bibliotecas como [`farmhash::Fingerprint64`](https://github.com/google/farmhash). + +Observação: o uso desse recurso de serialização exige o [SDK OpenCL](https://github.com/KhronosGroup/OpenCL-SDK). diff --git a/site/pt-br/lite/performance/implementing_delegate.md b/site/pt-br/lite/performance/implementing_delegate.md new file mode 100644 index 0000000000..ea16e0ab09 --- /dev/null +++ b/site/pt-br/lite/performance/implementing_delegate.md @@ -0,0 +1,506 @@ +# Implementando um delegado personalizado + +[TOC] + +## O que é um delegado do TensorFlow Lite? + +Um [delegado](https://www.tensorflow.org/lite/performance/delegates) do TensorFlow Lite permite que você execute seus modelos (inteiros ou parte deles) em outro executor. Esse mecanismo pode usar uma variedade de aceleradores no dispositivo, como GPU ou Edge TPU (unidade de processamento de tensor) para inferência. Isso fornece aos desenvolvedores um método flexível e desacoplado do padrão TFLite para acelerar a inferência. + +O diagrama abaixo resume os delegados. Veja mais detalhes nas seções a seguir. + +![Delegados do TFLite](images/tflite_delegate.png "TFLite Delegates") + +## Quando devo criar um delegado personalizado? + +O TensorFlow Lite tem uma ampla variedade de delegados para aceleradores alvo, por exemplo, GPU, DSP, EdgeTPU e frameworks como a NNAPI do Android. + +É útil criar seu próprio delegado nos seguintes casos: + +- Você quer integrar um novo mecanismo de inferência de ML que não é compatível com qualquer delegado existente. +- Você tem um acelerador de hardware personalizado que melhora o runtime para cenários conhecidos. +- Você está desenvolvendo otimizações de CPU (como fusão de operadores) que podem acelerar determinados modelos. + +## Como funcionam os delegados? + +Considere um grafo de modelo simples como o abaixo e um delegado "MyDelegate" que tem uma implementação mais rápida para operações Conv2D e Mean. + +![Grafo original](../images/performance/tflite_delegate_graph_1.png "Original Graph") + +Depois de aplicar o "MyDelegate", o grafo original do TensorFlow Lite será atualizado da seguinte maneira: + +![Grafo com o delegado](../images/performance/tflite_delegate_graph_2.png "Graph with delegate") + +O grafo acima é obtido quando o TensorFlow Lite divide o grafo original em duas regras: + +- Operações específicas que podem ser processadas pelo delegado são colocadas em uma partição sem deixar de satisfazer as dependências do fluxo de trabalho de computação original entre as operações. +- Cada partição a ser delegada só tem nós de entrada e saída que não são processados pelo delegado. + +Cada partição que é processada por um delegado é substituída por um nó de delegado (também pode ser chamada de kernel de delegado) no grafo original que avalia a partição na sua chamada de invocação. + +Dependendo do modelo, o grafo final pode acabar com um ou mais nós, sendo que o último significa que algumas ops não são compatíveis com o delegado. Em geral, não é recomendável ter várias partições processadas pelo delegado, porque, cada vez que você alterna entre o delegado e o grafo principal, ocorre uma sobrecarga para passar os resultados do subgrafo delegado ao grafo principal que resulta das cópias na memória (por exemplo, GPU à CPU). Essa sobrecarga pode anular ganhos de desempenho, especialmente quando há um grande número de cópias na memória. + +## Implementando seu próprio delegado personalizado + +O método preferencial para adicionar um delegado é usando a [API SimpleDelegate](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/utils/simple_delegate.h). + +Para criar um novo delegado, você precisa implementar 2 interfaces e fornecer sua própria implementação para os métodos das interfaces. + +### 1 - `SimpleDelegateInterface` + +Essa classe representa as capacidades do delegado, quais operações são compatíveis e uma classe de fábrica para criar um kernel que encapsula o grafo delegado. Para mais detalhes, veja a interface definida neste [arquivo de cabeçalho C++](https://github.com/tensorflow/tensorflow/blob/8a643858ce174b8bd1b4bb8fa4bfaa62f7e8c45f/tensorflow/lite/delegates/utils/simple_delegate.h#L71). Os comentários no código explicam cada API em detalhes. + +### 2 - `SimpleDelegateKernelInterface` + +Essa classe encapsula a lógica para inicializar/preparar/executar a partição delegada. + +Ela tem: (veja a [definição](https://github.com/tensorflow/tensorflow/blob/8a643858ce174b8bd1b4bb8fa4bfaa62f7e8c45f/tensorflow/lite/delegates/utils/simple_delegate.h#L43)) + +- Init(...): pode ser chamado uma vez para fazer qualquer inicialização única. +- Prepare(...): chamado para cada instância diferente desse nó — isso acontece se você tiver várias partições delegadas. Geralmente, é recomendável fazer alocações de memória aqui, já que isso será chamado sempre que os tensores forem redimensionados. +- Invoke(...): chamado para a inferência. + +### Exemplo + +Neste exemplo, você criará um delegado bastante simples que é compatível com apenas 2 tipos de operações (ADD) e (SUB) com somente tensores float32. + +``` +// MyDelegate implements the interface of SimpleDelegateInterface. +// This holds the Delegate capabilities. +class MyDelegate : public SimpleDelegateInterface { + public: + bool IsNodeSupportedByDelegate(const TfLiteRegistration* registration, + const TfLiteNode* node, + TfLiteContext* context) const override { + // Only supports Add and Sub ops. + if (kTfLiteBuiltinAdd != registration->builtin_code && + kTfLiteBuiltinSub != registration->builtin_code) + return false; + // This delegate only supports float32 types. + for (int i = 0; i < node->inputs->size; ++i) { + auto& tensor = context->tensors[node->inputs->data[i]]; + if (tensor.type != kTfLiteFloat32) return false; + } + return true; + } + + TfLiteStatus Initialize(TfLiteContext* context) override { return kTfLiteOk; } + + const char* Name() const override { + static constexpr char kName[] = "MyDelegate"; + return kName; + } + + std::unique_ptr CreateDelegateKernelInterface() + override { + return std::make_unique(); + } +}; +``` + +Em seguida, crie seu próprio kernel de delegado ao herdar de `SimpleDelegateKernelInterface` + +``` +// My delegate kernel. +class MyDelegateKernel : public SimpleDelegateKernelInterface { + public: + TfLiteStatus Init(TfLiteContext* context, + const TfLiteDelegateParams* params) override { + // Save index to all nodes which are part of this delegate. + inputs_.resize(params->nodes_to_replace->size); + outputs_.resize(params->nodes_to_replace->size); + builtin_code_.resize(params->nodes_to_replace->size); + for (int i = 0; i < params->nodes_to_replace->size; ++i) { + const int node_index = params->nodes_to_replace->data[i]; + // Get this node information. + TfLiteNode* delegated_node = nullptr; + TfLiteRegistration* delegated_node_registration = nullptr; + TF_LITE_ENSURE_EQ( + context, + context->GetNodeAndRegistration(context, node_index, &delegated_node, + &delegated_node_registration), + kTfLiteOk); + inputs_[i].push_back(delegated_node->inputs->data[0]); + inputs_[i].push_back(delegated_node->inputs->data[1]); + outputs_[i].push_back(delegated_node->outputs->data[0]); + builtin_code_[i] = delegated_node_registration->builtin_code; + } + return kTfLiteOk; + } + + TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) override { + return kTfLiteOk; + } + + TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) override { + // Evaluate the delegated graph. + // Here we loop over all the delegated nodes. + // We know that all the nodes are either ADD or SUB operations and the + // number of nodes equals ''inputs_.size()'' and inputs[i] is a list of + // tensor indices for inputs to node ''i'', while outputs_[i] is the list of + // outputs for node + // ''i''. Note, that it is intentional we have simple implementation as this + // is for demonstration. + + for (int i = 0; i < inputs_.size(); ++i) { + // Get the node input tensors. + // Add/Sub operation accepts 2 inputs. + auto& input_tensor_1 = context->tensors[inputs_[i][0]]; + auto& input_tensor_2 = context->tensors[inputs_[i][1]]; + auto& output_tensor = context->tensors[outputs_[i][0]]; + TF_LITE_ENSURE_EQ( + context, + ComputeResult(context, builtin_code_[i], &input_tensor_1, + &input_tensor_2, &output_tensor), + kTfLiteOk); + } + return kTfLiteOk; + } + + private: + // Computes the result of addition of 'input_tensor_1' and 'input_tensor_2' + // and store the result in 'output_tensor'. + TfLiteStatus ComputeResult(TfLiteContext* context, int builtin_code, + const TfLiteTensor* input_tensor_1, + const TfLiteTensor* input_tensor_2, + TfLiteTensor* output_tensor) { + if (NumElements(input_tensor_1) != NumElements(input_tensor_2) || + NumElements(input_tensor_1) != NumElements(output_tensor)) { + return kTfLiteDelegateError; + } + // This code assumes no activation, and no broadcasting needed (both inputs + // have the same size). + auto* input_1 = GetTensorData(input_tensor_1); + auto* input_2 = GetTensorData(input_tensor_2); + auto* output = GetTensorData(output_tensor); + for (int i = 0; i < NumElements(input_tensor_1); ++i) { + if (builtin_code == kTfLiteBuiltinAdd) + output[i] = input_1[i] + input_2[i]; + else + output[i] = input_1[i] - input_2[i]; + } + return kTfLiteOk; + } + + // Holds the indices of the input/output tensors. + // inputs_[i] is list of all input tensors to node at index 'i'. + // outputs_[i] is list of all output tensors to node at index 'i'. + std::vector> inputs_, outputs_; + // Holds the builtin code of the ops. + // builtin_code_[i] is the type of node at index 'i' + std::vector builtin_code_; +}; + + +``` + +## Benchmarking e avaliação do novo delegado + +O TFLite tem um conjunto de ferramentas que você pode testar rapidamente em um modelo do TFLite. + +- [Ferramenta de benchmarking de modelo](https://github.com/tensorflow/tensorflow/tree/f9ef3a8a0b64ad6393785f3259e9a24af09c84ad/tensorflow/lite/tools/benchmark): a ferramenta aceita um modelo do TFLite, gera entradas aleatórias e executa o modelo repetidamente por um número específico de vezes. Ela imprime as estatísticas de latência agregadas no final. +- [Ferramenta de diff da inferência](https://github.com/tensorflow/tensorflow/tree/f9ef3a8a0b64ad6393785f3259e9a24af09c84ad/tensorflow/lite/tools/evaluation/tasks/inference_diff): para um modelo específico, a ferramenta gera dados gaussianos aleatórios e os passa por dois interpretadores diferentes do TFLite, um que executa um kernel de CPU de thread único e outro que usa uma especificação definida pelo usuário. Ela mede a diferença absoluta entre os tensores de saída de cada interpretador com base em cada elemento. Essa ferramenta também pode ser útil para depurar problemas de exatidão. +- Também há ferramentas de avaliação específicas a tarefas, para classificação de imagens e detecção de objetos. Elas podem ser encontradas [aqui](https://www.tensorflow.org/lite/performance/delegates#tools_for_evaluation). + +Além disso, o TFLite tem um grande conjunto de testes unitários de kernels e ops que podem ser reutilizados para testar o novo delegado com mais cobertura e garantir que o caminho de execução regular do TFLite não esteja quebrado. + +Para conseguir reutilizar testes e ferramentas do TFLite para o novo delegado, você pode usar uma das seguintes opções: + +- Utilizar o mecanismo [registrador de delegados](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/delegates). +- Utilizar o mecanismo [delegado externo](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/external). + +### Escolhendo a melhor abordagem + +Ambas as abordagens exigem algumas mudanças, conforme detalhado abaixo. No entanto, a primeira abordagem vincula o delegado estaticamente e exige a reconstrução das ferramentas de teste, benchmarking e avaliação. Em contraste, a segunda transforma o delegado em uma biblioteca compartilhada e exige que você exponha os métodos de criação/exclusão da biblioteca compartilhada. + +Como resultado, o mecanismo de delegado externo funcionará com os [binários das ferramentas pré-criadas do TensorFlow Lite](#download-links-for-nightly-pre-built-tflite-tooling-binaries). Porém, é menos explícito e pode ser mais complicado de configurar em testes de integração automatizados. Use a abordagem de registrador de delegados para maior clareza. + +### Opção 1: use o registrador de delegados + +O [registrador de delegado](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/delegates) mantém uma lista de provedores de delegados, sendo que cada um oferece uma maneira fácil de criar delegados do TFLite com base em flags de linha de comando e, portanto, são convenientes para as ferramentas. Para conectar o novo delegado a todas as ferramentas do TensorFlow mencionadas acima, primeiro crie um novo provedor de delegado como [este](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/delegates/hexagon_delegate_provider.cc) e, depois, faça apenas algumas mudanças nas regras de BUILD. Confira abaixo um exemplo completo dessa integração (e o código pode ser encontrado [aqui](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/utils/dummy_delegate)). + +Supondo que você tenha um delegado que implementa as APIs SimpleDelegate e as APIs "C" externas de criação/exclusão desse delegado "dummy" (falso) conforme mostrado abaixo: + +``` +// Returns default options for DummyDelegate. +DummyDelegateOptions TfLiteDummyDelegateOptionsDefault(); + +// Creates a new delegate instance that need to be destroyed with +// `TfLiteDummyDelegateDelete` when delegate is no longer used by TFLite. +// When `options` is set to `nullptr`, the above default values are used: +TfLiteDelegate* TfLiteDummyDelegateCreate(const DummyDelegateOptions* options); + +// Destroys a delegate created with `TfLiteDummyDelegateCreate` call. +void TfLiteDummyDelegateDelete(TfLiteDelegate* delegate); +``` + +Para integrar o "DummyDelegate" à ferramenta de benchmarking e de inferência, defina um DelegateProvider da seguinte maneira: + +``` +class DummyDelegateProvider : public DelegateProvider { + public: + DummyDelegateProvider() { + default_params_.AddParam("use_dummy_delegate", + ToolParam::Create(false)); + } + + std::vector CreateFlags(ToolParams* params) const final; + + void LogParams(const ToolParams& params) const final; + + TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final; + + std::string GetName() const final { return "DummyDelegate"; } +}; +REGISTER_DELEGATE_PROVIDER(DummyDelegateProvider); + +std::vector DummyDelegateProvider::CreateFlags(ToolParams* params) const { + std::vector flags = {CreateFlag("use_dummy_delegate", params, + "use the dummy delegate.")}; + return flags; +} + +void DummyDelegateProvider::LogParams(const ToolParams& params) const { + TFLITE_LOG(INFO) << "Use dummy test delegate : [" + << params.Get("use_dummy_delegate") << "]"; +} + +TfLiteDelegatePtr DummyDelegateProvider::CreateTfLiteDelegate( + const ToolParams& params) const { + if (params.Get("use_dummy_delegate")) { + auto default_options = TfLiteDummyDelegateOptionsDefault(); + return TfLiteDummyDelegateCreateUnique(&default_options); + } + return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {}); +} + +``` + +As definições da regra de BUILD são importantes, porque você precisa garantir que a biblioteca esteja sempre vinculada e não seja descartada pelo otimizador. + +``` +#### The following are for using the dummy test delegate in TFLite tooling #### +cc_library( + name = "dummy_delegate_provider", + srcs = ["dummy_delegate_provider.cc"], + copts = tflite_copts(), + deps = [ + ":dummy_delegate", + "//tensorflow/lite/tools/delegates:delegate_provider_hdr", + ], + alwayslink = 1, # This is required so the optimizer doesn't optimize the library away. +) +``` + +Agora inclua estas duas regras de wrapper no seu arquivo BUILD para criar uma versão das ferramentas de benchmarking e inferência, além de outras ferramentas de avaliação, que podem ser executadas com seu próprio delegado. + +``` +cc_binary( + name = "benchmark_model_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/benchmark:benchmark_model_main", + ], +) + +cc_binary( + name = "inference_diff_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/inference_diff:run_eval_lib", + ], +) + +cc_binary( + name = "imagenet_classification_eval_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification:run_eval_lib", + ], +) + +cc_binary( + name = "coco_object_detection_eval_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/coco_object_detection:run_eval_lib", + ], +) +``` + +Você também pode conectar esse provedor de delegado aos testes de kernels do TFLite conforme descrito [aqui](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/utils/dummy_delegate/README.md#kernel-tests). + +### Opção 2: use o delegado externo + +Nesta alternativa, primeiro você cria um adaptador de delegado externo, o [external_delegate_adaptor.cc](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/utils/dummy_delegate/external_delegate_adaptor.cc), conforme mostrado abaixo. Observe que essa abordagem é menos recomendável do que a Opção 1, como [mencionado](#comparison-between-the-two-options). + +``` +TfLiteDelegate* CreateDummyDelegateFromOptions(char** options_keys, + char** options_values, + size_t num_options) { + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); + + // Parse key-values options to DummyDelegateOptions. + // You can achieve this by mimicking them as command-line flags. + std::unique_ptr argv = + std::unique_ptr(new const char*[num_options + 1]); + constexpr char kDummyDelegateParsing[] = "dummy_delegate_parsing"; + argv.get()[0] = kDummyDelegateParsing; + + std::vector option_args; + option_args.reserve(num_options); + for (int i = 0; i < num_options; ++i) { + option_args.emplace_back("--"); + option_args.rbegin()->append(options_keys[i]); + option_args.rbegin()->push_back('='); + option_args.rbegin()->append(options_values[i]); + argv.get()[i + 1] = option_args.rbegin()->c_str(); + } + + // Define command-line flags. + // ... + std::vector flag_list = { + tflite::Flag::CreateFlag(...), + ..., + tflite::Flag::CreateFlag(...), + }; + + int argc = num_options + 1; + if (!tflite::Flags::Parse(&argc, argv.get(), flag_list)) { + return nullptr; + } + + return TfLiteDummyDelegateCreate(&options); +} + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Defines two symbols that need to be exported to use the TFLite external +// delegate. See tensorflow/lite/delegates/external for details. +TFL_CAPI_EXPORT TfLiteDelegate* tflite_plugin_create_delegate( + char** options_keys, char** options_values, size_t num_options, + void (*report_error)(const char*)) { + return tflite::tools::CreateDummyDelegateFromOptions( + options_keys, options_values, num_options); +} + +TFL_CAPI_EXPORT void tflite_plugin_destroy_delegate(TfLiteDelegate* delegate) { + TfLiteDummyDelegateDelete(delegate); +} + +#ifdef __cplusplus +} +#endif // __cplusplus +``` + +Agora crie o BUILD de destino para criar uma biblioteca dinâmica como mostrado a seguir: + +``` +cc_binary( + name = "dummy_external_delegate.so", + srcs = [ + "external_delegate_adaptor.cc", + ], + linkshared = 1, + linkstatic = 1, + deps = [ + ":dummy_delegate", + "//tensorflow/lite/c:common", + "//tensorflow/lite/tools:command_line_flags", + "//tensorflow/lite/tools:logging", + ], +) +``` + +Depois que esse arquivo .so do delegado externo for criado, você poderá criar binários ou usar pré-criados para a execução com o novo delegado, desde que o binário esteja vinculado a uma biblioteca [external_delegate_provider](https://github.com/tensorflow/tensorflow/blob/8c6f2d55762f3fc94f98fdd8b3c5d59ee1276dba/tensorflow/lite/tools/delegates/BUILD#L145-L159) compatível com flags de linha de comando, como descrito [aqui](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/delegates#external-delegate-provider). Observação: esse provedor de delegado externo já foi vinculado aos binários existentes de testes e ferramentas. + +Consulte as descrições [aqui](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/utils/dummy_delegate/README.md#option-2-utilize-tensorflow-lite-external-delegate) para uma ilustração de como fazer o benchmarking do delegado "dummy" por essa abordagem de delegado externo. Você pode usar comandos semelhantes para as ferramentas de teste e avaliação mencionadas anteriormente. + +Vale ressaltar que o *delegado externo* é a implementação C++ correspondente do *delegado* na vinculação Python do Tensorflow, como mostrado [aqui](https://github.com/tensorflow/tensorflow/blob/7145fc0e49be01ef6943f4df386ce38567e37797/tensorflow/lite/python/interpreter.py#L42). Portanto, a biblioteca de adaptador do delegado externo dinâmico criada aqui pode ser usada diretamente com as APIs Python do TensorFlow Lite. + +## Recursos + +### Links para baixar os binários das ferramentas pré-criadas noturnas do TFLite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OSARCHBINARY_NAME
Linuxx86_64 + +
arm + +
aarch64 + +
Androidarm + +
aarch64 + +
diff --git a/site/pt-br/lite/performance/measurement.md b/site/pt-br/lite/performance/measurement.md new file mode 100644 index 0000000000..d85c62da85 --- /dev/null +++ b/site/pt-br/lite/performance/measurement.md @@ -0,0 +1,473 @@ +# Medição de desempenho + +## Ferramentas de benchmarking + +No momento, as ferramentas de benchmarking do TensorFlow Lite medem e calculam estatísticas para as seguintes métricas de desempenho importantes: + +- Tempo de inicialização +- Tempo de inferência do estado de warmup +- Tempo de inferência do estado estacionário +- Uso da memória durante o tempo de inicialização +- Uso geral da memória + +As ferramentas de benchmarking estão disponíveis como aplicativos de benchmarking para Android e iOS e como binários de linha de comando nativos, e todas elas compartilham a mesma lógica de medição de desempenho principal. Observe que as opções e os formatos de saída disponíveis são um pouco diferentes devido às diferenças no ambiente de runtime. + +### Aplicativo de benchmarking do Android + +Há duas opções para usar a ferramenta de benchmarking com o Android. Uma é um [binário de benchmarking nativo](#native-benchmark-binary) e a outra é um aplicativo de benchmarking do Android, um medidor melhor do desempenho do modelo no aplicativo. De qualquer forma, os números da ferramenta de benchmarking ainda diferem um pouco de quando a inferência é executada com o modelo no próprio aplicativo. + +Esse aplicativo de benchmarking do Android não tem interface do usuário. Instale e execute usando o comando `adb` e recupere os resultados usando o comando `adb logcat`. + +#### Baixe ou compile o aplicativo + +Baixe os aplicativos de benchmarking do Android pré-criados e noturnos usando os links abaixo: + +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model.apk) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_benchmark_model.apk) + +Para os aplicativos de benchmarking do Android compatíveis com [ops do TF](https://www.tensorflow.org/lite/guide/ops_select) pelo [delegado Flex](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/flex), use os links abaixo: + +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model_plus_flex.apk) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_benchmark_model_plus_flex.apk) + +Você também pode compilar o aplicativo do código-fonte seguindo estas [instruções](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/android). + +Observação: é necessário compilar o aplicativo do código-fonte se você quiser executar o APK de benchmarking do Android na CPU x86 ou no delegado Hexagon ou se o modelo tiver [determinados operadores do TF](../guide/ops_select) ou [operadores personalizados](../guide/ops_custom). + +#### Prepare o benchmarking + +Antes de executar o aplicativo de benchmarking, instale o aplicativo e envie o arquivo do modelo ao dispositivo da seguinte maneira: + +```shell +adb install -r -d -g android_aarch64_benchmark_model.apk +adb push your_model.tflite /data/local/tmp +``` + +#### Execute o benchmarking + +```shell +adb shell am start -S \ + -n org.tensorflow.lite.benchmark/.BenchmarkModelActivity \ + --es args '"--graph=/data/local/tmp/your_model.tflite \ + --num_threads=4"' +``` + +`graph` é um parâmetro obrigatório. + +- `graph`: `string`
O caminho para o arquivo do modelo do TFLite. + +Você pode especificar mais parâmetros opcionais para executar o benchmarking. + +- `num_threads`: `int` (default=1)
O número de threads que devem ser usados ao executar o interpretador do TFLite. +- `use_gpu`: `bool` (default=false)
Use o [delegado de GPU](gpu). +- `use_nnapi`: `bool` (default=false)
Use o [delegado NNAPI](nnapi). +- `use_xnnpack`: `bool` (default=`false`)
Use o [delegado XNNPACK](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/xnnpack). +- `use_hexagon`: `bool` (default=`false`)
Use o [delegado Hexagon](hexagon_delegate). + +Dependendo do dispositivo usado, algumas dessas opções podem não estar disponíveis ou não fazer nenhum efeito. Consulte mais [parâmetros](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#parameters) desempenho de que você pode executar com o aplicativo de benchmarking. + +Veja os resultados usando o comando `logcat`: + +```shell +adb logcat | grep "Inference timings" +``` + +Os resultados de benchmarking são relatados assim: + +``` +... tflite : Inference timings in us: Init: 5685, First inference: 18535, Warmup (avg): 14462.3, Inference (avg): 14575.2 +``` + +### Biblioteca de benchmarking nativa + +A ferramenta de benchmarking também é fornecida como um `benchmark_model` de binário nativo. Você pode executar essa ferramenta a partir de uma linha de comando de shell em Linux, Mac, dispositivos embarcados e dispositivos Android. + +#### Baixe ou compile o binário + +Baixe os binários de linha de comando nativos pré-criados e noturnos usando os links abaixo: + +- [linux_x86-64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_x86-64_benchmark_model) +- [linux_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_aarch64_benchmark_model) +- [linux_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_arm_benchmark_model) +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_benchmark_model) + +Para os binários pré-criados e noturnos que são compatíveis com [ops do TF](https://www.tensorflow.org/lite/guide/ops_select) pelo [delegado Flex](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/flex), use os links abaixo: + +- [linux_x86-64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_x86-64_benchmark_model_plus_flex) +- [linux_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_aarch64_benchmark_model_plus_flex) +- [linux_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_arm_benchmark_model_plus_flex) +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model_plus_flex) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_benchmark_model_plus_flex) + +Para fazer o benchmarking com o [delegado Hexagon do TensorFlow Lite](https://www.tensorflow.org/lite/android/delegates/hexagon), também pré-criamos os arquivos `libhexagon_interface.so` necessários (veja [aqui](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/hexagon/README.md) mais detalhes sobre esse arquivo). Depois de baixar o arquivo da plataforma correspondente pelos links abaixo, renomeie-o como `libhexagon_interface.so`. + +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_libhexagon_interface.so) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_libhexagon_interface.so) + +Você também pode compilar o binário de benchmarking nativo a partir do [código-fonte](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark) no seu computador. + +```shell +bazel build -c opt //tensorflow/lite/tools/benchmark:benchmark_model +``` + +Para compilar com a toolchain do Android NDK, você precisa configurar o ambiente de build primeiro ao seguir este [guia](../android/lite_build#set_up_build_environment_without_docker) ou usar a imagem docker conforme descrito neste [guia](../android/lite_build#set_up_build_environment_using_docker). + +```shell +bazel build -c opt --config=android_arm64 \ + //tensorflow/lite/tools/benchmark:benchmark_model +``` + +Observação: é uma abordagem válida enviar e executar binários diretamente em um dispositivo Android para benchmarking, mas pode resultar em diferenças sutis (mas observáveis) no desempenho relativo à execução dentro de um aplicativo Android real. Em especial, o agendador do Android ajusta o comportamento com base nas prioridades de thread e processo, que diferem de uma atividade/aplicativo em primeiro plano e um binário em segundo plano regular executado pelo `adb shell ...`. Esse comportamento ajustado é mais evidente ao permitir a execução de CPU de vários threads com o TensorFlow Lite. Por isso, o aplicativo de benchmarking do Android é recomendado para a medição de desempenho. + +#### Execute o benchmarking + +Para executar o benchmarking no seu computador, execute o binário no shell. + +```shell +path/to/downloaded_or_built/benchmark_model \ + --graph=your_model.tflite \ + --num_threads=4 +``` + +Você pode usar o mesmo conjunto de [parâmetros](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#parameters) conforme mencionado acima com o binário de linha de comando nativo. + +#### Análise de perfil das ops do modelo + +O binário do modelo de benchmarking também permite que você analise as ops do modelo e obtenha os tempos de execução de cada operador. Para fazer isso, passe a flag `--enable_op_profiling=true` a `benchmark_model` durante a invocação. Os detalhes são explicados [aqui](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#profiling-model-operators). + +### Binário de benchmarking nativo para várias opções de desempenho em uma única execução + +Um binário C++ conveniente e simples também é fornecido para o [benchmarking de várias opções de desempenho](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#benchmark-multiple-performance-options-in-a-single-run) em uma única execução. Esse binário é criado com base na ferramenta de benchmarking mencionada acima que só pode fazer o benchmarking de uma única opção de desempenho por vez. Eles compartilham o mesmo processo de build/instalação/execução, mas o nome de destino do BUILD desse binário é `benchmark_model_performance_options` e exige alguns parâmetros adicionais. Um parâmetro importante para esse binário é: + +`perf_options_list`: `string` (default='all')
Uma lista separada por vírgulas das opções de desempenho do TFLite para o benchmarking. + +Você pode obter binários pré-criados noturnos para essa ferramenta conforme listado abaixo: + +- [linux_x86-64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_x86-64_benchmark_model_performance_options) +- [linux_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_aarch64_benchmark_model_performance_options) +- [linux_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/linux_arm_benchmark_model_performance_options) +- [android_aarch64](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_aarch64_benchmark_model_performance_options) +- [android_arm](https://storage.googleapis.com/tensorflow-nightly-public/prod/tensorflow/release/lite/tools/nightly/latest/android_arm_benchmark_model_performance_options) + +### Aplicativo de benchmarking do iOS + +Para realizar o benchmarking em um dispositivo iOS, você precisa compilar o aplicativo do [código-fonte](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/ios). Coloque o arquivo do modelo do TensorFlow Lite no diretório [benchmark_data](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/ios/TFLiteBenchmark/TFLiteBenchmark/benchmark_data) da árvore de código-fonte e modifique o arquivo `benchmark_params.json`. Esses arquivos são empacotados no aplicativo e o aplicativo lê os dados do diretório. Acesse o [aplicativo de benchmarking do iOS](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/ios) para instruções detalhadas. + +## Benchmarks de desempenho para modelos conhecidos + +Esta seção lista benchmarks de desempenho do TensorFlow ao executar modelos conhecidos em alguns dispositivos Android e iOS. + +### Benchmarks de desempenho do Android + +Esses números de benchmarking de desempenho foram gerados com o [binário de benchmarking nativo](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark). + +Para benchmarks do Android, a afinidade de CPU é definida para usar big cores no dispositivo para reduzir a variância (veja mais [detalhes](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#reducing-variance-between-runs-on-android)). + +Ela supõe que os modelos foram baixados e descompactados no diretório `/data/local/tmp/tflite_models`. O binário de benchmark é criado usando [estas instruções](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark#on-android) e se supõe que esteja no diretório `/data/local/tmp`. + +Para realizar o benchmark: + +```sh +adb shell /data/local/tmp/benchmark_model \ + --num_threads=4 \ + --graph=/data/local/tmp/tflite_models/${GRAPH} \ + --warmup_runs=1 \ + --num_runs=50 +``` + +Para executar com o delegado NNAPI, defina `--use_nnapi=true`. Para executar com o delegado de GPU, defina `--use_gpu=true`. + +Os valores de desempenho abaixo são medidos no Android 10. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nome do modeloDispositivoCPU, 4 threadsGPUNNAPI
Mobilenet_1.0_224(float) +Pixel 323,9 ms6,45 ms13,8 ms
Pixel 414,0 ms9,0 ms14,8 ms
Mobilenet_1.0_224 (quant) +Pixel 313,4 ms---6,0 ms
Pixel 45,0 ms---3,2 ms
NASNet mobile +Pixel 356 ms---102 ms
Pixel 434,5 ms---99,0 ms
SqueezeNet +Pixel 335,8 ms9,5 ms18,5 ms
Pixel 423,9 ms11,1 ms19,0 ms
Inception_ResNet_V2 +Pixel 3422 ms99,8 ms201 ms
Pixel 4272,6 ms87,2 ms171,1 ms
Inception_V4 +Pixel 3486 ms93 ms292 ms
Pixel 4324,1 ms97,6 ms186,9 ms
+ +### Benchmarks de desempenho do iOS + +Esses números de benchmarking de desempenho foram gerados com o [aplicativo de benchmarking do iOS](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/benchmark/ios). + +Para realizar os benchmarks do iOS, o aplicativo foi modificado para incluir o modelo apropriado e `benchmark_params.json` foi modificado para definir o `num_threads` como 2. Para usar o delegado de GPU, as opções `"use_gpu" : "1"` e `"gpu_wait_type" : "aggressive"` foram adicionadas a `benchmark_params.json`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nome do modeloDispositivoCPU, 2 threadsGPU
Mobilenet_1.0_224(float) +iPhone XS14,8 ms3,4 ms
Mobilenet_1.0_224 (quant) +iPhone XS11 ms---
NASNet mobile +iPhone XS30,4 ms---
SqueezeNet +iPhone XS21,1 ms15,5 ms
Inception_ResNet_V2 +iPhone XS261,1 ms45,7 ms
Inception_V4 +iPhone XS309 ms54,4 ms
+ +## Rastreie internals do TensorFlow Lite + +### Rastreie internals do TensorFlow Lite no Android + +Observação: esse recurso está disponível a partir do TensorFlow Lite v2.4. + +Os eventos internos do interpretador do TensorFlow Lite de um aplicativo Android podem ser capturados por [ferramentas de tracing do Android](https://developer.android.com/topic/performance/tracing). Eles são os mesmos eventos com a API [Trace](https://developer.android.com/reference/android/os/Trace) do Android, então os eventos capturados do código Java/Kotlin são vistos juntos com os eventos internos do TensorFlow Lite. + +Alguns exemplos de eventos são: + +- Invocação de operador +- Modificação de grafo por delegado +- Alocação de tensor + +Entre as diferentes opções de captura de traces, este guia aborda o Android Studio CPU Profiler e o aplicativo System Tracing. Consulte a [ferramenta de linha de comando Perfetto](https://developer.android.com/studio/command-line/perfetto) ou a [ferramenta de linha de comando Systrace](https://developer.android.com/topic/performance/tracing/command-line) para mais opções. + +#### Adicionando eventos de trace em código Java + +Este é uma amostra de código do aplicativo de exemplo de [Classificação de imagens](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/android). O interpretador do TensorFlow Lite é executado na seção `recognizeImage/runInference`. Essa etapa é opcional, mas é útil para ajudar a perceber onde é realizada a chamada de inferência. + +```java + Trace.beginSection("recognizeImage"); + ... + // Runs the inference call. + Trace.beginSection("runInference"); + tflite.run(inputImageBuffer.getBuffer(), outputProbabilityBuffer.getBuffer().rewind()); + Trace.endSection(); + ... + Trace.endSection(); + +``` + +#### Ative o tracing do TensorFlow Lite + +Para ativar o tracing do TensorFlow Lite, defina a propriedade `debug.tflite.trace` do sistema Android como 1
antes de iniciar o aplicativo Android. + +```shell +adb shell setprop debug.tflite.trace 1 +``` + +Se essa propriedade for definida com o interpretador do TensorFlow inicializado, serão rastreados os principais eventos (por exemplo, invocação de operador) do interpretador. + +Depois de capturar todos os traces, desative o tracing ao definir o valor da propriedade como 0. + +```shell +adb shell setprop debug.tflite.trace 0 +``` + +#### Android Studio CPU Profiler + +Capture traces com o [Android Studio CPU Profiler](https://developer.android.com/studio/profile/cpu-profiler) ao seguir as etapas abaixo: + +1. Selecione **Run > Profile 'app'** (Executar > Fazer o profiling do aplicativo) nos menus superiores. + +2. Clique em qualquer lugar na linha do tempo da CPU quando aparecer a janela do Profiler. + +3. Selecione "Trace System Calls" (Rastrear chamadas do sistema) entre os modos de profiling da CPU. + + ![Selecione 'Trace System Calls'](images/as_select_profiling_mode.png) + +4. Pressione o botão "Record" (Gravar). + +5. Pressione o botão "Stop" (Parar). + +6. Investigue o resultado do tracing. + + ![Trace do Android Studio](images/as_traces.png) + +Nesse exemplo, você pode ver a hierarquia dos eventos em um thread e as estatísticas para cada tempo do operador, além de conferir o fluxo dos dados do aplicativo inteiro entre os threads. + +#### Aplicativo System Tracing + +Capture traces sem o Android Studio ao seguir as etapas detalhadas no [aplicativo System Tracing](https://developer.android.com/topic/performance/tracing/on-device). + +Nesse exemplo, os mesmos eventos do TFLite foram capturados e salvos no formato Perfetto ou Systrace dependendo da versão do dispositivo Android. Os arquivos dos traces capturados podem ser abertos na [interface de usuário Perfetto](https://ui.perfetto.dev/#!/). + +![Trace Perfetto](images/perfetto_traces.png) + +### Rastreie internals do TensorFlow Lite no iOS + +Observação: esse recurso está disponível a partir do TensorFlow Lite v2.5. + +Os eventos internos do interpretador do TensorFlow Lite de um aplicativo iOS podem ser capturados pela ferramenta [Instruments](https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/MeasuringPerformance.html#//apple_ref/doc/uid/TP40010215-CH60-SW1) incluída com Xcode. Eles são os eventos [signpost](https://developer.apple.com/documentation/os/logging/recording_performance_data) do iOS, então os eventos capturados do código Swift/Objective-C são vistos juntos com os eventos internos do TensorFlow Lite. + +Alguns exemplos de eventos são: + +- Invocação de operador +- Modificação de grafo por delegado +- Alocação de tensor + +#### Ative o tracing do TensorFlow Lite + +Defina a variável de ambiente `debug.tflite.trace` seguindo as etapas abaixo: + +1. Selecione **Product > Scheme > Edit Scheme...** (Produto > Esquema > Editar esquema...) nos menus superiores do Xcode. + +2. Clique em "Profile" (Perfil) no painel à esquerda. + +3. Desmarque a caixa de seleção "Use the Run action's arguments and environment variables" (Usar os argumentos e as variáveis de ambiente da ação de execução). + +4. Adicione `debug.tflite.trace` à seção "Environment Variables" (Variáveis de ambiente). + + ![Defina a variável de ambiente](images/xcode_profile_environment.png) + +Se você quiser excluir os eventos do TensorFlow Lite ao analisar o perfil do aplicativo iOS, desative o tracing ao remover a variável de ambiente. + +#### Instruments do XCode + +Capture traces seguindo as etapas abaixo: + +1. Selecione **Product > Profile** (Produto > Perfil) nos menus superiores do Xcode. + +2. Clique em **Logging** nos modelos de profiling quando a ferramenta Instruments for inicializada. + +3. Pressione o botão "Start" (Iniciar). + +4. Pressione o botão "Stop" (Parar). + +5. Clique em "os_signpost" para abrir os itens do subsistema de registros do SO. + +6. Clique no subsistema de registros do SO "org.tensorflow.lite". + +7. Investigue o resultado do tracing. + + ![Trace do Instruments do Xcode](images/xcode_traces.png) + +Nesse exemplo, você pode ver a hierarquia de eventos e as estatísticas para cada tempo do operador. + +### Usando os dados de tracing + +Os dados de tracing permitem que você identifique os gargalos de desempenho. + +Veja alguns exemplos de insights que você pode obter do profiler e possíveis soluções para melhorar o desempenho: + +- Se o número de núcleos de CPU disponíveis for menor do que o número de threads de inferência, então a sobrecarga do agendamento da CPU pode levar a um desempenho inferior. Você pode reagendar outras tarefas intensivas da CPU no seu aplicativo para evitar a sobreposição com a inferência do seu modelo ou ajustar o número de threads do interpretador. +- Se os operadores não forem totalmente delegados, algumas partes do grafo do modelo são executas na CPU, em vez do acelerador de hardware esperado. Você pode substituir os operadores incompatíveis por operadores compatíveis semelhantes. diff --git a/site/pt-br/lite/performance/model_optimization.md b/site/pt-br/lite/performance/model_optimization.md new file mode 100644 index 0000000000..0c611b1a62 --- /dev/null +++ b/site/pt-br/lite/performance/model_optimization.md @@ -0,0 +1,144 @@ +# Otimização de modelo + +Os dispositivos de borda geralmente têm memória ou poder computacional limitado. Várias otimizações podem ser aplicadas aos modelos para que eles possam ser executados nessas restrições. Além disso, algumas otimizações permitem o uso de hardware especializado para a inferência acelerada. + +O TensorFlow Lite e o [Kit de ferramentas para otimização de modelo do TensorFlow](https://www.tensorflow.org/model_optimization) fornece ferramentas para reduzir a complexidade de otimizar a inferência. + +É recomendável considerar a otimização do modelo durante o processo de desenvolvimento do seu aplicativo. Este documento descreve algumas práticas recomendadas para otimizar modelos do TensorFlow para a implantação de hardware de borda. + +## Por que os modelos devem ser otimizados + +A otimização de modelo pode ajudar com o desenvolvimento de aplicativos de várias maneiras. + +### Redução de tamanho + +Algumas formas de otimização podem ser usadas para reduzir o tamanho de um modelo. Modelos menores têm os seguintes benefícios: + +- **Menor tamanho de armazenamento:** modelos menores ocupam menos espaço de armazenamento nos dispositivos dos seus usuários. Por exemplo, um aplicativo Android usando um modelo menor ocupará menos espaço de armazenamento no dispositivo móvel do usuário. +- **Menor tamanho de download:** modelos menores exigem menos tempo e largura de banda para serem baixados nos dispositivos dos usuários. +- **Menos uso da memória:** modelos menores usam menos RAM quando são executados, o que libera a memória para que seja usada por outras partes do seu aplicativo e pode resultar em melhor desempenho e estabilidade. + +A quantização pode reduzir o tamanho de um modelo em todos esses casos, possivelmente à custa de um pouco de exatidão. O pruning e o clustering podem reduzir o tamanho de um modelo para download ao torná-lo mais facilmente compressível. + +### Redução de latência + +A *latência* é a quantidade de tempo que leva para executar uma única inferência com um determinado modelo. Algumas formas de otimização podem reduzir a quantidade de computação necessária para realizar a inferência usando um modelo, resultando em menor latência. A latência também pode ter um impacto no consumo de energia. + +No momento, a quantização pode ser usada para reduzir a latência ao simplificar os cálculos que ocorrem durante a inferência, possivelmente à custa de um pouco de exatidão. + +### Compatibilidade com os aceleradores + +Alguns aceleradores de hardware, como o [Edge TPU](https://cloud.google.com/edge-tpu/), podem realizar a inferência de forma extremamente rápida com modelos que foram otimizados de maneira correta. + +Geralmente, esses tipos de dispositivos exigem que os modelos sejam quantizados de maneira específica. Veja a documentação de cada acelerador de hardware para saber mais sobre os requisitos deles. + +## Trade-offs + +As otimizações podem resultar possivelmente em mudanças na exatidão do modelo, o que precisa ser considerado durante o processo de desenvolvimento do aplicativo. + +As mudanças na exatidão dependem do modelo individual que está sendo otimizado e são difíceis de prever com antecedência. Geralmente, os modelos otimizados para o tamanho ou a latência perdem um pouco da exatidão. Dependendo do seu aplicativo, isso pode afetar ou não a experiência dos seus usuários. Em casos raros, alguns modelos podem ganhar um pouco de exatidão como resultado do processo de otimização. + +## Tipos de otimização + +Atualmente, o TensorFlow Lite aceita a otimização por quantização, pruning e clustering. + +Eles fazem parte do [Kit de ferramentas para a otimização de modelo do TensorFlow](https://www.tensorflow.org/model_optimization), que fornece recursos para técnicas de otimização de modelo compatíveis com o TensorFlow Lite. + +### Quantização + +A [quantização](https://www.tensorflow.org/model_optimization/guide/quantization/post_training) funciona ao reduzir a precisão dos números usados para representar os parâmetros de um modelo, que, por padrão, são números de ponto flutuante de 32 bits. Isso resulta em um menor tamanho de modelo e uma computação mais rápida. + +Os seguintes tipos de quantização estão disponíveis no TensorFlow Lite: + +Técnica | Requisitos de dados | Redução de tamanho | Exatidão | Hardware compatível +--- | --- | --- | --- | --- +[Quantização float16 pós-treinamento](post_training_float16_quant.ipynb) | Nenhum dado | Até 50% | Perda de exatidão insignificante | CPU, GPU +[Quantização de intervalo dinâmico pós-treinamento](post_training_quant.ipynb) | Nenhum dado | Até 75% | Perda de exatidão mínima | CPU, GPU (Android) +[Quantização de números inteiros pós-treinamento](post_training_integer_quant.ipynb) | Amostra representativa não rotulada | Até 75% | Perda de exatidão pequena | CPU, GPU (Android), EdgeTPU, DSP Hexagon +[Treinamento consciente de quantização](http://www.tensorflow.org/model_optimization/guide/quantization/training) | Dados de treinamento rotulados | Até 75% | Perda de exatidão mínima | CPU, GPU (Android), EdgeTPU, DSP Hexagon + +A seguinte árvore de decisão ajuda você a selecionar os esquemas de quantização que talvez queira usar para seu modelo, simplesmente com base no tamanho e na exatidão esperados do modelo. + +![Árvore de decisão de quantização](images/quantization_decision_tree.png) + +Confira abaixo os resultados de latência e exatidão para a quantização pós-treinamento e o treinamento consciente de quantização em alguns modelos. Todos os números de latência são medidos em dispositivos Pixel 2 usando uma única CPU big core. Conforme o kit de ferramentas melhorar, os números aqui também vão: + +
+ + + + + + + + + + + + + + + + + + + +
ModelTop-1 Accuracy (Original) Top-1 Accuracy (Post Training Quantized) Top-1 Accuracy (Quantization Aware Training) Latency (Original) (ms) Latency (Post Training Quantized) (ms) Latency (Quantization Aware Training) (ms) Size (Original) (MB) Size (Optimized) (MB)
Mobilenet-v1-1-2240.7090.6570.701241126416.94.3
Mobilenet-v2-1-2240.7190.6370.709899854143.6
Inception_v30.780.7720.775113084554395.723.9
Resnet_v2_1010.7700.768N/A39732868N/A178.344.9
+
+ Table 1 Benefits of model quantization for select CNN models +
+
+ +### Quantização de números inteiros com ativações int16 e pesos int8 + +A [quantização com ativações int16](https://www.tensorflow.org/model_optimization/guide/quantization/post_training) é um esquema de quantização de números inteiros com ativações em int16 e pesos em int8. Esse modo pode melhorar a exatidão do modelo quantizado em comparação com o esquema de quantização de números inteiros com as ativações e os pesos em int8, mantendo um tamanho de modelo semelhante. É recomendado quando as ativações são sensíveis à quantização. + +OBSERVAÇÃO: no momento, somente implementações de kernels de referência não otimizados estão disponíveis no TFLite para esse esquema de quantização. Então, por padrão, o desempenho será lento em comparação aos kernels int8. Os benefícios completos desse modo podem ser acessados por hardware especializado ou software personalizado. + +Confira os resultados de exatidão para alguns modelos que se beneficiam desse modo. + +
+ + + + + + + + + + + + + + + + + + + +
ModelAccuracy metric type Accuracy (float32 activations) Accuracy (int8 activations) Accuracy (int16 activations)
Wav2letterWER6.7%7.7%7.2%
DeepSpeech 0.5.1 (unrolled)CER6.13%43.67%6.52%
YoloV3mAP(IOU=0.5)0.5770.5630.574
MobileNetV1Top-1 Accuracy0.70620.6940.6936
MobileNetV2Top-1 Accuracy0.7180.71260.7137
MobileBertF1(Exact match)88.81(81.23)2.08(0)88.73(81.15)
+
+ Table 2 Benefits of model quantization with int16 activations +
+
+ +### Pruning + +O [pruning](https://www.tensorflow.org/model_optimization/guide/pruning) atua removendo os parâmetros de um modelo que só têm um impacto menor nas suas previsões. Os modelos que passaram pelo pruning têm o mesmo tamanho em disco e a mesma latência de runtime, mas podem ser comprimidos com mais eficiência. Isso faz com que o pruning seja uma técnica útil para reduzir o tamanho de download do modelo. + +No futuro, o TensorFlow Lite proporcionará a redução da latência para modelos após o pruning. + +### Clustering + +O [clustering](https://www.tensorflow.org/model_optimization/guide/clustering) atua agrupando os pesos de cada camada de um modelo em um número predefinido de clusters e, depois, compartilhando os valores de centroides para os pesos que pertencem a cada cluster individual. Isso reduz o número de valores de pesos únicos em um modelo, diminuindo sua complexidade. + +Como resultado, os modelos que passaram pelo clustering podem ser comprimidos com mais eficiência, oferecendo benefícios semelhantes ao pruning para a implantação. + +## Fluxo de trabalho de desenvolvimento + +Como ponto de partida, verifique se os [modelos hospedados](../guide/hosted_models.md) funcionam para seu aplicativo. Caso contrário, recomendamos que os usuários comecem com a [ferramenta de quantização pós-treinamento](post_training_quantization.md), já que é amplamente aplicável e não exige dados de treinamento. + +Para os casos em que os alvos de exatidão e latência não forem atingidos ou o suporte ao acelerador de hardware for importante, o [treinamento consciente de quantização](https://www.tensorflow.org/model_optimization/guide/quantization/training){:.external} é a melhor opção. Veja as técnicas de otimização adicionais no [Kit de ferramentas para a otimização de modelo do TensorFlow](https://www.tensorflow.org/model_optimization). + +Se você quiser reduzir ainda mais o tamanho do modelo, experimente o [pruning](#pruning) e/ou [clustering](#clustering) antes da quantização. diff --git a/site/pt-br/lite/performance/post_training_float16_quant.ipynb b/site/pt-br/lite/performance/post_training_float16_quant.ipynb new file mode 100644 index 0000000000..05903da3ef --- /dev/null +++ b/site/pt-br/lite/performance/post_training_float16_quant.ipynb @@ -0,0 +1,575 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "c8Cx-rUMVX25" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "I9sUhVL_VZNO" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Y8E0lw5eYWm" + }, + "source": [ + "# Quantização float16 pós-treinamento" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CGuqeuPSVNo-" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTC1rDAuei_1" + }, + "source": [ + "## Visão geral\n", + "\n", + "O [TensorFlow Lite](https://www.tensorflow.org/lite/) é agora compatível com a conversão de pesos para valores de ponto flutuante de 16 bits ao converter o modelo do TensorFlow para o formato de flatbuffer do TensorFlow Lite. Isso resulta em uma redução do tamanho do modelo em duas vezes. Alguns hardwares, como GPUs, podem computar nativamente nessa aritmética de precisão reduzida, realizando um speedup sobre a execução de ponto flutuante tradicional. O delegado de GPU do TensorFlow Lite pode ser configurado para essa execução. No entanto, um modelo convertido para os pesos float16 ainda pode ser executado na CPU sem modificação adicional: é realizado o upsampling dos pesos float16 em float32 para a primeira inferência. Isso permite uma redução significativa no tamanho do modelo em troca de um impacto mínimo na latência e na exatidão.\n", + "\n", + "Neste tutorial, você vai treinar um modelo MNIST do zero, verificar a exatidão no TensorFlow e converter o modelo em um flatbuffer do TensorFlow Lite com quantização float16." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2XsEP17Zelz9" + }, + "source": [ + "## Crie um modelo MNIST" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dDqqUIZjZjac" + }, + "source": [ + "### Configuração" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gyqAw1M9lyab" + }, + "outputs": [ + + ], + "source": [ + "import logging\n", + "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", + "\n", + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "import numpy as np\n", + "import pathlib" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eQ6Q0qqKZogR" + }, + "source": [ + "### Treine e exporte o modelo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hWSAjQWagIHl" + }, + "outputs": [ + + ], + "source": [ + "# Load MNIST dataset\n", + "mnist = keras.datasets.mnist\n", + "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", + "\n", + "# Normalize the input image so that each pixel value is between 0 to 1.\n", + "train_images = train_images / 255.0\n", + "test_images = test_images / 255.0\n", + "\n", + "# Define the model architecture\n", + "model = keras.Sequential([\n", + " keras.layers.InputLayer(input_shape=(28, 28)),\n", + " keras.layers.Reshape(target_shape=(28, 28, 1)),\n", + " keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),\n", + " keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " keras.layers.Flatten(),\n", + " keras.layers.Dense(10)\n", + "])\n", + "\n", + "# Train the digit classification model\n", + "model.compile(optimizer='adam',\n", + " loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['accuracy'])\n", + "model.fit(\n", + " train_images,\n", + " train_labels,\n", + " epochs=1,\n", + " validation_data=(test_images, test_labels)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5NMaNZQCkW9X" + }, + "source": [ + "Para o exemplo, você treinou o modelo por apenas uma única época, então ele só treina com uma exatidão de aproximadamente 96%." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xl8_fzVAZwOh" + }, + "source": [ + "### Converta para um modelo do TensorFlow Lite\n", + "\n", + "Usando o [Conversor](https://www.tensorflow.org/lite/models/convert) do TensorFlow Lite, você pode converter o modelo treinado em um modelo do TensorFlow Lite.\n", + "\n", + "Agora carregue o modelo usando o `TFLiteConverter`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_i8B2nDZmAgQ" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "tflite_model = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F2o2ZfF0aiCx" + }, + "source": [ + "Escreva em um arquivo `.tflite`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vptWZq2xnclo" + }, + "outputs": [ + + ], + "source": [ + "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", + "tflite_models_dir.mkdir(exist_ok=True, parents=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ie9pQaQrn5ue" + }, + "outputs": [ + + ], + "source": [ + "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", + "tflite_model_file.write_bytes(tflite_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7BONhYtYocQY" + }, + "source": [ + "Em vez disso, para quantizar o modelo em float16 na exportação, primeiro defina a flag `optimizations` para usar as otimizações padrão. Em seguida, especifique que o float16 é o tipo compatível na plataforma de destino:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HEZ6ET1AHAS3" + }, + "outputs": [ + + ], + "source": [ + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.target_spec.supported_types = [tf.float16]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xW84iMYjHd9t" + }, + "source": [ + "Por fim, converta o modelo normalmente. Observe que, por padrão, o modelo convertido ainda usará a entrada e as saídas de float para a conveniência da invocação." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yuNfl3CoHNK3" + }, + "outputs": [ + + ], + "source": [ + "tflite_fp16_model = converter.convert()\n", + "tflite_model_fp16_file = tflite_models_dir/\"mnist_model_quant_f16.tflite\"\n", + "tflite_model_fp16_file.write_bytes(tflite_fp16_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PhMmUTl4sbkz" + }, + "source": [ + "O arquivo resultante tem aproximadamente `1/2` do tamanho." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JExfcfLDscu4" + }, + "outputs": [ + + ], + "source": [ + "!ls -lh {tflite_models_dir}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L8lQHMp_asCq" + }, + "source": [ + "## Execute os modelos do TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-5l6-ciItvX6" + }, + "source": [ + "Execute o modelo do TensorFlow Lite usando o interpretador do TensorFlow Lite em Python." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ap_jE7QRvhPf" + }, + "source": [ + "### Carregue o modelo nos interpretadores" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Jn16Rc23zTss" + }, + "outputs": [ + + ], + "source": [ + "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", + "interpreter.allocate_tensors()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J8Pztk1mvNVL" + }, + "outputs": [ + + ], + "source": [ + "interpreter_fp16 = tf.lite.Interpreter(model_path=str(tflite_model_fp16_file))\n", + "interpreter_fp16.allocate_tensors()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2opUt_JTdyEu" + }, + "source": [ + "### Teste os modelos em uma imagem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AKslvo2kwWac" + }, + "outputs": [ + + ], + "source": [ + "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", + "\n", + "input_index = interpreter.get_input_details()[0][\"index\"]\n", + "output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + "interpreter.set_tensor(input_index, test_image)\n", + "interpreter.invoke()\n", + "predictions = interpreter.get_tensor(output_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XZClM2vo3_bm" + }, + "outputs": [ + + ], + "source": [ + "import matplotlib.pylab as plt\n", + "\n", + "plt.imshow(test_images[0])\n", + "template = \"True:{true}, predicted:{predict}\"\n", + "_ = plt.title(template.format(true= str(test_labels[0]),\n", + " predict=str(np.argmax(predictions[0]))))\n", + "plt.grid(False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3gwhv4lKbYZ4" + }, + "outputs": [ + + ], + "source": [ + "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", + "\n", + "input_index = interpreter_fp16.get_input_details()[0][\"index\"]\n", + "output_index = interpreter_fp16.get_output_details()[0][\"index\"]\n", + "\n", + "interpreter_fp16.set_tensor(input_index, test_image)\n", + "interpreter_fp16.invoke()\n", + "predictions = interpreter_fp16.get_tensor(output_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CIH7G_MwbY2x" + }, + "outputs": [ + + ], + "source": [ + "plt.imshow(test_images[0])\n", + "template = \"True:{true}, predicted:{predict}\"\n", + "_ = plt.title(template.format(true= str(test_labels[0]),\n", + " predict=str(np.argmax(predictions[0]))))\n", + "plt.grid(False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LwN7uIdCd8Gw" + }, + "source": [ + "### Avalie os modelos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "05aeAuWjvjPx" + }, + "outputs": [ + + ], + "source": [ + "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", + "def evaluate_model(interpreter):\n", + " input_index = interpreter.get_input_details()[0][\"index\"]\n", + " output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + " # Run predictions on every image in the \"test\" dataset.\n", + " prediction_digits = []\n", + " for test_image in test_images:\n", + " # Pre-processing: add batch dimension and convert to float32 to match with\n", + " # the model's input data format.\n", + " test_image = np.expand_dims(test_image, axis=0).astype(np.float32)\n", + " interpreter.set_tensor(input_index, test_image)\n", + "\n", + " # Run inference.\n", + " interpreter.invoke()\n", + "\n", + " # Post-processing: remove batch dimension and find the digit with highest\n", + " # probability.\n", + " output = interpreter.tensor(output_index)\n", + " digit = np.argmax(output()[0])\n", + " prediction_digits.append(digit)\n", + "\n", + " # Compare prediction results with ground truth labels to calculate accuracy.\n", + " accurate_count = 0\n", + " for index in range(len(prediction_digits)):\n", + " if prediction_digits[index] == test_labels[index]:\n", + " accurate_count += 1\n", + " accuracy = accurate_count * 1.0 / len(prediction_digits)\n", + "\n", + " return accuracy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "T5mWkSbMcU5z" + }, + "outputs": [ + + ], + "source": [ + "print(evaluate_model(interpreter))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Km3cY9ry8ZlG" + }, + "source": [ + "Repita a avaliação no modelo quantizado em float16 para obter o seguinte:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-9cnwiPp6EGm" + }, + "outputs": [ + + ], + "source": [ + "# NOTE: Colab runs on server CPUs. At the time of writing this, TensorFlow Lite\n", + "# doesn't have super optimized server CPU kernels. For this reason this may be\n", + "# slower than the above float interpreter. But for mobile CPUs, considerable\n", + "# speedup can be observed.\n", + "print(evaluate_model(interpreter_fp16))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L7lfxkor8pgv" + }, + "source": [ + "Nesse exemplo, você quantizou um modelo em float16 sem nenhuma diferença na exatidão.\n", + "\n", + "Também é possível avaliar o modelo quantizado FP16 na GPU. Para realizar toda a aritmética com os valores de precisão reduzidos, crie a estrutura `TfLiteGPUDelegateOptions` no seu aplicativo e defina `precision_loss_allowed` como `1`, da seguinte maneira:\n", + "\n", + "```\n", + "//Prepare GPU delegate.\n", + "const TfLiteGpuDelegateOptions options = {\n", + " .metadata = NULL,\n", + " .compile_options = {\n", + " .precision_loss_allowed = 1, // FP16\n", + " .preferred_gl_object_type = TFLITE_GL_OBJECT_TYPE_FASTEST,\n", + " .dynamic_batch_enabled = 0, // Not fully functional yet\n", + " },\n", + "};\n", + "```\n", + "\n", + "Encontre documentação detalhada sobre o delegado de GPU do TensorFlow Lite e como usá-lo no seu aplicativo [aqui](https://www.tensorflow.org/lite/performance/gpu_advanced?source=post_page---------------------------)." + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "post_training_float16_quant.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/performance/post_training_integer_quant.ipynb b/site/pt-br/lite/performance/post_training_integer_quant.ipynb new file mode 100644 index 0000000000..80af883760 --- /dev/null +++ b/site/pt-br/lite/performance/post_training_integer_quant.ipynb @@ -0,0 +1,735 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "_DDaAex5Q7u-" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "W1dWWdNHQ9L0" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Y8E0lw5eYWm" + }, + "source": [ + "# Quantização de números inteiros pós-treinamento" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CIGrZZPTZVeO" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTC1rDAuei_1" + }, + "source": [ + "## Visão geral\n", + "\n", + "A quantização de números inteiros é uma estratégia de otimização que converte números de ponto flutuante de 32 bits (como pesos e saídas de ativação) para os números de ponto fixo de 8 bits mais próximos. Isso resulta em um modelo menor e maior velocidade de inferência, que é importante para dispositivos de baixa energia como [microcontroladores](https://www.tensorflow.org/lite/microcontrollers). Esse formato de dados também é exigido por aceleradores somente números inteiros, como o [Edge TPU](https://coral.ai/).\n", + "\n", + "Neste tutorial, você vai treinar um modelo MNIST do zero, convertê-lo em um arquivo do TensorFlow Lite e aplicar a [quantização pós-treinamento](https://www.tensorflow.org/lite/performance/post_training_quantization). Por fim, você vai verificar a exatidão do modelo convertido e compará-la ao modelo float original.\n", + "\n", + "Na verdade, você tem várias opções para o quanto quer quantizar o modelo. Neste tutorial, você vai realizar a \"quantização de números inteiros\", que converte todos os pesos e saídas de ativação em dados de números inteiros de 8 bits — enquanto outras estratégias podem deixar alguns dados em ponto flutuante.\n", + "\n", + "Para saber mais sobre as diversas estratégias de quantização, leia sobre a [otimização de modelo do TensorFlow Lite](https://www.tensorflow.org/lite/performance/model_optimization).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dDqqUIZjZjac" + }, + "source": [ + "## Configuração" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "I0nR5AMEWq0H" + }, + "source": [ + "Para quantizar ambos os tensores de entrada e saída, precisamos usar as APIs adicionadas no TensorFlow 2.3:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WsN6s5L1ieNl" + }, + "outputs": [ + + ], + "source": [ + "import logging\n", + "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", + "\n", + "import tensorflow as tf\n", + "import numpy as np\n", + "print(\"TensorFlow version: \", tf.__version__)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2XsEP17Zelz9" + }, + "source": [ + "## Gere um modelo do TensorFlow" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5NMaNZQCkW9X" + }, + "source": [ + "Vamos criar um modelo simples para classificar números do [dataset MNIST](https://www.tensorflow.org/datasets/catalog/mnist).\n", + "\n", + "Este treinamento não levará muito tempo, porque o modelo será treinado por apenas 5 épocas, com uma exatidão de aproximadamente 98%." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "eMsw_6HujaqM" + }, + "outputs": [ + + ], + "source": [ + "# Load MNIST dataset\n", + "mnist = tf.keras.datasets.mnist\n", + "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", + "\n", + "# Normalize the input image so that each pixel value is between 0 to 1.\n", + "train_images = train_images.astype(np.float32) / 255.0\n", + "test_images = test_images.astype(np.float32) / 255.0\n", + "\n", + "# Define the model architecture\n", + "model = tf.keras.Sequential([\n", + " tf.keras.layers.InputLayer(input_shape=(28, 28)),\n", + " tf.keras.layers.Reshape(target_shape=(28, 28, 1)),\n", + " tf.keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation='relu'),\n", + " tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " tf.keras.layers.Flatten(),\n", + " tf.keras.layers.Dense(10)\n", + "])\n", + "\n", + "# Train the digit classification model\n", + "model.compile(optimizer='adam',\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(\n", + " from_logits=True),\n", + " metrics=['accuracy'])\n", + "model.fit(\n", + " train_images,\n", + " train_labels,\n", + " epochs=5,\n", + " validation_data=(test_images, test_labels)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KuTEoGFYd8aM" + }, + "source": [ + "## Converta para um modelo do TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xl8_fzVAZwOh" + }, + "source": [ + "Agora você pode converter o modelo treinado para o formato do TensorFlow Lite usando o [Conversor](https://www.tensorflow.org/lite/models/convert) do TensorFlow Lite e aplicar níveis variados de quantização.\n", + "\n", + "Esteja ciente de que algumas versões de quantização deixam alguns dados em formato float. Por isso, as seções a seguir mostram cada opção com níveis crescentes de quantização, até obter um modelo inteiramente de dados int8 ou uint8. (Observe que duplicamos um pouco do código em cada seção para você ver todas as etapas de quantização das opções.)\n", + "\n", + "Primeiro, um modelo convertido sem nenhuma quantização:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_i8B2nDZmAgQ" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "\n", + "tflite_model = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7BONhYtYocQY" + }, + "source": [ + "Agora, é um modelo do TensorFlow Lite, mas ainda está usando valores float de 32 bits para todos os dados de parâmetros." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jPYZwgZTwJMT" + }, + "source": [ + "### Converta usando a quantização de intervalo dinâmico\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hjvq1vpJd4U_" + }, + "source": [ + "Ative a flag `optimizations` padrão para quantizar todos os parâmetros fixos (como pesos):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HEZ6ET1AHAS3" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "\n", + "tflite_model_quant = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "o5wuE-RcdX_3" + }, + "source": [ + "Agora, o modelo está um pouco menor com pesos quantizados, mas os outros dados variáveis ainda estão em formato float." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UgKDdnHQEhpb" + }, + "source": [ + "### Converta usando a quantização com fallback de float" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rTe8avZJHMDO" + }, + "source": [ + "Para quantizar os dados variáveis (como a entrada/saída do modelo e os intermediários entre camadas), você precisa fornecer um [`RepresentativeDataset`](https://www.tensorflow.org/api_docs/python/tf/lite/RepresentativeDataset). Essa é uma função geradora que oferece um conjunto de dados de entrada grande o suficiente para representar valores típicos. Ela permite que o conversor estime um intervalo dinâmico para todos os dados variáveis. (O dataset não precisa ser único em relação ao dataset de treinamento ou avaliação.) Para aceitar várias entradas, cada ponto de dados representativo é uma lista, e os elementos na lista são alimentados ao modelo de acordo com os seus índices.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FiwiWU3gHdkW" + }, + "outputs": [ + + ], + "source": [ + "def representative_data_gen():\n", + " for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):\n", + " # Model has only one input so each data point has one element.\n", + " yield [input_value]\n", + "\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen\n", + "\n", + "tflite_model_quant = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_GC3HFlptf7x" + }, + "source": [ + "Agora, todos os pesos e dados variáveis estão quantizados, e o modelo está significativamente menor em comparação com o original do TensorFlow Lite.\n", + "\n", + "No entanto, para manter a compatibilidade com os aplicativos que usam tradicionalmente os tensores de entrada e saída do modelo float, o Conversor do TensorFlow Lite deixa esses tensores em float:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "id1OEKFELQwp" + }, + "outputs": [ + + ], + "source": [ + "interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)\n", + "input_type = interpreter.get_input_details()[0]['dtype']\n", + "print('input: ', input_type)\n", + "output_type = interpreter.get_output_details()[0]['dtype']\n", + "print('output: ', output_type)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RACBJuj2XO8x" + }, + "source": [ + "Geralmente, isso é bom para a compatibilidade, mas não será compatível com dispositivos que realizam operações baseadas somente em números inteiros, como o Edge TPU.\n", + "\n", + "Além disso, o processo acima pode deixar uma operação no formato float se o TensorFlow Lite não incluir uma implementação quantizada para essa operação. Essa estratégia permite que a conversão seja concluída, para ter um modelo menor e mais eficiente, mas, novamente, não será compatível com hardware somente números inteiros. (Todas as operações nesse modelo MNIST têm uma implementação quantizada.)\n", + "\n", + "Portanto, para garantir um modelo somente números inteiros de ponta a ponta, você precisa de mais alguns parâmetros..." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FQgTqbvPvxGJ" + }, + "source": [ + "### Converta usando a quantização somente números inteiros" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mwR9keYAwArA" + }, + "source": [ + "Para quantizar os tensores de entrada e saída e fazer o conversor gerar um erro ao encontrar uma operação que não pode quantizar, converta o modelo novamente com alguns parâmetros adicionais:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kzjEjcDs3BHa" + }, + "outputs": [ + + ], + "source": [ + "def representative_data_gen():\n", + " for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):\n", + " yield [input_value]\n", + "\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_data_gen\n", + "# Ensure that if any ops can't be quantized, the converter throws an error\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n", + "# Set the input and output tensors to uint8 (APIs added in r2.3)\n", + "converter.inference_input_type = tf.uint8\n", + "converter.inference_output_type = tf.uint8\n", + "\n", + "tflite_model_quant = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wYd6NxD03yjB" + }, + "source": [ + "A quantização interna permanece a mesma que acima, mas você pode ver que os tensores de entrada e saída estão agora no formato de números inteiros:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PaNkOS-twz4k" + }, + "outputs": [ + + ], + "source": [ + "interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)\n", + "input_type = interpreter.get_input_details()[0]['dtype']\n", + "print('input: ', input_type)\n", + "output_type = interpreter.get_output_details()[0]['dtype']\n", + "print('output: ', output_type)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TO17AP84wzBb" + }, + "source": [ + "Agora, você tem um modelo quantizado de números inteiros que usa dados de números inteiros para os tensores de saída e entrada, para que seja compatível com hardware somente números inteiros, como o [Edge TPU](https://coral.ai)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sse224YJ4KMm" + }, + "source": [ + "### Salve os modelos como arquivos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4_9nZ4nv4b9P" + }, + "source": [ + "Você precisará de um arquivo `.tflite` para implantar seu modelo em outros dispositivos. Portanto, vamos salvar os modelos convertidos em arquivos e carregá-los ao realizar as inferências abaixo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BEY59dC14uRv" + }, + "outputs": [ + + ], + "source": [ + "import pathlib\n", + "\n", + "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", + "tflite_models_dir.mkdir(exist_ok=True, parents=True)\n", + "\n", + "# Save the unquantized/float model:\n", + "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", + "tflite_model_file.write_bytes(tflite_model)\n", + "# Save the quantized model:\n", + "tflite_model_quant_file = tflite_models_dir/\"mnist_model_quant.tflite\"\n", + "tflite_model_quant_file.write_bytes(tflite_model_quant)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9t9yaTeF9fyM" + }, + "source": [ + "## Execute os modelos do TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L8lQHMp_asCq" + }, + "source": [ + "Agora, vamos realizar as inferências usando o [`Interpreter`](https://www.tensorflow.org/api_docs/python/tf/lite/Interpreter) do TensorFlow Lite para comparar as exatidões dos modelos.\n", + "\n", + "Primeiro, precisamos de uma função que realize a inferência com um determinado modelo e imagens, para depois retornar as previsões:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "X092SbeWfd1A" + }, + "outputs": [ + + ], + "source": [ + "# Helper function to run inference on a TFLite model\n", + "def run_tflite_model(tflite_file, test_image_indices):\n", + " global test_images\n", + "\n", + " # Initialize the interpreter\n", + " interpreter = tf.lite.Interpreter(model_path=str(tflite_file))\n", + " interpreter.allocate_tensors()\n", + "\n", + " input_details = interpreter.get_input_details()[0]\n", + " output_details = interpreter.get_output_details()[0]\n", + "\n", + " predictions = np.zeros((len(test_image_indices),), dtype=int)\n", + " for i, test_image_index in enumerate(test_image_indices):\n", + " test_image = test_images[test_image_index]\n", + " test_label = test_labels[test_image_index]\n", + "\n", + " # Check if the input type is quantized, then rescale input data to uint8\n", + " if input_details['dtype'] == np.uint8:\n", + " input_scale, input_zero_point = input_details[\"quantization\"]\n", + " test_image = test_image / input_scale + input_zero_point\n", + "\n", + " test_image = np.expand_dims(test_image, axis=0).astype(input_details[\"dtype\"])\n", + " interpreter.set_tensor(input_details[\"index\"], test_image)\n", + " interpreter.invoke()\n", + " output = interpreter.get_tensor(output_details[\"index\"])[0]\n", + "\n", + " predictions[i] = output.argmax()\n", + "\n", + " return predictions\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2opUt_JTdyEu" + }, + "source": [ + "### Teste os modelos em uma imagem\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QpPpFPaz7eEM" + }, + "source": [ + "Agora, vamos comparar o desempenho dos modelos float e quantizado:\n", + "\n", + "- `tflite_model_file` é o modelo original do TensorFlow Lite com os dados de ponto flutuante.\n", + "- `tflite_model_quant_file` é o último modelo que convertemos usando a quantização somente números inteiros (ele usa dados uint8 para a entrada e saída).\n", + "\n", + "Vamos criar outra função para imprimir nossas previsões:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zR2cHRUcUZ6e" + }, + "outputs": [ + + ], + "source": [ + "import matplotlib.pylab as plt\n", + "\n", + "# Change this to test a different image\n", + "test_image_index = 1\n", + "\n", + "## Helper function to test the models on one image\n", + "def test_model(tflite_file, test_image_index, model_type):\n", + " global test_labels\n", + "\n", + " predictions = run_tflite_model(tflite_file, [test_image_index])\n", + "\n", + " plt.imshow(test_images[test_image_index])\n", + " template = model_type + \" Model \\n True:{true}, Predicted:{predict}\"\n", + " _ = plt.title(template.format(true= str(test_labels[test_image_index]), predict=str(predictions[0])))\n", + " plt.grid(False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A5OTJ_6Vcslt" + }, + "source": [ + "Agora, teste o modelo float:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iTK0x980coto" + }, + "outputs": [ + + ], + "source": [ + "test_model(tflite_model_file, test_image_index, model_type=\"Float\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "o3N6-UGl1dfE" + }, + "source": [ + "E teste o modelo quantizado:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rc1i9umMcp0t" + }, + "outputs": [ + + ], + "source": [ + "test_model(tflite_model_quant_file, test_image_index, model_type=\"Quantized\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LwN7uIdCd8Gw" + }, + "source": [ + "### Avalie os modelos em todas as imagens" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RFKOD4DG8XmU" + }, + "source": [ + "Agora, vamos executar os dois modelos usando todas as imagens de teste que carregamos no início deste tutorial:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "05aeAuWjvjPx" + }, + "outputs": [ + + ], + "source": [ + "# Helper function to evaluate a TFLite model on all images\n", + "def evaluate_model(tflite_file, model_type):\n", + " global test_images\n", + " global test_labels\n", + "\n", + " test_image_indices = range(test_images.shape[0])\n", + " predictions = run_tflite_model(tflite_file, test_image_indices)\n", + "\n", + " accuracy = (np.sum(test_labels== predictions) * 100) / len(test_images)\n", + "\n", + " print('%s model accuracy is %.4f%% (Number of test samples=%d)' % (\n", + " model_type, accuracy, len(test_images)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xnFilQpBuMh5" + }, + "source": [ + "Avalie o modelo float:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "T5mWkSbMcU5z" + }, + "outputs": [ + + ], + "source": [ + "evaluate_model(tflite_model_file, model_type=\"Float\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Km3cY9ry8ZlG" + }, + "source": [ + "Avalie o modelo quantizado:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-9cnwiPp6EGm" + }, + "outputs": [ + + ], + "source": [ + "evaluate_model(tflite_model_quant_file, model_type=\"Quantized\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L7lfxkor8pgv" + }, + "source": [ + "Agora, você tem um modelo quantizado de números inteiros com quase nenhuma diferença na exatidão, em comparação com o modelo float.\n", + "\n", + "Para saber mais sobre outras estratégias de quantização, leia sobre a [otimização de modelo do TensorFlow Lite](https://www.tensorflow.org/lite/performance/model_optimization)." + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "post_training_integer_quant.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb b/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb new file mode 100644 index 0000000000..1b8e900495 --- /dev/null +++ b/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb @@ -0,0 +1,626 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "c8Cx-rUMVX25" + }, + "source": [ + "##### Copyright 2020 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "I9sUhVL_VZNO" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Y8E0lw5eYWm" + }, + "source": [ + "# Quantização de números inteiros pós-treinamento com ativações int16" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CGuqeuPSVNo-" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTC1rDAuei_1" + }, + "source": [ + "## Visão geral\n", + "\n", + "O [TensorFlow Lite](https://www.tensorflow.org/lite/) agora é compatível com a conversão de pesos e ativações de valores de número inteiro de 16 bits em 8 bits ao converter o modelo do TensorFlow para o formato flatbuffer do TensorFlow Lite. Chamamos isso de \"modo de quantização 16x8\". Esse modo pode melhorar significativamente a exatidão do modelo quantizado e também reduzir o tamanho do modelo em 3 a 4 vezes. Além disso, esse modelo totalmente quantizado pode ser consumido por aceleradores de hardware somente números inteiros.\n", + "\n", + "Alguns exemplos de modelos que se beneficiam desse modo de quantização pós-treinamento:\n", + "\n", + "- super-resolução,\n", + "- processamento de sinais de áudio, como cancelamento de ruído e beamforming,\n", + "- remoção de ruído de imagens,\n", + "- reconstrução em HDR a partir de uma única imagem\n", + "\n", + "Neste tutorial, você vai treinar um modelo MNIST do zero, verificar a exatidão no TensorFlow e converter o modelo em um flatbuffer do TensorFlow Lite usando esse modo. No final, você vai verificar a exatidão do modelo convertido e compará-lo ao modelo float32 original. Observe que este exemplo demonstra o uso desse modo e não mostra benefícios em relação a outras técnicas de quantização disponíveis no TensorFlow Lite." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2XsEP17Zelz9" + }, + "source": [ + "## Crie um modelo MNIST" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dDqqUIZjZjac" + }, + "source": [ + "### Configuração" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gyqAw1M9lyab" + }, + "outputs": [ + + ], + "source": [ + "import logging\n", + "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", + "\n", + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "import numpy as np\n", + "import pathlib" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "srTSFKjn1tMp" + }, + "source": [ + "Verifique se o modo de quantização 16x8 está disponível: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "c6nb7OPlXs_3" + }, + "outputs": [ + + ], + "source": [ + "tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eQ6Q0qqKZogR" + }, + "source": [ + "### Treine e exporte o modelo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hWSAjQWagIHl" + }, + "outputs": [ + + ], + "source": [ + "# Load MNIST dataset\n", + "mnist = keras.datasets.mnist\n", + "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", + "\n", + "# Normalize the input image so that each pixel value is between 0 to 1.\n", + "train_images = train_images / 255.0\n", + "test_images = test_images / 255.0\n", + "\n", + "# Define the model architecture\n", + "model = keras.Sequential([\n", + " keras.layers.InputLayer(input_shape=(28, 28)),\n", + " keras.layers.Reshape(target_shape=(28, 28, 1)),\n", + " keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),\n", + " keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " keras.layers.Flatten(),\n", + " keras.layers.Dense(10)\n", + "])\n", + "\n", + "# Train the digit classification model\n", + "model.compile(optimizer='adam',\n", + " loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['accuracy'])\n", + "model.fit(\n", + " train_images,\n", + " train_labels,\n", + " epochs=1,\n", + " validation_data=(test_images, test_labels)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5NMaNZQCkW9X" + }, + "source": [ + "Para o exemplo, você treinou o modelo por apenas uma única época, então ele só treina com uma exatidão de aproximadamente 96%." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xl8_fzVAZwOh" + }, + "source": [ + "### Converta para um modelo do TensorFlow Lite\n", + "\n", + "Usando o [Conversor](https://www.tensorflow.org/lite/models/convert) do TensorFlow Lite, você pode converter o modelo treinado em um modelo do TensorFlow Lite.\n", + "\n", + "Agora, converta o modelo usando o `TFliteConverter` no formato float32 padrão:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_i8B2nDZmAgQ" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "tflite_model = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F2o2ZfF0aiCx" + }, + "source": [ + "Escreva em um arquivo `.tflite`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vptWZq2xnclo" + }, + "outputs": [ + + ], + "source": [ + "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", + "tflite_models_dir.mkdir(exist_ok=True, parents=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ie9pQaQrn5ue" + }, + "outputs": [ + + ], + "source": [ + "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", + "tflite_model_file.write_bytes(tflite_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7BONhYtYocQY" + }, + "source": [ + "Em vez disso, para quantizar o modelo no modo de quantização 16x8, primeiro defina a flag `optimizations` para usar as otimizações padrão. Em seguida, especifique que o modo de quantização 16x8 é a operação compatível exigida na especificação de destino:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HEZ6ET1AHAS3" + }, + "outputs": [ + + ], + "source": [ + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zLxQwZq9CpN7" + }, + "source": [ + "Como no caso da quantização pós-treinamento int8, é possível produzir um modelo totalmente quantizado de número inteiro ao definir as opções `inference_input(output)_type` do conversor como tf.int16." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yZekFJC5-fOG" + }, + "source": [ + "Configure os dados de calibração:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Y3a6XFqvHbYM" + }, + "outputs": [ + + ], + "source": [ + "mnist_train, _ = tf.keras.datasets.mnist.load_data()\n", + "images = tf.cast(mnist_train[0], tf.float32) / 255.0\n", + "mnist_ds = tf.data.Dataset.from_tensor_slices((images)).batch(1)\n", + "def representative_data_gen():\n", + " for input_value in mnist_ds.take(100):\n", + " # Model has only one input so each data point has one element.\n", + " yield [input_value]\n", + "converter.representative_dataset = representative_data_gen" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xW84iMYjHd9t" + }, + "source": [ + "Por fim, converta o modelo normalmente. Observe que, por padrão, o modelo convertido ainda usará a entrada e as saídas de float para a conveniência da invocação." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yuNfl3CoHNK3" + }, + "outputs": [ + + ], + "source": [ + "tflite_16x8_model = converter.convert()\n", + "tflite_model_16x8_file = tflite_models_dir/\"mnist_model_quant_16x8.tflite\"\n", + "tflite_model_16x8_file.write_bytes(tflite_16x8_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PhMmUTl4sbkz" + }, + "source": [ + "O arquivo resultante tem aproximadamente `1/3` do tamanho." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JExfcfLDscu4" + }, + "outputs": [ + + ], + "source": [ + "!ls -lh {tflite_models_dir}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L8lQHMp_asCq" + }, + "source": [ + "## Execute os modelos do TensorFlow Lite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-5l6-ciItvX6" + }, + "source": [ + "Execute o modelo do TensorFlow Lite usando o interpretador do TensorFlow Lite em Python." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ap_jE7QRvhPf" + }, + "source": [ + "### Carregue o modelo nos interpretadores" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Jn16Rc23zTss" + }, + "outputs": [ + + ], + "source": [ + "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", + "interpreter.allocate_tensors()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J8Pztk1mvNVL" + }, + "outputs": [ + + ], + "source": [ + "interpreter_16x8 = tf.lite.Interpreter(model_path=str(tflite_model_16x8_file))\n", + "interpreter_16x8.allocate_tensors()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2opUt_JTdyEu" + }, + "source": [ + "### Teste os modelos em uma imagem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AKslvo2kwWac" + }, + "outputs": [ + + ], + "source": [ + "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", + "\n", + "input_index = interpreter.get_input_details()[0][\"index\"]\n", + "output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + "interpreter.set_tensor(input_index, test_image)\n", + "interpreter.invoke()\n", + "predictions = interpreter.get_tensor(output_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XZClM2vo3_bm" + }, + "outputs": [ + + ], + "source": [ + "import matplotlib.pylab as plt\n", + "\n", + "plt.imshow(test_images[0])\n", + "template = \"True:{true}, predicted:{predict}\"\n", + "_ = plt.title(template.format(true= str(test_labels[0]),\n", + " predict=str(np.argmax(predictions[0]))))\n", + "plt.grid(False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3gwhv4lKbYZ4" + }, + "outputs": [ + + ], + "source": [ + "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", + "\n", + "input_index = interpreter_16x8.get_input_details()[0][\"index\"]\n", + "output_index = interpreter_16x8.get_output_details()[0][\"index\"]\n", + "\n", + "interpreter_16x8.set_tensor(input_index, test_image)\n", + "interpreter_16x8.invoke()\n", + "predictions = interpreter_16x8.get_tensor(output_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CIH7G_MwbY2x" + }, + "outputs": [ + + ], + "source": [ + "plt.imshow(test_images[0])\n", + "template = \"True:{true}, predicted:{predict}\"\n", + "_ = plt.title(template.format(true= str(test_labels[0]),\n", + " predict=str(np.argmax(predictions[0]))))\n", + "plt.grid(False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LwN7uIdCd8Gw" + }, + "source": [ + "### Avalie os modelos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "05aeAuWjvjPx" + }, + "outputs": [ + + ], + "source": [ + "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", + "def evaluate_model(interpreter):\n", + " input_index = interpreter.get_input_details()[0][\"index\"]\n", + " output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + " # Run predictions on every image in the \"test\" dataset.\n", + " prediction_digits = []\n", + " for test_image in test_images:\n", + " # Pre-processing: add batch dimension and convert to float32 to match with\n", + " # the model's input data format.\n", + " test_image = np.expand_dims(test_image, axis=0).astype(np.float32)\n", + " interpreter.set_tensor(input_index, test_image)\n", + "\n", + " # Run inference.\n", + " interpreter.invoke()\n", + "\n", + " # Post-processing: remove batch dimension and find the digit with highest\n", + " # probability.\n", + " output = interpreter.tensor(output_index)\n", + " digit = np.argmax(output()[0])\n", + " prediction_digits.append(digit)\n", + "\n", + " # Compare prediction results with ground truth labels to calculate accuracy.\n", + " accurate_count = 0\n", + " for index in range(len(prediction_digits)):\n", + " if prediction_digits[index] == test_labels[index]:\n", + " accurate_count += 1\n", + " accuracy = accurate_count * 1.0 / len(prediction_digits)\n", + "\n", + " return accuracy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "T5mWkSbMcU5z" + }, + "outputs": [ + + ], + "source": [ + "print(evaluate_model(interpreter))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Km3cY9ry8ZlG" + }, + "source": [ + "Repita a avaliação no modelo quantizado em 16x8:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-9cnwiPp6EGm" + }, + "outputs": [ + + ], + "source": [ + "# NOTE: This quantization mode is an experimental post-training mode,\n", + "# it does not have any optimized kernels implementations or\n", + "# specialized machine learning hardware accelerators. Therefore,\n", + "# it could be slower than the float interpreter.\n", + "print(evaluate_model(interpreter_16x8))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L7lfxkor8pgv" + }, + "source": [ + "Nesse exemplo, você quantizou um modelo em 16x8 sem nenhuma diferença na exatidão, mas com um tamanho 3x menor.\n" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "post_training_integer_quant_16x8.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/performance/post_training_quant.ipynb b/site/pt-br/lite/performance/post_training_quant.ipynb new file mode 100644 index 0000000000..4422ed8921 --- /dev/null +++ b/site/pt-br/lite/performance/post_training_quant.ipynb @@ -0,0 +1,586 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "_-GR0EDHM1SO" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "R3yYtBPkM2qZ" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Y8E0lw5eYWm" + }, + "source": [ + "# Quantização de intervalo dinâmico pós-treinamento" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CIGrZZPTZVeO" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + " Ver modelo do TF Hub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTC1rDAuei_1" + }, + "source": [ + "## Visão geral\n", + "\n", + "O [TensorFlow Lite](https://www.tensorflow.org/lite/) é agora compatível com a conversão de pesos para a precisão de 8 bits como parte da conversão do modelo do GraphDefs do TensorFlow para o formato de flatbuffer do TensorFlow Lite. A quantização de intervalo dinâmico obtém uma redução de 4 vezes no tamanho do modelo. Além disso, o TFLite é compatível com a quantização e desquantização ao vivo de ativações para permitir:\n", + "\n", + "1. O uso de kernels quantizados para uma implementação mais rápida, quando disponível.\n", + "2. A combinação de kernels de ponto flutuante com kernels quantizados para diferentes partes do grafo.\n", + "\n", + "As ativações são sempre armazenadas em ponto flutuante. Para operações compatíveis com kernels quantizados, as ativações são quantizadas dinamicamente para a precisão de 8 bits antes do processamento e são desquantizadas para a precisão de float após o processamento. Dependendo do modelo que está sendo convertido, isso pode proporcionar um speedup em relação à computação pura de ponto flutuante.\n", + "\n", + "Em contraste com o [treinamento consciente de quantização](https://github.com/tensorflow/tensorflow/tree/r1.14/tensorflow/contrib/quantize), os pesos são quantizados pós-treinamento e as ativações são quantizadas dinamicamente durante a inferência nesse método. Portanto, os pesos do modelo não são treinados novamente para compensar os erros induzidos pela quantização. É importante conferir a exatidão do modelo quantizado para garantir que a degradação seja aceitável.\n", + "\n", + "Neste tutorial, você vai treinar um modelo MNIST do zero, verificar a exatidão no TensorFlow e converter o modelo em um flatbuffer do TensorFlow Lite com a quantização de intervalo dinâmico. Por fim, você vai conferir a exatidão do modelo convertido e compará-lo ao modelo float original." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2XsEP17Zelz9" + }, + "source": [ + "## Crie um modelo MNIST" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dDqqUIZjZjac" + }, + "source": [ + "### Configuração" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gyqAw1M9lyab" + }, + "outputs": [ + + ], + "source": [ + "import logging\n", + "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", + "\n", + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "import numpy as np\n", + "import pathlib" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eQ6Q0qqKZogR" + }, + "source": [ + "### Treine um modelo do TensorFlow" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hWSAjQWagIHl" + }, + "outputs": [ + + ], + "source": [ + "# Load MNIST dataset\n", + "mnist = keras.datasets.mnist\n", + "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n", + "\n", + "# Normalize the input image so that each pixel value is between 0 to 1.\n", + "train_images = train_images / 255.0\n", + "test_images = test_images / 255.0\n", + "\n", + "# Define the model architecture\n", + "model = keras.Sequential([\n", + " keras.layers.InputLayer(input_shape=(28, 28)),\n", + " keras.layers.Reshape(target_shape=(28, 28, 1)),\n", + " keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),\n", + " keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " keras.layers.Flatten(),\n", + " keras.layers.Dense(10)\n", + "])\n", + "\n", + "# Train the digit classification model\n", + "model.compile(optimizer='adam',\n", + " loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=['accuracy'])\n", + "model.fit(\n", + " train_images,\n", + " train_labels,\n", + " epochs=1,\n", + " validation_data=(test_images, test_labels)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5NMaNZQCkW9X" + }, + "source": [ + "Para o exemplo, como você treinou o modelo por apenas uma única época, ele só treina com uma exatidão de aproximadamente 96%.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xl8_fzVAZwOh" + }, + "source": [ + "### Converta para um modelo do TensorFlow Lite\n", + "\n", + "Usando o [Conversor](https://www.tensorflow.org/lite/models/convert) do TensorFlow Lite, você pode converter o modelo treinado em um modelo do TensorFlow Lite.\n", + "\n", + "Agora carregue o modelo usando o `TFLiteConverter`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_i8B2nDZmAgQ" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "tflite_model = converter.convert()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F2o2ZfF0aiCx" + }, + "source": [ + "Escreva em um arquivo .tflite:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vptWZq2xnclo" + }, + "outputs": [ + + ], + "source": [ + "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", + "tflite_models_dir.mkdir(exist_ok=True, parents=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ie9pQaQrn5ue" + }, + "outputs": [ + + ], + "source": [ + "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", + "tflite_model_file.write_bytes(tflite_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7BONhYtYocQY" + }, + "source": [ + "Para quantizar o modelo na exportação, configure a flag `optimizations` para otimizar o tamanho:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "g8PUvLWDlmmz" + }, + "outputs": [ + + ], + "source": [ + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "tflite_quant_model = converter.convert()\n", + "tflite_model_quant_file = tflite_models_dir/\"mnist_model_quant.tflite\"\n", + "tflite_model_quant_file.write_bytes(tflite_quant_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PhMmUTl4sbkz" + }, + "source": [ + "O arquivo resultante tem aproximadamente `1/4` do tamanho." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JExfcfLDscu4" + }, + "outputs": [ + + ], + "source": [ + "!ls -lh {tflite_models_dir}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L8lQHMp_asCq" + }, + "source": [ + "## Execute os modelos do TFLite\n", + "\n", + "Execute o modelo do TensorFlow Lite usando o interpretador do TensorFlow Lite em Python.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ap_jE7QRvhPf" + }, + "source": [ + "### Carregue o modelo em um interpretador" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Jn16Rc23zTss" + }, + "outputs": [ + + ], + "source": [ + "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", + "interpreter.allocate_tensors()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J8Pztk1mvNVL" + }, + "outputs": [ + + ], + "source": [ + "interpreter_quant = tf.lite.Interpreter(model_path=str(tflite_model_quant_file))\n", + "interpreter_quant.allocate_tensors()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2opUt_JTdyEu" + }, + "source": [ + "### Teste o modelo em uma imagem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AKslvo2kwWac" + }, + "outputs": [ + + ], + "source": [ + "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", + "\n", + "input_index = interpreter.get_input_details()[0][\"index\"]\n", + "output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + "interpreter.set_tensor(input_index, test_image)\n", + "interpreter.invoke()\n", + "predictions = interpreter.get_tensor(output_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XZClM2vo3_bm" + }, + "outputs": [ + + ], + "source": [ + "import matplotlib.pylab as plt\n", + "\n", + "plt.imshow(test_images[0])\n", + "template = \"True:{true}, predicted:{predict}\"\n", + "_ = plt.title(template.format(true= str(test_labels[0]),\n", + " predict=str(np.argmax(predictions[0]))))\n", + "plt.grid(False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LwN7uIdCd8Gw" + }, + "source": [ + "### Avalie os modelos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "05aeAuWjvjPx" + }, + "outputs": [ + + ], + "source": [ + "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", + "def evaluate_model(interpreter):\n", + " input_index = interpreter.get_input_details()[0][\"index\"]\n", + " output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + " # Run predictions on every image in the \"test\" dataset.\n", + " prediction_digits = []\n", + " for test_image in test_images:\n", + " # Pre-processing: add batch dimension and convert to float32 to match with\n", + " # the model's input data format.\n", + " test_image = np.expand_dims(test_image, axis=0).astype(np.float32)\n", + " interpreter.set_tensor(input_index, test_image)\n", + "\n", + " # Run inference.\n", + " interpreter.invoke()\n", + "\n", + " # Post-processing: remove batch dimension and find the digit with highest\n", + " # probability.\n", + " output = interpreter.tensor(output_index)\n", + " digit = np.argmax(output()[0])\n", + " prediction_digits.append(digit)\n", + "\n", + " # Compare prediction results with ground truth labels to calculate accuracy.\n", + " accurate_count = 0\n", + " for index in range(len(prediction_digits)):\n", + " if prediction_digits[index] == test_labels[index]:\n", + " accurate_count += 1\n", + " accuracy = accurate_count * 1.0 / len(prediction_digits)\n", + "\n", + " return accuracy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DqXBnDfJ7qxL" + }, + "outputs": [ + + ], + "source": [ + "print(evaluate_model(interpreter))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Km3cY9ry8ZlG" + }, + "source": [ + "Repita a avaliação no modelo quantizado em intervalo dinâmico para obter o seguinte:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-9cnwiPp6EGm" + }, + "outputs": [ + + ], + "source": [ + "print(evaluate_model(interpreter_quant))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L7lfxkor8pgv" + }, + "source": [ + "Nesse exemplo, o modelo comprimido não tem nenhuma diferença na exatidão." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M0o1FtmWeKZm" + }, + "source": [ + "## Otimizando um modelo existente\n", + "\n", + "As resnets com camadas de pré-ativação (Resnet-v2) são amplamente usadas para aplicativos de visão. O grafo congelado pré-treinado para a resnet-v2-101 está disponível no [TensorFlow Hub](https://tfhub.dev/google/imagenet/resnet_v2_101/classification/4).\n", + "\n", + "Você pode converter o grafo congelado em um flatbuffer do TensorFlow Lite com a quantização da seguinte maneira:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jrXZxSJiJfYN" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow_hub as hub\n", + "\n", + "resnet_v2_101 = tf.keras.Sequential([\n", + " keras.layers.InputLayer(input_shape=(224, 224, 3)),\n", + " hub.KerasLayer(\"https://tfhub.dev/google/imagenet/resnet_v2_101/classification/4\")\n", + "])\n", + "\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(resnet_v2_101)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LwnV4KxwVEoG" + }, + "outputs": [ + + ], + "source": [ + "# Convert to TF Lite without quantization\n", + "resnet_tflite_file = tflite_models_dir/\"resnet_v2_101.tflite\"\n", + "resnet_tflite_file.write_bytes(converter.convert())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2qkZD0VoVExe" + }, + "outputs": [ + + ], + "source": [ + "# Convert to TF Lite with quantization\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "resnet_quantized_tflite_file = tflite_models_dir/\"resnet_v2_101_quantized.tflite\"\n", + "resnet_quantized_tflite_file.write_bytes(converter.convert())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vhOjeg1x9Knp" + }, + "outputs": [ + + ], + "source": [ + "!ls -lh {tflite_models_dir}/*.tflite" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qqHLaqFMCjRZ" + }, + "source": [ + "O tamanho do modelo é reduzido de 171 MB para 43 MB. A exatidão dele na imagenet pode ser avaliada usando os scripts fornecidos pela [medição de exatidão do TFLite](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification).\n", + "\n", + "A exatidão top-1 do modelo otimizado é 76,8, a mesma que o modelo de ponto flutuante." + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "post_training_quant.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/performance/post_training_quantization.md b/site/pt-br/lite/performance/post_training_quantization.md new file mode 100644 index 0000000000..9a5933ad23 --- /dev/null +++ b/site/pt-br/lite/performance/post_training_quantization.md @@ -0,0 +1,213 @@ +# Quantização pós-treinamento + +A quantização pós-treinamento é uma técnica de conversão que pode reduzir o tamanho do modelo e, ao mesmo tempo, melhorar a latência do acelerador de hardware e da CPU, com pouca degradação da exatidão do modelo. Você pode quantizar um modelo float já treinado do TensorFlow ao convertê-lo para o formato TensorFlow Lite usando o [Conversor do TensorFlow Lite](../models/convert/). + +Observação: os procedimentos nesta página exigem o TensorFlow 1.15 ou mais recente. + +### Métodos de otimização + +Há várias opções de quantização pós-treinamento disponíveis. Veja esta tabela com um resumo das alternativas e dos benefícios que elas oferecem: + +Técnica | Benefícios | Hardware +--- | --- | --- +Intervalo dinâmico | 4x menor, speedup de 2-3x | CPU +: quantização : : : | | +Números inteiros | 4x menor, speedup de 3x+ | CPU, Edge TPU, +: quantização : : Microcontroladores : | | +Quantização float16 | 2x menor, GPU | CPU, GPU +: : aceleração : : | | + +A seguinte árvore de decisão pode ajudar a determinar qual método de quantização pós-treinamento é o melhor para seu caso de uso: + +![opções de otimização pós-treinamento](images/optimization.jpg) + +### Quantização de intervalo dinâmico + +A quantização de intervalo dinâmico é um ponto de partida recomendado, porque possibilita um uso menor de memória e computações mais rápidas sem precisar fornecer um dataset representativo para fazer calibração. Esse tipo de quantização quantiza estaticamente somente os pesos, de ponto flutuante para inteiro no momento da conversão, o que proporciona a precisão de 8 bits: + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+<b>converter.optimizations = [tf.lite.Optimize.DEFAULT]</b>
+tflite_quant_model = converter.convert()
+
+ +Para reduzir a latência ainda mais durante a inferência, os operadores de "intervalo dinâmico" quantizam as ativações dinamicamente com base no intervalo até 8 bits e realizam computações com pesos e ativações de 8 bits. Essa otimização fornece latências próximas às inferências inteiramente de ponto fixo. No entanto, as saídas ainda são armazenadas usando o ponto flutuante, então a maior velocidade das operações de intervalo dinâmico é menor do que uma computação inteira de ponto fixo. + +### Quantização de números inteiros + +Você pode obter ainda mais melhorias na latência, reduções no pico de uso da memória e compatibilidade com dispositivos ou aceleradores de hardware somente números inteiros ao garantir que toda a matemática do modelo seja quantizada em números inteiros. + +Para a quantização de números inteiros, você precisa calibrar ou estimar o intervalo, ou seja, (min, max) de todos os tensores de ponto flutuante no modelo. Ao contrário dos tensores constantes, como pesos e biases, os tensores variáveis, como entrada e saída do modelo e ativações (saídas de camadas intermediárias), não podem ser calibrados a menos que sejam realizados alguns ciclos de inferência. Como resultado, o conversor exige um dataset representativo para calibrá-los. Esse dataset pode ser um subset pequeno (cerca de 100 a 500 amostras) dos dados de treinamento ou validação. Consulte a função `representative_dataset()` abaixo. + +A partir da versão 2.7 do TensorFlow, você pode especificar o dataset representativo através de uma [assinatura](../guide/signatures.ipynb), como neste exemplo: + +
+def representative_dataset():
+  for data in dataset:
+    yield {
+      "image": data.image,
+      "bias": data.bias,
+    }
+
+ +Se houver mais de uma assinatura no modelo do TensorFlow, você pode especificar o dataset múltiplo ao especificar as chaves de assinatura: + +
+def representative_dataset():
+  # Feed data set for the "encode" signature.
+  for data in encode_signature_dataset:
+    yield (
+      "encode", {
+        "image": data.image,
+        "bias": data.bias,
+      }
+    )
+
+  # Feed data set for the "decode" signature.
+  for data in decode_signature_dataset:
+    yield (
+      "decode", {
+        "image": data.image,
+        "hint": data.hint,
+      },
+    )
+
+ +Você pode gerar o dataset representativo ao fornecer uma lista de tensores de entrada: + +
+def representative_dataset():
+  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
+    yield [tf.dtypes.cast(data, tf.float32)]
+
+ +Desde a versão 2.7 do TensorFlow, recomendamos usar uma abordagem baseada na assinatura em vez de baseada na lista de tensores de entrada, porque a ordem dos tensores pode ser facilmente invertida. + +Para fins de teste, você pode usar um dataset falso da seguinte maneira: + +
+def representative_dataset():
+    for _ in range(100):
+      data = np.random.rand(1, 244, 244, 3)
+      yield [data.astype(np.float32)]
+ 
+ +#### Números inteiros com fallback de float (usando a entrada/saída de float padrão) + +Para fazer a quantização de números inteiros de um modelo, mas usar operadores float quando eles não tiverem uma implementação de números inteiros (para garantir que a conversão ocorra sem problemas), use as seguintes etapas: + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+<b>converter.optimizations = [tf.lite.Optimize.DEFAULT]
+converter.representative_dataset = representative_dataset</b>
+tflite_quant_model = converter.convert()
+
+ +Observação: esse `tflite_quant_model` não será compatível com dispositivos somente números inteiros (como microcontroladores de 8 bits) e aceleradores (como o Coral Edge TPU), porque a entrada e a saída ainda permanecem em float para ter a mesma interface que o modelo somente float original. + +#### Somente números inteiros + +*A criação de modelos somente números inteiros é um caso de uso comum no [TensorFlow Lite para microcontroladores](https://www.tensorflow.org/lite/microcontrollers) e [Coral Edge TPUs](https://coral.ai/).* + +Observação: a partir do 2.3.0, oferecemos suporte aos atributos `inference_input_type` e `inference_output_type`. + +Além disso, para garantir a compatibilidade com dispositivos somente números inteiros (como microcontroladores de 8 bits) e aceleradores (como o Coral Edge TPU), você pode aplicar a quantização de números inteiros a todas as operações, incluindo a entrada e a saída, ao seguir estes passos: + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+converter.optimizations = [tf.lite.Optimize.DEFAULT]
+converter.representative_dataset = representative_dataset
+<b>converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]</b>
+<b>converter.inference_input_type = tf.int8</b>  # or tf.uint8
+<b>converter.inference_output_type = tf.int8</b>  # or tf.uint8
+tflite_quant_model = converter.convert()
+
+ +### Quantização float16 + +Você pode reduzir o tamanho de um modelo de ponto flutuante ao quantizar os pesos em float16, o padrão IEEE para números de ponto flutuante de 16 bits. Para ativar a quantização float16 dos pesos, siga estas etapas: + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+<b>converter.optimizations = [tf.lite.Optimize.DEFAULT]
+converter.target_spec.supported_types = [tf.float16]</b>
+tflite_quant_model = converter.convert()
+
+ +Estas são as vantagens da quantização float16: + +- Ela reduz o tamanho do modelo pela metade (já que todos os pesos ficam a metade do tamanho original). +- Ela causa perda mínima de exatidão. +- Ela é compatível com alguns delegados (por exemplo, o delegado de GPU) que podem operar diretamente nos dados float16, resultando em uma execução mais rápida que as computações float32. + +Estas são as desvantagens da quantização float16: + +- Ela não reduz tanto a latência como a quantização de matemática de ponto fixo. +- Por padrão, um modelo quantizado float16 "desquantizará" os valores dos pesos para float32 quando executado na CPU. (Observe que o delegado de GPU não realizará essa desquantização, já que pode operar em dados float16.) + +### Somente números inteiros: ativações de 16 bits com pesos de 8 bits (experimental) + +Esse é um esquema de quantização experimental. É semelhante ao esquema "somente números inteiros", mas as ativações são quantizadas com base no intervalo até 16 bits, os pesos são quantizados em números inteiros de 18 bits e o bias é quantizado em números inteiros de 64 bits. Daqui em diante, isso será chamado de quantização 16x8. + +O principal benefício dessa quantização é que ela pode melhorar a exatidão significativamente, mas só aumentar levemente o tamanho do modelo. + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+converter.representative_dataset = representative_dataset
+<b>converter.optimizations = [tf.lite.Optimize.DEFAULT]
+converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]</b>
+tflite_quant_model = converter.convert()
+
+ +Se a quantização 16x8 não for compatível com alguns operadores no modelo, ele ainda poderá ser quantizado, mas os operadores incompatíveis são mantidos em float. A seguinte opção deve ser adicionada a target_spec para permitir isso. + +
+import tensorflow as tf
+converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+converter.representative_dataset = representative_dataset
+converter.optimizations = [tf.lite.Optimize.DEFAULT]
+converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
+<b>tf.lite.OpsSet.TFLITE_BUILTINS</b>]
+tflite_quant_model = converter.convert()
+
+ +Exemplos de casos de uso em que esse esquema de quantização oferece melhorias na exatidão: + +- super-resolução, +- processamento de sinais de áudio, como cancelamento de ruído e beamforming, +- remoção de ruído de imagens, +- reconstrução em HDR a partir de uma única imagem. + +As desvantagens dessa quantização são: + +- No momento, a inferência é perceptivelmente mais lenta que os números inteiros de 8 bits devido à ausência de implementação de kernels otimizados. +- Atualmente, é incompatível com os delegados do TFLite acelerados de hardware existentes. + +Observação: esse é um recurso experimental. + +Encontre um tutorial para esse modelo quantizado [aqui](post_training_integer_quant_16x8.ipynb). + +### Exatidão do modelo + +Como os pesos são quantizados após o treinamento, pode haver uma perda na exatidão, principalmente para redes menores. Modelos totalmente quantizados pré-treinados são fornecidos para redes específicas no [TensorFlow Hub](https://tfhub.dev/s?deployment-format=lite&q=quantized){:.external}. É importante conferir a exatidão do modelo quantizado para verificar se qualquer degradação está dentro dos limites aceitáveis. Há ferramentas para avaliar a [exatidão de modelos do TensorFlow Lite](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/evaluation/tasks){:.external}. + +Como alternativa, se a queda na exatidão for muito grande, considere usar o [treinamento consciente de quantização](https://www.tensorflow.org/model_optimization/guide/quantization/training). No entanto, para isso, é necessário fazer modificações durante o treinamento do modelo para adicionar nós de quantização falsos, enquanto as técnicas de quantização pós-treinamento nesta página usam um modelo pré-treinado existente. + +### Representação para tensores quantizados + +A quantização de 8 bits aproxima os valores de ponto flutuante usando a seguinte fórmula. + +$$real_value = (int8_value - zero_point) \times scale$$ + +A representação tem duas partes: + +- Os pesos por eixo (ou seja, por canal) ou por tensor são representados por dois valores complementares int8 no intervalo [-127, 127] com um ponto zero igual a 0. + +- As ativações/entradas por tensor são representadas por dois valores complementares int8 no intervalo [-128, 127], com um ponto zero no intervalo [-128, 127]. + +Para uma visão detalhada do nosso esquema de quantização, confira nossa [especificação de quantização](./quantization_spec). Os fornecedores de hardware que quiserem se conectar à interface de delegados do TensorFlow Lite são incentivados a implementar o esquema de quantização descrito aqui. diff --git a/site/pt-br/lite/performance/quantization_debugger.ipynb b/site/pt-br/lite/performance/quantization_debugger.ipynb new file mode 100644 index 0000000000..a4344cf142 --- /dev/null +++ b/site/pt-br/lite/performance/quantization_debugger.ipynb @@ -0,0 +1,833 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "KimMZUVqcJ8_" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "BRQ6HQ8zcV5v" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BlWzg1D9_EhW" + }, + "source": [ + "# Inspeção de erros de quantização com o depurador" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XLoHL19yb-a0" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + " Ver modelo do TF Hub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MWO_yYDGcGWY" + }, + "source": [ + "Embora a quantização de números inteiros forneça melhorias de tamanho do modelo e latência, o modelo quantizado nem sempre funcionará como esperado. Geralmente, o esperado é que a qualidade do modelo (por exemplo, exatidão, mAP, WER) seja um pouco inferior ao modelo float original. No entanto, há casos em que a qualidade do modelo pode ficar abaixo das suas expectativas ou gerar resultados totalmente errados.\n", + "\n", + "Quando ocorrer esse problema, é complicado e trabalhoso localizar a causa raiz do erro de quantização, mas corrigi-lo é ainda mais difícil. Para ajudar no processo de inspeção do modelo, o **depurador de quantização** pode ser usado para identificar as camadas problemáticas, e a **quantização seletiva** pode deixar essas camadas problemáticas em float para que a exatidão do modelo seja recuperada à custa de um benefício reduzido da quantização.\n", + "\n", + "Observação: essa API é experimental, e pode haver mudanças que causem quebras na API no decorrer das melhorias." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9kD29R1I_Mn6" + }, + "source": [ + "## Depurador de quantização\n", + "\n", + "O depurador de quantização possibilita a análise de métricas de qualidade da quantização no modelo existente. Ele pode automatizar os processos para a execução do modelo com um dataset de depuração e coletar métricas de qualidade de quantização para cada tensor.\n", + "\n", + "Observação: no momento, o depurador de quantização e a quantização seletiva só funcionam para a quantização de números inteiros com ativações int8." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "221Qon7G_PmZ" + }, + "source": [ + "### Pré-requisitos\n", + "\n", + "Se você já tem um pipeline para quantizar um modelo, tem todos os elementos necessários para executar o depurador de quantização!\n", + "\n", + "- Modelo que será quantizado\n", + "- Dataset representativo\n", + "\n", + "Além do modelo e dos dados, você precisará usar um framework de processamento de dados (por exemplo, pandas, Planilhas Google) para analisar os resultados exportados." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qTEEzJWo_iZ_" + }, + "source": [ + "### Configuração\n", + "\n", + "Esta seção prepara as bibliotecas, o modelo MobileNet v3 e o dataset de teste de 100 imagens." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "l7epUDUP_6qo" + }, + "outputs": [ + + ], + "source": [ + "# Quantization debugger is available from TensorFlow 2.7.0\n", + "!pip uninstall -y tensorflow\n", + "!pip install tf-nightly\n", + "!pip install tensorflow_datasets --upgrade # imagenet_v2 needs latest checksum" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LLsgiUZe_hIa" + }, + "outputs": [ + + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import tensorflow as tf\n", + "import tensorflow_datasets as tfds\n", + "import tensorflow_hub as hub" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "veWjO3u32vzz" + }, + "outputs": [ + + ], + "source": [ + "#@title Boilerplates and helpers\n", + "MODEL_URI = 'https://tfhub.dev/google/imagenet/mobilenet_v3_small_100_224/classification/5'\n", + "\n", + "\n", + "def process_image(data):\n", + " data['image'] = tf.image.resize(data['image'], (224, 224)) / 255.0\n", + " return data\n", + "\n", + "\n", + "# Representative dataset\n", + "def representative_dataset(dataset):\n", + "\n", + " def _data_gen():\n", + " for data in dataset.batch(1):\n", + " yield [data['image']]\n", + "\n", + " return _data_gen\n", + "\n", + "\n", + "def eval_tflite(tflite_model, dataset):\n", + " \"\"\"Evaluates tensorflow lite classification model with the given dataset.\"\"\"\n", + " interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + " interpreter.allocate_tensors()\n", + "\n", + " input_idx = interpreter.get_input_details()[0]['index']\n", + " output_idx = interpreter.get_output_details()[0]['index']\n", + "\n", + " results = []\n", + "\n", + " for data in representative_dataset(dataset)():\n", + " interpreter.set_tensor(input_idx, data[0])\n", + " interpreter.invoke()\n", + " results.append(interpreter.get_tensor(output_idx).flatten())\n", + "\n", + " results = np.array(results)\n", + " gt_labels = np.array(list(dataset.map(lambda data: data['label'] + 1)))\n", + " accuracy = (\n", + " np.sum(np.argsort(results, axis=1)[:, -5:] == gt_labels.reshape(-1, 1)) /\n", + " gt_labels.size)\n", + " print(f'Top-5 accuracy (quantized): {accuracy * 100:.2f}%')\n", + "\n", + "\n", + "model = tf.keras.Sequential([\n", + " tf.keras.layers.Input(shape=(224, 224, 3), batch_size=1),\n", + " hub.KerasLayer(MODEL_URI)\n", + "])\n", + "model.compile(\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics='sparse_top_k_categorical_accuracy')\n", + "model.build([1, 224, 224, 3])\n", + "\n", + "# Prepare dataset with 100 examples\n", + "ds = tfds.load('imagenet_v2', split='test[:1%]')\n", + "ds = ds.map(process_image)\n", + "\n", + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.representative_dataset = representative_dataset(ds)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "quantized_model = converter.convert()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7mX-R-xK4ADB" + }, + "outputs": [ + + ], + "source": [ + "test_ds = ds.map(lambda data: (data['image'], data['label'] + 1)).batch(16)\n", + "loss, acc = model.evaluate(test_ds)\n", + "print(f'Top-5 accuracy (float): {acc * 100:.2f}%')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Mnp6yBnJSCoh" + }, + "outputs": [ + + ], + "source": [ + "eval_tflite(quantized_model, ds)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Tblkk3cxxpuw" + }, + "source": [ + "Podemos ver que o modelo original tem uma exatidão top-5 muito mais alta do que nosso pequeno dataset, enquanto o modelo quantizado tem uma perda significativa na exatidão." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dBBcfCQw_Wqd" + }, + "source": [ + "### Etapa 1. Prepare o depurador\n", + "\n", + "A maneira mais fácil de usar o depurador de quantização é fornecer o `tf.lite.TFLiteConverter` usado para quantizar o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NOByihbD_NZZ" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter.representative_dataset = representative_dataset(ds)\n", + "\n", + "# my_debug_dataset should have the same format as my_representative_dataset\n", + "debugger = tf.lite.experimental.QuantizationDebugger(\n", + " converter=converter, debug_dataset=representative_dataset(ds))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9vR1IIrmQS9W" + }, + "source": [ + "### Etapa 2. Execute o depurador e obtenha os resultados\n", + "\n", + "Ao chamar `QuantizationDebugger.run()`, o depurador registrará as diferenças entre os tensores float e quantizados para o mesmo local da op e os processará com as determinadas métricas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HsUM54g-_E52" + }, + "outputs": [ + + ], + "source": [ + "debugger.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yQpX_SBUQXvr" + }, + "source": [ + "As métricas processadas podem ser acessadas com `QuantizationDebugger.layer_statistics` ou despejadas em um arquivo de texto em formato CSV com `QuantizationDebugger.layer_statistics_dump()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "U-AGYUAbQUmx" + }, + "outputs": [ + + ], + "source": [ + "RESULTS_FILE = '/tmp/debugger_results.csv'\n", + "with open(RESULTS_FILE, 'w') as f:\n", + " debugger.layer_statistics_dump(f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LQzEi6VnQaen" + }, + "outputs": [ + + ], + "source": [ + "!head /tmp/debugger_results.csv" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4np7VqU-Qfke" + }, + "source": [ + "Para cada linha no dump, o nome da op e o índice vêm primeiro, seguidos pelos parâmetros de quantização e métricas de erros (incluindo [métricas de erros definidas pelo usuário](#custom-metrics), se houver alguma). O arquivo CSV resultante pode ser usado para escolher as camadas problemáticas com grandes métricas de erros de quantização.\n", + "\n", + "Com o pandas ou outra biblioteca de processamento de dados, podemos inspecionar as métricas de erros detalhadas por camada." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XUcSqYFGQb-f" + }, + "outputs": [ + + ], + "source": [ + "layer_stats = pd.read_csv(RESULTS_FILE)\n", + "layer_stats.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7C_oHxWFOV6M" + }, + "source": [ + "### Etapa 3. Analise os dados\n", + "\n", + "Há várias maneiras de analisar os resultados. Primeiro, vamos adicionar algumas métricas úteis derivadas das saídas do depurador. (`scale` significa o fator de escala de quantização para cada tensor.)\n", + "\n", + "- Range, ou intervalo, (`256 / scale`)\n", + "- RMSE / scale, ou raiz do erro quadrático médio / escala, (`sqrt(mean_squared_error) / scale`)\n", + "\n", + "O `RMSE / scale` é próximo a `1 / sqrt(12)` (cerca de 0,289) quando a distribuição quantizada é semelhante à distribuição float original, indicando um bom modelo quantizado. Quanto maior for o valor, mais provável será que a camada não tenha sido bem quantizada." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mwviORyJN6e5" + }, + "outputs": [ + + ], + "source": [ + "layer_stats['range'] = 255.0 * layer_stats['scale']\n", + "layer_stats['rmse/scale'] = layer_stats.apply(\n", + " lambda row: np.sqrt(row['mean_squared_error']) / row['scale'], axis=1)\n", + "layer_stats[['op_name', 'range', 'rmse/scale']].head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oAAv35CdPvc4" + }, + "outputs": [ + + ], + "source": [ + "plt.figure(figsize=(15, 5))\n", + "ax1 = plt.subplot(121)\n", + "ax1.bar(np.arange(len(layer_stats)), layer_stats['range'])\n", + "ax1.set_ylabel('range')\n", + "ax2 = plt.subplot(122)\n", + "ax2.bar(np.arange(len(layer_stats)), layer_stats['rmse/scale'])\n", + "ax2.set_ylabel('rmse/scale')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8pqUQvRUWB3Q" + }, + "source": [ + "Há várias camadas com grandes intervalos, e algumas camadas com valores altos de `RMSE/scale`. Vamos obter as camadas com métricas de erros altas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UqFsUX4_Q-cE" + }, + "outputs": [ + + ], + "source": [ + "layer_stats[layer_stats['rmse/scale'] > 0.7][[\n", + " 'op_name', 'range', 'rmse/scale', 'tensor_name'\n", + "]]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DHeALFTGWl_e" + }, + "source": [ + "Com essas camadas, você pode tentar a quantização seletiva para ver se a qualidade do modelo melhora ao deixar de quantizá-las." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cvdkjsbwYC6e" + }, + "outputs": [ + + ], + "source": [ + "suspected_layers = list(\n", + " layer_stats[layer_stats['rmse/scale'] > 0.7]['tensor_name'])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W6RQw9JobOTR" + }, + "source": [ + "Além disso, pular a quantização nas primeiras camadas também ajuda a melhorar a qualidade do modelo quantizado." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ikF2bp6NZcXN" + }, + "outputs": [ + + ], + "source": [ + "suspected_layers.extend(list(layer_stats[:5]['tensor_name']))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1DfT78w6W6Li" + }, + "source": [ + "## Quantização seletiva" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-pubC-01cGEH" + }, + "source": [ + "A quantização seletiva pula alguns nós, para que o cálculo possa ser feito no domínio de ponto flutuante original. Quando as camadas corretas são puladas, podemos esperar a recuperação de um pouco da qualidade do modelo à custa de maior latência e tamanho do modelo.\n", + "\n", + "No entanto, se você estiver planejando executar modelos quantizados em aceleradores somente números inteiros (por exemplo, DSP Hexagon ou EdgeTPU), a quantização seletiva causaria a fragmentação do modelo e resultaria em uma latência de inferência mais lenta, causada principalmente pelo custo da transferência de dados entre a CPU e esses aceleradores. Para evitar isso, considere realizar o [treinamento consciente de quantização](https://www.tensorflow.org/model_optimization/guide/quantization/training) para manter todas as camadas em números inteiros, preservando a exatidão do modelo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EQFBfR7YW-oh" + }, + "source": [ + "O depurador de quantização aceita as opções `denylisted_nodes` e `denylisted_ops` para pular a quantização em camadas específicas ou todas as instâncias de determinadas ops. Usando as `suspected_layers` que preparamos na etapa anterior, podemos utilizar o depurador de quantização para obter um modelo quantizado de forma seletiva." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "K5KD0JAEbpsv" + }, + "outputs": [ + + ], + "source": [ + "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", + " denylisted_nodes=suspected_layers)\n", + "debugger = tf.lite.experimental.QuantizationDebugger(\n", + " converter=converter,\n", + " debug_dataset=representative_dataset(ds),\n", + " debug_options=debug_options)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pfj9gzv4b7h4" + }, + "outputs": [ + + ], + "source": [ + "selective_quantized_model = debugger.get_nondebug_quantized_model()\n", + "eval_tflite(selective_quantized_model, ds)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1RkfMYSHdtZy" + }, + "source": [ + "A exatidão é ainda mais baixa em comparação com o modelo float original, mas o modelo totalmente quantizado tem melhorias notáveis ao pular a quantização para cerca de 10 das 111 camadas.\n", + "\n", + "Você também pode tentar não quantizar todas as operações na mesma classe. Por exemplo, para pular a quantização em todas as operações de média, você pode passar `MEAN` a `denylisted_ops`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ruUoP7SgcLpO" + }, + "outputs": [ + + ], + "source": [ + "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", + " denylisted_ops=['MEAN'])\n", + "debugger = tf.lite.experimental.QuantizationDebugger(\n", + " converter=converter,\n", + " debug_dataset=representative_dataset(ds),\n", + " debug_options=debug_options)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oY6kb5g_cO4H" + }, + "outputs": [ + + ], + "source": [ + "selective_quantized_model = debugger.get_nondebug_quantized_model()\n", + "eval_tflite(selective_quantized_model, ds)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xa8488TeAyx-" + }, + "source": [ + "Com essas técnicas, podemos melhorar a exatidão do modelo MobileNet V3. Em seguida, vamos explorar técnicas avançadas para melhorar ainda mais a exatidão." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZD75cY9PUb2u" + }, + "source": [ + "## Usos avançados\n", + "\n", + "Com os seguintes recursos, você pode personalizar ainda mais seu pipeline de depuração." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aVj9yrQoUfGo" + }, + "source": [ + "### Métricas personalizadas\n", + "\n", + "Por padrão, o depurador de quantização emite cinco métricas para cada diferença float-quant: tamanho do tensor, desvio padrão, erro médio, erro absoluto máximo e erro quadrático médio. Você pode adicionar mais métricas personalizadas ao passá-las às opções. Para cada métrica, o resultado deverá ser um único valor float, e a métrica resultante será uma média das métricas de todos os exemplos.\n", + "\n", + "- `layer_debug_metrics`: calcula uma métrica baseada na diferença de cada saída de operação em relação às saídas de operações float e quantizadas.\n", + "- `layer_direct_compare_metrics`: em vez de só obter a diferença, calcula uma métrica baseada nos tensores float e quantizados brutos e seus parâmetros de quantização (escala, ponto zero).\n", + "- `model_debug_metrics`: **só é usada quando `float_model_(path|content)` é passado** ao depurador. Além das métricas no nível da operação, a saída da camada final é comparada à saída de referência do modelo float original." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WqmRQSxoVVwu" + }, + "outputs": [ + + ], + "source": [ + "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", + " layer_debug_metrics={\n", + " 'mean_abs_error': (lambda diff: np.mean(np.abs(diff)))\n", + " },\n", + " layer_direct_compare_metrics={\n", + " 'correlation':\n", + " lambda f, q, s, zp: (np.corrcoef(f.flatten(),\n", + " (q.flatten() - zp) / s)[0, 1])\n", + " },\n", + " model_debug_metrics={\n", + " 'argmax_accuracy': (lambda f, q: np.mean(np.argmax(f) == np.argmax(q)))\n", + " })\n", + "\n", + "debugger = tf.lite.experimental.QuantizationDebugger(\n", + " converter=converter,\n", + " debug_dataset=representative_dataset(ds),\n", + " debug_options=debug_options)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PVQ4nEicXz2l" + }, + "outputs": [ + + ], + "source": [ + "debugger.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dfKA90csX9UL" + }, + "outputs": [ + + ], + "source": [ + "CUSTOM_RESULTS_FILE = '/tmp/debugger_results.csv'\n", + "with open(CUSTOM_RESULTS_FILE, 'w') as f:\n", + " debugger.layer_statistics_dump(f)\n", + "\n", + "custom_layer_stats = pd.read_csv(CUSTOM_RESULTS_FILE)\n", + "custom_layer_stats[['op_name', 'mean_abs_error', 'correlation']].tail()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Qqq30oWsZF5b" + }, + "source": [ + "O resultado de `model_debug_metrics` pode ser visto separadamente de `debugger.model_statistics`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wrXlmzEHYhQ5" + }, + "outputs": [ + + ], + "source": [ + "debugger.model_statistics" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DqJBLIsoUyIg" + }, + "source": [ + "### Usando a API mlir_quantize (interna) para acessar recursos detalhados\n", + "\n", + "Observação: alguns recursos na seção a seguir, `TFLiteConverter._experimental_calibrate_only` e `converter.mlir_quantize`, são APIs internas experimentais e estão sujeitas a mudanças incompatíveis com versões anteriores." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VJm66Cz-XpeF" + }, + "outputs": [ + + ], + "source": [ + "from tensorflow.lite.python import convert" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2krUVzpiUp3u" + }, + "source": [ + "#### Modo de verificação do modelo inteiro\n", + "\n", + "O comportamento padrão para a geração do modelo de depuração é a verificação por camada. Nesse modo, a entrada para o par de operações float e quantizadas é da mesma fonte (operação quantizada anteriormente). Outro modo é a verificação do modelo inteiro, em que os modelos float e quantizados são separados. Esse modo seria útil para observar como o erro é propagado pelo modelo. Para ativar, defina `enable_whole_model_verify=True` para `convert.mlir_quantize` ao gerar o modelo de depuração manualmente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5zykINDlVLSg" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.representative_dataset = representative_dataset(ds)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "converter._experimental_calibrate_only = True\n", + "calibrated_model = converter.convert()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "eqvXlEiFXfSu" + }, + "outputs": [ + + ], + "source": [ + "# Note that enable_numeric_verify and enable_whole_model_verify are set.\n", + "quantized_model = convert.mlir_quantize(\n", + " calibrated_model,\n", + " enable_numeric_verify=True,\n", + " enable_whole_model_verify=True)\n", + "debugger = tf.lite.experimental.QuantizationDebugger(\n", + " quant_debug_model_content=quantized_model,\n", + " debug_dataset=representative_dataset(ds))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xQ6TFsXQVHMe" + }, + "source": [ + "#### Quantização seletiva de um modelo já calibrado\n", + "\n", + "Você pode chamar `convert.mlir_quantize` diretamente para obter o modelo quantizado seletivamente do modelo já calibrado. Isso é especialmente útil quando você quer calibrar o modelo uma vez e experimentar com várias combinações de denylist." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZCS-Fa9lbdc0" + }, + "outputs": [ + + ], + "source": [ + "selective_quantized_model = convert.mlir_quantize(\n", + " calibrated_model, denylisted_nodes=suspected_layers)\n", + "eval_tflite(selective_quantized_model, ds)" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "Eq_8T2oauIED" + ], + "name": "quantization_debugger.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/lite/performance/quantization_spec.md b/site/pt-br/lite/performance/quantization_spec.md new file mode 100644 index 0000000000..b2bd7da1ef --- /dev/null +++ b/site/pt-br/lite/performance/quantization_spec.md @@ -0,0 +1,500 @@ +# Especificação da quantização de 8 bits do TensorFlow Lite + +Este documento descreve a especificação para o esquema de quantização de 8 its do TensorFlow Lite. O objetivo dele é ajudar os desenvolvedores de hardware a oferecer suporte para a inferência com modelos do TensorFlow Lite quantizados. + +## Resumo da especificação + +Estamos fornecendo uma especificação e só podemos dar algumas garantias de comportamento se a especificação for seguida. Também entendemos que cada hardware pode ter preferências e restrições que causam leves desvios ao implementar a especificação, resultando em implementações de bits não exatos. Isso pode ser aceitável na maioria dos casos (e oferecemos um pacote de testes que, de acordo com nosso conhecimento, incluem tolerâncias por operação que reunimos de vários modelos), a natureza do aprendizado de máquina (e do aprendizado profundo no caso mais comum) torna impossível dar quaisquer garantias sólidas. + +A quantização de 8 bits aproxima os valores de ponto flutuante usando a seguinte fórmula. + +$$real_value = (int8_value - zero_point) \times scale$$ + +Os pesos por eixo (ou seja, por canal nas operações Conv) ou por tensor são representados por dois valores complementares `int8` no intervalo `[-127, 127]` com um ponto zero igual a 0. As ativações/entradas por tensor são representadas por dois valores complementares `int8` no intervalo `[-128, 127]`, com um ponto zero no intervalo `[-128, 127]`. + +Há outras exceções para operações específicas documentadas abaixo. + +Observação: no passado, nossas ferramentas de quantização usavam a quantização `uint8` assimétrica por tensor. As novas ferramentas, os kernels de referência e os kernels otimizados para a quantização de 8 bits usarão esta especificação. + +## Números inteiros assinados x não assinados + +A quantização do TensorFlow Lite priorizará principalmente as ferramentas e os kernels para a quantização `int8` de 8 bits. Isso é para a conveniência de a quantização simétrica ser representada pelo ponto zero igual a 0. Além disso, vários back-end têm otimizações adicionais para a acumulação `int8xint8`. + +## Por eixo x por tensor + +A quantização por tensor significa que haverá uma escala e/ou ponto zero para cada tensor. A quantização por eixo significa que haverá uma escala e/ou `zero_point` por fatia em `quantized_dimension`. A dimensão quantizada especifica a dimensão do formato do tensor a que as escalas e os pontos zeros correspondem. Por exemplo, um tensor `t`, de `dims=[4, 3, 2, 1]` com os parâmetros de quantização: `scale=[1.0, 2.0, 3.0]`, `zero_point=[1, 2, 3]`, `quantization_dimension=1` será quantizado em toda a segunda dimensão de `t`: + +``` +t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1 +t[:, 1, :, :] will have scale[1]=2.0, zero_point[1]=2 +t[:, 2, :, :] will have scale[2]=3.0, zero_point[2]=3 +``` + +Geralmente, a `quantized_dimension` é o `output_channel` dos pesos das convoluções, mas, em teoria, pode ser que a dimensão corresponda a cada produto escalar na implementação do kernel, permitindo maior granularidade da quantização sem implicações no desempenho. Isso leva a grandes melhorias na exatidão. + +O TFLite oferece o suporte por eixo a um número crescente de operações. No momento da publicação deste documento, há suporte para Conv2d e DepthwiseConv2d. + +## Simétrico x assimétrico + +As ativações são assimétricas: elas podem ter o ponto zero em qualquer lugar no intervalo `[-128, 127]` do `int8` assinado. Várias ativações têm natureza assimétrica e o ponto zero é uma maneira relativamente barata de conseguir mais um bit binário de precisão de forma eficiente. Como as ativações só são multiplicadas por pesos constantes, o valor de ponto zero constante pode ser bastante otimizado. + +Os pesos são assimétricos: eles são forçados a ter o ponto zero igual a 0. Os valores dos pesos são multiplicados pelos valores de ativação e entrada dinâmica. Isso significa que há o custo de runtime inevitável de multiplicar o ponto zero do peso com o valor de ativação. Ao impor o ponto zero como 0, podemos evitar esse custo. + +A explicação da matemática: isso é semelhante à seção 2.3 em [arXiv:1712.05877](https://arxiv.org/abs/1712.05877), exceto que a diferença permitida para os valores escalares são por eixo. Isso é prontamente generalizado da seguinte maneira: + +$A$ é uma matriz $m \times n$ das ativações quantizadas.
$B$ é uma matriz $n \times p$ dos pesos quantizados.
Considere multiplicar a linha $j$th de $A$, $a_j$ pela coluna $k$th de $B$, $b_k$, ambos de comprimento $n$. Os valores de números inteiros quantizados e de pontos zeros são $q_a$, $z_a$ e $q_b$, $z_b$, respectivamente. + +$$a_j \cdot b_k = \sum_{i=0}^{n} a_{j}^{(i)} b_{k}^{(i)} = \sum_{i=0}^{n} (q_{a}^{(i)} - z_a) (q_{b}^{(i)} - z_b) = \sum_{i=0}^{n} q_{a}^{(i)} q_{b}^{(i)} - \sum_{i=0}^{n} q_{a}^{(i)} z_b - \sum_{i=0}^{n} q_{b}^{(i)} z_a + \sum_{i=0}^{n} z_a z_b$$ + + + +O termo \(\sum_{i=0}^{n} q_{a}^{(i)} q_{b}^{(i)}\) é inevitável, já que fornece o valor escalar dos valores da entrada e do peso. + +Os termos $$\sum_{i=0}^{n} q_{b}^{(i)} z_a$$ and $$\sum_{i=0}^{n} z_a z_b$$ são compostos de constantes que permanecem iguais por invocação de inferência e, por isso, podem ser pré-calculadas. + +O termo \(\sum_{i=0}^{n} q_{a}^{(i)} z_b\) precisa ser computado a cada inferência, porque a ativação muda a cada inferência. Ao impor que os pesos sejam simétricos, podemos remover o custo desse termo. + +## Especificações de operadores quantizados int8 + +Descrevemos abaixo os requisitos de quantização para nossos kernels tflite int8: + +``` +ADD + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +AVERAGE_POOL_2D + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +CONCATENATION + Input ...: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +CONV_2D + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1 (Weight): + data_type : int8 + range : [-127, 127] + granularity: per-axis (dim = 0) + restriction: zero_point = 0 + Input 2 (Bias): + data_type : int32 + range : [int32_min, int32_max] + granularity: per-axis + restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0) + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +DEPTHWISE_CONV_2D + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1 (Weight): + data_type : int8 + range : [-127, 127] + granularity: per-axis (dim = 3) + restriction: zero_point = 0 + Input 2 (Bias): + data_type : int32 + range : [int32_min, int32_max] + granularity: per-axis + restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0) + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +FULLY_CONNECTED + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1 (Weight): + data_type : int8 + range : [-127, 127] + granularity: per-tensor + restriction: zero_point = 0 + Input 2 (Bias): + data_type : int32 + range : [int32_min, int32_max] + granularity: per-tensor + restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0) + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +L2_NORMALIZATION + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: (scale, zero_point) = (1.0 / 128.0, 0) + +LOGISTIC + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: (scale, zero_point) = (1.0 / 256.0, -128) + +MAX_POOL_2D + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +MUL + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +RESHAPE + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +RESIZE_BILINEAR + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +SOFTMAX + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: (scale, zero_point) = (1.0 / 256.0, -128) + +SPACE_TO_DEPTH + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +TANH + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: (scale, zero_point) = (1.0 / 128.0, 0) + +PAD + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +GATHER + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +BATCH_TO_SPACE_ND + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +SPACE_TO_BATCH_ND + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +TRANSPOSE + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +MEAN + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +SUB + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +SUM + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +SQUEEZE + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +LOG_SOFTMAX + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: (scale, zero_point) = (16.0 / 256.0, 127) + +MAXIMUM + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +ARG_MAX + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +MINIMUM + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +LESS + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +PADV2 + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +GREATER + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +GREATER_EQUAL + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +LESS_EQUAL + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +SLICE + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + restriction: Input and outputs must all have same scale/zero_point + +EQUAL + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +NOT_EQUAL + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Input 1: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +SHAPE + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + +QUANTIZE (Requantization) + Input 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor + Output 0: + data_type : int8 + range : [-128, 127] + granularity: per-tensor +``` + +## Referências + +[arXiv:1712.05877](https://arxiv.org/abs/1712.05877) diff --git a/site/pt-br/lite/tutorials/pose_classification.ipynb b/site/pt-br/lite/tutorials/pose_classification.ipynb new file mode 100644 index 0000000000..c8bd4f31b2 --- /dev/null +++ b/site/pt-br/lite/tutorials/pose_classification.ipynb @@ -0,0 +1,1413 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "L30JbHSkiVZx" + }, + "source": [ + "##### Copyright 2021 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "ZtimvKLdili0" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QXdiroR-Ue-Z" + }, + "source": [ + "# Classificação de poses humanas com o MoveNet e o TensorFlow Lite\n", + "\n", + "Este notebook ensina a você como treinar um modelo de classificação de poses usando o MoveNet e o TensorFlow Lite. O resultado é um novo modelo do TensorFlow Lite que aceita a saída do modelo MoveNet como sua entrada e gera uma classificação da pose, como o nome de uma pose de yoga.\n", + "\n", + "O procedimento neste notebook consiste em 3 partes:\n", + "\n", + "- Parte 1: pré-processe os dados de treinamento da classificação de poses em um arquivo CSV que especifica os landmarks (pontos-chave corporais) detectados pelo modelo MoveNet, além dos rótulos de pose de verdade absoluta.\n", + "- Parte 2: crie e treine um modelo de classificação de poses que aceita coordenadas de landmarks do arquivo CSV como entrada e gera os rótulos previstos.\n", + "- Parte 3: converta o modelo de classificação de poses para o TFLite.\n", + "\n", + "Por padrão, este notebook usa um dataset de imagens com poses de yoga rotuladas, mas também incluímos uma seção na Parte 1 onde você pode fazer upload do seu próprio dataset de imagens de poses.\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + " Ver modelo do TF Hub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IfQ3xP6-EY5r" + }, + "source": [ + "## Preparação" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Jpy4A1Vpi9jH" + }, + "source": [ + "Nesta seção, você importará as bibliotecas necessárias e definirá várias funções para pré-processar as imagens de treinamento em um arquivo CSV com as coordenadas dos landmarks e os rótulos de verdade absoluta.\n", + "\n", + "Não acontece nada observável aqui, mas você pode expandir as células de código ocultas para ver a implementação de algumas funções que serão chamadas depois.\n", + "\n", + "**Se você só quiser criar o arquivo CSV sem saber todos os detalhes, basta executar esta seção e seguir para a Parte 1.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PWlbrkMCx-W-" + }, + "outputs": [ + + ], + "source": [ + "!pip install -q opencv-python" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KTkttSWnUi1Q" + }, + "outputs": [ + + ], + "source": [ + "import csv\n", + "import cv2\n", + "import itertools\n", + "import numpy as np\n", + "import pandas as pd\n", + "import os\n", + "import sys\n", + "import tempfile\n", + "import tqdm\n", + "\n", + "from matplotlib import pyplot as plt\n", + "from matplotlib.collections import LineCollection\n", + "\n", + "import tensorflow as tf\n", + "import tensorflow_hub as hub\n", + "from tensorflow import keras\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.metrics import accuracy_score, classification_report, confusion_matrix" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KwRwEssyTciI" + }, + "source": [ + "### Código para executar a estimativa de pose usando o MoveNet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "48kW1c2F5l1R" + }, + "outputs": [ + + ], + "source": [ + "#@title Functions to run pose estimation with MoveNet\n", + "\n", + "#@markdown You'll download the MoveNet Thunder model from [TensorFlow Hub](https://www.google.com/url?sa=D&q=https%3A%2F%2Ftfhub.dev%2Fs%3Fq%3Dmovenet), and reuse some inference and visualization logic from the [MoveNet Raspberry Pi (Python)](https://github.com/tensorflow/examples/tree/master/lite/examples/pose_estimation/raspberry_pi) sample app to detect landmarks (ear, nose, wrist etc.) from the input images.\n", + "\n", + "#@markdown *Note: You should use the most accurate pose estimation model (i.e. MoveNet Thunder) to detect the keypoints and use them to train the pose classification model to achieve the best accuracy. When running inference, you can use a pose estimation model of your choice (e.g. either MoveNet Lightning or Thunder).*\n", + "\n", + "# Download model from TF Hub and check out inference code from GitHub\n", + "!wget -q -O movenet_thunder.tflite https://tfhub.dev/google/lite-model/movenet/singlepose/thunder/tflite/float16/4?lite-format=tflite\n", + "!git clone https://github.com/tensorflow/examples.git\n", + "pose_sample_rpi_path = os.path.join(os.getcwd(), 'examples/lite/examples/pose_estimation/raspberry_pi')\n", + "sys.path.append(pose_sample_rpi_path)\n", + "\n", + "# Load MoveNet Thunder model\n", + "import utils\n", + "from data import BodyPart\n", + "from ml import Movenet\n", + "movenet = Movenet('movenet_thunder')\n", + "\n", + "# Define function to run pose estimation using MoveNet Thunder.\n", + "# You'll apply MoveNet's cropping algorithm and run inference multiple times on\n", + "# the input image to improve pose estimation accuracy.\n", + "def detect(input_tensor, inference_count=3):\n", + " \"\"\"Runs detection on an input image.\n", + " \n", + " Args:\n", + " input_tensor: A [height, width, 3] Tensor of type tf.float32.\n", + " Note that height and width can be anything since the image will be\n", + " immediately resized according to the needs of the model within this\n", + " function.\n", + " inference_count: Number of times the model should run repeatly on the\n", + " same input image to improve detection accuracy.\n", + " \n", + " Returns:\n", + " A Person entity detected by the MoveNet.SinglePose.\n", + " \"\"\"\n", + " image_height, image_width, channel = input_tensor.shape\n", + " \n", + " # Detect pose using the full input image\n", + " movenet.detect(input_tensor.numpy(), reset_crop_region=True)\n", + " \n", + " # Repeatedly using previous detection result to identify the region of\n", + " # interest and only croping that region to improve detection accuracy\n", + " for _ in range(inference_count - 1):\n", + " person = movenet.detect(input_tensor.numpy(), \n", + " reset_crop_region=False)\n", + "\n", + " return person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "fKo0NzwQJ5Rm" + }, + "outputs": [ + + ], + "source": [ + "#@title Functions to visualize the pose estimation results.\n", + "\n", + "def draw_prediction_on_image(\n", + " image, person, crop_region=None, close_figure=True,\n", + " keep_input_size=False):\n", + " \"\"\"Draws the keypoint predictions on image.\n", + " \n", + " Args:\n", + " image: An numpy array with shape [height, width, channel] representing the\n", + " pixel values of the input image.\n", + " person: A person entity returned from the MoveNet.SinglePose model.\n", + " close_figure: Whether to close the plt figure after the function returns.\n", + " keep_input_size: Whether to keep the size of the input image.\n", + " \n", + " Returns:\n", + " An numpy array with shape [out_height, out_width, channel] representing the\n", + " image overlaid with keypoint predictions.\n", + " \"\"\"\n", + " # Draw the detection result on top of the image.\n", + " image_np = utils.visualize(image, [person])\n", + " \n", + " # Plot the image with detection results.\n", + " height, width, channel = image.shape\n", + " aspect_ratio = float(width) / height\n", + " fig, ax = plt.subplots(figsize=(12 * aspect_ratio, 12))\n", + " im = ax.imshow(image_np)\n", + " \n", + " if close_figure:\n", + " plt.close(fig)\n", + " \n", + " if not keep_input_size:\n", + " image_np = utils.keep_aspect_ratio_resizer(image_np, (512, 512))\n", + "\n", + " return image_np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "QUkOW_26S6K-" + }, + "outputs": [ + + ], + "source": [ + "#@title Code to load the images, detect pose landmarks and save them into a CSV file\n", + "\n", + "class MoveNetPreprocessor(object):\n", + " \"\"\"Helper class to preprocess pose sample images for classification.\"\"\"\n", + " \n", + " def __init__(self,\n", + " images_in_folder,\n", + " images_out_folder,\n", + " csvs_out_path):\n", + " \"\"\"Creates a preprocessor to detection pose from images and save as CSV.\n", + "\n", + " Args:\n", + " images_in_folder: Path to the folder with the input images. It should\n", + " follow this structure:\n", + " yoga_poses\n", + " |__ downdog\n", + " |______ 00000128.jpg\n", + " |______ 00000181.bmp\n", + " |______ ...\n", + " |__ goddess\n", + " |______ 00000243.jpg\n", + " |______ 00000306.jpg\n", + " |______ ...\n", + " ...\n", + " images_out_folder: Path to write the images overlay with detected\n", + " landmarks. These images are useful when you need to debug accuracy\n", + " issues.\n", + " csvs_out_path: Path to write the CSV containing the detected landmark\n", + " coordinates and label of each image that can be used to train a pose\n", + " classification model.\n", + " \"\"\"\n", + " self._images_in_folder = images_in_folder\n", + " self._images_out_folder = images_out_folder\n", + " self._csvs_out_path = csvs_out_path\n", + " self._messages = []\n", + "\n", + " # Create a temp dir to store the pose CSVs per class\n", + " self._csvs_out_folder_per_class = tempfile.mkdtemp()\n", + " \n", + " # Get list of pose classes and print image statistics\n", + " self._pose_class_names = sorted(\n", + " [n for n in os.listdir(self._images_in_folder) if not n.startswith('.')]\n", + " )\n", + " \n", + " def process(self, per_pose_class_limit=None, detection_threshold=0.1):\n", + " \"\"\"Preprocesses images in the given folder.\n", + " Args:\n", + " per_pose_class_limit: Number of images to load. As preprocessing usually\n", + " takes time, this parameter can be specified to make the reduce of the\n", + " dataset for testing.\n", + " detection_threshold: Only keep images with all landmark confidence score\n", + " above this threshold.\n", + " \"\"\"\n", + " # Loop through the classes and preprocess its images\n", + " for pose_class_name in self._pose_class_names:\n", + " print('Preprocessing', pose_class_name, file=sys.stderr)\n", + "\n", + " # Paths for the pose class.\n", + " images_in_folder = os.path.join(self._images_in_folder, pose_class_name)\n", + " images_out_folder = os.path.join(self._images_out_folder, pose_class_name)\n", + " csv_out_path = os.path.join(self._csvs_out_folder_per_class,\n", + " pose_class_name + '.csv')\n", + " if not os.path.exists(images_out_folder):\n", + " os.makedirs(images_out_folder)\n", + " \n", + " # Detect landmarks in each image and write it to a CSV file\n", + " with open(csv_out_path, 'w') as csv_out_file:\n", + " csv_out_writer = csv.writer(csv_out_file, \n", + " delimiter=',', \n", + " quoting=csv.QUOTE_MINIMAL)\n", + " # Get list of images\n", + " image_names = sorted(\n", + " [n for n in os.listdir(images_in_folder) if not n.startswith('.')])\n", + " if per_pose_class_limit is not None:\n", + " image_names = image_names[:per_pose_class_limit]\n", + "\n", + " valid_image_count = 0\n", + " \n", + " # Detect pose landmarks from each image\n", + " for image_name in tqdm.tqdm(image_names):\n", + " image_path = os.path.join(images_in_folder, image_name)\n", + "\n", + " try:\n", + " image = tf.io.read_file(image_path)\n", + " image = tf.io.decode_jpeg(image)\n", + " except:\n", + " self._messages.append('Skipped ' + image_path + '. Invalid image.')\n", + " continue\n", + " else:\n", + " image = tf.io.read_file(image_path)\n", + " image = tf.io.decode_jpeg(image)\n", + " image_height, image_width, channel = image.shape\n", + " \n", + " # Skip images that isn't RGB because Movenet requires RGB images\n", + " if channel != 3:\n", + " self._messages.append('Skipped ' + image_path +\n", + " '. Image isn\\'t in RGB format.')\n", + " continue\n", + " person = detect(image)\n", + " \n", + " # Save landmarks if all landmarks were detected\n", + " min_landmark_score = min(\n", + " [keypoint.score for keypoint in person.keypoints])\n", + " should_keep_image = min_landmark_score >= detection_threshold\n", + " if not should_keep_image:\n", + " self._messages.append('Skipped ' + image_path +\n", + " '. No pose was confidentlly detected.')\n", + " continue\n", + "\n", + " valid_image_count += 1\n", + "\n", + " # Draw the prediction result on top of the image for debugging later\n", + " output_overlay = draw_prediction_on_image(\n", + " image.numpy().astype(np.uint8), person, \n", + " close_figure=True, keep_input_size=True)\n", + " \n", + " # Write detection result into an image file\n", + " output_frame = cv2.cvtColor(output_overlay, cv2.COLOR_RGB2BGR)\n", + " cv2.imwrite(os.path.join(images_out_folder, image_name), output_frame)\n", + " \n", + " # Get landmarks and scale it to the same size as the input image\n", + " pose_landmarks = np.array(\n", + " [[keypoint.coordinate.x, keypoint.coordinate.y, keypoint.score]\n", + " for keypoint in person.keypoints],\n", + " dtype=np.float32)\n", + "\n", + " # Write the landmark coordinates to its per-class CSV file\n", + " coordinates = pose_landmarks.flatten().astype(np.str).tolist()\n", + " csv_out_writer.writerow([image_name] + coordinates)\n", + "\n", + " if not valid_image_count:\n", + " raise RuntimeError(\n", + " 'No valid images found for the \"{}\" class.'\n", + " .format(pose_class_name))\n", + " \n", + " # Print the error message collected during preprocessing.\n", + " print('\\n'.join(self._messages))\n", + "\n", + " # Combine all per-class CSVs into a single output file\n", + " all_landmarks_df = self._all_landmarks_as_dataframe()\n", + " all_landmarks_df.to_csv(self._csvs_out_path, index=False)\n", + "\n", + " def class_names(self):\n", + " \"\"\"List of classes found in the training dataset.\"\"\"\n", + " return self._pose_class_names\n", + " \n", + " def _all_landmarks_as_dataframe(self):\n", + " \"\"\"Merge all per-class CSVs into a single dataframe.\"\"\"\n", + " total_df = None\n", + " for class_index, class_name in enumerate(self._pose_class_names):\n", + " csv_out_path = os.path.join(self._csvs_out_folder_per_class,\n", + " class_name + '.csv')\n", + " per_class_df = pd.read_csv(csv_out_path, header=None)\n", + " \n", + " # Add the labels\n", + " per_class_df['class_no'] = [class_index]*len(per_class_df)\n", + " per_class_df['class_name'] = [class_name]*len(per_class_df)\n", + "\n", + " # Append the folder name to the filename column (first column)\n", + " per_class_df[per_class_df.columns[0]] = (os.path.join(class_name, '') \n", + " + per_class_df[per_class_df.columns[0]].astype(str))\n", + "\n", + " if total_df is None:\n", + " # For the first class, assign its data to the total dataframe\n", + " total_df = per_class_df\n", + " else:\n", + " # Concatenate each class's data into the total dataframe\n", + " total_df = pd.concat([total_df, per_class_df], axis=0)\n", + " \n", + " list_name = [[bodypart.name + '_x', bodypart.name + '_y', \n", + " bodypart.name + '_score'] for bodypart in BodyPart] \n", + " header_name = []\n", + " for columns_name in list_name:\n", + " header_name += columns_name\n", + " header_name = ['file_name'] + header_name\n", + " header_map = {total_df.columns[i]: header_name[i] \n", + " for i in range(len(header_name))}\n", + " \n", + " total_df.rename(header_map, axis=1, inplace=True)\n", + "\n", + " return total_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "LB3QIVrdU108" + }, + "outputs": [ + + ], + "source": [ + "#@title (Optional) Code snippet to try out the Movenet pose estimation logic\n", + "\n", + "#@markdown You can download an image from the internet, run the pose estimation logic on it and plot the detected landmarks on top of the input image. \n", + "\n", + "#@markdown *Note: This code snippet is also useful for debugging when you encounter an image with bad pose classification accuracy. You can run pose estimation on the image and see if the detected landmarks look correct or not before investigating the pose classification logic.*\n", + "\n", + "test_image_url = \"https://cdn.pixabay.com/photo/2017/03/03/17/30/yoga-2114512_960_720.jpg\" #@param {type:\"string\"}\n", + "!wget -O /tmp/image.jpeg {test_image_url}\n", + "\n", + "if len(test_image_url):\n", + " image = tf.io.read_file('/tmp/image.jpeg')\n", + " image = tf.io.decode_jpeg(image)\n", + " person = detect(image)\n", + " _ = draw_prediction_on_image(image.numpy(), person, crop_region=None, \n", + " close_figure=False, keep_input_size=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L24GWhgo4WAl" + }, + "source": [ + "## Parte 1: pré-processe as imagens de entrada\n", + "\n", + "Como a entrada do nosso classificador de poses são os landmarks de *saída* do modelo MoveNet, precisamos gerar o dataset de treinamento ao executar imagens rotuladas através do MoveNet e depois capturar todos os dados de landmarks e rótulos de verdade absoluta em um arquivo CSV.\n", + "\n", + "O dataset que fornecemos para este tutorial é um dataset de poses de yoga gerado por CG. Ele contém imagens de vários modelos gerados por CG fazendo 5 poses de yoga diferentes. O diretório já está dividido em datasets `train` e `test`.\n", + "\n", + "Portanto, nesta seção, vamos baixar o dataset de yoga e executá-lo pelo MoveNet para que possamos capturar todos os landmarks em um arquivo CSV... **No entanto, leva cerca de 15 minutos para alimentar nosso dataset de yoga ao MoveNet e gerar esse arquivo CSV**. Então, como alternativa, você pode baixar um arquivo CSV pré-existente para o dataset de yoga ao definir o parâmetro `is_skip_step_1` abaixo como **True**. Assim, você pulará este passo e baixará o mesmo arquivo CSV criado nesta etapa de pré-processamento.\n", + "\n", + "Por outro lado, se você quiser treinar o classificador de poses com seu próprio dataset de imagens, precisará fazer upload das imagens e realizar este passo de pré-processamento (deixe `is_skip_step_1` como **False**): siga as instruções abaixo para carregar seu próprio dataset de poses." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "Kw6jwOFD40Fr" + }, + "outputs": [ + + ], + "source": [ + "is_skip_step_1 = False #@param [\"False\", \"True\"] {type:\"raw\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TJXSR2CQhm-z" + }, + "source": [ + "### (Opcional) Faça upload do seu próprio dataset de poses" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "iEnjgeKeS_VP" + }, + "outputs": [ + + ], + "source": [ + "use_custom_dataset = False #@param [\"False\", \"True\"] {type:\"raw\"}\n", + "\n", + "dataset_is_split = False #@param [\"False\", \"True\"] {type:\"raw\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YiqF3sRf3LLC" + }, + "source": [ + "Se você quiser treinar o classificador de poses com suas próprias poses rotuladas (pode ser de qualquer tipo, e não só poses de yoga), siga estas etapas:\n", + "\n", + "1. Defina a opção `use_custom_dataset` acima como **True**.\n", + "\n", + "2. Prepare um arquivo (ZIP, TAR etc.) que inclua uma pasta com seu dataset de imagens. Essa pasta precisa ter imagens classificadas das suas poses da maneira a seguir.\n", + "\n", + "Se você já dividiu seu dataset em conjuntos de treinamento e teste, defina `dataset_is_split` como **True**. Isto é, sua pasta de imagens precisa incluir os diretórios \"train\" e \"teste\" assim:\n", + "\n", + "```\n", + "```\n", + "yoga_poses/\n", + "|__ train/\n", + " |__ downdog/\n", + " |______ 00000128.jpg\n", + " |______ ...\n", + "|__ test/\n", + " |__ downdog/\n", + " |______ 00000181.jpg\n", + " |______ ...\n", + "```\n", + "\n", + "Or, if your dataset is NOT split yet, then set\n", + "`dataset_is_split` to **False** and we'll split it up based\n", + "on a specified split fraction. That is, your uploaded images\n", + "folder should look like this:\n", + "\n", + "```\n", + "yoga_poses/\n", + "|__ downdog/\n", + " |______ 00000128.jpg\n", + " |______ 00000181.jpg\n", + " |______ ...\n", + "|__ goddess/\n", + " |______ 00000243.jpg\n", + " |______ 00000306.jpg\n", + " |______ ...\n", + "```\n", + "```\n", + "\n", + "1. Clique na guia **Files**, \"Arquivos\", à esquerda (ícone de pasta) e depois em **Upload to session storage**, \"Fazer upload no armazenamento da sessão\", (ícone de arquivo).\n", + "2. Selecione seu arquivo e espere até que o upload seja concluído antes de continuar.\n", + "3. Edite o bloco de código a seguir para especificar o nome do arquivo e do diretório de imagens. (Por padrão, esperamos um arquivo ZIP, então você também precisará modificar essa parte se o seu arquivo estiver em outro formato.)\n", + "4. Agora, execute o resto do notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "joAHy_r62dsI" + }, + "outputs": [ + + ], + "source": [ + "#@markdown Be sure you run this cell. It's hiding the `split_into_train_test()` function that's called in the next code block.\n", + "\n", + "import os\n", + "import random\n", + "import shutil\n", + "\n", + "def split_into_train_test(images_origin, images_dest, test_split):\n", + " \"\"\"Splits a directory of sorted images into training and test sets.\n", + "\n", + " Args:\n", + " images_origin: Path to the directory with your images. This directory\n", + " must include subdirectories for each of your labeled classes. For example:\n", + " yoga_poses/\n", + " |__ downdog/\n", + " |______ 00000128.jpg\n", + " |______ 00000181.jpg\n", + " |______ ...\n", + " |__ goddess/\n", + " |______ 00000243.jpg\n", + " |______ 00000306.jpg\n", + " |______ ...\n", + " ...\n", + " images_dest: Path to a directory where you want the split dataset to be\n", + " saved. The results looks like this:\n", + " split_yoga_poses/\n", + " |__ train/\n", + " |__ downdog/\n", + " |______ 00000128.jpg\n", + " |______ ...\n", + " |__ test/\n", + " |__ downdog/\n", + " |______ 00000181.jpg\n", + " |______ ...\n", + " test_split: Fraction of data to reserve for test (float between 0 and 1).\n", + " \"\"\"\n", + " _, dirs, _ = next(os.walk(images_origin))\n", + "\n", + " TRAIN_DIR = os.path.join(images_dest, 'train')\n", + " TEST_DIR = os.path.join(images_dest, 'test')\n", + " os.makedirs(TRAIN_DIR, exist_ok=True)\n", + " os.makedirs(TEST_DIR, exist_ok=True)\n", + "\n", + " for dir in dirs:\n", + " # Get all filenames for this dir, filtered by filetype\n", + " filenames = os.listdir(os.path.join(images_origin, dir))\n", + " filenames = [os.path.join(images_origin, dir, f) for f in filenames if (\n", + " f.endswith('.png') or f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.bmp'))]\n", + " # Shuffle the files, deterministically\n", + " filenames.sort()\n", + " random.seed(42)\n", + " random.shuffle(filenames)\n", + " # Divide them into train/test dirs\n", + " os.makedirs(os.path.join(TEST_DIR, dir), exist_ok=True)\n", + " os.makedirs(os.path.join(TRAIN_DIR, dir), exist_ok=True)\n", + " test_count = int(len(filenames) * test_split)\n", + " for i, file in enumerate(filenames):\n", + " if i < test_count:\n", + " destination = os.path.join(TEST_DIR, dir, os.path.split(file)[1])\n", + " else:\n", + " destination = os.path.join(TRAIN_DIR, dir, os.path.split(file)[1])\n", + " shutil.copyfile(file, destination)\n", + " print(f'Moved {test_count} of {len(filenames)} from class \"{dir}\" into test.')\n", + " print(f'Your split dataset is in \"{images_dest}\"')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IfpNIjAmR0lp" + }, + "outputs": [ + + ], + "source": [ + "if use_custom_dataset:\n", + " # ATTENTION:\n", + " # You must edit these two lines to match your archive and images folder name:\n", + " # !tar -xf YOUR_DATASET_ARCHIVE_NAME.tar\n", + " !unzip -q YOUR_DATASET_ARCHIVE_NAME.zip\n", + " dataset_in = 'YOUR_DATASET_DIR_NAME'\n", + "\n", + " # You can leave the rest alone:\n", + " if not os.path.isdir(dataset_in):\n", + " raise Exception(\"dataset_in is not a valid directory\")\n", + " if dataset_is_split:\n", + " IMAGES_ROOT = dataset_in\n", + " else:\n", + " dataset_out = 'split_' + dataset_in\n", + " split_into_train_test(dataset_in, dataset_out, test_split=0.2)\n", + " IMAGES_ROOT = dataset_out" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IPkTA5-sNF7W" + }, + "source": [ + "**Observação:** se você estiver usando o `split_into_train_test()` para dividir o dataset, ele espera que todas as imagens sejam PNG, JPEG ou BMP e ignora os outros tipos de arquivo." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dcoak0QHW5d1" + }, + "source": [ + "### Baixe o dataset de yoga" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GVpOi5Hr4Xxt" + }, + "outputs": [ + + ], + "source": [ + "if not is_skip_step_1 and not use_custom_dataset:\n", + " !wget -O yoga_poses.zip http://download.tensorflow.org/data/pose_classification/yoga_poses.zip\n", + " !unzip -q yoga_poses.zip -d yoga_cg\n", + " IMAGES_ROOT = \"yoga_cg\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vxOkXvm-TvOZ" + }, + "source": [ + "### Faça o pré-processamento do dataset `TRAIN`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OsdqxGfxTE2H" + }, + "outputs": [ + + ], + "source": [ + "if not is_skip_step_1:\n", + " images_in_train_folder = os.path.join(IMAGES_ROOT, 'train')\n", + " images_out_train_folder = 'poses_images_out_train'\n", + " csvs_out_train_path = 'train_data.csv'\n", + "\n", + " preprocessor = MoveNetPreprocessor(\n", + " images_in_folder=images_in_train_folder,\n", + " images_out_folder=images_out_train_folder,\n", + " csvs_out_path=csvs_out_train_path,\n", + " )\n", + "\n", + " preprocessor.process(per_pose_class_limit=None)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cQtgAeHVT0UE" + }, + "source": [ + "### Faça o pré-processamento do dataset `TEST`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hddKVPjrTNbt" + }, + "outputs": [ + + ], + "source": [ + "if not is_skip_step_1:\n", + " images_in_test_folder = os.path.join(IMAGES_ROOT, 'test')\n", + " images_out_test_folder = 'poses_images_out_test'\n", + " csvs_out_test_path = 'test_data.csv'\n", + "\n", + " preprocessor = MoveNetPreprocessor(\n", + " images_in_folder=images_in_test_folder,\n", + " images_out_folder=images_out_test_folder,\n", + " csvs_out_path=csvs_out_test_path,\n", + " )\n", + "\n", + " preprocessor.process(per_pose_class_limit=None)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UevEKViRT_6J" + }, + "source": [ + "## Parte 2: treine um modelo de classificação de poses que aceita coordenadas de landmarks como entrada e gera rótulos previstos\n", + "\n", + "Você criará um modelo do TensorFlow que aceita coordenadas de landmark e prevê a classe da pose em que está a pessoa na imagem de entrada. O modelo consiste em dois submodelos:\n", + "\n", + "- O submodelo 1 calcula um embedding da pose (ou seja, um vetor de características) a partir das coordenadas de landmark detectadas.\n", + "- O submodelo 2 alimenta o embedding da pose por várias camadas `Dense` para prever a classe dela.\n", + "\n", + "Depois, você treinará o modelo com base no dataset pré-processado na parte 1." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "E2D1czPJazvb" + }, + "source": [ + "### (Opcional) Baixe o dataset pré-processado se você não executou a parte 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ShpOD7yb4MRp" + }, + "outputs": [ + + ], + "source": [ + "# Download the preprocessed CSV files which are the same as the output of step 1\n", + "if is_skip_step_1:\n", + " !wget -O train_data.csv http://download.tensorflow.org/data/pose_classification/yoga_train_data.csv\n", + " !wget -O test_data.csv http://download.tensorflow.org/data/pose_classification/yoga_test_data.csv\n", + "\n", + " csvs_out_train_path = 'train_data.csv'\n", + " csvs_out_test_path = 'test_data.csv'\n", + " is_skipped_step_1 = True" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iGMcoSwLwRSD" + }, + "source": [ + "### Carregue os CSVs pré-processados nos datasets `TRAIN` e `TEST`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pOUcc8EL5rrj" + }, + "outputs": [ + + ], + "source": [ + "def load_pose_landmarks(csv_path):\n", + " \"\"\"Loads a CSV created by MoveNetPreprocessor.\n", + " \n", + " Returns:\n", + " X: Detected landmark coordinates and scores of shape (N, 17 * 3)\n", + " y: Ground truth labels of shape (N, label_count)\n", + " classes: The list of all class names found in the dataset\n", + " dataframe: The CSV loaded as a Pandas dataframe features (X) and ground\n", + " truth labels (y) to use later to train a pose classification model.\n", + " \"\"\"\n", + "\n", + " # Load the CSV file\n", + " dataframe = pd.read_csv(csv_path)\n", + " df_to_process = dataframe.copy()\n", + "\n", + " # Drop the file_name columns as you don't need it during training.\n", + " df_to_process.drop(columns=['file_name'], inplace=True)\n", + "\n", + " # Extract the list of class names\n", + " classes = df_to_process.pop('class_name').unique()\n", + "\n", + " # Extract the labels\n", + " y = df_to_process.pop('class_no')\n", + "\n", + " # Convert the input features and labels into the correct format for training.\n", + " X = df_to_process.astype('float64')\n", + " y = keras.utils.to_categorical(y)\n", + "\n", + " return X, y, classes, dataframe" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UMrLzfPz7E1U" + }, + "source": [ + "Carregue e divida o dataset `TRAIN` original em `TRAIN` (85% dos dados) e `VALIDATE` (os 15% restantes)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xawmSDGXUUzW" + }, + "outputs": [ + + ], + "source": [ + "# Load the train data\n", + "X, y, class_names, _ = load_pose_landmarks(csvs_out_train_path)\n", + "\n", + "# Split training data (X, y) into (X_train, y_train) and (X_val, y_val)\n", + "X_train, X_val, y_train, y_val = train_test_split(X, y,\n", + " test_size=0.15)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "R42kicUMaTX0" + }, + "outputs": [ + + ], + "source": [ + "# Load the test data\n", + "X_test, y_test, _, df_test = load_pose_landmarks(csvs_out_test_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ydb-bd_UWXMq" + }, + "source": [ + "### Defina funções para converter os landmarks das poses em um embedding (ou seja, um vetor de características) para a classificação\n", + "\n", + "Em seguida, converta as coordenadas de landmark em um vetor de características ao:\n", + "\n", + "1. Mover o centro da pose para a origem.\n", + "2. Dimensionar a pose para que o tamanho dela seja 1.\n", + "3. Achatar essas coordenadas em um vetor de características.\n", + "\n", + "Em seguida, use esse vetor de características para treinar um classificador de poses baseado em rede neural." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HgQMdfeT65Z5" + }, + "outputs": [ + + ], + "source": [ + "def get_center_point(landmarks, left_bodypart, right_bodypart):\n", + " \"\"\"Calculates the center point of the two given landmarks.\"\"\"\n", + "\n", + " left = tf.gather(landmarks, left_bodypart.value, axis=1)\n", + " right = tf.gather(landmarks, right_bodypart.value, axis=1)\n", + " center = left * 0.5 + right * 0.5\n", + " return center\n", + "\n", + "\n", + "def get_pose_size(landmarks, torso_size_multiplier=2.5):\n", + " \"\"\"Calculates pose size.\n", + "\n", + " It is the maximum of two values:\n", + " * Torso size multiplied by `torso_size_multiplier`\n", + " * Maximum distance from pose center to any pose landmark\n", + " \"\"\"\n", + " # Hips center\n", + " hips_center = get_center_point(landmarks, BodyPart.LEFT_HIP, \n", + " BodyPart.RIGHT_HIP)\n", + "\n", + " # Shoulders center\n", + " shoulders_center = get_center_point(landmarks, BodyPart.LEFT_SHOULDER,\n", + " BodyPart.RIGHT_SHOULDER)\n", + "\n", + " # Torso size as the minimum body size\n", + " torso_size = tf.linalg.norm(shoulders_center - hips_center)\n", + "\n", + " # Pose center\n", + " pose_center_new = get_center_point(landmarks, BodyPart.LEFT_HIP, \n", + " BodyPart.RIGHT_HIP)\n", + " pose_center_new = tf.expand_dims(pose_center_new, axis=1)\n", + " # Broadcast the pose center to the same size as the landmark vector to\n", + " # perform substraction\n", + " pose_center_new = tf.broadcast_to(pose_center_new,\n", + " [tf.size(landmarks) // (17*2), 17, 2])\n", + "\n", + " # Dist to pose center\n", + " d = tf.gather(landmarks - pose_center_new, 0, axis=0,\n", + " name=\"dist_to_pose_center\")\n", + " # Max dist to pose center\n", + " max_dist = tf.reduce_max(tf.linalg.norm(d, axis=0))\n", + "\n", + " # Normalize scale\n", + " pose_size = tf.maximum(torso_size * torso_size_multiplier, max_dist)\n", + "\n", + " return pose_size\n", + "\n", + "\n", + "def normalize_pose_landmarks(landmarks):\n", + " \"\"\"Normalizes the landmarks translation by moving the pose center to (0,0) and\n", + " scaling it to a constant pose size.\n", + " \"\"\"\n", + " # Move landmarks so that the pose center becomes (0,0)\n", + " pose_center = get_center_point(landmarks, BodyPart.LEFT_HIP, \n", + " BodyPart.RIGHT_HIP)\n", + " pose_center = tf.expand_dims(pose_center, axis=1)\n", + " # Broadcast the pose center to the same size as the landmark vector to perform\n", + " # substraction\n", + " pose_center = tf.broadcast_to(pose_center, \n", + " [tf.size(landmarks) // (17*2), 17, 2])\n", + " landmarks = landmarks - pose_center\n", + "\n", + " # Scale the landmarks to a constant pose size\n", + " pose_size = get_pose_size(landmarks)\n", + " landmarks /= pose_size\n", + "\n", + " return landmarks\n", + "\n", + "\n", + "def landmarks_to_embedding(landmarks_and_scores):\n", + " \"\"\"Converts the input landmarks into a pose embedding.\"\"\"\n", + " # Reshape the flat input into a matrix with shape=(17, 3)\n", + " reshaped_inputs = keras.layers.Reshape((17, 3))(landmarks_and_scores)\n", + "\n", + " # Normalize landmarks 2D\n", + " landmarks = normalize_pose_landmarks(reshaped_inputs[:, :, :2])\n", + "\n", + " # Flatten the normalized landmark coordinates into a vector\n", + " embedding = keras.layers.Flatten()(landmarks)\n", + "\n", + " return embedding" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PI7Wb3Bagau3" + }, + "source": [ + "### Defina um modelo do Keras para a classificação de poses\n", + "\n", + "Nosso modelo do Keras recebe os landmarks detectados da pose, calcula o embedding e prevê a classe dela." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1Pte6b1bgWKv" + }, + "outputs": [ + + ], + "source": [ + "# Define the model\n", + "inputs = tf.keras.Input(shape=(51))\n", + "embedding = landmarks_to_embedding(inputs)\n", + "\n", + "layer = keras.layers.Dense(128, activation=tf.nn.relu6)(embedding)\n", + "layer = keras.layers.Dropout(0.5)(layer)\n", + "layer = keras.layers.Dense(64, activation=tf.nn.relu6)(layer)\n", + "layer = keras.layers.Dropout(0.5)(layer)\n", + "outputs = keras.layers.Dense(len(class_names), activation=\"softmax\")(layer)\n", + "\n", + "model = keras.Model(inputs, outputs)\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5ZuMwd7Ugtsa" + }, + "outputs": [ + + ], + "source": [ + "model.compile(\n", + " optimizer='adam',\n", + " loss='categorical_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", + "# Add a checkpoint callback to store the checkpoint that has the highest\n", + "# validation accuracy.\n", + "checkpoint_path = \"weights.best.hdf5\"\n", + "checkpoint = keras.callbacks.ModelCheckpoint(checkpoint_path,\n", + " monitor='val_accuracy',\n", + " verbose=1,\n", + " save_best_only=True,\n", + " mode='max')\n", + "earlystopping = keras.callbacks.EarlyStopping(monitor='val_accuracy', \n", + " patience=20)\n", + "\n", + "# Start training\n", + "history = model.fit(X_train, y_train,\n", + " epochs=200,\n", + " batch_size=16,\n", + " validation_data=(X_val, y_val),\n", + " callbacks=[checkpoint, earlystopping])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pNVqmd2JO6Rp" + }, + "outputs": [ + + ], + "source": [ + "# Visualize the training history to see whether you're overfitting.\n", + "plt.plot(history.history['accuracy'])\n", + "plt.plot(history.history['val_accuracy'])\n", + "plt.title('Model accuracy')\n", + "plt.ylabel('accuracy')\n", + "plt.xlabel('epoch')\n", + "plt.legend(['TRAIN', 'VAL'], loc='lower right')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "m_byMBVQgyQm" + }, + "outputs": [ + + ], + "source": [ + "# Evaluate the model using the TEST dataset\n", + "loss, accuracy = model.evaluate(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JPnPmwjn9452" + }, + "source": [ + "### Desenhe a matriz de confusão para entender melhor o desempenho do modelo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CJuVw7gygyyd" + }, + "outputs": [ + + ], + "source": [ + "def plot_confusion_matrix(cm, classes,\n", + " normalize=False,\n", + " title='Confusion matrix',\n", + " cmap=plt.cm.Blues):\n", + " \"\"\"Plots the confusion matrix.\"\"\"\n", + " if normalize:\n", + " cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n", + " print(\"Normalized confusion matrix\")\n", + " else:\n", + " print('Confusion matrix, without normalization')\n", + "\n", + " plt.imshow(cm, interpolation='nearest', cmap=cmap)\n", + " plt.title(title)\n", + " plt.colorbar()\n", + " tick_marks = np.arange(len(classes))\n", + " plt.xticks(tick_marks, classes, rotation=55)\n", + " plt.yticks(tick_marks, classes)\n", + " fmt = '.2f' if normalize else 'd'\n", + " thresh = cm.max() / 2.\n", + " for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n", + " plt.text(j, i, format(cm[i, j], fmt),\n", + " horizontalalignment=\"center\",\n", + " color=\"white\" if cm[i, j] > thresh else \"black\")\n", + "\n", + " plt.ylabel('True label')\n", + " plt.xlabel('Predicted label')\n", + " plt.tight_layout()\n", + "\n", + "# Classify pose in the TEST dataset using the trained model\n", + "y_pred = model.predict(X_test)\n", + "\n", + "# Convert the prediction result to class name\n", + "y_pred_label = [class_names[i] for i in np.argmax(y_pred, axis=1)]\n", + "y_true_label = [class_names[i] for i in np.argmax(y_test, axis=1)]\n", + "\n", + "# Plot the confusion matrix\n", + "cm = confusion_matrix(np.argmax(y_test, axis=1), np.argmax(y_pred, axis=1))\n", + "plot_confusion_matrix(cm,\n", + " class_names,\n", + " title ='Confusion Matrix of Pose Classification Model')\n", + "\n", + "# Print the classification report\n", + "print('\\nClassification Report:\\n', classification_report(y_true_label,\n", + " y_pred_label))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YPmtRf79GkCa" + }, + "source": [ + "### (Opcional) Investigue previsões incorretas\n", + "\n", + "Você pode analisar as poses do dataset `TEST` que foram previstas incorretamente para ver se a exatidão do modelo pode ser melhorada.\n", + "\n", + "Observação: isso só funciona se você executou a etapa 1, porque precisa dos arquivos de imagem das poses na sua máquina local para exibi-los." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bdJdwOkFGonK" + }, + "outputs": [ + + ], + "source": [ + "if is_skip_step_1:\n", + " raise RuntimeError('You must have run step 1 to run this cell.')\n", + "\n", + "# If step 1 was skipped, skip this step.\n", + "IMAGE_PER_ROW = 3\n", + "MAX_NO_OF_IMAGE_TO_PLOT = 30\n", + "\n", + "# Extract the list of incorrectly predicted poses\n", + "false_predict = [id_in_df for id_in_df in range(len(y_test)) \\\n", + " if y_pred_label[id_in_df] != y_true_label[id_in_df]]\n", + "if len(false_predict) > MAX_NO_OF_IMAGE_TO_PLOT:\n", + " false_predict = false_predict[:MAX_NO_OF_IMAGE_TO_PLOT]\n", + "\n", + "# Plot the incorrectly predicted images\n", + "row_count = len(false_predict) // IMAGE_PER_ROW + 1\n", + "fig = plt.figure(figsize=(10 * IMAGE_PER_ROW, 10 * row_count))\n", + "for i, id_in_df in enumerate(false_predict):\n", + " ax = fig.add_subplot(row_count, IMAGE_PER_ROW, i + 1)\n", + " image_path = os.path.join(images_out_test_folder,\n", + " df_test.iloc[id_in_df]['file_name'])\n", + "\n", + " image = cv2.imread(image_path)\n", + " plt.title(\"Predict: %s; Actual: %s\"\n", + " % (y_pred_label[id_in_df], y_true_label[id_in_df]))\n", + " plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uhY0VeDkFK7W" + }, + "source": [ + "## Parte 3: converta o modelo de classificação de poses para o TensorFlow Lite\n", + "\n", + "Você converterá o modelo de classificação de poses do Keras para o formato do TensorFlow Lite para implantá-lo em aplicativos móveis, navegadores da Web e dispositivos de borda. Ao converter o modelo, você aplicará a [quantização de intervalo dinâmico](https://www.tensorflow.org/lite/performance/post_training_quant) para reduzir o tamanho do modelo do TensorFlow Lite para classificação de poses em 4 vezes com uma perda de exatidão insignificante.\n", + "\n", + "Observação: o TensorFlow Lite é compatível com vários esquemas de quantização. Veja a [documentação](https://www.tensorflow.org/lite/performance/model_optimization) se você tiver interesse em saber mais." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FmwEAgi2Flb3" + }, + "outputs": [ + + ], + "source": [ + "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", + "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", + "tflite_model = converter.convert()\n", + "\n", + "print('Model size: %dKB' % (len(tflite_model) / 1024))\n", + "\n", + "with open('pose_classifier.tflite', 'wb') as f:\n", + " f.write(tflite_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XUOQwuBP6jMH" + }, + "source": [ + "Em seguida, você escreverá o arquivo de rótulos com o mapeamento de índices de classes para nomes de classes legíveis por humanos." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZVW9j5vF6hBM" + }, + "outputs": [ + + ], + "source": [ + "with open('pose_labels.txt', 'w') as f:\n", + " f.write('\\n'.join(class_names))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "H4T0HFGCve-Y" + }, + "source": [ + "Como você aplicou a quantização para reduzir o tamanho do modelo, vamos avaliar o modelo do TFLite quantizado para verificar se a queda na exatidão é aceitável." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rv4fZFNcsN-1" + }, + "outputs": [ + + ], + "source": [ + "def evaluate_model(interpreter, X, y_true):\n", + " \"\"\"Evaluates the given TFLite model and return its accuracy.\"\"\"\n", + " input_index = interpreter.get_input_details()[0][\"index\"]\n", + " output_index = interpreter.get_output_details()[0][\"index\"]\n", + "\n", + " # Run predictions on all given poses.\n", + " y_pred = []\n", + " for i in range(len(y_true)):\n", + " # Pre-processing: add batch dimension and convert to float32 to match with\n", + " # the model's input data format.\n", + " test_image = X[i: i + 1].astype('float32')\n", + " interpreter.set_tensor(input_index, test_image)\n", + "\n", + " # Run inference.\n", + " interpreter.invoke()\n", + "\n", + " # Post-processing: remove batch dimension and find the class with highest\n", + " # probability.\n", + " output = interpreter.tensor(output_index)\n", + " predicted_label = np.argmax(output()[0])\n", + " y_pred.append(predicted_label)\n", + "\n", + " # Compare prediction results with ground truth labels to calculate accuracy.\n", + " y_pred = keras.utils.to_categorical(y_pred)\n", + " return accuracy_score(y_true, y_pred)\n", + "\n", + "# Evaluate the accuracy of the converted TFLite model\n", + "classifier_interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", + "classifier_interpreter.allocate_tensors()\n", + "print('Accuracy of TFLite model: %s' %\n", + " evaluate_model(classifier_interpreter, X_test, y_test))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-HWqcersePiY" + }, + "source": [ + "Agora, você pode baixar o modelo do TFLite (`pose_classifier.tflite`) e o arquivo de rótulos (`pose_labels.txt`) para classificar as poses personalizadas. Veja o aplicativo de amostra [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/pose_estimation/android) e [Python/Raspberry Pi](https://github.com/tensorflow/examples/tree/master/lite/examples/pose_estimation/raspberry_pi) para um exemplo completo de como usar o modelo de classificação de poses do TFLite." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KvcM_LkApOT3" + }, + "outputs": [ + + ], + "source": [ + "!zip pose_classifier.zip pose_labels.txt pose_classifier.tflite" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VQ-i27VypI1u" + }, + "outputs": [ + + ], + "source": [ + "# Download the zip archive if running on Colab.\n", + "try:\n", + " from google.colab import files\n", + " files.download('pose_classifier.zip')\n", + "except:\n", + " pass" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "pose_classification.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/mlir/dialects.md b/site/pt-br/mlir/dialects.md new file mode 100644 index 0000000000..bbfebbbda5 --- /dev/null +++ b/site/pt-br/mlir/dialects.md @@ -0,0 +1,19 @@ +# Dialetos do MLIR + +## Visão geral + +Para separar diferentes alvos de hardware e software, o MLIR tem "dialetos", incluindo: + +- TensorFlow IR, que representa tudo o que é possível nos grafos do TensorFlow. +- XLA HLO IR, que foi criado para aproveitar as capacidades de compilação do XLA (com saída para, entre outros, TPUs). +- Um dialeto affine experimental, que foca em otimizações e [representações poliédricas](https://en.wikipedia.org/wiki/Polytope_model). +- LLVM IR, que tem um mapeamento 1:1 com a própria representação do LLVM, permitindo que o MLIR emita o código de GPU e CPU pelo LLVM. +- TensorFlow Lite, que traduzirá para código de execução em plataformas móveis. + +Cada dialeto consiste em um conjunto de operações definidas que têm invariantes colocadas, como: "Isso é um operador binário, e as entradas e saídas têm os mesmos tipos". + +## Somando ao MLIR + +O MLIR não tem uma lista fixa/integrada de operações conhecidas globalmente (nenhum "intrínseco"). Os dialetos podem definir tipos inteiramente personalizados, que é como o MLIR pode modelar algo como o sistema de tipo IR do LLVM (que tem agregados de primeira classe), abstrações de domínio importantes para aceleradores otimizados por ML como tipos quantizados e até os sistemas de tipo Swift ou Clang (que foram criados com base em nós de declaração Swift/Clang) no futuro. + +Se você quiser conectar um compilador de baixo nível, deve criar um novo dialeto e os rebaixamentos entre o dialeto do grafo do TensorFlow e seu dialeto. Isso suaviza o caminho para os fabricantes de compiladores e hardware. Você pode até segmentar dialetos em diferentes níveis no mesmo modelo; os otimizados de nível superior vão respeitar as partes desconhecidas do IR e aguardar um nível inferior lidar com elas. diff --git a/site/pt-br/mlir/tf_passes.md b/site/pt-br/mlir/tf_passes.md new file mode 100644 index 0000000000..a1b2179e2c --- /dev/null +++ b/site/pt-br/mlir/tf_passes.md @@ -0,0 +1,7 @@ +# Passagens do TensorFlow + +[TOC] + +## Passagens de dialetos do TF + +<<_includes/tf_passes.md>> diff --git a/site/pt-br/tfx/api_overview.md b/site/pt-br/tfx/api_overview.md new file mode 100644 index 0000000000..ea3617e991 --- /dev/null +++ b/site/pt-br/tfx/api_overview.md @@ -0,0 +1,35 @@ +# Referência da API TFX + +## TensorFlow Extended + +- [TensorFlow Extended](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1) + +## Validação de dados + +- [Validação de dados](https://www.tensorflow.org/tfx/data_validation/api_docs/python/tfdv) + +## Transform + +- [Transform](https://www.tensorflow.org/tfx/transform/api_docs/python/tft) +- [Transform.beam](https://www.tensorflow.org/tfx/transform/api_docs/python/tft_beam) + +## Análise de modelo + +- Análise de modelo + +## Serviço + +- [API cliente (REST)](https://www.tensorflow.org/tfx/serving/api_rest) +- [API servidor (C++)](https://www.tensorflow.org/tfx/serving/api_docs/cc) + +## Metadados de ML + +- [Metadados de ML](https://www.tensorflow.org/tfx/ml_metadata/api_docs/python/mlmd) + +## Metadados do TF + +- Metadados de ML + +## Bibliotecas compartilhadas básicas do TFX (`tfx_bsl`) + +- [tfx_bsl](https://www.tensorflow.org/tfx/tfx_bsl/api_docs/python/tfx_bsl/public) diff --git a/site/pt-br/tfx/guide/airflow.md b/site/pt-br/tfx/guide/airflow.md new file mode 100644 index 0000000000..1605c4e00f --- /dev/null +++ b/site/pt-br/tfx/guide/airflow.md @@ -0,0 +1,7 @@ +# Orquestração de pipelines TFX + +## Apache Airflow + +O [Apache Airflow](https://airflow.apache.org/) é uma plataforma para criar, agendar e monitorar fluxos de trabalho de forma programática. O TFX usa o Airflow para criar workflows como gráficos acíclicos direcionados (DAGs) de tarefas. O agendador do Airflow executa tarefas numa série de workers enquanto segue as dependências especificadas. Utilitários avançados de linha de comando facilitam a realização de cirurgias complexas em DAGs. A interface de usuário avançada facilita a visualização de pipelines em execução na produção, o monitoramento do progresso e a solução de problemas quando necessário. Quando os fluxos de trabalho são definidos como código, eles se tornam mais fáceis de manter, versionáveis, testáveis ​​e colaborativos. + +Veja [Apache Airflow](https://airflow.apache.org/) para mais detalhes sobre como instalar e usar o Apache Airflow. diff --git a/site/pt-br/tfx/guide/beam.md b/site/pt-br/tfx/guide/beam.md new file mode 100644 index 0000000000..c6d4f07559 --- /dev/null +++ b/site/pt-br/tfx/guide/beam.md @@ -0,0 +1,92 @@ +# Apache Beam e TFX + +O [Apache Beam](https://beam.apache.org/) fornece um framework para executar tarefas de processamento de dados em lote e via streaming que são executadas em vários motores de execução. Diversas bibliotecas do TFX usam o Beam para executar tarefas, o que permite um alto grau de escalabilidade em clusters de computação. O Beam inclui suporte para uma variedade de motores de execução ou "executores", incluindo um executor direto que é executado num único nó de computação e é muito útil para desenvolvimento, testes ou pequenas implantações. O Beam fornece uma camada de abstração que permite que o TFX seja executado em qualquer executor compatível sem modificações no código. O TFX usa a API Beam em Python, portanto, é limitado aos executores compatíveis com a API Python. + +## Implantação e escalabilidade + +À medida que os requisitos de carga de trabalho aumentam, o Beam pode ser escalonado para implantações muito grandes em grandes clusters de computação. Isto é limitado apenas pela escalabilidade do executor subjacente. Os executores em grandes implantações normalmente serão implantados num sistema de orquestração de containers, como Kubernetes ou Apache Mesos, para automatizar a implantação, o escalonamento e o gerenciamento de aplicativos. + +Veja a documentação do [Apache Beam](https://beam.apache.org/) para mais informações sobre o Apache Beam. + +Para usuários do Google Cloud, o [Dataflow](https://cloud.google.com/dataflow) é o executor recomendado, que fornece uma plataforma econômica e sem servidor por meio de escalonamento automático de recursos, rebalanceamento dinâmico de trabalho, integração profunda com outros serviços do Google Cloud, segurança integrada e monitoramento. + +## Código Python personalizado e dependências + +Uma complexidade notável do uso do Beamnum pipeline TFX é lidar com código personalizado e/ou as dependências necessárias de módulos Python adicionais. Aqui estão alguns exemplos de quando isso pode ser um problema: + +- preprocessing_fn precisa se referir ao próprio módulo Python do usuário +- um extrator personalizado para o componente Evaluator +- módulos personalizados que herdam (como subclasses) de um componente TFX + +O TFX conta com o suporte do Beam para [gerenciar dependências de pipeline do Python](https://beam.apache.org/documentation/sdks/python-pipeline-dependencies/) para lidar com dependências do Python. Atualmente existem duas maneiras de gerenciar isso: + +1. Fornecendo código Python e dependências como um pacote fonte +2. [Somente Dataflow] Usando uma imagem de container para um worker + +Esses são discutidos a seguir. + +### Fornecendo código Python e dependências como um pacote fonte + +Isto é recomendado para usuários que: + +1. Estão familiarizados com empacotamento Python e +2. Usem apenas código-fonte Python (ou seja, sem módulos C ou bibliotecas compartilhadas). + +Siga um dos caminhos em [Gerenciando dependências de pipeline do Python](https://beam.apache.org/documentation/sdks/python-pipeline-dependencies/) para fornecer isto usando um dos seguintes argumentos beam_pipeline_args: + +- --setup_file +- --extra_package +- --requirements_file + +Aviso: Em qualquer um dos casos acima, certifique-se de que a mesma versão do `tfx` esteja listada como uma dependência. + +### [Somente Dataflow] Usando uma imagem de container para um worker + +O TFX 0.26.0 e versões posteriores têm suporte experimental para o uso de [imagem de container personalizada](https://beam.apache.org/documentation/runtime/environments/#customizing-container-images) para workers Dataflow. + +Para usar isto, você precisa: + +- Criar uma imagem Docker que tenha `tfx` e o código personalizado e as dependências dos usuários pré-instalados. + - Para usuários que (1) usam `tfx>=0.26` e (2) usam python 3.7 para desenvolver seus pipelines, a maneira mais fácil de fazer isso é estendendo a versão correspondente da imagem oficial `tensorflow/tfx`: + +```Dockerfile +# You can use a build-arg to dynamically pass in the +# version of TFX being used to your Dockerfile. + +ARG TFX_VERSION +FROM tensorflow/tfx:${TFX_VERSION} +# COPY your code and dependencies in +``` + +- Enviar a imagem criada para um registro de imagens em container que é acessível pelo projeto usado pelo Dataflow. + - Os usuários do Google Cloud podem considerar o uso do [Cloud Build](https://cloud.google.com/cloud-build/docs/quickstart-build), que automatiza perfeitamente as etapas acima. +- Fornecer os seguintes `beam_pipeline_args`: + +```python +beam_pipeline_args.extend([ + '--runner=DataflowRunner', + '--project={project-id}', + '--worker_harness_container_image={image-ref}', + '--experiments=use_runner_v2', +]) +``` + +**TODO(b/171733562): remover use_runner_v2 quando ele for padrão para o Dataflow.** + +**TODO(b/179738639): criar documentação sobre como testar o container personalizado localmente após https://issues.apache.org/jira/browse/BEAM-5440.** + +## Argumentos do pipeline do Beam + +Diversos componentes do TFX dependem do Beam para processamento distribuído de dados. Eles são configurados com `beam_pipeline_args`, que é especificado durante a criação do pipeline: + +```python +my_pipeline = Pipeline( + ..., + beam_pipeline_args=[...]) +``` + +O TFX 0.30 ou superior adiciona uma interface, `with_beam_pipeline_args`, para estender os argumentos do Beam no nível do pipeline por componente: + +```python +example_gen = CsvExampleGen(input_base=data_root).with_beam_pipeline_args([...]) +``` diff --git a/site/pt-br/tfx/guide/build_local_pipeline.md b/site/pt-br/tfx/guide/build_local_pipeline.md new file mode 100644 index 0000000000..099e654347 --- /dev/null +++ b/site/pt-br/tfx/guide/build_local_pipeline.md @@ -0,0 +1,278 @@ +# Construindo um pipeline TFX localmente + +O TFX facilita a orquestração do fluxo de trabalho de machine learning (ML) como um pipeline, para: + +- Automatizar seu processo de ML, o que permite treinar, avaliar e implantar regularmente seu modelo. +- Criar pipelines de ML que incluem análise profunda do desempenho do modelo e validação de modelos recém-treinados para garantir desempenho e confiabilidade. +- Monitorar dados de treinamento em busca de anomalias e eliminar distorções no fornecimento de treinamento +- Aumentar a velocidade da experimentação executando um pipeline com diferentes conjuntos de hiperparâmetros. + +Um processo típico de desenvolvimento de pipeline começa numa máquina local, com análise de dados e configuração de componentes, antes de ser implantado na produção. Este guia descreve duas maneiras de construir um pipeline localmente. + +- Personalizando um modelo de pipeline do TFX para atender às necessidades do seu workflows de ML. Os modelos de pipeline do TFX são workflows pré-construídos que demonstram as práticas recomendadas usando os componentes padrão do TFX. +- Criando um pipeline usando TFX. Neste caso de uso, você define um pipeline sem partir de um modelo. + +Ao desenvolver seu pipeline, você poderá executá-lo com `LocalDagRunner`. Depois que os componentes do pipeline tiverem sido bem definidos e testados, você pode usar um orquestrador de nível de produção, como Kubeflow ou Airflow. + +## Antes de começar + +O TFX é um pacote Python, então você precisará configurar um ambiente de desenvolvimento Python, como um ambiente virtual ou um container do Docker. Depois disso faça: + +```bash +pip install tfx +``` + +Se você é novato em pipelines TFX, [aprenda mais sobre os principais conceitos dos pipelines TFX](understanding_tfx_pipelines) antes de continuar. + +## Crie um pipeline usando um modelo + +Os modelos de pipeline do TFX facilitam o início do desenvolvimento de um pipeline, fornecendo um conjunto pré-construído de definições de pipeline que você pode adaptar para seu caso de uso. + +As seções a seguir descrevem como criar uma cópia de um modelo e personalizá-lo para atender às suas necessidades. + +### Crie uma cópia do modelo do pipeline + +1. Veja a lista dos modelos de pipeline TFX disponíveis: + +
+        tfx template list
+        
+ +2. Selecione um modelo da lista + +
+        tfx template copy --model=<var>template</var> --pipeline_name=<var>pipeline-name</var> \
+        --destination_path=<var>destination-path</var>
+        
+ + Substitua o seguinte: + + - template: O nome do modelo que você deseja copiar. + - pipeline-name: o nome do pipeline a ser criado. + - destination-path: o caminho para copiar o modelo. + + Saiba mais sobre o [comando `tfx template copy`](cli#copy). + +3. Uma cópia do modelo de pipeline foi criada no caminho especificado. + +Observação: O restante deste guia pressupõe que você selecionou o modelo `penguin`. + +### Explore o modelo do pipeline + +Esta seção fornece uma visão geral da estrutura criada por um modelo. + +1. Explore os diretórios e arquivos que foram copiados para o diretório raiz do seu pipeline + + - Um diretório **pipeline** com + + - `pipeline.py` – define o pipeline e lista quais componentes estão sendo usados + - `configs.py` - contém detalhes de configuração, como de onde vêm os dados ou qual orquestrador está sendo usado + + - Um diretório **data** + + - Normalmente contém um arquivo `data.csv`, que é a fonte padrão para `ExampleGen`. Você pode alterar a fonte de dados em `configs.py`. + + - Um diretório **models** com código de pré-processamento e implementações de modelo + + - O modelo copia executores DAG para ambiente local e Kubeflow. + + - Alguns modelos também incluem Notebooks Python para que você possa explorar seus dados e artefatos com metadados de aprendizado de máquina. + +2. Execute os seguintes comandos no diretório do pipeline: + +
+        tfx pipeline create --pipeline_path local_runner.py
+        
+ +
+        tfx run create --pipeline_name <var>pipeline_name</var>
+        
+ + O comando cria uma execução de pipeline usando `LocalDagRunner`, que adiciona os seguintes diretórios ao pipeline: + + - Um diretório **tfx_metadata** que contém o armazenamento de metadados de ML usado localmente. + - Um diretório **tfx_pipeline_output** que contém as saídas de arquivos do pipeline. + + Observação: `LocalDagRunner` é um dos vários orquestradores suportados no TFX. É especialmente adequado para executar pipelines localmente para iterações mais rápidas, possivelmente com datasets menores. `LocalDagRunner` pode não ser adequado para uso em produção, pois é executado numa única máquina, o que é mais vulnerável à perda de trabalho se o sistema ficar indisponível. O TFX também oferece suporte a orquestradores como Apache Beam, Apache Airflow e Kubeflow Pipeline. Se você estiver usando o TFX com um orquestrador diferente, use o executor DAG apropriado para esse orquestrador. + + Observação: no momento em que este artigo foi escrito, `LocalDagRunner` era usado no modelo `penguin`, enquanto o modelo `taxi` usava Apache Beam. Os arquivos de configuração do modelo `taxi` estão configurados para usar o Beam e o comando CLI é o mesmo. + +3. Abra o arquivo `pipeline/configs.py` do seu pipeline e revise seu conteúdo. Este script define as opções de configuração usadas pelo pipeline e pelas funções do componente. É aqui que você especificaria coisas como a localização da fonte de dados ou o número de passos de treinamento numa execução. + +4. Abra o arquivo `pipeline/pipeline.py` do seu pipeline e revise seu conteúdo. Este script cria o pipeline do TFX. Inicialmente, o pipeline contém apenas um componente `ExampleGen`. + + - Siga as instruções nos comentários **TODO** em `pipeline.py` para adicionar mais passos ao pipeline. + +5. Abra o arquivo `local_runner.py` e revise seu conteúdo. Este script cria uma execução de pipeline e especifica os *parâmetros* da execução, como `data_path` e `preprocessing_fn`. + +6. Você revisou a estrutura criado pelo modelo e criou uma execução de pipeline usando `LocalDagRunner`. Em seguida, você precisa personalizar o modelo para atender às suas necessidades. + +### Personalize seu pipeline + +Esta seção fornece uma visão geral de como começar a personalizar seu modelo. + +1. Projete seu pipeline. A estrutura fornecida por um modelo ajuda a implementar um pipeline para dados tabulares usando os componentes padrão do TFX. Se você estiver migrando um workflow de ML existente para um pipeline, talvez seja necessário revisar seu código para aproveitar ao máximo [os componentes padrão do TFX](index#tfx_standard_components). Você também pode precisar criar [componentes personalizados](understanding_custom_components) que implementem recursos exclusivos do seu workflow ou que ainda não sejam suportados pelos componentes padrão do TFX. + +2. Depois de projetar seu pipeline, personalize-o iterativamente seguindo o processo a seguir. Comece pelo componente que consome dados no seu pipeline, que geralmente é o componente `ExampleGen`. + + 1. Personalize o pipeline ou um componente de acordo com seu caso de uso. Essas personalizações podem incluir alterações como: + + - Alteração de parâmetros do pipeline. + - Adição de componentes ao pipeline ou sua remoção. + - Substituição da fonte de dados de entrada. Essa fonte de dados pode ser um arquivo ou consultas em serviços como o BigQuery. + - Alteração da configuração de um componente no pipeline. + - Alteração da função de personalização de um componente. + + 2. Execute o componente localmente usando o script `local_runner.py` ou outro executor DAG apropriado se você estiver usando um orquestrador diferente. Se o script falhar, depure a falha e tente executar o script novamente. + + 3. Assim que essa personalização estiver funcionando, passe para a próxima personalização. + +3. Trabalhando de forma iterativa, você poderá personalizar cada etapa do fluxo de trabalho do modelo para atender às suas necessidades. + +## Crie um pipeline personalizado + +Use as instruções a seguir para saber mais sobre como criar um pipeline personalizado sem usar um modelo. + +1. Projete seu pipeline. Os componentes padrão do TFX fornecem funcionalidade comprovada para ajudá-lo a implementar um workflow de ML completo. Se você estiver migrando um workflow de ML existente para um pipeline, talvez seja necessário revisar seu código para aproveitar ao máximo os componentes padrão do TFX. Também pode ser necessário criar [componentes personalizados](understanding_custom_components) que implementem recursos como aumento de dados. + + - Saiba mais sobre os [componentes padrão do TFX](index#tfx_standard_components). + - Saiba mais sobre [componentes personalizados](understanding_custom_components). + +2. Crie um arquivo de script para definir seu pipeline usando o exemplo a seguir. Este guia refere-se a este arquivo como `my_pipeline.py`. + +
+        import os
+        from typing import Optional, Text, List
+        from absl import logging
+        from ml_metadata.proto import metadata_store_pb2
+        import tfx.v1 as tfx
+
+        PIPELINE_NAME = 'my_pipeline'
+        PIPELINE_ROOT = os.path.join('.', 'my_pipeline_output')
+        METADATA_PATH = os.path.join('.', 'tfx_metadata', PIPELINE_NAME, 'metadata.db')
+        ENABLE_CACHE = True
+
+        def create_pipeline(
+          pipeline_name: Text,
+          pipeline_root:Text,
+          enable_cache: bool,
+          metadata_connection_config: Optional[
+            metadata_store_pb2.ConnectionConfig] = None,
+          beam_pipeline_args: Optional[List[Text]] = None
+        ):
+          components = []
+
+          return tfx.dsl.Pipeline(
+                pipeline_name=pipeline_name,
+                pipeline_root=pipeline_root,
+                components=components,
+                enable_cache=enable_cache,
+                metadata_connection_config=metadata_connection_config,
+                beam_pipeline_args=beam_pipeline_args, <!-- needed? -->
+            )
+
+        def run_pipeline():
+          my_pipeline = create_pipeline(
+              pipeline_name=PIPELINE_NAME,
+              pipeline_root=PIPELINE_ROOT,
+              enable_cache=ENABLE_CACHE,
+              metadata_connection_config=tfx.orchestration.metadata.sqlite_metadata_connection_config(METADATA_PATH)
+              )
+
+          tfx.orchestration.LocalDagRunner().run(my_pipeline)
+
+        if __name__ == '__main__':
+          logging.set_verbosity(logging.INFO)
+          run_pipeline()
+        
+ + Nos próximos passos, você definirá seu pipeline em `create_pipeline` e executará seu pipeline localmente usando o executor local. + + Construa seu pipeline iterativamente usando o processo a seguir. + + 1. Personalize o pipeline ou um componente de acordo com seu caso de uso. Essas personalizações podem incluir alterações como: + + - Alteração de parâmetros do pipeline. + - Adição de componentes ao pipeline ou sua remoção. + - Substituição de um arquivo de entrada de dados. + - Alteração da configuração de um componente no pipeline. + - Alteração da função de personalização de um componente. + + 2. Execute o componente localmente usando o executor local ou executando o script diretamente. Se o script falhar, depure a falha e tente executar o script novamente. + + 3. Assim que essa personalização estiver funcionando, passe para a próxima personalização. + + Comece no primeiro nó do workflow do seu pipeline, normalmente o primeiro nó consome dados para o seu pipeline. + +3. Adicione o primeiro nó do workflow ao pipeline. Neste exemplo, o pipeline usa o componente padrão `ExampleGen` para carregar um CSV de um diretório em `./data`. + +
+        from tfx.components import CsvExampleGen
+
+        DATA_PATH = os.path.join('.', 'data')
+
+        def create_pipeline(
+          pipeline_name: Text,
+          pipeline_root:Text,
+          data_path: Text,
+          enable_cache: bool,
+          metadata_connection_config: Optional[
+            metadata_store_pb2.ConnectionConfig] = None,
+          beam_pipeline_args: Optional[List[Text]] = None
+        ):
+          components = []
+
+          example_gen = tfx.components.CsvExampleGen(input_base=data_path)
+          components.append(example_gen)
+
+          return tfx.dsl.Pipeline(
+                pipeline_name=pipeline_name,
+                pipeline_root=pipeline_root,
+                components=components,
+                enable_cache=enable_cache,
+                metadata_connection_config=metadata_connection_config,
+                beam_pipeline_args=beam_pipeline_args, <!-- needed? -->
+            )
+
+        def run_pipeline():
+          my_pipeline = create_pipeline(
+            pipeline_name=PIPELINE_NAME,
+            pipeline_root=PIPELINE_ROOT,
+            data_path=DATA_PATH,
+            enable_cache=ENABLE_CACHE,
+            metadata_connection_config=tfx.orchestration.metadata.sqlite_metadata_connection_config(METADATA_PATH)
+            )
+
+          tfx.orchestration.LocalDagRunner().run(my_pipeline)
+        
+ + `CsvExampleGen` cria registros de exemplo serializados usando os dados do CSV no caminho de dados especificado. Definindo o parâmetro `input_base` do componente `CsvExampleGen` com a raiz de dados. + +4. Crie um diretório `data` no mesmo diretório que `my_pipeline.py`. Adicione um pequeno arquivo CSV ao diretório `data`. + +5. Use o seguinte comando para executar seu script `my_pipeline.py`. + +
+        python my_pipeline.py
+        
+ + O resultado deve ser algo similar ao mostrado abaixo: + +
+        INFO:absl:Component CsvExampleGen depends on [].
+        INFO:absl:Component CsvExampleGen is scheduled.
+        INFO:absl:Component CsvExampleGen is running.
+        INFO:absl:Running driver for CsvExampleGen
+        INFO:absl:MetadataStore with DB connection initialized
+        INFO:absl:Running executor for CsvExampleGen
+        INFO:absl:Generating examples.
+        INFO:absl:Using 1 process(es) for Local pipeline execution.
+        INFO:absl:Processing input csv data ./data/* to TFExample.
+        WARNING:root:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.
+        INFO:absl:Examples generated.
+        INFO:absl:Running publisher for CsvExampleGen
+        INFO:absl:MetadataStore with DB connection initialized
+        INFO:absl:Component CsvExampleGen is finished.
+        
+ +6. Continue a adicionar componentes iterativamente ao seu pipeline. diff --git a/site/pt-br/tfx/guide/build_tfx_pipeline.md b/site/pt-br/tfx/guide/build_tfx_pipeline.md new file mode 100644 index 0000000000..44f63f787e --- /dev/null +++ b/site/pt-br/tfx/guide/build_tfx_pipeline.md @@ -0,0 +1,55 @@ +# Construindo pipelines TFX + +Observação: para uma visão conceitual dos pipelines do TFX, consulte [Noções básicas sobre pipelines do TFX](understanding_tfx_pipelines). + +Observação: quer construir seu primeiro pipeline antes de se aprofundar nos detalhes? Comece com [criando um pipeline usando um template](https://www.tensorflow.org/tfx/guide/build_local_pipeline#build_a_pipeline_using_a_template). + +## Usando a classe `Pipeline` + +Os pipelines do TFX são definidos usando a [classe `Pipeline`](https://github.com/tensorflow/tfx/blob/master/tfx/orchestration/pipeline.py){: .external }. O exemplo a seguir demonstra como usar a classe `Pipeline`. + +
+pipeline.Pipeline(
+    pipeline_name=<var>pipeline-name</var>,
+    pipeline_root=<var>pipeline-root</var>,
+    components=<var>components</var>,
+    enable_cache=<var>enable-cache</var>,
+    metadata_connection_config=<var>metadata-connection-config</var>,
+)
+
+ +Substitua o seguinte: + +- pipeline-name: o nome deste pipeline. O nome do pipeline deve ser único. + + O TFX usa o nome do pipeline ao consultar metadados de ML para artefatos de componentes de entrada. Reusar o nome de um pipeline pode resultar em comportamentos inesperados. + +- pipeline-root: o caminho raiz das saídas deste pipeline. O caminho raiz deve ser o caminho completo para um diretório ao qual seu orquestrador tenha acesso de leitura e gravação. Em tempo de execução, o TFX usa a raiz do pipeline para gerar caminhos de saída para artefatos de componentes. Esse diretório pode ser local ou num sistema de arquivos distribuído compatível, como Google Cloud Storage ou HDFS. + +- components: uma lista de instâncias de componentes que compõem o workflow deste pipeline. + +- enable-cache: (opcional.) Um valor booleano que indica se este pipeline usa cache para acelerar a execução do pipeline. + +- metadata-connection-config: (Optional.) A connection configuration for ML Metadata. + +## Definindo o grafo de execução do componente + +As instâncias de componentes produzem artefatos como saídas e normalmente dependem de artefatos produzidos por instâncias de componentes upstream como entradas. A sequência de execução para instâncias de componentes é determinada pela criação de um grafo acíclico direcionado (DAG) das dependências do artefato. + +Por exemplo, o componente padrão `ExampleGen` pode consumir dados de um arquivo CSV e gerar registros de exemplo serializados. O componente padrão `StatisticsGen` aceita esses registros de exemplo como entrada e produz estatísticas do dataset. Neste exemplo, a instância de `StatisticsGen` deve seguir `ExampleGen` porque `SchemaGen` depende da saída de `ExampleGen`. + +### Dependências baseadas em tarefas + +Observação: Normalmente não é recomendado usar dependências baseadas em tarefas. Definir o grafo de execução com dependências de artefato permite aproveitar as vantagens do rastreamento automático de linhagem de artefatos e dos recursos de cache do TFX. + +Você também pode definir dependências baseadas em tarefas usando os métodos [`add_upstream_node` e `add_downstream_node`](https://github.com/tensorflow/tfx/blob/master/tfx/components/base/base_node.py){: .external } do seu componente. `add_upstream_node` permite especificar que o componente atual deve ser executado após o componente especificado. `add_downstream_node` permite especificar que o componente atual deve ser executado antes do componente especificado. + +## Templates de pipeline + +A maneira mais fácil de configurar um pipeline rapidamente e ver como todas as peças se encaixam é usar um template. O uso de templates é abordado em [Construindo um pipeline TFX localmente](build_local_pipeline). + +## Caching + +O cache do pipeline TFX permite que seu pipeline ignore componentes que foram executados com o mesmo conjunto de entradas numa execução anterior do pipeline. Se o cache estiver habilitado, o pipeline tentará corresponder a assinatura de cada componente, o componente em si e o conjunto de entradas, com uma das execuções anteriores do componente desse pipeline. Se houver uma correspondência, o pipeline usará as saídas do componente da execução anterior. Se não houver correspondência, o componente é executado. + +Não use caches se o pipeline usar componentes não determinísticos. Por exemplo, se você criar um componente para produzir um número aleatório para seu pipeline, ativar o cache fará com que esse componente seja executado uma vez. Neste exemplo, as execuções subsequentes reusam o número aleatório da primeira execução em vez de gerar um número aleatório novo. diff --git a/site/pt-br/tfx/guide/bulkinferrer.md b/site/pt-br/tfx/guide/bulkinferrer.md new file mode 100644 index 0000000000..ff60846265 --- /dev/null +++ b/site/pt-br/tfx/guide/bulkinferrer.md @@ -0,0 +1,33 @@ +# O componente de pipeline BulkInferrer TFX + +O componente BulkInferrer TFX realiza inferência em lote em dados não rotulados. O InferenceResult gerado ([tensorflow_serving.apis.prediction_log_pb2.PredictionLog](https://github.com/tensorflow/serving/blob/master/tensorflow_serving/apis/prediction_log.proto)) contém as características originais e os resultados da previsão. + +O BulkInferrer consome: + +- Um modelo treinado no formato [SavedModel](https://www.tensorflow.org/guide/saved_model.md). +- tf.Examples não rotulados que contêm características. +- (Opcional) Resultado da validação do componente [Evaluator](https://www.tensorflow.org/tfx/guide/evaluator.md). + +O BulkInferrer produz: + +- [InferenceResult](https://github.com/tensorflow/tfx/blob/master/tfx/types/standard_artifacts.py) + +## Usando o componente BulkInferrer + +Um componente BulkInferrer TFX é usado para realizar inferência em lote em tf.Examples não rotulados. Normalmente é implantado depois de um componente [Evaluator](https://www.tensorflow.org/tfx/guide/evaluator.md) para realizar inferência com um modelo validado ou após um componente [Trainer](https://www.tensorflow.org/tfx/guide/trainer.md) para realizar inferência diretamente no modelo exportado. + +Ele atualmente realiza inferência de modelo na memória e inferência remota. A inferência remota requer que o modelo seja hospedado no Cloud AI Platform. + +Este é um exemplo de código típico: + +```python +bulk_inferrer = BulkInferrer( + examples=examples_gen.outputs['examples'], + model=trainer.outputs['model'], + model_blessing=evaluator.outputs['blessing'], + data_spec=bulk_inferrer_pb2.DataSpec(), + model_spec=bulk_inferrer_pb2.ModelSpec() +) +``` + +Mais detalhes estão disponíveis na [referência da API BulkInferrer](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/BulkInferrer). diff --git a/site/pt-br/tfx/guide/cli.md b/site/pt-br/tfx/guide/cli.md new file mode 100644 index 0000000000..0bf92bbc29 --- /dev/null +++ b/site/pt-br/tfx/guide/cli.md @@ -0,0 +1,1051 @@ +# Usando a interface de linha de comando do TFX + +A interface de linha de comando (CLI) do TFX executa uma gama completa de ações de pipeline usando orquestradores de pipeline, como Kubeflow Pipelines e Vertex Pipelines. O orquestrador local também pode ser usado para desenvolvimento ou depuração mais rápidos. Apache Beam e Apache Airflow são suportados como recursos experimentais. Por exemplo, você pode usar a CLI para: + +- Criar, atualizar e excluir pipelines. +- Executar um pipeline e monitorar a execução em vários orquestradores. +- Listar pipelines e execuções de pipeline. + +Observação: o TFX CLI atualmente não oferece garantias de compatibilidade. A interface CLI pode mudar à medida que novas versões forem lançadas. + +## Sobre a CLI do TFX + +A CLI do TFX é instalada como parte do pacote TFX. Todos os comandos CLI seguem a estrutura abaixo: + +
+tfx <var>command-group</var> <var>command</var> <var>flags</var>
+
+ +As seguintes opções de command-group são atualmente suportadas: + +- [tfx pipeline](#tfx-pipeline) - Criar e gerenciar pipelines TFX. +- [tfx run](#tfx-run) - Criar e gerenciar execuções de pipelines TFX em várias plataformas de orquestração. +- [tfx template](#tfx-template-experimental) - Comandos experimentais para listar e copiar templates de pipelines TFX. + +Cada grupo de comandos fornece um conjunto de comandos. Siga as instruções nas seções [comandos de pipeline](#tfx-pipeline), [comandos de execução](#tfx-run) e [comandos de template](#tfx-template-experimental) para saber mais sobre como usar esses comandos. + +Aviso: atualmente nem todos os comandos são suportados em todos os orquestradores. Esses comandos mencionam explicitamente os mecanismos suportados. + +Os sinalizadores permitem que você passe argumentos para os comandos da CLI. As palavras nos sinalizadores são separadas ou por um hífen (`-`) ou por sublinhado (`_`). Por exemplo, o sinalizador do nome do pipeline pode ser especificado como `--pipeline-name` ou `--pipeline_name`. Este documento especifica sinalizadores com sublinhados por questões de brevidade. Saiba mais sobre os [sinalizadores usados ​​na CLI do TFX](#understanding-tfx-cli-flags). + +## tfx pipeline + +A estrutura dos comandos no grupo de comandos `tfx pipeline` é a seguinte: + +
+tfx pipeline <var>command</var> <var>required-flags</var> [<var>optional-flags</var>]
+
+ +Use as seções a seguir para saber mais sobre os comandos no grupo de comandos do `tfx pipeline`. + +### create + +Cria um novo pipeline no orquestrador fornecido. + +Uso + +
+tfx pipeline create --pipeline_path=<var>pipeline-path</var> [--endpoint=<var>endpoint</var> --engine=<var>engine</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> \
+--build_image --build_base_image=<var>build-base-image</var>]
+
+ +
+
--pipeline_path=pipeline-path +
+
O caminho para o arquivo de configuração do pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP ao usar Kubeflow Pipelines.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + +
--build_image
+
+

(Opcional.) Quando o engine é kubeflow ou vertex, o TFX cria uma imagem de container para seu pipeline, se especificado. `Dockerfile` no diretório atual será usado e o TFX irá gerar um automaticamente se não existir.

+

A imagem construída será enviada para o registro remoto especificado em `KubeflowDagRunnerConfig` ou `KubeflowV2DagRunnerConfig`.

+
+
--build_base_image=build-base-image +
+
+

(Opcional.) Quando o engine é kubeflow, o TFX cria uma imagem de container para seu pipeline. A imagem base do build especifica a imagem de container base a ser usada ao criar a imagem do container do pipeline.

+
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx pipeline create --engine=kubeflow --pipeline_path=<var>pipeline-path</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> --endpoint=<var>endpoint</var> \
+--build_image
+
+ +Local: + +
+tfx pipeline create --engine=local --pipeline_path=<var>pipeline-path</var>
+
+ +Vertex: + +
+tfx pipeline create --engine=vertex --pipeline_path=<var>pipeline-path</var> \
+--build_image
+
+ +Para detectar automaticamente o motor do ambiente do usuário, simplesmente evite usar o sinalizador engine como no exemplo abaixo. Para mais detalhes, veja a seção sobre sinalizadores. + +
+tfx pipeline create --pipeline_path=<var>pipeline-path</var>
+
+ +### update + +Atualiza um pipeline existente no orquestrador fornecido. + +Uso: + +
+tfx pipeline update --pipeline_path=<var>pipeline-path</var> [--endpoint=<var>endpoint</var> --engine=<var>engine</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> --build_image]
+
+ +
+
--pipeline_path=pipeline-path +
+
O caminho para o arquivo de configuração do pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+
--build_image
+
+

(Opcional.) Quando o engine é kubeflow ou vertex, o TFX cria uma imagem de container para seu pipeline, se especificado. `Dockerfile` no diretório atual será usado.

+

A imagem construída será enviada para o registro remoto especificado em `KubeflowDagRunnerConfig` ou `KubeflowV2DagRunnerConfig`.

+
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx pipeline update --engine=kubeflow --pipeline_path=<var>pipeline-path</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> --endpoint=<var>endpoint</var> \
+--build_image
+
+ +Local: + +
+tfx pipeline update --engine=local --pipeline_path=<var>pipeline-path</var>
+
+ +Vertex: + +
+tfx pipeline update --engine=vertex --pipeline_path=<var>pipeline-path</var> \
+--build_image
+
+ +### compile + +Compila o arquivo de configuração do pipeline para criar um arquivo de workflow no Kubeflow e executa as seguintes verificações durante a compilação: + +1. Verifica se o caminho do pipeline é válido. +2. Verifica se os dados do pipeline foram extraídos com sucesso do arquivo de configuração do pipeline. +3. Verifica se o DagRunner na configuração do pipeline corresponde ao motor. +4. Verifica se o arquivo de workflow foi criado com sucesso no caminho do pacote fornecido (somente para Kubeflow). + +Recomenda-se usar antes de criar ou atualizar um pipeline. + +Uso: + +
+tfx pipeline compile --pipeline_path=<var>pipeline-path</var> [--engine=<var>engine</var>]
+
+ +
+
--pipeline_path=pipeline-path +
+
O caminho para o arquivo de configuração do pipeline.
+
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
+ +#### Exemplos: + +Kubeflow: + +
+tfx pipeline compile --engine=kubeflow --pipeline_path=<var>pipeline-path</var>
+
+ +Local: + +
+tfx pipeline compile --engine=local --pipeline_path=<var>pipeline-path</var>
+
+ +Vertex: + +
+tfx pipeline compile --engine=vertex --pipeline_path=<var>pipeline-path</var>
+
+ +### delete + +Exclui um pipeline do orquestrador fornecido. + +Uso: + +
+tfx pipeline delete --pipeline_path=<var>pipeline-path</var> [--endpoint=<var>endpoint</var> --engine=<var>engine</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--pipeline_path=pipeline-path +
+
O caminho para o arquivo de configuração do pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx pipeline delete --engine=kubeflow --pipeline_name=<var>pipeline-name</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +Local: + +
+tfx pipeline delete --engine=local --pipeline_name=<var>pipeline-name</var>
+
+ +Vertex: + +
+tfx pipeline delete --engine=vertex --pipeline_name=<var>pipeline-name</var>
+
+ +### list + +Lista todos os pipelines no orquestrador fornecido. + +Uso: + +
+tfx pipeline list [--endpoint=<var>endpoint</var> --engine=<var>engine</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx pipeline list --engine=kubeflow --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +Local: + +
+tfx pipeline list --engine=local
+
+ +Vertex: + +
+tfx pipeline list --engine=vertex
+
+ +## tfx run + +A estrutura dos comandos no grupo de comandos `tfx run` é a seguinte: + +
+tfx run <var>command</var> <var>required-flags</var> [<var>optional-flags</var>]
+
+ +Use as seções a seguir para saber mais sobre os comandos do grupo de comandos `tfx run`. + +### create + +Cria uma nova instância de execução para um pipeline no orquestrador. Para o Kubeflow, é usada a versão mais recente do pipeline no cluster. + +Uso: + +
+tfx run create --pipeline_name=<var>pipeline-name</var> [--endpoint=<var>endpoint</var> \
+--engine=<var>engine</var> --iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--pipeline_name=pipeline-name +
+
O nome do pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+ + +
--runtime_parameter=parameter-name=parameter-value +
+
(Opcional.) Define um valor de parâmetro de tempo de execução. Pode ser definido várias vezes para configurar os valores de múltiplas variáveis. Aplicável apenas aos motores `airflow`, `kubeflow` e `vertex`.
+ + +
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + +
--project=GCP-project-id +
+
(Obrigatório para Vertex.) ID do projeto GCP para o pipeline vertex.
+ + +
--region=GCP-region +
+
(Obrigatório para Vertex.) Nome da região GCP, como us-central1. Veja a [documentação da Vertex](https://cloud.google.com/vertex-ai/docs/general/locations) para saber quais são as regiões disponíveis.
+ + + + + +#### Exemplos: + +Kubeflow: + +
+tfx run create --engine=kubeflow --pipeline_name=<var>pipeline-name</var> --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +Local: + +
+tfx run create --engine=local --pipeline_name=<var>pipeline-name</var>
+
+ +Vertex: + +
+tfx run create --engine=vertex --pipeline_name=<var>pipeline-name</var> \
+  --runtime_parameter=<var>var_name</var>=<var>var_value</var> \
+  --project=<var>gcp-project-id</var> --region=<var>gcp-region</var>
+
+ +### terminate + +Interrompe a execução de um determinado pipeline. + +** Observação importante: atualmente suportado apenas no Kubeflow. + +Uso: + +
+tfx run terminate --run_id=<var>run-id</var> [--endpoint=<var>endpoint</var> --engine=<var>engine</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--run_id=run-id +
+
Identificador exclusivo para uma execução de pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx run delete --engine=kubeflow --run_id=<var>run-id</var> --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +### list + +Lista todas as execuções de um pipeline. + +** Observação importante: atualmente não é suportado em motores Local e Apache Beam. + +Uso: + +
+tfx run list --pipeline_name=<var>pipeline-name</var> [--endpoint=<var>endpoint</var> \
+--engine=<var>engine</var> --iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--pipeline_name=pipeline-name +
+
O nome do pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx run list --engine=kubeflow --pipeline_name=<var>pipeline-name</var> --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +### status + +Retorna o status atual de uma execução. + +** Observação importante: atualmente não é suportado em motores Local e Apache Beam. + +Uso: + +
+tfx run status --pipeline_name=<var>pipeline-name</var> --run_id=<var>run-id</var> [--endpoint=<var>endpoint</var> \
+--engine=<var>engine</var> --iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var>]
+
+ +
+
--pipeline_name=pipeline-name +
+
O nome do pipeline.
+
--run_id=run-id +
+
Identificador exclusivo para uma execução de pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx run status --engine=kubeflow --run_id=<var>run-id</var> --pipeline_name=<var>pipeline-name</var> \
+--iap_client_id=<var>iap-client-id</var> --namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +### delete + +Exclui uma execução de um determinado pipeline. + +** Observação importante: atualmente suportado apenas no Kubeflow. + +Uso: + +
+tfx run delete --run_id=<var>run-id</var> [--engine=<var>engine</var> --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>]
+
+ +
+
--run_id=run-id +
+
Identificador exclusivo para uma execução de pipeline.
+
--endpoint=endpoint +
+
+

(Opcional.) Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + +
--engine=engine +
+
+

(Opcional.) O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
--iap_client_id=iap-client-id +
+
(Opcional.) ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
(Opcional.) Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +#### Exemplos: + +Kubeflow: + +
+tfx run delete --engine=kubeflow --run_id=<var>run-id</var> --iap_client_id=<var>iap-client-id</var> \
+--namespace=<var>namespace</var> --endpoint=<var>endpoint</var>
+
+ +## tfx template [Experimental] + +A estrutura dos comandos no grupo de comandos `tfx template` é a seguinte: + +
+tfx template <var>command</var> <var>required-flags</var> [<var>optional-flags</var>]
+
+ +Use as seções a seguir para saber mais sobre os comandos no grupo de comandos `tfx template`. O template é um recurso experimental e está sujeito a alterações a qualquer momento. + +### list + +Veja a lista dos templates de pipeline TFX disponíveis: + +Uso: + +
+tfx template list
+
+ +### copy + +Copia um template para o diretório de destino. + +Uso: + +
+tfx template copy --model=<var>model</var> --pipeline_name=<var>pipeline-name</var> \
+--destination_path=<var>destination-path</var>
+
+ +
+
--model=model +
+
O nome do modelo criado pelo template do pipeline.
+
--pipeline_name=pipeline-name +
+
O nome do pipeline.
+
--destination_path=destination-path +
+
O caminho para onde copiar o template.
+
+ +## Understanding TFX CLI Flags + +### Common flags + +
+
--engine=engine +
+
+

O orquestrador a ser usado para o pipeline. O valor de engine deve corresponder a um dos seguintes valores:

+
    +
  • +kubeflow: define o motor como Kubeflow
  • +
  • +local: define o motor como orquestrador local
  • +
  • +vertex: define o motor como Vertex Pipelines
  • +
  • +airflow: (experimental) define o motor como Apache Airflow
  • +
  • +beam: (experimental) define o motor como Apache Beam
  • +
+

Se o engine não estiver configurado, ele será detectado automaticamente com base no ambiente.

+

** Nota importante: O orquestrador exigido pelo DagRunner no arquivo de configuração do pipeline deve corresponder ao motor selecionado ou detectado automaticamente. A detecção automática do motor é baseada no ambiente do usuário. Se o Apache Airflow e o Kubeflow Pipelines não estiverem instalados, o orquestrador local será usado por padrão.

+
+
+ +
--pipeline_name=pipeline-name +
+
O nome do pipeline.
+ + +
--pipeline_path=pipeline-path +
+
O caminho para o arquivo de configuração do pipeline.
+ + +
--run_id=run-id +
+
Identificador exclusivo para uma execução de pipeline.
+ + + + + +### Kubeflow specific flags + +
+
--endpoint=endpoint +
+
+

Endpoint do serviço da API Kubeflow Pipelines. O endpoint do seu serviço de API do Kubeflow Pipelines é o mesmo que a URL do painel do Kubeflow Pipelines. O valor do seu endpoint deve ser algo como:

+
+
+ +``` +
https://host-name/pipeline
+ +

+ If you do not know the endpoint for your Kubeflow Pipelines cluster, + contact you cluster administrator. +

+ +

+ If the --endpoint is not specified, the in-cluster service + DNS name is used as the default value. This name works only if the + CLI command executes in a pod on the Kubeflow Pipelines cluster, such as a + Kubeflow Jupyter notebooks instance. +

+``` + + + + +
--iap_client_id=iap-client-id +
+
ID do cliente para endpoint protegido por IAP.
+ + +
--namespace=namespace +
+
Namespace Kubernetes para conectar-se à API Kubeflow Pipelines. Se o namespace não for especificado, o valor padrão será kubeflow.
+ + + +## Generated files by TFX CLI + +Quando pipelines são criados e executados, vários arquivos são gerados para gerenciamento do pipeline. + +- ${HOME}/tfx/local, beam, airflow, vertex + - Os metadados do pipeline lidos da configuração são armazenados em `${HOME}/tfx/${ORCHESTRATION_ENGINE}/${PIPELINE_NAME}`. Este local pode ser personalizado definindo uma variável de ambiente como `AIRFLOW_HOME` ou `KUBEFLOW_HOME`. Este comportamento poderá ser alterado em versões futuras. Este diretório é usado para armazenar informações de pipeline, incluindo IDs de pipeline no cluster Kubeflow Pipelines, que são necessários para criar execuções ou atualizar pipelines. + - Antes do TFX 0.25, esses arquivos estavam localizados em `${HOME}/${ORCHESTRATION_ENGINE}`. No TFX 0.25, os arquivos no local antigo serão movidos automaticamente para o novo local para uma migração tranquila. + - A partir do TFX 0.27, o kubeflow não cria esses arquivos de metadados no sistema de arquivos local. No entanto, veja abaixo outros arquivos que o kubeflow cria. +- (somente Kubeflow) Dockerfile e uma imagem de container + - O Kubeflow Pipelines requer dois tipos de entrada para um pipeline. Esses arquivos são gerados pelo TFX no diretório atual. + - Um é uma imagem de container que será usada para executar componentes no pipeline. Esta imagem de container é criada quando um pipeline para Kubeflow Pipelines é criado ou atualizado com o sinalizador `--build-image`. A CLI do TFX gerará `Dockerfile` se não existir e criará e enviará uma imagem de container para o registro especificado em KubeflowDagRunnerConfig. diff --git a/site/pt-br/tfx/guide/container_component.md b/site/pt-br/tfx/guide/container_component.md new file mode 100644 index 0000000000..b8a795b538 --- /dev/null +++ b/site/pt-br/tfx/guide/container_component.md @@ -0,0 +1,74 @@ +# Criando componentes baseados em container + +Os componentes baseados em container fornecem flexibilidade para integrar código escrito em qualquer linguagem em seu pipeline, desde que você possa executar esse código num container do Docker. + +Se você é novato em pipelines TFX, [aprenda mais sobre os principais conceitos dos pipelines TFX](understanding_tfx_pipelines) antes de continuar. + +## Criando um componente baseado em container + +Os componentes baseados em container são apoiados por programas de linha de comando em containers. Se você já possui uma imagem de container, pode usar o TFX para criar um componente a partir dela usando a [função `create_container_component`](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/component/experimental/container_component.py){: .external } para declarar entradas e saídas. Parâmetros da função: + +- **name:** o nome do componente. +- **inputs:** um dicionário que mapeia nomes de entrada para tipos. outputs: um dicionário que mapeia nomes de saída para tipos. parameters: um dicionário que mapeia nomes de parâmetros para tipos. +- **image:** nome da imagem do container e, opcionalmente, tag da imagem. +- **command:** linha de comando do ponto de entrada do container. Não executável dentro de um shell. A linha de comando pode usar placeholders que são substituídos no momento da compilação pelo input, output ou parameter. Os placeholders podem ser importados de [`tfx.dsl.component.experimental.placeholders`](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/component/experimental/placeholders.py) {: .external }. Observe que os modelos Jinja não são suportados. + +**Valor de retorno:** uma classe Component herdada de base_component.BaseComponent que pode ser instanciada e usada dentro do pipeline. + +### Placeholders + +Para um componente que possui entradas ou saídas, o `command` geralmente precisa ter placeholders que sejam substituídos por dados reais em tempo de execução. Vários placeholders são fornecidos para essa finalidade: + +- `InputValuePlaceholder`: um placeholder para o valor do artefato de entrada. Em tempo de execução, este placeholder é substituído pela representação em string do valor do artefato. + +- `InputUriPlaceholder`: um placeholder para o URI do argumento do artefato de entrada. Em tempo de execução, este placeholder é substituído pela URI dos dados do artefato de entrada. + +- `OutputUriPlaceholder`: um placeholder para o URI do argumento do artefato de saída. Em tempo de execução, este placeholder é substituído pela URI onde o componente deve armazenar os dados do artefato de saída. + +Saiba mais sobre [Placeholders de linha de comando do componente TFX](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/component/experimental/placeholders.py){: .external }. + +### Exemplo de componente baseado em container + +O código a seguir é um exemplo de um componente não python que baixa, transforma e carrega os dados: + +```python +import tfx.v1 as tfx + +grep_component = tfx.dsl.components.create_container_component( + name='FilterWithGrep', + inputs={ + 'text': tfx.standard_artifacts.ExternalArtifact, + }, + outputs={ + 'filtered_text': tfx.standard_artifacts.ExternalArtifact, + }, + parameters={ + 'pattern': str, + }, + # The component code uses gsutil to upload the data to Google Cloud Storage, so the + # container image needs to have gsutil installed and configured. + image='google/cloud-sdk:278.0.0', + command=[ + 'sh', '-exc', + ''' + pattern="$1" + text_uri="$3"/data # Adding suffix, because currently the URI are "directories". This will be fixed soon. + text_path=$(mktemp) + filtered_text_uri="$5"/data # Adding suffix, because currently the URI are "directories". This will be fixed soon. + filtered_text_path=$(mktemp) + + # Getting data into the container + gsutil cp "$text_uri" "$text_path" + + # Running the main code + grep "$pattern" "$text_path" >"$filtered_text_path" + + # Getting data out of the container + gsutil cp "$filtered_text_path" "$filtered_text_uri" + ''', + '--pattern', tfx.dsl.placeholders.InputValuePlaceholder('pattern'), + '--text', tfx.dsl.placeholders.InputUriPlaceholder('text'), + '--filtered-text', tfx.dsl.placeholders.OutputUriPlaceholder('filtered_text'), + ], +) +``` diff --git a/site/pt-br/tfx/guide/custom_component.md b/site/pt-br/tfx/guide/custom_component.md new file mode 100644 index 0000000000..d9cab775d3 --- /dev/null +++ b/site/pt-br/tfx/guide/custom_component.md @@ -0,0 +1,141 @@ +# Construindo componentes totalmente personalizados + +Este guia descreve como usar a API TFX para criar um componente totalmente personalizado. Componentes totalmente personalizados permitem construir componentes definindo a especificação do componente, o executor e as classes de interface do componente. Essa abordagem permite reutilizar e estender um componente padrão para atender às suas necessidades. + +Se você é novato em pipelines TFX, [aprenda mais sobre os principais conceitos dos pipelines TFX](understanding_tfx_pipelines) antes de continuar. + +## Executor personalizado ou componente personalizado + +Se apenas a lógica de processamento customizada for necessária enquanto as entradas, saídas e propriedades de execução do componente forem as mesmas de um componente existente, um executor customizado será suficiente. Um componente totalmente personalizado é necessário quando qualquer uma das entradas, saídas ou propriedades de execução é diferente de qualquer componente TFX existente. + +## Como criar um componente personalizado? + +O desenvolvimento de um componente totalmente personalizado requer: + +- Um conjunto definido de especificações de artefatos de entrada e saída para o novo componente. Mais importante é que os tipos dos artefatos de entrada sejam consistentes com os tipos de artefatos de saída dos componentes que produzem os artefatos (componentes upstream), e que os tipos dos artefatos de saída sejam consistentes com os tipos de artefatos de entrada dos componentes que consomem os artefatos (componentes downstream), se houver. +- Os parâmetros de execução que não são artefatos e que são necessários para o novo componente. + +### ComponentSpec + +A classe `ComponentSpec` define o contrato do componente definindo os artefatos de entrada e saída para um componente, bem como os parâmetros que são usados ​​para a execução do componente. Tem três partes: + +- *INPUTS*: Um dicionário de parâmetros digitados para os artefatos de entrada que são passados ​​para o executor do componente. Normalmente, os artefatos de entrada são as saídas dos componentes upstream e, portanto, compartilham o mesmo tipo. +- *OUTPUTS*: Um dicionário de parâmetros digitados para os artefatos de saída que o componente produz. +- *PARAMETERS*: Um dicionário de itens [ExecutionParameter](https://github.com/tensorflow/tfx/blob/54aa6fbec6bffafa8352fe51b11251b1e44a2bf1/tfx/types/component_spec.py#L274) adicionais que serão passados ​​para o executor do componente. Esses são parâmetros que não são artefatos e que queremos definir de forma flexível no pipeline DSL e passar para execução. + +Aqui está um exemplo do ComponentSpec: + +```python +class HelloComponentSpec(types.ComponentSpec): + """ComponentSpec for Custom TFX Hello World Component.""" + + PARAMETERS = { + # These are parameters that will be passed in the call to + # create an instance of this component. + 'name': ExecutionParameter(type=Text), + } + INPUTS = { + # This will be a dictionary with input artifacts, including URIs + 'input_data': ChannelParameter(type=standard_artifacts.Examples), + } + OUTPUTS = { + # This will be a dictionary which this component will populate + 'output_data': ChannelParameter(type=standard_artifacts.Examples), + } +``` + +### Executor + +Em seguida, escreva o código executor do novo componente. Basicamente, uma nova subclasse de `base_executor.BaseExecutor` precisa ser criada com sua função `Do` sobreposta. Na função `Do`, os argumentos `input_dict`, `output_dict` e `exec_properties` que são passados ​​​​no mapa para `INPUTS`, `OUTPUTS` e `PARAMETERS` que são definidos em ComponentSpec respectivamente. Para `exec_properties`, o valor pode ser obtido diretamente através de uma pesquisa no dicionário. Para artefatos em `input_dict` e `output_dict`, existem funções convenientes disponíveis na classe [artefato_utils](https://github.com/tensorflow/tfx/blob/41823f91dbdcb93195225a538968a80ba4bb1f55/tfx/types/artifact_utils.py) que podem ser usadas para buscar a instância ou URI do artefato. + +```python +class Executor(base_executor.BaseExecutor): + """Executor for HelloComponent.""" + + def Do(self, input_dict: Dict[Text, List[types.Artifact]], + output_dict: Dict[Text, List[types.Artifact]], + exec_properties: Dict[Text, Any]) -> None: + ... + + split_to_instance = {} + for artifact in input_dict['input_data']: + for split in json.loads(artifact.split_names): + uri = artifact_utils.get_split_uri([artifact], split) + split_to_instance[split] = uri + + for split, instance in split_to_instance.items(): + input_dir = instance + output_dir = artifact_utils.get_split_uri( + output_dict['output_data'], split) + for filename in tf.io.gfile.listdir(input_dir): + input_uri = os.path.join(input_dir, filename) + output_uri = os.path.join(output_dir, filename) + io_utils.copy_file(src=input_uri, dst=output_uri, overwrite=True) +``` + +#### Teste de unidade de um executor personalizado + +Testes de unidade para o executor personalizado podem ser criados de forma semelhante a [este](https://github.com/tensorflow/tfx/blob/r0.15/tfx/components/transform/executor_test.py). + +### Interface do componente + +Agora que a parte mais complexa está concluída, o próximo passo é montar essas peças numa interface de componente, para permitir que o componente seja usado em um pipeline. São vários passos: + +- Torne a interface do componente uma subclasse de `base_component.BaseComponent` +- Atribua uma variável de classe `SPEC_CLASS` com a classe `ComponentSpec` que foi definida anteriormente +- Atribua uma variável de classe `EXECUTOR_SPEC` com a classe Executor que foi definida anteriormente +- Defina a função construtora `__init__()` usando os argumentos da função para construir uma instância da classe ComponentSpec e invocar a superfunção com esse valor, junto com um nome opcional + +Quando uma instância do componente é criada, a lógica de verificação de tipo na classe `base_component.BaseComponent` será invocada para garantir que os argumentos que foram passados ​​sejam compatíveis com as informações de tipo definidas na classe `ComponentSpec`. + +```python +from tfx.types import standard_artifacts +from hello_component import executor + +class HelloComponent(base_component.BaseComponent): + """Custom TFX Hello World Component.""" + + SPEC_CLASS = HelloComponentSpec + EXECUTOR_SPEC = executor_spec.ExecutorClassSpec(executor.Executor) + + def __init__(self, + input_data: types.Channel = None, + output_data: types.Channel = None, + name: Optional[Text] = None): + if not output_data: + examples_artifact = standard_artifacts.Examples() + examples_artifact.split_names = input_data.get()[0].split_names + output_data = channel_utils.as_channel([examples_artifact]) + + spec = HelloComponentSpec(input_data=input_data, + output_data=output_data, name=name) + super(HelloComponent, self).__init__(spec=spec) +``` + +### Instalação do componente num pipeline TFX + +A última etapa é conectar o novo componente personalizado a um pipeline do TFX. Além de adicionar uma instância do novo componente, também são necessários os seguintes itens: + +- Conecte corretamente os componentes upstream e downstream do novo componente. Isto é feito referenciando as saídas do componente upstream no novo componente e referenciando as saídas do novo componente nos componentes downstream. +- Adicione a nova instância do componente à lista de componentes ao construir o pipeline. + +O exemplo abaixo destaca as alterações mencionadas. Um exemplo completo pode ser encontrado no [repositório TFX GitHub](https://github.com/tensorflow/tfx/tree/master/tfx/examples/custom_components/hello_world). + +```python +def _create_pipeline(): + ... + example_gen = CsvExampleGen(input_base=examples) + hello = component.HelloComponent( + input_data=example_gen.outputs['examples'], name='HelloWorld') + statistics_gen = StatisticsGen(examples=hello.outputs['output_data']) + ... + return pipeline.Pipeline( + ... + components=[example_gen, hello, statistics_gen, ...], + ... + ) +``` + +## Implantação de um componente totalmente personalizado + +Além das alterações de código, todas as partes recém-adicionadas (`ComponentSpec` , `Executor`, interface do componente) precisam estar acessíveis no ambiente de execução do pipeline para executar o pipeline corretamente. diff --git a/site/pt-br/tfx/guide/custom_function_component.md b/site/pt-br/tfx/guide/custom_function_component.md new file mode 100644 index 0000000000..546589d6ba --- /dev/null +++ b/site/pt-br/tfx/guide/custom_function_component.md @@ -0,0 +1,114 @@ +# Componentes de função Python personalizados + +A definição de componentes baseados em funções Python facilita a criação de componentes personalizados do TFX, economizando o esforço de definir uma classe de especificação do componente, uma classe de executor e uma classe de interface do componente. Neste estilo de definição de componentes, você escreve uma função anotada com dicas de tipo. As dicas de tipo descrevem os artefatos de entrada, os artefatos de saída e os parâmetros do seu componente. + +Escrever seu componente personalizado neste estilo é muito simples, como no exemplo a seguir. + +```python +class MyOutput(TypedDict): + accuracy: float + +@component +def MyValidationComponent( + model: InputArtifact[Model], + blessing: OutputArtifact[Model], + accuracy_threshold: Parameter[int] = 10, +) -> MyOutput: + '''My simple custom model validation component.''' + + accuracy = evaluate_model(model) + if accuracy >= accuracy_threshold: + write_output_blessing(blessing) + + return { + 'accuracy': accuracy + } +``` + +Nos bastidores, isto define um componente personalizado que é uma subclasse de [`BaseComponent`](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/components/base/base_component.py){: .external } e suas classes Spec e Executor. + +Observação: o recurso (componente baseado em BaseBeamComponent anotando uma função com `@component(use_beam=True)`) descrito abaixo é experimental e não há garantias públicas de compatibilidade com versões anteriores. + +Se você quer definir uma subclasse de [`BaseBeamComponent`](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/components/base/base_beam_component.py){: .external } de modo que possa usar um pipeline Beam com configuração compartilhada do pipeline TFX, ou seja, `beam_pipeline_args` ao compilar o pipeline ([Chicago Taxi Pipeline Exemplo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/chicago_taxi_pipeline/taxi_pipeline_simple.py#L192){: .external }), você poderia definir `use_beam=True` no decorador e adicionar outro `BeamComponentParameter` com valor padrão `None` em sua função como no exemplo a seguir: + +```python +@component(use_beam=True) +def MyDataProcessor( + examples: InputArtifact[Example], + processed_examples: OutputArtifact[Example], + beam_pipeline: BeamComponentParameter[beam.Pipeline] = None, + ) -> None: + '''My simple custom model validation component.''' + + with beam_pipeline as p: + # data pipeline definition with beam_pipeline begins + ... + # data pipeline definition with beam_pipeline ends +``` + +Se você é novato em pipelines TFX, [aprenda mais sobre os principais conceitos dos pipelines TFX](understanding_tfx_pipelines) antes de continuar. + +## Entradas, saídas e parâmetros + +No TFX, as entradas e saídas são rastreadas como objetos de artefato que descrevem a localização e as propriedades de metadados associadas aos dados subjacentes; essas informações são armazenadas em metadados de aprendizado de máquina (ML Metadata). Os artefatos podem descrever tipos de dados complexos ou tipos de dados simples, como: int, float, bytes ou strings unicode. + +Um parâmetro é um argumento (int, float, bytes ou string unicode) para um componente conhecido no momento da construção do pipeline. Os parâmetros são úteis para especificar argumentos e hiperparâmetros, como contagem de iterações de treinamento, taxa de dropout e outras configurações para seu componente. Os parâmetros são armazenados como propriedades de execuções de componentes quando rastreados no ML Metadata. + +Observação: Atualmente, os valores de tipo de dados simples de saída não podem ser usados ​​como parâmetros, pois não são conhecidos em tempo de execução. Da mesma forma, os valores de tipo de dados simples de entrada atualmente não podem assumir valores concretos conhecidos no momento da construção do pipeline. Poderemos remover esta restrição numa versão futura do TFX. + +## Definição + +Para criar um componente personalizado, escreva uma função que implemente sua lógica personalizada e decore-a com o [`@component` decorator](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/component/experimental/decorators.py) {: .external } do módulo `tfx.dsl.component.experimental.decorators`. Para definir o esquema de entrada e saída do seu componente, anote os argumentos da sua função e o valor de retorno usando anotações do módulo `tfx.dsl.component.experimental.annotations`: + +- Para cada **entrada de artefato**, aplique a anotação de dica de tipo `InputArtifact[ArtifactType]`. Substitua `ArtifactType` pelo tipo do artefato, que é uma subclasse de `tfx.types.Artifact`. Essas entradas podem ser argumentos opcionais. + +- Para cada **artefato de saída**, aplique a anotação de dica de tipo `OutputArtifact[ArtifactType]`. Substitua `ArtifactType` pelo tipo do artefato, que é uma subclasse de `tfx.types.Artifact`. Os artefatos de saída do componente devem ser passados ​​como argumentos de entrada da função, para que seu componente possa gravar saídas em um local gerenciado pelo sistema e configurar propriedades apropriadas de metadados do artefato. Este argumento pode ser opcional ou pode ser definido com um valor padrão. + +- Para cada **parâmetro**, use a anotação de dica de tipo `Parameter[T]`. Substitua `T` pelo tipo do parâmetro. Atualmente, oferecemos suporte apenas a tipos python primitivos: `bool`, `int`, `float`, `str` ou `bytes`. + +- Para o **beam pipeline**, use a anotação de dica de tipo `BeamComponentParameter[beam.Pipeline]`. Defina o valor padrão como `None`. O valor `None` será substituído por um pipeline beam instanciado criado por `_make_beam_pipeline()` de [`BaseBeamExecutor`](https://github.com/tensorflow/tfx/blob/master/tfx/dsl/components/base/base_beam_executor.py){: .external } + +- Para cada **entrada de tipo de dados simples** (`int`, `float`, `str` ou `bytes`) não conhecida no momento da construção do pipeline, use a dica de tipo `T`. Observe que na versão 0.22 do TFX, valores concretos não podem ser passados no momento da construção do pipeline para esse tipo de entrada (em vez disso, use a anotação `Parameter`, conforme descrito na seção anterior). Este argumento pode ser opcional ou pode ser definido com um valor padrão. Se o seu componente tiver saídas de tipo de dados simples (`int`, `float`, `str` ou `bytes`), você poderá retornar essas saídas usando um `TypedDict` como uma anotação de tipo de retorno e retornando um objeto dict apropriado. + +No corpo da sua função, os artefatos de entrada e saída são passados ​​como objetos `tfx.types.Artifact`; você pode inspecionar sua `.uri` para obter sua localização gerenciada pelo sistema e ler/definir quaisquer propriedades. Parâmetros de entrada e entradas de tipo de dados simples são passados ​​como objetos do tipo especificado. As saídas de tipo de dados simples devem ser retornadas como um dicionário, onde as chaves são os nomes de saída apropriados e os valores são os valores de retorno desejados. + +O componente de função concluído pode ser similar ao código a seguir: + +```python +from typing import TypedDict +import tfx.v1 as tfx +from tfx.dsl.component.experimental.decorators import component + +class MyOutput(TypedDict): + loss: float + accuracy: float + +@component +def MyTrainerComponent( + training_data: tfx.dsl.components.InputArtifact[tfx.types.standard_artifacts.Examples], + model: tfx.dsl.components.OutputArtifact[tfx.types.standard_artifacts.Model], + dropout_hyperparameter: float, + num_iterations: tfx.dsl.components.Parameter[int] = 10 +) -> MyOutput: + '''My simple trainer component.''' + + records = read_examples(training_data.uri) + model_obj = train_model(records, num_iterations, dropout_hyperparameter) + model_obj.write_to(model.uri) + + return { + 'loss': model_obj.loss, + 'accuracy': model_obj.accuracy + } + +# Example usage in a pipeline graph definition: +# ... +trainer = MyTrainerComponent( + examples=example_gen.outputs['examples'], + dropout_hyperparameter=other_component.outputs['dropout'], + num_iterations=1000) +pusher = Pusher(model=trainer.outputs['model']) +# ... +``` + +O exemplo anterior define `MyTrainerComponent` como um componente personalizado baseado em função Python. Este componente consome um artefato de `examples` como entrada e produz um artefato `model` como saída. O componente usa o `artifact_instance.uri` para ler ou gravar o artefato em seu local gerenciado pelo sistema. O componente usa um parâmetro de entrada `num_iterations` e um valor de tipo de dados simples `dropout_hyperparameter`, e o componente gera métricas `loss` e `accuracy` como valores de saída de tipo de dados simples. O artefato `model` de saída é então usado pelo componente `Pusher`. diff --git a/site/pt-br/tfx/guide/custom_orchestrator.md b/site/pt-br/tfx/guide/custom_orchestrator.md new file mode 100644 index 0000000000..736f4969c4 --- /dev/null +++ b/site/pt-br/tfx/guide/custom_orchestrator.md @@ -0,0 +1,34 @@ +# Orquestração de pipelines TFX + +## Orquestrador personalizado + +O TFX foi projetado para ser portável para múltiplos ambientes e frameworks de orquestração. Os desenvolvedores podem criar orquestradores personalizados ou incluir orquestradores adicionais além dos orquestradores padrão que já são suportados pelo TFX, que são [Local](local_orchestrator.md), [Vertex AI](vertex.md), [Airflow](airflow.md) e [Kubeflow](kubeflow.md). + +Todos os orquestradores precisam herdar de [TfxRunner](https://github.com/tensorflow/tfx/blob/master/tfx/orchestration/tfx_runner.py). Os orquestradores TFX recebem o objeto lógico do pipeline, que contém argumentos do pipeline, componentes e DAG, e são responsáveis ​​por agendar componentes do pipeline TFX com base nas dependências definidas pelo DAG. + +Por exemplo, vejamos como criar um orquestrador personalizado com [BaseComponentLauncher](https://github.com/tensorflow/tfx/blob/master/tfx/orchestration/launcher/base_component_launcher.py). O BaseComponentLauncher já cuida do driver, da execução e publicação de um único componente. O novo orquestrador só precisa agendar ComponentLaunchers com base no DAG. Um orquestrador simples é fornecido como [LocalDagRunner](https://github.com/tensorflow/tfx/blob/master/tfx/orchestration/local/local_dag_runner.py), que executa os componentes um por um na ordem topológica do DAG. + +Este orquestrador pode ser usado na DSL Python: + +```python +def _create_pipeline(...) -> dsl.Pipeline: + ... + return dsl.Pipeline(...) + +if __name__ == '__main__': + orchestration.LocalDagRunner().run(_create_pipeline(...)) +``` + +Para executar o arquivo Python DSL acima (assumindo que seu nome seja dsl.py), basta fazer o seguinte: + +```bash +import direct_runner +from tfx.orchestration import pipeline + +def _create_pipeline(...) -> pipeline.Pipeline: + ... + return pipeline.Pipeline(...) + +if __name__ == '__main__': + direct_runner.DirectDagRunner().run(_create_pipeline(...)) +``` diff --git a/site/pt-br/tfx/guide/evaluator.md b/site/pt-br/tfx/guide/evaluator.md new file mode 100644 index 0000000000..bc2f8274c9 --- /dev/null +++ b/site/pt-br/tfx/guide/evaluator.md @@ -0,0 +1,116 @@ +# O componente de pipeline Evaluator TFX + +O componente de pipeline Evaluator TFX realiza análises profundas nos resultados de treinamento dos seus modelos, para ajudar você a entender o desempenho do seu modelo em subconjuntos de seus dados. O Evaluator também ajuda a validar seus modelos exportados, garantindo que eles sejam “bons o suficiente” para serem enviados para produção. + +Quando a validação está habilitada, o Evaluator compara novos modelos com uma referência (como, por exemplo, o modelo atualmente em serviço) para determinar se eles são "bons o suficiente" em relação à referência. Isto é feito avaliando ambos os modelos em um dataset de avaliação e computando seu desempenho em métricas (por exemplo, AUC, perda). Se as métricas do novo modelo atenderem aos critérios especificados pelo desenvolvedor em relação ao modelo de referência (por exemplo, AUC não for inferior), o modelo será autorizado, ou "abençoado" (marcado como bom), indicando ao [Pusher](pusher.md) que não há problema em enviar o modelo para produção. + +- Consome: + - Uma divisão de avaliação de [ExampleGen](https://www.tensorflow.org/tfx/guide/examplegen) + - Um modelo treinado do [Trainer](trainer.md) + - Um modelo previamente abençoado (se a validação for realizada) +- Produz: + - Resultados da análise para [ML Metadata](mlmd.md) + - Resultados de validação para [ML Metadata](mlmd.md) (se a validação for realizada) + +## Evaluator e o TensorFlow Model Analysis + +O Evaluator aproveita a biblioteca [TensorFlow Model Analysis](tfma.md) para realizar a análise, que por sua vez usa o [Apache Beam](beam.md) para processamento escalonável. + +## Usando o componente Evaluator + +Um componente de pipeline Evaluator normalmente é muito fácil de implantar e requer pouca personalização, já que a maior parte do trabalho é feita pelo próprio componente Evaluator TFX. + +Para configurar o evaluator são necessárias as seguintes informações: + +- Métricas a serem configuradas (necessárias apenas se métricas adicionais estiverem sendo adicionadas fora daquelas salvas com o modelo). Consulte [Métricas do Tensorflow Model Analysis](https://github.com/tensorflow/model-analysis/blob/master/g3doc/metrics.md) para mais informações. +- Fatias a serem configuradas (se nenhuma fatia for fornecida, uma fatia "geral" será adicionada por padrão). Consulte [Configuração do Tensorflow Model Analysis](https://github.com/tensorflow/model-analysis/blob/master/g3doc/setup.md) para mais informações. + +Se a validação for incluída, as seguintes informações adicionais serão necessárias: + +- Qual modelo comparar (último abençoado, etc.). +- Validações de modelo (limites) a serem verificadas. Consulte [Validações de modelo do Tensorflow Model Analysis](https://github.com/tensorflow/model-analysis/blob/master/g3doc/model_validations.md) para mais informações. + +Quando ativada, a validação será realizada em todas as métricas e fatias que foram definidas. + +Este é um exemplo de código típico: + +```python +import tensorflow_model_analysis as tfma +... + +# For TFMA evaluation + +eval_config = tfma.EvalConfig( + model_specs=[ + # This assumes a serving model with signature 'serving_default'. If + # using estimator based EvalSavedModel, add signature_name='eval' and + # remove the label_key. Note, if using a TFLite model, then you must set + # model_type='tf_lite'. + tfma.ModelSpec(label_key='') + ], + metrics_specs=[ + tfma.MetricsSpec( + # The metrics added here are in addition to those saved with the + # model (assuming either a keras model or EvalSavedModel is used). + # Any metrics added into the saved model (for example using + # model.compile(..., metrics=[...]), etc) will be computed + # automatically. + metrics=[ + tfma.MetricConfig(class_name='ExampleCount'), + tfma.MetricConfig( + class_name='BinaryAccuracy', + threshold=tfma.MetricThreshold( + value_threshold=tfma.GenericValueThreshold( + lower_bound={'value': 0.5}), + change_threshold=tfma.GenericChangeThreshold( + direction=tfma.MetricDirection.HIGHER_IS_BETTER, + absolute={'value': -1e-10}))) + ] + ) + ], + slicing_specs=[ + # An empty slice spec means the overall slice, i.e. the whole dataset. + tfma.SlicingSpec(), + # Data can be sliced along a feature column. In this case, data is + # sliced along feature column trip_start_hour. + tfma.SlicingSpec(feature_keys=['trip_start_hour']) + ]) + +# The following component is experimental and may change in the future. This is +# required to specify the latest blessed model will be used as the baseline. +model_resolver = Resolver( + strategy_class=dsl.experimental.LatestBlessedModelStrategy, + model=Channel(type=Model), + model_blessing=Channel(type=ModelBlessing) +).with_id('latest_blessed_model_resolver') + +model_analyzer = Evaluator( + examples=examples_gen.outputs['examples'], + model=trainer.outputs['model'], + baseline_model=model_resolver.outputs['model'], + # Change threshold will be ignored if there is no baseline (first run). + eval_config=eval_config) +``` + +O evaluator produz um [EvalResult](https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/EvalResult) (e opcionalmente um [ValidationResult](https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/ValidationResult) se a validação tiver sido usada) que pode ser carregado usando o [TFMA](tfma.md). A seguir está um exemplo de como carregar os resultados em um notebook Jupyter: + +``` +import tensorflow_model_analysis as tfma + +output_path = evaluator.outputs['evaluation'].get()[0].uri + +# Load the evaluation results. +eval_result = tfma.load_eval_result(output_path) + +# Visualize the metrics and plots using tfma.view.render_slicing_metrics, +# tfma.view.render_plot, etc. +tfma.view.render_slicing_metrics(tfma_result) +... + +# Load the validation results +validation_result = tfma.load_validation_result(output_path) +if not validation_result.validation_ok: + ... +``` + +Mais detalhes estão disponíveis na [Referência da API do Evaluator](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/Evaluator). diff --git a/site/pt-br/tfx/guide/examplegen.md b/site/pt-br/tfx/guide/examplegen.md new file mode 100644 index 0000000000..94157c153b --- /dev/null +++ b/site/pt-br/tfx/guide/examplegen.md @@ -0,0 +1,504 @@ +# O componente de pipeline ExampleGen TFX + +O componente de pipeline ExampleGen TFX consome dados em pipelines do TFX. Ele consome arquivos/serviços externos para gerar exemplos que serão lidos por outros componentes do TFX. Ele também fornece uma partição consistente e configurável e embaralha o dataset de acordo com as práticas recomendadas de ML. + +- Consome: Dados de fontes de dados externas como CSV, `TFRecord`, Avro, Parquet e BigQuery. +- Produz: registros `tf.Example`, registros `tf.SequenceExample` ou formato proto, dependendo do formato da payload. + +## ExampleGen e outros componentes + +O ExampleGen fornece dados para componentes que fazem uso da biblioteca [TensorFlow Data Validation](tfdv.md), como [SchemaGen](schemagen.md), [StatisticsGen](statsgen.md) e [Example Validator](exampleval.md). Ele também fornece dados para [Transform](transform.md), que faz uso da biblioteca [TensorFlow Transform](tft.md) e, em última análise, para alvos de implantação durante a inferência. + +## Fontes e formatos de dados + +Atualmente, uma instalação padrão do TFX inclui componentes completos do ExampleGen para estas fontes e formatos de dados: + +- [CSV](https://github.com/tensorflow/tfx/tree/master/tfx/components/example_gen/csv_example_gen) +- [tf.Record](https://github.com/tensorflow/tfx/tree/master/tfx/components/example_gen/import_example_gen) +- [BigQuery](https://github.com/tensorflow/tfx/tree/master/tfx/extensions/google_cloud_big_query/example_gen) + +Também estão disponíveis executores personalizados que permitem o desenvolvimento de componentes ExampleGen para estas fontes e formatos de dados: + +- [Avro](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/custom_executors/avro_executor.py) +- [Parquet](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/custom_executors/parquet_executor.py) + +Consulte os exemplos de uso no código-fonte e [esta discussão](/tfx/guide/examplegen#custom_examplegen) para mais informações sobre como usar e desenvolver executores personalizados. + +Observação: Na maioria dos casos, é melhor herdar de `base_example_gen_executor` em vez de `base_executor`. Portanto, pode ser aconselhável seguir o exemplo Avro ou Parquet no código-fonte do Executor. + +Além disso, estas fontes e formatos de dados estão disponíveis como exemplos de [componentes personalizados](/tfx/guide/understanding_custom_components): + +- [Presto](https://github.com/tensorflow/tfx/tree/master/tfx/examples/custom_components/presto_example_gen) + +### Consumindo formatos de dados suportados pelo Apache Beam + +O Apache Beam oferece suporte ao consumo de dados de uma [ampla variedade de fontes e formatos de dados](https://beam.apache.org/documentation/io/built-in/) ([veja abaixo](#additional_data_formats)). Esses recursos podem ser usados ​​para criar componentes Example Gen personalizados para o TFX, o que é demonstrado por alguns componentes ExampleGen existentes ([veja abaixo](#additional_data_formats)). + +## Como usar um componente ExampleGen + +Para fontes de dados suportadas (atualmente, arquivos CSV, arquivos TFRecord com `tf.Example`, `tf.SequenceExample` e formato proto e resultados de consultas do BigQuery), o componente de pipeline ExampleGen pode ser usado diretamente na implantação e requer pouca personalização. Por exemplo: + +```python +example_gen = CsvExampleGen(input_base='data_root') +``` + +ou como abaixo para importar um TFRecord externo diretamente com `tf.Example`: + +```python +example_gen = ImportExampleGen(input_base=path_to_tfrecord_dir) +``` + +## Span, Version e Split + +Um Span é um agrupamento de exemplos de treinamento. Se seus dados são armazenados num sistema de arquivos, cada Span poderá ser armazenado num diretório separado. A semântica de um Span não é codificada no TFX; um Span pode corresponder a um dia de dados, uma hora de dados ou qualquer outro agrupamento que seja significativo para sua tarefa. + +Cada Span pode conter múltiplas versões (Version) de dados. Para dar um exemplo, se você remover alguns exemplos de um Span para limpar dados de baixa qualidade, isso poderá resultar numa nova Version desse Span. Por padrão, os componentes do TFX operam na Version mais recente dentro de um Span. + +Cada Version dentro de um Span pode ainda ser subdividida em múltiplas Splits (divisões). O caso de uso mais comum para dividir um Span é dividi-lo em dados de treinamento (train) e avaliação (eval). + +![Spans e Splits](images/spans_splits.png) + +### Divisão (split) personalizada de entrada/saída + +Observação: este recurso só está disponível para versões posteriores ao TFX 0.14. + +Para personalizar a proporção da divisão de treinamento/avaliação que o ExampleGen produzirá, defina o `output_config` para o componente ExampleGen. Por exemplo: + +```python +# Input has a single split 'input_dir/*'. +# Output 2 splits: train:eval=3:1. +output = proto.Output( + split_config=example_gen_pb2.SplitConfig(splits=[ + proto.SplitConfig.Split(name='train', hash_buckets=3), + proto.SplitConfig.Split(name='eval', hash_buckets=1) + ])) +example_gen = CsvExampleGen(input_base=input_dir, output_config=output) +``` + +Observe como os `hash_buckets` foram definidos neste exemplo. + +Para uma fonte de entrada que já foi dividida, defina `input_config` para o componente ExampleGen: + +```python + +# Input train split is 'input_dir/train/*', eval split is 'input_dir/eval/*'. +# Output splits are generated one-to-one mapping from input splits. +input = proto.Input(splits=[ + example_gen_pb2.Input.Split(name='train', pattern='train/*'), + example_gen_pb2.Input.Split(name='eval', pattern='eval/*') + ]) +example_gen = CsvExampleGen(input_base=input_dir, input_config=input) +``` + +Para geração de exemplo baseada em arquivo (por exemplo, CsvExampleGen e ImportExampleGen), `pattern` é um padrão de arquivo glob relativo que mapeia para arquivos de entrada com diretório raiz fornecido pelo caminho base de entrada. Para geração de exemplos com base em consultas (por exemplo, BigQueryExampleGen, PrestoExampleGen), o `pattern` é uma consulta SQL. + +Por padrão, todo o diretório base de entrada é tratado como uma única divisão de entrada, e a divisão de saída treinamento/avaliação é gerada com uma proporção de 2:1. + +Consulte [proto/example_gen.proto](https://github.com/tensorflow/tfx/blob/master/tfx/proto/example_gen.proto) para obter a configuração de divisão de entrada e saída do ExampleGen. E consulte o [guia de componentes downstream](#examplegen_downstream_components) para utilizar as divisões personalizadas downstream. + +#### Método de divisão + +Ao usar o método de divisão `hash_buckets`, em vez do registro inteiro, pode-se usar uma característica para particionar os exemplos. Se uma característica estiver presente, o ExampleGen usará uma impressão digital dessa característica como chave de partição. + +Este característica pode ser usada para manter uma divisão estável com certas propriedades de exemplos: por exemplo, um usuário sempre será colocado na mesma divisão se "user_id" for selecionado como o nome da característica de partição. + +A interpretação do que significa uma "característica" e como corresponder uma "característica" ao nome especificado depende da implementação do ExampleGen e do tipo dos exemplos. + +Para implementações de ExampleGen prontas: + +- Se gerar tf.Example, então uma "característica" significa uma entrada em tf.Example.features.feature. +- Se gerar tf.SequenceExample, então uma "característica" significa uma entrada em tf.SequenceExample.context.feature. +- Somente característica int64 e bytes são suportadas. + +Nos seguintes casos, o ExampleGen gera erros de tempo de execução: + +- O nome da característica especificada não existe no exemplo. +- Característica vazia: `tf.train.Feature()`. +- Tipos de característica não suportados, por exemplo, característica do tipo float. + +Para gerar a divisão train/eval com base em uma característica nos exemplos, defina o `output_config` para o componente ExampleGen. Por exemplo: + +```python +# Input has a single split 'input_dir/*'. +# Output 2 splits based on 'user_id' features: train:eval=3:1. +output = proto.Output( + split_config=proto.SplitConfig(splits=[ + proto.SplitConfig.Split(name='train', hash_buckets=3), + proto.SplitConfig.Split(name='eval', hash_buckets=1) + ], + partition_feature_name='user_id')) +example_gen = CsvExampleGen(input_base=input_dir, output_config=output) +``` + +Observe como o `partition_feature_name` foi definido neste exemplo. + +### Span + +Observação: este recurso só está disponível para versões posteriores ao TFX 0.15. + +O span pode ser recuperado usando a especificação '{SPAN}' no [padrão de entrada glob](https://github.com/tensorflow/tfx/blob/master/tfx/proto/example_gen.proto) : + +- Esta especificação combina dígitos e mapeia os dados nos números SPAN relevantes. Por exemplo, 'data_{SPAN}-*.tfrecord' coletará arquivos como 'data_12-a.tfrecord', 'date_12-b.tfrecord'. +- Opcionalmente, esta especificação pode ser especificada com a largura dos inteiros quando mapeada. Por exemplo, 'data_{SPAN:2}.file' mapeia para arquivos como 'data_02.file' e 'data_27.file' (como entradas para Span-2 e Span-27 respectivamente), mas não mapeia para 'data_1. arquivo' nem 'data_123.file'. +- Quando a especificação SPAN está faltando, presume-se que seja sempre Span '0'. +- Se SPAN for especificado, o pipeline processará o intervalo mais recente e armazenará o número do span nos metadados. + +Por exemplo, vamos supor que existam os seguintes dados de entrada: + +- '/tmp/span-1/train/data' +- '/tmp/span-1/eval/data' +- '/tmp/span-2/train/data' +- '/tmp/span-2/eval/data' + +e a configuração de entrada mostrada abaixo: + +```python +splits { + name: 'train' + pattern: 'span-{SPAN}/train/*' +} +splits { + name: 'eval' + pattern: 'span-{SPAN}/eval/*' +} +``` + +ao acionar o pipeline, ele processará: + +- '/tmp/span-2/train/data' como uma divisão de treinamento (train) +- '/tmp/span-2/eval/data' como uma divisão de avaliação (eval) + +com o número de span igual a '2'. Se mais tarde '/tmp/span-3/...' estiverem prontos, basta acionar o pipeline novamente e ele pegará o span '3' para processamento. Abaixo está mostrado um exemplo de código usando a especificação span: + +```python +input = proto.Input(splits=[ + proto.Input.Split(name='train', + pattern='span-{SPAN}/train/*'), + proto.Input.Split(name='eval', + pattern='span-{SPAN}/eval/*') + ]) +example_gen = CsvExampleGen(input_base='/tmp', input_config=input) +``` + +A recuperação de um determinado span pode ser feita com RangeConfig, detalhado a seguir. + +### Date + +Observação: este recurso só está disponível para versões posteriores ao TFX 0.24.0. + +Se a sua fonte de dados estiver organizada no sistema de arquivos por data, o TFX oferece suporte ao mapeamento direto de datas para números de span. Existem três especificações para representar o mapeamento de datas para spans: {YYYY}, {MM} e {DD}: + +- As três especificações devem estar presentes no [padrão de entrada glob](https://github.com/tensorflow/tfx/blob/master/tfx/proto/example_gen.proto), se alguma for especificada: +- Ou a especificação {SPAN} ou este conjunto de especificações de data podem ser especificados exclusivamente. +- Uma data de calendário com o ano a partir de YYYY, o mês a partir de MM e o dia do mês a partir de DD é calculada, então o número do span é calculado como o número de dias desde a época Unix (ou seja, 1970-01-01). Por exemplo, 'log-{YYYY}{MM}{DD}.data' corresponde a um arquivo 'log-19700101.data' e o consome como entrada para Span-0, e 'log-20170101.data' como entrada para Span-17167. +- Se este conjunto de especificações de data for especificado, o pipeline processará a data mais recente e armazenará o número de span correspondente nos metadados. + +Por exemplo, vamos supor que existam os seguintes dados de entrada organizados por data do calendário: + +- '/tmp/1970-01-02/train/data' +- '/tmp/1970-01-02/eval/data' +- '/tmp/1970-01-03/train/data' +- '/tmp/1970-01-03/eval/data' + +e a configuração de entrada mostrada abaixo: + +```python +splits { + name: 'train' + pattern: '{YYYY}-{MM}-{DD}/train/*' +} +splits { + name: 'eval' + pattern: '{YYYY}-{MM}-{DD}/eval/*' +} +``` + +ao acionar o pipeline, ele processará: + +- '/tmp/1970-01-03/train/data' como uma divisão de treinamento (train) +- '/tmp/1970-01-03/eval/data' como uma divisão de avaliação (eval) + +com número de span igual '2'. Se mais tarde '/tmp/1970-01-04/...' estiverem prontos, basta acionar o pipeline novamente e ele pegará o span '3' para processamento. Abaixo está mostrado um exemplo de código que usa a especificação Date: + +```python +input = proto.Input(splits=[ + proto.Input.Split(name='train', + pattern='{YYYY}-{MM}-{DD}/train/*'), + proto.Input.Split(name='eval', + pattern='{YYYY}-{MM}-{DD}/eval/*') + ]) +example_gen = CsvExampleGen(input_base='/tmp', input_config=input) +``` + +### Version + +Observação: este recurso só está disponível para versões posteriores ao TFX 0.24.0. + +A versão pode ser recuperada usando a especificação '{VERSION}' no [padrão de entrada glob](https://github.com/tensorflow/tfx/blob/master/tfx/proto/example_gen.proto): + +- Esta especificação combina dígitos e mapeia os dados para os números de VERSÃO relevantes no SPAN. Observe que a especificação Version pode ser usada em combinação com a especificação Span ou Data. +- Esta especificação também pode ser opcionalmente especificada com a largura da mesma forma que a especificação SPAN. por exemplo, 'span-{SPAN}/version-{VERSION:4}/data-*'. +- Quando a especificação VERSION está faltando, a versão é definida como None. +- Se SPAN e VERSION forem especificados, o pipeline processará a versão mais recente para o span mais recente e armazenará o número da versão nos metadados. +- Se VERSION for especificado, mas não SPAN (ou especificação Date), um erro será gerado. + +Por exemplo, vamos supor que existam os seguintes dados de entrada: + +- '/tmp/span-1/ver-1/train/data' +- '/tmp/span-1/ver-1/eval/data' +- '/tmp/span-2/ver-1/train/data' +- '/tmp/span-2/ver-1/eval/data' +- '/tmp/span-2/ver-2/train/data' +- '/tmp/span-2/ver-2/eval/data' + +e a configuração de entrada mostrada abaixo: + +```python +splits { + name: 'train' + pattern: 'span-{SPAN}/ver-{VERSION}/train/*' +} +splits { + name: 'eval' + pattern: 'span-{SPAN}/ver-{VERSION}/eval/*' +} +``` + +ao acionar o pipeline, ele processará: + +- '/tmp/span-2/ver-2/train/data' como uma divisão de treinamento (train) +- '/tmp/span-2/ver-2/train/data' como uma divisão de avaliação (eval) + +com número de span igual a '2' e número de versão igual a '2'. Se mais tarde '/tmp/span-2/ver-3/...' estiverem prontos, basta acionar o pipeline novamente e ele selecionará o span '2' e a versão '3' para processamento. Abaixo está mostrado um exemplo de código que usa a especificação Version: + +```python +input = proto.Input(splits=[ + proto.Input.Split(name='train', + pattern='span-{SPAN}/ver-{VERSION}/train/*'), + proto.Input.Split(name='eval', + pattern='span-{SPAN}/ver-{VERSION}/eval/*') + ]) +example_gen = CsvExampleGen(input_base='/tmp', input_config=input) +``` + +### Range Config (configuração de intervalo) + +Observação: este recurso só está disponível para versões posteriores ao TFX 0.24.0. + +O TFX oferece suporte à recuperação e ao processamento de um span específico em ExampleGen baseado em arquivo usando range config (configuração de intervalo), uma configuração abstrata usada para descrever intervalos (ranges) para diferentes entidades TFX. Para recuperar um span específico, defina `range_config` para um componente ExampleGen baseado em arquivo. Por exemplo, vamos supor que existam os seguintes dados de entrada: + +- '/tmp/span-01/train/data' +- '/tmp/span-01/eval/data' +- '/tmp/span-02/train/data' +- '/tmp/span-02/eval/data' + +Para recuperar e processar especificamente dados com span '1', especificamos uma configuração de intervalo (range config) além da configuração de entrada. Observe que ExampleGen oferece suporte apenas a intervalos estáticos de span único (para especificar o processamento de spans individuais específicos). Assim, para StaticRange, start_span_number deve ser igual a end_span_number. Usando o span fornecido e as informações de largura do span (se fornecidas) para preenchimento com zeros, o ExampleGen substituirá a especificação SPAN nos padrões de divisão fornecidos pelo número do span desejado. Um exemplo de uso é mostrado abaixo: + +```python +# In cases where files have zero-padding, the width modifier in SPAN spec is +# required so TFX can correctly substitute spec with zero-padded span number. +input = proto.Input(splits=[ + proto.Input.Split(name='train', + pattern='span-{SPAN:2}/train/*'), + proto.Input.Split(name='eval', + pattern='span-{SPAN:2}/eval/*') + ]) +# Specify the span number to be processed here using StaticRange. +range = proto.RangeConfig( + static_range=proto.StaticRange( + start_span_number=1, end_span_number=1) + ) + +# After substitution, the train and eval split patterns will be +# 'input_dir/span-01/train/*' and 'input_dir/span-01/eval/*', respectively. +example_gen = CsvExampleGen(input_base=input_dir, input_config=input, + range_config=range) +``` + +A configuração de intervalo também pode ser usada para processar datas específicas, se a especificação de data for usada em vez da especificação SPAN. Por exemplo, vamos supor que existam dados de entrada organizados pela data de calendário: + +- '/tmp/1970-01-02/train/data' +- '/tmp/1970-01-02/eval/data' +- '/tmp/1970-01-03/train/data' +- '/tmp/1970-01-03/eval/data' + +Para recuperar e processar especificamente dados de 2 de janeiro de 1970, fazemos o seguinte: + +```python +from tfx.components.example_gen import utils + +input = proto.Input(splits=[ + proto.Input.Split(name='train', + pattern='{YYYY}-{MM}-{DD}/train/*'), + proto.Input.Split(name='eval', + pattern='{YYYY}-{MM}-{DD}/eval/*') + ]) +# Specify date to be converted to span number to be processed using StaticRange. +span = utils.date_to_span_number(1970, 1, 2) +range = proto.RangeConfig( + static_range=range_config_pb2.StaticRange( + start_span_number=span, end_span_number=span) + ) + +# After substitution, the train and eval split patterns will be +# 'input_dir/1970-01-02/train/*' and 'input_dir/1970-01-02/eval/*', +# respectively. +example_gen = CsvExampleGen(input_base=input_dir, input_config=input, + range_config=range) +``` + +## ExampleGen personalizado + +Se os componentes do ExampleGen atualmente disponíveis não atenderem às suas necessidades, você poderá criar um ExampleGen personalizado, que permitirá a leitura de diferentes fontes de dados ou em diferentes formatos de dados. + +### Personalização de ExampleGen baseada em arquivo (experimental) + +Primeiro, estenda BaseExampleGenExecutor com um Beam PTransform personalizado, que fornece a conversão de sua divisão de entrada de treinamento/avaliação para exemplos do TF. Por exemplo, o [executor CsvExampleGen](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/csv_example_gen/executor.py) fornece a conversão de uma divisão CSV de entrada para exemplos do TF. + +Em seguida, crie um componente com o executor acima, como feito em [CsvExampleGen component](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/csv_example_gen/component.py). Como alternativa, passe um executor personalizado para o componente ExampleGen padrão conforme mostrado abaixo. + +```python +from tfx.components.base import executor_spec +from tfx.components.example_gen.csv_example_gen import executor + +example_gen = FileBasedExampleGen( + input_base=os.path.join(base_dir, 'data/simple'), + custom_executor_spec=executor_spec.ExecutorClassSpec(executor.Executor)) +``` + +Agora também oferecemos suporte à leitura de arquivos Avro e Parquet usando este [método](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/custom_executors/). + +### Formatos de dados adicionais + +O Apache Beam oferece suporte à leitura de vários [formatos de dados adicionais](https://beam.apache.org/documentation/io/built-in/) através de transformações de E/S do Beam (Beam I/O Transforms). Você pode criar componentes ExampleGen personalizados aproveitando o Beam I/O Transforms usando um padrão semelhante ao do [exemplo de leitura de arquivos Avro](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/custom_executors/avro_executor.py#L56) + +```python + return (pipeline + | 'ReadFromAvro' >> beam.io.ReadFromAvro(avro_pattern) + | 'ToTFExample' >> beam.Map(utils.dict_to_example)) +``` + +No momento em que este artigo foi escrito, os formatos e fontes de dados atualmente suportados pelo Beam Python SDK são os seguintes: + +- Amazon S3 +- Apache Avro +- Apache Hadoop +- Apache Kafka +- Apache Parquet +- Google Cloud BigQuery +- Google Cloud BigTable +- Google Cloud Datastore +- Google Cloud Pub/Sub +- Google Cloud Storage (GCS) +- MongoDB + +Confira a [Documentação do Beam](https://beam.apache.org/documentation/io/built-in/) para obter a lista mais recente. + +### Personalização de ExampleGen baseada em consulta (experimental) + +Primeiro, estenda o BaseExampleGenExecutor com um Beam PTransform personalizado, que lê a fonte de dados externa. Em seguida, crie um componente simples estendendo QueryBasedExampleGen. + +Isto poderá ou não exigir configurações de conexão adicionais. Por exemplo, o [executor BigQuery](https://github.com/tensorflow/tfx/blob/master/tfx/extensions/google_cloud_big_query/example_gen/executor.py) lê usando um conector beam.io padrão, que abstrai os detalhes de configuração da conexão. O [executor Presto](https://github.com/tensorflow/tfx/blob/master/tfx/examples/custom_components/presto_example_gen/presto_component/executor.py) requer um Beam PTransform personalizado e um [protobuf de configuração de conexão personalizada](https://github.com/tensorflow/tfx/blob/master/tfx/examples/custom_components/presto_example_gen/proto/presto_config.proto) como entrada. + +Se uma configuração de conexão for necessária para um componente SampleGen personalizado, crie um novo protobuf e passe-o via custom_config, que agora é um parâmetro de execução opcional. Abaixo está um exemplo de como usar um componente configurado. + +```python +from tfx.examples.custom_components.presto_example_gen.proto import presto_config_pb2 +from tfx.examples.custom_components.presto_example_gen.presto_component.component import PrestoExampleGen + +presto_config = presto_config_pb2.PrestoConnConfig(host='localhost', port=8080) +example_gen = PrestoExampleGen(presto_config, query='SELECT * FROM chicago_taxi_trips') +``` + +## Componentes downstream do ExampleGen + +A configuração personalizada de divisões (splits) é suportada para componentes que aparecem no pipeline depois do ExampleGen (componentes downstream). + +### StatisticsGen + +O comportamento padrão é gerar estatísticas para todas as divisões. + +Para excluir quaisquer divisões, defina `exclude_splits` para o componente StatisticsGen. Por exemplo: + +```python +# Exclude the 'eval' split. +statistics_gen = StatisticsGen( + examples=example_gen.outputs['examples'], + exclude_splits=['eval']) +``` + +### SchemaGen + +O comportamento padrão é gerar um esquema baseado em todas as divisões. + +Para excluir quaisquer divisões, defina `exclude_splits` para o componente SchemaGen. Por exemplo: + +```python +# Exclude the 'eval' split. +schema_gen = SchemaGen( + statistics=statistics_gen.outputs['statistics'], + exclude_splits=['eval']) +``` + +### ExampleValidator + +O comportamento padrão é validar as estatísticas de todas as divisões em exemplos de entrada em relação a um esquema. + +Para excluir quaisquer divisões, defina `exclude_splits` para o componente ExampleValidator. Por exemplo: + +```python +# Exclude the 'eval' split. +example_validator = ExampleValidator( + statistics=statistics_gen.outputs['statistics'], + schema=schema_gen.outputs['schema'], + exclude_splits=['eval']) +``` + +### Transform + +O comportamento padrão é analisar e produzir os metadados da divisão 'train' e transformar todas as divisões. + +Para especificar as divisões de análise e de transformação, defina `splits_config` para o componente Transform. Por exemplo: + +```python +# Analyze the 'train' split and transform all splits. +transform = Transform( + examples=example_gen.outputs['examples'], + schema=schema_gen.outputs['schema'], + module_file=_taxi_module_file, + splits_config=proto.SplitsConfig(analyze=['train'], + transform=['train', 'eval'])) +``` + +### Trainer e Tuner + +O comportamento padrão é treinar na divisão 'train' e avaliar na divisão 'eval'. + +Para especificar as divisões de treinamento e avaliação, defina `train_args` e `eval_args` para o componente Trainer. Por exemplo: + +```python +# Train on the 'train' split and evaluate on the 'eval' split. +Trainer = Trainer( + module_file=_taxi_module_file, + examples=transform.outputs['transformed_examples'], + schema=schema_gen.outputs['schema'], + transform_graph=transform.outputs['transform_graph'], + train_args=proto.TrainArgs(splits=['train'], num_steps=10000), + eval_args=proto.EvalArgs(splits=['eval'], num_steps=5000)) +``` + +### Evaluator + +O comportamento padrão é fornecer métricas computadas na divisão 'eval'. + +Para computar estatísticas de avaliação em divisões personalizadas, defina `example_splits` para o componente Evaluator. Por exemplo: + +```python +# Compute metrics on the 'eval1' split and the 'eval2' split. +evaluator = Evaluator( + examples=example_gen.outputs['examples'], + model=trainer.outputs['model'], + example_splits=['eval1', 'eval2']) +``` + +Mais detalhes estão disponíveis na [Referência da API do CsvExampleGen](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/CsvExampleGen), na [Implementação da API FileBasedExampleGen](https://github.com/tensorflow/tfx/blob/master/tfx/components/example_gen/component.py) e na [Referência da API ImportExampleGen](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/ImportExampleGen). diff --git a/site/pt-br/tfx/guide/exampleval.md b/site/pt-br/tfx/guide/exampleval.md new file mode 100644 index 0000000000..0c4266eaa0 --- /dev/null +++ b/site/pt-br/tfx/guide/exampleval.md @@ -0,0 +1,30 @@ +# O componente de pipeline ExampleValidator TFX + +O componente de pipeline ExampleValidator identifica anomalias no treinamento e no fornecimento de dados. Ele pode detectar diferentes classes de anomalias nos dados. Por exemplo, ele pode: + +1. realizar verificações de validade comparando estatísticas de dados com um esquema que codifica as expectativas do usuário. +2. detectar desvios no fornecimento de treinamento comparando dados de treinamento e fornecimento. +3. detectar desvios de dados observando uma série de dados. +4. executar [validações personalizadas](https://github.com/tensorflow/data-validation/blob/master/g3doc/custom_data_validation.md) usando uma configuração baseada em SQL. + +O componente de pipeline ExampleValidator identifica quaisquer anomalias nos dados de exemplo comparando estatísticas de dados calculadas pelo componente de pipeline StatisticsGen contra um esquema. O esquema inferido codifica propriedades que se espera que os dados de entrada satisfaçam e podem ser modificados pelo desenvolvedor. + +- Consome: o esquema de um componente SchemaGen e estatísticas de um componente StatisticsGen. +- Produz: resultados de validação + +## ExampleValidator e TensorFlow Data Validation + +O ExampleValidator faz uso extensivo do [TensorFlow Data Validation](tfdv.md) para validar seus dados de entrada. + +## Usando o componente ExampleValidator + +Um componente de pipeline ExampleValidator normalmente é muito fácil de implantar e requer pouca personalização. O código típico está mostrado a seguir: + +```python +validate_stats = ExampleValidator( + statistics=statistics_gen.outputs['statistics'], + schema=schema_gen.outputs['schema'] + ) +``` + +Mais detalhes estão disponíveis na [Referência da API ExampleValidator](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/ExampleValidator). diff --git a/site/pt-br/tfx/guide/fairness_indicators.md b/site/pt-br/tfx/guide/fairness_indicators.md new file mode 100644 index 0000000000..34ffaee544 --- /dev/null +++ b/site/pt-br/tfx/guide/fairness_indicators.md @@ -0,0 +1,247 @@ +# Fairness Indicators + +A ferramenta Fairness Indicators foi projetada para apoiar as equipes na avaliação e melhoria de modelos para questões de equidade em parceria com o kit de ferramentas mais abrangente do Tensorflow. A ferramenta é usada internamente por muitos de nossos produtos e agora está disponível em BETA para você testar nos seus próprios casos de uso. + +![Dashboard do Fairness Indicator](https://github.com/tensorflow/docs-l10n/blob/master/site/pt-br/tfx/guide/images/fairnessIndicators.png?raw=true) + +## O que é o Fairness Indicators? + +Fairness Indicators (indicadores de equidade) é uma biblioteca que permite a computação fácil de métricas de equidade frequentemente identificadas para classificadores binários e multiclasse. Muitas ferramentas existentes para avaliar questões de equidade não funcionam bem em datasets e modelos de grande escala. No Google, é importante que tenhamos ferramentas que possam funcionar em sistemas com bilhões de usuários. O Fairness Indicators permitire que você avalie casos de uso de qualquer tamanho. + +Em particular, o Fairness Indicators inclui a capacidade de: + +- Avaliar a distribuição de datasets +- Avaliar o desempenho de modelos, divididos em grupos de usuários definidos + - Trazer confiança em relação aos seus resultados com intervalos de confiança e avaliações em múltiplod limites +- Mergulhar fundo em fatias individuais para explorar as causas raízes e oportunidades de melhoria + +Este [estudo de caso](https://developers.google.com/machine-learning/practica/fairness-indicators), completo com [vídeos](https://www.youtube.com/watch?v=pHT-ImFXPQo) e exercícios de programação, demonstra como o Fairness Indicators pode ser usado ​​num de seus próprios produtos para avaliar preocupações quanto à equidade ao longo do tempo. + +[](http://www.youtube.com/watch?v=pHT-ImFXPQo) + +O download do pacote pip inclui: + +- **[Tensorflow Data Validation (TFDV)](https://www.tensorflow.org/tfx/data_validation/get_started)** +- **[Tensorflow Model Analysis (TFMA)](https://www.tensorflow.org/tfx/model_analysis/get_started)** + - **Fairness Indicators** +- **[The What-If Tool (WIT)](https://www.tensorflow.org/tensorboard/what_if_tool)** + +## Usando Fairness Indicators com modelos Tensorflow + +### Dados + +Para executar Fairness Indicators com o TFMA, certifique-se de que o dataset de avaliação esteja rotulado para as características que você gostaria usar para fatiar. Se você não tiver as características exatas de fatiamento para suas questões de equidade, você pode tentar encontrar um conjunto de avaliações que tenha, ou considerar usar características intermediárias no seu conjunto de características que possam destacar disparidades dos resultados. Para orientação adicional, clique [aqui](https://tensorflow.org/responsible_ai/fairness_indicators/guide/guidance). + +### Modelos + +Você pode usar a classe Tensorflow Estimator para construir seu modelo. O suporte para modelos Keras chegará em breve ao TFMA. Se você deseja executar o TFMA num modelo Keras, consulte a seção “TFMA independente de modelo” abaixo. + +Depois do treinamento do seu Estimator, você precisará exportar um modelo salvo para fins de avaliação. Para saber mais, veja o [guia do TFMA](/tfx/model_analysis/get_started). + +### Configurando fatias + +Em seguida, defina as fatias que você gostaria de avaliar: + +```python +slice_spec = [ + tfma.slicer.SingleSliceSpec(columns=[‘fur color’]) +] +``` + +Se quiser avaliar fatias interseccionais (por exemplo, cor e altura do pelo), você pode definir o seguinte: + +```python +slice_spec = [ + tfma.slicer.SingleSliceSpec(columns=[‘fur_color’, ‘height’]) +]` +``` + +### Computação de métricas de equidade + +Adicione um callback do Fairness Indicators à lista `metrics_callback`. No retorno de chamada, você poderá definir uma lista de limites nos quais o modelo será avaliado. + +```python +from tensorflow_model_analysis.addons.fairness.post_export_metrics import fairness_indicators + +# Build the fairness metrics. Besides the thresholds, you also can config the example_weight_key, labels_key here. For more details, please check the api. +metrics_callbacks = \ + [tfma.post_export_metrics.fairness_indicators(thresholds=[0.1, 0.3, + 0.5, 0.7, 0.9])] + +eval_shared_model = tfma.default_eval_shared_model( + eval_saved_model_path=tfma_export_dir, + add_metrics_callbacks=metrics_callbacks) +``` + +Antes de executar a configuração, determine se deseja ou não ativar a computação de intervalos de confiança. Os intervalos de confiança são calculados usando inicialização de Poisson e requerem recomputação em 20 amostras. + +```python +compute_confidence_intervals = True +``` + +Execute o pipeline de avaliação do TFMA: + +```python +validate_dataset = tf.data.TFRecordDataset(filenames=[validate_tf_file]) + +# Run the fairness evaluation. +with beam.Pipeline() as pipeline: + _ = ( + pipeline + | beam.Create([v.numpy() for v in validate_dataset]) + | 'ExtractEvaluateAndWriteResults' >> + tfma.ExtractEvaluateAndWriteResults( + eval_shared_model=eval_shared_model, + slice_spec=slice_spec, + compute_confidence_intervals=compute_confidence_intervals, + output_path=tfma_eval_result_path) + ) +eval_result = tfma.load_eval_result(output_path=tfma_eval_result_path) +``` + +### Renderização de Fairness Indicators + +```python +from tensorflow_model_analysis.addons.fairness.view import widget_view + +widget_view.render_fairness_indicator(eval_result=eval_result) +``` + +![Fairness Indicators](images/fairnessIndicators.png) + +Dicas para usar Fairness Indicators: + +- **Selecione as métricas a serem exibidas** marcando as caixas do lado esquerdo. Grafos individuais para cada uma das métricas aparecerão no widget, em ordem. +- **Altere a fatia de referência**, a primeira barra do grafo, usando o menu dropdown. Os deltas serão calculados com base neste valor de referência. +- **Selecione limites** usando o menu dropdown. Você pode visualizar vários limites no mesmo grafo. Os limites selecionados estarão em negrito e você pode clicar sobre um limite em negrito para deselecioná-lo. +- **Passe o mouse sobre uma barra** para ver as métricas dessa fatia. +- **Identifique disparidades com a linha de referência** usando a coluna "Diferença com linha de referência", que identifica a diferença percentual entre a fatia atual e a referência. +- **Explore detalhadamente os pontos de dados de uma fatia** usando a [ferramenta What-If](https://pair-code.github.io/what-if-tool/). Veja [aqui](https://github.com/tensorflow/fairness-indicators/) um exemplo. + +#### Renderizando Fairness Indicators para múltiplos modelos + +Os Fairness Indicators também podem ser usados ​​para comparar modelos. Em vez de passar um único eval_result, passe um objeto multi_eval_results, que é um dicionário que mapeia dois nomes de modelos para objetos eval_result. + +```python +from tensorflow_model_analysis.addons.fairness.view import widget_view + +eval_result1 = tfma.load_eval_result(...) +eval_result2 = tfma.load_eval_result(...) +multi_eval_results = {"MyFirstModel": eval_result1, "MySecondModel": eval_result2} + +widget_view.render_fairness_indicator(multi_eval_results=multi_eval_results) +``` + +![Fairness Indicators - comparação de modelos](https://github.com/tensorflow/docs-l10n/blob/master/site/pt-br/tfx/guide/images/fairnessIndicators.png?raw=true) + +A comparação de modelos pode ser usada junto com a comparação de limites. Por exemplo, você pode comparar dois modelos em dois conjuntos de limites para encontrar a combinação ideal para suas métricas de equidade. + +## Usando Fairness Indicators com modelos não TensorFlow + +Para melhor atender aos clientes que possuem diferentes modelos e workflows, desenvolvemos uma biblioteca de avaliação que independe do modelo que está sendo avaliado. + +Qualquer pessoa que queira avaliar seu sistema de aprendizado de máquina pode usá-lo, especialmente se você tiver modelos não baseados no TensorFlow. Usando o Apache Beam Python SDK, você pode criar um binário de avaliação TFMA independente e executá-lo para analisar seu modelo. + +### Dados + +Esta etapa tem como objetivo fornecer o dataset no qual você deseja que as avaliações sejam executadas. Deve estar no formato proto [tf.Example](https://www.tensorflow.org/tutorials/load_data/tfrecord) com rótulos, previsões e outras caraterísticas que você pode querer dividir. + +```python +tf.Example { + features { + feature { + key: "fur_color" value { bytes_list { value: "gray" } } + } + feature { + key: "height" value { bytes_list { value: "tall" } } + } + feature { + key: "prediction" value { float_list { value: 0.9 } } + } + feature { + key: "label" value { float_list { value: 1.0 } } + } + } +} +``` + +### Modelos + +Em vez de especificar um modelo, você cria uma configuração e um extrator de avaliação independente do modelo para analisar e fornecer os dados que o TFMA precisa para calcular as métricas. A especificação [ModelAgnosticConfig](https://github.com/tensorflow/model-analysis/blob/master/tensorflow_model_analysis/model_agnostic_eval/model_agnostic_predict.py) define as características, previsões e rótulos a serem usados ​​nos exemplos de entrada. + +Para isso, crie um mapa de características com chaves que representam todas as características, incluindo chaves de rótulo e predição e valores que representam o tipo de dados da característica. + +```python +feature_map[label_key] = tf.FixedLenFeature([], tf.float32, default_value=[0]) +``` + +Crie uma configuração independente de modelo usando chaves de rótulo, chaves de previsão e mapa de características. + +```python +model_agnostic_config = model_agnostic_predict.ModelAgnosticConfig( + label_keys=list(ground_truth_labels), + prediction_keys=list(predition_labels), + feature_spec=feature_map) +``` + +### Configuração de um Extractor independente de modelos + +O [Extractor](https://github.com/tensorflow/model-analysis/blob/master/tensorflow_model_analysis/model_agnostic_eval/model_agnostic_extractor.py) é usado para extrair as características, rótulos e previsões da entrada usando uma configuração independente de modelos (model agnostic). E se quiser fatiar seus dados, você também precisará definir a [slice key spec](https://github.com/tensorflow/model-analysis/tree/master/tensorflow_model_analysis/slicer), contendo informações sobre as colunas que deseja fatiar. + +```python +model_agnostic_extractors = [ + model_agnostic_extractor.ModelAgnosticExtractor( + model_agnostic_config=model_agnostic_config, desired_batch_size=3), + slice_key_extractor.SliceKeyExtractor([ + slicer.SingleSliceSpec(), + slicer.SingleSliceSpec(columns=[‘height’]), + ]) +] +``` + +### Computação de métricas de equidade + +Como parte do [EvalSharedModel](https://www.tensorflow.org/tfx/model_analysis/api_docs/python/tfma/types/EvalSharedModel), você pode fornecer todas as métricas nas quais deseja que seu modelo seja avaliado. As métricas são fornecidas na forma de retornos de chamada de métricas, como os definidos em [post_export_metrics](https://github.com/tensorflow/model-analysis/blob/master/tensorflow_model_analysis/post_export_metrics/post_export_metrics.py) ou [fairness_indicators](https://github.com/tensorflow/model-analysis/blob/master/tensorflow_model_analysis/addons/fairness/post_export_metrics/fairness_indicators.py). + +```python +metrics_callbacks.append( + post_export_metrics.fairness_indicators( + thresholds=[0.5, 0.9], + target_prediction_keys=[prediction_key], + labels_key=label_key)) +``` + +Ele também recebe um `construct_fn` que é usado para criar um grafo tensorflow para realizar a avaliação. + +```python +eval_shared_model = types.EvalSharedModel( + add_metrics_callbacks=metrics_callbacks, + construct_fn=model_agnostic_evaluate_graph.make_construct_fn( + add_metrics_callbacks=metrics_callbacks, + fpl_feed_config=model_agnostic_extractor + .ModelAgnosticGetFPLFeedConfig(model_agnostic_config))) +``` + +Depois que tudo estiver configurado, use uma das funções `ExtractEvaluate` ou `ExtractEvaluateAndWriteResults` fornecidas por [model_eval_lib](https://github.com/tensorflow/model-analysis/blob/master/tensorflow_model_analysis/api/model_eval_lib.py) para avaliar o modelo. + +```python +_ = ( + examples | + 'ExtractEvaluateAndWriteResults' >> + model_eval_lib.ExtractEvaluateAndWriteResults( + eval_shared_model=eval_shared_model, + output_path=output_path, + extractors=model_agnostic_extractors)) + +eval_result = tensorflow_model_analysis.load_eval_result(output_path=tfma_eval_result_path) +``` + +Finalmente, renderize Fairness Indicators usando as instruções da seção "Renderizando Fairness Indicators" acima. + +## Mais exemplos + +O [diretório de exemplos d Fairness Indicators](https://github.com/tensorflow/fairness-indicators/blob/master/g3doc/tutorials/) contém vários exemplos: + +- [Fairness_Indicators_Example_Colab.ipynb](https://github.com/tensorflow/fairness-indicators/blob/master/g3doc/tutorials/Fairness_Indicators_Example_Colab.ipynb) fornece uma visão geral do Fairness Indicators no [TensorFlow Model Analysis](https://www.tensorflow.org/tfx/guide/tfma) e como usá-lo com um dataset de verdade. Este notebook também aborda o [TensorFlow Data Validation](https://www.tensorflow.org/tfx/data_validation/get_started) e a ferramenta [What-If](https://pair-code.github.io/what-if-tool/), duas ferramentas para analisar modelos do TensorFlow que vêm com indicadores de equidade. +- [Fairness_Indicators_on_TF_Hub.ipynb](https://github.com/tensorflow/fairness-indicators/blob/master/g3doc/tutorials/Fairness_Indicators_on_TF_Hub_Text_Embeddings.ipynb) demonstra como usar Fairness Indicators para comparar modelos treinados em diferentes [embeddings de texto](https://en.wikipedia.org/wiki/Word_embedding). Este notebook usa embeddings de texto do [TensorFlow Hub](https://www.tensorflow.org/hub), a biblioteca do TensorFlow para publicar, descobrir e reutilizar componentes do modelo. +- [Fairness_Indicators_TensorBoard_Plugin_Example_Colab.ipynb](https://github.com/tensorflow/fairness-indicators/blob/master/g3doc/tutorials/Fairness_Indicators_TensorBoard_Plugin_Example_Colab.ipynb) demonstra como visualizar Fairness Indicators no TensorBoard. diff --git a/site/pt-br/tfx/guide/infra_validator.md b/site/pt-br/tfx/guide/infra_validator.md new file mode 100644 index 0000000000..6be48146b2 --- /dev/null +++ b/site/pt-br/tfx/guide/infra_validator.md @@ -0,0 +1,174 @@ +# O componente de pipeline InfraValidator TFX + +O InfraValidator é um componente TFX usado como uma camada de alerta antecipado antes de enviar um modelo para produção. O nome validador “infra” vem do fato de estar validando o modelo no próprio modelo que atende a “infraestrutura”. Se o [Evaluator](evaluator.md) precisa garantir o desempenho do modelo, o InfraValidator precisa garantir que o modelo esteja mecanicamente correto e evitar que modelos ruins sejam enviados. + +## Como funciona? + +O InfraValidator pega o modelo, inicia um servidor de modelos em sandbox com o modelo e verifica se ele pode ser carregado com sucesso e, opcionalmente, pesquisado. O resultado da infra-validação será gerado na saída de `blessing` da mesma forma que o [Evaluator](evaluator.md). + +O InfraValidator foca na compatibilidade entre o binário do servidor do modelo (por exemplo, [TensorFlow Serving](serving.md)) e o modelo a ser implantado. Apesar do nome validador "infra", é **responsabilidade do usuário** configurar o ambiente corretamente, e o infravalidador apenas interage com o servidor de modelos no ambiente configurado pelo usuário para verificar se funciona bem. Configurar este ambiente corretamente garantirá que a aprovação ou falha na infravalidação será um indicativo de se o modelo seria utilizável no ambiente do serviço em produção. Isto implica, mas não se limita a, algumas das seguintes questões: + +1. O InfraValidator está usando o mesmo modelo binário de servidor que será usado em produção. Este é o nível mínimo para o qual o ambiente de infravalidação deve convergir. +2. O InfraValidator está usando os mesmos recursos (por exemplo, quantidade de alocação e tipo de CPU, memória e aceleradores) que serão usados ​​em produção. +3. O InfraValidator está usando o mesmo modelo de configuração de servidor que será usado em produção. + +Dependendo da situação, os usuários poderão escolher até que ponto o InfraValidator deve ser idêntico ao ambiente em produção. Tecnicamente, um modelo pode ser infravalidado num ambiente Docker local e depois servido num ambiente completamente diferente (por exemplo, num cluster Kubernetes) sem problemas. No entanto, o InfraValidator não terá verificado esta divergência. + +### Modo de operação + +Dependendo da configuração, a infravalidação é feita num dos seguintes modos: + +- Modo `LOAD_ONLY`: verifica se o modelo foi carregado com sucesso na infraestrutura de serviço ou não, **OU** +- Modo `LOAD_AND_QUERY`: modo `LOAD_ONLY` mais o envio de algumas solicitações de amostra para verificar se o modelo é capaz de servir inferências. O InfraValidator não se importa se a previsão estava correta ou não, apenas se a solicitação foi bem-sucedida ou não. + +## Como usar? + +Geralmente o InfraValidator é definido junto com um componente Evaluator, e sua saída é alimentada a um Pusher. Se o InfraValidator falhar, o modelo não será enviado. + +```python +evaluator = Evaluator( + model=trainer.outputs['model'], + examples=example_gen.outputs['examples'], + baseline_model=model_resolver.outputs['model'], + eval_config=tfx.proto.EvalConfig(...) +) + +infra_validator = InfraValidator( + model=trainer.outputs['model'], + serving_spec=tfx.proto.ServingSpec(...) +) + +pusher = Pusher( + model=trainer.outputs['model'], + model_blessing=evaluator.outputs['blessing'], + infra_blessing=infra_validator.outputs['blessing'], + push_destination=tfx.proto.PushDestination(...) +) +``` + +### Configurando um componente InfraValidator. + +Existem três tipos de protos para configurar o InfraValidator. + +#### `ServingSpec` + +`ServingSpec` é a configuração mais importante para o InfraValidator. Ele define: + +- que tipo de servidor modelo executar +- onde executá-lo + +Para tipos de servidores de modelo (chamados de binários de serviço), oferecemos suporte a + +- [TensorFlow Serving](serving.md) + +Observação: O InfraValidator permite especificar diversas versões do mesmo tipo de servidor de modelos para atualizar a versão do servidor de modelos sem afetar a compatibilidade dos modelos. Por exemplo, o usuário pode testar a imagem `tensorflow/serving` com as versões `2.1.0` e `latest`, para garantir que o modelo também será compatível com a versão mais recente do `tensorflow/serving`. + +As seguintes plataformas de serviço são atualmente suportadas: + +- Docker local (o Docker deve ser instalado com antecedência) +- Kubernetes (suporte limitado apenas para KubeflowDagRunner) + +A escolha do serviço binário e da plataforma de serviço é feita especificando um bloco [`oneof`](https://developers.google.com/protocol-buffers/docs/proto3#oneof) do `ServingSpec`. Por exemplo, para usar o binário TensorFlow Serving em execução no cluster Kubernetes, os campos `tensorflow_serving` e `kubernetes` devem ser definidos. + +```python +infra_validator=InfraValidator( + model=trainer.outputs['model'], + serving_spec=tfx.proto.ServingSpec( + tensorflow_serving=tfx.proto.TensorFlowServing( + tags=['latest'] + ), + kubernetes=tfx.proto.KubernetesConfig() + ) +) +``` + +Para configurar ainda mais o `ServingSpec`, veja a [Definição do protobuf](https://github.com/tensorflow/tfx/blob/master/tfx/proto/infra_validator.proto). + +#### `ValidationSpec` + +Configuração opcional para ajustar os critérios de infravalidação ou workflow. + +```python +infra_validator=InfraValidator( + model=trainer.outputs['model'], + serving_spec=tfx.proto.ServingSpec(...), + validation_spec=tfx.proto.ValidationSpec( + # How much time to wait for model to load before automatically making + # validation fail. + max_loading_time_seconds=60, + # How many times to retry if infra validation fails. + num_tries=3 + ) +) +``` + +Todos os campos ValidationSpec possuem um valor padrão sólido. Confira mais detalhes na [definição do protobuf](https://github.com/tensorflow/tfx/blob/master/tfx/proto/infra_validator.proto). + +#### `RequestSpec` + +Configuração opcional para especificar como criar solicitações de exemplo ao executar a infra-validação no modo `LOAD_AND_QUERY`. Para usar o modo `LOAD_AND_QUERY`, é necessário especificar as propriedades de execução `request_spec`, bem como o canal de entrada `examples` na definição do componente. + +```python +infra_validator = InfraValidator( + model=trainer.outputs['model'], + # This is the source for the data that will be used to build a request. + examples=example_gen.outputs['examples'], + serving_spec=tfx.proto.ServingSpec( + # Depending on what kind of model server you're using, RequestSpec + # should specify the compatible one. + tensorflow_serving=tfx.proto.TensorFlowServing(tags=['latest']), + local_docker=tfx.proto.LocalDockerConfig(), + ), + request_spec=tfx.proto.RequestSpec( + # InfraValidator will look at how "classification" signature is defined + # in the model, and automatically convert some samples from `examples` + # artifact to prediction RPC requests. + tensorflow_serving=tfx.proto.TensorFlowServingRequestSpec( + signature_names=['classification'] + ), + num_examples=10 # How many requests to make. + ) +) +``` + +### Produzindo um SavedModel com warmup (aquecimento) + +(Da versão 0.30.0) + +Já que o InfraValidator valida o modelo com solicitações reais, ele pode facilmente reutilizar essas solicitações de validação como [solicitações de warmup (aquecimento)](https://www.tensorflow.org/tfx/serving/saved_model_warmup) de um SavedModel. O InfraValidator fornece uma opção (`RequestSpec.make_warmup`) para exportar um SavedModel com warmup. + +```python +infra_validator = InfraValidator( + ..., + request_spec=tfx.proto.RequestSpec(..., make_warmup=True) +) +``` + +Em seguida, o artefato de saída `InfraBlessing` conterá um SavedModel com warmup e também poderá ser enviado pelo [Pusher](pusher.md), assim como o artefato `Model`. + +## Limitações + +O InfraValidator atual ainda não está pronto e tem algumas limitações. + +- Somente o formato de modelo do TensorFlow [SavedModel](/guide/saved_model) pode ser validado. + +- Ao executar o TFX no Kubernetes, o pipeline deve ser executado pelo `KubeflowDagRunner` dentro do Kubeflow Pipelines. O servidor de modelos será iniciado no mesmo cluster Kubernetes e no mesmo namespace que o Kubeflow está usando. + +- O InfraValidator foca principalmente em implantações no [TensorFlow Serving](serving.md) e, embora ainda seja útil, é menos exato para implantações no [TensorFlow Lite](/lite) e [TensorFlow.js](/js) ou em outros frameworks de inferência. + +- Há suporte limitado no modo `LOAD_AND_QUERY` para a assinatura do método [Predict](/versions/r1.15/api_docs/python/tf/saved_model/predict_signature_def) (que é o único método exportável no TensorFlow 2). O InfraValidator requer que a assinatura do Predict consuma um[`tf.Example`](/tutorials/load_data/tfrecord#tfexample) serializado como a única entrada. + + ```python + @tf.function + def parse_and_run(serialized_example): + features = tf.io.parse_example(serialized_example, FEATURES) + return model(features) + + model.save('path/to/save', signatures={ + # This exports "Predict" method signature under name "serving_default". + 'serving_default': parse_and_run.get_concrete_function( + tf.TensorSpec(shape=[None], dtype=tf.string, name='examples')) + }) + ``` + + - Veja o exemplo de código do [Penguin](https://github.com/tensorflow/tfx/blob/master/tfx/examples/penguin/penguin_pipeline_local_infraval.py) para ver como essa assinatura interage com outros componentes no TFX. diff --git a/site/pt-br/tfx/guide/keras.md b/site/pt-br/tfx/guide/keras.md new file mode 100644 index 0000000000..2acabd0e56 --- /dev/null +++ b/site/pt-br/tfx/guide/keras.md @@ -0,0 +1,239 @@ +# TensorFlow 2.x no TFX + +O [TensorFlow 2.0 foi lançado em 2019](https://blog.tensorflow.org/2019/09/tensorflow-20-is-now-available.html), com [forte integração com o Keras](https://www.tensorflow.org/guide/keras/overview), [execução eager](https://www.tensorflow.org/guide/eager) por padrão e [execução de funções no estilo Python](https://www.tensorflow.org/guide/function), entre outros [novos recursos e melhorias](https://www.tensorflow.org/guide/effective_tf2#a_brief_summary_of_major_changes). + +Este guia fornece uma visão geral técnica abrangente do TF 2.x no TFX. + +## Qual versão usar? + +O TFX é compatível com o TensorFlow 2.x, e as APIs de alto nível que existiam no TensorFlow 1.x (principalmente Estimators) continuam funcionando. + +### Inicie novos projetos no TensorFlow 2.x + +Já que o TensorFlow 2.x mantém os recursos de alto nível do TensorFlow 1.x, não há vantagem em usar a versão mais antiga em novos projetos, mesmo que você não planeje usar os novos recursos. + +Portanto, se você estiver iniciando um novo projeto TFX, recomendamos usar o TensorFlow 2.x. Talvez você queira atualizar seu código posteriormente, à medida que o suporte completo para Keras e outros novos recursos estiver disponível, e o escopo das alterações será muito menor se você começar logo com o TensorFlow 2.x, em vez de tentar atualizar do TensorFlow 1.x em o futuro. + +### Convertendo projetos existentes para o TensorFlow 2.x + +O código escrito para o TensorFlow 1.x é amplamente compatível com o TensorFlow 2.x e continuará funcionando no TFX. + +No entanto, se quiser aproveitar as melhorias e os novos recursos à medida que forem disponibilizados no TF 2.x, você pode seguir as [instruções para migrar para o TF 2.x](https://www.tensorflow.org/guide/migrate). + +## Estimator + +A API Estimator foi mantida no TensorFlow 2.x, mas não é o foco de novos recursos e desenvolvimento. O código escrito no TensorFlow 1.x ou 2.x usando Estimators continuará funcionando conforme esperado no TFX. + +Aqui está um exemplo de TFX ponta a ponta usando o Estimator puro: [Exemplo do táxi (Estimator)](https://github.com/tensorflow/tfx/blob/r0.21/tfx/examples/chicago_taxi_pipeline/taxi_utils.py) + +## Keras com `model_to_estimator` + +Os modelos Keras podem ser agrupados com a função `tf.keras.estimator.model_to_estimator`, que permite que funcionem como se fossem Estimators. Para usar: + +1. Construa um modelo Keras. +2. Passe o modelo compilado para `model_to_estimator`. +3. Use o resultado de `model_to_estimator` no Trainer, da mesma forma que você normalmente usaria um Estimator. + +```py +# Build a Keras model. +def _keras_model_builder(): + """Creates a Keras model.""" + ... + + model = tf.keras.Model(inputs=inputs, outputs=output) + model.compile() + + return model + + +# Write a typical trainer function +def trainer_fn(trainer_fn_args, schema): + """Build the estimator, using model_to_estimator.""" + ... + + # Model to estimator + estimator = tf.keras.estimator.model_to_estimator( + keras_model=_keras_model_builder(), config=run_config) + + return { + 'estimator': estimator, + ... + } +``` + +Além do arquivo do módulo do usuário do Trainer, o restante do pipeline permanece inalterado. + +## Keras nativo (ou seja, Keras sem `model_to_estimator`) + +Observação: O suporte completo para todos os recursos do Keras está em andamento; na maioria dos casos, o Keras no TFX funcionará conforme o esperado. Ainda não funciona com Sparse Features para FeatureColumns. + +### Exemplos e Colab + +Aqui estão vários exemplos com Keras nativo: + +- [Penguin](https://github.com/tensorflow/tfx/blob/master/tfx/examples/penguin/penguin_pipeline_local.py) ([arquivo de módulo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/penguin/penguin_utils_keras.py)): exemplo 'Hello world' completo. +- [MNIST](https://github.com/tensorflow/tfx/blob/master/tfx/examples/mnist/mnist_pipeline_native_keras.py) ([arquivo de módulo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/mnist/mnist_utils_native_keras.py)): exemplo com Image e TFLite completo. +- [Taxi](https://github.com/tensorflow/tfx/blob/master/tfx/examples/chicago_taxi_pipeline/taxi_pipeline_native_keras.py) ([arquivo de módulo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/chicago_taxi_pipeline/taxi_utils_native_keras.py)): exemplo completo com uso de Transform. + +Também temos um [Keras Colab](https://www.tensorflow.org/tfx/tutorials/tfx/components_keras) por componente. + +### Componentes TFX + +As seguintes seções explicam como os componentes TFX relacionados oferecem suporte ao Keras nativo. + +#### Transform + +Atualmente, o Transform tem suporte experimental para modelos Keras. + +O próprio componente Transform pode ser usado no Keras nativo sem alterações. A definição `preprocessing_fn` permanece a mesma, usando ops do [TensorFlow](https://www.tensorflow.org/api_docs/python/tf) e [tf.Transform](https://www.tensorflow.org/tfx/transform/api_docs/python/tft). + +A função serving e a função eval foram alteradas para Keras nativo. Os detalhes serão discutidos nas seções a seguir do Trainer e do Evaluator. + +Observação: As transformações dentro de `preprocessing_fn` não podem ser aplicadas à característica de rótulo para treinamento ou avaliação. + +#### Trainer + +Para configurar o Keras nativo, o `GenericExecutor` precisa ser definido para o componente Trainer para substituir o executor padrão baseado no Estimator. Para mais detalhes, clique [aqui](trainer.md#configuring-the-trainer-component-to-use-the-genericexecutor). + +##### Arquivo Keras Module com Transform + +O arquivo do módulo de treinamento deve conter um `run_fn` que será chamado pelo `GenericExecutor`. Um `run_fn` típico do Keras ficaria assim: + +```python +def run_fn(fn_args: TrainerFnArgs): + """Train the model based on given args. + + Args: + fn_args: Holds args used to train the model as name/value pairs. + """ + tf_transform_output = tft.TFTransformOutput(fn_args.transform_output) + + # Train and eval files contains transformed examples. + # _input_fn read dataset based on transformed schema from tft. + train_dataset = _input_fn(fn_args.train_files, fn_args.data_accessor, + tf_transform_output.transformed_metadata.schema) + eval_dataset = _input_fn(fn_args.eval_files, fn_args.data_accessor, + tf_transform_output.transformed_metadata.schema) + + model = _build_keras_model() + + model.fit( + train_dataset, + steps_per_epoch=fn_args.train_steps, + validation_data=eval_dataset, + validation_steps=fn_args.eval_steps) + + signatures = { + 'serving_default': + _get_serve_tf_examples_fn(model, + tf_transform_output).get_concrete_function( + tf.TensorSpec( + shape=[None], + dtype=tf.string, + name='examples')), + } + model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures) +``` + +No `run_fn` acima, uma assinatura de serviço é necessária ao exportar o modelo treinado para que o modelo possa obter exemplos brutos para previsão. Uma função de serviço típica seria assim: + +```python +def _get_serve_tf_examples_fn(model, tf_transform_output): + """Returns a function that parses a serialized tf.Example.""" + + # the layer is added as an attribute to the model in order to make sure that + # the model assets are handled correctly when exporting. + model.tft_layer = tf_transform_output.transform_features_layer() + + @tf.function + def serve_tf_examples_fn(serialized_tf_examples): + """Returns the output to be used in the serving signature.""" + feature_spec = tf_transform_output.raw_feature_spec() + feature_spec.pop(_LABEL_KEY) + parsed_features = tf.io.parse_example(serialized_tf_examples, feature_spec) + + transformed_features = model.tft_layer(parsed_features) + + return model(transformed_features) + + return serve_tf_examples_fn +``` + +Na função de serviço acima, as transformações tf.Transform precisam ser aplicadas aos dados brutos para inferência, usando a camada [`tft.TransformFeaturesLayer`](https://www.tensorflow.org/tfx/transform/api_docs/python/tft/TransformFeaturesLayer). O `_serving_input_receiver_fn` anterior que era necessário para Estimators não será mais necessário com Keras. + +##### Arquivo Keras Module sem Transform + +Isto é semelhante ao arquivo do módulo mostrado acima, mas sem as transformações: + +```python +def _get_serve_tf_examples_fn(model, schema): + + @tf.function + def serve_tf_examples_fn(serialized_tf_examples): + feature_spec = _get_raw_feature_spec(schema) + feature_spec.pop(_LABEL_KEY) + parsed_features = tf.io.parse_example(serialized_tf_examples, feature_spec) + return model(parsed_features) + + return serve_tf_examples_fn + + +def run_fn(fn_args: TrainerFnArgs): + schema = io_utils.parse_pbtxt_file(fn_args.schema_file, schema_pb2.Schema()) + + # Train and eval files contains raw examples. + # _input_fn reads the dataset based on raw data schema. + train_dataset = _input_fn(fn_args.train_files, fn_args.data_accessor, schema) + eval_dataset = _input_fn(fn_args.eval_files, fn_args.data_accessor, schema) + + model = _build_keras_model() + + model.fit( + train_dataset, + steps_per_epoch=fn_args.train_steps, + validation_data=eval_dataset, + validation_steps=fn_args.eval_steps) + + signatures = { + 'serving_default': + _get_serve_tf_examples_fn(model, schema).get_concrete_function( + tf.TensorSpec(shape=[None], dtype=tf.string, name='examples')), + } + model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures) +``` + +##### [tf.distribute.Strategy](https://www.tensorflow.org/guide/distributed_training) + +No momento, o TFX oferece suporte apenas a estratégias de worker único (por exemplo, [MirroredStrategy](https://www.tensorflow.org/api_docs/python/tf/distribute/MirroredStrategy), [OneDeviceStrategy](https://www.tensorflow.org/api_docs/python/tf/distribute/OneDeviceStrategy)). + +Para usar uma estratégia de distribuição, crie um tf.distribute.Strategy apropriado e mova a criação e compilação do modelo Keras dentro de um escopo de estratégia. + +Por exemplo, substitua `model = _build_keras_model()` acima por: + +```python + mirrored_strategy = tf.distribute.MirroredStrategy() + with mirrored_strategy.scope(): + model = _build_keras_model() + + # Rest of the code can be unchanged. + model.fit(...) +``` + +Para verificar o dispositivo (CPU/GPU) usado por `MirroredStrategy`, habilite o log do TensorFlow para o nível info: + +```python +import logging +logging.getLogger("tensorflow").setLevel(logging.INFO) +``` + +e você deverá ver `Using MirroredStrategy with devices (...)` no log. + +Observação: A variável de ambiente `TF_FORCE_GPU_ALLOW_GROWTH=true` pode ser necessária para um problema de falta de memória da GPU. Para mais detalhes, veja o [Guia da GPU Tensorflow](https://www.tensorflow.org/guide/gpu#limiting_gpu_memory_growth). + +#### Evaluator + +No TFMA v0.2x, ModelValidator e Evaluator foram combinados num único [novo componente Evaluator](https://github.com/tensorflow/community/blob/master/rfcs/20200117-tfx-combining-model-validator-with-evaluator.md). O novo componente Evaluator pode tanto realizar a avaliação de modelo único, como também validar o modelo atual em comparação com modelos anteriores. Com essa alteração, o componente Pusher agora consome um resultado de blessing do Evaluator em vez do ModelValidator. + +O novo Evaluator oferece suporte a modelos Keras e também a modelos Estimator. O `_eval_input_receiver_fn` e o modelo salvo eval que eram exigidos anteriormente não serão mais necessários com Keras, pois o Evaluator agora é baseado no mesmo `SavedModel` usado ao servir. + +[Veja Evaluator para mais informações](evaluator.md). diff --git a/site/pt-br/tfx/guide/kubeflow.md b/site/pt-br/tfx/guide/kubeflow.md new file mode 100644 index 0000000000..87f7ce5966 --- /dev/null +++ b/site/pt-br/tfx/guide/kubeflow.md @@ -0,0 +1,7 @@ +# Orquestração de pipelines TFX + +## Pipelines Kubeflow + +O [Kubeflow](https://www.kubeflow.org/) é uma plataforma de ML de código aberto dedicada a deixar as implantações de workflows de aprendizado de máquina (ML) no Kubernetes mas simples, portáteis e escalonáveis. O [Kubeflow Pipelines](https://www.kubeflow.org/docs/pipelines/pipelines-overview/) é uma parte da plataforma Kubeflow que permite a composição e execução de workflows reproduzíveis no Kubeflow, integrados com experimentação e experiências baseadas em notebooks. Os serviços Kubeflow Pipelines no Kubernetes incluem a hospedagem do TF Metadata, mecanismo de orquestração baseado em container, servidor de notebooks e interface do usuário para ajudar os usuários a desenvolver, executar e gerenciar pipelines de ML complexos em escala. O SDK do Kubeflow Pipelines permite a criação e o compartilhamento de componentes, além da composição programática de pipelines. + +Veja o [exemplo do TFX no Kubeflow Pipelines](https://www.tensorflow.org/tfx/tutorials/tfx/cloud-ai-platform-pipelines) para detalhes sobre como executar o TFX em escala na nuvem do Google. diff --git a/site/pt-br/tfx/guide/local_orchestrator.md b/site/pt-br/tfx/guide/local_orchestrator.md new file mode 100644 index 0000000000..f6b9498768 --- /dev/null +++ b/site/pt-br/tfx/guide/local_orchestrator.md @@ -0,0 +1,7 @@ +# Orquestração de pipelines TFX + +## Orquestrador local + +O Local Orchestrator (orquestrador local) é um orquestrador simples incluído no pacote TFX Python. Ele executa pipelines no ambiente local num único processo. Ele fornece iterações rápidas para desenvolvimento e depuração, mas não é adequado para grandes cargas de trabalho em produção. Use [Vertex Pipelines](/tfx/guide/vertex) ou [Kubeflow Pipelines](/tfx/guide/kubeflow) para casos de uso em produção. + +Experimente os [tutoriais do TFX](/tfx/tutorials/tfx/penguin_simple) executados no Colab para aprender como usar o orquestrador local. diff --git a/site/pt-br/tfx/guide/mlmd.md b/site/pt-br/tfx/guide/mlmd.md new file mode 100644 index 0000000000..c777abb451 --- /dev/null +++ b/site/pt-br/tfx/guide/mlmd.md @@ -0,0 +1,339 @@ +# ML Metadata + +P [ML Metadata (MLMD)](https://github.com/google/ml-metadata) é uma biblioteca para registrar e recuperar metadados associados a workflows de desenvolvedores de ML e cientistas de dados. O MLMD é parte integrante do [TensorFlow Extended (TFX)](https://www.tensorflow.org/tfx), mas foi projetado para que possa ser usado de forma independente. + +Cada execução de um pipeline de ML em produção gera metadados contendo informações sobre os vários componentes do pipeline, suas execuções (por exemplo, execuções de treinamento) e artefatos resultantes (por exemplo, modelos treinados). No caso de erros ou comportamentos inesperados do pipeline, esses metadados podem ser aproveitados para analisar a linhagem dos componentes do pipeline e depurar problemas. Pense nesses metadados como o equivalente ao registro de logs no desenvolvimento de software. + +O MLMD ajuda você a compreender e analisar todas as partes interconectadas do seu pipeline de ML, em vez de analisá-las isoladamente, e pode ajudá-lo a responder perguntas sobre o seu pipeline de ML, como: + +- Em qual dataset o modelo foi treinado? +- Quais foram os hiperparâmetros usados ​​para treinar o modelo? +- Qual execução do pipeline criou o modelo? +- Qual execução de treinamento levou a esse modelo? +- Qual versão do TensorFlow criou este modelo? +- Quando o modelo que falhou foi enviado? + +## Metadata Store + +O MLMD registra os seguintes tipos de metadados em um banco de dados chamado **Metadata Store**. + +1. Metadados sobre os artefatos gerados por meio dos componentes/etapas dos seus pipelines de ML +2. Metadados sobre as execuções desses componentes/etapas +3. Metadados sobre pipelines e informações de linhagem associadas + +O Metadata Store fornece APIs para registrar e recuperar metadados de e para o back-end de armazenamento. O back-end de armazenamento é conectável e pode ser estendido. O MLMD fornece implementações prontas para uso de referência para o SQLite (que pode ser usado via memória ou disco) e MySQL. + +Este gráfico mostra uma visão geral resumida dos vários componentes que fazem parte do MLMD. + +![Visão geral do ML Metadata](images/mlmd_overview.png) + +### Back-ends do Metadata Storage e configuração de conexão + +O objeto `MetadataStore` recebe uma configuração de conexão que corresponde ao backend de armazenamento utilizado. + +- O **Fake Database** fornece um banco de dados na memória (usando SQLite) para experimentação rápida e execuções locais. O banco de dados é excluído quando o objeto de armazenamento é destruído. + +```python +import ml_metadata as mlmd +from ml_metadata.metadata_store import metadata_store +from ml_metadata.proto import metadata_store_pb2 + +connection_config = metadata_store_pb2.ConnectionConfig() +connection_config.fake_database.SetInParent() # Sets an empty fake database proto. +store = metadata_store.MetadataStore(connection_config) +``` + +- O **SQLite** lê e grava arquivos do disco. + +```python +connection_config = metadata_store_pb2.ConnectionConfig() +connection_config.sqlite.filename_uri = '...' +connection_config.sqlite.connection_mode = 3 # READWRITE_OPENCREATE +store = metadata_store.MetadataStore(connection_config) +``` + +- O **MySQL** se conecta a um servidor MySQL. + +```python +connection_config = metadata_store_pb2.ConnectionConfig() +connection_config.mysql.host = '...' +connection_config.mysql.port = '...' +connection_config.mysql.database = '...' +connection_config.mysql.user = '...' +connection_config.mysql.password = '...' +store = metadata_store.MetadataStore(connection_config) +``` + +Da mesma forma, ao usar uma instância MySQL com Google CloudSQL ([quickstart](https://cloud.google.com/sql/docs/mysql/quickstart), [connect-overview](https://cloud.google.com/sql/docs/mysql/connect-overview)), também é possível usar a opção SSL, se aplicável. + +```python +connection_config.mysql.ssl_options.key = '...' +connection_config.mysql.ssl_options.cert = '...' +connection_config.mysql.ssl_options.ca = '...' +connection_config.mysql.ssl_options.capath = '...' +connection_config.mysql.ssl_options.cipher = '...' +connection_config.mysql.ssl_options.verify_server_cert = '...' +store = metadata_store.MetadataStore(connection_config) +``` + +## Modelo de dados + +A Metadata Store usa o modelo de dados a seguir para registrar e recuperar metadados do back-end de armazenamento. + +- `ArtifactType` descreve o tipo de artefato e suas propriedades armazenadas no storage de metadados. Você pode registrar esses tipos dinamicamente com o Metadata Store em código ou pode carregá-los no storage a partir de um formato serializado. Depois de registrar um tipo, sua definição fica disponível durante todo o tempo de vida do storage. +- Um `Artifact` descreve uma instância específica de um `ArtifactType` e suas propriedades que são gravadas no Metadata Store. +- Um `ExecutionType` descreve um tipo de componente ou etapa de um workflow e seus parâmetros de runtime. +- Uma `Execution` é um registro da execução de um componente ou de uma etapa de um workflow de ML e dos parâmetros de runtime. Uma execução pode ser considerada uma instância de `ExecutionType`. As execuções são registradas quando você executa um pipeline ou etapa de ML. +- Um `Event` é um registro do relacionamento entre artefatos e execuções. Quando ocorre uma execução, os eventos registram todos os artefatos usados ​​pela execução e todos os artefatos produzidos. Esses registros permitem o rastreamento de linhagem em todo um workflow. Ao observar todos os eventos, o MLMD sabe quais execuções aconteceram e quais artefatos foram criados como resultado. O MLMD pode então voltar a qualquer artefato de qualquer uma das suas entradas anteriores (upstream). +- Um `ContextType` descreve um tipo de grupo conceitual de artefatos e execuções de um workflow e suas propriedades estruturais. Por exemplo: projetos, execuções de pipeline, experimentos, proprietários etc. +- Um `Context` é uma instância de um `ContextType`. Ele captura as informações compartilhadas dentro do grupo. Por exemplo: nome do projeto, ID de commit da changelist, anotações de experimentos, etc. Ele possui um nome exclusivo definido pelo usuário em seu `ContextType`. +- Uma `Attribution` é um registro do relacionamento entre artefatos e contextos. +- Uma `Association` é um registro do relacionamento entre execuções e contextos. + +## Funcionalidade do MLMD + +Rastrear as entradas e saídas de todos os componentes/etapas em um workflow de ML e sua linhagem permite que as plataformas de ML habilitem vários recursos importantes. A lista a seguir fornece uma visão geral não exaustiva de alguns dos principais benefícios. + +- **Listar todos os artefatos de um tipo específico.** Exemplo: todos os modelos que foram treinados. +- **Carregar dois artefatos do mesmo tipo para comparação.** Exemplo: comparar os resultados de dois experimentos. +- **Mostrar um DAG de todas as execuções relacionadas e seus artefatos de entrada e saída de um contexto.** Exemplo: visualizar o workflow de um experimento para depuração e descoberta. +- **Voltar a todos os eventos para ver como um artefato foi criado.** Exemplos: ver quais dados foram inseridos num modelo; aplicar planos de retenção de dados. +- **Identifique todos os artefatos que foram criados usando um determinado artefato.** Exemplos: ver todos os modelos treinados a partir de um dataset específico; marcar modelos com base em dados incorretos. +- **Determinar se uma execução já foi executada nas mesmas entradas antes.** Exemplo: determinar se um componente/etapa já concluiu o mesmo trabalho e se a saída anterior pode apenas ser reutilizada. +- **Registrar e consultar o contexto das execuções do workflow.** Exemplos: rastrear o proprietário e a lista de alterações usados ​​para uma execução de workflows; agrupar a linhagem por experimentos; gerenciar artefatos por projetos. +- **Capacidades de filtragem de nós declarativos em propriedades e nós de vizinhança de 1-hop.** Exemplos: procurar artefatos de um tipo e em algum contexto de pipeline; retornar artefatos digitados onde o valor de uma determinada propriedade está dentro de um intervalo; encontrar execuções anteriores em um contexto com as mesmas entradas. + +Veja o [tutorial do MLMD](https://www.tensorflow.org/tfx/tutorials/mlmd/mlmd_tutorial) para obter um exemplo que mostra como usar a API do MLMD e o metadata store para recuperar informações de linhagem. + +### Integre ML Metadata nos seus workflows de ML + +Se você for um desenvolvedor de plataforma interessado em integrar o MLMD ao seu sistema, use o exemplo de workflow abaixo para usar as APIs do MLMD de baixo nível para rastrear a execução de uma tarefa de treinamento. Você também pode usar APIs Python de nível superior em ambientes de notebook para registrar metadados de experimentos. + +![Exemplo de fluxo do ML Metadata](images/mlmd_overview.png) + +1. Registrar tipos de artefato + +```python +# Create ArtifactTypes, e.g., Data and Model +data_type = metadata_store_pb2.ArtifactType() +data_type.name = "DataSet" +data_type.properties["day"] = metadata_store_pb2.INT +data_type.properties["split"] = metadata_store_pb2.STRING +data_type_id = store.put_artifact_type(data_type) + +model_type = metadata_store_pb2.ArtifactType() +model_type.name = "SavedModel" +model_type.properties["version"] = metadata_store_pb2.INT +model_type.properties["name"] = metadata_store_pb2.STRING +model_type_id = store.put_artifact_type(model_type) + +# Query all registered Artifact types. +artifact_types = store.get_artifact_types() +``` + +1. Registre tipos de execução para todas as etapas do workflow de ML + +```python +# Create an ExecutionType, e.g., Trainer +trainer_type = metadata_store_pb2.ExecutionType() +trainer_type.name = "Trainer" +trainer_type.properties["state"] = metadata_store_pb2.STRING +trainer_type_id = store.put_execution_type(trainer_type) + +# Query a registered Execution type with the returned id +[registered_type] = store.get_execution_types_by_id([trainer_type_id]) +``` + +1. Crie um artefato do ArtifactType DataSet + +```python +# Create an input artifact of type DataSet +data_artifact = metadata_store_pb2.Artifact() +data_artifact.uri = 'path/to/data' +data_artifact.properties["day"].int_value = 1 +data_artifact.properties["split"].string_value = 'train' +data_artifact.type_id = data_type_id +[data_artifact_id] = store.put_artifacts([data_artifact]) + +# Query all registered Artifacts +artifacts = store.get_artifacts() + +# Plus, there are many ways to query the same Artifact +[stored_data_artifact] = store.get_artifacts_by_id([data_artifact_id]) +artifacts_with_uri = store.get_artifacts_by_uri(data_artifact.uri) +artifacts_with_conditions = store.get_artifacts( + list_options=mlmd.ListOptions( + filter_query='uri LIKE "%/data" AND properties.day.int_value > 0')) +``` + +1. Crie uma execução da execução do Trainer + +```python +# Register the Execution of a Trainer run +trainer_run = metadata_store_pb2.Execution() +trainer_run.type_id = trainer_type_id +trainer_run.properties["state"].string_value = "RUNNING" +[run_id] = store.put_executions([trainer_run]) + +# Query all registered Execution +executions = store.get_executions_by_id([run_id]) +# Similarly, the same execution can be queried with conditions. +executions_with_conditions = store.get_executions( + list_options = mlmd.ListOptions( + filter_query='type = "Trainer" AND properties.state.string_value IS NOT NULL')) +``` + +1. Defina o evento de entrada e leia os dados + +```python +# Define the input event +input_event = metadata_store_pb2.Event() +input_event.artifact_id = data_artifact_id +input_event.execution_id = run_id +input_event.type = metadata_store_pb2.Event.DECLARED_INPUT + +# Record the input event in the metadata store +store.put_events([input_event]) +``` + +1. Declare o artefato de saída + +```python +# Declare the output artifact of type SavedModel +model_artifact = metadata_store_pb2.Artifact() +model_artifact.uri = 'path/to/model/file' +model_artifact.properties["version"].int_value = 1 +model_artifact.properties["name"].string_value = 'MNIST-v1' +model_artifact.type_id = model_type_id +[model_artifact_id] = store.put_artifacts([model_artifact]) +``` + +1. Grave o evento de saída + +```python +# Declare the output event +output_event = metadata_store_pb2.Event() +output_event.artifact_id = model_artifact_id +output_event.execution_id = run_id +output_event.type = metadata_store_pb2.Event.DECLARED_OUTPUT + +# Submit output event to the Metadata Store +store.put_events([output_event]) +``` + +1. Marque a execução como concluída + +```python +trainer_run.id = run_id +trainer_run.properties["state"].string_value = "COMPLETED" +store.put_executions([trainer_run]) +``` + +1. Agrupe artefatos e execuções num contexto usando artefatos de atribuições e asserções + +```python +# Create a ContextType, e.g., Experiment with a note property +experiment_type = metadata_store_pb2.ContextType() +experiment_type.name = "Experiment" +experiment_type.properties["note"] = metadata_store_pb2.STRING +experiment_type_id = store.put_context_type(experiment_type) + +# Group the model and the trainer run to an experiment. +my_experiment = metadata_store_pb2.Context() +my_experiment.type_id = experiment_type_id +# Give the experiment a name +my_experiment.name = "exp1" +my_experiment.properties["note"].string_value = "My first experiment." +[experiment_id] = store.put_contexts([my_experiment]) + +attribution = metadata_store_pb2.Attribution() +attribution.artifact_id = model_artifact_id +attribution.context_id = experiment_id + +association = metadata_store_pb2.Association() +association.execution_id = run_id +association.context_id = experiment_id + +store.put_attributions_and_associations([attribution], [association]) + +# Query the Artifacts and Executions that are linked to the Context. +experiment_artifacts = store.get_artifacts_by_context(experiment_id) +experiment_executions = store.get_executions_by_context(experiment_id) + +# You can also use neighborhood queries to fetch these artifacts and executions +# with conditions. +experiment_artifacts_with_conditions = store.get_artifacts( + list_options = mlmd.ListOptions( + filter_query=('contexts_a.type = "Experiment" AND contexts_a.name = "exp1"'))) +experiment_executions_with_conditions = store.get_executions( + list_options = mlmd.ListOptions( + filter_query=('contexts_a.id = {}'.format(experiment_id)))) +``` + +## Usando MLMD com um servidor gRPC remoto + +Você pode usar MLMD com servidores gRPC remotos conforme mostrado abaixo: + +- Inicie um servidor + +```bash +bazel run -c opt --define grpc_no_ares=true //ml_metadata/metadata_store:metadata_store_server +``` + +Por padrão, o servidor usa um banco de dados falso na memória por solicitação e não persiste os metadados nas chamadas. Ele também pode ser configurado com MLMD `MetadataStoreServerConfig` para usar arquivos SQLite ou instâncias MySQL. A configuração pode ser armazenada num arquivo de texto protobuf e passada para o binário com `--metadata_store_server_config_file=path_to_the_config_file`. + +Um exemplo de arquivo `MetadataStoreServerConfig` em formato de texto protobuf: + +```textpb +connection_config { + sqlite { + filename_uri: '/tmp/test_db' + connection_mode: READWRITE_OPENCREATE + } +} +``` + +- Crie o stub do cliente e use-o em Python + +```python +from grpc import insecure_channel +from ml_metadata.proto import metadata_store_pb2 +from ml_metadata.proto import metadata_store_service_pb2 +from ml_metadata.proto import metadata_store_service_pb2_grpc + +channel = insecure_channel('localhost:8080') +stub = metadata_store_service_pb2_grpc.MetadataStoreServiceStub(channel) +``` + +- Use MLMD com chamadas RPC + +```python +# Create ArtifactTypes, e.g., Data and Model +data_type = metadata_store_pb2.ArtifactType() +data_type.name = "DataSet" +data_type.properties["day"] = metadata_store_pb2.INT +data_type.properties["split"] = metadata_store_pb2.STRING + +request = metadata_store_service_pb2.PutArtifactTypeRequest() +request.all_fields_match = True +request.artifact_type.CopyFrom(data_type) +stub.PutArtifactType(request) + +model_type = metadata_store_pb2.ArtifactType() +model_type.name = "SavedModel" +model_type.properties["version"] = metadata_store_pb2.INT +model_type.properties["name"] = metadata_store_pb2.STRING + +request.artifact_type.CopyFrom(model_type) +stub.PutArtifactType(request) +``` + +## Recursos + +A biblioteca MLMD possui uma API de alto nível que você pode usar prontamente com seus pipelines de ML. Consulte a [documentação da API MLMD](https://www.tensorflow.org/tfx/ml_metadata/api_docs/python/mlmd) para mais detalhes. + +Confira [Filtragem de nós declarativos no MLMD](https://github.com/google/ml-metadata/blob/v1.2.0/ml_metadata/proto/metadata_store.proto#L708-L786) para aprender como usar os recursos de filtragem de nós declarativos no MLMD em propriedades e nós vizinhos 1-hop. + +Confira também o [tutorial do MLMD](https://www.tensorflow.org/tfx/tutorials/mlmd/mlmd_tutorial) para aprender como usar o MLMD para rastrear a linhagem dos componentes do pipeline. + +MLMD provides utilities to handle schema and data migrations across releases. See the MLMD [Guide](https://github.com/google/ml-metadata/blob/master/g3doc/get_started.md#upgrade-the-mlmd-library) for more details. diff --git a/site/pt-br/tfx/guide/modelval.md b/site/pt-br/tfx/guide/modelval.md new file mode 100644 index 0000000000..9208474d62 --- /dev/null +++ b/site/pt-br/tfx/guide/modelval.md @@ -0,0 +1,74 @@ +# O componente ModelValidator TFX Pipeline (descontinuado) + +O ModelValidator era utilizado para verificar se um modelo era bom o suficiente para ser usado em produção. Ainda achamos que essa validação seja útil, mas como o [Evaluator](evaluator.md) de modelos já tem computado todas as métricas que você vai querer validar, decidimos fundir os dois para eliminar a duplicação. + +Embora tenhamos descontinuado o ModelValidator e não recomendemos seu uso, se você precisar manter um componente ModelValidator legado, um exemplo de configuração está mostrado a seguir: + +```python +import tfx +import tensorflow_model_analysis as tfma +from tfx.components.model_validator.component import ModelValidator + +... + +model_validator = ModelValidator( + examples=example_gen.outputs['output_data'], + model=trainer.outputs['model']) +``` + +Para aqueles que gostariam de migrar a configuração para o Evaluator, uma configuração semelhante para o Evaluator seria a seguinte: + +```python +from tfx import components +import tensorflow_model_analysis as tfma + +... + +eval_config = tfma.EvalConfig( + model_specs=[ + # This assumes a serving model with signature 'serving_default'. If + # using estimator based EvalSavedModel, add signature_name: 'eval' and + # remove the label_key. + tfma.ModelSpec(label_key='') + ], + metrics_specs=[ + tfma.MetricsSpec( + # The metrics added here are in addition to those saved with the + # model (assuming either a keras model or EvalSavedModel is used). + # Any metrics added into the saved model (for example using + # model.compile(..., metrics=[...]), etc) will be computed + # automatically. + metrics=[ + tfma.MetricConfig(class_name='ExampleCount'), + tfma.MetricConfig( + class_name='BinaryAccuracy', + threshold=tfma.MetricThreshold( + value_threshold=tfma.GenericValueThreshold( + lower_bound={'value': 0.5}), + change_threshold=tfma.GenericChangeThreshold( + direction=tfma.MetricDirection.HIGHER_IS_BETTER, + absolute={'value': -1e-10}))) + ] + ) + ], + slicing_specs=[ + # An empty slice spec means the overall slice, i.e. the whole dataset. + tfma.SlicingSpec(), + # Data can be sliced along a feature column. In this case, data is + # sliced along feature column trip_start_hour. + tfma.SlicingSpec(feature_keys=['trip_start_hour']) + ]) + +model_resolver = Resolver( + strategy_class=latest_blessed_model_resolver.LatestBlessedModelResolver, + model=Channel(type=Model), + model_blessing=Channel(type=ModelBlessing) +).with_id('latest_blessed_model_resolver') + +model_analyzer = components.Evaluator( + examples=examples_gen.outputs['examples'], + model=trainer.outputs['model'], + baseline_model=model_resolver.outputs['model'], + # Change threshold will be ignored if there is no baseline (first run). + eval_config=eval_config) +``` diff --git a/site/pt-br/tfx/guide/non_tf.md b/site/pt-br/tfx/guide/non_tf.md new file mode 100644 index 0000000000..d05a62f268 --- /dev/null +++ b/site/pt-br/tfx/guide/non_tf.md @@ -0,0 +1,24 @@ +# Usando outros frameworks de ML no TFX + +O TFX como plataforma é neutro em relação a frameworks e pode ser usado com outros frameworks de ML, por exemplo, JAX, scikit-learn. + +Para desenvolvedores de modelo, isto significa que eles não precisam reescrever o código do modelo implementado em outro framework de ML, mas podem reutilizar a maior parte do código de treinamento como está no TFX e se beneficiar de outros recursos do TFX e recursos oferecidos pelo ecossistema do TensorFlow. + +O SDK do pipeline do TFX e a maioria dos módulos do TFX, por exemplo, orquestrador do pipeline, não têm nenhuma dependência direta no TensorFlow, mas possui alguns aspectos que são orientados para o TensorFlow, como formatos de dados. Levando em consideração as necessidades de um framework de modelagem específico, um pipeline TFX poderia ser usado para treinar modelos em qualquer outro framework de ML baseado no Python. Isto inclui o Scikit-learn, o XGBoost e o PyTorch, entre outros. Algumas questões a serem consideradas ao usar os componentes padrão do TFX com outros frameworks incluem: + +- O **ExampleGen** gera [tf.train.Example](https://www.tensorflow.org/tutorials/load_data/tfrecord) em arquivos TFRecord. É uma representação genérica para dados de treinamento, e os componentes downstream usam [TFXIO](https://github.com/tensorflow/community/blob/master/rfcs/20191017-tfx-standardized-inputs.md) para lê-los como Arrow/RecordBatch na memória, que pode ser posteriormente convertido em `tf.dataset`, `Tensors` ou outros formatos. Estão sendo considerados formatos de payload/arquivo diferentes de tf.train.Example/TFRecord, mas para os usuários do TFXIO, isto deve ser uma caixa preta. +- O **Transform** pode ser usado para gerar exemplos de treinamento transformados, independentemente do framework usado no treinamento, mas se o formato do modelo não for `saved_model`, os usuários não poderão incorporar o grafo de transformação ao modelo. Neste caso, a previsão do modelo precisa usar características transformadas em vez de características brutas, e os usuários poderão executar a transformação como uma etapa de pré-processamento antes de chamar a previsão do modelo durante o serviço. +- O **O Trainer** suporta o [GenericTraining](https://www.tensorflow.org/tfx/guide/trainer#generic_trainer) para que os usuários possam treinar seus modelos usando qualquer framework de ML. +- Por padrão, o **Evaluator** suporta apenas `saved_model`, mas os usuários podem fornecer uma UDF que gera previsões para a avaliação de modelos. + +O treinamento de um modelo num framework que não se baseia em Python exigirá o isolamento de um componente de treinamento personalizado num container Docker, como parte de um pipeline que esteja sendo executado num ambiente de container, como o Kubernetes. + +## JAX + +O [JAX](https://github.com/google/jax) é Autograd e XLA, combinados para a pesquisa de aprendizado de máquina de alto desempenho. O [Flax](https://github.com/google/flax) é uma biblioteca de redes neurais e ecossistema para o JAX, projetada para oferecer flexibilidade. + +Com o [jax2tf](https://github.com/google/jax/tree/main/jax/experimental/jax2tf), podemos converter modelos JAX/Flax treinados no formato `saved_model`, que pode ser usado tranquilamente no TFX com treinamento genérico e avaliação de modelos. Para mais detalhes, veja este [exemplo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/penguin/penguin_utils_flax_experimental.py). + +## scikit-learn + +O [Scikit-learn](https://scikit-learn.org/stable/) é uma biblioteca de aprendizado de máquina para a linguagem de programação Python. Temos um [exemplo](https://github.com/tensorflow/tfx-addons/tree/main/examples/sklearn_penguins) e2e com treinamento e avaliação customizados em TFX-Addons. diff --git a/site/pt-br/tfx/guide/pusher.md b/site/pt-br/tfx/guide/pusher.md new file mode 100644 index 0000000000..740390f8a3 --- /dev/null +++ b/site/pt-br/tfx/guide/pusher.md @@ -0,0 +1,47 @@ +# O componente do pipeline Pusher TFX + +O componente Pusher é usado para enviar um modelo validado para um [destino de implantação](index.md#deployment_targets) durante o treinamento ou retreinamento do modelo. Antes da implantação, o Pusher depende de uma ou mais autorizações (blessings) de outros componentes de validação para decidir se deve ou não enviar o modelo. + +- O [Evaluator](evaluator) autoriza (blesses) o modelo se o novo modelo treinado for "bom o suficiente" para ser colocado em produção. +- (Opcional, mas recomendado) O [InfraValidator](infra_validator) autoriza o modelo se o modelo puder ser atendido mecanicamente num ambiente de produção. + +Um componente Pusher consome um modelo treinado no formato [SavedModel](/guide/saved_model) e produz o mesmo SavedModel, juntamente com metadados de controle de versão. + +## Usando o componente Pusher + +Um componente de pipeline Pusher normalmente é muito fácil de implantar e requer pouca personalização, já que todo o trabalho é feito pelo componente Pusher TFX. O código típico é assim: + +```python +pusher = Pusher( + model=trainer.outputs['model'], + model_blessing=evaluator.outputs['blessing'], + infra_blessing=infra_validator.outputs['blessing'], + push_destination=tfx.proto.PushDestination( + filesystem=tfx.proto.PushDestination.Filesystem( + base_directory=serving_model_dir) + ) +) +``` + +### Enviando um modelo produzido a partir do InfraValidator. + +(Da versão 0.30.0) + +O InfraValidator também pode produzir o artefato `InfraBlessing` contendo um [modelo com warmup](infra_validator#producing_a_savedmodel_with_warmup), e o Pusher pode enviá-lo como um artefato `Model`. + +```python +infra_validator = InfraValidator( + ..., + # make_warmup=True will produce a model with warmup requests in its + # 'blessing' output. + request_spec=tfx.proto.RequestSpec(..., make_warmup=True) +) + +pusher = Pusher( + # Push model from 'infra_blessing' input. + infra_blessing=infra_validator.outputs['blessing'], + push_destination=tfx.proto.PushDestination(...) +) +``` + +Mais detalhes estão disponíveis na [Referência da API Pusher](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/Pusher). diff --git a/site/pt-br/tfx/guide/schemagen.md b/site/pt-br/tfx/guide/schemagen.md new file mode 100644 index 0000000000..e988e805da --- /dev/null +++ b/site/pt-br/tfx/guide/schemagen.md @@ -0,0 +1,77 @@ +# O componente de pipeline SchemaGen TFX + +Alguns componentes do TFX usam uma descrição dos seus dados de entrada, que é chamada de *esquema* (schema). O esquema é uma instância de [schema.proto](https://github.com/tensorflow/metadata/blob/master/tensorflow_metadata/proto/v0/schema.proto). Ele pode especificar os tipos de dados para valores de características, se uma característica deve estar presente em todos os exemplos, intervalos de valores permitidos e outras propriedades. Um componente de pipeline SchemaGen gerará um esquema automaticamente, inferindo tipos, categorias e intervalos dos dados de treinamento. + +- Consome: estatísticas de um componente StatisticsGen +- Produz: Data schema proto + +Aqui está o trecho de um schema proto: + +```proto +... +feature { + name: "age" + value_count { + min: 1 + max: 1 + } + type: FLOAT + presence { + min_fraction: 1 + min_count: 1 + } +} +feature { + name: "capital-gain" + value_count { + min: 1 + max: 1 + } + type: FLOAT + presence { + min_fraction: 1 + min_count: 1 + } +} +... +``` + +As seguintes bibliotecas TFX usam o esquema: + +- TensorFlow Data Validation +- TensorFlow Transform +- TensorFlow Model Analysis + +Num pipeline TFX típico, o SchemaGen gera um esquema, que é consumido pelos outros componentes do pipeline. No entanto, o esquema gerado automaticamente é o melhor esforço e tenta apenas inferir propriedades básicas dos dados. Espera-se que os desenvolvedores o revisem e modifiquem conforme seja necessário. + +O esquema modificado pode ser trazido de volta ao pipeline usando o componente ImportSchemaGen. O componente SchemaGen para a geração inicial do esquema pode ser removido e todos os componentes downstream podem usar a saída de ImportSchemaGen. Também é recomendado adicionar [ExampleValidator](https://www.tensorflow.org/tfx/guide/exampleval) usando o esquema importado para examinar os dados de treinamento continuamente. + +## SchemaGen e TensorFlow Data Validation + +O SchemaGen faz uso extensivo do [TensorFlow Data Validator](tfdv.md) para inferir um esquema. + +## Usando o componente SchemaGen + +### Para a geração inicial do esquema + +Um componente de pipeline SchemaGen geralmente é muito fácil de implantar e requer pouca personalização. O código típico está mostrado a seguir: + +```python +schema_gen = tfx.components.SchemaGen( + statistics=stats_gen.outputs['statistics']) +``` + +Mais detalhes estão disponíveis na [Referência da API SchemaGen](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/SchemaGen). + +### Para a importação do esquema revisado + +Adicione o componente ImportSchemaGen ao pipeline para trazer a definição de esquema revisada para dentro do pipeline. + +```python +schema_gen = tfx.components.ImportSchemaGen( + schema_file='/some/path/schema.pbtxt') +``` + +O `schema_file` deve ser um caminho completo para o arquivo de texto protobuf. + +Mais detalhes estão disponíveis na [referência da API ImportSchemaGen](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/ImportSchemaGen). diff --git a/site/pt-br/tfx/guide/serving.md b/site/pt-br/tfx/guide/serving.md new file mode 100644 index 0000000000..2468f8b650 --- /dev/null +++ b/site/pt-br/tfx/guide/serving.md @@ -0,0 +1,11 @@ +# Modelos Serving + +## Introdução + +O TensorFlow Serving é um sistema de serviço flexível e de alto desempenho para modelos de machine learning, projetado para ambientes de produção. O TensorFlow Serving facilita a implantação de novos algoritmos e experimentos, mantendo a mesma arquitetura de servidor e APIs. O TensorFlow Serving oferece integração pronta para uso com modelos do TensorFlow, mas pode ser facilmente estendido para servir outros tipos de modelos e dados. + +Documentação de desenvolvimento detalhada sobre o TensorFlow Serving está disponível: + +- [Visão geral da arquitetura](https://www.tensorflow.org/tfx/serving/architecture) +- [API do servidor](https://www.tensorflow.org/tfx/serving/api_docs/cc/) +- [API do cliente REST](https://www.tensorflow.org/tfx/serving/api_rest) diff --git a/site/pt-br/tfx/guide/solutions.md b/site/pt-br/tfx/guide/solutions.md new file mode 100644 index 0000000000..be35938832 --- /dev/null +++ b/site/pt-br/tfx/guide/solutions.md @@ -0,0 +1,41 @@ +# Soluções em nuvem para o TFX + +Procurando insights sobre como o TFX pode ser aplicado para construir uma solução que atenda às suas necessidades? Esses artigos e guias detalhados podem ajudar! + +Observação: estes artigos discutem soluções completas nas quais o TFX é uma parte fundamental, mas não a única. Este é quase sempre o caso em implantações no mundo real. Portanto, implementar você mesmo essas soluções exigirá mais do que apenas TFX. O objetivo principal é fornecer algumas dicas sobre como outras pessoas implementaram soluções que podem atender a requisitos semelhantes aos seus, e não servir como um livro de receitas ou lista de aplicativos aprovados do TFX. + +## Arquitetura de um sistema de aprendizado de máquina para correspondência de itens em tempo quase real + +Use este documento para saber mais sobre a arquitetura de uma solução de aprendizado de máquina (ML - Machine Learning) que aprende e fornece embeddings de itens. Os embeddings podem ajudar você a entender quais itens seus clientes consideram semelhantes, o que permite oferecer sugestões de "itens semelhantes" em tempo real no seu aplicativo. Esta solução mostra como identificar músicas semelhantes num dataset e como usar essas informações para fazer recomendações de músicas. Leia mais + +## Pré-processamento de dados para aprendizado de máquina: opções e recomendações + +Este artigo em duas partes explora o tópico da engenharia de dados e engenharia de características para o aprendizado de máquina (ML). Esta primeira parte discute as práticas recomendadas de pré-processamento de dados num pipeline de aprendizado de máquina no Google Cloud. O artigo foca no uso do TensorFlow e da biblioteca de código aberto TensorFlow Transform (tf.Transform) para preparar dados, treinar o modelo e servir o modelo para previsão. Esta parte destaca os desafios do pré-processamento de dados para aprendizado de máquina e ilustra as opções e cenários para realizar a transformação de dados no Google Cloud de maneira eficaz. Parte 1 Parte 2 + +## Arquitetura para o MLOps usando TFX, Kubeflow Pipelines e Cloud Build + +Este documento descreve a arquitetura geral de um sistema de aprendizado de máquina (ML) usando bibliotecas TensorFlow Extended (TFX). Ele também discute como configurar integração contínua (CI), entrega contínua (CD) e treinamento contínuo (CT) para o sistema de ML usando Cloud Build e Kubeflow Pipelines. Leia mais + +## MLOps: entrega contínua e pipelines de automação em aprendizado de máquina + +Este documento discute técnicas para implementar e automatizar integração contínua (CI), entrega contínua (CD) e treinamento contínuo (CT) para sistemas de aprendizado de máquina (ML). A ciência de dados e o ML estão se tornando recursos essenciais para resolver problemas complexos do mundo real, transformar indústrias e agregar valor em todos os domínios. Leia mais + +## Como configurar um ambiente MLOps no Google Cloud + +Este guia de referência descreve a arquitetura de um ambiente de operações de aprendizado de máquina (MLOps) no Google Cloud. **O guia vem com laboratórios práticos** no GitHub que orientam você no processo de provisionamento e configuração do ambiente descrito aqui. Praticamente todas as indústrias estão adotando o aprendizado de máquina (ML) num ritmo cada vez mais acelerado. Um desafio importante para obter valor do ML é criar maneiras de implantar e operar sistemas de ML de maneira eficaz. Este guia destina-se a engenheiros de aprendizado de máquina (ML - Machine Learning) e DevOps. Leia mais + +## Requisitos principais para uma fundação MLOps + +As organizações orientadas por IA estão usando dados e aprendizado de máquina para resolver seus problemas mais difíceis e já estão colhendo os frutos. + +*“As empresas que absorverem totalmente a IA nos seus workflows de produção de valor até 2025 dominarão a economia mundial de 2030, com um crescimento de fluxo de caixa de +120%”,* de acordo com o McKinsey Global Institute. + +Mas não é fácil agora. Os sistemas de aprendizao de máquina (ML) têm uma capacidade especial de criar dívida técnica se não forem bem geridos. Leia mais + +## Como criar e implantar um cartão modelo (model card) na nuvem com Scikit-Learn + +Modelos de aprendizado de máquina agora estão sendo usados ​​para realizar muitas tarefas desafiadoras. Com seu vasto potencial, os modelos de ML também levantam questões sobre seu uso, construção e limitações. Documentar as respostas a essas perguntas ajuda a trazer clareza e compreensão compartilhada. Para ajudar a alcançar esses objetivos, o Google introduziu cartões modelo (model cards). Leia mais + +## Análise e validação de dados em escala para aprendizado de máquina com o TensorFlow Data Validation + +Este documento discute como usar a biblioteca TensorFlow Data Validation (TFDV) para exploração de dados e análise descritiva durante a experimentação. Cientistas de dados e engenheiros de aprendizado de máquina (ML) podem usar o TFDV num sistema de ML em produção para validar dados usados ​​num pipeline de treinamento contínuo (CT) e para detectar desvios e outliers nos dados recebidos para serviço de previsão. Inclui **laboratórios práticos**. Leia mais diff --git a/site/pt-br/tfx/guide/statsgen.md b/site/pt-br/tfx/guide/statsgen.md new file mode 100644 index 0000000000..ef9d94a745 --- /dev/null +++ b/site/pt-br/tfx/guide/statsgen.md @@ -0,0 +1,51 @@ +# O componente de pipeline StatisticsGen TFX + +O componente de pipeline StatisticsGen TFX gera estatísticas de características sobre dados de treinamento e serviço, que podem ser usados ​​por outros componentes de pipeline. O StatisticsGen usa o Beam para escalar grandes datasets. + +- Consome: datasets criados por um componente de pipeline ExampleGen. +- Produz: estatísticas do dataset. + +## StatisticsGen e TensorFlow Data Validation + +O StatisticsGen faz uso extensivo do [TensorFlow Data Validation](tfdv.md) para gerar estatísticas a partir do seu dataset. + +## Usando o componente StatsGen + +Um componente de pipeline StatisticsGen geralmente é muito fácil de implantar e requer pouca personalização. O código típico está mostrado a seguir: + +```python +compute_eval_stats = StatisticsGen( + examples=example_gen.outputs['examples'], + name='compute-eval-stats' + ) +``` + +## Usando o componente StatsGen com um esquema + +Para a primeira execução de um pipeline, a saída do StatisticsGen será usada para inferir um esquema. No entanto, em execuções subsequentes você poderá ter um esquema curado manualmente que contém informações adicionais sobre seu dataset. Ao fornecer este esquema ao StatisticsGen, o TFDV poderá fornecer estatísticas mais úteis com base nas propriedades declaradas do seu dataset. + +Nesta configuração, você invocará o StatisticsGen com um esquema selecionado que foi importado por um ImporterNode da seguinte forma: + +```python +user_schema_importer = Importer( + source_uri=user_schema_dir, # directory containing only schema text proto + artifact_type=standard_artifacts.Schema).with_id('schema_importer') + +compute_eval_stats = StatisticsGen( + examples=example_gen.outputs['examples'], + schema=user_schema_importer.outputs['result'], + name='compute-eval-stats' + ) +``` + +### Criando um esquema curado + +`Schema`, no TFX, é uma instância de `Schema` proto do TensorFlow Metadata. Ele pode ser escrito em [formato texto](https://googleapis.dev/python/protobuf/latest/google/protobuf/text_format.html) do zero. No entanto, é mais fácil usar o esquema inferido produzido pelo `SchemaGen` como ponto de partida. Depois que o componente `SchemaGen` for executado, o esquema estará localizado na raiz do pipeline no seguinte caminho: + +``` +/SchemaGen/schema//schema.pbtxt +``` + +Onde `` representa um ID exclusivo para esta versão do esquema no MLMD. Este schema proto pode então ser modificado para comunicar informações sobre o dataset que não podem ser inferidas de forma confiável, o que deixará a saída do `StatisticsGen` mais útil e a validação realizada no componente [`ExampleValidator`](https://www.tensorflow.org/tfx/guide/exampleval) mais rigorosa. + +Mais detalhes estão disponíveis na [Referência da API StatisticsGen](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/StatisticsGen). diff --git a/site/pt-br/tfx/guide/tfdv.md b/site/pt-br/tfx/guide/tfdv.md new file mode 100644 index 0000000000..1747634b2b --- /dev/null +++ b/site/pt-br/tfx/guide/tfdv.md @@ -0,0 +1,193 @@ +# TensorFlow Data Validation: verificando e analisando seus dados + +Depois que seus dados estiverem num pipeline do TFX, você poderá usar componentes do TFX para analisá-los e transformá-los. Você pode usar essas ferramentas antes mesmo de treinar um modelo. + +Existem muitos motivos para analisar e transformar seus dados: + +- Para encontrar problemas em seus dados. Problemas comuns incluem: + - Dados ausentes, como características com valores vazios. + - Rótulos tratados como características, para que seu modelo possa dar uma olhada na resposta certa durante o treinamento. + - Características com valores fora do intervalo esperado. + - Anomalias de dados. + - O modelo de transferência aprendida com pré-processamento que não corresponde aos dados de treinamento. +- Para projetar conjuntos de recursos mais eficazes. Por exemplo, você poderá identificar: + - Características especialmente informativas. + - Características redundantes. + - Características que variam tanto em escala que podem retardar o aprendizado. + - Características com pouca ou nenhuma informação preditiva exclusiva. + +As ferramentas do TFX podem ajudar a encontrar bugs em seus dados e ajudar na engenharia de características. + +## TensorFlow Data Validation + +- [Visão geral](#overview) +- [Validação de exemplo baseada em esquema](#schema_based_example_validation) +- [Detecção de desvios (skew) entre treinamento e serviço](#skewdetect) +- [Detecção de deriva (drift) de dados](#drift_detection) + +### Visão geral + +O TensorFlow Data Validation identifica anomalias no treinamento e no fornecimento de dados e poderá criar automaticamente um esquema ao examinar os dados. O componente pode ser configurado para detectar diferentes classes de anomalias nos dados. Pode, por exemplo: + +1. Realizar verificações de validade comparando estatísticas de dados com um esquema que codifica as expectativas do usuário. +2. Detectar desvios entre treinamento/serviço comparando dados do treinamento com dados do fornecimento do serviço. +3. Detectar deriva de dados ao observar uma série de dados. + +Documentamos cada uma dessas funcionalidades de forma independente: + +- [Validação de exemplo baseada em esquema](#schema_based_example_validation) +- [Detecção de desvios (skew) entre treinamento e serviço](#skewdetect) +- [Detecção de deriva (drift) de dados](#drift_detection) + +### Validação de exemplo baseada em esquema + +O TensorFlow Data Validation identifica quaisquer anomalias nos dados de entrada comparando estatísticas de dados com um esquema. O esquema codifica propriedades que se espera que os dados de entrada satisfaçam, como tipos de dados ou valores categóricos, e podem ser modificados ou substituídos pelo usuário. + +O Tensorflow Data Validation normalmente é chamado várias vezes no contexto do pipeline TFX: (i) para cada divisão obtida do ExampleGen, (ii) para todos os dados pré-transformação usados ​​pelo Transform e (iii) para todos os dados pós-transformação gerados pelo Transform. Quando chamado no contexto de Transform (ii-iii), as opções de estatísticas e restrições baseadas em esquema podem ser definidas definindo [`stats_options_updater_fn`](tft.md). Isto é útil ao validar dados não estruturados (por exemplo, características em formato texto). Veja o [user code](https://github.com/tensorflow/tfx/blob/master/tfx/examples/bert/mrpc/bert_mrpc_utils.py), como exemplo. + +#### Recursos avançados de esquemas + +Esta seção aborda configurações mais avançadas para esquemas que podem ser úteis em determinadas situações. + +##### Características esparsas + +A inclusão de características esparsas em Exemplos geralmente introduz várias características que precisam ter a mesma valência para todos os Exemplos. Por exemplo, a característica esparsa: + +

+WeightedCategories = [('CategoryA', 0.3), ('CategoryX', 0.7)]
+
+ +seria codificada usando características separadas para índice e valor: + +

+WeightedCategoriesIndex = ['CategoryA', 'CategoryX']
+WeightedCategoriesValue = [0.3, 0.7]
+
+ +com a restrição de que a valência da característica de índice e valor deve corresponder para todos os exemplos. Esta restrição pode ser explicitada no esquema definindo um sparse_feature: + +

+sparse_feature {
+  name: 'WeightedCategories'
+  index_feature { name: 'WeightedCategoriesIndex' }
+  value_feature { name: 'WeightedCategoriesValue' }
+}
+
+ +A definição de característica esparsa requer uma ou mais características de índice e uma característica de valor que façam referência às características que existem no esquema. Definir explicitamente características esparsas permite que o TFDV verifique se as valências de todas as característica referidas correspondem. + +Alguns casos de uso introduzem restrições de valência similar entre características, mas não necessariamente contém uma característica esparsa. O uso de uma característica esparsa permite eliminar a restrição, mas não é a solução ideal. + +##### Ambientes (environments) de esquema + +Por padrão, as validações assumem que todos os exemplos em um pipeline aderem a um único esquema. Em alguns casos, é necessária a introdução de pequenas variações de esquema, por exemplo, recursos usados ​​como rótulos são necessários durante o treinamento (e devem ser validados), mas faltam durante a o fornecimento do serviço. Ambientes (environments) podem ser usados ​​para expressar tais requisitos, em particular `default_environment()`, `in_environment()`, `not_in_environment()`. + +Por exemplo, suponha que um recurso chamado 'LABEL' seja necessário para treinamento, mas espera-se que esteja ausente no fornecimento do serviço. Isto pode ser expresso por: + +- Definir dois ambientes distintos no esquema: ["SERVING", "TRAINING"] e associar 'LABEL' apenas ao ambiente "TRAINING". +- Associar os dados de treinamento ao ambiente "TRAINING" e os dados de fornecimento do serviço ao ambiente "SERVING". + +##### Geração de esquemas + +O esquema de dados de entrada é especificado como uma instância do TensorFlow [Schema](https://github.com/tensorflow/metadata/blob/master/tensorflow_metadata/proto/v0/schema.proto). + +Em vez de construir um esquema manualmente do zero, um desenvolvedor pode contar com a construção automática de esquemas do TensorFlow Data Validation. Especificamente, o TensorFlow Data Validation constrói automaticamente um esquema inicial com base em estatísticas calculadas sobre dados de treinamento disponíveis no pipeline. Os usuários podem simplesmente revisar esse esquema gerado automaticamente, modificá-lo conforme necessário, registrá-lo num sistema de controle de versão e enviá-lo explicitamente ao pipeline para validação adicional. + +O TFDV inclui `infer_schema()` para gerar um esquema automaticamente. Por exemplo: + +```python +schema = tfdv.infer_schema(statistics=train_stats) +tfdv.display_schema(schema=schema) +``` + +Isto aciona uma geração automática de esquema com base nas seguintes regras: + +- Se um esquema já tiver sido gerado automaticamente, ele será usado como está. + +- Caso contrário, o TensorFlow Data Validation examina as estatísticas de dados disponíveis e calcula um esquema adequado para os dados. + +*Nota: O esquema gerado automaticamente é o de melhor esforço e tenta apenas inferir propriedades básicas dos dados. Espera-se que os usuários o revisem e modifiquem conforme seja necessário.* + +### Detecção de desvios (skew) entre treinamento e serviço + +#### Visão geral + +O TensorFlow Data Validation pode detectar desvios (skew) de distribuição entre o treinamento e o fornecimento (serving) de dados. A distorção de distribuição ocorre quando a distribuição de valores de características para dados de treinamento é significativamente diferente do fornecimento dos dados. Uma das principais causas do desvio na distribuição é o uso de um corpus completamente diferente para treinar a geração de dados para lidar com a falta de dados iniciais no corpus desejado. Outro motivo é um mecanismo de amostragem defeituoso que escolhe apenas uma subamostra dos dados fornecidos para o treinamento. + +##### Cenário de exemplo + +Observação: por exemplo, para compensar uma fatia de dados sub-representada, se uma amostragem tendenciosa for usada sem aumentar o peso dos exemplos com uma amostragem reduzida de forma adequada, haverá um desvio artificial na distribuição de valores de características entre o treinamento e o fornecimento de dados. + +Veja o [Guia de introdução ao TensorFlow Data Validation](https://www.tensorflow.org/tfx/data_validation/get_started#checking_data_skew_and_drift) para mais informações sobre como configurar a detecção de desvios (skew). + +### Detecção de deriva (drift) de dados + +A detecção de deriva é suportada entre intervalos consecutivos de dados (ou seja, entre o intervalo N e o intervalo N+1), como por exemplo, entre diferentes dias de dados de treinamento. Expressamos a deriva em termos de [distância L-infinito](https://en.wikipedia.org/wiki/Chebyshev_distance) para características categóricas e [divergência aproximada de Jensen-Shannon](https://en.wikipedia.org/wiki/Jensen%E2%80%93Shannon_divergence) para características numéricas. Você pode definir a distância limite para receber avisos quando a deriva for maior do que a aceitável. Definir a distância correta é normalmente um processo iterativo que requer conhecimento de domínio e experimentação. + +Veja o [Guia de introdução ao TensorFlow Data Validation](https://www.tensorflow.org/tfx/data_validation/get_started#checking_data_skew_and_drift) para mais informações sobre como configurar a detecção de derivas (drift). + +## Usando visualizações para verificar seus dados + +O TensorFlow Data Validation fornece ferramentas para visualizar a distribuição de valores de características. Ao examinar essas distribuições num notebook Jupyter usando [Facets](https://pair-code.github.io/facets/), você poderá detectar problemas comuns com seus dados. + +![Estatísticas de características](images/feature_stats.png) + +### Identificando distribuições suspeitas + +Você pode identificar bugs comuns nos seus dados usando uma visualização de Facets Overview para procurar distribuições suspeitas de valores de características. + +#### Dados desbalanceados + +Uma característica desbalanceada é aquela para a qual um valor predomina. Características desbalanceadas podem ocorrer naturalmente, mas se uma característica sempre tiver o mesmo valor, você talvez tenha um bug nos seus dados. Para detectar características desbalanceadas numa Facets Overview, escolha "Non-uniformity" no menu suspenso "Sort by". + +As características mais desbalanceadas serão listadas no topo de cada lista de tipo de característica. Por exemplo, a captura de tela a seguir mostra uma característica composta apenas por zeros e uma segunda característica altamente desbalanceada, no topo da lista "Numeric Features": + +![Visualização de dados desbalanceados](images/unbalanced.png) + +#### Dados distribuídos uniformemente + +Uma característica uniformemente distribuída é aquela para a qual todos os valores possíveis aparecem quase com a mesma frequência. Tal como acontece com os dados desbalanceados, esta distribuição pode ocorrer naturalmente, mas também pode ser causada por bugs nos dados. + +Para detectar características distribuídas uniformemente numa Facets Overview, escolha "Non-uniformity" no menu suspenso "Sort by" e marque a caixa de seleção "Reverse order": + +![Histograma de dados uniformes](images/uniform.png) + +Os dados em formato string são representados usando gráficos de barras se houver 20 ou menos valores exclusivos e como um gráfico de distribuição cumulativa se houver mais de 20 valores exclusivos. Portanto, para dados em formato string, distribuições uniformes poderão aparecer como gráficos de barras planas como o mostrado acima ou linhas retas como mostrado abaixo: + +![Gráfico de linhas: distribuição cumulativa de dados uniformes](images/uniform_cumulative.png) + +##### Bugs que podem produzir dados distribuídos uniformemente + +Aqui estão alguns bugs comuns que podem produzir dados distribuídos uniformemente: + +- Usar strings para representar tipos de dados que não são strings, como datas. Por exemplo, você terá muitos valores exclusivos para uma característica de data e hora contendo representações do tipo "2017-03-01-11-45-03". Valores exclusivos serão distribuídos uniformemente. + +- Incluir índices como "número da linha" como características. Aqui, novamente, você terá muitos valores exclusivos. + +#### Dados ausentes + +Para verificar se uma característica está totalmente sem valores: + +1. Escolha "Amount missing/zero" no menu suspenso "Sort by". +2. Marque a caixa de seleção "Reverse order". +3. Observe a coluna "missing" para ver a porcentagem de instâncias com valores ausentes para uma característica. + +Um bug de dados também pode ser a causa de valores de característica incompletos. Por exemplo, você pode esperar que a lista de valores de uma característica sempre tenha três elementos e descobrir depois que às vezes ela possui apenas um. Para verificar valores incompletos ou outros casos em que as listas de valores das características não possuem o número esperado de elementos, faça o seguinte: + +1. Escolha “Value list length” no menu suspenso “Chart to show” à direita. + +2. Observe o gráfico à direita de cada linha de característica. O gráfico mostra o intervalo de comprimentos da lista de valores para a característica. Por exemplo, a linha destacada na captura de tela abaixo mostra uma característica que possui algumas listas de valores de comprimento zero: + +![Facets Overview contendo característica com listas de valores de características de comprimento zero](images/zero_length.png) + +#### Grandes diferenças de escala entre características + +Se suas características variarem muito em escala, o modelo poderá ter dificuldades de aprendizado. Por exemplo, se algumas características variam de 0 a 1 e outras variam de 0 a 1.000.000.000, você tem uma grande diferença de escala. Compare as colunas "max" e "min" entre as características para descobrir escalas que variam muito. + +Considere normalizar os valores das características para reduzir essas variações grandes. + +#### Rótulos inválidos + +Os estimadores do TensorFlow têm restrições quanto ao tipo de dados que aceitam como rótulos. Por exemplo, classificadores binários normalmente funcionam apenas com rótulos {0, 1}. + +Revise os valores dos rótulos no Facets Overview e certifique-se de que estejam em conformidade com os [requisitos dos Estimators](https://github.com/tensorflow/docs/blob/master/site/en/r1/guide/feature_columns.md) . diff --git a/site/pt-br/tfx/guide/tfma.md b/site/pt-br/tfx/guide/tfma.md new file mode 100644 index 0000000000..fb0258bd73 --- /dev/null +++ b/site/pt-br/tfx/guide/tfma.md @@ -0,0 +1,22 @@ +# Melhorando a qualidade do modelo com o TensorFlow Model Analysis + +## Introdução + +À medida em que você ajusta seu modelo durante o desenvolvimento, você precisa verificar se suas alterações estão melhorando seu modelo. Apenas verificar a exatidão pode não ser suficiente. Por exemplo, se você tiver um classificador para um problema no qual 95% de suas instâncias são positivas, você poderá melhorar a exatidão simplesmente prevendo sempre o positivo, mas não terá um classificador muito robusto. + +## Visão geral + +O objetivo do TensorFlow Model Analysis é fornecer um mecanismo para avaliação de modelos no TFX. A TensorFlow Model Analysis permite realizar avaliações de modelo no pipeline do TFX e visualizar métricas e gráficos resultantes num notebook Jupyter. Especificamente, ele pode fornecer: + +- [Métricas](../model_analysis/metrics) computadas sobre todo o dataset de treinamento e validação, bem como avaliações do dia seguinte +- Acompanhamento de métricas ao longo do tempo +- Desempenho de qualidade do modelo em diferentes fatias de características +- [Validação do modelo](../model_analysis/model_validations) para garantir que o modelo mantenha um desempenho consistente + +## Próximos passos + +Veja nosso [tutorial TFMA](../tutorials/model_analysis/tfma_basic). + +Confira nossa página no [github](https://github.com/tensorflow/model-analysis) para detalhes sobre as [métricas e gráficos](../model_analysis/metrics) suportados e [visualizações](../model_analysis/visualizations) de notebook associadas. + +Consulte os guias de [instalação](../model_analysis/install) e [introdução](../model_analysis/get_started) para informações e exemplos sobre como [configurar](../model_analysis/setup) um pipeline independente. Lembre-se de que o TFMA também é usado no componente [Evaluator](evaluator.md) do TFX, portanto, esses recursos também serão úteis para começar no TFX. diff --git a/site/pt-br/tfx/guide/tft.md b/site/pt-br/tfx/guide/tft.md new file mode 100644 index 0000000000..789feffb77 --- /dev/null +++ b/site/pt-br/tfx/guide/tft.md @@ -0,0 +1,8 @@ +# Biblioteca Transform para usuários não-TFX + +A biblioteca Transform está disponível como uma biblioteca independente. + +- [Introdução ao TensorFlow Transform](https://www.tensorflow.org/tfx/transform/get_started) +- [Referência da API Transform do TensorFlow](https://www.tensorflow.org/tfx/transform/api_docs/python/tft) + +A documentação do módulo `tft` é o único módulo relevante para usuários do TFX. O módulo `tft_beam` é relevante apenas ao usar Transform como uma biblioteca independente. Normalmente, um usuário TFX cria uma `preprocessing_fn` e o restante das chamadas da biblioteca Transform são feitas pelo componente Transform. diff --git a/site/pt-br/tfx/guide/train.md b/site/pt-br/tfx/guide/train.md new file mode 100644 index 0000000000..05ed6c258f --- /dev/null +++ b/site/pt-br/tfx/guide/train.md @@ -0,0 +1,27 @@ +# Projetando código de modelagem do TensorFlow para o TFX + +Ao projetar seu código de modelagem do TensorFlow para o TFX, há alguns itens que você deve conhecer, incluindo a escolha de uma API de modelagem. + +- Consome: SavedModel de [Transform](transform.md) e dados de [ExampleGen](examplegen.md) +- Produz: modelo treinado no formato SavedModel + + + +
    +
  • Novos pipelines do TFX devem usar o TensorFlow 2.x com modelos Keras por meio do Generic Trainer.
  • +
  • O suporte total ao TensorFlow 2.X, incluindo suporte aprimorado para tf.distribute, será adicionado de forma incremental nas próximas versões.
  • +
  • Os pipelines anteriores do TFX podem continuar usando o TensorFlow 1.15. Para migrar para o TensorFlow 2.X, veja o guia de migração do TensorFlow.
  • +
+ +Para ficar em dia quando aos lançamentos do TFX, consulte o TFX OSS Roadmap, leia o blog do TFX e assine o boletim informativo do TensorFlow. + + + + +A camada de entrada do seu modelo deve consumir do SavedModel que foi criado por um componente [Transform](transform.md), e as camadas do modelo Transform devem ser incluídas no seu modelo de forma que, quando você exportar seu SavedModel e EvalSavedModel, eles incluam as transformações que foram criadas pelo componente [Transform](transform.md). + +Um típico projeto de modelo do TensorFlow para TFX está mostrado a seguir: + +```python +def _build_estimator(tf_transform_dir, config, hidden_units=None, warm_start_from=None): """Build an estimator for predicting the tipping behavior of taxi riders. Args: tf_transform_dir: directory in which the tf-transform model was written during the preprocessing step. config: tf.contrib.learn.RunConfig defining the runtime environment for the estimator (including model_dir). hidden_units: [int], the layer sizes of the DNN (input layer first) warm_start_from: Optional directory to warm start from. Returns: Resulting DNNLinearCombinedClassifier. """ metadata_dir = os.path.join(tf_transform_dir, transform_fn_io.TRANSFORMED_METADATA_DIR) transformed_metadata = metadata_io.read_metadata(metadata_dir) transformed_feature_spec = transformed_metadata.schema.as_feature_spec() transformed_feature_spec.pop(_transformed_name(_LABEL_KEY)) real_valued_columns = [ tf.feature_column.numeric_column(key, shape=()) for key in _transformed_names(_DENSE_FLOAT_FEATURE_KEYS) ] categorical_columns = [ tf.feature_column.categorical_column_with_identity( key, num_buckets=_VOCAB_SIZE + _OOV_SIZE, default_value=0) for key in _transformed_names(_VOCAB_FEATURE_KEYS) ] categorical_columns += [ tf.feature_column.categorical_column_with_identity( key, num_buckets=_FEATURE_BUCKET_COUNT, default_value=0) for key in _transformed_names(_BUCKET_FEATURE_KEYS) ] categorical_columns += [ tf.feature_column.categorical_column_with_identity( key, num_buckets=num_buckets, default_value=0) for key, num_buckets in zip( _transformed_names(_CATEGORICAL_FEATURE_KEYS), # _MAX_CATEGORICAL_FEATURE_VALUES) ] return tf.estimator.DNNLinearCombinedClassifier( config=config, linear_feature_columns=categorical_columns, dnn_feature_columns=real_valued_columns, dnn_hidden_units=hidden_units or [100, 70, 50, 25], warm_start_from=warm_start_from) +``` diff --git a/site/pt-br/tfx/guide/trainer.md b/site/pt-br/tfx/guide/trainer.md new file mode 100644 index 0000000000..786da5e744 --- /dev/null +++ b/site/pt-br/tfx/guide/trainer.md @@ -0,0 +1,74 @@ +# O componente de pipeline Trainer TFX + +O componente de pipeline Trainer TFX treina um modelo do TensorFlow. + +## Trainer e TensorFlow + +O Trainer faz uso extensivo da API Python [TensorFlow](https://www.tensorflow.org) para treinar modelos. + +Observação: o TFX oferece suporte ao TensorFlow 1.15 e 2.x. + +## Componente + +O Trainer recebe: + +- tf.Examples usados ​​para treinamento e avaliação. +- Um arquivo de módulo fornecido pelo usuário que define a lógica do treinador. +- Definição [protobuf](https://developers.google.com/protocol-buffers) de argumentos de treinamento e avaliação. +- (Opcional) Um esquema de dados criado por um componente de pipeline SchemaGen e opcionalmente alterado pelo desenvolvedor. +- (Opcional) grafo de transformação produzido por um componente Transform em etapa anterior do pipeline. +- (Opcional) modelos pré-treinados usados ​​para cenários como warmstart. +- (Opcional) Hiperparâmetros, que serão passados ​​para a função do módulo do usuário. Detalhes da integração com o Tuner podem ser encontrados [aqui](tuner.md). + +O Trainer produz: pelo menos um modelo para inferência/exibição (normalmente em SavedModelFormat) e opcionalmente outro modelo para avaliação (normalmente um EvalSavedModel). + +Fornecemos suporte para formatos de modelo alternativos, como [TFLite](https://www.tensorflow.org/lite), por meio da [Model Rewriting Library](https://github.com/tensorflow/tfx/blob/master/tfx/components/trainer/rewriting/README.md). Siga o link para a Model Rewriting Library para exemplos de como converter modelos Estimator e Keras. + +## Trainer genérico + +Um Trainer genérico permite que os desenvolvedores usem qualquer API de modelo do TensorFlow com o componente Trainer. Além dos Estimators do TensorFlow, os desenvolvedores podem usar modelos Keras ou loops de treinamento personalizados. Para mais detalhes, veja a [RFC para trainer genérico](https://github.com/tensorflow/community/blob/master/rfcs/20200117-tfx-generic-trainer.md). + +### Configurando o componente Trainer + +O código DSL de pipeline típico para o Trainer genérico é o seguinte: + +```python +from tfx.components import Trainer + +... + +trainer = Trainer( + module_file=module_file, + examples=transform.outputs['transformed_examples'], + transform_graph=transform.outputs['transform_graph'], + train_args=trainer_pb2.TrainArgs(num_steps=10000), + eval_args=trainer_pb2.EvalArgs(num_steps=5000)) +``` + +O Trainer invoca um módulo de treinamento, que é especificado no parâmetro `module_file` (arquivo de módulo). Em vez de `trainer_fn`], um `run_fn` será necessário no arquivo do módulo se `GenericExecutor` for especificado em `custom_executor_spec`. O `trainer_fn` foi o responsável pela criação do modelo. Além disso, `run_fn` também precisa cuidar da parte de treinamento e enviar o modelo treinado para o local desejado fornecido por [FnArgs](https://github.com/tensorflow/tfx/blob/master/tfx/components/trainer/fn_args_utils.py): + +```python +from tfx.components.trainer.fn_args_utils import FnArgs + +def run_fn(fn_args: FnArgs) -> None: + """Build the TF model and train it.""" + model = _build_keras_model() + model.fit(...) + # Save model to fn_args.serving_model_dir. + model.save(fn_args.serving_model_dir, ...) +``` + +Eis um [exemplo de arquivo de módulo](https://github.com/tensorflow/tfx/blob/master/tfx/examples/penguin/penguin_utils_keras.py) com `run_fn`. + +Observe que se o componente Transform não for usado no pipeline, o Trainer pegaria os exemplos diretamente do ExampleGen: + +```python +trainer = Trainer( + module_file=module_file, + examples=example_gen.outputs['examples'], + schema=infer_schema.outputs['schema'], + train_args=trainer_pb2.TrainArgs(num_steps=10000), + eval_args=trainer_pb2.EvalArgs(num_steps=5000)) +``` + +Mais detalhes estão disponíveis na [referência da API Trainer](https://www.tensorflow.org/tfx/api_docs/python/tfx/v1/components/Trainer). diff --git a/site/pt-br/tfx/guide/transform.md b/site/pt-br/tfx/guide/transform.md new file mode 100644 index 0000000000..5ffd8da9fd --- /dev/null +++ b/site/pt-br/tfx/guide/transform.md @@ -0,0 +1,167 @@ +# O componente de pipeline Transform TFX + +O componente de pipeline Transform TFX executa engenharia de recursos em tf.Examples produzidos por um componente [ExampleGen](examplegen.md), usando um esquema de dados criado por um componente [SchemaGen](schemagen.md) e produz um SavedModel, bem como estatísticas sobre dados pré-transformação e pós-transformação. Quando executado, o SavedModel aceitará tf.Examples produzido por um componente ExampleGen e produzirá os dados do recurso transformado. + +- Consome: tf.Examples de um componente ExampleGen e um esquema de dados de um componente SchemaGen. +- Produz: Um SavedModel para um componente Trainer, estatísticas de pré-transformação e pós-transformação. + +## Configurando um componente Transform + +Depois que seu `preprocessing_fn` for escrito, ele precisará ser definido num módulo Python que será fornecido ao componente Transform como entrada. Esse módulo será carregado por Transform e a função chamada `preprocessing_fn` será localizada e usada por Transform para construir o pipeline de pré-processamento. + +``` +transform = Transform( + examples=example_gen.outputs['examples'], + schema=schema_gen.outputs['schema'], + module_file=os.path.abspath(_taxi_transform_module_file)) +``` + +Além disso, você talvez queira fornecer opções para a computação de estatísticas pré-transformação ou pós-transformação baseadas no [TFDV](tfdv.md). Para fazer isso, defina `stats_options_updater_fn` dentro do mesmo módulo. + +## Transform e TensorFlow Transform + +O Transform faz uso extensivo do [TensorFlow Transform](tft.md) para realizar engenharia de recursos no seu dataset. O TensorFlow Transform é uma ótima ferramenta para transformar dados de características antes que sejam enviados para o seu modelo e como parte do processo de treinamento. As transformações de características comuns incluem: + +- **Embedding**: conversão de características esparsas (como os IDs inteiros produzidos por um vocabulário) em características densas, encontrando um mapeamento significativo do espaço de alta dimensão para o espaço de baixa dimensão. Veja [Unidade de Embeddings no Machine-learning Crash Course](https://developers.google.com/machine-learning/crash-course/embedding) para uma introdução aos embeddings. +- **Geração de vocabulário**: conversão de strings ou outras características não numéricas para inteiras, criando um vocabulário que mapeia cada valor exclusivo para um número de identificação. +- **Normalização de valores**: transformando características numéricas para que todos caiam num intervalo semelhante. +- **Bucketização**: conversão de características de valor contínuo para características categóricas, atribuindo valores a intervalos discretos. +- **Enriquecimento de características textuais**: produção de textuais a partir de dados brutos, como tokens, n-gramas, entidades, sentimentos, etc., para enriquecer o conjunto de características. + +O TensorFlow Transform oferece suporte para estas e muitos outros tipos de transformações: + +- Gerar automaticamente um vocabulário a partir de seus dados mais recentes. + +- Realizar transformações arbitrárias nos seus dados antes de enviá-los ao seu modelo. O TensorFlow Transform cria transformações no grafo do TensorFlow para seu modelo para que as mesmas transformações sejam realizadas no momento do treinamento e da inferência. Você pode definir transformações que se referem a propriedades globais dos dados, como o valor máximo de uma característica em todas as instâncias de treinamento. + +Você pode transformar seus dados como quiser antes de executar o TFX. Mas se você fizer isto no TensorFlow Transform, as transformações se tornarão parte do grafo do TensorFlow. Essa abordagem ajuda a evitar distorções de treinamento/serviço. + +As transformações dentro do seu código de modelagem usam FeatureColumns. Usando FeatureColumns, você pode definir bucketizações, transformações em inteiro que usam vocabulários predefinidos ou quaisquer outras transformações que possam ser definidas sem examinar os dados. + +Por outro lado, o TensorFlow Transform foi projetado para transformações que exigem uma passagem completa dos dados para computar valores que não são conhecidos antecipadamente. Por exemplo, a geração de vocabulário requer uma passagem completo por todos os dados. + +Observação: essas computações são implementadas internamente no [Apache Beam](https://beam.apache.org/) . + +Além de computar valores usando o Apache Beam, o TensorFlow Transform permite que os usuários incorporem esses valores em um grafo do TensorFlow, que pode então ser carregado no grafo de treinamento. Por exemplo, ao normalizar características, a função `tft.scale_to_z_score` calculará a média e o desvio padrão de uma característica e também uma representação, num grafo do TensorFlow, da função que subtrai a média e divide pelo desvio padrão. Ao produzir um grafo do TensorFlow, não apenas estatísticas, o TensorFlow Transform simplifica o processo de criação do pipeline de pré-processamento. + +Ja que o pré-processamento é expresso num grafo, ele pode acontecer no servidor e tem garantia de consistência entre o treinamento e o serviço. Essa consistência elimina uma fonte de desvio do treinamento/serviço. + +O TensorFlow Transform permite que os usuários especifiquem seu pipeline de pré-processamento usando código do TensorFlow. Isto significa que um pipeline é construído da mesma maneira que um grafo do TensorFlow. Se apenas as operações do TensorFlow fossem usadas neste grafo, o pipeline seria um mapa puro que aceita lotes de entrada e retorna lotes de saída. Tal pipeline seria equivalente a colocar este grafo dentro de seu `input_fn` ao usar a API `tf.Estimator`. Para especificar operações de passo completo, como quantis de computação, o TensorFlow Transform fornece funções especiais chamadas `analyzers` que aparecem como ops do TensorFlow, mas que na verdade especificam uma computação adiada que será feita pelo Apache Beam e que terá a saída inserida no grafo como um constante. Embora uma op comum do TensorFlow receba um único lote como entrada, execute algumas computações apenas nesse lote e produza um lote, um `analyzer` realizará uma redução global (implementada no Apache Beam) sobre todos os lotes e retornará o resultado. + +Ao combinar operações comuns do TensorFlow e analisadores do TensorFlow Transform, os usuários podem criar pipelines complexos para pré-processar seus dados. Por exemplo, a função `tft.scale_to_z_score` recebe um tensor de entrada e retorna esse tensor normalizado para obter a média `0` e variância `1`. Ele faz isso chamando os analisadores `mean` e `var` nos bastidores, o que irá efetivamente gerar constantes no grafo iguais à média e à variância do tensor de entrada. Em seguida, ele usará operações do TensorFlow para subtrair a média e dividir pelo desvio padrão. + +## A função `preprocessing_fn` do TensorFlow Transform + +O componente TFX Transform simplifica o uso do Transform manipulando as chamadas de API relacionadas à leitura e gravação de dados e gravando a saída SavedModel no disco. Como usuário do TFX, você só precisa definir uma única função chamada `preprocessing_fn`. Em `preprocessing_fn` você define uma série de funções que manipulam o dict de tensores de entrada para produzir o dict de tensores de saída. Você encontrará funções helper como scale_to_0_1 e compute_and_apply_vocabulary na [API do TensorFlow Transform](/tfx/transform/api_docs/python/tft) ou usar funções regulares do TensorFlow conforme mostrado abaixo. + +```python +def preprocessing_fn(inputs): + """tf.transform's callback function for preprocessing inputs. + + Args: + inputs: map from feature keys to raw not-yet-transformed features. + + Returns: + Map from string feature key to transformed feature operations. + """ + outputs = {} + for key in _DENSE_FLOAT_FEATURE_KEYS: + # If sparse make it dense, setting nan's to 0 or '', and apply zscore. + outputs[_transformed_name(key)] = transform.scale_to_z_score( + _fill_in_missing(inputs[key])) + + for key in _VOCAB_FEATURE_KEYS: + # Build a vocabulary for this feature. + outputs[_transformed_name( + key)] = transform.compute_and_apply_vocabulary( + _fill_in_missing(inputs[key]), + top_k=_VOCAB_SIZE, + num_oov_buckets=_OOV_SIZE) + + for key in _BUCKET_FEATURE_KEYS: + outputs[_transformed_name(key)] = transform.bucketize( + _fill_in_missing(inputs[key]), _FEATURE_BUCKET_COUNT) + + for key in _CATEGORICAL_FEATURE_KEYS: + outputs[_transformed_name(key)] = _fill_in_missing(inputs[key]) + + # Was this passenger a big tipper? + taxi_fare = _fill_in_missing(inputs[_FARE_KEY]) + tips = _fill_in_missing(inputs[_LABEL_KEY]) + outputs[_transformed_name(_LABEL_KEY)] = tf.where( + tf.is_nan(taxi_fare), + tf.cast(tf.zeros_like(taxi_fare), tf.int64), + # Test if the tip was > 20% of the fare. + tf.cast( + tf.greater(tips, tf.multiply(taxi_fare, tf.constant(0.2))), tf.int64)) + + return outputs +``` + +### Entendendo as entradas para preprocessing_fn + +O `preprocessing_fn` descreve uma série de operações em tensores (ou seja, objetos `Tensor`, `SparseTensor` ou `RaggedTensor`). Para definir corretamente o `preprocessing_fn` é necessário entender como os dados são representados como tensores. A entrada para `preprocessing_fn` é determinada pelo esquema. Um [proto `Schema`](https://github.com/tensorflow/metadata/blob/master/tensorflow_metadata/proto/v0/schema.proto#L72) será em algum momento convertido numa "feature spec" (especificação de característica), às vezes chamada de "parsing spec" (especificação de processamento) que é usada para o processamento dos dados. Veja mais detalhes sobre a lógica de conversão [aqui](https://github.com/tensorflow/metadata/blob/master/tfx_bsl/docs/schema_interpretation.md). + +## Usando o TensorFlow Transform para lidar com rótulos em formato string + +Normalmente, deseja-se usar o TensorFlow Transform para gerar um vocabulário e aplicar esse vocabulário para converter strings em números inteiros. Ao seguir este workflow, o `input_fn` construído no modelo produzirá como saída a string como inteiro. No entanto, os rótulos são uma exceção, porque para que o modelo seja capaz de mapear os rótulos de saída (inteiros) de volta para strings, o modelo precisa que o `input_fn` gere um rótulo em formato string, junto com uma lista de valores possíveis para o rótulo. Por exemplo, se os rótulos forem `cat` e `dog`, então a saída de `input_fn` deve consistir dessas strings brutas, e as chaves `["cat", "dog"]` precisam ser passadas para o estimador como um parâmetro (veja detalhes abaixo). + +Para lidar com o mapeamento de rótulos em formato string para números inteiros, você deve usar o TensorFlow Transform para gerar um vocabulário. Demonstramos isto no trecho de código abaixo: + +```python +def _preprocessing_fn(inputs): + """Preprocess input features into transformed features.""" + + ... + + + education = inputs[features.RAW_LABEL_KEY] + _ = tft.vocabulary(education, vocab_filename=features.RAW_LABEL_KEY) + + ... +``` + +A função de pré-processamento acima recebe a característica de entrada bruta (que também será retornada como parte da saída da função de pré-processamento) e chama `tft.vocabulary` nela. Isto tem como resultado a geração de um vocabulário para `education` que poderá ser acessado no modelo. + +O exemplo também mostra como transformar um rótulo e depois gerar um vocabulário para o rótulo transformado. Em particular, ele recebe o rótulo bruto `education` e converte todos os rótulos, exceto os 5 principais (por frequência), em `UNKNOWN`, sem converter o rótulo em número inteiro. + +No código do modelo, o classificador deve receber o vocabulário gerado por `tft.vocabulary` como argumento de `label_vocabulary`. Isto é feito primeiro lendo este vocabulário como uma lista através de uma função helper. Isto é mostrado no trecho abaixo. Observe que o código de exemplo usa o rótulo transformado discutido acima, mas aqui mostramos o código para o uso do rótulo bruto. + +```python +def create_estimator(pipeline_inputs, hparams): + + ... + + tf_transform_output = trainer_util.TFTransformOutput( + pipeline_inputs.transform_dir) + + # vocabulary_by_name() returns a Python list. + label_vocabulary = tf_transform_output.vocabulary_by_name( + features.RAW_LABEL_KEY) + + return tf.contrib.learn.DNNLinearCombinedClassifier( + ... + n_classes=len(label_vocab), + label_vocabulary=label_vocab, + ...) +``` + +## Configurando estatísticas de pré-transformação e pós-transformação + +Conforme mencionado acima, o componente Transform chama o TFDV para calcular estatísticas de pré- e pós-transformação. O TFDV recebe como entrada um objeto [StatsOptions](https://github.com/tensorflow/data-validation/blob/master/tensorflow_data_validation/statistics/stats_options.py) opcional. Os usuários podem querer configurar este objeto para permitir certas estatísticas adicionais (por exemplo, estatísticas de NLP) ou para definir limites que sejam validados (por exemplo, frequência mínima/máxima do token). Para isto, defina `stats_options_updater_fn` no arquivo do módulo. + +```python +def stats_options_updater_fn(stats_type, stats_options): + ... + if stats_type == stats_options_util.StatsType.PRE_TRANSFORM: + # Update stats_options to modify pre-transform statistics computation. + # Most constraints are specified in the schema which can be accessed + # via stats_options.schema. + if stats_type == stats_options_util.StatsType.POST_TRANSFORM + # Update stats_options to modify post-transform statistics computation. + # Most constraints are specified in the schema which can be accessed + # via stats_options.schema. + return stats_options +``` + +As estatísticas de pós-transformação geralmente tiram proveito do conhecimento do vocabulário usado para pré-processar uma característica. O nome do vocabulário para mapeamento de caminhos é fornecido ao StatsOptions (e, portanto, ao TFDV) para cada vocabulário gerado pelo TFT. Além disso, mapeamentos para vocabulários criados externamente podem ser adicionados (i) modificando diretamente o dicionário `vocab_paths` em StatsOptions ou (ii) usando `tft.annotate_asset`. diff --git a/site/pt-br/tutorials/images/transfer_learning.ipynb b/site/pt-br/tutorials/images/transfer_learning.ipynb index 623a6d3bd7..ab4c898dcd 100644 --- a/site/pt-br/tutorials/images/transfer_learning.ipynb +++ b/site/pt-br/tutorials/images/transfer_learning.ipynb @@ -16,7 +16,9 @@ "cellView": "form", "id": "d8jyt37T42Vf" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -38,7 +40,9 @@ "cellView": "form", "id": "aPxHdjwW5P2j" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title MIT License\n", "#\n", @@ -79,18 +83,11 @@ }, "source": [ "\n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", "
\n", - " Ver em TensorFlow.org\n", - " \n", - " Executar no Google Colab\n", - " \n", - " Visualizar Código Fonte no GitHub\n", - " \n", - " Baixar notebook\n", - " Ver em TensorFlow.org Executar no Google Colab\n", + "Ver fonte no GitHub Baixar notebook
" ] }, @@ -102,13 +99,13 @@ "source": [ "Neste tutorial, você aprenderá a classificar imagens de cães e gatos usando a transferência de aprendizado de uma rede pré-treinada.\n", "\n", - "Um modelo pré-treinado é uma rede salva que foi treinada anteriormente em um grande conjunto de dados, geralmente em uma tarefa de classificação de imagem em larga escala. Você usa o modelo pré-treinado como está ou usa a transferência de aprendizado para personalizar esse modelo para uma determinada tarefa.\n", + "Um modelo pré-treinado é uma rede salva que foi treinada anteriormente em um grande dataset, geralmente em uma tarefa de classificação de imagem em larga escala. Você usa o modelo pré-treinado como está ou usa a transferência de aprendizado para personalizar esse modelo para uma determinada tarefa.\n", "\n", - "A intuição por trás da transferência de aprendizado para classificação de imagens é que, se um modelo for treinado em um conjunto de dados grande e geral o suficiente, esse modelo servirá efetivamente como um modelo genérico do mundo visual. Você pode aproveitar esses mapas de características aprendidas sem precisar começar do zero treinando um modelo grande em um grande conjunto de dados.\n", + "A intuição por trás da transferência de aprendizado para classificação de imagens é que, se um modelo for treinado em um dataset grande e geral o suficiente, esse modelo servirá efetivamente como um modelo genérico do mundo visual. Você pode aproveitar esses mapas de características aprendidas sem precisar começar do zero treinando um modelo grande em um grande dataset.\n", "\n", "Neste notebook, você tentará duas maneiras de personalizar um modelo pré-treinado:\n", "\n", - "1. Extração de características: use as representações aprendidas por uma rede anterior para extrair características significativas de novas amostras. Você simplesmente adiciona um novo classificador, que será treinado do zero, sobre o modelo pré-treinado, para que você possa adaptar novamente os mapas de características aprendidas anteriormente para o conjunto de dados.\n", + "1. Extração de características: use as representações aprendidas por uma rede anterior para extrair características significativas de novas amostras. Você simplesmente adiciona um novo classificador, que será treinado do zero, sobre o modelo pré-treinado, para que você possa adaptar novamente os mapas de características aprendidas anteriormente para o dataset.\n", "\n", " Você não precisa (re) treinar o modelo inteiro. A rede convolucional de base já contém características que são genericamente úteis para classificar imagens. No entanto, a parte final de classificação do modelo pré-treinado é específica para a tarefa de classificação original e subsequentemente específica para o conjunto de classes em que o modelo foi treinado.\n", "\n", @@ -117,273 +114,327 @@ "Você seguirá o fluxo de trabalho geral de aprendizado de máquina.\n", "\n", "1. Examine e entenda os dados\n", - "1. Crie um pipeline de entrada, neste caso usando o Keras ImageDataGenerator\n", - "1. Componha o modelo\n", - "   * Carregar no modelo básico pré-treinado (e pesos pré-treinados)\n", - "   * Empilhe as camadas de classificação na parte superior\n", - "1. Treine o modelo\n", - "1. Avalie o modelo\n" + "2. Crie um pipeline de entrada, neste caso usando o Keras ImageDataGenerator\n", + "3. Componha o modelo\n", + " - Carregue no modelo base pré-treinado (e pesos pré-treinados)\n", + " - Empilhe as camadas de classificação na parte superior\n", + "4. Treine o modelo\n", + "5. Avalie o modelo\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "iBMcobPHdD8O" + "id": "TqOt6Sv7AsMi" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "from __future__ import absolute_import, division, print_function, unicode_literals\n", - "\n", - "import os\n", - "\n", + "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "\n", - "import matplotlib.pyplot as plt" + "import os\n", + "import tensorflow as tf" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "TqOt6Sv7AsMi" + "id": "v77rlkCKW0IJ" }, - "outputs": [], "source": [ - "try:\n", - " # %tensorflow_version only exists in Colab.\n", - " %tensorflow_version 2.x\n", - "except Exception:\n", - " pass\n", - "import tensorflow as tf\n", - "\n", - "keras = tf.keras" + "## Pré-Processamento dos Dados" ] }, { "cell_type": "markdown", "metadata": { - "id": "v77rlkCKW0IJ" + "id": "0GoKGm1duzgk" }, "source": [ - "## Pré-Processamento dos Dados" + "### Baixe os dados" ] }, { "cell_type": "markdown", "metadata": { - "id": "0GoKGm1duzgk" + "id": "vHP9qMJxt2oz" }, "source": [ - "### Baixar os Dados" + "Neste tutorial, você usará um dataset contendo milhares de imagens de cães e gatos. Baixe e extraia um arquivo zip contendo as imagens e, em seguida, crie um `tf.data.Dataset` para treinamento e validação usando o utilitário `tf.keras.utils.image_dataset_from_directory`. Você pode aprender mais sobre como carregar imagens neste [tutorial](https://www.tensorflow.org/tutorials/load_data/images)." ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "vHP9qMJxt2oz" + "id": "ro4oYaEmxe4r" }, + "outputs": [ + + ], "source": [ - "Use [Conjuntos de dados TensorFlow] (http://tensorflow.org/datasets) para carregar o conjunto de dados de cães e gatos.\n", + "_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'\n", + "path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)\n", + "PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')\n", "\n", - "O pacote `tfds` é a maneira mais fácil de carregar dados pré-definidos. Se você possui seus próprios dados e está interessado em importá-los com o TensorFlow, consulte [carregando dados da imagem] (../load_data/images.ipynb)\n" + "train_dir = os.path.join(PATH, 'train')\n", + "validation_dir = os.path.join(PATH, 'validation')\n", + "\n", + "BATCH_SIZE = 32\n", + "IMG_SIZE = (160, 160)\n", + "\n", + "train_dataset = tf.keras.utils.image_dataset_from_directory(train_dir,\n", + " shuffle=True,\n", + " batch_size=BATCH_SIZE,\n", + " image_size=IMG_SIZE)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "KVh7rDVAuW8Y" + "id": "cAvtLwi7_J__" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "import tensorflow_datasets as tfds\n", - "tfds.disable_progress_bar()" + "validation_dataset = tf.keras.utils.image_dataset_from_directory(validation_dir,\n", + " shuffle=True,\n", + " batch_size=BATCH_SIZE,\n", + " image_size=IMG_SIZE)" ] }, { "cell_type": "markdown", "metadata": { - "id": "Nsoic6bGuwQ-" + "id": "yO1Q2JaW5sIy" }, "source": [ - "O método `tfds.load` baixa e armazena em cache os dados e retorna um objeto `tf.data.Dataset`. Esses objetos fornecem métodos poderosos e eficientes para manipular dados e canalizá-los para o seu modelo.\n", - "\n", - "Como `\"cats_vs_dogs\"` não define padrões para divisões, use o recurso subsplit para dividi-lo em (treinamento, validação, teste) com 80%, 10% e 10% dos dados, respectivamente." + "Mostre as duas primeiras imagens e rótulos do dataset de treinamento:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "ro4oYaEmxe4r" + "id": "K5BeQyKThC_Y" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "SPLIT_WEIGHTS = (8, 1, 1)\n", - "splits = tfds.Split.TRAIN.subsplit(weighted=SPLIT_WEIGHTS)\n", + "class_names = train_dataset.class_names\n", "\n", - "(raw_train, raw_validation, raw_test), metadata = tfds.load(\n", - " 'cats_vs_dogs', split=list(splits),\n", - " with_info=True, as_supervised=True)" + "plt.figure(figsize=(10, 10))\n", + "for images, labels in train_dataset.take(1):\n", + " for i in range(9):\n", + " ax = plt.subplot(3, 3, i + 1)\n", + " plt.imshow(images[i].numpy().astype(\"uint8\"))\n", + " plt.title(class_names[labels[i]])\n", + " plt.axis(\"off\")" ] }, { "cell_type": "markdown", "metadata": { - "id": "o29EfE-p0g5X" + "id": "EZqCX_mpV3Mx" }, "source": [ - "Os objetos `tf.data.Dataset` resultantes contêm pares `(image, label)` onde as imagens têm formato variável e 3 canais, e o rótulo é escalar." + "Como o dataset original não contém um dataset de testes, você criará um. Para fazer isso, determine quantos lotes de dados estão disponíveis no dataset de validação usando `tf.data.experimental.cardinality` e mova 20% deles para um dataset de teste." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "GIys1_zY1S9b" + "id": "uFFIYrTFV9RO" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "print(raw_train)\n", - "print(raw_validation)\n", - "print(raw_test)" + "val_batches = tf.data.experimental.cardinality(validation_dataset)\n", + "test_dataset = validation_dataset.take(val_batches // 5)\n", + "validation_dataset = validation_dataset.skip(val_batches // 5)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "yO1Q2JaW5sIy" + "id": "Q9pFlFWgBKgH" }, + "outputs": [ + + ], "source": [ - "Mostre as duas primeiras imagens e rótulos do conjunto de treinamento:" + "print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))\n", + "print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "K5BeQyKThC_Y" + "id": "MakSrdd--RKg" }, - "outputs": [], "source": [ - "get_label_name = metadata.features['label'].int2str\n", - "\n", - "for image, label in raw_train.take(2):\n", - " plt.figure()\n", - " plt.imshow(image)\n", - " plt.title(get_label_name(label))" + "### Configure o dataset para melhor desempenho" ] }, { "cell_type": "markdown", "metadata": { - "id": "wvidPx6jeFzf" + "id": "22XWC7yjkZu4" }, "source": [ - "### Formate os dados\n", - "\n", - "Use o módulo `tf.image` para formatar as imagens para a tarefa.\n", - "\n", - "Redimensione as imagens para um tamanho de entrada fixo e redimensione os canais de entrada para um intervalo de `[-1,1]`\n", - "\n", - "" + "Use a pré-busca em buffer para carregar imagens do disco sem bloquear a E/S. Para saber mais sobre esse método, consulte o guia [desempenho de dados](https://www.tensorflow.org/guide/data_performance)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "y3PM6GVHcC31" + "id": "p3UUPdm86LNC" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "IMG_SIZE = 160 # Todas as imagens serão ajustadas para 160x160\n", + "AUTOTUNE = tf.data.AUTOTUNE\n", "\n", - "def format_example(image, label):\n", - " image = tf.cast(image, tf.float32)\n", - " image = (image/127.5) - 1\n", - " image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))\n", - " return image, label" + "train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)\n", + "validation_dataset = validation_dataset.prefetch(buffer_size=AUTOTUNE)\n", + "test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)" ] }, { "cell_type": "markdown", "metadata": { - "id": "i2MRh_AeBtOM" + "id": "MYfcVwYLiR98" }, "source": [ - "Aplique esta função a cada item no conjunto de dados usando o método map:" + "### Use ampliação de dados" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bDWc5Oad1daX" + }, + "source": [ + "Quando você não tem um grande dataset de imagens, é uma boa prática introduzir artificialmente a diversidade de amostras aplicando transformações aleatórias, mas realistas, às imagens de treinamento, como rotação e inversão horizontal. Isto ajuda a expor o modelo a diferentes aspectos dos dados de treinamento e a reduzir o [overfitting](https://www.tensorflow.org/tutorials/keras/overfit_and_underfit). Você pode aprender mais sobre ampliação de dados neste [tutorial](https://www.tensorflow.org/tutorials/images/data_augmentation)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "SFZ6ZW7KSXP9" + "id": "3P99QiMGit1A" + }, + "outputs": [ + + ], + "source": [ + "data_augmentation = tf.keras.Sequential([\n", + " tf.keras.layers.RandomFlip('horizontal'),\n", + " tf.keras.layers.RandomRotation(0.2),\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s9SlcbhrarOO" }, - "outputs": [], "source": [ - "train = raw_train.map(format_example)\n", - "validation = raw_validation.map(format_example)\n", - "test = raw_test.map(format_example)" + "Observação: estas camadas ficam ativas somente durante o treinamento, quando você faz uma chamada a `Model.fit`. Elas ficam inativas quando o modelo é usado no modo de inferência em `Model.evaluate`, `Model.predict` ou `Model.call`." ] }, { "cell_type": "markdown", "metadata": { - "id": "E5ifgXDuBfOC" + "id": "9mD3rE2Lm7-d" }, "source": [ - "Agora embaralhe e agrupe os dados." + "Vamos aplicar essas camadas repetidamente na mesma imagem e ver o resultado." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "Yic-I66m6Isv" + "id": "aQullOUHkm67" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "BATCH_SIZE = 32\n", - "SHUFFLE_BUFFER_SIZE = 1000" + "for image, _ in train_dataset.take(1):\n", + " plt.figure(figsize=(10, 10))\n", + " first_image = image[0]\n", + " for i in range(9):\n", + " ax = plt.subplot(3, 3, i + 1)\n", + " augmented_image = data_augmentation(tf.expand_dims(first_image, 0))\n", + " plt.imshow(augmented_image[0] / 255)\n", + " plt.axis('off')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bAywKtuVn8uK" + }, + "source": [ + "### Redimensione valores de pixel\n", + "\n", + "Em alguns instantes, você fará o download do `tf.keras.applications.MobileNetV2` para usar como modelo básico. Este modelo espera valores de pixel em `[-1, 1]`, mas neste ponto, os valores de pixel em suas imagens estão em `[0, 255]`. Para redimensioná-las, use o método de pré-processamento incluído no modelo." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "p3UUPdm86LNC" + "id": "cO0HM9JAQUFq" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "train_batches = train.shuffle(SHUFFLE_BUFFER_SIZE).batch(BATCH_SIZE)\n", - "validation_batches = validation.batch(BATCH_SIZE)\n", - "test_batches = test.batch(BATCH_SIZE)" + "preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input" ] }, { "cell_type": "markdown", "metadata": { - "id": "02rJpcFtChP0" + "id": "xnr81qRMzcs5" }, "source": [ - "Inspecione um lote de dados:" + "Observação: como alternativa, você pode redimensionar os valores de pixel de `[0, 255]` para `[-1, 1]` usando `tf.keras.layers.Rescaling`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "iknFo3ELBVho" + "id": "R2NyJn4KQMux" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "for image_batch, label_batch in train_batches.take(1):\n", - " pass\n", - "\n", - "image_batch.shape" + "rescale = tf.keras.layers.Rescaling(1./127.5, offset=-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wz7qgImhTxw4" + }, + "source": [ + "Observação: Se estiver usando outro `tf.keras.applications`, certifique-se de verificar o documento da API para determinar se eles esperam pixels em `[-1, 1]` ou `[0, 1]`, ou use a função `preprocess_input` incluída." ] }, { @@ -393,7 +444,8 @@ }, "source": [ "## Crie o modelo base a partir das ConvNets pré-treinadas\n", - "Você criará o modelo base a partir do modelo **MobileNet V2** desenvolvido no Google. Isso é pré-treinado no conjunto de dados ImageNet, um grande conjunto de dados composto por 1,4 milhões de imagens e 1000 classes. O ImageNet é um conjunto de dados de treinamento de pesquisa com uma ampla variedade de categorias, como `jaca` e `seringa`. Essa base de conhecimento nos ajudará a classificar cães e gatos de nosso conjunto de dados específico.\n", + "\n", + "Você criará o modelo base a partir do modelo **MobileNet V2** desenvolvido no Google. Isso é pré-treinado no dataset ImageNet, um grande dataset composto por 1,4 milhões de imagens e 1000 classes. O ImageNet é um dataset de treinamento de pesquisa com uma ampla variedade de categorias, como `jaca` e `seringa`. Essa base de conhecimento nos ajudará a classificar cães e gatos de nosso dataset específico.\n", "\n", "Primeiro, você precisa escolher qual camada do MobileNet V2 usará para extração de características. A última camada de classificação (na parte superior, como a maioria dos diagramas dos modelos de aprendizado de máquina vai de baixo para cima) não é muito útil. Em vez disso, você seguirá a prática comum de depender da última camada antes da operação de nivelamento. Essa camada é chamada de \"camada de gargalo\". Os recursos da camada de gargalo retêm mais generalidade em comparação com a camada final/superior.\n", "\n", @@ -406,11 +458,12 @@ "metadata": { "id": "19IQ2gqneqmS" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "IMG_SHAPE = (IMG_SIZE, IMG_SIZE, 3)\n", - "\n", - "# Criar o modelo base a partir do modelo MobileNet V2 pré-treinado\n", + "# Create the base model from the pre-trained model MobileNet V2\n", + "IMG_SHAPE = IMG_SIZE + (3,)\n", "base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,\n", " include_top=False,\n", " weights='imagenet')" @@ -431,8 +484,11 @@ "metadata": { "id": "Y-2LJL0EEUcx" }, - "outputs": [], + "outputs": [ + + ], "source": [ + "image_batch, label_batch = next(iter(train_dataset))\n", "feature_batch = base_model(image_batch)\n", "print(feature_batch.shape)" ] @@ -444,6 +500,7 @@ }, "source": [ "## Extração de Características\n", + "\n", "Nesta etapa, você congelará a base convolucional criada a partir da etapa anterior e utilizará como extrator de características. Além disso, você adiciona um classificador sobre ele e treina o classificador de nível superior." ] }, @@ -453,9 +510,16 @@ "id": "CnMLieHBCwil" }, "source": [ - "### Congelar a base convolucional\n", - "\n", - "É importante congelar a base convolucional antes de compilar e treinar o modelo. O congelamento (configurando layer.trainable = False) impede que os pesos em uma determinada camada sejam atualizados durante o treinamento. O MobileNet V2 possui muitas camadas, portanto, definir o sinalizador treinável do modelo inteiro como False congelará todas as camadas." + "### Congele a base convolucional" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7fL6upiN3ekS" + }, + "source": [ + "É importante congelar a base convolucional antes de compilar e treinar o modelo. O congelamento (definindo layer.trainable = False) evita que os pesos de uma determinada camada sejam atualizados durante o treinamento. O MobileNet V2 tem muitas camadas, portanto, definir o sinalizador `trainable` de todo o modelo como False irá congelar todas elas." ] }, { @@ -464,20 +528,41 @@ "metadata": { "id": "OTCJH4bphOeo" }, - "outputs": [], + "outputs": [ + + ], "source": [ "base_model.trainable = False" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "jsNHwpm7BeVM" + }, + "source": [ + "### Observações importantes sobre as camadas BatchNormalization\n", + "\n", + "Muitos modelos contêm camadas `tf.keras.layers.BatchNormalization`. Esta camada é um caso especial e devem ser tomadas precauções no contexto do tuning, conforme mostrado mais adiante neste tutorial.\n", + "\n", + "Quando você define `layer.trainable = False`, a camada `BatchNormalization` será executada no modo de inferência e não atualizará suas estatísticas de média e variância.\n", + "\n", + "Ao descongelar um modelo que contém camadas BatchNormalization para fazer o tuning, você deve manter as camadas BatchNormalization no modo de inferência passando `training = False` ao chamar o modelo base. Caso contrário, as atualizações aplicadas aos pesos não treináveis ​​destruirão o que o modelo aprendeu.\n", + "\n", + "Para mais detalhes, consulte o [Guia de aprendizado por transferência](https://www.tensorflow.org/guide/keras/transfer_learning)." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "KpbzSmPkDa-N" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "# Vamos dar uma olhada na arquitetura do modelo base\n", + "# Let's take a look at the base model architecture\n", "base_model.summary()" ] }, @@ -487,7 +572,7 @@ "id": "wdMRM8YModbk" }, "source": [ - "### Adicionar um cabeçalho de classificação" + "### Adicione um cabeçalho de classificação" ] }, { @@ -505,7 +590,9 @@ "metadata": { "id": "dLnpMF5KOALm" }, - "outputs": [], + "outputs": [ + + ], "source": [ "global_average_layer = tf.keras.layers.GlobalAveragePooling2D()\n", "feature_batch_average = global_average_layer(feature_batch)\n", @@ -527,9 +614,11 @@ "metadata": { "id": "Wv4afXKj6cVa" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "prediction_layer = keras.layers.Dense(1)\n", + "prediction_layer = tf.keras.layers.Dense(1)\n", "prediction_batch = prediction_layer(feature_batch_average)\n", "print(prediction_batch.shape)" ] @@ -537,81 +626,105 @@ { "cell_type": "markdown", "metadata": { - "id": "0iqnBeZrfoIc" + "id": "HXvz-ZkTa9b3" }, "source": [ - "Agora empilhe o extrator de características e essas duas camadas usando um modelo `tf.keras.Sequential`:" + "Crie um modelo encadeando as camadas de ampliação de dados, redimensionamento, `base_model` e extrator de recursos usando a [API Keras Functional](https://www.tensorflow.org/guide/keras/functional). Conforme mencionado anteriormente, use `training=False` pois nosso modelo contém uma camada `BatchNormalization`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "eApvroIyn1K0" + "id": "DgzQX6Veb2WT" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "model = tf.keras.Sequential([\n", - " base_model,\n", - " global_average_layer,\n", - " prediction_layer\n", - "])" + "inputs = tf.keras.Input(shape=(160, 160, 3))\n", + "x = data_augmentation(inputs)\n", + "x = preprocess_input(x)\n", + "x = base_model(x, training=False)\n", + "x = global_average_layer(x)\n", + "x = tf.keras.layers.Dropout(0.2)(x)\n", + "outputs = prediction_layer(x)\n", + "model = tf.keras.Model(inputs, outputs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "I8ARiyMFsgbH" + }, + "outputs": [ + + ], + "source": [ + "model.summary()" ] }, { "cell_type": "markdown", "metadata": { - "id": "g0ylJXE_kRLi" + "id": "lxOcmVr0ydFZ" }, "source": [ - "### Compilar o modelo\n", - "\n", - "Você deve compilar o modelo antes de treiná-lo. Como existem duas classes, use uma perda de entropia cruzada binária com `from_logits = True`, pois o modelo fornece uma saída linear." + "Os mais de 8 milhões de parâmetros no MobileNet estão congelados, mas existem 1,2 mil parâmetros *treináveis* ​​na camada Densa. Eles são divididos entre dois objetos `tf.Variable`, os pesos e os bias." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "RpR8HdyMhukJ" + "id": "krvBumovycVA" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "base_learning_rate = 0.0001\n", - "model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate),\n", - " loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", - " metrics=['accuracy'])" + "len(model.trainable_variables)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "I8ARiyMFsgbH" + "id": "jeGk93R2ahav" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "model.summary()" + "tf.keras.utils.plot_model(model, show_shapes=True)" ] }, { "cell_type": "markdown", "metadata": { - "id": "lxOcmVr0ydFZ" + "id": "g0ylJXE_kRLi" }, "source": [ - "Os parâmetros de 2,5 milhões no MobileNet estão congelados, mas existem 1,2 mil parâmetros _trainable_ na camada Dense. Estes são divididos entre dois objetos `tf.Variable`, os pesos e desvios." + "### Compile o modelo\n", + "\n", + "Compile o modelo antes de treiná-lo. Como existem duas classes, use a perda `tf.keras.losses.BinaryCrossentropy` com `from_logits=True`, pois o modelo fornece uma saída linear." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "krvBumovycVA" + "id": "RpR8HdyMhukJ" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "len(model.trainable_variables)" + "base_learning_rate = 0.0001\n", + "model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=base_learning_rate),\n", + " loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", + " metrics=[tf.keras.metrics.BinaryAccuracy(threshold=0, name='accuracy')])" ] }, { @@ -620,23 +733,9 @@ "id": "RxvgOYTDSWTx" }, "source": [ - "### Trainar o modelo\n", + "### Treine o modelo\n", "\n", - "Após o treinamento por 10 épocas, você deverá ver ~96% de acurácia.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "hlHEavK7DUI7" - }, - "outputs": [], - "source": [ - "num_train, num_val, num_test = (\n", - " metadata.splits['train'].num_examples*weight/10\n", - " for weight in SPLIT_WEIGHTS\n", - ")" + "Após treinar por 10 épocas, você deverá perceber uma precisão de aproximadamente 96% no dataset de validação.\n" ] }, { @@ -645,13 +744,13 @@ "metadata": { "id": "Om4O3EESkab1" }, - "outputs": [], + "outputs": [ + + ], "source": [ "initial_epochs = 10\n", - "steps_per_epoch = round(num_train)//BATCH_SIZE\n", - "validation_steps=20\n", "\n", - "loss0,accuracy0 = model.evaluate(validation_batches, steps = validation_steps)" + "loss0, accuracy0 = model.evaluate(validation_dataset)" ] }, { @@ -660,7 +759,9 @@ "metadata": { "id": "8cYT1c48CuSd" }, - "outputs": [], + "outputs": [ + + ], "source": [ "print(\"initial loss: {:.2f}\".format(loss0))\n", "print(\"initial accuracy: {:.2f}\".format(accuracy0))" @@ -672,11 +773,13 @@ "metadata": { "id": "JsaRFlZ9B6WK" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "history = model.fit(train_batches,\n", + "history = model.fit(train_dataset,\n", " epochs=initial_epochs,\n", - " validation_data=validation_batches)" + " validation_data=validation_dataset)" ] }, { @@ -685,7 +788,7 @@ "id": "Hd94CKImf8vi" }, "source": [ - "### Curvas de Aprendizado\n", + "### Curvas de aprendizado\n", "\n", "Vamos dar uma olhada nas curvas de aprendizado da acurácia/perda do treinamento e da validação ao usar o modelo base do MobileNet V2 como um extrator de características fixo." ] @@ -696,7 +799,9 @@ "metadata": { "id": "53OTCh3jnbwV" }, - "outputs": [], + "outputs": [ + + ], "source": [ "acc = history.history['accuracy']\n", "val_acc = history.history['val_accuracy']\n", @@ -741,14 +846,15 @@ "id": "CqwV-CRdS6Nv" }, "source": [ - "## Ajuste Fino\n", + "## Ajuste fino (tuning)\n", + "\n", "No experimento de extração de características, você treinava apenas algumas camadas sobre um modelo base do MobileNet V2. Os pesos da rede pré-treinada não foram atualizados durante o treinamento.\n", "\n", - "Uma maneira de aumentar ainda mais o desempenho é treinar (ou \"ajustar\") os pesos das camadas superiores do modelo pré-treinado, juntamente com o treinamento do classificador adicionado. O processo de treinamento forçará os pesos a serem ajustados com mapas de características genéricas para recursos associados especificamente ao conjunto de dados.\n", + "Uma maneira de aumentar ainda mais o desempenho é treinar (ou \"ajustar\") os pesos das camadas superiores do modelo pré-treinado, juntamente com o treinamento do classificador adicionado. O processo de treinamento forçará os pesos a serem ajustados com mapas de características genéricas para recursos associados especificamente ao dataset.\n", "\n", "Nota: Isso só deve ser tentado depois de você treinar o classificador de nível superior com o modelo pré-treinado definido como não treinável. Se você adicionar um classificador inicializado aleatoriamente sobre um modelo pré-treinado e tentar treinar todas as camadas em conjunto, a magnitude das atualizações de gradiente será muito grande (devido aos pesos aleatórios do classificador) e seu modelo pré-treinado esquecerá o que aprendeu.\n", "\n", - "Além disso, você deve tentar ajustar um pequeno número de camadas superiores em vez de todo o modelo MobileNet. Na maioria das redes convolucionais, quanto mais alta a camada, mais especializada ela é. As primeiras camadas aprendem recursos muito simples e genéricos que generalizam para quase todos os tipos de imagens. À medida que você aumenta, as características são cada vez mais específicas para o conjunto de dados no qual o modelo foi treinado. O objetivo do ajuste fino é adaptar essas características especializados para trabalhar com o novo conjunto de dados, em vez de substituir o aprendizado genérico." + "Além disso, você deve tentar ajustar um pequeno número de camadas superiores em vez de todo o modelo MobileNet. Na maioria das redes convolucionais, quanto mais alta a camada, mais especializada ela é. As primeiras camadas aprendem recursos muito simples e genéricos que generalizam para quase todos os tipos de imagens. À medida que você aumenta, as características são cada vez mais específicas para o dataset no qual o modelo foi treinado. O objetivo do ajuste fino é adaptar essas características especializados para trabalhar com o novo dataset, em vez de substituir o aprendizado genérico." ] }, { @@ -775,7 +881,9 @@ "metadata": { "id": "4nzcagVitLQm" }, - "outputs": [], + "outputs": [ + + ], "source": [ "base_model.trainable = True" ] @@ -786,17 +894,19 @@ "metadata": { "id": "-4HgVAacRs5v" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "# Vamos dar uma olhada para ver quantas camadas existem no modelo base\n", + "# Let's take a look to see how many layers are in the base model\n", "print(\"Number of layers in the base model: \", len(base_model.layers))\n", "\n", - "# Ajuste a partir desta camada em diante\n", + "# Fine-tune from this layer onwards\n", "fine_tune_at = 100\n", "\n", - "# Congele todas as camadas antes de `fine_tune_at`\n", + "# Freeze all the layers before the `fine_tune_at` layer\n", "for layer in base_model.layers[:fine_tune_at]:\n", - " layer.trainable = False" + " layer.trainable = False" ] }, { @@ -805,7 +915,7 @@ "id": "4Uk1dgsxT0IS" }, "source": [ - "### Compilar o modelo\n", + "### Compile o modelo\n", "\n", "Compile o modelo usando uma taxa de aprendizado muito menor." ] @@ -816,11 +926,13 @@ "metadata": { "id": "NtUnaz0WUDva" }, - "outputs": [], + "outputs": [ + + ], "source": [ "model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", - " optimizer = tf.keras.optimizers.RMSprop(lr=base_learning_rate/10),\n", - " metrics=['accuracy'])" + " optimizer = tf.keras.optimizers.RMSprop(learning_rate=base_learning_rate/10),\n", + " metrics=[tf.keras.metrics.BinaryAccuracy(threshold=0, name='accuracy')])" ] }, { @@ -829,7 +941,9 @@ "metadata": { "id": "WwBWy7J2kZvA" }, - "outputs": [], + "outputs": [ + + ], "source": [ "model.summary()" ] @@ -840,7 +954,9 @@ "metadata": { "id": "bNXelbMQtonr" }, - "outputs": [], + "outputs": [ + + ], "source": [ "len(model.trainable_variables)" ] @@ -869,15 +985,17 @@ "metadata": { "id": "ECQLkAsFTlun" }, - "outputs": [], + "outputs": [ + + ], "source": [ "fine_tune_epochs = 10\n", "total_epochs = initial_epochs + fine_tune_epochs\n", "\n", - "history_fine = model.fit(train_batches,\n", + "history_fine = model.fit(train_dataset,\n", " epochs=total_epochs,\n", - " initial_epoch = history.epoch[-1],\n", - " validation_data=validation_batches)" + " initial_epoch=history.epoch[-1],\n", + " validation_data=validation_dataset)" ] }, { @@ -888,7 +1006,7 @@ "source": [ "Vamos dar uma olhada nas curvas de aprendizado da acurácia/perda do treinamento e da validação ao ajustar as últimas camadas do modelo base do MobileNet V2 e treinar o classificador sobre ele. A perda de validação é muito maior do que a perda de treinamento, portanto, você pode obter um overfitting.\n", "\n", - "Você também pode obter um overfitting, pois o novo conjunto de treinamento é relativamente pequeno e semelhante aos conjuntos de dados originais do MobileNet V2.\n" + "Você também pode obter um overfitting, pois o novo dataset de treinamento é relativamente pequeno e semelhante aos datasets originais do MobileNet V2.\n" ] }, { @@ -906,7 +1024,9 @@ "metadata": { "id": "PpA8PlpQKygw" }, - "outputs": [], + "outputs": [ + + ], "source": [ "acc += history_fine.history['accuracy']\n", "val_acc += history_fine.history['val_accuracy']\n", @@ -921,7 +1041,9 @@ "metadata": { "id": "chW103JUItdk" }, - "outputs": [], + "outputs": [ + + ], "source": [ "plt.figure(figsize=(8, 8))\n", "plt.subplot(2, 1, 1)\n", @@ -945,6 +1067,76 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "R6cWgjgfrsn5" + }, + "source": [ + "### Avaliação e previsão" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PSXH7PRMxOi5" + }, + "source": [ + "Finalmente, você pode verificar o desempenho do modelo em novos dados usando o dataset de testes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2KyNhagHwfar" + }, + "outputs": [ + + ], + "source": [ + "loss, accuracy = model.evaluate(test_dataset)\n", + "print('Test accuracy :', accuracy)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8UjS5ukZfOcR" + }, + "source": [ + "E agora você está pronto para usar este modelo para prever se seu animal de estimação é um gato ou um cachorro." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RUNoQNgtfNgt" + }, + "outputs": [ + + ], + "source": [ + "# Retrieve a batch of images from the test set\n", + "image_batch, label_batch = test_dataset.as_numpy_iterator().next()\n", + "predictions = model.predict_on_batch(image_batch).flatten()\n", + "\n", + "# Apply a sigmoid since our model returns logits\n", + "predictions = tf.nn.sigmoid(predictions)\n", + "predictions = tf.where(predictions < 0.5, 0, 1)\n", + "\n", + "print('Predictions:\\n', predictions.numpy())\n", + "print('Labels:\\n', label_batch)\n", + "\n", + "plt.figure(figsize=(10, 10))\n", + "for i in range(9):\n", + " ax = plt.subplot(3, 3, i + 1)\n", + " plt.imshow(image_batch[i].astype(\"uint8\"))\n", + " plt.title(class_names[predictions[i]])\n", + " plt.axis(\"off\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -953,18 +1145,17 @@ "source": [ "## Resumo:\n", "\n", - "* ** Usando um modelo pré-treinado para extração de características **: Ao trabalhar com um pequeno conjunto de dados, é uma prática comum tirar proveito das características aprendidas por um modelo treinado em um conjunto de dados maior no mesmo domínio. Isso é feito instanciando o modelo pré-treinado e adicionando um classificador totalmente conectado na parte superior. O modelo pré-treinado é \"congelado\" e apenas os pesos do classificador são atualizados durante o treinamento.\n", - "Nesse caso, a base convolucional extraiu todas as características associadas a cada imagem e você acabou de treinar um classificador que determina a classe da imagem, considerando esse conjunto de características extraídas.\n", + "- **Usando um modelo pré-treinado para extração de características**: Ao trabalhar com um pequeno dataset, é uma prática comum tirar proveito das características aprendidas por um modelo treinado em um dataset maior no mesmo domínio. Isso é feito instanciando o modelo pré-treinado e adicionando um classificador totalmente conectado na parte superior. O modelo pré-treinado é \"congelado\" e apenas os pesos do classificador são atualizados durante o treinamento. Nesse caso, a base convolucional extraiu todas as características associadas a cada imagem e você acabou de treinar um classificador que determina a classe da imagem, considerando esse conjunto de características extraídas.\n", + "\n", + "- **Ajuste fino de um modelo pré-treinado**: Para melhorar ainda mais o desempenho, é possível redirecionar as camadas de nível superior dos modelos pré-treinados para o novo dataset via ajuste fino. Nesse caso, você ajustou seus pesos para que seu modelo aprendesse características de alto nível específicas ao dataset. Essa técnica geralmente é recomendada quando o dataset de treinamento é grande e muito semelhante ao dataset original em que o modelo pré-treinado foi treinado.\n", "\n", - "* ** Ajuste fino de um modelo pré-treinado **: Para melhorar ainda mais o desempenho, é possível redirecionar as camadas de nível superior dos modelos pré-treinados para o novo conjunto de dados via ajuste fino.\n", - "Nesse caso, você ajustou seus pesos para que seu modelo aprendesse características de alto nível específicas ao conjunto de dados. Essa técnica geralmente é recomendada quando o conjunto de dados de treinamento é grande e muito semelhante ao conjunto de dados original em que o modelo pré-treinado foi treinado." + "Para saber mais, veja o [Guia de aprendizado por transferência](https://www.tensorflow.org/guide/keras/transfer_learning).\n" ] } ], "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [], "name": "transfer_learning.ipynb", "toc_visible": true }, diff --git a/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb b/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb index cc1685283b..b9567ce217 100644 --- a/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb +++ b/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb @@ -16,7 +16,9 @@ "cellView": "form", "id": "ioaprt5q5US7" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -49,14 +51,10 @@ "\n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", - " Ver no GitHub\n", - " Baixar notebook\n", - " Ver modelo do TF Hub\n", - " Executar no Google Colab Ver no GitHub Baixar notebook Ver modelo do TF Hub
" ] }, @@ -92,7 +90,9 @@ "metadata": { "id": "cbUMIubipgg0" }, - "outputs": [], + "outputs": [ + + ], "source": [ "import matplotlib.pylab as plt\n", "import numpy as np\n", @@ -124,7 +124,9 @@ "metadata": { "id": "14APZcfHolKj" }, - "outputs": [], + "outputs": [ + + ], "source": [ "model = tf.keras.Sequential([\n", " hub.KerasLayer(\n", @@ -146,7 +148,7 @@ "\n", "**Entradas**: o formato de entrada esperado para o modelo é `(None, 224, 224, 3)`. É um tensor 4D denso de dtype float32 e formato `(batch_size, height, width, RGB channels)`, que tem elementos de valores de cores RGB de pixels normalizados para o intervalo [0, 1]. O primeiro elemento é `None` para indicar que o modelo aceita qualquer tamanho de lote de números inteiros.\n", "\n", - "**Saídas**: um `tf.Tensor` de logits no formato `(batch_size, 1001)`. Cada linha representa a pontuação prevista do modelo para cada uma das 1.001 classes da ImageNet. Para o índice de principais classes previstas do modelo, você pode usar o `tf.math.argmax(predictions, axis=-1)`. Além disso, você também pode converter a saída de logit do modelo para as probabilidades previstas de todas as classes usando o `tf.nn.softmax(predictions, axis=-1)` para quantificar a incerteza do modelo, além de explorar classes previstas semelhantes para depuração." + "**Saídas** : Um `tf.Tensor` de logits na forma de `(batch_size, 1001)` . Cada linha representa a pontuação prevista do modelo para 1.001 classes do ImageNet. Para o principal índice de classe previsto do modelo, você pode usar `tf.math.argmax(predictions, axis=-1)`. Além disso, você também pode converter a saída logit do modelo em probabilidades previstas em todas as classes usando `tf.nn.softmax(predictions, axis=-1)` para quantificar a incerteza do modelo e explorar classes previstas semelhantes para depuração." ] }, { @@ -155,7 +157,9 @@ "metadata": { "id": "huZnb_O0L9mw" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def load_imagenet_labels(file_path):\n", " labels_file = tf.keras.utils.get_file('ImageNetLabels.txt', file_path)\n", @@ -171,7 +175,9 @@ "metadata": { "id": "Rtrl-u7T6NEk" }, - "outputs": [], + "outputs": [ + + ], "source": [ "imagenet_labels = load_imagenet_labels('https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')" ] @@ -193,7 +199,9 @@ "metadata": { "id": "YOb0Adq-rU5J" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def read_image(file_name):\n", " image = tf.io.read_file(file_name)\n", @@ -209,7 +217,9 @@ "metadata": { "id": "_khLTN75CLMJ" }, - "outputs": [], + "outputs": [ + + ], "source": [ "img_url = {\n", " 'Fireboat': 'http://storage.googleapis.com/download.tensorflow.org/example_images/San_Francisco_fireboat_showing_off.jpg',\n", @@ -226,7 +236,9 @@ "metadata": { "id": "AYIeu8rMLN-8" }, - "outputs": [], + "outputs": [ + + ], "source": [ "plt.figure(figsize=(8, 8))\n", "for n, (name, img_tensors) in enumerate(img_name_tensors.items()):\n", @@ -245,7 +257,7 @@ "source": [ "### Classifique as imagens\n", "\n", - "Vamos começar classificando essas imagens e mostrando as três principais previsões mais confiantes. Confira uma função utilitária a seguir para recuperar os principais k rótulos e probabilidades previstos." + "Comece classificando essas imagens e mostrando as três principais previsões mais confiáveis. A função utilitária a seguir é usada para recuperar os principais k rótulos e probabilidades previstos." ] }, { @@ -254,7 +266,9 @@ "metadata": { "id": "5gsO7ILHZ0By" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def top_k_predictions(img, k=3):\n", " image_batch = tf.expand_dims(img, 0)\n", @@ -271,7 +285,9 @@ "metadata": { "id": "l80a8N2vcIP-" }, - "outputs": [], + "outputs": [ + + ], "source": [ "for (name, img_tensor) in img_name_tensors.items():\n", " plt.imshow(img_tensor)\n", @@ -308,7 +324,9 @@ "metadata": { "id": "0AUkIUvpkaO8" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def f(x):\n", " \"\"\"A simplified model function.\"\"\"\n", @@ -328,7 +346,9 @@ "metadata": { "id": "kMdAKooulVRE" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title\n", "fig = plt.figure(figsize=(12, 5))\n", @@ -364,7 +384,7 @@ "id": "LswhGFd0xZBr" }, "source": [ - "- **esquerda**: os gradientes do seu modelo para o pixel `x` são positivos entre 0.0 e 0.8, mas chegam a 0.0 entre 0.8 e 1.0. Claramente, o pixel `x` influencia bastante seu modelo a chegar à probabilidade prevista de 80% na classe verdadeira. Faz sentido que a importância do pixel `x` seja pequena ou descontínua?\n", + "- **esquerda**: os gradientes do seu modelo para o pixel `x` são positivos entre 0.0 e 0.8, mas chegam a 0.0 entre 0.8 e 1.0. Claramente, o pixel `x` influencia bastante seu modelo a chegar à probabilidade prevista de 80% na classe verdadeira. Faz sentido que a importância do pixel `x` seja pequena ou descontínua?\n", "\n", "- **direita**: a intuição por trás do GI é fazer o acumulado dos gradientes locais do pixel `x` e atribuir a importância como uma pontuação para o quanto ele adiciona ou subtrai da probabilidade geral de classe de saída do modelo. Você pode dividir e computar o GI em 3 partes:\n", "\n", @@ -401,7 +421,9 @@ "metadata": { "id": "wxvpwGkj4G4J" }, - "outputs": [], + "outputs": [ + + ], "source": [ "baseline = tf.zeros(shape=(224,224,3))" ] @@ -412,7 +434,9 @@ "metadata": { "id": "vXRYwBWQS19B" }, - "outputs": [], + "outputs": [ + + ], "source": [ "plt.imshow(baseline)\n", "plt.title(\"Baseline\")\n", @@ -492,7 +516,9 @@ "metadata": { "id": "I42mBKXyjcIc" }, - "outputs": [], + "outputs": [ + + ], "source": [ "m_steps=50\n", "alphas = tf.linspace(start=0.0, stop=1.0, num=m_steps+1) # Generate m_steps intervals for integral_approximation() below." @@ -504,7 +530,9 @@ "metadata": { "id": "7SWLSFOHsbgh" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def interpolate_images(baseline,\n", " image,\n", @@ -523,7 +551,7 @@ "id": "s4zFzbUBj684" }, "source": [ - "Vamos usar a função acima para gerar imagens interpoladas em um caminho linear a intervalos alpha entre uma imagem preta de linha de base e a imagem de exemplo \"Barco de bombeiros\"." + "Use a função acima para gerar imagens interpoladas ao longo de um caminho linear em intervalos alfa entre uma imagem de linha de base preta e a imagem de exemplo \"Fireboat\" (Barco de bombeiros)." ] }, { @@ -532,7 +560,9 @@ "metadata": { "id": "NgVx8swDQtTl" }, - "outputs": [], + "outputs": [ + + ], "source": [ "interpolated_images = interpolate_images(\n", " baseline=baseline,\n", @@ -546,7 +576,7 @@ "id": "QABFsuCvkO1h" }, "source": [ - "Vamos visualizar as imagens interpoladas. Observação: outra maneira de pensar na constante $\\alpha$ é que ela aumenta consistentemente a intensidade de cada imagem interpolada." + "Visualize as imagens interpoladas. Observação: outra maneira de pensar sobre a constante $\\alpha$ é que ela aumenta consistentemente a intensidade de cada imagem interpolada." ] }, { @@ -555,7 +585,9 @@ "metadata": { "id": "9tmBGdnHAupk" }, - "outputs": [], + "outputs": [ + + ], "source": [ "fig = plt.figure(figsize=(20, 20))\n", "\n", @@ -585,7 +617,7 @@ "id": "tps0eWc0REqL" }, "source": [ - "Agora, vamos ver como calcular os gradientes para medir a relação entre as mudanças em uma característica e as mudanças nas previsões do modelo. No caso das imagens, o gradiente informa quais pixels afetam mais as probabilidades de classes previstas do modelo." + "Esta seção explica como computar os gradientes para medir a relação entre as alterações em um recurso e as alterações nas previsões do modelo. No caso de imagens, o gradiente nos diz quais pixels têm o efeito mais forte nas probabilidades de classe previstas do modelo." ] }, { @@ -614,7 +646,9 @@ "metadata": { "id": "JW1O9qEsxZOP" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def compute_gradients(images, target_class_idx):\n", " with tf.GradientTape() as tape:\n", @@ -630,7 +664,7 @@ "id": "9BfRuzx4-c87" }, "source": [ - "Vamos computar os gradientes para cada imagem no caminho de interpolação em relação à saída correta. Lembre-se de que seu modelo retorna um `Tensor` com o formato `(1, 1001)` e logits que você converte em probabilidades previstas para cada classe. Você precisa passar o índice de classe alvo correto da ImageNet à função `compute_gradients` para sua imagem." + "Compute os gradientes de cada imagem ao longo do caminho de interpolação em relação à saída correta. Lembre-se de que seu modelo retorna um `Tensor` em formato `(1, 1001)` com logits que você converte em probabilidades previstas para cada classe. Você precisa passar o índice de classe de destino correto do ImageNet para a função `compute_gradients` da sua imagem." ] }, { @@ -639,7 +673,9 @@ "metadata": { "id": "kHIR58rNJ3q_" }, - "outputs": [], + "outputs": [ + + ], "source": [ "path_gradients = compute_gradients(\n", " images=interpolated_images,\n", @@ -661,7 +697,9 @@ "metadata": { "id": "v2rpO2JTbQId" }, - "outputs": [], + "outputs": [ + + ], "source": [ "print(path_gradients.shape)" ] @@ -685,7 +723,9 @@ "metadata": { "id": "FQWwcI0Wr0AX" }, - "outputs": [], + "outputs": [ + + ], "source": [ "pred = model(interpolated_images)\n", "pred_proba = tf.nn.softmax(pred, axis=-1)[:, 555]" @@ -697,7 +737,9 @@ "metadata": { "id": "mCH8sAf3TTJ2" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title\n", "plt.figure(figsize=(10, 4))\n", @@ -759,7 +801,7 @@ "source": [ "$IntegratedGrads^{approx}{em0}{i}(x)::=(x{/em0}{i}-x'{em1}{i})\\times \\overbrace{\\sum{/em1}{k=1}^{m}}^\\text{Sum m local gradients}\\text{gradients(interpolated images)} \\times \\overbrace{\\frac{1}{m}}^\\text{Divide by m steps}$\n", "\n", - "Na equação, você pode ver que está somando `m` gradientes e dividindo por `m` passos. Você pode implementar as duas operações juntas para a parte 3 como uma média dos gradientes locais de `m` previsões interpoladas e imagens de entrada." + "Na equação, você pode ver que está somando `m` gradientes e dividindo por `m` passos. Você pode implementar as duas operações juntas para a parte 3 como uma média dos gradientes locais de `m` previsões interpoladas e imagens de entrada." ] }, { @@ -768,7 +810,9 @@ "metadata": { "id": "1cMVl-Grx3lp" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def integral_approximation(gradients):\n", " # riemann_trapezoidal\n", @@ -792,7 +836,9 @@ "metadata": { "id": "JeF01fydNq0I" }, - "outputs": [], + "outputs": [ + + ], "source": [ "ig = integral_approximation(\n", " gradients=path_gradients)" @@ -813,7 +859,9 @@ "metadata": { "id": "z1bP6l3ahfyn" }, - "outputs": [], + "outputs": [ + + ], "source": [ "print(ig.shape)" ] @@ -868,7 +916,9 @@ "metadata": { "id": "O_H3k9Eu7Rl5" }, - "outputs": [], + "outputs": [ + + ], "source": [ "def integrated_gradients(baseline,\n", " image,\n", @@ -908,7 +958,9 @@ "metadata": { "id": "dszwB_Sp0CX0" }, - "outputs": [], + "outputs": [ + + ], "source": [ "@tf.function\n", "def one_batch(baseline, image, alpha_batch, target_class_idx):\n", @@ -929,7 +981,9 @@ "metadata": { "id": "8G0ELl_wRrd0" }, - "outputs": [], + "outputs": [ + + ], "source": [ "ig_attributions = integrated_gradients(baseline=baseline,\n", " image=img_name_tensors['Fireboat'],\n", @@ -952,7 +1006,9 @@ "metadata": { "id": "beoEunC5aZOa" }, - "outputs": [], + "outputs": [ + + ], "source": [ "print(ig_attributions.shape)" ] @@ -990,7 +1046,9 @@ "metadata": { "id": "4QN2cEA_WFym" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title\n", "def plot_img_attributions(baseline,\n", @@ -1048,7 +1106,9 @@ "metadata": { "id": "vxCQFx96iDVs" }, - "outputs": [], + "outputs": [ + + ], "source": [ "_ = plot_img_attributions(image=img_name_tensors['Fireboat'],\n", " baseline=baseline,\n", @@ -1073,7 +1133,9 @@ "metadata": { "id": "TcpGLJWuHnYl" }, - "outputs": [], + "outputs": [ + + ], "source": [ "_ = plot_img_attributions(image=img_name_tensors['Giant Panda'],\n", " baseline=baseline,\n", @@ -1104,9 +1166,9 @@ "\n", "Limitações\n", "\n", - "- Os gradientes integrados fornecem importâncias de características em exemplos individuais. No entanto, eles não oferecem importâncias de características globais em todo o dataset.\n", + "- A técnica de gradientes integrados fornece importâncias de características em exemplos individuais. No entanto, ela não fornece as importâncias de características globais em todo o dataset.\n", "\n", - "- Os gradientes integrados oferecem importâncias de características individuais, mas não explicam as interações e combinações de características." + "- A técnica de gradientes integrados fornece importâncias de características individuais, mas não explica interações e combinações de características." ] }, { @@ -1137,7 +1199,9 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [], + "collapsed_sections": [ + + ], "name": "integrated_gradients.ipynb", "toc_visible": true }, diff --git a/site/pt-br/tutorials/load_data/csv.ipynb b/site/pt-br/tutorials/load_data/csv.ipynb index 124bbfb4b5..5745ff10b2 100644 --- a/site/pt-br/tutorials/load_data/csv.ipynb +++ b/site/pt-br/tutorials/load_data/csv.ipynb @@ -16,7 +16,9 @@ "cellView": "form", "id": "AVV2e0XKbJeX" }, - "outputs": [], + "outputs": [ + + ], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -37,7 +39,7 @@ "id": "sUtoed20cRJJ" }, "source": [ - "# Carregar dados CSV" + "# Carregando dados em CSV" ] }, { @@ -47,18 +49,12 @@ }, "source": [ "\n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", "
\n", - " Ver em TensorFlow.org\n", - " \n", - " Executar em Google Colab\n", - " \n", - " Ver código fonte no GitHub\n", - " \n", - " Baixar notebook\n", - " Ver em TensorFlow.org Executar no Google Colab\n", + " Ver fonte no GitHub\n", + "Baixar notebook
" ] }, @@ -68,127 +64,919 @@ "id": "C-3Xbt0FfGfs" }, "source": [ - "Este tutorial fornece um exemplo de como carregar dados CSV de um arquivo em um `tf.data.Dataset`.\n", + "Este tutorial fornece exemplos de como usar dados CSV com o TensorFlow.\n", "\n", - "Os dados usados neste tutorial foram retirados da lista de passageiros do Titanic. O modelo preverá a probabilidade de sobrevivência de um passageiro com base em características como idade, sexo, classe de passagem e se a pessoa estava viajando sozinha." + "Esse processo consiste de duas partes:\n", + "\n", + "1. **Carregar os dados do disco**\n", + "2. **Pré-processar os dados em formato adequado para treinamento.**\n", + "\n", + "Este tutorial foca no carregamento e fornece alguns exemplos rápidos de pré-processamento. Para saber mais sobre o aspecto de pré-processamento, veja o guia [Trabalhando com camadas de pré-processamento](https://www.tensorflow.org/guide/keras/preprocessing_layers) e o tutorial [Classificando dados estruturados com camadas de pré-processamento Keras](../structured_data/preprocessing_layers.ipynb).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fgZ9gjmPfSnK" + }, + "source": [ + "## Configuração" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "baYFZMW_bJHh" + }, + "outputs": [ + + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "# Make numpy values easier to read.\n", + "np.set_printoptions(precision=3, suppress=True)\n", + "\n", + "import tensorflow as tf\n", + "from tensorflow.keras import layers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1ZhJYbJxHNGJ" + }, + "source": [ + "## Dados na memória" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ny5TEgcmHjVx" + }, + "source": [ + "Para qualquer pequeno dataset em CSV, a maneira mais simples de treinar um modelo TensorFlow nele é carregá-lo na memória como um Dataframe pandas ou um array NumPy.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LgpBOuU8PGFf" + }, + "source": [ + "Um exemplo relativamente simples é o [dataset abalone](https://archive.ics.uci.edu/ml/datasets/abalone) .\n", + "\n", + "- O dataset é pequeno.\n", + "- Todas as características de entrada são valores de ponto flutuante de faixa limitada.\n", + "\n", + "Eis como baixar os dados num [`DataFrame` do pandas](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IZVExo9DKoNz" + }, + "outputs": [ + + ], + "source": [ + "abalone_train = pd.read_csv(\n", + " \"https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv\",\n", + " names=[\"Length\", \"Diameter\", \"Height\", \"Whole weight\", \"Shucked weight\",\n", + " \"Viscera weight\", \"Shell weight\", \"Age\"])\n", + "\n", + "abalone_train.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hP22mdyPQ1_t" + }, + "source": [ + "O dataset contém um conjunto de medições de [abalone](https://en.wikipedia.org/wiki/Abalone), um tipo de caracol marinho.\n", + "\n", + "![an abalone shell](https://tensorflow.org/images/abalone_shell.jpg)\n", + "\n", + "[“Casca de abalone”](https://www.flickr.com/photos/thenickster/16641048623/) (por [Nicki Dugan Pogue](https://www.flickr.com/photos/thenickster/), CC BY-SA 2.0)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vlfGrk_9N-wf" + }, + "source": [ + "A tarefa nominal para este dataset é prever a idade a partir de outras medidas, então separe as características e rótulos para treinamento:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "udOnDJOxNi7p" + }, + "outputs": [ + + ], + "source": [ + "abalone_features = abalone_train.copy()\n", + "abalone_labels = abalone_features.pop('Age')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "seK9n71-UBfT" + }, + "source": [ + "Para este dataset, você tratará todos os recursos de forma idêntica. Agrupe os recursos num único array NumPy.:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Dp3N5McbUMwb" + }, + "outputs": [ + + ], + "source": [ + "abalone_features = np.array(abalone_features)\n", + "abalone_features" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1C1yFOxLOdxh" + }, + "source": [ + "Em seguida, crie um modelo de regressão para prever a idade. Como existe apenas um único tensor de entrada, um modelo `tf.keras.Sequential` é suficiente aqui." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "d8zzNrZqOmfB" + }, + "outputs": [ + + ], + "source": [ + "abalone_model = tf.keras.Sequential([\n", + " layers.Dense(64, activation='relu'),\n", + " layers.Dense(1)\n", + "])\n", + "\n", + "abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n", + " optimizer = tf.keras.optimizers.Adam())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j6IWeP78O2wE" + }, + "source": [ + "Para treinar esse modelo, passe os recursos e rótulos para `Model.fit`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uZdpCD92SN3Z" + }, + "outputs": [ + + ], + "source": [ + "abalone_model.fit(abalone_features, abalone_labels, epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GapLOj1OOTQH" + }, + "source": [ + "Você acabou de ver a maneira mais básica de treinar um modelo usando dados CSV. A seguir, você aprenderá como aplicar o pré-processamento para normalizar colunas numéricas." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "B87Rd1SOUv02" + }, + "source": [ + "## Pré-processamento básico" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yCrB2Jd-U0Vt" + }, + "source": [ + "É uma boa prática normalizar as entradas do seu modelo. As camadas de pré-processamento Keras fornecem uma maneira conveniente de incorporar essa normalização em seu modelo.\n", + "\n", + "A camada `tf.keras.layers.Normalization` pré-calcula a média e a variância de cada coluna e as usa para normalizar os dados.\n", + "\n", + "Primeiro, crie a camada:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "H2WQpDU5VRk7" + }, + "outputs": [ + + ], + "source": [ + "normalize = layers.Normalization()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hGgEZE-7Vpt6" + }, + "source": [ + "Em seguida, use o método `Normalization.adapt` para adaptar a camada de normalização aos seus dados.\n", + "\n", + "Observação: use apenas seus dados de treinamento com o método `PreprocessingLayer.adapt`. Não use seus dados de validação ou teste." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2WgOPIiOVpLg" + }, + "outputs": [ + + ], + "source": [ + "normalize.adapt(abalone_features)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rE6vh0byV7cE" + }, + "source": [ + "Em seguida, use a camada de normalização no seu modelo:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "quPcZ9dTWA9A" + }, + "outputs": [ + + ], + "source": [ + "norm_abalone_model = tf.keras.Sequential([\n", + " normalize,\n", + " layers.Dense(64, activation='relu'),\n", + " layers.Dense(1)\n", + "])\n", + "\n", + "norm_abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n", + " optimizer = tf.keras.optimizers.Adam())\n", + "\n", + "norm_abalone_model.fit(abalone_features, abalone_labels, epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wuqj601Qw0Ml" + }, + "source": [ + "## Tipos de dados mistos\n", + "\n", + "O dataset \"Titanic\" contém informações sobre os passageiros do Titanic. A tarefa nominal neste dataset é prever quem sobreviveu.\n", + "\n", + "![A traffic jam.](https://github.com/tensorflow/docs-l10n/blob/master/site/pt-br/tutorials/load_data/images/csv/traffic.jpg?raw=true)\n", + "\n", + "Imagem [da Wikimedia](https://commons.wikimedia.org/wiki/File:RMS_Titanic_3.jpg)\n", + "\n", + "Os dados brutos podem ser facilmente carregados como um `DataFrame` do Pandas, mas não podem ser usados ​​imediatamente como entrada para um modelo do TensorFlow.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GS-dBMpuYMnz" + }, + "outputs": [ + + ], + "source": [ + "titanic = pd.read_csv(\"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")\n", + "titanic.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "D8rCGIK1ZzKx" + }, + "outputs": [ + + ], + "source": [ + "titanic_features = titanic.copy()\n", + "titanic_labels = titanic_features.pop('survived')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "urHOwpCDYtcI" + }, + "source": [ + "Devido aos diferentes tipos e intervalos de dados, você não pode simplesmente empilhar as características numa matriz NumPy e passá-las para um modelo `tf.keras.Sequential`. Cada coluna precisa ser tratada individualmente.\n", + "\n", + "Como opção, você pode pré-processar seus dados off-line (usando qualquer ferramenta de sua preferência) para converter colunas categóricas em colunas numéricas e, em seguida, passar a saída processada para seu modelo do TensorFlow. A desvantagem dessa abordagem é que se você salvar e exportar seu modelo, o pré-processamento não será salvo com ele. As camadas de pré-processamento do Keras evitam esse problema porque fazem parte do modelo.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Bta4Sx0Zau5v" + }, + "source": [ + "Neste exemplo, você construirá um modelo que implementa a lógica de pré-processamento usando a [API funcional Keras](https://www.tensorflow.org/guide/keras/functional). Você também pode fazer isso [através de uma subclasse](https://www.tensorflow.org/guide/keras/custom_layers_and_models).\n", + "\n", + "A API funcional opera sobre tensores \"simbólicos\". Tensores normais \"eager\" têm um valor. Em contraste, esses tensores “simbólicos” não têm. Em vez disso, eles controlam quais operações são executadas neles e constroem uma representação do cálculo, que você pode executar posteriormente. Aqui está um exemplo rápido:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "730F16_97D-3" + }, + "outputs": [ + + ], + "source": [ + "# Create a symbolic input\n", + "input = tf.keras.Input(shape=(), dtype=tf.float32)\n", + "\n", + "# Perform a calculation using the input\n", + "result = 2*input + 1\n", + "\n", + "# the result doesn't have a value\n", + "result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RtcNXWB18kMJ" + }, + "outputs": [ + + ], + "source": [ + "calc = tf.keras.Model(inputs=input, outputs=result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fUGQOUqZ8sa-" + }, + "outputs": [ + + ], + "source": [ + "print(calc(1).numpy())\n", + "print(calc(2).numpy())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rNS9lT7f6_U2" + }, + "source": [ + "Para construir o modelo de pré-processamento, comece construindo um conjunto de objetos `tf.keras.Input` simbólicos, correspondendo aos nomes e tipos de dados das colunas do CSV." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5WODe_1da3yw" + }, + "outputs": [ + + ], + "source": [ + "inputs = {}\n", + "\n", + "for name, column in titanic_features.items():\n", + " dtype = column.dtype\n", + " if dtype == object:\n", + " dtype = tf.string\n", + " else:\n", + " dtype = tf.float32\n", + "\n", + " inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype)\n", + "\n", + "inputs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aaheJFmymq8l" + }, + "source": [ + "O primeiro passo na sua lógica de pré-processamento é concatenar as entradas numéricas e executá-las por meio de uma camada de normalização:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wPRC_E6rkp8D" + }, + "outputs": [ + + ], + "source": [ + "numeric_inputs = {name:input for name,input in inputs.items()\n", + " if input.dtype==tf.float32}\n", + "\n", + "x = layers.Concatenate()(list(numeric_inputs.values()))\n", + "norm = layers.Normalization()\n", + "norm.adapt(np.array(titanic[numeric_inputs.keys()]))\n", + "all_numeric_inputs = norm(x)\n", + "\n", + "all_numeric_inputs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-JoR45Uj712l" + }, + "source": [ + "Junte todos os resultados do pré-processamento simbólico, para concatená-los posteriormente:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "M7jIJw5XntdN" + }, + "outputs": [ + + ], + "source": [ + "preprocessed_inputs = [all_numeric_inputs]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r0Hryylyosfm" + }, + "source": [ + "Para as entradas que são strings, use a função `tf.keras.layers.StringLookup` para mapear de strings para índices inteiros num vocabulário. Em seguida, use `tf.keras.layers.CategoryEncoding` para converter os índices em dados `float32` apropriados para o modelo.\n", + "\n", + "As configurações padrão para a camada `tf.keras.layers.CategoryEncoding` criam um vetor one-hot para cada entrada. Um `tf.keras.layers.Embedding` também funcionaria. Confira o guia [Trabalhando com camadas de pré-processamento](https://www.tensorflow.org/guide/keras/preprocessing_layers) e o tutorial [Classificando dados estruturados usando camadas de pré-processamento do Keras](../structured_data/preprocessing_layers.ipynb) para mais informações sobre este tópico." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "79fi1Cgan2YV" + }, + "outputs": [ + + ], + "source": [ + "for name, input in inputs.items():\n", + " if input.dtype == tf.float32:\n", + " continue\n", + " \n", + " lookup = layers.StringLookup(vocabulary=np.unique(titanic_features[name]))\n", + " one_hot = layers.CategoryEncoding(num_tokens=lookup.vocabulary_size())\n", + "\n", + " x = lookup(input)\n", + " x = one_hot(x)\n", + " preprocessed_inputs.append(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wnhv0T7itnc7" + }, + "source": [ + "Com a coleção de `inputs` e `preprocessed_inputs`, você pode concatenar todas as entradas pré-processadas e construir um modelo que cuide do pré-processamento:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XJRzUTe8ukXc" + }, + "outputs": [ + + ], + "source": [ + "preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs)\n", + "\n", + "titanic_preprocessing = tf.keras.Model(inputs, preprocessed_inputs_cat)\n", + "\n", + "tf.keras.utils.plot_model(model = titanic_preprocessing , rankdir=\"LR\", dpi=72, show_shapes=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PNHxrNW8vdda" + }, + "source": [ + "Este modelo contém apenas o pré-processamento da entrada. Você pode executá-lo para ver o que ele faz com seus dados. Os modelos do Keras não convertem automaticamente objetos `DataFrame` do Pandas porque não está claro se eles devem ser convertidos em tensores ou em dicionários de tensores. Então, converta-o num dicionário de tensores:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5YjdYyMEacwQ" + }, + "outputs": [ + + ], + "source": [ + "titanic_features_dict = {name: np.array(value) \n", + " for name, value in titanic_features.items()}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0nKJYoPByada" + }, + "source": [ + "Divida o primeiro exemplo de treinamento e passe-o para este modelo de pré-processamento. Você verá as características numéricas e as strings one-hots, todas concatenadas:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SjnmU8PSv8T3" + }, + "outputs": [ + + ], + "source": [ + "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", + "titanic_preprocessing(features_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qkBf4LvmzMDp" + }, + "source": [ + "Agora, construa o modelo em cima disso:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "coIPtGaCzUV7" + }, + "outputs": [ + + ], + "source": [ + "def titanic_model(preprocessing_head, inputs):\n", + " body = tf.keras.Sequential([\n", + " layers.Dense(64, activation='relu'),\n", + " layers.Dense(1)\n", + " ])\n", + "\n", + " preprocessed_inputs = preprocessing_head(inputs)\n", + " result = body(preprocessed_inputs)\n", + " model = tf.keras.Model(inputs, result)\n", + "\n", + " model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", + " optimizer=tf.keras.optimizers.Adam())\n", + " return model\n", + "\n", + "titanic_model = titanic_model(titanic_preprocessing, inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LK5uBQQF2KbZ" + }, + "source": [ + "Ao treinar o modelo, passe o dicionário de características como `x` e o rótulo como `y`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "D1gVfwJ61ejz" + }, + "outputs": [ + + ], + "source": [ + "titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LxgJarZk3bfH" + }, + "source": [ + "Já que o pré-processamento faz parte do modelo, você pode salvar o modelo e recarregá-lo noutro lugar e obter resultados idênticos:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ay-8ymNA2ZCh" + }, + "outputs": [ + + ], + "source": [ + "titanic_model.save('test.keras')\n", + "reloaded = tf.keras.models.load_model('test.keras')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qm6jMTpD20lK" + }, + "outputs": [ + + ], + "source": [ + "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", + "\n", + "before = titanic_model(features_dict)\n", + "after = reloaded(features_dict)\n", + "assert (before-after)<1e-3\n", + "print(before)\n", + "print(after)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7VsPlxIRZpXf" + }, + "source": [ + "## Usando tf.data\n" ] }, { "cell_type": "markdown", "metadata": { - "id": "fgZ9gjmPfSnK" + "id": "NyVDCwGzR5HW" + }, + "source": [ + "Na seção anterior, você contou com o embaralhamento e agrupamento em lote de dados integrados do modelo durante o treinamento.\n", + "\n", + "Se você precisar de mais controle sobre o pipeline de dados de entrada ou precisar usar dados que não cabem facilmente na memória: use `tf.data`.\n", + "\n", + "Para mais exemplos, consulte o guia [`tf.data`: criando pipelines de entrada do TensorFlow](../../guide/data.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gP5Y1jM2Sor0" }, "source": [ - "## Setup" + "### Com dados na memória\n", + "\n", + "Como um primeiro exemplo da aplicação de `tf.data` a dados CSV, considere o código a seguir para dividir manualmente o dicionário de características da seção anterior. Para cada índice, é necessário usar aquele índice para cada característica:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "I4dwMQVQMQWD" + "id": "i8wE-MVuVu7_" + }, + "outputs": [ + + ], + "source": [ + "import itertools\n", + "\n", + "def slices(features):\n", + " for i in itertools.count():\n", + " # For each feature take index `i`\n", + " example = {name:values[i] for name, values in features.items()}\n", + " yield example" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cQ3RTbS9YEal" }, - "outputs": [], "source": [ - "try:\n", - " # %tensorflow_version only exists in Colab.\n", - " %tensorflow_version 2.x\n", - "except Exception:\n", - " pass\n" + "Execute e imprima o primeiro exemplo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "baYFZMW_bJHh" + "id": "Wwq8XK88WwFk" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "from __future__ import absolute_import, division, print_function, unicode_literals\n", - "import functools\n", - "\n", - "import numpy as np\n", - "import tensorflow as tf" + "for example in slices(titanic_features_dict):\n", + " for name, value in example.items():\n", + " print(f\"{name:19s}: {value}\")\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vvp8Dct6YOIE" + }, + "source": [ + "O mais simples carregador de dados `tf.data.Dataset` na memória é o construtor `Dataset.from_tensor_slices`. Ele retorna um `tf.data.Dataset` que implementa uma versão generalizada da função `slices` acima, no TensorFlow." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "Ncf5t6tgL5ZI" + "id": "2gEJthslYxeV" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "TRAIN_DATA_URL = \"https://storage.googleapis.com/tf-datasets/titanic/train.csv\"\n", - "TEST_DATA_URL = \"https://storage.googleapis.com/tf-datasets/titanic/eval.csv\"\n", - "\n", - "train_file_path = tf.keras.utils.get_file(\"train.csv\", TRAIN_DATA_URL)\n", - "test_file_path = tf.keras.utils.get_file(\"eval.csv\", TEST_DATA_URL)" + "features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-ZC0rTpMZMZK" + }, + "source": [ + "Você pode iterar sobre um `tf.data.Dataset` como qualquer outro objeto Python iterável:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "4ONE94qulk6S" + "id": "gOHbiefaY4ag" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "# Facilitar a leitura de valores numpy.\n", - "np.set_printoptions(precision=3, suppress=True)" + "for example in features_ds:\n", + " for name, value in example.items():\n", + " print(f\"{name:19s}: {value}\")\n", + " break" ] }, { "cell_type": "markdown", "metadata": { - "id": "Wuqj601Qw0Ml" + "id": "uwcFoVJWZY5F" }, "source": [ - "## Carregar dados\n", - "\n", - "Para começar, vejamos a parte superior do arquivo CSV para ver como ele está formatado." + "A função `from_tensor_slices` pode lidar com qualquer estrutura de dicionários ou tuplas aninhadas. O código a seguir cria um dataset de pares `(features_dict, labels)`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xIHGBy76Zcrx" + }, + "outputs": [ + + ], + "source": [ + "titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gQwxitt8c2GK" + }, + "source": [ + "Para treinar um modelo usando este `Dataset`, você precisará de pelo menos fazer `shuffle` (embaralhar) e `batch` (colocar em lote) sobre os dados." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "54Dv7mCrf9Yw" + "id": "SbJcbldhddeC" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "!head {train_file_path}" + "titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)" ] }, { "cell_type": "markdown", "metadata": { - "id": "jC9lRhV-q_R3" + "id": "-4FRqhRFuoJx" + }, + "source": [ + "Em vez de passar `features` e `labels` para `Model.fit`, você passa o dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8yXkNPumdBtB" }, + "outputs": [ + + ], "source": [ - "Você pode [carregar isso usando pandas] (pandas.ipynb) e passar as matrizes NumPy para o TensorFlow. Se você precisar escalar até um grande conjunto de arquivos ou precisar de um carregador que se integre ao [TensorFlow e tf.data] (../../guide/data.ipynb), use o `tf.data.experimental. função make_csv_dataset`:" + "titanic_model.fit(titanic_batches, epochs=5)" ] }, { "cell_type": "markdown", "metadata": { - "id": "67mfwr4v-mN_" + "id": "qXuibiv9exT7" }, "source": [ - "A única coluna que você precisa identificar explicitamente é aquela com o valor que o modelo pretende prever. " + "### De um único arquivo\n", + "\n", + "Até agora, este tutorial funcionou com dados na memória. `tf.data` é um kit de ferramentas altamente escalável para construir pipelines de dados e fornece algumas funções para lidar com o carregamento de arquivos em CSV. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "iXROZm5f3V4E" + "id": "Ncf5t6tgL5ZI" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "LABEL_COLUMN = 'survived'\n", - "LABELS = [0, 1]" + "titanic_file_path = tf.keras.utils.get_file(\"train.csv\", \"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")" ] }, { @@ -197,9 +985,9 @@ "id": "t4N-plO4tDXd" }, "source": [ - "Now read the CSV data from the file and create a dataset. \n", + "Agora leia os dados CSV do arquivo e crie um `tf.data.Dataset`.\n", "\n", - "(For the full documentation, see `tf.data.experimental.make_csv_dataset`)\n" + "(Para a documentação completa, consulte `tf.data.experimental.make_csv_dataset`)\n" ] }, { @@ -208,21 +996,30 @@ "metadata": { "id": "yIbUscB9sqha" }, - "outputs": [], + "outputs": [ + + ], + "source": [ + "titanic_csv_ds = tf.data.experimental.make_csv_dataset(\n", + " titanic_file_path,\n", + " batch_size=5, # Artificially small to make examples easier to show.\n", + " label_name='survived',\n", + " num_epochs=1,\n", + " ignore_errors=True,)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Sf3v3BKgy4AG" + }, "source": [ - "def get_dataset(file_path, **kwargs):\n", - " dataset = tf.data.experimental.make_csv_dataset(\n", - " file_path,\n", - " batch_size=5, # Artificialmente pequeno para facilitar a exibição de exemplos\n", - " label_name=LABEL_COLUMN,\n", - " na_value=\"?\",\n", - " num_epochs=1,\n", - " ignore_errors=True, \n", - " **kwargs)\n", - " return dataset\n", + "Esta função inclui diversos recursos convenientes, para que fique fácil trabalhar com os dados. Isto inclui:\n", "\n", - "raw_train_data = get_dataset(train_file_path)\n", - "raw_test_data = get_dataset(test_file_path)" + "- O uso dos cabeçalhos das colunas como chaves de dicionário.\n", + "- Determinando automaticamente o tipo de cada coluna.\n", + "\n", + "Atenção: certifique-se de definir o argumento `num_epochs` em `tf.data.experimental.make_csv_dataset`, caso contrário, o comportamento padrão para `tf.data.Dataset` é fazer um loop infinito." ] }, { @@ -231,662 +1028,979 @@ "metadata": { "id": "v4oMO9MIxgTG" }, - "outputs": [], + "outputs": [ + + ], + "source": [ + "for batch, label in titanic_csv_ds.take(1):\n", + " for key, value in batch.items():\n", + " print(f\"{key:20s}: {value}\")\n", + " print()\n", + " print(f\"{'label':20s}: {label}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k-TgA6o2Ja6U" + }, "source": [ - "def show_batch(dataset):\n", - " for batch, label in dataset.take(1):\n", - " for key, value in batch.items():\n", - " print(\"{:20s}: {}\".format(key,value.numpy()))" + "Observação: Se você executar a célula acima duas vezes, produzirá resultados diferentes. As configurações padrão para `tf.data.experimental.make_csv_dataset` incluem `shuffle_buffer_size=1000`, que é mais que suficiente para este pequeno dataset, mas pode não ser para um dataset do mundo real." ] }, { "cell_type": "markdown", "metadata": { - "id": "vHUQFKoQI6G7" + "id": "d6uviU_KCCWD" }, "source": [ - "Cada item do conjunto de dados é um lote, representado como uma tupla de (* muitos exemplos *, * muitos rótulos *). Os dados dos exemplos são organizados em tensores baseados em colunas (em vez de tensores baseados em linhas), cada um com tantos elementos quanto o tamanho do lote (5 neste caso).\n", + "Isto também pode ser usado para descompactar os dados instantaneamente. Aqui está um arquivo CSV compactado contendo o [dataset de tráfego interestadual metropolitano](https://archive.ics.uci.edu/ml/datasets/Metro+Interstate+Traffic+Volume).\n", + "\n", + "![Fonts](https://github.com/tensorflow/docs-l10n/blob/master/site/pt-br/tutorials/load_data/images/csv/fonts.jpg?raw=true)\n", "\n", - "Pode ajudar a ver isso por si mesmo." + "Imagem [da Wikimedia](https://commons.wikimedia.org/wiki/File:Trafficjam.jpg)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "HjrkJROoxoll" + "id": "kT7oZI2E46Q8" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "show_batch(raw_train_data)" + "traffic_volume_csv_gz = tf.keras.utils.get_file(\n", + " 'Metro_Interstate_Traffic_Volume.csv.gz', \n", + " \"https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz\",\n", + " cache_dir='.', cache_subdir='traffic')" ] }, { "cell_type": "markdown", "metadata": { - "id": "YOYKQKmMj3D6" + "id": "F-IOsFHbCw0i" }, "source": [ - "Como você pode ver, as colunas no CSV são nomeadas. O construtor do conjunto de dados selecionará esses nomes automaticamente. Se o arquivo com o qual você está trabalhando não contém os nomes das colunas na primeira linha, passe-os em uma lista de strings para o argumento `column_names` na função `make_csv_dataset`." + "Defina o argumento `compression_type` para ler diretamente do arquivo compactado:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "2Av8_9L3tUg1" + "id": "ar0MPEVJ5NeA" + }, + "outputs": [ + + ], + "source": [ + "traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset(\n", + " traffic_volume_csv_gz,\n", + " batch_size=256,\n", + " label_name='traffic_volume',\n", + " num_epochs=1,\n", + " compression_type=\"GZIP\")\n", + "\n", + "for batch, label in traffic_volume_csv_gz_ds.take(1):\n", + " for key, value in batch.items():\n", + " print(f\"{key:20s}: {value[:5]}\")\n", + " print()\n", + " print(f\"{'label':20s}: {label[:5]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p12Y6tGq8D6M" + }, + "source": [ + "Observação: se precisar analisar essas strings de data e hora no pipeline `tf.data`, você poderá usar `tfa.text.parse_time`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EtrAXzYGP3l0" + }, + "source": [ + "### Cache" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fN2dL_LRP83r" }, - "outputs": [], "source": [ - "CSV_COLUMNS = ['survived', 'sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']\n", + "Existe algum overhead no processamento dos dados em formato CSV. Para modelos pequenos este pode ser o gargalo do treinamento.\n", + "\n", + "Dependendo do seu caso de uso, pode ser uma boa ideia usar `Dataset.cache` ou `tf.data.Dataset.snapshot`, para que os dados CSV sejam processados ​​apenas na primeira época.\n", "\n", - "temp_dataset = get_dataset(train_file_path, column_names=CSV_COLUMNS)\n", + "A principal diferença entre os métodos de `cache` e `snapshot` é que os arquivos `cache` só podem ser usados ​​pelo processo do TensorFlow que os criou, mas os arquivos `snapshot` podem ser lidos por outros processos.\n", "\n", - "show_batch(temp_dataset)" + "Por exemplo, iterar sobre `traffic_volume_csv_gz_ds` 20 vezes pode levar cerca de 15 segundos sem armazenamento em cache ou cerca de dois segundos com armazenamento em cache." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qk38Sw4MO4eh" + }, + "outputs": [ + + ], + "source": [ + "%%time\n", + "for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):\n", + " if i % 40 == 0:\n", + " print('.', end='')\n", + "print()" ] }, { "cell_type": "markdown", "metadata": { - "id": "gZfhoX7bR9u4" + "id": "pN3HtDONh5TX" }, "source": [ - "Este exemplo vai usar todas as colunas disponíveis. Se você precisar omitir algumas colunas do conjunto de dados, crie uma lista apenas das colunas que planeja usar e passe-a para o argumento (opcional) `select_columns` do construtor." + "Observação: `Dataset.cache` armazena os dados da primeira época e os reproduz em ordem. Portanto, usar o método `cache` desativa qualquer embaralhamento anterior no pipeline. Abaixo, `Dataset.shuffle` é adicionado novamente após `Dataset.cache`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "S1TzSkUKwsNP" + "id": "r5Jj72MrPbnh" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'class', 'deck', 'alone']\n", + "%%time\n", + "caching = traffic_volume_csv_gz_ds.cache().shuffle(1000)\n", "\n", - "temp_dataset = get_dataset(train_file_path, select_columns=SELECT_COLUMNS)\n", - "\n", - "show_batch(temp_dataset)" + "for i, (batch, label) in enumerate(caching.shuffle(1000).repeat(20)):\n", + " if i % 40 == 0:\n", + " print('.', end='')\n", + "print()" ] }, { "cell_type": "markdown", "metadata": { - "id": "9cryz31lxs3e" + "id": "wN7uUBjmgNZ9" }, "source": [ - "## Pré-processamento dos Dados\n", - "\n", - "Um arquivo CSV pode conter uma variedade de tipos de dados. Normalmente, você deseja converter desses tipos mistos em um vetor de comprimento fixo antes de alimentar os dados em seu modelo.\n", + "Observação: Os arquivos `tf.data.Dataset.snapshot` destinam-se ao armazenamento *temporário* de um dataset durante o uso. Este *não* é um formato para armazenamento de longo prazo. O formato do arquivo é considerado um detalhe interno e não é garantido entre versões do TensorFlow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PHGD1E8ktUvW" + }, + "outputs": [ + + ], + "source": [ + "%%time\n", + "snapshotting = traffic_volume_csv_gz_ds.snapshot('titanic.tfsnap').shuffle(1000)\n", "\n", - "O TensorFlow possui um sistema interno para descrever conversões de entrada comuns: `tf.feature_column`, consulte [este tutorial] (../keras/feature_columns) para detalhes.\n", + "for i, (batch, label) in enumerate(snapshotting.shuffle(1000).repeat(20)):\n", + " if i % 40 == 0:\n", + " print('.', end='')\n", + "print()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fUSSegnMCGRz" + }, + "source": [ + "Se o carregamento de dados for retardado pelo carregamento de arquivos CSV e `Dataset.cache` e `tf.data.Dataset.snapshot` forem insuficientes para seu caso de uso, considere recodificar seus dados num formato mais simplificado." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M0iGXv9pC5kr" + }, + "source": [ + "### Múltiplos arquivos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9FFzHQrCDH4w" + }, + "source": [ + "Todos os exemplos até agora nesta seção poderiam ser realizados facilmente sem `tf.data`. Um lugar onde `tf.data` pode realmente simplificar as coisas é ao lidar com coleções de arquivos.\n", "\n", + "Por exemplo, o dataset de [imagens de fontes de caracteres](https://archive.ics.uci.edu/ml/datasets/Character+Font+Images) é distribuído como uma coleção de arquivos csv, um arquivo por fonte.\n", "\n", - "Você pode pré-processar seus dados usando qualquer ferramenta que desejar (como [nltk] (https://www.nltk.org/) ou [sklearn] (https://scikit-learn.org/stable/)) e apenas passar a saída processada para o TensorFlow.\n", + "![A traffic jam.](https://github.com/tensorflow/docs-l10n/blob/master/site/pt-br/tutorials/load_data/images/csv/fonts.jpg?raw=true)\n", "\n", + "Imagem por Willi Heidelbach do Pixabay\n", "\n", - "A principal vantagem de fazer o pré-processamento dentro do seu modelo é que, quando você exporta o modelo, ele inclui o pré-processamento. Dessa forma, você pode passar os dados brutos diretamente para o seu modelo." + "Baixe o dataset e revise os arquivos contidos nele:" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "9AsbaFmCeJtF" + "id": "RmVknMdJh5ks" }, + "outputs": [ + + ], "source": [ - "### Dados contínuos" + "fonts_zip = tf.keras.utils.get_file(\n", + " 'fonts.zip', \"https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\",\n", + " cache_dir='.', cache_subdir='fonts',\n", + " extract=True)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "Xl0Q0DcfA_rt" + "id": "xsDlMCnyi55e" }, + "outputs": [ + + ], "source": [ - "Se seus dados já estiverem em um formato numérico apropriado, você poderá compactá-los em um vetor antes de transmiti-los ao modelo:" + "import pathlib\n", + "font_csvs = sorted(str(p) for p in pathlib.Path('fonts').glob(\"*.csv\"))\n", + "\n", + "font_csvs[:10]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "4Yfji3J5BMxz" + "id": "lRAEJx9ROAGl" + }, + "outputs": [ + + ], + "source": [ + "len(font_csvs)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "19Udrw9iG-FS" }, - "outputs": [], "source": [ - "SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'parch', 'fare']\n", - "DEFAULTS = [0, 0.0, 0.0, 0.0, 0.0]\n", - "temp_dataset = get_dataset(train_file_path, \n", - " select_columns=SELECT_COLUMNS,\n", - " column_defaults = DEFAULTS)\n", + "Ao lidar com muitos arquivos, você pode passar um `file_pattern` estilo glob para a função `tf.data.experimental.make_csv_dataset`. A ordem dos arquivos é embaralhada a cada iteração.\n", "\n", - "show_batch(temp_dataset)" + "Use o argumento `num_parallel_reads` para definir quantos arquivos são lidos em paralelo e intercalados." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "zEUhI8kZCfq8" + "id": "6TSUNdT6iG58" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "example_batch, labels_batch = next(iter(temp_dataset)) " + "fonts_ds = tf.data.experimental.make_csv_dataset(\n", + " file_pattern = \"fonts/*.csv\",\n", + " batch_size=10, num_epochs=1,\n", + " num_parallel_reads=20,\n", + " shuffle_buffer_size=10000)" ] }, { "cell_type": "markdown", "metadata": { - "id": "IP45_2FbEKzn" + "id": "XMoexinLHYFa" }, "source": [ - "Aqui está uma função simples que agrupará todas as colunas:" + "Esses arquivos CSV têm as imagens achatadas numa única linha. Os nomes das colunas são formatados `r{row}c{column}`. Aqui está o primeiro lote:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "JQ0hNSL8CC3a" + "id": "RmFvBWxxi3pq" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "def pack(features, label):\n", - " return tf.stack(list(features.values()), axis=-1), label" + "for features in fonts_ds.take(1):\n", + " for i, (name, value) in enumerate(features.items()):\n", + " if i>15:\n", + " break\n", + " print(f\"{name:20s}: {value}\")\n", + "print('...')\n", + "print(f\"[total: {len(features)} features]\")" ] }, { "cell_type": "markdown", "metadata": { - "id": "75LA9DisEIoE" + "id": "xrC3sKdeOhb5" }, "source": [ - "Aplique isso a cada elemento do conjunto de dados:" + "#### Opcional: empacotando campos\n", + "\n", + "Você provavelmente não vai querer trabalhar com cada pixel em colunas separadas como esta. Antes de tentar usar este dataset, certifique-se de compactar os pixels em um tensor de imagem.\n", + "\n", + "Aqui está o código que analisa os nomes das colunas para construir imagens para cada exemplo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "VnP2Z2lwCTRl" + "id": "hct5EMEWNyfH" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "packed_dataset = temp_dataset.map(pack)\n", + "import re\n", "\n", - "for features, labels in packed_dataset.take(1):\n", - " print(features.numpy())\n", - " print()\n", - " print(labels.numpy())" + "def make_images(features):\n", + " image = [None]*400\n", + " new_feats = {}\n", + "\n", + " for name, value in features.items():\n", + " match = re.match('r(\\d+)c(\\d+)', name)\n", + " if match:\n", + " image[int(match.group(1))*20+int(match.group(2))] = value\n", + " else:\n", + " new_feats[name] = value\n", + "\n", + " image = tf.stack(image, axis=0)\n", + " image = tf.reshape(image, [20, 20, -1])\n", + " new_feats['image'] = image\n", + "\n", + " return new_feats" ] }, { "cell_type": "markdown", "metadata": { - "id": "1VBvmaFrFU6J" + "id": "61qy8utAwARP" }, "source": [ - "Se você tiver tipos de dados mistos, poderá separar esses campos numéricos simples. A API `tf.feature_column` pode lidar com eles, mas isso gera alguma sobrecarga e deve ser evitado, a menos que seja realmente necessário. Volte para o conjunto de dados misto:" + "Aplique essa função a cada lote no dataset:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "ad-IQ_JPFQge" + "id": "DJnnfIW9baE4" + }, + "outputs": [ + + ], + "source": [ + "fonts_image_ds = fonts_ds.map(make_images)\n", + "\n", + "for features in fonts_image_ds.take(1):\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_ThqrthGwHSm" }, - "outputs": [], "source": [ - "show_batch(raw_train_data)" + "Plote as imagens resultantes:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "HSrYNKKcIdav" + "id": "I5dcey31T_tk" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "example_batch, labels_batch = next(iter(temp_dataset)) " + "from matplotlib import pyplot as plt\n", + "\n", + "plt.figure(figsize=(6,6), dpi=120)\n", + "\n", + "for n in range(9):\n", + " plt.subplot(3,3,n+1)\n", + " plt.imshow(features['image'][..., n])\n", + " plt.title(chr(features['m_label'][n]))\n", + " plt.axis('off')" ] }, { "cell_type": "markdown", "metadata": { - "id": "p5VtThKfGPaQ" + "id": "7-nNR0Nncdd1" }, "source": [ - "Portanto, defina um pré-processador mais geral que selecione uma lista de recursos numéricos e os agrupe em uma única coluna:" + "## Funções de nível inferior" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "5DRishYYGS-m" + "id": "3jiGZeUijJNd" }, - "outputs": [], "source": [ - "class PackNumericFeatures(object):\n", - " def __init__(self, names):\n", - " self.names = names\n", + "Até o momento, este tutorial tem se concentrado nos utilitários de nível mais alto para leitura de dados em formato CSV. Existem outras duas APIs que podem ser úteis para usuários avançados se o seu caso de uso não se enquadrar nos padrões básicos.\n", "\n", - " def __call__(self, features, labels):\n", - " numeric_features = [features.pop(name) for name in self.names]\n", - " numeric_features = [tf.cast(feat, tf.float32) for feat in numeric_features]\n", - " numeric_features = tf.stack(numeric_features, axis=-1)\n", - " features['numeric'] = numeric_features\n", + "- `tf.io.decode_csv`: uma função para processar linhas de texto numa lista de tensores de coluna CSV.\n", + "- `tf.data.experimental.CsvDataset`: um construtor de datasets CSV de nível inferior.\n", "\n", - " return features, labels" + "Esta seção recria a funcionalidade fornecida por `tf.data.experimental.make_csv_dataset`, para demonstrar como essa funcionalidade de nível inferior pode ser usada.\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "1SeZka9AHfqD" + "id": "LL_ixywomOHW" }, - "outputs": [], "source": [ - "NUMERIC_FEATURES = ['age','n_siblings_spouses','parch', 'fare']\n", + "### `tf.io.decode_csv`\n", + "\n", + "Esta função decodifica uma string ou lista de strings em uma lista de colunas.\n", "\n", - "packed_train_data = raw_train_data.map(\n", - " PackNumericFeatures(NUMERIC_FEATURES))\n", + "Ao contrário de `tf.data.experimental.make_csv_dataset` esta função não tenta adivinhar os tipos de dados da coluna. Você especifica os tipos de coluna fornecendo uma lista de `record_defaults` contendo um valor do tipo correto, para cada coluna.\n", "\n", - "packed_test_data = raw_test_data.map(\n", - " PackNumericFeatures(NUMERIC_FEATURES))" + "Para ler os dados do Titanic **como strings** usando `tf.io.decode_csv` você faria:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "wFrw0YobIbUB" + "id": "m1D2C-qdlqeW" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "show_batch(packed_train_data)" + "text = pathlib.Path(titanic_file_path).read_text()\n", + "lines = text.split('\\n')[1:-1]\n", + "\n", + "all_strings = [str()]*10\n", + "all_strings" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "_EPUS8fPLUb1" + "id": "9W4UeJYyHPx5" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "example_batch, labels_batch = next(iter(packed_train_data)) " + "features = tf.io.decode_csv(lines, record_defaults=all_strings) \n", + "\n", + "for f in features:\n", + " print(f\"type: {f.dtype.name}, shape: {f.shape}\")" ] }, { "cell_type": "markdown", "metadata": { - "id": "o2maE8d2ijsq" + "id": "j8TaHSQFoQL4" }, "source": [ - "#### Normalização dos dados\n", - "\n", - "Dados contínuos sempre devem ser normalizados." + "Para processá-los com seus tipos reais, crie uma lista de `record_defaults` dos tipos correspondentes: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "WKT1ASWpwH46" + "id": "rzUjR59yoUe1" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "import pandas as pd\n", - "desc = pd.read_csv(train_file_path)[NUMERIC_FEATURES].describe()\n", - "desc" + "print(lines[0])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "cHHstcKPsMXM" + "id": "7sPTunxwoeWU" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "MEAN = np.array(desc.T['mean'])\n", - "STD = np.array(desc.T['std'])" + "titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()]\n", + "titanic_types" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "REKqO_xHPNx0" + "id": "n3NlViCzoB7F" + }, + "outputs": [ + + ], + "source": [ + "features = tf.io.decode_csv(lines, record_defaults=titanic_types) \n", + "\n", + "for f in features:\n", + " print(f\"type: {f.dtype.name}, shape: {f.shape}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "m-LkTUTnpn2P" }, - "outputs": [], "source": [ - "def normalize_numeric_data(data, mean, std):\n", - " # Center the data\n", - " return (data-mean)/std\n" + "Observação: É mais eficiente chamar `tf.io.decode_csv` em grandes lotes de linhas do que em linhas individuais de texto CSV." ] }, { "cell_type": "markdown", "metadata": { - "id": "VPsoMUgRCpUM" + "id": "Yp1UItJmqGqw" }, "source": [ - "Agora crie uma coluna numérica. A API `tf.feature_columns.numeric_column` aceita um argumento `normalizer_fn`, que será executado em cada lote.\n", + "### `tf.data.experimental.CsvDataset`\n", "\n", - "Ligue o `MEAN` e o` STD` ao normalizador fn usando [`functools.partial`] (https://docs.python.org/3/library/functools.html#functools.partial)" + "A classe `tf.data.experimental.CsvDataset` fornece uma interface CSV `Dataset` mínima sem os recursos convenientes da função `tf.data.experimental.make_csv_dataset`: análise de cabeçalho de coluna, inferência de tipo de coluna, embaralhamento automático, intercalação de arquivos.\n", + "\n", + "Este construtor usa `record_defaults` da mesma forma que `tf.io.decode_csv`:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "Bw0I35xRS57V" + "id": "9OzZLp3krP-t" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "# Veja o que você acabou de criar.\n", - "normalizer = functools.partial(normalize_numeric_data, mean=MEAN, std=STD)\n", + "simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True)\n", "\n", - "numeric_column = tf.feature_column.numeric_column('numeric', normalizer_fn=normalizer, shape=[len(NUMERIC_FEATURES)])\n", - "numeric_columns = [numeric_column]\n", - "numeric_column" + "for example in simple_titanic.take(1):\n", + " print([e.numpy() for e in example])" ] }, { "cell_type": "markdown", "metadata": { - "id": "HZxcHXc6LCa7" + "id": "_HBmfI-Ks7dw" }, "source": [ - "Ao treinar o modelo, inclua esta coluna de característica para selecionar e centralizar este bloco de dados numéricos:" + "O código acima é praticamente equivalente a:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "b61NM76Ot_kb" + "id": "E5O5d69Yq7gG" + }, + "outputs": [ + + ], + "source": [ + "def decode_titanic_line(line):\n", + " return tf.io.decode_csv(line, titanic_types)\n", + "\n", + "manual_titanic = (\n", + " # Load the lines of text\n", + " tf.data.TextLineDataset(titanic_file_path)\n", + " # Skip the header row.\n", + " .skip(1)\n", + " # Decode the line.\n", + " .map(decode_titanic_line)\n", + ")\n", + "\n", + "for example in manual_titanic.take(1):\n", + " print([e.numpy() for e in example])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5R3ralsnt2AC" }, - "outputs": [], "source": [ - "example_batch['numeric']" + "#### Múltiplos arquivos\n", + "\n", + "Para processar o dataset de fontes usando `tf.data.experimental.CsvDataset`, primeiro você precisa determinar os tipos de coluna para `record_defaults`. Comece inspecionando a primeira linha de um arquivo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "j-r_4EAJAZoI" + "id": "3tlFOTjCvAI5" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "numeric_layer = tf.keras.layers.DenseFeatures(numeric_columns)\n", - "numeric_layer(example_batch).numpy()" + "font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1]\n", + "print(font_line)" ] }, { "cell_type": "markdown", "metadata": { - "id": "M37oD2VcCO4R" + "id": "etyGu8K_ySRz" + }, + "source": [ + "Apenas os dois primeiros campos são strings, os restantes são inteiros ou flutuantes, e você pode obter o número total de características contando as vírgulas:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "crgZZn0BzkSB" }, + "outputs": [ + + ], "source": [ - "A normalização baseada em média usada aqui requer conhecer os meios de cada coluna antes do tempo." + "num_font_features = font_line.count(',')+1\n", + "font_column_types = [str(), str()] + [float()]*(num_font_features-2)" ] }, { "cell_type": "markdown", "metadata": { - "id": "tSyrkSQwYHKi" + "id": "YeK2Pw540RNj" }, "source": [ - "### Dados categóricos\n", - "\n", - "Algumas das colunas nos dados CSV são colunas categóricas. Ou seja, o conteúdo deve ser um dentre um conjunto limitado de opções.\n", - "\n", - "Use a API `tf.feature_column` para criar uma coleção com uma `tf.feature_column.indicator_column` para cada coluna categórica.\n" + "O construtor `tf.data.experimental.CsvDataset` pode receber uma lista de arquivos de entrada, mas vai lê-los sequencialmente. O primeiro arquivo na lista de CSVs é `AGENCY.csv`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "mWDniduKMw-C" + "id": "_SvL5Uvl0r0N" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "CATEGORIES = {\n", - " 'sex': ['male', 'female'],\n", - " 'class' : ['First', 'Second', 'Third'],\n", - " 'deck' : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],\n", - " 'embark_town' : ['Cherbourg', 'Southhampton', 'Queenstown'],\n", - " 'alone' : ['y', 'n']\n", - "}\n" + "font_csvs[0]" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "kkxLdrsLwHPT" + "id": "EfAX3G8Xywy6" }, - "outputs": [], "source": [ - "categorical_columns = []\n", - "for feature, vocab in CATEGORIES.items():\n", - " cat_col = tf.feature_column.categorical_column_with_vocabulary_list(\n", - " key=feature, vocabulary_list=vocab)\n", - " categorical_columns.append(tf.feature_column.indicator_column(cat_col))" + "Assim, ao passar a lista de arquivos para `CsvDataset`, os registros de `AGENCY.csv` são lidos primeiro:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "H18CxpHY_Nma" + "id": "Gtr1E66VmBqj" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "# Veja o que você acabou de criar.\n", - "categorical_columns" + "simple_font_ds = tf.data.experimental.CsvDataset(\n", + " font_csvs, \n", + " record_defaults=font_column_types, \n", + " header=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "p7mACuOsArUH" + "id": "k750Mgq4yt_o" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "categorical_layer = tf.keras.layers.DenseFeatures(categorical_columns)\n", - "print(categorical_layer(example_batch).numpy()[0])" + "for row in simple_font_ds.take(10):\n", + " print(row[0].numpy())" ] }, { "cell_type": "markdown", "metadata": { - "id": "R7-1QG99_1sN" + "id": "NiqWKQV21FrE" }, "source": [ - "Isso fará parte de uma entrada de processamento de dados posteriormente, quando você construir o modelo." + "Para intercalar múltiplos arquivos, use `Dataset.interleave`.\n", + "\n", + "Eis um dataset inicial que contém os nomes dos arquivos CSV: " ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "kPWkC4_1l3IG" + "id": "t9dS3SNb23W8" }, + "outputs": [ + + ], "source": [ - "### Camada combinada de pré-processamento" + "font_files = tf.data.Dataset.list_files(\"fonts/*.csv\")" ] }, { "cell_type": "markdown", "metadata": { - "id": "R3QAjo1qD4p9" + "id": "TNiLHMXpzHy5" }, "source": [ - "Adicione as duas coleções de colunas de recursos e passe-as para um `tf.keras.layers.DenseFeatures` para criar uma camada de entrada que extrairá e pré-processará os dois tipos de entrada:" + "Isto embaralha os nomes dos arquivos em cada época:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "3-OYK7GnaH0r" + "id": "zNd-TYyNzIgg" + }, + "outputs": [ + + ], + "source": [ + "print('Epoch 1:')\n", + "for f in list(font_files)[:5]:\n", + " print(\" \", f.numpy())\n", + "print(' ...')\n", + "print()\n", + "\n", + "print('Epoch 2:')\n", + "for f in list(font_files)[:5]:\n", + " print(\" \", f.numpy())\n", + "print(' ...')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "B0QB1PtU3WAN" }, - "outputs": [], "source": [ - "preprocessing_layer = tf.keras.layers.DenseFeatures(categorical_columns+numeric_columns)" + "O método `interleave` usa um `map_func` que cria um `Dataset` filho para cada elemento do `Dataset` pai.\n", + "\n", + "Aqui, você vai querer criar um `tf.data.experimental.CsvDataset` a partir de cada elemento do dataset de arquivos:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "m7_U_K0UMSVS" + "id": "QWp4rH0Q4uPh" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "print(preprocessing_layer(example_batch).numpy()[0])" + "def make_font_csv_ds(path):\n", + " return tf.data.experimental.CsvDataset(\n", + " path, \n", + " record_defaults=font_column_types, \n", + " header=True)" ] }, { "cell_type": "markdown", "metadata": { - "id": "DlF_omQqtnOP" + "id": "VxRGdLMB5nRF" }, "source": [ - "## Construir o modelo" + "O `Dataset` retornado por interleave retorna elementos percorrendo vários objetos `Dataset` filhos. Observe, abaixo, como o dataset percorre três arquivos de fonte (`cycle_length=3`):" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "lQoFh16LxtT_" + "id": "OePMNF_x1_Cc" }, + "outputs": [ + + ], "source": [ - "Crie um `tf.keras.Sequential`, começando com o `preprocessing_layer`." + "font_rows = font_files.interleave(make_font_csv_ds,\n", + " cycle_length=3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "3mSGsHTFPvFo" + "id": "UORIGWLy54-E" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "model = tf.keras.Sequential([\n", - " preprocessing_layer,\n", - " tf.keras.layers.Dense(128, activation='relu'),\n", - " tf.keras.layers.Dense(128, activation='relu'),\n", - " tf.keras.layers.Dense(1),\n", - "])\n", + "fonts_dict = {'font_name':[], 'character':[]}\n", + "\n", + "for row in font_rows.take(10):\n", + " fonts_dict['font_name'].append(row[0].numpy().decode())\n", + " fonts_dict['character'].append(chr(row[2].numpy()))\n", "\n", - "model.compile(\n", - " loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", - " optimizer='adam',\n", - " metrics=['accuracy'])" + "pd.DataFrame(fonts_dict)" ] }, { "cell_type": "markdown", "metadata": { - "id": "hPdtI2ie0lEZ" + "id": "mkKZa_HX8zAm" }, "source": [ - "## Treinar, avaliar, e prever" + "#### Desempenho\n" ] }, { "cell_type": "markdown", "metadata": { - "id": "8gvw1RE9zXkD" + "id": "8BtGHraUApdJ" }, "source": [ - "Agora o modelo pode ser instanciado e treinado." + "Anteriormente, foi observado que `tf.io.decode_csv` é mais eficiente quando executado num lote de strings.\n", + "\n", + "É possível tomar proveito desse fato, ao usar lotes grandes, para melhorar o desempenho do carregamento de CSV (mas tente primeiro [armazenar em cache](#caching))." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "d35zWMH7MDL1" + }, + "source": [ + "Com o carregador integrado 20 lotes de 2.048 exemplos levam cerca de 17s. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "sW-4XlLeEQ2B" + "id": "ieUVAPryjpJS" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "train_data = packed_train_data.shuffle(500)\n", - "test_data = packed_test_data" + "BATCH_SIZE=2048\n", + "fonts_ds = tf.data.experimental.make_csv_dataset(\n", + " file_pattern = \"fonts/*.csv\",\n", + " batch_size=BATCH_SIZE, num_epochs=1,\n", + " num_parallel_reads=100)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "Q_nm28IzNDTO" + "id": "MUC2KW4LkQIz" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "model.fit(train_data, epochs=20)" + "%%time\n", + "for i,batch in enumerate(fonts_ds.take(20)):\n", + " print('.',end='')\n", + "\n", + "print()" ] }, { "cell_type": "markdown", "metadata": { - "id": "QyDMgBurzqQo" + "id": "5lhnh6rZEDS2" }, "source": [ - "Depois que o modelo é treinado, você pode verificar sua acurácia no conjunto `test_data`." + "Passar **lotes de linhas de texto** para `decode_csv` é mais rápido, em cerca de 5s:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "eB3R3ViVONOp" + "id": "4XbPZV1okVF9" }, - "outputs": [], + "outputs": [ + + ], "source": [ - "test_loss, test_accuracy = model.evaluate(test_data)\n", + "fonts_files = tf.data.Dataset.list_files(\"fonts/*.csv\")\n", + "fonts_lines = fonts_files.interleave(\n", + " lambda fname:tf.data.TextLineDataset(fname).skip(1), \n", + " cycle_length=100).batch(BATCH_SIZE)\n", "\n", - "print('\\n\\nTest Loss {}, Test Accuracy {}'.format(test_loss, test_accuracy))" + "fonts_fast = fonts_lines.map(lambda x: tf.io.decode_csv(x, record_defaults=font_column_types))" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "id": "sTrn_pD90gdJ" + "id": "te9C2km-qO8W" }, + "outputs": [ + + ], "source": [ - "Use `tf.keras.Model.predict` para inferir rótulos em um lote ou em um conjunto de dados de lotes." + "%%time\n", + "for i,batch in enumerate(fonts_fast.take(20)):\n", + " print('.',end='')\n", + "\n", + "print()" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "id": "Qwcx74F3ojqe" + "id": "aebC1plsMeOi" }, - "outputs": [], "source": [ - "predictions = model.predict(test_data)\n", + "Para outro exemplo de como aumentar o desempenho do CSV usando lotes grandes, consulte o [tutorial sobre overfit e underfit](../keras/overfit_and_underfit.ipynb).\n", "\n", - "# Mostrar alguns resultados\n", - "for prediction, survived in zip(predictions[:10], list(test_data)[0][1][:10]):\n", - " print(\"Predicted survival: {:.2%}\".format(prediction[0]),\n", - " \" | Actual outcome: \",\n", - " (\"SURVIVED\" if bool(survived) else \"DIED\"))\n" + "Esse tipo de abordagem pode funcionar, mas considere outras opções como `Dataset.cache` e `tf.data.Dataset.snapshot` ou recodificar seus dados num formato mais simplificado." ] } ], "metadata": { "colab": { - "collapsed_sections": [], "name": "csv.ipynb", "toc_visible": true }, diff --git a/site/pt-br/tutorials/video/video_classification.ipynb b/site/pt-br/tutorials/video/video_classification.ipynb new file mode 100644 index 0000000000..a394449aea --- /dev/null +++ b/site/pt-br/tutorials/video/video_classification.ipynb @@ -0,0 +1,1107 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "TBFXQGKYUc4X" + }, + "source": [ + "##### Copyright 2022 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "1z4xy2gTUc4a" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KwQtSOz0VrVX" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Ver fonte no GitHub\n", + " Baixar notebook\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L2MHy42s5wl6" + }, + "source": [ + "# Classificação de vídeos com uma rede neural convolucional 3D\n", + "\n", + "Este tutorial demonstra o treinamento de uma rede neural convolucional (CNN) 3D para classificação de vídeo usando o dataset de reconhecimento de ações [UCF101](https://www.crcv.ucf.edu/data/UCF101.php). Uma CNN 3D usa um filtro tridimensional para realizar convoluções. O kernel é capaz de deslizar em três direções, enquanto que numa CNN 2D ele pode deslizar em duas dimensões. O modelo é baseado no trabalho publicado em [A Closer Look at Spatiotemporal Convolutions for Action Recognition](https://arxiv.org/abs/1711.11248v3) por D. Tran et al. (2017). Neste tutorial, você irá:\n", + "\n", + "- Construir um pipeline de entrada\n", + "- Construir um modelo de rede neural convolucional 3D com conexões residuais usando a API funcional Keras\n", + "- Treinar o modelo\n", + "- Avaliar e testar o modelo\n", + "\n", + "Este tutorial de classificação de vídeo é a segunda parte de uma série de tutoriais em vídeo do TensorFlow. Aqui estão os outros três tutoriais:\n", + "\n", + "- [Carregando dados de vídeo](https://www.tensorflow.org/tutorials/load_data/video): Este tutorial explica grande parte do código usado neste documento.\n", + "- [MoViNet para o reconhecimento de ações de streaming](https://www.tensorflow.org/hub/tutorials/movinet): conheça os modelos MoViNet disponíveis no TF Hub.\n", + "- [Aprendizado por transferência para a classificação de vídeos com MoViNet](https://www.tensorflow.org/tutorials/video/transfer_learning_with_movinet): este tutorial explica como usar um modelo de classificação de vídeos pré-treinado em um dataset diferente com o dataset UCF-101." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_Ih_df2q0kw4" + }, + "source": [ + "## Configuração\n", + "\n", + "Comece instalando e importando algumas bibliotecas necessárias, incluindo: [remotezip](https://github.com/gtsystem/python-remotezip) para inspecionar o conteúdo de um arquivo ZIP, [tqdm](https://github.com/tqdm/tqdm) para usar uma barra de progresso, [OpenCV](https://opencv.org/) para processar arquivos de vídeo, [einops](https://github.com/arogozhnikov/einops/tree/master/docs) para realizar operações de tensor mais complexas e [`tensorflow_docs`](https://github.com/tensorflow/docs/tree/master/tools/tensorflow_docs) para incorporar dados em um notebook Jupyter.\n", + "\n", + "**Observação**: use o TensorFlow 2.10 para executar este tutorial. Versões acima do TensorFlow 2.10 podem não ser executadas com sucesso." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KEbL4Mwi01PV" + }, + "outputs": [ + + ], + "source": [ + "!pip install remotezip tqdm opencv-python einops \n", + "# Install TensorFlow 2.10\n", + "!pip install tensorflow==2.10.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gg0otuqb0hIf" + }, + "outputs": [ + + ], + "source": [ + "import tqdm\n", + "import random\n", + "import pathlib\n", + "import itertools\n", + "import collections\n", + "\n", + "import cv2\n", + "import einops\n", + "import numpy as np\n", + "import remotezip as rz\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import tensorflow as tf\n", + "import keras\n", + "from keras import layers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ctk9A57-6ABq" + }, + "source": [ + "## Carregamento e pré-processamento dos dados de vídeo\n", + "\n", + "A célula oculta abaixo define funções auxiliares para baixar uma fatia de dados do dataset UCF-101 e carregá-los num `tf.data.Dataset`. Você pode aprender mais sobre os passos específicos de pré-processamento no [tutorial Carregando dados de vídeo](../load_data/video.ipynb), que apresenta instruções detalhadas sobre esse código.\n", + "\n", + "A classe `FrameGenerator` no final do bloco oculto é o utilitário mais importante que temos aqui, pois cria um objeto iterável que pode alimentar dados no pipeline de dados do TensorFlow. Especificamente, essa classe contém um gerador Python que carrega os quadros do vídeo juntamente com seu rótulo codificado. A função geradora (`__call__`) gera a array de quadros produzida por `frames_from_video_file` e um vetor com codificação one-hot do rótulo associado ao conjunto de quadros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nB2aOTU35r9_" + }, + "outputs": [ + + ], + "source": [ + "#@title\n", + "\n", + "def list_files_per_class(zip_url):\n", + " \"\"\"\n", + " List the files in each class of the dataset given the zip URL.\n", + "\n", + " Args:\n", + " zip_url: URL from which the files can be unzipped. \n", + "\n", + " Return:\n", + " files: List of files in each of the classes.\n", + " \"\"\"\n", + " files = []\n", + " with rz.RemoteZip(URL) as zip:\n", + " for zip_info in zip.infolist():\n", + " files.append(zip_info.filename)\n", + " return files\n", + "\n", + "def get_class(fname):\n", + " \"\"\"\n", + " Retrieve the name of the class given a filename.\n", + "\n", + " Args:\n", + " fname: Name of the file in the UCF101 dataset.\n", + "\n", + " Return:\n", + " Class that the file belongs to.\n", + " \"\"\"\n", + " return fname.split('_')[-3]\n", + "\n", + "def get_files_per_class(files):\n", + " \"\"\"\n", + " Retrieve the files that belong to each class. \n", + "\n", + " Args:\n", + " files: List of files in the dataset.\n", + "\n", + " Return:\n", + " Dictionary of class names (key) and files (values).\n", + " \"\"\"\n", + " files_for_class = collections.defaultdict(list)\n", + " for fname in files:\n", + " class_name = get_class(fname)\n", + " files_for_class[class_name].append(fname)\n", + " return files_for_class\n", + "\n", + "def download_from_zip(zip_url, to_dir, file_names):\n", + " \"\"\"\n", + " Download the contents of the zip file from the zip URL.\n", + "\n", + " Args:\n", + " zip_url: Zip URL containing data.\n", + " to_dir: Directory to download data to.\n", + " file_names: Names of files to download.\n", + " \"\"\"\n", + " with rz.RemoteZip(zip_url) as zip:\n", + " for fn in tqdm.tqdm(file_names):\n", + " class_name = get_class(fn)\n", + " zip.extract(fn, str(to_dir / class_name))\n", + " unzipped_file = to_dir / class_name / fn\n", + "\n", + " fn = pathlib.Path(fn).parts[-1]\n", + " output_file = to_dir / class_name / fn\n", + " unzipped_file.rename(output_file,)\n", + "\n", + "def split_class_lists(files_for_class, count):\n", + " \"\"\"\n", + " Returns the list of files belonging to a subset of data as well as the remainder of\n", + " files that need to be downloaded.\n", + " \n", + " Args:\n", + " files_for_class: Files belonging to a particular class of data.\n", + " count: Number of files to download.\n", + "\n", + " Return:\n", + " split_files: Files belonging to the subset of data.\n", + " remainder: Dictionary of the remainder of files that need to be downloaded.\n", + " \"\"\"\n", + " split_files = []\n", + " remainder = {}\n", + " for cls in files_for_class:\n", + " split_files.extend(files_for_class[cls][:count])\n", + " remainder[cls] = files_for_class[cls][count:]\n", + " return split_files, remainder\n", + "\n", + "def download_ufc_101_subset(zip_url, num_classes, splits, download_dir):\n", + " \"\"\"\n", + " Download a subset of the UFC101 dataset and split them into various parts, such as\n", + " training, validation, and test. \n", + "\n", + " Args:\n", + " zip_url: Zip URL containing data.\n", + " num_classes: Number of labels.\n", + " splits: Dictionary specifying the training, validation, test, etc. (key) division of data \n", + " (value is number of files per split).\n", + " download_dir: Directory to download data to.\n", + "\n", + " Return:\n", + " dir: Posix path of the resulting directories containing the splits of data.\n", + " \"\"\"\n", + " files = list_files_per_class(zip_url)\n", + " for f in files:\n", + " tokens = f.split('/')\n", + " if len(tokens) <= 2:\n", + " files.remove(f) # Remove that item from the list if it does not have a filename\n", + " \n", + " files_for_class = get_files_per_class(files)\n", + "\n", + " classes = list(files_for_class.keys())[:num_classes]\n", + "\n", + " for cls in classes:\n", + " new_files_for_class = files_for_class[cls]\n", + " random.shuffle(new_files_for_class)\n", + " files_for_class[cls] = new_files_for_class\n", + " \n", + " # Only use the number of classes you want in the dictionary\n", + " files_for_class = {x: files_for_class[x] for x in list(files_for_class)[:num_classes]}\n", + "\n", + " dirs = {}\n", + " for split_name, split_count in splits.items():\n", + " print(split_name, \":\")\n", + " split_dir = download_dir / split_name\n", + " split_files, files_for_class = split_class_lists(files_for_class, split_count)\n", + " download_from_zip(zip_url, split_dir, split_files)\n", + " dirs[split_name] = split_dir\n", + "\n", + " return dirs\n", + "\n", + "def format_frames(frame, output_size):\n", + " \"\"\"\n", + " Pad and resize an image from a video.\n", + " \n", + " Args:\n", + " frame: Image that needs to resized and padded. \n", + " output_size: Pixel size of the output frame image.\n", + "\n", + " Return:\n", + " Formatted frame with padding of specified output size.\n", + " \"\"\"\n", + " frame = tf.image.convert_image_dtype(frame, tf.float32)\n", + " frame = tf.image.resize_with_pad(frame, *output_size)\n", + " return frame\n", + "\n", + "def frames_from_video_file(video_path, n_frames, output_size = (224,224), frame_step = 15):\n", + " \"\"\"\n", + " Creates frames from each video file present for each category.\n", + "\n", + " Args:\n", + " video_path: File path to the video.\n", + " n_frames: Number of frames to be created per video file.\n", + " output_size: Pixel size of the output frame image.\n", + "\n", + " Return:\n", + " An NumPy array of frames in the shape of (n_frames, height, width, channels).\n", + " \"\"\"\n", + " # Read each video frame by frame\n", + " result = []\n", + " src = cv2.VideoCapture(str(video_path)) \n", + "\n", + " video_length = src.get(cv2.CAP_PROP_FRAME_COUNT)\n", + "\n", + " need_length = 1 + (n_frames - 1) * frame_step\n", + "\n", + " if need_length > video_length:\n", + " start = 0\n", + " else:\n", + " max_start = video_length - need_length\n", + " start = random.randint(0, max_start + 1)\n", + "\n", + " src.set(cv2.CAP_PROP_POS_FRAMES, start)\n", + " # ret is a boolean indicating whether read was successful, frame is the image itself\n", + " ret, frame = src.read()\n", + " result.append(format_frames(frame, output_size))\n", + "\n", + " for _ in range(n_frames - 1):\n", + " for _ in range(frame_step):\n", + " ret, frame = src.read()\n", + " if ret:\n", + " frame = format_frames(frame, output_size)\n", + " result.append(frame)\n", + " else:\n", + " result.append(np.zeros_like(result[0]))\n", + " src.release()\n", + " result = np.array(result)[..., [2, 1, 0]]\n", + "\n", + " return result\n", + "\n", + "class FrameGenerator:\n", + " def __init__(self, path, n_frames, training = False):\n", + " \"\"\" Returns a set of frames with their associated label. \n", + "\n", + " Args:\n", + " path: Video file paths.\n", + " n_frames: Number of frames. \n", + " training: Boolean to determine if training dataset is being created.\n", + " \"\"\"\n", + " self.path = path\n", + " self.n_frames = n_frames\n", + " self.training = training\n", + " self.class_names = sorted(set(p.name for p in self.path.iterdir() if p.is_dir()))\n", + " self.class_ids_for_name = dict((name, idx) for idx, name in enumerate(self.class_names))\n", + "\n", + " def get_files_and_class_names(self):\n", + " video_paths = list(self.path.glob('*/*.avi'))\n", + " classes = [p.parent.name for p in video_paths] \n", + " return video_paths, classes\n", + "\n", + " def __call__(self):\n", + " video_paths, classes = self.get_files_and_class_names()\n", + "\n", + " pairs = list(zip(video_paths, classes))\n", + "\n", + " if self.training:\n", + " random.shuffle(pairs)\n", + "\n", + " for path, name in pairs:\n", + " video_frames = frames_from_video_file(path, self.n_frames) \n", + " label = self.class_ids_for_name[name] # Encode labels\n", + " yield video_frames, label" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OYY7PkdJFM4Z" + }, + "outputs": [ + + ], + "source": [ + "URL = 'https://storage.googleapis.com/thumos14_files/UCF101_videos.zip'\n", + "download_dir = pathlib.Path('./UCF101_subset/')\n", + "subset_paths = download_ufc_101_subset(URL, \n", + " num_classes = 10, \n", + " splits = {\"train\": 30, \"val\": 10, \"test\": 10},\n", + " download_dir = download_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "C0O3ttIzpFZJ" + }, + "source": [ + "Crie os datasets de treinamento, validação e teste (`train_ds` , `val_ds` e `test_ds`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "lq86IyGDJjTX" + }, + "outputs": [ + + ], + "source": [ + "n_frames = 10\n", + "batch_size = 8\n", + "\n", + "output_signature = (tf.TensorSpec(shape = (None, None, None, 3), dtype = tf.float32),\n", + " tf.TensorSpec(shape = (), dtype = tf.int16))\n", + "\n", + "train_ds = tf.data.Dataset.from_generator(FrameGenerator(subset_paths['train'], n_frames, training=True),\n", + " output_signature = output_signature)\n", + "\n", + "\n", + "# Batch the data\n", + "train_ds = train_ds.batch(batch_size)\n", + "\n", + "val_ds = tf.data.Dataset.from_generator(FrameGenerator(subset_paths['val'], n_frames),\n", + " output_signature = output_signature)\n", + "val_ds = val_ds.batch(batch_size)\n", + "\n", + "test_ds = tf.data.Dataset.from_generator(FrameGenerator(subset_paths['test'], n_frames),\n", + " output_signature = output_signature)\n", + "\n", + "test_ds = test_ds.batch(batch_size)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nzogoGA4pQW0" + }, + "source": [ + "## Criação do modelo\n", + "\n", + "O seguinte modelo de rede neural convolucional 3D é baseado no artigo [A Closer Look at Spatiotemporal Convolutions for Action Recognition](https://arxiv.org/abs/1711.11248v3) de D. Tran et al. (2017). O artigo compara várias versões de ResNets 3D. Em vez de operar em uma única imagem com dimensões `(height, width)`, como os ResNets padrão, estes operam no volume do vídeo `(time, height, width)`. A abordagem mais óbvia para este problema seria substituir cada convolução 2D (`layers.Conv2D`) por uma convolução 3D (`layers.Conv3D`).\n", + "\n", + "Este tutorial usa uma convolução (2 + 1)D com [conexões residuais](https://arxiv.org/abs/1512.03385). A convolução (2 + 1)D permite a decomposição das dimensões espacial e temporal, criando assim dois passos distintos. Uma vantagem desta abordagem é que a fatoração das convoluções em dimensões espaciais e temporais economiza parâmetros.\n", + "\n", + "Para cada local de saída, uma convolução 3D combina todos os vetores de um patch 3D do volume para criar um vetor no volume de saída.\n", + "\n", + "![3D convolutions](https://www.tensorflow.org/images/tutorials/video/3DCNN.png)\n", + "\n", + "Esta operação leva `time * height * width * channels` e produz saídas `channels` (assumindo que o número de canais de entrada e saída são iguais. Portanto, uma camada de convolução 3D com um tamanho de kernel de `(3 x 3 x 3)` precisaria de uma matriz de pesos com `27 * channels ** 2` entradas. O artigo de referência descobriu que uma abordagem mais eficaz e eficiente era fatorar a convolução. Em vez de uma única convolução 3D para processar as dimensões de tempo e espaço, eles propuseram uma convolução \"(2+1 )D\" que processa as dimensões de espaço e tempo separadamente. A figura abaixo mostra as convoluções espaciais e temporais fatoradas de uma convolução (2 + 1)D.\n", + "\n", + "![(2+1)D convolutions](https://www.tensorflow.org/images/tutorials/video/2plus1CNN.png)\n", + "\n", + "A principal vantagem desta abordagem é que ela reduz o número de parâmetros. Na convolução (2 + 1)D, a convolução espacial recebe dados da forma `(1, width, height)`, enquanto a convolução temporal recebe dados da forma `(time, 1, 1)`. Por exemplo, uma convolução (2 + 1)D com tamanho de kernel `(3 x 3 x 3)` precisaria de matrizes de peso de tamanho `(9 * channels**2) + (3 * channels**2)`, menos da metade da convolução 3D completa. Este tutorial implementa (2 + 1)D ResNet18, onde cada convolução na resnet é substituída por uma convolução (2+1)D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GZcB_7dg-EZJ" + }, + "outputs": [ + + ], + "source": [ + "# Define the dimensions of one frame in the set of frames created\n", + "HEIGHT = 224\n", + "WIDTH = 224" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yD_sDIBlNu7K" + }, + "outputs": [ + + ], + "source": [ + "class Conv2Plus1D(keras.layers.Layer):\n", + " def __init__(self, filters, kernel_size, padding):\n", + " \"\"\"\n", + " A sequence of convolutional layers that first apply the convolution operation over the\n", + " spatial dimensions, and then the temporal dimension. \n", + " \"\"\"\n", + " super().__init__()\n", + " self.seq = keras.Sequential([ \n", + " # Spatial decomposition\n", + " layers.Conv3D(filters=filters,\n", + " kernel_size=(1, kernel_size[1], kernel_size[2]),\n", + " padding=padding),\n", + " # Temporal decomposition\n", + " layers.Conv3D(filters=filters, \n", + " kernel_size=(kernel_size[0], 1, 1),\n", + " padding=padding)\n", + " ])\n", + " \n", + " def call(self, x):\n", + " return self.seq(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "I-fCAddqEORZ" + }, + "source": [ + "Um modelo ResNet é feito a partir de uma sequência de blocos residuais. Um bloco residual possui duas ramificações. O ramo principal realiza o cálculo, mas dificulta o fluxo dos gradientes. A ramificação residual ignora o cálculo principal e geralmente apenas adiciona a entrada à saída da ramificação principal. Os gradientes fluem facilmente através deste ramo. Portanto, um caminho fácil da função de perda para qualquer ramo principal do bloco residual estará presente. Isto evita o problema do sumiço do gradiente.\n", + "\n", + "Crie a ramificação principal do bloco residual com a seguinte classe. Em contraste com a estrutura ResNet padrão, esta usa a camada `Conv2Plus1D` personalizada em vez de `layers.Conv2D`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tjxAKHwn6mTJ" + }, + "outputs": [ + + ], + "source": [ + "class ResidualMain(keras.layers.Layer):\n", + " \"\"\"\n", + " Residual block of the model with convolution, layer normalization, and the\n", + " activation function, ReLU.\n", + " \"\"\"\n", + " def __init__(self, filters, kernel_size):\n", + " super().__init__()\n", + " self.seq = keras.Sequential([\n", + " Conv2Plus1D(filters=filters,\n", + " kernel_size=kernel_size,\n", + " padding='same'),\n", + " layers.LayerNormalization(),\n", + " layers.ReLU(),\n", + " Conv2Plus1D(filters=filters, \n", + " kernel_size=kernel_size,\n", + " padding='same'),\n", + " layers.LayerNormalization()\n", + " ])\n", + " \n", + " def call(self, x):\n", + " return self.seq(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CevmZ9qsdpWC" + }, + "source": [ + "Para adicionar o ramo residual ao ramo principal ele precisa ter o mesmo tamanho. A camada `Project` abaixo trata dos casos em que o número de canais é alterado na ramificação. No caso em particular, é adicionada uma sequência de camadas densamente conectadas seguida de normalização. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "znrk5BrL6kuq" + }, + "outputs": [ + + ], + "source": [ + "class Project(keras.layers.Layer):\n", + " \"\"\"\n", + " Project certain dimensions of the tensor as the data is passed through different \n", + " sized filters and downsampled. \n", + " \"\"\"\n", + " def __init__(self, units):\n", + " super().__init__()\n", + " self.seq = keras.Sequential([\n", + " layers.Dense(units),\n", + " layers.LayerNormalization()\n", + " ])\n", + "\n", + " def call(self, x):\n", + " return self.seq(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "S8zycXGvfnak" + }, + "source": [ + "Use `add_residual_block` para introduzir uma conexão de salto entre as camadas do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "urjVgqvw-TlB" + }, + "outputs": [ + + ], + "source": [ + "def add_residual_block(input, filters, kernel_size):\n", + " \"\"\"\n", + " Add residual blocks to the model. If the last dimensions of the input data\n", + " and filter size does not match, project it such that last dimension matches.\n", + " \"\"\"\n", + " out = ResidualMain(filters, \n", + " kernel_size)(input)\n", + " \n", + " res = input\n", + " # Using the Keras functional APIs, project the last dimension of the tensor to\n", + " # match the new filter size\n", + " if out.shape[-1] != input.shape[-1]:\n", + " res = Project(out.shape[-1])(res)\n", + "\n", + " return layers.add([res, out])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bozog_0hFKrD" + }, + "source": [ + "O redimensionamento do vídeo é necessário para realizar a redução da resolução dos dados. Em particular, a redução da resolução dos quadros de vídeo permite que o modelo examine partes específicas dos quadros para detectar padrões que podem ser específicos de uma determinada ação. Através da redução da resolução, informações não essenciais podem ser descartadas. Além disso, o redimensionamento do vídeo permitirá a redução da dimensionalidade e garantirá, portanto, um processamento mais rápido através do modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lQOWuc2I-QqK" + }, + "outputs": [ + + ], + "source": [ + "class ResizeVideo(keras.layers.Layer):\n", + " def __init__(self, height, width):\n", + " super().__init__()\n", + " self.height = height\n", + " self.width = width\n", + " self.resizing_layer = layers.Resizing(self.height, self.width)\n", + "\n", + " def call(self, video):\n", + " \"\"\"\n", + " Use the einops library to resize the tensor. \n", + " \n", + " Args:\n", + " video: Tensor representation of the video, in the form of a set of frames.\n", + " \n", + " Return:\n", + " A downsampled size of the video according to the new height and width it should be resized to.\n", + " \"\"\"\n", + " # b stands for batch size, t stands for time, h stands for height, \n", + " # w stands for width, and c stands for the number of channels.\n", + " old_shape = einops.parse_shape(video, 'b t h w c')\n", + " images = einops.rearrange(video, 'b t h w c -> (b t) h w c')\n", + " images = self.resizing_layer(images)\n", + " videos = einops.rearrange(\n", + " images, '(b t) h w c -> b t h w c',\n", + " t = old_shape['t'])\n", + " return videos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Z9IqzCq--Uu9" + }, + "source": [ + "Use a [API funcional Keras](https://www.tensorflow.org/guide/keras/functional) para construir a rede residual." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_bROfh_K-Wxs" + }, + "outputs": [ + + ], + "source": [ + "input_shape = (None, 10, HEIGHT, WIDTH, 3)\n", + "input = layers.Input(shape=(input_shape[1:]))\n", + "x = input\n", + "\n", + "x = Conv2Plus1D(filters=16, kernel_size=(3, 7, 7), padding='same')(x)\n", + "x = layers.BatchNormalization()(x)\n", + "x = layers.ReLU()(x)\n", + "x = ResizeVideo(HEIGHT // 2, WIDTH // 2)(x)\n", + "\n", + "# Block 1\n", + "x = add_residual_block(x, 16, (3, 3, 3))\n", + "x = ResizeVideo(HEIGHT // 4, WIDTH // 4)(x)\n", + "\n", + "# Block 2\n", + "x = add_residual_block(x, 32, (3, 3, 3))\n", + "x = ResizeVideo(HEIGHT // 8, WIDTH // 8)(x)\n", + "\n", + "# Block 3\n", + "x = add_residual_block(x, 64, (3, 3, 3))\n", + "x = ResizeVideo(HEIGHT // 16, WIDTH // 16)(x)\n", + "\n", + "# Block 4\n", + "x = add_residual_block(x, 128, (3, 3, 3))\n", + "\n", + "x = layers.GlobalAveragePooling3D()(x)\n", + "x = layers.Flatten()(x)\n", + "x = layers.Dense(10)(x)\n", + "\n", + "model = keras.Model(input, x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TiO0WylG-ZHM" + }, + "outputs": [ + + ], + "source": [ + "frames, label = next(iter(train_ds))\n", + "model.build(frames)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GAsKrM8r-bKM" + }, + "outputs": [ + + ], + "source": [ + "# Visualize the model\n", + "keras.utils.plot_model(model, expand_nested=True, dpi=60, show_shapes=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1yvJJPnY-dMP" + }, + "source": [ + "## Treinamento do modelo\n", + "\n", + "Neste tutorial, escolha o otimizador `tf.keras.optimizers.Adam` e a função de perda `tf.keras.losses.SparseCategoricalCrossentropy`. Use o argumento metrics para ver a exatidão do desempenho do modelo a cada passo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ejrbyebDp2tA" + }, + "outputs": [ + + ], + "source": [ + "model.compile(loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True), \n", + " optimizer = keras.optimizers.Adam(learning_rate = 0.0001), \n", + " metrics = ['accuracy'])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nZT1Xlx9stP2" + }, + "source": [ + "Treine o modelo com 50 épocas usando o método `Model.fit` do Keras:\n", + "\n", + "Observação: Este modelo de exemplo é treinado em menos pontos de dados (300 exemplos de treinamento e 100 exemplos de validação) para manter o tempo de treinamento razoável para este tutorial. Além disso, este modelo de exemplo pode levar mais de uma hora para ser treinado." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VMrMUl2hOqMs" + }, + "outputs": [ + + ], + "source": [ + "history = model.fit(x = train_ds,\n", + " epochs = 50, \n", + " validation_data = val_ds)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KKUfMNVns2hu" + }, + "source": [ + "### Visualize os resultados\n", + "\n", + "Crie gráficos da perda e da exatidão para os conjuntos de treinamento e avaliação:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Cd5tpNrtOrs7" + }, + "outputs": [ + + ], + "source": [ + "def plot_history(history):\n", + " \"\"\"\n", + " Plotting training and validation learning curves.\n", + "\n", + " Args:\n", + " history: model history with all the metric measures\n", + " \"\"\"\n", + " fig, (ax1, ax2) = plt.subplots(2)\n", + "\n", + " fig.set_size_inches(18.5, 10.5)\n", + "\n", + " # Plot loss\n", + " ax1.set_title('Loss')\n", + " ax1.plot(history.history['loss'], label = 'train')\n", + " ax1.plot(history.history['val_loss'], label = 'test')\n", + " ax1.set_ylabel('Loss')\n", + " \n", + " # Determine upper bound of y-axis\n", + " max_loss = max(history.history['loss'] + history.history['val_loss'])\n", + "\n", + " ax1.set_ylim([0, np.ceil(max_loss)])\n", + " ax1.set_xlabel('Epoch')\n", + " ax1.legend(['Train', 'Validation']) \n", + "\n", + " # Plot accuracy\n", + " ax2.set_title('Accuracy')\n", + " ax2.plot(history.history['accuracy'], label = 'train')\n", + " ax2.plot(history.history['val_accuracy'], label = 'test')\n", + " ax2.set_ylabel('Accuracy')\n", + " ax2.set_ylim([0, 1])\n", + " ax2.set_xlabel('Epoch')\n", + " ax2.legend(['Train', 'Validation'])\n", + "\n", + " plt.show()\n", + "\n", + "plot_history(history)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EJrGF0Sss8E0" + }, + "source": [ + "## Avaliação do modelo\n", + "\n", + "Use `Model.evaluate` do Keras para obter a perda e a precisão do dataset de dados de teste.\n", + "\n", + "Observação: o modelo de exemplo neste tutorial usa um subconjunto do dataset UCF101 para manter o tempo de treinamento razoável. A precisão e a perda podem ser melhoradas com mais ajustes de hiperparâmetros ou mais dados de treinamento. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hev0hMCxOtfy" + }, + "outputs": [ + + ], + "source": [ + "model.evaluate(test_ds, return_dict=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-F73GxD1-yc8" + }, + "source": [ + "Para avaliar o desempenho do modelo com mais detalhes, use uma [matriz de confusão](https://www.tensorflow.org/api_docs/python/tf/math/confusion_matrix), que permite avaliar o desempenho do modelo de classificação além da exatidão. Para criar a matriz de confusão para este problema de classificação multiclasse, obtenha os valores reais do dataset de teste e os valores previstos. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Yw-6rG5V-0L-" + }, + "outputs": [ + + ], + "source": [ + "def get_actual_predicted_labels(dataset): \n", + " \"\"\"\n", + " Create a list of actual ground truth values and the predictions from the model.\n", + "\n", + " Args:\n", + " dataset: An iterable data structure, such as a TensorFlow Dataset, with features and labels.\n", + "\n", + " Return:\n", + " Ground truth and predicted values for a particular dataset.\n", + " \"\"\"\n", + " actual = [labels for _, labels in dataset.unbatch()]\n", + " predicted = model.predict(dataset)\n", + "\n", + " actual = tf.stack(actual, axis=0)\n", + " predicted = tf.concat(predicted, axis=0)\n", + " predicted = tf.argmax(predicted, axis=1)\n", + "\n", + " return actual, predicted" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aln6qWW_-2dk" + }, + "outputs": [ + + ], + "source": [ + "def plot_confusion_matrix(actual, predicted, labels, ds_type):\n", + " cm = tf.math.confusion_matrix(actual, predicted)\n", + " ax = sns.heatmap(cm, annot=True, fmt='g')\n", + " sns.set(rc={'figure.figsize':(12, 12)})\n", + " sns.set(font_scale=1.4)\n", + " ax.set_title('Confusion matrix of action recognition for ' + ds_type)\n", + " ax.set_xlabel('Predicted Action')\n", + " ax.set_ylabel('Actual Action')\n", + " plt.xticks(rotation=90)\n", + " plt.yticks(rotation=0)\n", + " ax.xaxis.set_ticklabels(labels)\n", + " ax.yaxis.set_ticklabels(labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tfQ3VAGd-4Az" + }, + "outputs": [ + + ], + "source": [ + "fg = FrameGenerator(subset_paths['train'], n_frames, training=True)\n", + "labels = list(fg.class_ids_for_name.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1ucGpbiA-5qi" + }, + "outputs": [ + + ], + "source": [ + "actual, predicted = get_actual_predicted_labels(train_ds)\n", + "plot_confusion_matrix(actual, predicted, labels, 'training')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Mfr7AT5T-7ZD" + }, + "outputs": [ + + ], + "source": [ + "actual, predicted = get_actual_predicted_labels(test_ds)\n", + "plot_confusion_matrix(actual, predicted, labels, 'test')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FefzeIZz-9aI" + }, + "source": [ + "Os valores de precisão e recuperação para cada classe também podem ser calculados usando uma matriz de confusão." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dq95-56Z-_E2" + }, + "outputs": [ + + ], + "source": [ + "def calculate_classification_metrics(y_actual, y_pred, labels):\n", + " \"\"\"\n", + " Calculate the precision and recall of a classification model using the ground truth and\n", + " predicted values. \n", + "\n", + " Args:\n", + " y_actual: Ground truth labels.\n", + " y_pred: Predicted labels.\n", + " labels: List of classification labels.\n", + "\n", + " Return:\n", + " Precision and recall measures.\n", + " \"\"\"\n", + " cm = tf.math.confusion_matrix(y_actual, y_pred)\n", + " tp = np.diag(cm) # Diagonal represents true positives\n", + " precision = dict()\n", + " recall = dict()\n", + " for i in range(len(labels)):\n", + " col = cm[:, i]\n", + " fp = np.sum(col) - tp[i] # Sum of column minus true positive is false negative\n", + " \n", + " row = cm[i, :]\n", + " fn = np.sum(row) - tp[i] # Sum of row minus true positive, is false negative\n", + " \n", + " precision[labels[i]] = tp[i] / (tp[i] + fp) # Precision \n", + " \n", + " recall[labels[i]] = tp[i] / (tp[i] + fn) # Recall\n", + " \n", + " return precision, recall" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4jSEonYQ_BZt" + }, + "outputs": [ + + ], + "source": [ + "precision, recall = calculate_classification_metrics(actual, predicted, labels) # Test dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hXvTW1Df_DV8" + }, + "outputs": [ + + ], + "source": [ + "precision" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "be1yrQl5_EYF" + }, + "outputs": [ + + ], + "source": [ + "recall" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "d4WsP4Z2HZ6L" + }, + "source": [ + "## Próximos passos\n", + "\n", + "Para saber mais sobre como trabalhar com dados de vídeo no TensorFlow, confira os seguintes tutoriais:\n", + "\n", + "- [Carregamento de dados de vídeo](https://www.tensorflow.org/tutorials/load_data/video)\n", + "- [MoViNet para o reconhecimento de ações de streaming](https://www.tensorflow.org/hub/tutorials/movinet)\n", + "- [Aprendizado por transferência para a classificação de vídeos com MoViNet](https://www.tensorflow.org/tutorials/video/transfer_learning_with_movinet)" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "video_classification.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/xla/aliasing.md b/site/pt-br/xla/aliasing.md new file mode 100644 index 0000000000..882809865b --- /dev/null +++ b/site/pt-br/xla/aliasing.md @@ -0,0 +1,51 @@ +# Aliasing em XLA + +Este documento descreve a API de aliasing para o XLA: ao construir um programa XLA, você pode especificar o aliasing desejado entre os buffers de entrada e saída. + +## Definindo aliasing em tempo de compilação + +Por exemplo, considere um módulo HLO trivial que simplesmente adiciona `1` à sua entrada: + +``` +HloModule increment + +ENTRY entry { + %p = f32[] parameter(0) + %c = f32[] constant(1) + ROOT %out = f32[] add(%p, %c) +} +``` + +Este módulo alocará dois buffers de 4 bytes: um para a entrada `%p` e outro para a saída `%out`. + +No entanto, muitas vezes é desejável realizar a atualização no local (por exemplo, se no front-end que gera a expressão a variável de entrada não estiver mais ativa após a computação, como no incremento `p++`). + +Para realizar essa atualização com eficiência, você pode especificar o aliasing de entrada: + +``` +HloModule increment, input_output_alias={ {}: 0 } + +ENTRY entry { + %p = f32[] parameter(0) + %c = f32[] constant(1) + ROOT %out = f32[] add(%p, %c) +} +``` + +O formato especifica que toda a saída (marcada por `{}`) tem o alias do parâmetro de entrada `0`. + +Veja a API [`XlaBuilder::SetUpAlias`](https://www.tensorflow.org/code/tensorflow/compiler/xla/client/xla_builder.h) ​​para especificar o aliasing programaticamente. + +## Definindo aliasing em tempo de execução + +O aliasing definido na etapa anterior é especificado durante a *compilação*. Durante a execução, você pode escolher se realmente deseja doar o buffer usando a API [`LocalClient::RunAsync`](https://www.tensorflow.org/code/tensorflow/compiler/xla/client/local_client.h). + +Os buffers de entrada para o programa são agrupados em [`ExecutionInput`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/executable.h), que por sua vez contém uma árvore de `MaybeOwningDeviceMemory`. Se a memória for especificada como *proprietária* (a propriedade do buffer é passada para o tempo de execução do XLA), o buffer é doado e a atualização é executada no local, conforme solicitado pela API de aliasing em tempo de compilação. + +Se, no entanto, o buffer que tem aliasing em tempo de compilação *não* for doado em tempo de execução, *a proteção contra cópia* entra em ação: um buffer de saída extra `O` é alocado e o conteúdo do buffer de entrada `P` que deveria ter aliasing é copiado para `O` (de forma tão eficaz que o programa pode ser executado como se o buffer `O` tivesse sido doado em tempo de execução). + +## Interoperação com o front-end + +### TF/XLA + +Em clusters do programa TensorFlow compilado com XLA, todas as atualizações de variáveis ​​de características recebem alias em tempo de compilação (o alias em tempo de execução depende se alguma outra coisa contém uma referência ao tensor de variável de característica). diff --git a/site/pt-br/xla/architecture.md b/site/pt-br/xla/architecture.md new file mode 100644 index 0000000000..95b6cee4fe --- /dev/null +++ b/site/pt-br/xla/architecture.md @@ -0,0 +1,37 @@ +# Arquitetura XLA + +
+
+ +## Por que construímos o XLA? + +Tínhamos diversos objetivos para o XLA trabalhar com o TensorFlow: + +- *Melhorar a velocidade de execução.* Compilar subgrafos para reduzir o tempo de execução de operações de curta duração visando eliminar a sobrecarga do runtime do TensorFlow, fundir operações em pipeline para reduzir a sobrecarga de memória e especializar-se em formas de tensor conhecidas para permitir uma propagação constante mais agressiva. + +- *Melhorar o uso da memória.* Analisar e programar o uso da memória, eliminando, em princípio, muitos buffers de armazenamento intermediários. + +- *Reduzir a dependência de operações personalizadas.* Eliminar a necessidade de diversas operações personalizadas, melhorando o desempenho de operações de baixo nível fundidas automaticamente para corresponder ao desempenho de operações personalizadas que foram fundidas manualmente. + +- *Reduzir o espaço ocupado em dispositivos móveis.* Eliminar o tempo de execução do TensorFlow compilando antecipadamente o subgrafo e emitindo um par de arquivo objeto/cabeçalho que pode ser vinculado diretamente a outro aplicativo. Os resultados podem reduzir o espaço ocupado pela inferência móvel em várias ordens de grandeza. + +- *Melhorar a portabilidade.* Tornar relativamente fácil escrever um novo back-end para hardware novo, ponto em que uma grande parte dos programas do TensorFlow será executada sem modificações nesse hardware. Isto contrasta com a abordagem de especialização de operações monolíticas individuais para novo hardware, que exige que os programas do TensorFlow sejam reescritos para fazer uso dessas operações. + +## Como funciona o XLA? + +A linguagem de entrada para o XLA é chamada de "HLO IR", ou apenas HLO (High Level Operations). A semântica do HLO está descrita na página [Operation Semantics](./operation_semantics.md). É mais conveniente pensar no HLO como um [compilador IR](https://en.wikipedia.org/wiki/Intermediate_representation). + +XLA recebe grafos ("computações") definidos em HLO e os compila para instruções de máquina de várias arquiteturas. O XLA é modular no sentido de que é fácil inserir um back-end alternativo para [atingir alguma nova arquitetura de HW](./developing_new_backend.md). O back-end da CPU para x64 e ARM64, bem como o back-end da GPU NVIDIA estão na árvore de fontes do TensorFlow. + +O diagrama a seguir mostra o processo de compilação em XLA: + +
+
+ +O XLA vem com diversas otimizações e passagens de análise independentes do alvo, como [CSE](https://en.wikipedia.org/wiki/Common_subexpression_elimination), fusão de operações independentes do alvo e análise de buffer para alocar memória de tempo de execução para a computação. + +Depois dessa etapa independente do alvo, o XLA envia a computação HLO para um backend. O back-end pode realizar otimizações adicionais no nível do HLO, desta vez com informações e necessidades específicas do alvo. Por exemplo, o back-end da GPU XLA pode realizar fusão de operações benéfica especificamente para o modelo de programação da GPU e determinar como particionar a computação em fluxos. Neste estágio, os back-ends também podem combinar padrões de certas operações ou combinações delas com chamadas de biblioteca otimizadas. + +A próxima etapa é a geração de código específico do destino. Os back-ends de CPU e GPU incluídos no XLA usam [LLVM](http://llvm.org) para IR de baixo nível, otimização e geração de código. Esses backends produzem o IR LLVM necessário para representar a computação XLA HLO de maneira eficiente e, em seguida, invocam o LLVM para emitir código nativo deste IR LLVM. + +O back-end da GPU atualmente oferece suporte a GPUs NVIDIA por meio do back-end LLVM NVPTX; o back-end da CPU oferece suporte a vários ISAs de CPU. diff --git a/site/pt-br/xla/broadcasting.md b/site/pt-br/xla/broadcasting.md new file mode 100644 index 0000000000..b0a157a38b --- /dev/null +++ b/site/pt-br/xla/broadcasting.md @@ -0,0 +1,146 @@ +# Semântica do broadcasting + +Este documento descreve como funciona a semântica de broadcasting no XLA. + +## O que é broadcasting? + +Broadcasting é o processo de fazer com que arrays com formatos diferentes tenham formatos compatíveis para operações aritméticas. A terminologia é emprestada do Numpy [Broadcasting](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html). + +O broadcasting pode ser necessário para operações entre arrays multidimensionais de diferentes postos ou entre arrays multidimensionais com formatos diferentes, mas compatíveis. Considere a adição `X+v` onde `X` é uma matriz (um array de posto 2) e `v` é um vetor (um array de posto 1). Para realizar a adição elemento a elemento, o XLA precisa fazer o "broadcasting" do vetor `v` para o mesmo posto da matriz `X`, replicando `v` um determinado número de vezes. O comprimento do vetor deve corresponder a pelo menos uma das dimensões da matriz. + +Por exemplo: + +``` +|1 2 3| + |7 8 9| +|4 5 6| +``` + +As dimensões da matriz são (2,3), as do vetor são (3). O vetor é transmitido replicando-o nas linhas para obter: + +``` +|1 2 3| + |7 8 9| = |8 10 12| +|4 5 6| |7 8 9| |11 13 15| +``` + +No Numpy, isso é chamado de [broadcasting](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html). + +## Princípios + +A linguagem XLA é tão estrita e explícita quanto possível, evitando recursos implícitos e “mágicos”. Esses recursos podem deixar algumas computações um pouco mais fáceis de definir, ao custo de mais suposições incorporadas ao código do usuário que serão difíceis de alterar no longo prazo. Se necessário, recursos implícitos e mágicos podem ser adicionados em wrappers no nível do cliente. + +No que diz respeito ao broadcasting, são necessárias especificações explícitas de broadcasting sobre operações entre arrays de diferentes postos. Isso difere do Numpy, que infere a especificação sempre que possível. + +## Fazendo o broadcasting de um array de posto inferior para um array de posto superior + +*Escalares* sempre podem ser convertidos em arrays via broadcasting sem uma especificação explícita das dimensões de broadcasting. Uma operação binária elemento a elemento entre um escalar e um array significa aplicar a operação com o escalar para cada elemento do array. Por exemplo, adicionar um escalar a um array significa produzir um array, onde cada elemento seja uma soma do escalar com o elemento correspondente do array de entrada. + +``` +|1 2 3| + 7 = |8 9 10| +|4 5 6| |11 12 13| +``` + +A maioria das necessidades de broadcasting pode ser capturada usando uma tupla de dimensões numa operação binária. Quando as entradas para a operação têm postos diferentes, esta tupla de broadcasting especifica quais dimensões no array **de posto mais alto** devem corresponder ao array **de posto mais baixo**. + +Considere o exemplo anterior, em vez de adicionar um escalar a uma matriz (2,3), adicione um vetor de dimensão (3) a uma matriz de dimensões (2,3). *Sem especificar o broadcasting, esta operação seria inválida.* Para solicitar corretamente a adição de matriz-vetor, especifique a dimensão de broadcasting como (1), o que significa que a dimensão do vetor corresponde à dimensão 1 da matriz. Em 2D, se a dimensão 0 for tratada como linhas e a dimensão 1 como colunas, isso significa que cada elemento do vetor se torna uma coluna de tamanho correspondente ao número de linhas na matriz: + +``` +|7 8 9| ==> |7 8 9| + |7 8 9| +``` + +Como um exemplo mais complexo, considere adicionar um vetor de 3 elementos (dimensão (3)) a uma matriz 3x3 (dimensões (3,3)). Existem duas maneiras pelas quais o broadcasting pode acontecer neste exemplo: + +(1) Uma dimensão de broadcasting de 1 pode ser usada. Cada elemento do vetor torna-se uma coluna e o vetor é duplicado para cada linha da matriz. + +``` +|7 8 9| ==> |7 8 9| + |7 8 9| + |7 8 9| +``` + +(2) Uma dimensão de broadcasting de 0 pode ser usada. Cada elemento do vetor torna-se uma linha e o vetor é repetido para cada coluna da matriz. + +``` + |7| ==> |7 7 7| + |8| |8 8 8| + |9| |9 9 9| +``` + +> Nota: ao adicionar uma matriz 2x3 a um vetor de 3 elementos, uma dimensão de broadcasting 0 é inválida. + +As dimensões de broadcasting podem ser uma tupla que descreve como um formato de posto menor é convertido para um formato de posto maior usando broadcasting. Por exemplo, dado um cubóide 2x3x4 e uma matriz 3x4, uma tupla de broadcasting (1,2) significa combinar a matriz com as dimensões 1 e 2 do cubóide. + +Este tipo de broadcasting é usado nas operações binárias em `XlaBuilder`, se o argumento `broadcast_dimensions` for fornecido. Por exemplo, veja [XlaBuilder::Add](https://www.tensorflow.org/code/tensorflow/compiler/xla/client/xla_builder.cc). No código-fonte do XLA, esse tipo de broadcasting às vezes é chamado de broadcasting "InDim". + +### Definição formal + +O atributo de broadcasting permite corresponder um array de posto inferior com um array de posto superior, especificando quais dimensões do array de posto mais alto devem ser correspondidas. Por exemplo, para um array com dimensões MxNxPxQ, um vetor com dimensão T pode ser correspondido da seguinte forma: + +``` + MxNxPxQ + +dim 3: T +dim 2: T +dim 1: T +dim 0: T +``` + +Em cada caso, T deve ser igual à dimensão correspondente do array de posto mais alto. Os valores do vetor são então convertidos via broadcasting da dimensão correspondente para todas as outras dimensões. + +Para corresponder uma matriz TxV com o array MxNxPxQ, um par de dimensões de broadcasting é usado: + +``` + MxNxPxQ +dim 2,3: T V +dim 1,2: T V +dim 0,3: T V +etc... +``` + +A ordem das dimensões na tupla de broadcasting deve ser a ordem na qual se espera que as dimensões do array de posto inferior correspondam às dimensões do array de posto superior. O primeiro elemento na tupla indica qual dimensão no array de posto mais alto deve corresponder à dimensão 0 no array de posto mais baixo. O segundo elemento para a dimensão 1 e assim por diante. A ordem das dimensões de broadcasting deve ser estritamente crescente. Por exemplo, no exemplo anterior é ilegal combinar V com N e T com P; também é ilegal combinar V com P e N. + +## Fazendo o broadcasting de arrays de posto similar com dimensões degeneradas + +Um problema de broadcasting relacionado é o broadcasting de dois arrays que possuem o mesmo posto, mas tamanhos de dimensão diferentes. Da mesma forma que as regras do Numpy, isto só é possível quando os arrays são *compatíveis*. Dois arrays são compatíveis quando todas as suas dimensões são compatíveis. Duas dimensões são compatíveis se: + +- Forem iguais, ou +- Uma delas for 1 (uma dimensão "degenerada") + +Quando dois arrays compatíveis são encontrados, o formato do resultado tem o máximo entre as duas entradas em cada índice de dimensão. + +Exemplos: + +1. (2,1) e (2,3) convertidos via broadcasting para (2,3). +2. (1,2,5) e (7,2,5) convertidos via broadcasting para (7,2,5) +3. (7,2,5) e (7,1,5) convertidos via broadcasting para (7,2,5) +4. (7,2,5) e (7,2,6) são incompatíveis e não podem ser convertidos via broadcasting. + +Surge um caso especial, que também é suportado, onde cada um dos arrays de entrada tem uma dimensão degenerada em um índice diferente. Neste caso, o resultado é uma “operação externa”: (2,1) e (1,3) convertidos via broadcasting para (2,3). Para mais exemplos, veja a [documentação do Numpy sobre broadcasting](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html). + +## Broadcasting composto + +O broadcasting de um array de posto inferior para um array de posto superior **e** o broadcasting usando dimensões degeneradas podem ser realizados na mesma operação binária. Por exemplo, um vetor de tamanho 4 e uma matriz de tamanho 1x2 podem ser somados usando o valor das dimensões de broadcasting de (0): + +``` +|1 2 3 4| + [5 6] // [5 6] is a 1x2 matrix, not a vector. +``` + +Primeiro, o vetor é convertido via broadcasting até o posto 2 (matriz) usando as dimensões de broadcasting. O valor único (0) nas dimensões de broadcasting indica que a dimensão zero do vetor corresponde à dimensão zero da matriz. Isto produz uma matriz de tamanho 4xM onde o valor M é escolhido para corresponder ao tamanho da dimensão correspondente no array 1x2. Portanto, uma matriz 4x2 é produzida: + +``` +|1 1| + [5 6] +|2 2| +|3 3| +|4 4| +``` + +Em seguida, o "broadcasting de dimensão degenerada" converte a dimensão zero da matriz 1x2 para corresponder ao tamanho da dimensão correspondente do lado direito: + +``` +|1 1| + |5 6| |6 7| +|2 2| + |5 6| = |7 8| +|3 3| + |5 6| |8 9| +|4 4| + |5 6| |9 10| +``` + +Um exemplo mais complicado é uma matriz de tamanho 1x2 adicionada a um array de tamanho 4x3x1 usando dimensões de broadcasting de (1, 2). Primeiro, a matriz 1x2 é convertida até o posto 3 usando as dimensões de broadcasting para produzir um array intermediário Mx1x2 onde o tamanho da dimensão M é determinado pelo tamanho do operando maior (a matriz 4x3x1) produzindo um array intermediário 4x1x2. O M está na dimensão 0 (dimensão mais à esquerda) porque as dimensões 1 e 2 são mapeadas para as dimensões da matriz 1x2 original já que as dimensões de broadcasting são (1, 2). Este array intermediário pode ser adicionado à matriz 4x3x1 usando broadcasting de dimensões degeneradas para produzir como resultado um array 4x3x2. diff --git a/site/pt-br/xla/code_reviews_guide.md b/site/pt-br/xla/code_reviews_guide.md new file mode 100644 index 0000000000..e64697f4dc --- /dev/null +++ b/site/pt-br/xla/code_reviews_guide.md @@ -0,0 +1,52 @@ +# Guia para revisões de código + +O objetivo deste documento é explicar o raciocínio por trás da posição da equipe XLA em relação a revisões de código – uma posição que cresceu a partir de anos de experiência coletiva trabalhando em projetos de código aberto em geral e em XLA em particular. + +Diferentes projetos de código aberto têm diferentes expectativas culturais sobre o quanto os revisores podem exigir dos autores de código. Em alguns projetos, os revisores pegarão uma pull request (PR) "quase correta", modificarão eles próprios e a enviarão. O XLA adota a abordagem oposta: esperamos que os autores repitam os PRs até que sejam bons o suficiente para serem enviados sem alterações adicionais. + +A principal razão para esta abordagem é que queremos que os autores de PR aprendam a ser contribuidores de pleno direito do XLA. Se os próprios revisores resolverem os problemas descritos no PR, será muito mais difícil para os autores aprenderem. A abordagem XLA pode ser desafiadora tanto para revisores quanto para revisados, mas acreditamos que, em última análise, nos ajuda a fazer crescer a comunidade. + +Aprender a ser um "colaborador XLA completo" não envolve apenas escrever código que não contenha bugs. Há muito mais para aprender sobre “como modificar o XLA”. Isto inclui: + +- estilo de programação, +- quais casos extremos procurar, +- expectativas quanto à criação de testes, +- expectativas relacionadas a comentários e descrições de pull requests, +- e expectativas em torno da construção de infraestrutura para dar suporte às suas alterações. + +À medida que você desenvolve o conhecimento do projeto e a confiança dos revisores, você pode esperar receber menos comentários, porque você estará naturalmente escrevendo um código mais alinhado com as expectativas do seu revisor. + +Como muitos projetos de código aberto, o XLA conta com algumas pessoas altamente experientes e muitas pessoas relativamente novas. Aqueles de nós que são altamente experientes têm muitas demandas de nosso tempo. Para manter os PRs avançando em tempo hábil, você pode ajudar a reduzir o tempo necessário para os revisores e o número de iterações necessárias, seguindo as recomendações abaixo: + +- *Revisar cuidadosamente e/ou fazer com que seu PR seja revisado por um colega antes de enviá-lo:* Tente remover o máximo de erros triviais (estilo de código, erros ortográficos e gramaticais, etc.) antes de enviar o PR para revisão. Certifique-se de que todos os testes estejam passando com sucesso. +- *Ler atentamente os comentários do revisor:* tente entender o que o revisor está pedindo e tente responder a todos os comentários antes de enviar uma nova versão. +- *Evitar discussões tangenciais (bikeshedding):* Discussões e desentendimentos técnicos são altamente valiosos e ninguém é perfeito. Porém, evite discussões que não façam diferença ou que sejam meramente estilísticas. Se você discordar do comentário de um revisor, tente detalhar seus motivos da forma mais precisa e abrangente possível para evitar longas discussões. +- *Evitar fazer as "perguntas de revisão mais frequentes" listadas abaixo:* Listamos algumas respostas a perguntas comuns e nossa justificativa abaixo. + +Em geral, convidamos você a tentar fazer com que a revisão de seus PRs leve o mínimo de tempo possível. Assim vamos querer revisar suas alterações rapidamente! + +Obrigado por contribuir com o XLA e boa programação! + +## Perguntas de revisão mais comuns + +### “Esta alteração de infraestrutura não está relacionada ao meu PR, por que devo fazer isso?” + +A equipe XLA não possui uma equipe de infraestrutura dedicada, então cabe a todos nós construir bibliotecas auxiliares e evitar aumentar a dívida técnica. Consideramos que isto é um procedimento comum nas alterações do XLA e espera-se que todos participem. Geralmente construímos infraestrutura conforme necessário ao escrever código. + +Os revisores do XLA podem solicitar que você construa alguma infraestrutura (ou faça uma grande alteração num PR) junto com um PR que você escreveu. Essa solicitação pode parecer desnecessária ou ortogonal à alteração que você está tentando fazer. Provavelmente, isto se deve a alguma incompatibilidade entre suas expectativas sobre a quantidade de infra que você precisa construir e as expectativas do revisor quanto à mesma. + +Haver uma incompatibilidade de expectativas não é problema! Isso é esperado quando você é novo num projeto (e às vezes até acontece com os veteranos). É provável que os projetos nos quais você trabalhou no passado tenham expectativas diferentes. Isso também é normal e esperado e não significa que nenhum desses projetos tenha a abordagem errada; eles são apenas diferentes. Convidamos você a aceitar solicitações de infra junto com todos os outros comentários de revisão como uma oportunidade de saber o que esperamos deste projeto. + +### "Posso tratar do seu comentário num PR futuro?" + +Uma pergunta frequente relativamente aos pedidos de infraestrutura (ou outros pedidos de grande dimensão) nos PR é se a alteração deve ou não ser feita no PR original, ou se pode ser feita como seguimento num PR futuro. + +Em geral, o XLA não permite que os autores de PR abordem os comentários da revisão como um PR de follow-up. Quando um revisor decide que algo precisa ser abordado neste PR, geralmente esperamos que os autores abordem isso no PR original, mesmo que o que seja solicitado seja uma grande alteração. Este padrão se aplica externamente e também internamente no Google. + +Existem algumas razões pelas quais o XLA adota essa abordagem. + +- *Confiança:* Ter conquistado a confiança do revisor é um componente chave. Num projeto de código aberto, os colaboradores podem aparecer ou desaparecer a qualquer momento. Depois que aprovamos um PR, os revisores não têm como garantir que os follow-ups prometidos sejam realmente realizados. + +- *Impacto sobre outros desenvolvedores:* Se você enviou um PR abordando uma parte específica do XLA, há uma boa chance de que outras pessoas estejam olhando para essa mesma parte. Se aceitarmos dívida técnica no seu PR, todos que estiverem visualizando este arquivo serão impactados por essa dívida até que o follow-up seja enviado. + +- *Largura de banda do revisor:* Adiar uma alteração para um follow-up impõe diversos custos aos nossos revisores já sobrecarregados. Os revisores provavelmente esquecerão do que se tratava este PR enquanto aguardam o follow-up, tornando a próxima revisão mais difícil. Além disso, os revisores terão que acompanhar os follow-ups que estão aguardando, certificando-se de que eles realmente aconteçam. Se a alteração puder ser feita de forma que seja verdadeiramente ortogonal ao PR original, para que algum outro revisor possa revisá-la, a largura de banda seria um problema menor. Na nossa experiência, isso raramente acontece. diff --git a/site/pt-br/xla/custom_call.md b/site/pt-br/xla/custom_call.md new file mode 100644 index 0000000000..f93caaebfb --- /dev/null +++ b/site/pt-br/xla/custom_call.md @@ -0,0 +1,213 @@ +# Chamadas personalizadas XLA + +Este documento descreve como escrever e usar "chamadas personalizadas" XLA. As chamadas personalizadas permitem invocar código escrito numa linguagem de programação como C++ ou CUDA a partir de um programa XLA. + +Atenção: chamadas personalizadas são um recurso de baixo nível para usuários avançados. É fácil quebrar seu programa de uma forma difícil de depurar (e até mesmo difícil de perceber) usando chamadas personalizadas. Você não deve usar chamadas personalizadas, a menos que esteja preparado para depurar o XLA quando algo der errado, e você deve esperar relativamente menos assistência dos desenvolvedores do XLA se tiver problemas. + +Atenção: a API/ABI de chamadas personalizadas não está estável no momento. Não pretendemos alterá-la muito, mas ela pode mudar. Algumas possíveis alterações futuras estão descritas abaixo. + +## Chamada personalizada na CPU + +Você pode criar uma instrução HLO que represente uma chamada personalizada por meio da API cliente do XLA. Isto ainda não é disponível via TensorFlow no momento em que este artigo foi escrito. + +Por exemplo, o código a seguir usa uma chamada personalizada para calcular `A[i] = B[i % 128]+ C[i]` na CPU. (É claro que você poderia - e deveria! - fazer isso com o HLO no uso normal.) + +```c++ +#include "tensorflow/compiler/xla/client/xla_builder.h" +#include "tensorflow/compiler/xla/service/custom_call_target_registry.h" + +void do_it() { + xla::XlaBuilder b("do_it"); + xla::XlaOp param0 = + xla::Parameter(&b, 0, xla::ShapeUtil::MakeShape(xla::F32, {128}), "p0"); + xla::XlaOp param1 = + xla::Parameter(&b, 1, xla::ShapeUtil::MakeShape(xla::F32, {2048}), "p1"); + xla::XlaOp custom_call = + xla::CustomCall(&b, "do_custom_call", /*operands=*/{param0, param1}, + /*shape=*/xla::ShapeUtil::MakeShape(xla::F32, {2048})); +} + +void do_custom_call(void* out, const void** in) { + float* out_buf = reinterpret_cast(out); + const float* in0 = reinterpret_cast(in[0]); + const float* in1 = reinterpret_cast(in[1]); + for (int i = 0; i < 2048; ++i) { + out_buf[i] = in0[i % 128] + in1[i]; + } +} +XLA_REGISTER_CUSTOM_CALL_TARGET(do_custom_call, "Host"); +``` + +Observe que a função `do_custom_call` precisa saber as dimensões dos buffers sobre os quais opera. Neste exemplo, fixamos os tamanhos em 128 e 2048. Se você não quiser fazer isso, pode passar as dimensões como parâmetros para a chamada. + +## Chamada personalizada na GPU + +A estrutura de uma chamada personalizada na GPU é um pouco diferente dela na CPU. Aqui está um exemplo CUDA que faz a mesma computação `A[i] = B[i % 128] + C[i]` que o código na CPU acima. + +```c++ +void do_it() { /* same implementation as above */ } + +__global__ custom_call_kernel(const float* in0, const float* in1, float* out) { + size_t idx = blockIdx.x * blockDim.x + threadIdx.x; + out[idx] = in0[idx % 128] + in1[idx]; +} + +void do_custom_call(CUstream stream, void** buffers, + const char* opaque, size_t opaque_len) { + const float* in0 = reinterpret_cast(buffers[0]); + const float* in1 = reinterpret_cast(buffers[1]); + float* out = reinterpret_cast(buffers[2]); + + const int64_t block_dim = 64; + const int64_t grid_dim = 2048 / block_dim; + custom_call_kernel<<>>(in0, in1, out); +} +XLA_REGISTER_CUSTOM_CALL_TARGET(do_custom_call, "CUDA"); +``` + +Observe primeiro que a função de chamada personalizada da GPU *ainda é uma função executada na CPU*. Nossa função na CPU `do_custom_call` é responsável por enfileirar o trabalho na GPU. Aqui ele lança um kernel CUDA, mas também poderia fazer outra coisa, como chamar cublas. + +`buffers` é um array de ponteiros que reside no host e cada elemento que contém aponta para a memória do dispositivo (ou seja, GPU). Os parâmetros vêm primeiro, seguidos pelo valor de saída. Isso é bem diferente da convenção de uma chamada na CPU, que possui dois parâmetros, `ins` e `out`. A principal razão pela qual divergimos é tornar possível lidar com entradas/saídas em forma de tupla de forma eficiente; veja a seção abaixo. + +Como no exemplo da CPU, fixamos os tamanhos dos buffers de entrada e saída em nossa chamada personalizada. No entanto, ao contrário do caso da CPU, passar os tamanhos dos buffers como operandos para a chamada personalizada não funcionaria bem. Normalmente precisamos dos tamanhos de buffer disponíveis na CPU; por exemplo, ao lançar um kernel, precisamos saber as dimensões do bloco/grid a ser usado. Mas se passássemos os tamanhos dos buffers como operandos para nossa chamada personalizada, seus valores residiriam na memória da GPU. Teríamos então que fazer um memcpy síncrono do dispositivo para o host no início de nossa operação apenas para ler os tamanhos (e isto consome muitos recursos). + +Para permitir que você contorne isso, fornecemos o parâmetro `opaque`. Você pode defini-lo como uma sequência arbitrária de bytes ao criar a chamada personalizada: + +```c++ +std::string opaque = "..."; +xla::CustomCall(&b, "do_custom_call", /*operands=*/{param0, param1}, + /*output_shape=*/xla::ShapeUtil::MakeShape(xla::F32, {2048}), + opaque); +``` + +Como `xla::Shape` tem uma representação de buffer de protocolo, você pode armazenar esse proto serializado dentro de `opaque` e desserializá-lo em sua chamada personalizada de GPU. Observe, entretanto, que embora `xla::ShapeProto` não mude com frequência, ele às vezes *muda*. Verifique o log do git para ver como ele mudou no passado. + +## Sinalizando um erro. + +Se sua chamada personalizada encontrar um erro, você poderá sinalizar o erro para o tempo de execução do XLA (em vez de, por exemplo, travar ou retornar texto sem sentido nos buffers de saída) usando a seguinte assinatura para sua função na CPU: + +```c++ +#include "tensorflow/compiler/xla/service/custom_call_status.h" + +void do_custom_call(void* out, const void** in, XlaCustomCallStatus* status); +``` + +... e na GPU: + +```c++ +#include "tensorflow/compiler/xla/service/custom_call_status.h" + +void do_custom_call(CUstream stream, void** buffers, const char* opaque, + size_t opaque_len, xla::XlaCustomCallStatus* status); +``` + +Você pode sinalizar uma falha usando `XlaCustomCallStatusSetFailure`, por exemplo: + +```c++ +void do_custom_call(void* out, const void** in, XlaCustomCallStatus* status) { + // ... do some work. + + if (bad_condition) { + char* error_message = "An error occurred"; + XlaCustomCallStatusSetFailure(status, error_message, strlen(error_message)); + return; + } + + // ... continue. +} +``` + +Você também pode usar `XlaCustomCallStatusSetSuccess` para indicar sucesso, mas o `XlaCustomCallStatus` está em estado de sucesso por padrão, portanto, ignorá-lo completamente também indicará sucesso. + +Ao usar funções de chamada personalizadas com esta assinatura, você deve criar a operação `custom-call` correspondente com o conjunto apropriado de versões de API, por exemplo: + +```c++ +xla::CustomCall(&b, "do_custom_call", /*operands=*/{param0, param1}, + /*output_shape=*/xla::ShapeUtil::MakeShape(F32, {2048}), + opaque, /*has_side_effect=*/false, + /*output_operand_aliasing=*/{}, /*literal=*/nullptr, + /*schedule=*/xla::CustomCallSchedule::SCHEDULE_NONE, + /*api_version=*/API_VERSION_STATUS_RETURNING); +``` + +OBSERVAÇÃO: No futuro, todos os clientes serão obrigados a migrar suas funções de chamada personalizadas para a nova versão da API e a antiga será obsoleta. Para chamadas personalizadas que não podem falhar, basta adicionar o novo parâmetro `XlaCustomCallStatus*` e ignorá-la. + +Em caso de falha, nenhuma das saídas de chamada customizadas será usada; o tempo de execução do XLA encerrará a computação. Não é possível, para uma computação HLO, se recuperar do erro (por exemplo, capturando-o e tratando-o). + +## Passando tuplas para chamadas personalizadas + +Considere a seguinte chamada personalizada. + +```c++ +using xla::ShapeUtil; +using xla::F32; +Shape p0_shape = ShapeUtil::MakeTuple({ + ShapeUtil::MakeShape(F32, {32}), + ShapeUtil::MakeTuple({ + ShapeUtil::MakeShape(F32, {64}), + ShapeUtil::MakeShape(F32, {128}), + }), + ShapeUtil::MakeShape(F32, {256}), +}); +xla::XlaOp p0 = xla::Parameter(0, p0_shape, "p0"); + +Shape out_shape = ShapeUtil::MakeTuple({ + ShapeUtil::MakeShape(F32, {512}), + ShapeUtil::MakeShape(F32, {1024}), +}); +xla::CustomCall(&b, "do_custom_call", /*operands=*/{p0}, out_shape); +``` + +Tanto na CPU quanto na GPU, uma tupla é representada na memória como um array de ponteiros. No pseudocódigo C++, o parâmetro 0 acima é apresentado da seguinte forma. + +```c++ +// In-memory layout of parameter 0 from custom-call above. True on both CPU +// and GPU. +float* subbuf0 = new float[32]; +float* subbuf1 = new float[64]; +float* subbuf2 = new float[128] +float* subbuf3 = new float[256]; + +void* subtuple = new void*[2]; +(*subtuple)[0] = subbuf1; +(*subtuple)[1] = subbuf2; + +void* p0 = new void*[3]; +(*p0)[0] = subbuf0; +(*p0)[1] = subtuple; +(*p0)[2] = subbuf3; +``` + +Embora a representação de tuplas na memória seja a mesma na CPU e na GPU, elas são tratadas de maneira diferente nas convenções de chamadas personalizadas da CPU e da GPU. + +### Saídas de tupla como buffers temporários + +As entradas de tupla para chamadas personalizadas são uma conveniência, mas não são estritamente necessárias. Se não tivéssemos suporte a entradas de tuplas para chamadas personalizadas, você sempre poderia descompactar as tuplas usando get-tuple-element antes de passá-las para a chamada personalizada. + +Por outro lado, as *saídas* de tupla permitem que você faça coisas que de outra forma não conseguiria. + +A razão óbvia para ter saídas de tupla é que é assim que uma chamada personalizada (ou qualquer outra operação XLA) retorna vários arrays independentes. + +Mas, de forma menos óbvia, uma saída de tupla também é uma maneira de fornecer memória temporária à sua chamada personalizada. Sim, uma *saída* pode representar um buffer temporário. Considere que um buffer de saída tem a propriedade de que a operação pode gravar nele e pode ler a partir dele depois de ter sido gravado. Isso é exatamente o que você espera de um buffer temporário. + +No exemplo acima, suponha que quiséssemos usar `F32[1024]` como buffer temporário. Então escreveríamos o HLO como acima e simplesmente nunca leríamos o índice 1 da tupla na saída da chamada personalizada. + +### Tuplas em chamadas personalizadas de CPU + +No código da CPU, temos uma função `do_custom_call(const void** ins, void* out)`. `ins` é um array com apenas um elemento, que aponta para `param0`. Os sub-buffers de `param0` são acessíveis desreferenciando esse ponteiro, e os sub-buffers de `output_tuple` são acessíveis desreferenciando `out`. + +### Tuplas em chamadas personalizadas de GPU + +No código da GPU, temos uma função `do_custom_call(..., void** buffers, ...)`. Neste caso, `buffers` é um array de host de *seis* ponteiros de dispositivo, um para cada buffer-folha na entrada/saída. Para gerar a lista simples, iteramos sobre os parâmetros e a saída, e para cada um fazemos uma travessia de pré-ordem de seu formato. Concretamente: + +```c++ +// Layout of `buffers` parameter to GPU custom call function for custom-call +// above. +buffers[0] == subbuf0 +buffers[1] == subbuf1 +buffers[2] == subbuf2 +buffers[3] == subbuf3 +buffers[4] == output_subbuf0 +buffers[5] == output_subbuf1 +``` diff --git a/site/pt-br/xla/developing_new_backend.md b/site/pt-br/xla/developing_new_backend.md new file mode 100644 index 0000000000..77fb45de97 --- /dev/null +++ b/site/pt-br/xla/developing_new_backend.md @@ -0,0 +1,36 @@ +# Desenvolvendo um novo backend para o XLA + +Este guia preliminar é para os primeiros usuários que queiram redirecionar facilmente o TensorFlow para seu hardware de maneira eficiente. O guia não é passo a passo e pressupõe conhecimentos de [LLVM](http://llvm.org), [Bazel](https://bazel.build/) e TensorFlow. + +O XLA fornece uma interface abstrata que uma nova arquitetura ou acelerador pode implementar para criar um back-end para executar grafos do TensorFlow. O redirecionamento do XLA deve ser significativamente mais simples e escalonável do que implementar todas as operações TensorFlow existentes para o novo hardware. + +A maioria das implementações se enquadrará num dos seguintes cenários: + +1. Arquitetura de CPU existente ainda não suportada oficialmente pelo XLA, com ou sem um back-end [LLVM](http://llvm.org) existente. +2. Hardware não similar a CPU com um back-end LLVM existente. +3. Hardware não similar a CPU sem um back-end LLVM existente. + +> Observação: um back-end LLVM pode significar um dos back-ends LLVM lançados oficialmente ou um back-end LLVM personalizado desenvolvido internamente. + +## Cenário 1: Arquitetura de CPU existente ainda não suportada oficialmente pelo XLA + +Neste cenário, comece examinando o [back-end da CPU XLA](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/cpu/) existente. O XLA facilita o redirecionamento do TensorFlow para CPUs diferentes usando LLVM, já que a principal diferença entre back-ends XLA para CPUs é o código gerado pelo LLVM. Google testa o XLA para arquiteturas x64 e ARM64. + +Se o fornecedor de hardware tiver um backend LLVM para seu hardware, é simples vincular o backend ao LLVM criado com XLA. No modo JIT, o backend da CPU XLA produz código para a CPU host. Para compilação antecipada, [`xla::AotCompilationOptions`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/compiler.h) pode fornecer um LLVM triplo para configurar a arquitetura de destino. + +Se não houver back-end LLVM existente, mas existir outro tipo de gerador de código, deverá ser possível reutilizar a maior parte do back-end da CPU existente. + +## Cenário 2: Hardware não similar a CPU com um back-end LLVM existente + +É possível modelar uma nova implementação de [`xla::Compiler`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/compiler.h) nas classes [`xla::CPUCompiler`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/cpu/cpu_compiler.cc) e [`xla::GPUCompiler`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/gpu/nvptx_compiler.cc) existentes, uma vez que estas já produzem IR LLVM. Dependendo da natureza do hardware, é possível que muitos dos aspectos de geração de IR LLVM tenham que ser alterados, mas muito código pode ser compartilhado com os back-ends existentes. + +Um bom exemplo a seguir é o [back-end da GPU](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/gpu/) do XLA. O back-end da GPU tem como alvo um ISA diferente da CPU e, portanto, alguns aspectos de sua geração de código são exclusivos do domínio da GPU. Outros tipos de hardware, por exemplo, DSPs como o Hexagon (que possui um backend LLVM upstream), podem reutilizar partes da lógica de emissão IR do LLVM, mas outras partes serão exclusivas. + +## Cenário 3: Hardware não similar a CPU sem um back-end LLVM existente + +Caso não seja possível utilizar o LLVM, a melhor opção é implementar um novo backend para o XLA para o hardware desejado. Essa opção requer mais esforço. As classes que precisam ser implementadas são as seguintes: + +- [`StreamExecutor`](https://www.tensorflow.org/code/tensorflow/compiler/xla/stream_executor/stream_executor.h): para muitos dispositivos, nem todos os métodos de `StreamExecutor` são necessários. Consulte as implementações existentes `StreamExecutor` para mais detalhes. +- [`xla::Compiler`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/compiler.h): esta classe encapsula a compilação de uma computação HLO em um `xla::Executable`. +- [`xla::Executable`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/executable.h): esta classe é usada para lançar uma computação compilada na plataforma. +- [`xla::TransferManager`](https://www.tensorflow.org/code/tensorflow/compiler/xla/service/transfer_manager.h): esta classe permite que back-ends forneçam mecanismos específicos de plataforma para construir dados literais XLA a partir de determinados identificadores de memória de dispositivo. Em outras palavras, ajuda a encapsular a transferência de dados do host para o dispositivo e vice-versa. diff --git a/site/pt-br/xla/known_issues.md b/site/pt-br/xla/known_issues.md new file mode 100644 index 0000000000..09b5239028 --- /dev/null +++ b/site/pt-br/xla/known_issues.md @@ -0,0 +1,49 @@ +# Problemas conhecidos + +A compilação com XLA pode melhorar muito o desempenho de seus programas, mas a interoperabilidade com o TensorFlow tem vários problemas conhecidos que devem ser considerados. + +## `tf.Variable` em dispositivo diferente + +*Mensagem de erro*: `INVALID_ARGUMENT: Trying to access resource (defined @ ) located in device CPU:0 from device GPU:0` + +O cluster XLA é executado em exatamente um dispositivo e não pode ler ou gravar numa `tf.Variable` localizada em dispositivo diferente. Geralmente, essa mensagem de erro indica que a variável não foi colocada no dispositivo correto. A mensagem de erro deve especificar precisamente a localização da variável ofensiva. + +OBSERVAÇÃO: As `tf.Variable` do tipo `int32` são sempre colocadas num host e não podem ser colocadas numa GPU. Como solução alternativa, `int64` pode ser usado. + +## Interconversão TensorArray TF/XLA não suportada + +*Mensagem de erro*: `Support for TensorList crossing the XLA/TF boundary is not implemented`. + +O XLA suporta `tf.TensorArray`. No entanto, a *interconversão* entre as representações TF e XLA ainda não está implementada. Este erro geralmente surge quando o `TensorArray` é usado dentro do bloco compilado, mas a derivada é obtida fora. + +*Solução alternativa*: compile o escopo mais externo que está obtendo a derivada. + +## Loops while do TensorFlow precisam ser limitados (ou ter a retropropagação desativada) + +*Mensagem de erro*: `XLA compilation requires a fixed tensor list size. Set the max number of elements. This could also happen if you're using a TensorArray in a while loop that does not have its maximum_iteration set, you can fix this by setting maximum_iteration to a suitable value`. + +[Loops](https://www.tensorflow.org/api_docs/python/tf/while_loop) while do TF criados usando `tf.while_loop` suportam retropropagação acumulando todos os resultados intermediários num `TensorArray`, mas XLA suporta apenas objetos `TensorArray` limitados. + +*Solução alternativa*: todos os loops while compilados precisam ter o parâmetro `maximum_iterations` definido como um valor constante conhecido em tempo de compilação ou ter a retropropagação desabilitada usando `back_prop=False`. + +## `tf.TensorArray` dinâmico não suportado + +Gravações para `tf.TensorArray(..., dynamic_size=True)` não são compiláveis ​​com XLA, pois tais gravações exigem um número desconhecido de realocações quando o array exceder o limite original. + +*Solução alternativa*: forneça um limite estaticamente conhecido para seus arrays. + +## Geração de números aleatórios ignora a semente TF + +Atualmente, o XLA ignora sementes TF para operações aleatórias. Isto afeta operações aleatórias de TF stateful, como `tf.random.normal` ou `tf.nn.dropout`. O XLA se comportará como se a compilação tivesse sido propagada com uma nova semente exclusiva a cada execução do mesmo processo (a primeira execução do processo sempre produzirá o mesmo resultado). + +*Solução alternativa*: use [geradores de números aleatórios recomendados](https://www.tensorflow.org/guide/random_numbers#stateless_rngs), como `tf.random.stateless_uniform` ou `tf.random.Generator` diretamente. + +## Entradas que precisam ser constantes e que são funções de variáveis ​​de indução não são suportadas + +*Mensagem de erro*: `XLA compilation requires that operator arguments that represent shapes or dimensions be evaluated to concrete values at compile time. This error means that a shape or dimension argument could not be evaluated at compile time, usually because the value of the argument depends on a parameter to the computation, on a variable, or on a stateful operation such as a random number generator` + +O XLA exige que certos valores sejam conhecidos em tempo de compilação, como o eixo de redução de uma operação reduce ou dimensões de transposição. Considere o caso quando, por exemplo, o eixo de redução é definido como uma função de uma variável de indução de `tf.range`: resolvê-lo estaticamente não é possível sem desenrolar todo o loop, o que pode não ser o que o usuário deseja. + +*Solução alternativa*: desenrole os loops, por exemplo, convertendo `tf.range` para `range` do Python. + +OBSERVAÇÃO: A mensagem de erro acima não é exclusiva deste problema e pode surgir devido a outras limitações ou bugs. diff --git a/site/pt-br/xla/shapes.md b/site/pt-br/xla/shapes.md new file mode 100644 index 0000000000..732142cbbd --- /dev/null +++ b/site/pt-br/xla/shapes.md @@ -0,0 +1,102 @@ +# Formatos e Layout + +O proto XLA `Shape` ([xla_data.proto](https://www.tensorflow.org/code/tensorflow/compiler/xla/xla_data.proto)) descreve o posto, o tamanho e o tipo de dados de um array N-dimensional (*array* em resumo). + +## Terminologia, notação e convenções + +- O posto de um array é igual ao número de dimensões. O *posto verdadeiro* de um array é o número de dimensões que possuem tamanho maior que 1. + +- As dimensões são numeradas de `0` a `N-1` para um array `N` dimensional. Os números das dimensões são rótulos arbitrários por conveniência. A ordem desses números de dimensão não implica uma ordem menor/maior específica no layout do formato. O layout é determinado pelo protótipo `Layout`. + +- Por convenção, as dimensões são listadas em ordem crescente de número de dimensão. Por exemplo, para um array tridimensional de tamanho `[A x B x C]`, a dimensão 0 tem tamanho `A`, a dimensão 1 tem tamanho `B` e a dimensão 2 tem tamanho `C`. + + Alguns utilitários no XLA também suportam indexação negativa, de forma semelhante ao Python; dimensão -1 é a última dimensão (equivalente a `N-1` para um array `N` dimensional). Por exemplo, para o array tridimensional descrito acima, a dimensão -1 tem tamanho `C`, a dimensão -2 tem tamanho `B` e assim por diante. + +- Arrays bidimensionais, tridimensionais e tetradimensionais geralmente têm letras específicas associadas às dimensões. Por exemplo, para um array 2D: + + - dimensão 0: `y` + - dimensão 1: `x` + + Para um array 3D: + + - dimensão 0: `z` + - dimensão 1: `y` + - dimensão 2: `x` + + Para um array 4D: + + - dimensão 0: `p` + - dimensão 1: `z` + - dimensão 2: `y` + - dimensão 3: `x` + +- As funções na API XLA que recebem dimensões fazem isso em ordem crescente do número da dimensão. Isto corresponde à ordem usada ao passar dimensões como um `initializer_list`; por exemplo + + `ShapeUtil::MakeShape(F32, {A, B, C, D})` + + Irá criar um formato cujo array de dimensão que consiste na sequência `[A, B, C, D]`. + +## Layout + +O proto `Layout` descreve como um array é representado na memória. O proto `Layout` inclui os seguintes campos: + +``` +message Layout { + repeated int64 minor_to_major = 1; + repeated int64 padded_dimensions = 2; + optional PaddingValue padding_value = 3; +} +``` + +### Ordenação de dimensões menor para maior + +O único campo obrigatório é `minor_to_major` . Este campo descreve a ordem menor para maior das dimensões dentro de um formato. Os valores em `minor_to_major` são uma ordenação das dimensões do array ( `0` a `N-1` para um array `N` dimensional), com o primeiro valor sendo a dimensão menor até o último valor, que é a dimensão maior. A dimensão menor é a dimensão que muda mais rapidamente ao percorrer os elementos do array dispostos na memória linear. + +Por exemplo, considere o seguinte array 2D de tamanho `[2 x 3]`: + +``` +a b c +d e f +``` + +Aqui a dimensão `0` é o tamanho 2 e a dimensão `1` é o tamanho 3. Se o campo `minor_to_major` no layout for `[0, 1]`, então a dimensão `0` é a dimensão menor e a dimensão `1` é a dimensão maior. Isto corresponde ao seguinte layout na memória linear: + +``` +a d b e c f +``` + +Esta ordem de dimensão menor para maior de `0` a `N-1` é semelhante à *coluna maior* (no posto 2). Assumindo uma ordenação monotônica de dimensões, outro nome que podemos usar para nos referir a esse layout no código é simplesmente “dim 0 é menor”. + +Por outro lado, se o campo `minor_to_major` no layout for `[1, 0]` então o layout na memória linear é: + +``` +a b c d e f +``` + +Uma ordem de dimensão menor para maior de `N-1` até `0` para um array `N` dimensional é semelhante ao *row-major* (no posto 2). Assumindo uma ordenação monotônica de dimensões, outro nome que podemos usar para nos referir a esse layout no código é simplesmente “dim 0 é maior”. + +#### Ordenação menor para maior padrão + +O layout padrão para Shapes recém-criados é "a ordem das dimensões é maior para menor" (similar ao row-major nanoposto 2). + +### Preenchimento + +O preenchimento (padding) é definido nos campos opcionais `padded_dimensions` e `padding_value`. O campo `padded_dimensions` descreve os tamanhos (larguras) para os quais cada dimensão é preenchida. Se presente, o número de elementos em `padded_dimensions` deve ser igual ao posto do formato. + +Por exemplo, dado o array `[2 x 3]` definido acima, se `padded_dimensions` for `[3, 5]`, então a dimensão 0 será preenchida com uma largura de 3 e a dimensão 1 será preenchida com uma largura 5. O layout na memória linear (assumindo um valor de preenchimento de 0 e layout de coluna principal) é: + +``` +a d 0 b e 0 c f 0 0 0 0 0 0 0 +``` + +Isto é equivalente ao layout do seguinte array com a mesma ordem de dimensão menor para maior: + +``` +a b c 0 0 +d e f 0 0 +0 0 0 0 0 +``` + +### Indexação em arrays + +A classe `IndexUtil` em [index_util.h](https://www.tensorflow.org/code/tensorflow/compiler/xla/index_util.h) fornece utilitários para conversão entre índices multidimensionais e índices lineares, dada um formato e um layout. Os índices multidimensionais incluem um índice `int64` para cada dimensão. Os índices lineares são um único valor `int64` que indexa no buffer que contém o array. Veja `shape_util.h` e `layout_util.h` no mesmo diretório para utilitários que simplificam a criação e manipulação de formatos e layouts. diff --git a/site/pt-br/xla/tfcompile.md b/site/pt-br/xla/tfcompile.md new file mode 100644 index 0000000000..a99bc9a0c2 --- /dev/null +++ b/site/pt-br/xla/tfcompile.md @@ -0,0 +1,218 @@ +# Usando compilação AOT + +## O que é tfcompile? + +O `tfcompile` é uma ferramenta autônoma que compila grafos do TensorFlow antecipadamente (AOT) em código executável. Ele pode reduzir o tamanho binário total e também evitar algumas sobrecargas de tempo de execução. Um caso de uso típico de `tfcompile` é compilar um grafo de inferência em código executável para dispositivos móveis. + +O grafo do TensorFlow normalmente é executado pelo runtime do TensorFlow. Isso incorre em alguma sobrecarga de tempo de execução para a execução de cada nó do grafo. Isso também leva a um tamanho total maior de código binário, já que o código do runtime do TensorFlow precisa estar disponível, além do próprio grafo. O código executável produzido por `tfcompile` não usa o runtime do TensorFlow e só possui dependências de kernels que são realmente usados ​​na computação. + +O compilador é construído sobre o framework XLA. O código que liga o TensorFlow ao framework XLA reside em [tensorflow/compiler](https://www.tensorflow.org/code/tensorflow/compiler/). + +## O que o tfcompile faz? + +O `tfcompile` pega um subgrafo, identificado pelos conceitos de feeds e fetches do TensorFlow, e gera uma função que implementa esse subgrafo. Os `feeds` são argumentos de entrada da função e os `fetches` são os argumentos de saída da função. Todas as entradas devem ser totalmente especificadas pelos feeds; o subgrafo removido resultante não pode conter nós Placeholder ou Variable. É comum especificar todos os espaços reservados e variáveis ​​como feeds, o que garante que o subgrafo resultante não contenha mais esses nós. A função gerada é empacotada como `cc_library`, com um arquivo de cabeçalho exportando a assinatura da função e um arquivo objeto contendo a implementação. O usuário escreve código para chamar a função gerada conforme apropriado. + +## Usando tfcompile + +Esta seção detalha passos de alto nível para gerar um binário executável com `tfcompile` a partir de um subgrafo do TensorFlow. Os passos são: + +- Passo 1: configure o subgrafo para compilar +- Passo 2: use a macro de build `tf_library` para compilar o subgrafo +- Passo 3: escreva o código para chamar o subgrafo +- Passo 4: crie o binário final + +### Passo 1: configure o subgrafo para compilar + +Identifique os feeds e fetches que correspondem aos argumentos de entrada e saída da função gerada. Em seguida, configure os `feeds` e `fetches` em um proto [`tensorflow.tf2xla.Config`](https://www.tensorflow.org/code/tensorflow/compiler/tf2xla/tf2xla.proto). + +```textproto +# Each feed is a positional input argument for the generated function. The order +# of each entry matches the order of each input argument. Here “x_hold” and “y_hold” +# refer to the names of placeholder nodes defined in the graph. +feed { + id { node_name: "x_hold" } + shape { + dim { size: 2 } + dim { size: 3 } + } +} +feed { + id { node_name: "y_hold" } + shape { + dim { size: 3 } + dim { size: 2 } + } +} + +# Each fetch is a positional output argument for the generated function. The order +# of each entry matches the order of each output argument. Here “x_y_prod” +# refers to the name of a matmul node defined in the graph. +fetch { + id { node_name: "x_y_prod" } +} +``` + +### Passo 2: use a macro de build tf_library para compilar o subgrafo + +Este passo converte o grafo numa `cc_library` usando a macro de build `tf_library`. A `cc_library` consiste num arquivo objeto contendo o código gerado a partir do grafo, junto com um arquivo de cabeçalho que dá acesso ao código gerado. `tf_library` utiliza `tfcompile` para compilar o grafo do TensorFlow em código executável. + +```build +load("//tensorflow/compiler/aot:tfcompile.bzl", "tf_library") + +# Use the tf_library macro to compile your graph into executable code. +tf_library( + # name is used to generate the following underlying build rules: + # : cc_library packaging the generated header and object files + # _test : cc_test containing a simple test and benchmark + # _benchmark : cc_binary containing a stand-alone benchmark with minimal deps; + # can be run on a mobile device + name = "test_graph_tfmatmul", + # cpp_class specifies the name of the generated C++ class, with namespaces allowed. + # The class will be generated in the given namespace(s), or if no namespaces are + # given, within the global namespace. + cpp_class = "foo::bar::MatMulComp", + # graph is the input GraphDef proto, by default expected in binary format. To + # use the text format instead, just use the ‘.pbtxt’ suffix. A subgraph will be + # created from this input graph, with feeds as inputs and fetches as outputs. + # No Placeholder or Variable ops may exist in this subgraph. + graph = "test_graph_tfmatmul.pb", + # config is the input Config proto, by default expected in binary format. To + # use the text format instead, use the ‘.pbtxt’ suffix. This is where the + # feeds and fetches were specified above, in the previous step. + config = "test_graph_tfmatmul.config.pbtxt", +) +``` + +> Para gerar o proto GraphDef (test_graph_tfmatmul.pb) para este exemplo, execute [make_test_graphs.py](https://www.tensorflow.org/code/tensorflow/compiler/aot/tests/make_test_graphs.py) e especifique o local de saída com o sinalizador --out_dir. + +Grafos típicos contêm [`Variables`](https://www.tensorflow.org/guide/variables) que representam os pesos que são aprendidos por meio de treinamento, mas `tfcompile` não pode compilar um subgrafo que contenha `Variables`. A ferramenta [freeze_graph.py](https://www.tensorflow.org/code/tensorflow/python/tools/freeze_graph.py) converte variáveis ​​em constantes, usando valores armazenados em um arquivo de checkpoint. Por conveniência, a macro `tf_library` suporta o argumento `freeze_checkpoint`, que executa a ferramenta. Para mais exemplos, consulte [tensorflow/compiler/aot/tests/BUILD](https://www.tensorflow.org/code/tensorflow/compiler/aot/tests/BUILD) . + +> As constantes que aparecem no subgrafo compilado são compiladas diretamente no código gerado. Para passar as constantes para a função gerada, em vez de compilá-las, simplesmente passe-as como feeds. + +Para detalhes sobre a macro de build `tf_library`, veja [tfcompile.bzl](https://www.tensorflow.org/code/tensorflow/compiler/aot/tfcompile.bzl). + +Para detalhes sobre a ferramenta `tfcompile` nativa, veja [tfcompile_main.cc](https://www.tensorflow.org/code/tensorflow/compiler/aot/tfcompile_main.cc). + +### Passo 3: escreva o código para chamar o subgrafo + +Este passo usa o arquivo de cabeçalho (`test_graph_tfmatmul.h`) gerado pela macro de build `tf_library` no passo anterior para chamar o código gerado. O arquivo de cabeçalho está localizado no diretório `bazel-bin` correspondente ao pacote de build e é nomeado com base no atributo name definido na macro de build `tf_library`. Por exemplo, o cabeçalho gerado para `test_graph_tfmatmul` seria `test_graph_tfmatmul.h`. Abaixo está uma versão abreviada do que é gerado. O arquivo gerado, em `bazel-bin`, contém comentários úteis adicionais. + +```c++ +namespace foo { +namespace bar { + +// MatMulComp represents a computation previously specified in a +// TensorFlow graph, now compiled into executable code. +class MatMulComp { + public: + // AllocMode controls the buffer allocation mode. + enum class AllocMode { + ARGS_RESULTS_AND_TEMPS, // Allocate arg, result and temp buffers + RESULTS_AND_TEMPS_ONLY, // Only allocate result and temp buffers + }; + + MatMulComp(AllocMode mode = AllocMode::ARGS_RESULTS_AND_TEMPS); + ~MatMulComp(); + + // Runs the computation, with inputs read from arg buffers, and outputs + // written to result buffers. Returns true on success and false on failure. + bool Run(); + + // Arg methods for managing input buffers. Buffers are in row-major order. + // There is a set of methods for each positional argument. + void** args(); + + void set_arg0_data(float* data); + float* arg0_data(); + float& arg0(size_t dim0, size_t dim1); + + void set_arg1_data(float* data); + float* arg1_data(); + float& arg1(size_t dim0, size_t dim1); + + // Result methods for managing output buffers. Buffers are in row-major order. + // Must only be called after a successful Run call. There is a set of methods + // for each positional result. + void** results(); + + + float* result0_data(); + float& result0(size_t dim0, size_t dim1); +}; + +} // end namespace bar +} // end namespace foo +``` + +A classe C++ gerada é chamada `MatMulComp` no namespace `foo::bar`, porque essa era a `cpp_class` especificada na macro `tf_library`. Todas as classes geradas possuem uma API semelhante, com a única diferença sendo os métodos para lidar com buffers de argumentos e resultados. Esses métodos diferem com base no número e nos tipos de buffers, que foram especificados pelos argumentos `feed` e `fetch` para a macro `tf_library`. + +Há três tipos de buffers gerenciados na classe gerada: `args` representando as entradas, `results` representando as saídas e `temps` representando buffers temporários usados ​​internamente para realizar o cálculo. Por padrão, cada instância da classe gerada aloca e gerencia todos esses buffers para você. O argumento do construtor `AllocMode` pode ser usado para alterar esse comportamento. Todos os buffers estão alinhados aos limites de 64 bytes. + +A classe C++ gerada é apenas um wrapper em torno do código de baixo nível gerado pelo XLA. + +Exemplo de chamada da função gerada com base em [`tfcompile_test.cc`](https://www.tensorflow.org/code/tensorflow/compiler/aot/tests/tfcompile_test.cc): + +```c++ +#define EIGEN_USE_THREADS +#define EIGEN_USE_CUSTOM_THREAD_POOL + +#include +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/compiler/aot/tests/test_graph_tfmatmul.h" // generated + +int main(int argc, char** argv) { + Eigen::ThreadPool tp(2); // Size the thread pool as appropriate. + Eigen::ThreadPoolDevice device(&tp, tp.NumThreads()); + + + foo::bar::MatMulComp matmul; + matmul.set_thread_pool(&device); + + // Set up args and run the computation. + const float args[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + std::copy(args + 0, args + 6, matmul.arg0_data()); + std::copy(args + 6, args + 12, matmul.arg1_data()); + matmul.Run(); + + // Check result + if (matmul.result0(0, 0) == 58) { + std::cout << "Success" << std::endl; + } else { + std::cout << "Failed. Expected value 58 at 0,0. Got:" + << matmul.result0(0, 0) << std::endl; + } + + return 0; +} +``` + +### Passo 4: crie o binário final + +Este passo combina a biblioteca gerada por `tf_library` no passo 2 e o código escrito no passo 3 para criar um arquivo binário final. Abaixo está um exemplo de arquivo BUILD do `bazel`. + +```build +# Example of linking your binary +# Also see //tensorflow/compiler/aot/tests/BUILD +load("//tensorflow/compiler/aot:tfcompile.bzl", "tf_library") + +# The same tf_library call from step 2 above. +tf_library( + name = "test_graph_tfmatmul", + ... +) + +# The executable code generated by tf_library can then be linked into your code. +cc_binary( + name = "my_binary", + srcs = [ + "my_code.cc", # include test_graph_tfmatmul.h to access the generated header + ], + deps = [ + ":test_graph_tfmatmul", # link in the generated object file + "//third_party/eigen3", + ], + linkopts = [ + "-lpthread", + ] +) +``` diff --git a/site/pt-br/xla/tiled_layout.md b/site/pt-br/xla/tiled_layout.md new file mode 100644 index 0000000000..78185d956b --- /dev/null +++ b/site/pt-br/xla/tiled_layout.md @@ -0,0 +1,55 @@ +# Layout com tiles + +Atenção: o layout com tiles é *um pré-lançamento* este documento descreve como ele deve funcionar. Erros poderãi ser ignorados silenciosamente. + +

Figura 1

+ +A Figura 1 mostra como um array F32[3,5] é disposto na memória com tiles (ladrilhos) nas dimensões 2x2. Um formato com este layout é escrito como F32[3,5]{1,0:T(2,2)}, onde 1,0 se refere à ordem física das dimensões (campo minor_to_major em Layout) enquanto (2,2) depois dos dois pontos indica o tiling das dimensões físicas por um tile de dimensões 2x2. + +Intuitivamente, os tiles são dispostos para cobrir o formato e, em seguida, dentro de cada tile, os elementos são dispostos sem usar tiling, como no exemplo acima, onde a parte direita do exemplo mostra o layout na memória, incluindo os elementos de preenchimento (padding) que são adicionados para ter tiles 2x2 completos, mesmo que os limites do array original não sejam iguais. + +Os elementos extras no preenchimento não precisam conter nenhum valor específico. + +## Fórmulas de índice linear para o tiling, dados um formato e um tile + +Sem tiling, um elemento e=(e n , e n-1, ... , e 1 ) num array com limites de array d=(d n , d n-1, ... , d 1) (d1 é a menor dimensão) é disposta na ordem de maior para menor na posição: + + linear_index(e, d)
= linear_index((en, en-1, ... , e1), (dn, dn-1, ... , d1))
= endn-1...d1 + en-1dn-2...d1 + ... + e1 + +Para simplificar a notação neste documento, assumimos que um tile tem o mesmo número de dimensões que o array. Na implementação de tiling do XLA, isto é generalizado para tiles com menos dimensões, deixando, inicialmente, as dimensões maiores inalteradas e aplicando o tiling apenas às dimensões menores, de modo que o tiling especificado mencione um sufixo das dimensões físicas do formato no qual se está aplicando o tiling. + +Quando o tiling de dimensões (t n, t n-1, ... , t 1) é usado, um elemento no array com índices (en, en-1, ... , e1) é mapeado para esta posição no layout final: + + linear_index_with_tile(e, d, t)
= linear_index((⌊e/t⌋, e mod t), (⌈d/t⌉, t)) (aritmética é elemento por elemento, (a,b) é concatenação)
= linear_index((⌊en/tn⌋, ... , ⌊e1/t1⌋, en mod tn, ... , e1 mod t1), (⌈dn/tn⌉, ... , ⌈d1/t1⌉, tn, tn-1, ... , t1))
= linear_index((⌊en/tn⌋, ... , ⌊e1/t1⌋), (⌈dn/tn⌉, ... , ⌈d1/t1⌉))∙tntn-1...t1 + linear_index((en mod tn, ... , e1 mod t1), (tn, tn-1, ... , t1)) + +Pode-se considerar o layout como tendo duas partes: (⌊e n/tn⌋, ... , ⌊e 1 /t1⌋), que corresponde a um índice de tiles num array de tiles de tamanho (⌈d n/tn ⌉, ... , ⌈d 1/t1 ⌉), e (e nmod tn , ... , e 1 mod t 1 ), que corresponde a um índice dentro do tile. A função ceil aparece em ⌈d i/ti ⌉ porque se os blocos ultrapassarem os limites do array maior, o preenchimento será inserido como na Figura 1. Tanto os blocos quanto os elementos dentro dos blocos são dispostos recursivamente sem tiling. + +Para o exemplo da Figura 1, o elemento (2,3) tem o índice do tile (1,1) e índice dentro do tile (0,1), para um vetor de coordenadas combinado de (1, 1, 0, 1). Os índices dos tiles têm limites (2, 3) e o próprio tile é (2, 2) para um vetor combinado de (2, 3, 2, 2). Assim, o índice linear com tile para o elemento com índice (2, 3) na forma lógica é + + linear_index_with_tile((2,3), (3,5), (2,2))
= linear_index((1,1,0,1), (2,3,2,2))
= linear_index((1,1), (2,3)) ∙ 2 ∙ 2 + linear_index((0,1), (2,2))
= (1 ∙ 3 + 1) ∙ 2 ∙ 2 + (0 ∙ 2 + 1)
= 17. + +# Tiling como pad-reshape-transpose + +O layout baseado em tiling funciona da seguinte maneira: (dn, dn-1, ... , d1) (d1 é a dimensão menor). Quando é disposto com um tiling de dimensões (tn, tn-1, ... , t1) (t1 é a dimensão menor), esse tiling pode ser descrito em termos de pad-reshape-transpose da seguinte forma + +1. O array é preenchido para (⌈dn/tn⌉∙tn, ... , ⌈d1/t1⌉∙t1). +2. Cada dimensão i é dividida em (⌈di/ti⌉, ti), ou seja, o array é reformatado para
(⌈dn/tn⌉, tn, ... , ⌈d1/t1⌉, t1).
Não há nenhuma mudança de layout físico nesta alteração por si só, então esta aleração é um bitcast. Se não estivermos pensando explicitamente em um tile, essa remodelação poderia expressar qualquer formato com o mesmo número de elementos que o formato com preenchimento - o exemplo aqui é sobre como expressar um tile dessa maneira. +3. Uma transposição (transpose) acontece movendo t n, ... , t 1 para as dimensões menores, mantendo sua ordem relativa, de modo que a maioria das ordens de dimensões do maior para o menor se torne (⌈dn/tn⌉, ... , ⌈d1/t1⌉, tn, ... , t1). + +O formato final tem o prefixo

(⌈dn/tn⌉, ... , ⌈d1/t1⌉), que descreve o número de tiles em cada dimensão. Um elemento na matriz (e n, ... , e 1) é mapeado para este elemento no formato final: (⌊en/tn⌋, ... , ⌊e0/t0⌋, en mod tn, ... , e1 mod t1). É fácil perceber que o índice linear do elemento segue a fórmula acima conforme o esperado. + +# Tiles repetidos + +O tiling do XLA torna-se ainda mais flexível ao aplicá-lo de forma repetida. + +

Figura 2

+ +A Figura 2 mostra como um array de tamanho 4x8 é dividido em dois níveis de tiling (primeiro 2x4 e depois 2x1). Representamos esse tiling repetido como (2,4)(2,1). Cada cor indica um tile 2x4 e cada caixa de borda vermelha é um tile 2x1. Os números indicam o índice linear na memória desse elemento no formato do tiling. Este formato corresponde ao formato usado para BF16 na TPU, exceto que o tile inicial é maior, ou seja, o tiling é (8,128)(2,1), onde o objetivo do segundo tiling por 2x1 é coletar dois valores de 16 bits para formar um valor de 32 bits de forma que se alinhe com a arquitetura de uma TPU. + +Observe que um segundo tile ou tile posterior pode se referir às dimensões menores dentro do tile, que apenas reorganiza os dados dentro dele, como neste exemplo com (8,128)(2,1), mas também pode se referir às dimensões principais entre tiles obtidas do tiling anterior. + +# Combinando dimensões usando tiles + +O tiling do XLA também suporta a combinação de dimensões. Por exemplo, ele pode combinar dimensões em F32[2,7,8,11,10]{4,3,2,1,0} para F32[112,110]{1,0} antes de fazer o tiling com (2,3 ). O tile usado é (∗,∗,2,∗,3). Aqui, um asterisco em um tile implica pegar essa dimensão e combiná-la com a próxima dimensão menor. Múltiplas dimensões adjacentes podem ser agrupadas numa dimensão. Uma dimensão agrupada é representada por um valor de tile de -1 naquela dimensão do tile, que de outra forma não seria válido num tile como tamanho de dimensão. + +Mais precisamente, se a dimensão i do formato for eliminada por meio de um asterisco no tile, então, antes da definição anterior de tiling ser aplicada, essa dimensão será removida tanto do formato que está sendo disposto usando tiling, quanto do vetor do tile, e o que era a dimensão i-1 do formato tem seu limite de array aumentado de di-1 para didi-1. Esse passo é repetido para cada asterisco no vetor de tiles. diff --git a/site/pt-br/xla/tutorials/autoclustering_xla.ipynb b/site/pt-br/xla/tutorials/autoclustering_xla.ipynb new file mode 100644 index 0000000000..4af0efb026 --- /dev/null +++ b/site/pt-br/xla/tutorials/autoclustering_xla.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "f4TSNCvpENrW" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "vamNSA0vEP-m" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "asd4sdga7g" + }, + "source": [ + "# Classificando o CIFAR-10 com XLA\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b7noD9NjFRL-" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + "Executar no Google ColabVer fonte no GitHubBaixar notebook
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mz65veHXsmnS" + }, + "source": [ + "Este tutorial treina um modelo TensorFlow para classificar o dataset [CIFAR-10](https://en.wikipedia.org/wiki/CIFAR-10) e o compilamos usando XLA.\n", + "\n", + "Você carregará e normalizará o dataset usando a API [TensorFlow Datasets (TFDS)](https://tensorflow.org/datasets). Primeiro, instale/atualize o TensorFlow e o TFDS:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "R4xtYyOf78e3" + }, + "outputs": [ + + ], + "source": [ + "!pip install -U -q tensorflow tensorflow_datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PH2HbLW65tmo" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n", + "import tensorflow_datasets as tfds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7vm2QsMisCxI" + }, + "outputs": [ + + ], + "source": [ + "# Check that GPU is available: cf. https://colab.research.google.com/notebooks/gpu.ipynb\n", + "assert(tf.test.gpu_device_name())\n", + "\n", + "tf.keras.backend.clear_session()\n", + "tf.config.optimizer.set_jit(False) # Start with XLA disabled.\n", + "\n", + "def load_data():\n", + " result = tfds.load('cifar10', batch_size = -1)\n", + " (x_train, y_train) = result['train']['image'],result['train']['label']\n", + " (x_test, y_test) = result['test']['image'],result['test']['label']\n", + " \n", + " x_train = x_train.numpy().astype('float32') / 256\n", + " x_test = x_test.numpy().astype('float32') / 256\n", + "\n", + " # Convert class vectors to binary class matrices.\n", + " y_train = tf.keras.utils.to_categorical(y_train, num_classes=10)\n", + " y_test = tf.keras.utils.to_categorical(y_test, num_classes=10)\n", + " return ((x_train, y_train), (x_test, y_test))\n", + "\n", + "(x_train, y_train), (x_test, y_test) = load_data()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MgNM2tbgtScx" + }, + "source": [ + "Definimos o modelo, adaptado do [exemplo Keras CIFAR-10](https://keras.io/examples/cifar10_cnn/):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3ZRQSwoRsKM_" + }, + "outputs": [ + + ], + "source": [ + "def generate_model():\n", + " return tf.keras.models.Sequential([\n", + " tf.keras.layers.Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:]),\n", + " tf.keras.layers.Activation('relu'),\n", + " tf.keras.layers.Conv2D(32, (3, 3)),\n", + " tf.keras.layers.Activation('relu'),\n", + " tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " tf.keras.layers.Dropout(0.25),\n", + "\n", + " tf.keras.layers.Conv2D(64, (3, 3), padding='same'),\n", + " tf.keras.layers.Activation('relu'),\n", + " tf.keras.layers.Conv2D(64, (3, 3)),\n", + " tf.keras.layers.Activation('relu'),\n", + " tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),\n", + " tf.keras.layers.Dropout(0.25),\n", + "\n", + " tf.keras.layers.Flatten(),\n", + " tf.keras.layers.Dense(512),\n", + " tf.keras.layers.Activation('relu'),\n", + " tf.keras.layers.Dropout(0.5),\n", + " tf.keras.layers.Dense(10),\n", + " tf.keras.layers.Activation('softmax')\n", + " ])\n", + "\n", + "model = generate_model()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-M4GtGDZtb8a" + }, + "source": [ + "Treinamos o modelo usando o otimizador [RMSprop](https://www.tensorflow.org/api_docs/python/tf/train/RMSPropOptimizer):\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UKCmrhF0tiMa" + }, + "outputs": [ + + ], + "source": [ + "def compile_model(model):\n", + " opt = tf.keras.optimizers.RMSprop(learning_rate=0.0001)\n", + " model.compile(loss='categorical_crossentropy',\n", + " optimizer=opt,\n", + " metrics=['accuracy'])\n", + " return model\n", + "\n", + "model = compile_model(model)\n", + "\n", + "def train_model(model, x_train, y_train, x_test, y_test, epochs=25):\n", + " model.fit(x_train, y_train, batch_size=256, epochs=epochs, validation_data=(x_test, y_test), shuffle=True)\n", + "\n", + "def warmup(model, x_train, y_train, x_test, y_test):\n", + " # Warm up the JIT, we do not wish to measure the compilation time.\n", + " initial_weights = model.get_weights()\n", + " train_model(model, x_train, y_train, x_test, y_test, epochs=1)\n", + " model.set_weights(initial_weights)\n", + "\n", + "warmup(model, x_train, y_train, x_test, y_test)\n", + "%time train_model(model, x_train, y_train, x_test, y_test)\n", + "\n", + "scores = model.evaluate(x_test, y_test, verbose=1)\n", + "print('Test loss:', scores[0])\n", + "print('Test accuracy:', scores[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SLpfQ0StRgsu" + }, + "source": [ + "Agora vamos treinar o modelo novamente, usando o compilador XLA. Para habilitar o compilador no meio da aplicação, precisamos redefinir a sessão Keras." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jxU-Tzy4SX7p" + }, + "outputs": [ + + ], + "source": [ + "# We need to clear the session to enable JIT in the middle of the program.\n", + "tf.keras.backend.clear_session()\n", + "tf.config.optimizer.set_jit(True) # Enable XLA.\n", + "model = compile_model(generate_model())\n", + "(x_train, y_train), (x_test, y_test) = load_data()\n", + "\n", + "warmup(model, x_train, y_train, x_test, y_test)\n", + "%time train_model(model, x_train, y_train, x_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iWHz6P1se92F" + }, + "source": [ + "Numa máquina com GPU Titan V e CPU Intel Xeon E5-2690, a velocidade é de aproximadamente 1,17x." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [ + + ], + "name": "autoclustering_xla.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/site/pt-br/xla/tutorials/compile.ipynb b/site/pt-br/xla/tutorials/compile.ipynb new file mode 100644 index 0000000000..b0ee5579d3 --- /dev/null +++ b/site/pt-br/xla/tutorials/compile.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "f4TSNCvpENrW" + }, + "source": [ + "##### Copyright 2019 The TensorFlow Authors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "vamNSA0vEP-m" + }, + "outputs": [ + + ], + "source": [ + "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e1oSi4lHFt3z" + }, + "source": [ + "# Usando XLA com tf.function" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b7noD9NjFRL-" + }, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + "
Ver em TensorFlow.org\n", + " Executar no Google Colab\n", + " Baixar notebook\n", + " Ver fonte no GitHub\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sDy5lSBd4BDE" + }, + "source": [ + "Este tutorial treina um modelo TensorFlow para classificar o dataset MNIST, onde a função de treinamento é compilada usando XLA.\n", + "\n", + "Primeiro, carregue o TensorFlow e habilite a execução eager." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "45kUPj5ZFrRa" + }, + "outputs": [ + + ], + "source": [ + "import tensorflow as tf\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GZVNiRmTDV-5" + }, + "source": [ + "Em seguida, defina algumas constantes necessárias e prepare o dataset MNIST." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "f37TSEGvGX4_" + }, + "outputs": [ + + ], + "source": [ + "# Size of each input image, 28 x 28 pixels\n", + "IMAGE_SIZE = 28 * 28\n", + "# Number of distinct number labels, [0..9]\n", + "NUM_CLASSES = 10\n", + "# Number of examples in each training batch (step)\n", + "TRAIN_BATCH_SIZE = 100\n", + "# Number of training steps to run\n", + "TRAIN_STEPS = 1000\n", + "\n", + "# Loads MNIST dataset.\n", + "train, test = tf.keras.datasets.mnist.load_data()\n", + "train_ds = tf.data.Dataset.from_tensor_slices(train).batch(TRAIN_BATCH_SIZE).repeat()\n", + "\n", + "# Casting from raw data to the required datatypes.\n", + "def cast(images, labels):\n", + " images = tf.cast(\n", + " tf.reshape(images, [-1, IMAGE_SIZE]), tf.float32)\n", + " labels = tf.cast(labels, tf.int64)\n", + " return (images, labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lv7I-u_82v1S" + }, + "source": [ + "Por fim, defina o modelo e o otimizador. O modelo usa uma única camada densa." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7O2NcEfG206Q" + }, + "outputs": [ + + ], + "source": [ + "layer = tf.keras.layers.Dense(NUM_CLASSES)\n", + "optimizer = tf.keras.optimizers.Adam()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "x_ZehpZP-SfS" + }, + "source": [ + "# Defina a função de treinamento\n", + "\n", + "Na função de treinamento, você obtém os rótulos previstos usando a camada definida acima e, em seguida, minimiza o gradiente de perda usando o otimizador. Para compilar a computação usando XLA, coloque-a dentro de `tf.function` com `jit_compile=True`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZbhJl_WvGa3g" + }, + "outputs": [ + + ], + "source": [ + "@tf.function(experimental_compile=True)\n", + "def train_mnist(images, labels):\n", + " images, labels = cast(images, labels)\n", + "\n", + " with tf.GradientTape() as tape:\n", + " predicted_labels = layer(images)\n", + " loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(\n", + " logits=predicted_labels, labels=labels\n", + " ))\n", + " layer_variables = layer.trainable_variables\n", + " grads = tape.gradient(loss, layer_variables)\n", + " optimizer.apply_gradients(zip(grads, layer_variables))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EZD1m_n1DxAF" + }, + "source": [ + "# Treine e teste o modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gukC2Hol3sFZ" + }, + "source": [ + "Depois de definir a função de treinamento, defina o modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qe28bAHNHUG2" + }, + "outputs": [ + + ], + "source": [ + "for images, labels in train_ds:\n", + " if optimizer.iterations > TRAIN_STEPS:\n", + " break\n", + " train_mnist(images, labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qgsKmz3n2UiW" + }, + "source": [ + "E, finalmente, verifique a exatidão:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_GxF6jTRHVuA" + }, + "outputs": [ + + ], + "source": [ + "images, labels = cast(test[0], test[1])\n", + "predicted_labels = layer(images)\n", + "correct_prediction = tf.equal(tf.argmax(predicted_labels, 1), labels)\n", + "accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", + "print(\"Prediction accuracy after training: %s\" % accuracy)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PXoOjJnuZRaV" + }, + "source": [ + "Nos bastidores, o compilador XLA compilou toda a função TF para HLO, o que permitiu otimizações de fusão. Usando os recursos de introspecção, podemos ver o código HLO (outros valores possíveis interessantes para \"stage\" são `optimized_hlo` para HLO após otimizações e `optimized_hlo_dot` para um grafo Graphviz):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_a8GsNLVaLSQ" + }, + "outputs": [ + + ], + "source": [ + "print(train_mnist.experimental_get_compiler_ir(images, labels)(stage='hlo'))" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + + ], + "name": "jit_compile.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 678b9c9c56b0671ec8933e6f11cc152875f5318e Mon Sep 17 00:00:00 2001 From: ilyaspiridonov Date: Sat, 4 Nov 2023 15:06:00 +0300 Subject: [PATCH 2/5] nblint, nbfmt --- site/pt-br/guide/core/mlp_core.ipynb | 124 ++------ site/pt-br/guide/saved_model.ipynb | 114 ++----- site/pt-br/guide/tpu.ipynb | 62 ++-- site/pt-br/lite/guide/model_analyzer.ipynb | 30 +- site/pt-br/lite/guide/signatures.ipynb | 38 +-- .../convert/metadata_writer_tutorial.ipynb | 94 ++---- .../model_maker/audio_classification.ipynb | 78 ++--- .../model_maker/image_classification.ipynb | 114 ++----- .../modify/model_maker/object_detection.ipynb | 62 ++-- .../modify/model_maker/question_answer.ipynb | 62 ++-- .../model_maker/speech_recognition.ipynb | 106 ++----- .../model_maker/text_classification.ipynb | 126 +++----- .../post_training_float16_quant.ipynb | 82 ++--- .../post_training_integer_quant.ipynb | 78 ++--- .../post_training_integer_quant_16x8.ipynb | 90 ++---- .../performance/post_training_quant.ipynb | 86 ++---- .../performance/quantization_debugger.ipynb | 118 ++------ .../lite/tutorials/pose_classification.ipynb | 130 +++----- .../tutorials/images/transfer_learning.ipynb | 154 +++------- .../integrated_gradients.ipynb | 136 +++------ site/pt-br/tutorials/load_data/csv.ipynb | 280 +++++------------- .../video/video_classification.ipynb | 118 ++------ .../xla/tutorials/autoclustering_xla.ipynb | 38 +-- site/pt-br/xla/tutorials/compile.ipynb | 44 +-- 24 files changed, 622 insertions(+), 1742 deletions(-) diff --git a/site/pt-br/guide/core/mlp_core.ipynb b/site/pt-br/guide/core/mlp_core.ipynb index 2f7aab79cd..cadca5012e 100644 --- a/site/pt-br/guide/core/mlp_core.ipynb +++ b/site/pt-br/guide/core/mlp_core.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "AwOEIRJC6Une" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -123,9 +121,7 @@ "metadata": { "id": "mSfgqmwBagw_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Use seaborn for countplot.\n", "!pip install -q seaborn" @@ -137,9 +133,7 @@ "metadata": { "id": "1rRo8oNqZ-Rj" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import pandas as pd\n", "import matplotlib\n", @@ -157,9 +151,7 @@ "metadata": { "id": "9xQKvCJ85kCQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", @@ -187,9 +179,7 @@ "metadata": { "id": "Uiuh0B098_3p" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data, val_data, test_data = tfds.load(\"mnist\", \n", " split=['train[10000:]', 'train[0:10000]', 'test'],\n", @@ -211,9 +201,7 @@ "metadata": { "id": "6V8hSqJ7AMjQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "x_viz, y_viz = tfds.load(\"mnist\", split=['train[:1500]'], batch_size=-1, as_supervised=True)[0]\n", "x_viz = tf.squeeze(x_viz, axis=3)\n", @@ -241,9 +229,7 @@ "metadata": { "id": "Rj3K4XgQE7qR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "sns.countplot(x=y_viz.numpy());\n", "plt.xlabel('Digits')\n", @@ -267,9 +253,7 @@ "metadata": { "id": "JSyCm2V2_AvI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def preprocess(x, y):\n", " # Reshaping the data\n", @@ -300,9 +284,7 @@ "metadata": { "id": "hYunzt3UyT9G" }, - "outputs": [ - - ], + "outputs": [], "source": [ "x = tf.linspace(-2, 2, 201)\n", "x = tf.cast(x, tf.float32)\n", @@ -329,9 +311,7 @@ "metadata": { "id": "fVM8pvhWwuwI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "x = tf.linspace(-4, 4, 201)\n", "x = tf.cast(x, tf.float32)\n", @@ -362,9 +342,7 @@ "metadata": { "id": "re1SSFyBdMrS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def xavier_init(shape):\n", " # Computes the xavier initialization values for a weight matrix\n", @@ -390,9 +368,7 @@ "metadata": { "id": "IM0yJos25FG5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class DenseLayer(tf.Module):\n", "\n", @@ -431,9 +407,7 @@ "metadata": { "id": "6XisRWiCyHAb" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class MLP(tf.Module):\n", "\n", @@ -467,9 +441,7 @@ "metadata": { "id": "VmlACuki3oPi" }, - "outputs": [ - - ], + "outputs": [], "source": [ "hidden_layer_1_size = 700\n", "hidden_layer_2_size = 500\n", @@ -507,9 +479,7 @@ "metadata": { "id": "rskOYA7FVCwg" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def cross_entropy_loss(y_pred, y):\n", " # Compute cross entropy loss with a sparse operation\n", @@ -532,9 +502,7 @@ "metadata": { "id": "jPJMWx2UgiBm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def accuracy(y_pred, y):\n", " # Compute accuracy after extracting class predictions\n", @@ -560,9 +528,7 @@ "metadata": { "id": "iGIBDk3cAv6a" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class Adam:\n", "\n", @@ -611,9 +577,7 @@ "metadata": { "id": "CJLeY2ao1aw6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def train_step(x_batch, y_batch, loss, acc, model, optimizer):\n", " # Update the model state given a batch of data\n", @@ -639,9 +603,7 @@ "metadata": { "id": "oC85kuZgmh3q" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def train_model(mlp, train_data, val_data, loss, acc, optimizer, epochs):\n", " # Initialize data structures\n", @@ -695,9 +657,7 @@ "metadata": { "id": "zPlT8QfxptYl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_losses, train_accs, val_losses, val_accs = train_model(mlp_model, train_data, val_data, \n", " loss=cross_entropy_loss, acc=accuracy,\n", @@ -721,9 +681,7 @@ "metadata": { "id": "VXTCYVtNDjAM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def plot_metrics(train_metric, val_metric, metric_type):\n", " # Visualize metrics vs training Epochs\n", @@ -742,9 +700,7 @@ "metadata": { "id": "DC-qIvZbHo0G" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plot_metrics(train_losses, val_losses, \"cross entropy loss\")" ] @@ -755,9 +711,7 @@ "metadata": { "id": "P-w2xk2PIDve" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plot_metrics(train_accs, val_accs, \"accuracy\")" ] @@ -783,9 +737,7 @@ "metadata": { "id": "1sszfWuJJZoo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class ExportModule(tf.Module):\n", " def __init__(self, model, preprocess, class_pred):\n", @@ -809,9 +761,7 @@ "metadata": { "id": "p8x6gjTDVi5d" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def preprocess_test(x):\n", " # The export module takes in unprocessed and unlabeled data\n", @@ -839,9 +789,7 @@ "metadata": { "id": "fN9pPBQTKTe3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "mlp_model_export = ExportModule(model=mlp_model,\n", " preprocess=preprocess_test,\n", @@ -854,9 +802,7 @@ "metadata": { "id": "idS7rQKbKwRS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "models = tempfile.mkdtemp()\n", "save_path = os.path.join(models, 'mlp_model_export')\n", @@ -878,9 +824,7 @@ "metadata": { "id": "W5cwBTUqxldW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "mlp_loaded = tf.saved_model.load(save_path)" ] @@ -891,9 +835,7 @@ "metadata": { "id": "bmv0u6j_b5OC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def accuracy_score(y_pred, y):\n", " # Generic accuracy function\n", @@ -921,9 +863,7 @@ "metadata": { "id": "UD8YiC1Vfeyp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(\"Accuracy breakdown by digit:\")\n", "print(\"---------------------------\")\n", @@ -954,9 +894,7 @@ "metadata": { "id": "JqCaqPwwh1tN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import sklearn.metrics as sk_metrics\n", "\n", diff --git a/site/pt-br/guide/saved_model.ipynb b/site/pt-br/guide/saved_model.ipynb index c609f29143..66f3c16a09 100644 --- a/site/pt-br/guide/saved_model.ipynb +++ b/site/pt-br/guide/saved_model.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "FlUw7tSKbtg4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,9 +49,9 @@ "\n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", + " Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", "
" ] @@ -110,9 +108,7 @@ "metadata": { "id": "Le5OB-fBHHW7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import os\n", "import tempfile\n", @@ -130,9 +126,7 @@ "metadata": { "id": "wlho4HEWoHUT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "physical_devices = tf.config.list_physical_devices('GPU')\n", "for device in physical_devices:\n", @@ -145,9 +139,7 @@ "metadata": { "id": "SofdPKo0G8Lb" }, - "outputs": [ - - ], + "outputs": [], "source": [ "file = tf.keras.utils.get_file(\n", " \"grace_hopper.jpg\",\n", @@ -175,9 +167,7 @@ "metadata": { "id": "JhVecdzJTsKE" }, - "outputs": [ - - ], + "outputs": [], "source": [ "labels_path = tf.keras.utils.get_file(\n", " 'ImageNetLabels.txt',\n", @@ -191,9 +181,7 @@ "metadata": { "id": "aEHSYjW6JZHV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "pretrained_model = tf.keras.applications.MobileNet()\n", "result_before_save = pretrained_model(x)\n", @@ -218,9 +206,7 @@ "metadata": { "id": "8nfznDmHCW6F" }, - "outputs": [ - - ], + "outputs": [], "source": [ "mobilenet_save_path = os.path.join(tmpdir, \"mobilenet/1/\")\n", "tf.saved_model.save(pretrained_model, mobilenet_save_path)" @@ -243,9 +229,7 @@ "metadata": { "id": "NP2UpVFRV7N_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loaded = tf.saved_model.load(mobilenet_save_path)\n", "print(list(loaded.signatures.keys())) # [\"serving_default\"]" @@ -266,9 +250,7 @@ "metadata": { "id": "ChFLpegYfQGR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "infer = loaded.signatures[\"serving_default\"]\n", "print(infer.structured_outputs)" @@ -289,9 +271,7 @@ "metadata": { "id": "9WjGEaS3XfX7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]\n", "\n", @@ -330,9 +310,7 @@ "metadata": { "id": "6u3YZuYZXyTO" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls {mobilenet_save_path}" ] @@ -354,9 +332,7 @@ "metadata": { "id": "Pus0dOYTYXbI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!saved_model_cli show --dir {mobilenet_save_path} --tag_set serve" ] @@ -376,9 +352,7 @@ "metadata": { "id": "EDYqhDlNZAC2" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls {mobilenet_save_path}/variables" ] @@ -415,9 +389,7 @@ "metadata": { "id": "6EPvKiqXMm3d" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class CustomModule(tf.Module):\n", "\n", @@ -458,9 +430,7 @@ "metadata": { "id": "85PUO9iWH7xn" }, - "outputs": [ - - ], + "outputs": [], "source": [ "module_no_signatures_path = os.path.join(tmpdir, 'module_no_signatures')\n", "module(tf.constant(0.))\n", @@ -492,9 +462,7 @@ "metadata": { "id": "EMASjADPxPso" }, - "outputs": [ - - ], + "outputs": [], "source": [ "imported = tf.saved_model.load(module_no_signatures_path)\n", "assert imported(tf.constant(3.)).numpy() == 3\n", @@ -536,9 +504,7 @@ "metadata": { "id": "PEkQNarJ-7nT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "optimizer = tf.keras.optimizers.SGD(0.05)\n", "\n", @@ -557,9 +523,7 @@ "metadata": { "id": "p41NM6fF---3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for _ in range(10):\n", " # \"v\" approaches 5, \"loss\" approaches 0\n", @@ -589,9 +553,7 @@ "metadata": { "id": "Y6EUFdY8_PRD" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loaded = tf.saved_model.load(mobilenet_save_path)\n", "print(\"MobileNet has {} trainable variables: {}, ...\".format(\n", @@ -605,9 +567,7 @@ "metadata": { "id": "B-mQJ8iP_R0h" }, - "outputs": [ - - ], + "outputs": [], "source": [ "trainable_variable_ids = {id(v) for v in loaded.trainable_variables}\n", "non_trainable_variables = [v for v in loaded.variables\n", @@ -638,9 +598,7 @@ "metadata": { "id": "h-IB5Xa0NxLa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "assert len(imported.signatures) == 0" ] @@ -660,9 +618,7 @@ "metadata": { "id": "_pAdgIORR2yH" }, - "outputs": [ - - ], + "outputs": [], "source": [ "module_with_signature_path = os.path.join(tmpdir, 'module_with_signature')\n", "call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))\n", @@ -675,9 +631,7 @@ "metadata": { "id": "nAzRHR0UT4hv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "imported_with_signatures = tf.saved_model.load(module_with_signature_path)\n", "list(imported_with_signatures.signatures.keys())\n" @@ -698,9 +652,7 @@ "metadata": { "id": "6VYAiQmLUiox" }, - "outputs": [ - - ], + "outputs": [], "source": [ "module_multiple_signatures_path = os.path.join(tmpdir, 'module_with_multiple_signatures')\n", "signatures = {\"serving_default\": call,\n", @@ -715,9 +667,7 @@ "metadata": { "id": "8IPx_0RWEx07" }, - "outputs": [ - - ], + "outputs": [], "source": [ "imported_with_multiple_signatures = tf.saved_model.load(module_multiple_signatures_path)\n", "list(imported_with_multiple_signatures.signatures.keys())" @@ -738,9 +688,7 @@ "metadata": { "id": "ACKPl1X8G1gw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class CustomModuleWithOutputName(tf.Module):\n", " def __init__(self):\n", @@ -764,9 +712,7 @@ "metadata": { "id": "1yGVy4MuH-V0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "imported_with_output_name = tf.saved_model.load(module_output_path)\n", "imported_with_output_name.signatures['serving_default'].structured_outputs" diff --git a/site/pt-br/guide/tpu.ipynb b/site/pt-br/guide/tpu.ipynb index 82dcd23d75..f237ccba71 100644 --- a/site/pt-br/guide/tpu.ipynb +++ b/site/pt-br/guide/tpu.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "tuOe1ymfHZPu" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -43,9 +41,9 @@ "\n", "\n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", "
Veja em TensorFlow.org Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", + " Executar no Google Colab Ver fonte em GitHub Baixar notebook\n", "
" ] @@ -87,9 +85,7 @@ "metadata": { "id": "Cw0WRaChRxTL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "\n", @@ -123,9 +119,7 @@ "metadata": { "id": "dKPqF8d1wJCV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='')\n", "tf.config.experimental_connect_to_cluster(resolver)\n", @@ -151,9 +145,7 @@ "metadata": { "id": "XRZ4kMoxBNND" }, - "outputs": [ - - ], + "outputs": [], "source": [ "a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])\n", "b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])\n", @@ -193,9 +185,7 @@ "metadata": { "id": "7SO23K8oRpjI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "strategy = tf.distribute.TPUStrategy(resolver)" ] @@ -215,9 +205,7 @@ "metadata": { "id": "-90CL5uFPTOa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "@tf.function\n", "def matmul_fn(x, y):\n", @@ -256,9 +244,7 @@ "metadata": { "id": "DiBiN-Z_R7P7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def create_model():\n", " regularizer = tf.keras.regularizers.L2(1e-5)\n", @@ -316,9 +302,7 @@ "metadata": { "id": "noAd416KSCo7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def get_dataset(batch_size, is_training=True):\n", " split = 'train' if is_training else 'test'\n", @@ -363,9 +347,7 @@ "metadata": { "id": "ubmDchPqSIx0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "with strategy.scope():\n", " model = create_model()\n", @@ -402,9 +384,7 @@ "metadata": { "id": "M6e3aVVLUorL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "with strategy.scope():\n", " model = create_model()\n", @@ -447,9 +427,7 @@ "metadata": { "id": "9aHhqwao2Fxi" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Create the model, optimizer and metrics inside the `tf.distribute.Strategy`\n", "# scope, so that the variables can be mirrored on each device.\n", @@ -506,9 +484,7 @@ "metadata": { "id": "1du5cXWt6Vtw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "steps_per_eval = 10000 // batch_size\n", "\n", @@ -545,9 +521,7 @@ "metadata": { "id": "2grYvXLzJYkP" }, - "outputs": [ - - ], + "outputs": [], "source": [ "@tf.function\n", "def train_multiple_steps(iterator, steps):\n", @@ -607,9 +581,7 @@ "metadata": { "accelerator": "TPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "tpu.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/guide/model_analyzer.ipynb b/site/pt-br/lite/guide/model_analyzer.ipynb index dd48e5170b..740f983ecf 100644 --- a/site/pt-br/lite/guide/model_analyzer.ipynb +++ b/site/pt-br/lite/guide/model_analyzer.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "2pHVBk_seED1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -105,9 +103,7 @@ "metadata": { "id": "_jkg6UNtdz8c" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "\n", @@ -140,9 +136,7 @@ "metadata": { "id": "QFywJ_g56VW5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = tf.keras.applications.MobileNetV3Large()\n", "fb_model = tf.lite.TFLiteConverter.from_keras_model(model).convert()\n", @@ -180,9 +174,7 @@ "metadata": { "id": "9GEg5plIzD-3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "\n", @@ -222,9 +214,7 @@ "metadata": { "id": "85RgG6tQ3ABT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = tf.keras.models.Sequential([\n", " tf.keras.layers.Flatten(input_shape=(128, 128)),\n", @@ -241,9 +231,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "model_analyzer.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/guide/signatures.ipynb b/site/pt-br/lite/guide/signatures.ipynb index f2ec01f81e..c926f7f1bb 100644 --- a/site/pt-br/lite/guide/signatures.ipynb +++ b/site/pt-br/lite/guide/signatures.ipynb @@ -18,9 +18,7 @@ "cellView": "form", "id": "2pHVBk_seED1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -55,11 +53,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -102,9 +100,7 @@ "metadata": { "id": "9j4MGqyKQEo4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf" ] @@ -128,9 +124,7 @@ "metadata": { "id": "d8577c80" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class Model(tf.Module):\n", "\n", @@ -202,9 +196,7 @@ "metadata": { "id": "96c8fc79" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = Model()\n", "\n", @@ -249,9 +241,7 @@ "metadata": { "id": "71f29229" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Generate a Keras model.\n", "keras_model = tf.keras.Sequential(\n", @@ -290,9 +280,7 @@ "metadata": { "id": "c9e8a742" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = Model()\n", "\n", @@ -419,9 +407,7 @@ "metadata": { "id": "ab7b1963" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load the TFLite model in TFLite Interpreter\n", "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n", @@ -475,9 +461,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "signatures.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb b/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb index aeb1da8a5a..3630b1d68c 100644 --- a/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb +++ b/site/pt-br/lite/models/convert/metadata_writer_tutorial.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "LEvnopDoTC4M" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -111,9 +109,7 @@ "metadata": { "id": "m-8xSrSvUg-6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!pip install tflite-support-nightly" ] @@ -162,9 +158,7 @@ "metadata": { "id": "hhgNqEtWrwB3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import image_classifier\n", "from tflite_support.metadata_writers import writer_utils" @@ -185,9 +179,7 @@ "metadata": { "id": "6WgSBbNet-Tt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite -o mobilenet_v2_1.0_224.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt -o mobilenet_labels.txt" @@ -208,9 +200,7 @@ "metadata": { "id": "_SMEBBt2r-W6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ImageClassifierWriter = image_classifier.MetadataWriter\n", "_MODEL_PATH = \"mobilenet_v2_1.0_224.tflite\"\n", @@ -272,9 +262,7 @@ "metadata": { "id": "2_NIROeouf0o" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import object_detector\n", "from tflite_support.metadata_writers import writer_utils" @@ -295,9 +283,7 @@ "metadata": { "id": "4i_BBfGzuf0o" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/ssd_mobilenet_v1.tflite -o ssd_mobilenet_v1.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/object_detector/labelmap.txt -o ssd_mobilenet_labels.txt" @@ -318,9 +304,7 @@ "metadata": { "id": "vMGGeJfCuf0p" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ObjectDetectorWriter = object_detector.MetadataWriter\n", "_MODEL_PATH = \"ssd_mobilenet_v1.tflite\"\n", @@ -382,9 +366,7 @@ "metadata": { "id": "H6Lrw3op6uGX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import image_segmenter\n", "from tflite_support.metadata_writers import writer_utils" @@ -405,9 +387,7 @@ "metadata": { "id": "feQDH0bN6uGY" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/deeplabv3.tflite -o deeplabv3.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_segmenter/labelmap.txt -o deeplabv3_labels.txt" @@ -428,9 +408,7 @@ "metadata": { "id": "yot8xLI46uGY" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ImageSegmenterWriter = image_segmenter.MetadataWriter\n", "_MODEL_PATH = \"deeplabv3.tflite\"\n", @@ -490,9 +468,7 @@ "metadata": { "id": "_FGVyb2iAG-k" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import nl_classifier\n", "from tflite_support.metadata_writers import metadata_info\n", @@ -514,9 +490,7 @@ "metadata": { "id": "TzuQcti2AG-l" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/movie_review.tflite -o movie_review.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/nl_classifier/labels.txt -o movie_review_labels.txt\n", @@ -538,9 +512,7 @@ "metadata": { "id": "NGPWzRuHAG-m" }, - "outputs": [ - - ], + "outputs": [], "source": [ "NLClassifierWriter = nl_classifier.MetadataWriter\n", "_MODEL_PATH = \"movie_review.tflite\"\n", @@ -602,9 +574,7 @@ "metadata": { "id": "JjddvTXKw8pL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import audio_classifier\n", "from tflite_support.metadata_writers import metadata_info\n", @@ -626,9 +596,7 @@ "metadata": { "id": "5eQY6znmw8pM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_wavin_quantized_mel_relu6.tflite -o yamnet.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/audio_classifier/yamnet_521_labels.txt -o yamnet_labels.txt\n" @@ -649,9 +617,7 @@ "metadata": { "id": "MDlSczBQw8pM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "AudioClassifierWriter = audio_classifier.MetadataWriter\n", "_MODEL_PATH = \"yamnet.tflite\"\n", @@ -708,9 +674,7 @@ "metadata": { "id": "KsL_egYcRGw3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support.metadata_writers import image_classifier\n", "from tflite_support.metadata_writers import metadata_info\n", @@ -733,9 +697,7 @@ "metadata": { "id": "TqJ-jh-PRVdk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite -o mobilenet_v2_1.0_224.tflite\n", "!curl -L https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/labels.txt -o mobilenet_labels.txt" @@ -756,9 +718,7 @@ "metadata": { "id": "urd7HDuaR_HC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model_buffer = writer_utils.load_file(\"mobilenet_v2_1.0_224.tflite\")\n", "\n", @@ -809,9 +769,7 @@ "metadata": { "id": "_iWIwdqEf_mr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ImageClassifierWriter = image_classifier.MetadataWriter\n", "# Create the metadata writer.\n", @@ -849,9 +807,7 @@ "metadata": { "id": "5D13YPUsp5VT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support import metadata\n", "\n", diff --git a/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb index 38c470412d..0fd209c098 100644 --- a/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/audio_classification.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "sKrlWr6Kh-mF" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -44,11 +42,11 @@ "\n", " \n", - " \n", - " \n", - " \n", " \n", @@ -85,9 +83,7 @@ "metadata": { "id": "wbMc4vHjaYdQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install tflite-model-maker" @@ -110,9 +106,7 @@ "metadata": { "id": "rwUA9u4oWoCR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "import tflite_model_maker as mm\n", @@ -161,9 +155,7 @@ "metadata": { "id": "upNRfilkNSmr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "birds_dataset_folder = tf.keras.utils.get_file('birds_dataset.zip',\n", " 'https://storage.googleapis.com/laurencemoroney-blog.appspot.com/birds_dataset.zip',\n", @@ -194,9 +186,7 @@ "metadata": { "id": "ayd7UqCfQQFU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# @title [Run this] Util functions and data structures.\n", "\n", @@ -261,9 +251,7 @@ "metadata": { "id": "tEeMZh-VQy97" }, - "outputs": [ - - ], + "outputs": [], "source": [ "random_audio = get_random_audio_file()\n", "show_bird_data(random_audio)" @@ -300,9 +288,7 @@ "metadata": { "id": "tUcxtfHXY7XS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = audio_classifier.YamNetSpec(\n", " keep_yamnet_and_custom_heads=True,\n", @@ -331,9 +317,7 @@ "metadata": { "id": "cX0RqETqZgzo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data = audio_classifier.DataLoader.from_folder(\n", " spec, os.path.join(data_dir, 'train'), cache=True)\n", @@ -365,9 +349,7 @@ "metadata": { "id": "8r6Awvl4ZkIv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "batch_size = 128\n", "epochs = 100\n", @@ -396,9 +378,7 @@ "metadata": { "id": "GDoQACMrZnOx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print('Evaluating the model')\n", "model.evaluate(test_data)" @@ -423,9 +403,7 @@ "metadata": { "id": "zqB3c0368iH3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def show_confusion_matrix(confusion, test_labels):\n", " \"\"\"Compute confusion matrix and normalize.\"\"\"\n", @@ -461,9 +439,7 @@ "metadata": { "id": "PmlmTl42Bq_u" }, - "outputs": [ - - ], + "outputs": [], "source": [ "serving_model = model.create_serving_model()\n", "\n", @@ -486,9 +462,7 @@ "metadata": { "id": "8dv5ViK0reXc" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# if you want to try another file just uncoment the line below\n", "random_audio = get_random_audio_file()\n", @@ -512,9 +486,7 @@ "metadata": { "id": "YAvGKQL0lNty" }, - "outputs": [ - - ], + "outputs": [], "source": [ "sample_rate, audio_data = wavfile.read(random_audio, 'rb')\n", "\n", @@ -547,9 +519,7 @@ "metadata": { "id": "4-8fJLrxGwYT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(random_audio)\n", "\n", @@ -592,9 +562,7 @@ "metadata": { "id": "Xw_ehPxAdQlz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "models_path = './birds_models'\n", "print(f'Exporing the TFLite model to {models_path}')\n", @@ -617,9 +585,7 @@ "metadata": { "id": "veBwppOsA-kn" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(models_path, export_format=[mm.ExportFormat.SAVED_MODEL, mm.ExportFormat.LABEL])" ] @@ -645,9 +611,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "audio_classification.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb index 430e1b6355..bf86c7e38e 100644 --- a/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/image_classification.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "TUfAcER1oUS6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver modelo do TF Hub\n", "
\n", " \n", - " \n", - " \n", - " \n", " \n", @@ -90,9 +88,7 @@ "metadata": { "id": "6cv3K3oaksJv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install -q tflite-model-maker" @@ -113,9 +109,7 @@ "metadata": { "id": "XtxiUeZEiXpt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import os\n", "\n", @@ -160,9 +154,7 @@ "cellView": "form", "id": "3jz5x0JoskPv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "image_path = tf.keras.utils.get_file(\n", " 'flower_photos.tgz',\n", @@ -217,9 +209,7 @@ "metadata": { "id": "lANoNS_gtdH1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "data = DataLoader.from_folder(image_path)\n", "train_data, test_data = data.split(0.9)" @@ -240,9 +230,7 @@ "metadata": { "id": "yRXMZbrwtyRD" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = image_classifier.create(train_data)" ] @@ -262,9 +250,7 @@ "metadata": { "id": "wQr02VxJt6Cs" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] @@ -288,9 +274,7 @@ "metadata": { "id": "Zb-eIzfluCoa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.')" ] @@ -360,9 +344,7 @@ "metadata": { "id": "7tOfUr2KlgpU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "image_path = tf.keras.utils.get_file(\n", " 'flower_photos.tgz',\n", @@ -388,9 +370,7 @@ "metadata": { "id": "I_fOlZsklmlL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "data = DataLoader.from_folder(image_path)" ] @@ -410,9 +390,7 @@ "metadata": { "id": "cY4UU5SUobtJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data, rest_data = data.split(0.8)\n", "validation_data, test_data = rest_data.split(0.5)" @@ -433,9 +411,7 @@ "metadata": { "id": "Ih4Wx44I482b" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.figure(figsize=(10,10))\n", "for i, (image, label) in enumerate(data.gen_dataset().unbatch().take(25)):\n", @@ -465,9 +441,7 @@ "metadata": { "id": "TvYSUuJY3QxR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = image_classifier.create(train_data, validation_data=validation_data)" ] @@ -487,9 +461,7 @@ "metadata": { "id": "QNXAfjl192dC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.summary()" ] @@ -511,9 +483,7 @@ "metadata": { "id": "A8c2ZQ0J3Riy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] @@ -533,9 +503,7 @@ "metadata": { "id": "n9O9Kx7nDQWD" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# A helper function that returns 'red'/'black' depending on if its two input\n", "# parameter matches or not.\n", @@ -593,9 +561,7 @@ "metadata": { "id": "Im6wA9lK3TQB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.')" ] @@ -632,9 +598,7 @@ "metadata": { "id": "BvxWsOTmKG4P" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.', export_format=ExportFormat.LABEL)" ] @@ -654,9 +618,7 @@ "metadata": { "id": "S1YoPX5wOK-u" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate_tflite('model.tflite', test_data)" ] @@ -715,9 +677,7 @@ "metadata": { "id": "k8hL2mstCxQl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "config = QuantizationConfig.for_float16()" ] @@ -737,9 +697,7 @@ "metadata": { "id": "WTJzFQnJFMjr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)" ] @@ -781,9 +739,7 @@ "metadata": { "id": "7JKsJ6-P6ae1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = image_classifier.create(train_data, model_spec=model_spec.get('mobilenet_v2'), validation_data=validation_data)" ] @@ -803,9 +759,7 @@ "metadata": { "id": "lB2Go3HW8X7_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] @@ -831,9 +785,7 @@ "metadata": { "id": "xdiMF2WMfAR4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "inception_v3_spec = image_classifier.ModelSpec(\n", " uri='https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1')\n", @@ -905,9 +857,7 @@ "metadata": { "id": "A3k7mhH54QcK" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = image_classifier.create(train_data, validation_data=validation_data, epochs=10)" ] @@ -927,9 +877,7 @@ "metadata": { "id": "VafIYpKWD4Sw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] @@ -953,9 +901,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "image_classification.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb b/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb index 6c250110a2..c45166a6ad 100644 --- a/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/object_detection.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "TUfAcER1oUS6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver modelo do TF Hub\n", "
\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -115,9 +113,7 @@ "metadata": { "id": "qhl8lqVamEty" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install -q --use-deprecated=legacy-resolver tflite-model-maker\n", @@ -141,9 +137,7 @@ "metadata": { "id": "XtxiUeZEiXpt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import numpy as np\n", "import os\n", @@ -243,9 +237,7 @@ "metadata": { "id": "CtdZ-JDwMimd" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = model_spec.get('efficientdet_lite0')" ] @@ -273,9 +265,7 @@ "metadata": { "id": "HD5BvzWe6YKa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data, validation_data, test_data = object_detector.DataLoader.from_csv('gs://cloud-ml-data/img/openimage/csv/salads_ml_use.csv')" ] @@ -299,9 +289,7 @@ "metadata": { "id": "kwlYdTcg63xy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = object_detector.create(train_data, model_spec=spec, batch_size=8, train_whole_model=True, validation_data=validation_data)" ] @@ -327,9 +315,7 @@ "metadata": { "id": "8xmnl6Yy7ARn" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate(test_data)" ] @@ -351,9 +337,7 @@ "metadata": { "id": "Hm_UULdW7A9T" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.')" ] @@ -380,9 +364,7 @@ "metadata": { "id": "RS3Ell_lqH4e" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate_tflite('model.tflite', test_data)" ] @@ -425,9 +407,7 @@ "cellView": "form", "id": "XqS0rFCrqM1o" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Load the trained TFLite model and define some visualization functions\n", "\n", @@ -533,9 +513,7 @@ "cellView": "form", "id": "GkXtipXKqXp4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Run object detection and show the detection results\n", "\n", @@ -583,9 +561,7 @@ "metadata": { "id": "Oy3QIn_YqaRP" }, - "outputs": [ - - ], + "outputs": [], "source": [ "! curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -\n", "\n", @@ -624,9 +600,7 @@ "cellView": "form", "id": "LZdonJGCqieU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "NUMBER_OF_TPUS = 1#@param {type:\"number\"}\n", "\n", @@ -856,9 +830,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "object_detection.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb b/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb index bf5dbf2aaa..c4976c182a 100644 --- a/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/question_answer.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "TUfAcER1oUS6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -166,9 +164,7 @@ "metadata": { "id": "qhl8lqVamEty" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install -q tflite-model-maker-nightly" @@ -189,9 +185,7 @@ "metadata": { "id": "XtxiUeZEiXpt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import numpy as np\n", "import os\n", @@ -239,9 +233,7 @@ "metadata": { "id": "vEAWuZQ1PFiX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = model_spec.get('mobilebert_qa_squad')" ] @@ -270,9 +262,7 @@ "metadata": { "id": "7tOfUr2KlgpU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data_path = tf.keras.utils.get_file(\n", " fname='triviaqa-web-train-8000.json',\n", @@ -310,9 +300,7 @@ "metadata": { "id": "I_fOlZsklmlL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)\n", "validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)" @@ -338,9 +326,7 @@ "metadata": { "id": "TvYSUuJY3QxR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = question_answer.create(train_data, model_spec=spec)" ] @@ -360,9 +346,7 @@ "metadata": { "id": "gd7Hs8TF8n3H" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.summary()" ] @@ -384,9 +368,7 @@ "metadata": { "id": "A8c2ZQ0J3Riy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate(validation_data)" ] @@ -410,9 +392,7 @@ "metadata": { "id": "Im6wA9lK3TQB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.')" ] @@ -447,9 +427,7 @@ "metadata": { "id": "ro2hz4kXVImY" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='.', export_format=ExportFormat.VOCAB)" ] @@ -469,9 +447,7 @@ "metadata": { "id": "ochbq95ZrVFX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate_tflite('model.tflite', validation_data)" ] @@ -534,9 +510,7 @@ "metadata": { "id": "e9WBN0UTQoMN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "new_spec = model_spec.get('mobilebert_qa')\n", "new_spec.seq_len = 512" @@ -637,9 +611,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "question_answer.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb b/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb index 2084e0686b..f98b60fa49 100644 --- a/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/speech_recognition.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "sKrlWr6Kh-mF" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -101,9 +99,7 @@ "metadata": { "id": "wbMc4vHjaYdQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install tflite-model-maker" @@ -115,9 +111,7 @@ "metadata": { "id": "rwUA9u4oWoCR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import os\n", "import glob\n", @@ -174,9 +168,7 @@ "cellView": "form", "id": "AK9o98X7qyhU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "use_custom_dataset = False #@param [\"False\", \"True\"] {type:\"raw\"}" ] @@ -207,9 +199,7 @@ "metadata": { "id": "qvJd9VfmHu29" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tf.keras.utils.get_file('speech_commands_v0.01.tar.gz',\n", " 'http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz',\n", @@ -238,9 +228,7 @@ "metadata": { "id": "xgwWNifGL-3b" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Create a list of all the background wav files\n", "files = glob.glob(os.path.join('./dataset-speech/_background_noise_', '*.wav'))\n", @@ -293,9 +281,7 @@ "metadata": { "id": "zUSRpw2nOp8p" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if not use_custom_dataset:\n", " commands = [ \"up\", \"down\", \"left\", \"right\", \"go\", \"stop\", \"on\", \"off\", \"background\"]\n", @@ -357,9 +343,7 @@ "metadata": { "id": "77PsQAKA4Arx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if use_custom_dataset:\n", " # Specify the ZIP file you uploaded:\n", @@ -386,9 +370,7 @@ "metadata": { "id": "tMQ6cpw_B9e_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def move_background_dataset(dataset_dir):\n", " dest_dir = os.path.join(dataset_dir, 'background')\n", @@ -406,9 +388,7 @@ "metadata": { "id": "45iru8OdliG3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if use_custom_dataset:\n", " # Move background samples into custom dataset\n", @@ -455,9 +435,7 @@ "metadata": { "id": "gLC3ayJsoeNw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def get_random_audio_file(samples_dir):\n", " files = os.path.abspath(os.path.join(samples_dir, '*/*.wav'))\n", @@ -484,9 +462,7 @@ "metadata": { "id": "todbtEWFy0mj" }, - "outputs": [ - - ], + "outputs": [], "source": [ "random_audio = get_random_audio_file(test_dir)\n", "show_sample(random_audio)" @@ -522,9 +498,7 @@ "metadata": { "id": "tUcxtfHXY7XS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = audio_classifier.BrowserFftSpec()" ] @@ -564,9 +538,7 @@ "metadata": { "id": "cX0RqETqZgzo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if not use_custom_dataset:\n", " train_data_ratio = 0.8\n", @@ -602,9 +574,7 @@ "cellView": "code", "id": "e86Ej-ZmuCzy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if use_custom_dataset:\n", " train_data_ratio = 0.8\n", @@ -643,9 +613,7 @@ "metadata": { "id": "GYaZvaOPgLUC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# If your dataset has fewer than 100 samples per class,\n", "# you might want to try a smaller batch size\n", @@ -678,9 +646,7 @@ "metadata": { "id": "n_4MGpzhWVhr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate(test_data)" ] @@ -709,9 +675,7 @@ "metadata": { "id": "zqB3c0368iH3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def show_confusion_matrix(confusion, test_labels):\n", " \"\"\"Compute confusion matrix and normalize.\"\"\"\n", @@ -747,9 +711,7 @@ "metadata": { "id": "4gEf59NfGWjq" }, - "outputs": [ - - ], + "outputs": [], "source": [ "TFLITE_FILENAME = 'browserfft-speech.tflite'\n", "SAVE_PATH = './models'" @@ -761,9 +723,7 @@ "metadata": { "id": "Xw_ehPxAdQlz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(f'Exporing the model to {SAVE_PATH}')\n", "model.export(SAVE_PATH, tflite_filename=TFLITE_FILENAME)\n", @@ -794,9 +754,7 @@ "metadata": { "id": "nR5zV53YbCIQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# This library provides the TFLite metadata API\n", "! pip install -q tflite_support" @@ -808,9 +766,7 @@ "metadata": { "id": "1AC7PRyiayU5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tflite_support import metadata\n", "import json\n", @@ -847,9 +803,7 @@ "metadata": { "id": "loU6PleipSPf" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Get a WAV file for inference and list of labels from the model\n", "tflite_file = os.path.join(SAVE_PATH, TFLITE_FILENAME)\n", @@ -907,9 +861,7 @@ "metadata": { "id": "cNuQoqtjG4zu" }, - "outputs": [ - - ], + "outputs": [], "source": [ "try:\n", " from google.colab import files\n", @@ -932,9 +884,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "speech_recognition.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb b/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb index ea30b8aeda..0b6df2b42b 100644 --- a/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb +++ b/site/pt-br/lite/models/modify/model_maker/text_classification.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "TUfAcER1oUS6" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -97,9 +95,7 @@ "metadata": { "id": "qhl8lqVamEty" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!sudo apt -y install libportaudio2\n", "!pip install -q tflite-model-maker\n", @@ -122,9 +118,7 @@ "metadata": { "id": "XtxiUeZEiXpt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import numpy as np\n", "import os\n", @@ -161,9 +155,7 @@ "metadata": { "id": "R2BSkxWg6Rhx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "data_dir = tf.keras.utils.get_file(\n", " fname='SST-2.zip',\n", @@ -199,9 +191,7 @@ "metadata": { "id": "iLNaOXnl3JQB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import pandas as pd\n", "\n", @@ -246,9 +236,7 @@ "metadata": { "id": "CtdZ-JDwMimd" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = model_spec.get('average_word_vec')" ] @@ -281,9 +269,7 @@ "metadata": { "id": "HD5BvzWe6YKa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data = DataLoader.from_csv(\n", " filename='train.csv',\n", @@ -316,9 +302,7 @@ "metadata": { "id": "kwlYdTcg63xy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = text_classifier.create(train_data, model_spec=spec, epochs=10)" ] @@ -342,9 +326,7 @@ "metadata": { "id": "8xmnl6Yy7ARn" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, acc = model.evaluate(test_data)" ] @@ -366,9 +348,7 @@ "metadata": { "id": "Hm_UULdW7A9T" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='average_word_vec')" ] @@ -425,9 +405,7 @@ "metadata": { "id": "XWwvHmIltQC2" }, - "outputs": [ - - ], + "outputs": [], "source": [ "sentence_data = pd.read_csv('/content/dev.csv', index_col=0)\n", "sentence_data" @@ -448,9 +426,7 @@ "metadata": { "id": "IAEEs3_3vPz5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Name of the TFLite text classification model.\n", "_MODEL = '/content/average_word_vec/model.tflite'\n", @@ -481,9 +457,7 @@ "metadata": { "id": "Haham4qT8hmV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Initialize the text classification model.\n", "base_options = core.BaseOptions(file_name=_MODEL, use_coral=_ENABLE_EDGETPU, num_threads=_NUM_THREADS)\n", @@ -508,9 +482,7 @@ "metadata": { "id": "pAQDHFs5tTxZ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for idx in range(20):\n", " sentence = sentence_data['sentence'].iloc[idx]\n", @@ -550,9 +522,7 @@ "metadata": { "id": "vEAWuZQ1PFiX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "mb_spec = model_spec.get('mobilebert_classifier')" ] @@ -589,9 +559,7 @@ "metadata": { "id": "I_fOlZsklmlL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "train_data = DataLoader.from_csv(\n", " filename='train.csv',\n", @@ -635,9 +603,7 @@ "metadata": { "id": "TvYSUuJY3QxR" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = text_classifier.create(train_data, model_spec=mb_spec, epochs=3)" ] @@ -657,9 +623,7 @@ "metadata": { "id": "gd7Hs8TF8n3H" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.summary()" ] @@ -681,9 +645,7 @@ "metadata": { "id": "A8c2ZQ0J3Riy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, acc = model.evaluate(test_data)" ] @@ -707,9 +669,7 @@ "metadata": { "id": "Im6wA9lK3TQB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='mobilebert/')" ] @@ -745,9 +705,7 @@ "metadata": { "id": "nbK7nzK_Mfx4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.export(export_dir='mobilebert/', export_format=[ExportFormat.LABEL, ExportFormat.VOCAB])" ] @@ -767,9 +725,7 @@ "metadata": { "id": "ochbq95ZrVFX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "accuracy = model.evaluate_tflite('mobilebert/model.tflite', test_data)\n", "print('TFLite model accuracy: ', accuracy)" @@ -821,9 +777,7 @@ "metadata": { "id": "4tr9BLcjy4Sh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "new_model_spec = model_spec.get('mobilebert_classifier')\n", "new_model_spec.seq_len = 256" @@ -855,9 +809,7 @@ "metadata": { "id": "e9WBN0UTQoMN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "new_model_spec = AverageWordVecSpec(wordvec_dim=32)" ] @@ -877,9 +829,7 @@ "metadata": { "id": "DVZurFBORG3J" }, - "outputs": [ - - ], + "outputs": [], "source": [ "new_train_data = DataLoader.from_csv(\n", " filename='train.csv',\n", @@ -904,9 +854,7 @@ "metadata": { "id": "PzpV246_JGEu" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = text_classifier.create(new_train_data, model_spec=new_model_spec)" ] @@ -933,9 +881,7 @@ "metadata": { "id": "rnWFaYZBG6NW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = text_classifier.create(new_train_data, model_spec=new_model_spec, epochs=20)" ] @@ -955,9 +901,7 @@ "metadata": { "id": "BMPi1xflHDSY" }, - "outputs": [ - - ], + "outputs": [], "source": [ "new_test_data = DataLoader.from_csv(\n", " filename='dev.csv',\n", @@ -988,9 +932,7 @@ "metadata": { "id": "QfFCWrwyggrT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "spec = model_spec.get('bert_classifier')" ] @@ -1046,9 +988,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "text_classification.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/performance/post_training_float16_quant.ipynb b/site/pt-br/lite/performance/post_training_float16_quant.ipynb index 05903da3ef..7461894662 100644 --- a/site/pt-br/lite/performance/post_training_float16_quant.ipynb +++ b/site/pt-br/lite/performance/post_training_float16_quant.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "I9sUhVL_VZNO" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -97,9 +95,7 @@ "metadata": { "id": "gyqAw1M9lyab" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import logging\n", "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", @@ -125,9 +121,7 @@ "metadata": { "id": "hWSAjQWagIHl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load MNIST dataset\n", "mnist = keras.datasets.mnist\n", @@ -187,9 +181,7 @@ "metadata": { "id": "_i8B2nDZmAgQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "tflite_model = converter.convert()" @@ -210,9 +202,7 @@ "metadata": { "id": "vptWZq2xnclo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", "tflite_models_dir.mkdir(exist_ok=True, parents=True)" @@ -224,9 +214,7 @@ "metadata": { "id": "Ie9pQaQrn5ue" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", "tflite_model_file.write_bytes(tflite_model)" @@ -247,9 +235,7 @@ "metadata": { "id": "HEZ6ET1AHAS3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", "converter.target_spec.supported_types = [tf.float16]" @@ -270,9 +256,7 @@ "metadata": { "id": "yuNfl3CoHNK3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_fp16_model = converter.convert()\n", "tflite_model_fp16_file = tflite_models_dir/\"mnist_model_quant_f16.tflite\"\n", @@ -294,9 +278,7 @@ "metadata": { "id": "JExfcfLDscu4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls -lh {tflite_models_dir}" ] @@ -334,9 +316,7 @@ "metadata": { "id": "Jn16Rc23zTss" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", "interpreter.allocate_tensors()" @@ -348,9 +328,7 @@ "metadata": { "id": "J8Pztk1mvNVL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter_fp16 = tf.lite.Interpreter(model_path=str(tflite_model_fp16_file))\n", "interpreter_fp16.allocate_tensors()" @@ -371,9 +349,7 @@ "metadata": { "id": "AKslvo2kwWac" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", "\n", @@ -391,9 +367,7 @@ "metadata": { "id": "XZClM2vo3_bm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pylab as plt\n", "\n", @@ -410,9 +384,7 @@ "metadata": { "id": "3gwhv4lKbYZ4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", "\n", @@ -430,9 +402,7 @@ "metadata": { "id": "CIH7G_MwbY2x" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.imshow(test_images[0])\n", "template = \"True:{true}, predicted:{predict}\"\n", @@ -456,9 +426,7 @@ "metadata": { "id": "05aeAuWjvjPx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", "def evaluate_model(interpreter):\n", @@ -498,9 +466,7 @@ "metadata": { "id": "T5mWkSbMcU5z" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(evaluate_model(interpreter))" ] @@ -520,9 +486,7 @@ "metadata": { "id": "-9cnwiPp6EGm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# NOTE: Colab runs on server CPUs. At the time of writing this, TensorFlow Lite\n", "# doesn't have super optimized server CPU kernels. For this reason this may be\n", @@ -559,9 +523,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "post_training_float16_quant.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/performance/post_training_integer_quant.ipynb b/site/pt-br/lite/performance/post_training_integer_quant.ipynb index 80af883760..afc29b49de 100644 --- a/site/pt-br/lite/performance/post_training_integer_quant.ipynb +++ b/site/pt-br/lite/performance/post_training_integer_quant.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "W1dWWdNHQ9L0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -101,9 +99,7 @@ "metadata": { "id": "WsN6s5L1ieNl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import logging\n", "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", @@ -139,9 +135,7 @@ "metadata": { "id": "eMsw_6HujaqM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load MNIST dataset\n", "mnist = tf.keras.datasets.mnist\n", @@ -202,9 +196,7 @@ "metadata": { "id": "_i8B2nDZmAgQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "\n", @@ -244,9 +236,7 @@ "metadata": { "id": "HEZ6ET1AHAS3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", @@ -287,9 +277,7 @@ "metadata": { "id": "FiwiWU3gHdkW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def representative_data_gen():\n", " for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):\n", @@ -320,9 +308,7 @@ "metadata": { "id": "id1OEKFELQwp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)\n", "input_type = interpreter.get_input_details()[0]['dtype']\n", @@ -368,9 +354,7 @@ "metadata": { "id": "kzjEjcDs3BHa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def representative_data_gen():\n", " for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):\n", @@ -403,9 +387,7 @@ "metadata": { "id": "PaNkOS-twz4k" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)\n", "input_type = interpreter.get_input_details()[0]['dtype']\n", @@ -447,9 +429,7 @@ "metadata": { "id": "BEY59dC14uRv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import pathlib\n", "\n", @@ -490,9 +470,7 @@ "metadata": { "id": "X092SbeWfd1A" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Helper function to run inference on a TFLite model\n", "def run_tflite_model(tflite_file, test_image_indices):\n", @@ -554,9 +532,7 @@ "metadata": { "id": "zR2cHRUcUZ6e" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pylab as plt\n", "\n", @@ -590,9 +566,7 @@ "metadata": { "id": "iTK0x980coto" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_model(tflite_model_file, test_image_index, model_type=\"Float\")" ] @@ -612,9 +586,7 @@ "metadata": { "id": "rc1i9umMcp0t" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_model(tflite_model_quant_file, test_image_index, model_type=\"Quantized\")" ] @@ -643,9 +615,7 @@ "metadata": { "id": "05aeAuWjvjPx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Helper function to evaluate a TFLite model on all images\n", "def evaluate_model(tflite_file, model_type):\n", @@ -676,9 +646,7 @@ "metadata": { "id": "T5mWkSbMcU5z" }, - "outputs": [ - - ], + "outputs": [], "source": [ "evaluate_model(tflite_model_file, model_type=\"Float\")" ] @@ -698,9 +666,7 @@ "metadata": { "id": "-9cnwiPp6EGm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "evaluate_model(tflite_model_quant_file, model_type=\"Quantized\")" ] @@ -719,9 +685,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "post_training_integer_quant.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb b/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb index 1b8e900495..81eb4e4ee6 100644 --- a/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb +++ b/site/pt-br/lite/performance/post_training_integer_quant_16x8.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "I9sUhVL_VZNO" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -104,9 +102,7 @@ "metadata": { "id": "gyqAw1M9lyab" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import logging\n", "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", @@ -132,9 +128,7 @@ "metadata": { "id": "c6nb7OPlXs_3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8" ] @@ -154,9 +148,7 @@ "metadata": { "id": "hWSAjQWagIHl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load MNIST dataset\n", "mnist = keras.datasets.mnist\n", @@ -216,9 +208,7 @@ "metadata": { "id": "_i8B2nDZmAgQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "tflite_model = converter.convert()" @@ -239,9 +229,7 @@ "metadata": { "id": "vptWZq2xnclo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", "tflite_models_dir.mkdir(exist_ok=True, parents=True)" @@ -253,9 +241,7 @@ "metadata": { "id": "Ie9pQaQrn5ue" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", "tflite_model_file.write_bytes(tflite_model)" @@ -276,9 +262,7 @@ "metadata": { "id": "HEZ6ET1AHAS3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", "converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]" @@ -308,9 +292,7 @@ "metadata": { "id": "Y3a6XFqvHbYM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "mnist_train, _ = tf.keras.datasets.mnist.load_data()\n", "images = tf.cast(mnist_train[0], tf.float32) / 255.0\n", @@ -337,9 +319,7 @@ "metadata": { "id": "yuNfl3CoHNK3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_16x8_model = converter.convert()\n", "tflite_model_16x8_file = tflite_models_dir/\"mnist_model_quant_16x8.tflite\"\n", @@ -361,9 +341,7 @@ "metadata": { "id": "JExfcfLDscu4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls -lh {tflite_models_dir}" ] @@ -401,9 +379,7 @@ "metadata": { "id": "Jn16Rc23zTss" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", "interpreter.allocate_tensors()" @@ -415,9 +391,7 @@ "metadata": { "id": "J8Pztk1mvNVL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter_16x8 = tf.lite.Interpreter(model_path=str(tflite_model_16x8_file))\n", "interpreter_16x8.allocate_tensors()" @@ -438,9 +412,7 @@ "metadata": { "id": "AKslvo2kwWac" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", "\n", @@ -458,9 +430,7 @@ "metadata": { "id": "XZClM2vo3_bm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pylab as plt\n", "\n", @@ -477,9 +447,7 @@ "metadata": { "id": "3gwhv4lKbYZ4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", "\n", @@ -497,9 +465,7 @@ "metadata": { "id": "CIH7G_MwbY2x" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.imshow(test_images[0])\n", "template = \"True:{true}, predicted:{predict}\"\n", @@ -523,9 +489,7 @@ "metadata": { "id": "05aeAuWjvjPx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", "def evaluate_model(interpreter):\n", @@ -565,9 +529,7 @@ "metadata": { "id": "T5mWkSbMcU5z" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(evaluate_model(interpreter))" ] @@ -587,9 +549,7 @@ "metadata": { "id": "-9cnwiPp6EGm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# NOTE: This quantization mode is an experimental post-training mode,\n", "# it does not have any optimized kernels implementations or\n", @@ -610,9 +570,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "post_training_integer_quant_16x8.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/performance/post_training_quant.ipynb b/site/pt-br/lite/performance/post_training_quant.ipynb index 4422ed8921..a66eaed2fc 100644 --- a/site/pt-br/lite/performance/post_training_quant.ipynb +++ b/site/pt-br/lite/performance/post_training_quant.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "R3yYtBPkM2qZ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", " \n", @@ -106,9 +104,7 @@ "metadata": { "id": "gyqAw1M9lyab" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import logging\n", "logging.getLogger(\"tensorflow\").setLevel(logging.DEBUG)\n", @@ -134,9 +130,7 @@ "metadata": { "id": "hWSAjQWagIHl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load MNIST dataset\n", "mnist = keras.datasets.mnist\n", @@ -196,9 +190,7 @@ "metadata": { "id": "_i8B2nDZmAgQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "tflite_model = converter.convert()" @@ -219,9 +211,7 @@ "metadata": { "id": "vptWZq2xnclo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_models_dir = pathlib.Path(\"/tmp/mnist_tflite_models/\")\n", "tflite_models_dir.mkdir(exist_ok=True, parents=True)" @@ -233,9 +223,7 @@ "metadata": { "id": "Ie9pQaQrn5ue" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tflite_model_file = tflite_models_dir/\"mnist_model.tflite\"\n", "tflite_model_file.write_bytes(tflite_model)" @@ -256,9 +244,7 @@ "metadata": { "id": "g8PUvLWDlmmz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", "tflite_quant_model = converter.convert()\n", @@ -281,9 +267,7 @@ "metadata": { "id": "JExfcfLDscu4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls -lh {tflite_models_dir}" ] @@ -314,9 +298,7 @@ "metadata": { "id": "Jn16Rc23zTss" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))\n", "interpreter.allocate_tensors()" @@ -328,9 +310,7 @@ "metadata": { "id": "J8Pztk1mvNVL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpreter_quant = tf.lite.Interpreter(model_path=str(tflite_model_quant_file))\n", "interpreter_quant.allocate_tensors()" @@ -351,9 +331,7 @@ "metadata": { "id": "AKslvo2kwWac" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)\n", "\n", @@ -371,9 +349,7 @@ "metadata": { "id": "XZClM2vo3_bm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pylab as plt\n", "\n", @@ -399,9 +375,7 @@ "metadata": { "id": "05aeAuWjvjPx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# A helper function to evaluate the TF Lite model using \"test\" dataset.\n", "def evaluate_model(interpreter):\n", @@ -441,9 +415,7 @@ "metadata": { "id": "DqXBnDfJ7qxL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(evaluate_model(interpreter))" ] @@ -463,9 +435,7 @@ "metadata": { "id": "-9cnwiPp6EGm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(evaluate_model(interpreter_quant))" ] @@ -498,9 +468,7 @@ "metadata": { "id": "jrXZxSJiJfYN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow_hub as hub\n", "\n", @@ -518,9 +486,7 @@ "metadata": { "id": "LwnV4KxwVEoG" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Convert to TF Lite without quantization\n", "resnet_tflite_file = tflite_models_dir/\"resnet_v2_101.tflite\"\n", @@ -533,9 +499,7 @@ "metadata": { "id": "2qkZD0VoVExe" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Convert to TF Lite with quantization\n", "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", @@ -549,9 +513,7 @@ "metadata": { "id": "vhOjeg1x9Knp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!ls -lh {tflite_models_dir}/*.tflite" ] @@ -570,9 +532,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "post_training_quant.ipynb", "toc_visible": true }, diff --git a/site/pt-br/lite/performance/quantization_debugger.ipynb b/site/pt-br/lite/performance/quantization_debugger.ipynb index a4344cf142..15f6e052fc 100644 --- a/site/pt-br/lite/performance/quantization_debugger.ipynb +++ b/site/pt-br/lite/performance/quantization_debugger.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "BRQ6HQ8zcV5v" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver modelo do TF Hub\n", "
\n", " \n", - " \n", - " \n", - " \n", " \n", @@ -121,9 +119,7 @@ "metadata": { "id": "l7epUDUP_6qo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Quantization debugger is available from TensorFlow 2.7.0\n", "!pip uninstall -y tensorflow\n", @@ -137,9 +133,7 @@ "metadata": { "id": "LLsgiUZe_hIa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", @@ -156,9 +150,7 @@ "cellView": "form", "id": "veWjO3u32vzz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Boilerplates and helpers\n", "MODEL_URI = 'https://tfhub.dev/google/imagenet/mobilenet_v3_small_100_224/classification/5'\n", @@ -227,9 +219,7 @@ "metadata": { "id": "7mX-R-xK4ADB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "test_ds = ds.map(lambda data: (data['image'], data['label'] + 1)).batch(16)\n", "loss, acc = model.evaluate(test_ds)\n", @@ -242,9 +232,7 @@ "metadata": { "id": "Mnp6yBnJSCoh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "eval_tflite(quantized_model, ds)" ] @@ -275,9 +263,7 @@ "metadata": { "id": "NOByihbD_NZZ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", @@ -305,9 +291,7 @@ "metadata": { "id": "HsUM54g-_E52" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debugger.run()" ] @@ -327,9 +311,7 @@ "metadata": { "id": "U-AGYUAbQUmx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "RESULTS_FILE = '/tmp/debugger_results.csv'\n", "with open(RESULTS_FILE, 'w') as f:\n", @@ -342,9 +324,7 @@ "metadata": { "id": "LQzEi6VnQaen" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!head /tmp/debugger_results.csv" ] @@ -366,9 +346,7 @@ "metadata": { "id": "XUcSqYFGQb-f" }, - "outputs": [ - - ], + "outputs": [], "source": [ "layer_stats = pd.read_csv(RESULTS_FILE)\n", "layer_stats.head()" @@ -396,9 +374,7 @@ "metadata": { "id": "mwviORyJN6e5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "layer_stats['range'] = 255.0 * layer_stats['scale']\n", "layer_stats['rmse/scale'] = layer_stats.apply(\n", @@ -412,9 +388,7 @@ "metadata": { "id": "oAAv35CdPvc4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.figure(figsize=(15, 5))\n", "ax1 = plt.subplot(121)\n", @@ -441,9 +415,7 @@ "metadata": { "id": "UqFsUX4_Q-cE" }, - "outputs": [ - - ], + "outputs": [], "source": [ "layer_stats[layer_stats['rmse/scale'] > 0.7][[\n", " 'op_name', 'range', 'rmse/scale', 'tensor_name'\n", @@ -465,9 +437,7 @@ "metadata": { "id": "cvdkjsbwYC6e" }, - "outputs": [ - - ], + "outputs": [], "source": [ "suspected_layers = list(\n", " layer_stats[layer_stats['rmse/scale'] > 0.7]['tensor_name'])" @@ -488,9 +458,7 @@ "metadata": { "id": "ikF2bp6NZcXN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "suspected_layers.extend(list(layer_stats[:5]['tensor_name']))" ] @@ -530,9 +498,7 @@ "metadata": { "id": "K5KD0JAEbpsv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", " denylisted_nodes=suspected_layers)\n", @@ -548,9 +514,7 @@ "metadata": { "id": "pfj9gzv4b7h4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "selective_quantized_model = debugger.get_nondebug_quantized_model()\n", "eval_tflite(selective_quantized_model, ds)" @@ -573,9 +537,7 @@ "metadata": { "id": "ruUoP7SgcLpO" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", " denylisted_ops=['MEAN'])\n", @@ -591,9 +553,7 @@ "metadata": { "id": "oY6kb5g_cO4H" }, - "outputs": [ - - ], + "outputs": [], "source": [ "selective_quantized_model = debugger.get_nondebug_quantized_model()\n", "eval_tflite(selective_quantized_model, ds)" @@ -640,9 +600,7 @@ "metadata": { "id": "WqmRQSxoVVwu" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debug_options = tf.lite.experimental.QuantizationDebugOptions(\n", " layer_debug_metrics={\n", @@ -669,9 +627,7 @@ "metadata": { "id": "PVQ4nEicXz2l" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debugger.run()" ] @@ -682,9 +638,7 @@ "metadata": { "id": "dfKA90csX9UL" }, - "outputs": [ - - ], + "outputs": [], "source": [ "CUSTOM_RESULTS_FILE = '/tmp/debugger_results.csv'\n", "with open(CUSTOM_RESULTS_FILE, 'w') as f:\n", @@ -709,9 +663,7 @@ "metadata": { "id": "wrXlmzEHYhQ5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "debugger.model_statistics" ] @@ -733,9 +685,7 @@ "metadata": { "id": "VJm66Cz-XpeF" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from tensorflow.lite.python import convert" ] @@ -757,9 +707,7 @@ "metadata": { "id": "5zykINDlVLSg" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "converter.representative_dataset = representative_dataset(ds)\n", @@ -774,9 +722,7 @@ "metadata": { "id": "eqvXlEiFXfSu" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Note that enable_numeric_verify and enable_whole_model_verify are set.\n", "quantized_model = convert.mlir_quantize(\n", @@ -805,9 +751,7 @@ "metadata": { "id": "ZCS-Fa9lbdc0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "selective_quantized_model = convert.mlir_quantize(\n", " calibrated_model, denylisted_nodes=suspected_layers)\n", diff --git a/site/pt-br/lite/tutorials/pose_classification.ipynb b/site/pt-br/lite/tutorials/pose_classification.ipynb index c8bd4f31b2..7b10b2d114 100644 --- a/site/pt-br/lite/tutorials/pose_classification.ipynb +++ b/site/pt-br/lite/tutorials/pose_classification.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "ZtimvKLdili0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -54,11 +52,11 @@ "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver modelo do TF Hub\n", "
\n", " \n", - " \n", - " \n", - " \n", " \n", @@ -93,9 +91,7 @@ "metadata": { "id": "PWlbrkMCx-W-" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!pip install -q opencv-python" ] @@ -106,9 +102,7 @@ "metadata": { "id": "KTkttSWnUi1Q" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import csv\n", "import cv2\n", @@ -147,9 +141,7 @@ "cellView": "form", "id": "48kW1c2F5l1R" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Functions to run pose estimation with MoveNet\n", "\n", @@ -207,9 +199,7 @@ "cellView": "form", "id": "fKo0NzwQJ5Rm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Functions to visualize the pose estimation results.\n", "\n", @@ -254,9 +244,7 @@ "cellView": "form", "id": "QUkOW_26S6K-" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Code to load the images, detect pose landmarks and save them into a CSV file\n", "\n", @@ -448,9 +436,7 @@ "cellView": "form", "id": "LB3QIVrdU108" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title (Optional) Code snippet to try out the Movenet pose estimation logic\n", "\n", @@ -493,9 +479,7 @@ "cellView": "form", "id": "Kw6jwOFD40Fr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "is_skip_step_1 = False #@param [\"False\", \"True\"] {type:\"raw\"}" ] @@ -516,9 +500,7 @@ "cellView": "form", "id": "iEnjgeKeS_VP" }, - "outputs": [ - - ], + "outputs": [], "source": [ "use_custom_dataset = False #@param [\"False\", \"True\"] {type:\"raw\"}\n", "\n", @@ -583,9 +565,7 @@ "cellView": "form", "id": "joAHy_r62dsI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@markdown Be sure you run this cell. It's hiding the `split_into_train_test()` function that's called in the next code block.\n", "\n", @@ -658,9 +638,7 @@ "metadata": { "id": "IfpNIjAmR0lp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if use_custom_dataset:\n", " # ATTENTION:\n", @@ -704,9 +682,7 @@ "metadata": { "id": "GVpOi5Hr4Xxt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if not is_skip_step_1 and not use_custom_dataset:\n", " !wget -O yoga_poses.zip http://download.tensorflow.org/data/pose_classification/yoga_poses.zip\n", @@ -729,9 +705,7 @@ "metadata": { "id": "OsdqxGfxTE2H" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if not is_skip_step_1:\n", " images_in_train_folder = os.path.join(IMAGES_ROOT, 'train')\n", @@ -762,9 +736,7 @@ "metadata": { "id": "hddKVPjrTNbt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if not is_skip_step_1:\n", " images_in_test_folder = os.path.join(IMAGES_ROOT, 'test')\n", @@ -811,9 +783,7 @@ "metadata": { "id": "ShpOD7yb4MRp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Download the preprocessed CSV files which are the same as the output of step 1\n", "if is_skip_step_1:\n", @@ -840,9 +810,7 @@ "metadata": { "id": "pOUcc8EL5rrj" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def load_pose_landmarks(csv_path):\n", " \"\"\"Loads a CSV created by MoveNetPreprocessor.\n", @@ -890,9 +858,7 @@ "metadata": { "id": "xawmSDGXUUzW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load the train data\n", "X, y, class_names, _ = load_pose_landmarks(csvs_out_train_path)\n", @@ -908,9 +874,7 @@ "metadata": { "id": "R42kicUMaTX0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Load the test data\n", "X_test, y_test, _, df_test = load_pose_landmarks(csvs_out_test_path)" @@ -939,9 +903,7 @@ "metadata": { "id": "HgQMdfeT65Z5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def get_center_point(landmarks, left_bodypart, right_bodypart):\n", " \"\"\"Calculates the center point of the two given landmarks.\"\"\"\n", @@ -1043,9 +1005,7 @@ "metadata": { "id": "1Pte6b1bgWKv" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Define the model\n", "inputs = tf.keras.Input(shape=(51))\n", @@ -1067,9 +1027,7 @@ "metadata": { "id": "5ZuMwd7Ugtsa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.compile(\n", " optimizer='adam',\n", @@ -1102,9 +1060,7 @@ "metadata": { "id": "pNVqmd2JO6Rp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Visualize the training history to see whether you're overfitting.\n", "plt.plot(history.history['accuracy'])\n", @@ -1122,9 +1078,7 @@ "metadata": { "id": "m_byMBVQgyQm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Evaluate the model using the TEST dataset\n", "loss, accuracy = model.evaluate(X_test, y_test)" @@ -1145,9 +1099,7 @@ "metadata": { "id": "CJuVw7gygyyd" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def plot_confusion_matrix(cm, classes,\n", " normalize=False,\n", @@ -1214,9 +1166,7 @@ "metadata": { "id": "bdJdwOkFGonK" }, - "outputs": [ - - ], + "outputs": [], "source": [ "if is_skip_step_1:\n", " raise RuntimeError('You must have run step 1 to run this cell.')\n", @@ -1265,9 +1215,7 @@ "metadata": { "id": "FmwEAgi2Flb3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n", @@ -1294,9 +1242,7 @@ "metadata": { "id": "ZVW9j5vF6hBM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "with open('pose_labels.txt', 'w') as f:\n", " f.write('\\n'.join(class_names))" @@ -1317,9 +1263,7 @@ "metadata": { "id": "rv4fZFNcsN-1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def evaluate_model(interpreter, X, y_true):\n", " \"\"\"Evaluates the given TFLite model and return its accuracy.\"\"\"\n", @@ -1369,9 +1313,7 @@ "metadata": { "id": "KvcM_LkApOT3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!zip pose_classifier.zip pose_labels.txt pose_classifier.tflite" ] @@ -1382,9 +1324,7 @@ "metadata": { "id": "VQ-i27VypI1u" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Download the zip archive if running on Colab.\n", "try:\n", @@ -1397,9 +1337,7 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "pose_classification.ipynb", "toc_visible": true }, diff --git a/site/pt-br/tutorials/images/transfer_learning.ipynb b/site/pt-br/tutorials/images/transfer_learning.ipynb index ab4c898dcd..f607534797 100644 --- a/site/pt-br/tutorials/images/transfer_learning.ipynb +++ b/site/pt-br/tutorials/images/transfer_learning.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "d8jyt37T42Vf" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -40,9 +38,7 @@ "cellView": "form", "id": "aPxHdjwW5P2j" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title MIT License\n", "#\n", @@ -84,7 +80,7 @@ "source": [ "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver modelo do TF Hub\n", "
\n", " \n", - " \n", " \n", " \n", @@ -128,9 +124,7 @@ "metadata": { "id": "TqOt6Sv7AsMi" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", @@ -171,9 +165,7 @@ "metadata": { "id": "ro4oYaEmxe4r" }, - "outputs": [ - - ], + "outputs": [], "source": [ "_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'\n", "path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)\n", @@ -197,9 +189,7 @@ "metadata": { "id": "cAvtLwi7_J__" }, - "outputs": [ - - ], + "outputs": [], "source": [ "validation_dataset = tf.keras.utils.image_dataset_from_directory(validation_dir,\n", " shuffle=True,\n", @@ -222,9 +212,7 @@ "metadata": { "id": "K5BeQyKThC_Y" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class_names = train_dataset.class_names\n", "\n", @@ -252,9 +240,7 @@ "metadata": { "id": "uFFIYrTFV9RO" }, - "outputs": [ - - ], + "outputs": [], "source": [ "val_batches = tf.data.experimental.cardinality(validation_dataset)\n", "test_dataset = validation_dataset.take(val_batches // 5)\n", @@ -267,9 +253,7 @@ "metadata": { "id": "Q9pFlFWgBKgH" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))\n", "print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))" @@ -299,9 +283,7 @@ "metadata": { "id": "p3UUPdm86LNC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "AUTOTUNE = tf.data.AUTOTUNE\n", "\n", @@ -334,9 +316,7 @@ "metadata": { "id": "3P99QiMGit1A" }, - "outputs": [ - - ], + "outputs": [], "source": [ "data_augmentation = tf.keras.Sequential([\n", " tf.keras.layers.RandomFlip('horizontal'),\n", @@ -368,9 +348,7 @@ "metadata": { "id": "aQullOUHkm67" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for image, _ in train_dataset.take(1):\n", " plt.figure(figsize=(10, 10))\n", @@ -399,9 +377,7 @@ "metadata": { "id": "cO0HM9JAQUFq" }, - "outputs": [ - - ], + "outputs": [], "source": [ "preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input" ] @@ -421,9 +397,7 @@ "metadata": { "id": "R2NyJn4KQMux" }, - "outputs": [ - - ], + "outputs": [], "source": [ "rescale = tf.keras.layers.Rescaling(1./127.5, offset=-1)" ] @@ -458,9 +432,7 @@ "metadata": { "id": "19IQ2gqneqmS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Create the base model from the pre-trained model MobileNet V2\n", "IMG_SHAPE = IMG_SIZE + (3,)\n", @@ -484,9 +456,7 @@ "metadata": { "id": "Y-2LJL0EEUcx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "image_batch, label_batch = next(iter(train_dataset))\n", "feature_batch = base_model(image_batch)\n", @@ -528,9 +498,7 @@ "metadata": { "id": "OTCJH4bphOeo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "base_model.trainable = False" ] @@ -558,9 +526,7 @@ "metadata": { "id": "KpbzSmPkDa-N" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Let's take a look at the base model architecture\n", "base_model.summary()" @@ -590,9 +556,7 @@ "metadata": { "id": "dLnpMF5KOALm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "global_average_layer = tf.keras.layers.GlobalAveragePooling2D()\n", "feature_batch_average = global_average_layer(feature_batch)\n", @@ -614,9 +578,7 @@ "metadata": { "id": "Wv4afXKj6cVa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "prediction_layer = tf.keras.layers.Dense(1)\n", "prediction_batch = prediction_layer(feature_batch_average)\n", @@ -638,9 +600,7 @@ "metadata": { "id": "DgzQX6Veb2WT" }, - "outputs": [ - - ], + "outputs": [], "source": [ "inputs = tf.keras.Input(shape=(160, 160, 3))\n", "x = data_augmentation(inputs)\n", @@ -658,9 +618,7 @@ "metadata": { "id": "I8ARiyMFsgbH" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.summary()" ] @@ -680,9 +638,7 @@ "metadata": { "id": "krvBumovycVA" }, - "outputs": [ - - ], + "outputs": [], "source": [ "len(model.trainable_variables)" ] @@ -693,9 +649,7 @@ "metadata": { "id": "jeGk93R2ahav" }, - "outputs": [ - - ], + "outputs": [], "source": [ "tf.keras.utils.plot_model(model, show_shapes=True)" ] @@ -717,9 +671,7 @@ "metadata": { "id": "RpR8HdyMhukJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "base_learning_rate = 0.0001\n", "model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=base_learning_rate),\n", @@ -744,9 +696,7 @@ "metadata": { "id": "Om4O3EESkab1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "initial_epochs = 10\n", "\n", @@ -759,9 +709,7 @@ "metadata": { "id": "8cYT1c48CuSd" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(\"initial loss: {:.2f}\".format(loss0))\n", "print(\"initial accuracy: {:.2f}\".format(accuracy0))" @@ -773,9 +721,7 @@ "metadata": { "id": "JsaRFlZ9B6WK" }, - "outputs": [ - - ], + "outputs": [], "source": [ "history = model.fit(train_dataset,\n", " epochs=initial_epochs,\n", @@ -799,9 +745,7 @@ "metadata": { "id": "53OTCh3jnbwV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "acc = history.history['accuracy']\n", "val_acc = history.history['val_accuracy']\n", @@ -881,9 +825,7 @@ "metadata": { "id": "4nzcagVitLQm" }, - "outputs": [ - - ], + "outputs": [], "source": [ "base_model.trainable = True" ] @@ -894,9 +836,7 @@ "metadata": { "id": "-4HgVAacRs5v" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Let's take a look to see how many layers are in the base model\n", "print(\"Number of layers in the base model: \", len(base_model.layers))\n", @@ -926,9 +866,7 @@ "metadata": { "id": "NtUnaz0WUDva" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", " optimizer = tf.keras.optimizers.RMSprop(learning_rate=base_learning_rate/10),\n", @@ -941,9 +879,7 @@ "metadata": { "id": "WwBWy7J2kZvA" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.summary()" ] @@ -954,9 +890,7 @@ "metadata": { "id": "bNXelbMQtonr" }, - "outputs": [ - - ], + "outputs": [], "source": [ "len(model.trainable_variables)" ] @@ -985,9 +919,7 @@ "metadata": { "id": "ECQLkAsFTlun" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fine_tune_epochs = 10\n", "total_epochs = initial_epochs + fine_tune_epochs\n", @@ -1024,9 +956,7 @@ "metadata": { "id": "PpA8PlpQKygw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "acc += history_fine.history['accuracy']\n", "val_acc += history_fine.history['val_accuracy']\n", @@ -1041,9 +971,7 @@ "metadata": { "id": "chW103JUItdk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.figure(figsize=(8, 8))\n", "plt.subplot(2, 1, 1)\n", @@ -1091,9 +1019,7 @@ "metadata": { "id": "2KyNhagHwfar" }, - "outputs": [ - - ], + "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_dataset)\n", "print('Test accuracy :', accuracy)" @@ -1114,9 +1040,7 @@ "metadata": { "id": "RUNoQNgtfNgt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Retrieve a batch of images from the test set\n", "image_batch, label_batch = test_dataset.as_numpy_iterator().next()\n", diff --git a/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb b/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb index b9567ce217..adf5963591 100644 --- a/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb +++ b/site/pt-br/tutorials/interpretability/integrated_gradients.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "ioaprt5q5US7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -90,9 +88,7 @@ "metadata": { "id": "cbUMIubipgg0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import matplotlib.pylab as plt\n", "import numpy as np\n", @@ -124,9 +120,7 @@ "metadata": { "id": "14APZcfHolKj" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model = tf.keras.Sequential([\n", " hub.KerasLayer(\n", @@ -157,9 +151,7 @@ "metadata": { "id": "huZnb_O0L9mw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def load_imagenet_labels(file_path):\n", " labels_file = tf.keras.utils.get_file('ImageNetLabels.txt', file_path)\n", @@ -175,9 +167,7 @@ "metadata": { "id": "Rtrl-u7T6NEk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "imagenet_labels = load_imagenet_labels('https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')" ] @@ -199,9 +189,7 @@ "metadata": { "id": "YOb0Adq-rU5J" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def read_image(file_name):\n", " image = tf.io.read_file(file_name)\n", @@ -217,9 +205,7 @@ "metadata": { "id": "_khLTN75CLMJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "img_url = {\n", " 'Fireboat': 'http://storage.googleapis.com/download.tensorflow.org/example_images/San_Francisco_fireboat_showing_off.jpg',\n", @@ -236,9 +222,7 @@ "metadata": { "id": "AYIeu8rMLN-8" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.figure(figsize=(8, 8))\n", "for n, (name, img_tensors) in enumerate(img_name_tensors.items()):\n", @@ -266,9 +250,7 @@ "metadata": { "id": "5gsO7ILHZ0By" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def top_k_predictions(img, k=3):\n", " image_batch = tf.expand_dims(img, 0)\n", @@ -285,9 +267,7 @@ "metadata": { "id": "l80a8N2vcIP-" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for (name, img_tensor) in img_name_tensors.items():\n", " plt.imshow(img_tensor)\n", @@ -324,9 +304,7 @@ "metadata": { "id": "0AUkIUvpkaO8" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def f(x):\n", " \"\"\"A simplified model function.\"\"\"\n", @@ -346,9 +324,7 @@ "metadata": { "id": "kMdAKooulVRE" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title\n", "fig = plt.figure(figsize=(12, 5))\n", @@ -421,9 +397,7 @@ "metadata": { "id": "wxvpwGkj4G4J" }, - "outputs": [ - - ], + "outputs": [], "source": [ "baseline = tf.zeros(shape=(224,224,3))" ] @@ -434,9 +408,7 @@ "metadata": { "id": "vXRYwBWQS19B" }, - "outputs": [ - - ], + "outputs": [], "source": [ "plt.imshow(baseline)\n", "plt.title(\"Baseline\")\n", @@ -516,9 +488,7 @@ "metadata": { "id": "I42mBKXyjcIc" }, - "outputs": [ - - ], + "outputs": [], "source": [ "m_steps=50\n", "alphas = tf.linspace(start=0.0, stop=1.0, num=m_steps+1) # Generate m_steps intervals for integral_approximation() below." @@ -530,9 +500,7 @@ "metadata": { "id": "7SWLSFOHsbgh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def interpolate_images(baseline,\n", " image,\n", @@ -560,9 +528,7 @@ "metadata": { "id": "NgVx8swDQtTl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "interpolated_images = interpolate_images(\n", " baseline=baseline,\n", @@ -585,9 +551,7 @@ "metadata": { "id": "9tmBGdnHAupk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fig = plt.figure(figsize=(20, 20))\n", "\n", @@ -646,9 +610,7 @@ "metadata": { "id": "JW1O9qEsxZOP" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def compute_gradients(images, target_class_idx):\n", " with tf.GradientTape() as tape:\n", @@ -673,9 +635,7 @@ "metadata": { "id": "kHIR58rNJ3q_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "path_gradients = compute_gradients(\n", " images=interpolated_images,\n", @@ -697,9 +657,7 @@ "metadata": { "id": "v2rpO2JTbQId" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(path_gradients.shape)" ] @@ -723,9 +681,7 @@ "metadata": { "id": "FQWwcI0Wr0AX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "pred = model(interpolated_images)\n", "pred_proba = tf.nn.softmax(pred, axis=-1)[:, 555]" @@ -737,9 +693,7 @@ "metadata": { "id": "mCH8sAf3TTJ2" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title\n", "plt.figure(figsize=(10, 4))\n", @@ -810,9 +764,7 @@ "metadata": { "id": "1cMVl-Grx3lp" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def integral_approximation(gradients):\n", " # riemann_trapezoidal\n", @@ -836,9 +788,7 @@ "metadata": { "id": "JeF01fydNq0I" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ig = integral_approximation(\n", " gradients=path_gradients)" @@ -859,9 +809,7 @@ "metadata": { "id": "z1bP6l3ahfyn" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(ig.shape)" ] @@ -916,9 +864,7 @@ "metadata": { "id": "O_H3k9Eu7Rl5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def integrated_gradients(baseline,\n", " image,\n", @@ -958,9 +904,7 @@ "metadata": { "id": "dszwB_Sp0CX0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "@tf.function\n", "def one_batch(baseline, image, alpha_batch, target_class_idx):\n", @@ -981,9 +925,7 @@ "metadata": { "id": "8G0ELl_wRrd0" }, - "outputs": [ - - ], + "outputs": [], "source": [ "ig_attributions = integrated_gradients(baseline=baseline,\n", " image=img_name_tensors['Fireboat'],\n", @@ -1006,9 +948,7 @@ "metadata": { "id": "beoEunC5aZOa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(ig_attributions.shape)" ] @@ -1046,9 +986,7 @@ "metadata": { "id": "4QN2cEA_WFym" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title\n", "def plot_img_attributions(baseline,\n", @@ -1106,9 +1044,7 @@ "metadata": { "id": "vxCQFx96iDVs" }, - "outputs": [ - - ], + "outputs": [], "source": [ "_ = plot_img_attributions(image=img_name_tensors['Fireboat'],\n", " baseline=baseline,\n", @@ -1133,9 +1069,7 @@ "metadata": { "id": "TcpGLJWuHnYl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "_ = plot_img_attributions(image=img_name_tensors['Giant Panda'],\n", " baseline=baseline,\n", @@ -1199,9 +1133,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "integrated_gradients.ipynb", "toc_visible": true }, diff --git a/site/pt-br/tutorials/load_data/csv.ipynb b/site/pt-br/tutorials/load_data/csv.ipynb index 5745ff10b2..9b3ccc1240 100644 --- a/site/pt-br/tutorials/load_data/csv.ipynb +++ b/site/pt-br/tutorials/load_data/csv.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "AVV2e0XKbJeX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -89,9 +87,7 @@ "metadata": { "id": "baYFZMW_bJHh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", @@ -141,9 +137,7 @@ "metadata": { "id": "IZVExo9DKoNz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "abalone_train = pd.read_csv(\n", " \"https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv\",\n", @@ -181,9 +175,7 @@ "metadata": { "id": "udOnDJOxNi7p" }, - "outputs": [ - - ], + "outputs": [], "source": [ "abalone_features = abalone_train.copy()\n", "abalone_labels = abalone_features.pop('Age')" @@ -204,9 +196,7 @@ "metadata": { "id": "Dp3N5McbUMwb" }, - "outputs": [ - - ], + "outputs": [], "source": [ "abalone_features = np.array(abalone_features)\n", "abalone_features" @@ -227,9 +217,7 @@ "metadata": { "id": "d8zzNrZqOmfB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "abalone_model = tf.keras.Sequential([\n", " layers.Dense(64, activation='relu'),\n", @@ -255,9 +243,7 @@ "metadata": { "id": "uZdpCD92SN3Z" }, - "outputs": [ - - ], + "outputs": [], "source": [ "abalone_model.fit(abalone_features, abalone_labels, epochs=10)" ] @@ -299,9 +285,7 @@ "metadata": { "id": "H2WQpDU5VRk7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "normalize = layers.Normalization()" ] @@ -323,9 +307,7 @@ "metadata": { "id": "2WgOPIiOVpLg" }, - "outputs": [ - - ], + "outputs": [], "source": [ "normalize.adapt(abalone_features)" ] @@ -345,9 +327,7 @@ "metadata": { "id": "quPcZ9dTWA9A" }, - "outputs": [ - - ], + "outputs": [], "source": [ "norm_abalone_model = tf.keras.Sequential([\n", " normalize,\n", @@ -384,9 +364,7 @@ "metadata": { "id": "GS-dBMpuYMnz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic = pd.read_csv(\"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")\n", "titanic.head()" @@ -398,9 +376,7 @@ "metadata": { "id": "D8rCGIK1ZzKx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_features = titanic.copy()\n", "titanic_labels = titanic_features.pop('survived')" @@ -434,9 +410,7 @@ "metadata": { "id": "730F16_97D-3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Create a symbolic input\n", "input = tf.keras.Input(shape=(), dtype=tf.float32)\n", @@ -454,9 +428,7 @@ "metadata": { "id": "RtcNXWB18kMJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "calc = tf.keras.Model(inputs=input, outputs=result)" ] @@ -467,9 +439,7 @@ "metadata": { "id": "fUGQOUqZ8sa-" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(calc(1).numpy())\n", "print(calc(2).numpy())" @@ -490,9 +460,7 @@ "metadata": { "id": "5WODe_1da3yw" }, - "outputs": [ - - ], + "outputs": [], "source": [ "inputs = {}\n", "\n", @@ -523,9 +491,7 @@ "metadata": { "id": "wPRC_E6rkp8D" }, - "outputs": [ - - ], + "outputs": [], "source": [ "numeric_inputs = {name:input for name,input in inputs.items()\n", " if input.dtype==tf.float32}\n", @@ -553,9 +519,7 @@ "metadata": { "id": "M7jIJw5XntdN" }, - "outputs": [ - - ], + "outputs": [], "source": [ "preprocessed_inputs = [all_numeric_inputs]" ] @@ -577,9 +541,7 @@ "metadata": { "id": "79fi1Cgan2YV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for name, input in inputs.items():\n", " if input.dtype == tf.float32:\n", @@ -608,9 +570,7 @@ "metadata": { "id": "XJRzUTe8ukXc" }, - "outputs": [ - - ], + "outputs": [], "source": [ "preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs)\n", "\n", @@ -634,9 +594,7 @@ "metadata": { "id": "5YjdYyMEacwQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_features_dict = {name: np.array(value) \n", " for name, value in titanic_features.items()}" @@ -657,9 +615,7 @@ "metadata": { "id": "SjnmU8PSv8T3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", "titanic_preprocessing(features_dict)" @@ -680,9 +636,7 @@ "metadata": { "id": "coIPtGaCzUV7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def titanic_model(preprocessing_head, inputs):\n", " body = tf.keras.Sequential([\n", @@ -716,9 +670,7 @@ "metadata": { "id": "D1gVfwJ61ejz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)" ] @@ -738,9 +690,7 @@ "metadata": { "id": "Ay-8ymNA2ZCh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_model.save('test.keras')\n", "reloaded = tf.keras.models.load_model('test.keras')" @@ -752,9 +702,7 @@ "metadata": { "id": "Qm6jMTpD20lK" }, - "outputs": [ - - ], + "outputs": [], "source": [ "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", "\n", @@ -804,9 +752,7 @@ "metadata": { "id": "i8wE-MVuVu7_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import itertools\n", "\n", @@ -832,9 +778,7 @@ "metadata": { "id": "Wwq8XK88WwFk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for example in slices(titanic_features_dict):\n", " for name, value in example.items():\n", @@ -857,9 +801,7 @@ "metadata": { "id": "2gEJthslYxeV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)" ] @@ -879,9 +821,7 @@ "metadata": { "id": "gOHbiefaY4ag" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for example in features_ds:\n", " for name, value in example.items():\n", @@ -904,9 +844,7 @@ "metadata": { "id": "xIHGBy76Zcrx" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))" ] @@ -926,9 +864,7 @@ "metadata": { "id": "SbJcbldhddeC" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)" ] @@ -948,9 +884,7 @@ "metadata": { "id": "8yXkNPumdBtB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_model.fit(titanic_batches, epochs=5)" ] @@ -972,9 +906,7 @@ "metadata": { "id": "Ncf5t6tgL5ZI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_file_path = tf.keras.utils.get_file(\"train.csv\", \"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")" ] @@ -996,9 +928,7 @@ "metadata": { "id": "yIbUscB9sqha" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_csv_ds = tf.data.experimental.make_csv_dataset(\n", " titanic_file_path,\n", @@ -1028,9 +958,7 @@ "metadata": { "id": "v4oMO9MIxgTG" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for batch, label in titanic_csv_ds.take(1):\n", " for key, value in batch.items():\n", @@ -1067,9 +995,7 @@ "metadata": { "id": "kT7oZI2E46Q8" }, - "outputs": [ - - ], + "outputs": [], "source": [ "traffic_volume_csv_gz = tf.keras.utils.get_file(\n", " 'Metro_Interstate_Traffic_Volume.csv.gz', \n", @@ -1092,9 +1018,7 @@ "metadata": { "id": "ar0MPEVJ5NeA" }, - "outputs": [ - - ], + "outputs": [], "source": [ "traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset(\n", " traffic_volume_csv_gz,\n", @@ -1149,9 +1073,7 @@ "metadata": { "id": "Qk38Sw4MO4eh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "%%time\n", "for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):\n", @@ -1175,9 +1097,7 @@ "metadata": { "id": "r5Jj72MrPbnh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "%%time\n", "caching = traffic_volume_csv_gz_ds.cache().shuffle(1000)\n", @@ -1203,9 +1123,7 @@ "metadata": { "id": "PHGD1E8ktUvW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "%%time\n", "snapshotting = traffic_volume_csv_gz_ds.snapshot('titanic.tfsnap').shuffle(1000)\n", @@ -1257,9 +1175,7 @@ "metadata": { "id": "RmVknMdJh5ks" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fonts_zip = tf.keras.utils.get_file(\n", " 'fonts.zip', \"https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\",\n", @@ -1273,9 +1189,7 @@ "metadata": { "id": "xsDlMCnyi55e" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import pathlib\n", "font_csvs = sorted(str(p) for p in pathlib.Path('fonts').glob(\"*.csv\"))\n", @@ -1289,9 +1203,7 @@ "metadata": { "id": "lRAEJx9ROAGl" }, - "outputs": [ - - ], + "outputs": [], "source": [ "len(font_csvs)" ] @@ -1313,9 +1225,7 @@ "metadata": { "id": "6TSUNdT6iG58" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fonts_ds = tf.data.experimental.make_csv_dataset(\n", " file_pattern = \"fonts/*.csv\",\n", @@ -1339,9 +1249,7 @@ "metadata": { "id": "RmFvBWxxi3pq" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for features in fonts_ds.take(1):\n", " for i, (name, value) in enumerate(features.items()):\n", @@ -1371,9 +1279,7 @@ "metadata": { "id": "hct5EMEWNyfH" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import re\n", "\n", @@ -1410,9 +1316,7 @@ "metadata": { "id": "DJnnfIW9baE4" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fonts_image_ds = fonts_ds.map(make_images)\n", "\n", @@ -1435,9 +1339,7 @@ "metadata": { "id": "I5dcey31T_tk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "from matplotlib import pyplot as plt\n", "\n", @@ -1494,9 +1396,7 @@ "metadata": { "id": "m1D2C-qdlqeW" }, - "outputs": [ - - ], + "outputs": [], "source": [ "text = pathlib.Path(titanic_file_path).read_text()\n", "lines = text.split('\\n')[1:-1]\n", @@ -1511,9 +1411,7 @@ "metadata": { "id": "9W4UeJYyHPx5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "features = tf.io.decode_csv(lines, record_defaults=all_strings) \n", "\n", @@ -1536,9 +1434,7 @@ "metadata": { "id": "rzUjR59yoUe1" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(lines[0])" ] @@ -1549,9 +1445,7 @@ "metadata": { "id": "7sPTunxwoeWU" }, - "outputs": [ - - ], + "outputs": [], "source": [ "titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()]\n", "titanic_types" @@ -1563,9 +1457,7 @@ "metadata": { "id": "n3NlViCzoB7F" }, - "outputs": [ - - ], + "outputs": [], "source": [ "features = tf.io.decode_csv(lines, record_defaults=titanic_types) \n", "\n", @@ -1601,9 +1493,7 @@ "metadata": { "id": "9OzZLp3krP-t" }, - "outputs": [ - - ], + "outputs": [], "source": [ "simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True)\n", "\n", @@ -1626,9 +1516,7 @@ "metadata": { "id": "E5O5d69Yq7gG" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def decode_titanic_line(line):\n", " return tf.io.decode_csv(line, titanic_types)\n", @@ -1663,9 +1551,7 @@ "metadata": { "id": "3tlFOTjCvAI5" }, - "outputs": [ - - ], + "outputs": [], "source": [ "font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1]\n", "print(font_line)" @@ -1686,9 +1572,7 @@ "metadata": { "id": "crgZZn0BzkSB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "num_font_features = font_line.count(',')+1\n", "font_column_types = [str(), str()] + [float()]*(num_font_features-2)" @@ -1709,9 +1593,7 @@ "metadata": { "id": "_SvL5Uvl0r0N" }, - "outputs": [ - - ], + "outputs": [], "source": [ "font_csvs[0]" ] @@ -1731,9 +1613,7 @@ "metadata": { "id": "Gtr1E66VmBqj" }, - "outputs": [ - - ], + "outputs": [], "source": [ "simple_font_ds = tf.data.experimental.CsvDataset(\n", " font_csvs, \n", @@ -1747,9 +1627,7 @@ "metadata": { "id": "k750Mgq4yt_o" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for row in simple_font_ds.take(10):\n", " print(row[0].numpy())" @@ -1772,9 +1650,7 @@ "metadata": { "id": "t9dS3SNb23W8" }, - "outputs": [ - - ], + "outputs": [], "source": [ "font_files = tf.data.Dataset.list_files(\"fonts/*.csv\")" ] @@ -1794,9 +1670,7 @@ "metadata": { "id": "zNd-TYyNzIgg" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print('Epoch 1:')\n", "for f in list(font_files)[:5]:\n", @@ -1827,9 +1701,7 @@ "metadata": { "id": "QWp4rH0Q4uPh" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def make_font_csv_ds(path):\n", " return tf.data.experimental.CsvDataset(\n", @@ -1853,9 +1725,7 @@ "metadata": { "id": "OePMNF_x1_Cc" }, - "outputs": [ - - ], + "outputs": [], "source": [ "font_rows = font_files.interleave(make_font_csv_ds,\n", " cycle_length=3)" @@ -1867,9 +1737,7 @@ "metadata": { "id": "UORIGWLy54-E" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fonts_dict = {'font_name':[], 'character':[]}\n", "\n", @@ -1915,9 +1783,7 @@ "metadata": { "id": "ieUVAPryjpJS" }, - "outputs": [ - - ], + "outputs": [], "source": [ "BATCH_SIZE=2048\n", "fonts_ds = tf.data.experimental.make_csv_dataset(\n", @@ -1932,9 +1798,7 @@ "metadata": { "id": "MUC2KW4LkQIz" }, - "outputs": [ - - ], + "outputs": [], "source": [ "%%time\n", "for i,batch in enumerate(fonts_ds.take(20)):\n", @@ -1958,9 +1822,7 @@ "metadata": { "id": "4XbPZV1okVF9" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fonts_files = tf.data.Dataset.list_files(\"fonts/*.csv\")\n", "fonts_lines = fonts_files.interleave(\n", @@ -1976,9 +1838,7 @@ "metadata": { "id": "te9C2km-qO8W" }, - "outputs": [ - - ], + "outputs": [], "source": [ "%%time\n", "for i,batch in enumerate(fonts_fast.take(20)):\n", diff --git a/site/pt-br/tutorials/video/video_classification.ipynb b/site/pt-br/tutorials/video/video_classification.ipynb index a394449aea..fa65a17355 100644 --- a/site/pt-br/tutorials/video/video_classification.ipynb +++ b/site/pt-br/tutorials/video/video_classification.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "1z4xy2gTUc4a" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -42,11 +40,11 @@ "
Ver em TensorFlow.org Executar no Google Colab\n", + " Executar no Google Colab\n", "Ver fonte no GitHub Baixar notebook
\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] @@ -92,9 +90,7 @@ "metadata": { "id": "KEbL4Mwi01PV" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!pip install remotezip tqdm opencv-python einops \n", "# Install TensorFlow 2.10\n", @@ -107,9 +103,7 @@ "metadata": { "id": "gg0otuqb0hIf" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tqdm\n", "import random\n", @@ -148,9 +142,7 @@ "metadata": { "id": "nB2aOTU35r9_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title\n", "\n", @@ -379,9 +371,7 @@ "metadata": { "id": "OYY7PkdJFM4Z" }, - "outputs": [ - - ], + "outputs": [], "source": [ "URL = 'https://storage.googleapis.com/thumos14_files/UCF101_videos.zip'\n", "download_dir = pathlib.Path('./UCF101_subset/')\n", @@ -407,9 +397,7 @@ "cellView": "form", "id": "lq86IyGDJjTX" }, - "outputs": [ - - ], + "outputs": [], "source": [ "n_frames = 10\n", "batch_size = 8\n", @@ -463,9 +451,7 @@ "metadata": { "id": "GZcB_7dg-EZJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Define the dimensions of one frame in the set of frames created\n", "HEIGHT = 224\n", @@ -478,9 +464,7 @@ "metadata": { "id": "yD_sDIBlNu7K" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class Conv2Plus1D(keras.layers.Layer):\n", " def __init__(self, filters, kernel_size, padding):\n", @@ -521,9 +505,7 @@ "metadata": { "id": "tjxAKHwn6mTJ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class ResidualMain(keras.layers.Layer):\n", " \"\"\"\n", @@ -563,9 +545,7 @@ "metadata": { "id": "znrk5BrL6kuq" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class Project(keras.layers.Layer):\n", " \"\"\"\n", @@ -598,9 +578,7 @@ "metadata": { "id": "urjVgqvw-TlB" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def add_residual_block(input, filters, kernel_size):\n", " \"\"\"\n", @@ -634,9 +612,7 @@ "metadata": { "id": "lQOWuc2I-QqK" }, - "outputs": [ - - ], + "outputs": [], "source": [ "class ResizeVideo(keras.layers.Layer):\n", " def __init__(self, height, width):\n", @@ -681,9 +657,7 @@ "metadata": { "id": "_bROfh_K-Wxs" }, - "outputs": [ - - ], + "outputs": [], "source": [ "input_shape = (None, 10, HEIGHT, WIDTH, 3)\n", "input = layers.Input(shape=(input_shape[1:]))\n", @@ -722,9 +696,7 @@ "metadata": { "id": "TiO0WylG-ZHM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "frames, label = next(iter(train_ds))\n", "model.build(frames)" @@ -736,9 +708,7 @@ "metadata": { "id": "GAsKrM8r-bKM" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Visualize the model\n", "keras.utils.plot_model(model, expand_nested=True, dpi=60, show_shapes=True)" @@ -761,9 +731,7 @@ "metadata": { "id": "ejrbyebDp2tA" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.compile(loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True), \n", " optimizer = keras.optimizers.Adam(learning_rate = 0.0001), \n", @@ -787,9 +755,7 @@ "metadata": { "id": "VMrMUl2hOqMs" }, - "outputs": [ - - ], + "outputs": [], "source": [ "history = model.fit(x = train_ds,\n", " epochs = 50, \n", @@ -813,9 +779,7 @@ "metadata": { "id": "Cd5tpNrtOrs7" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def plot_history(history):\n", " \"\"\"\n", @@ -874,9 +838,7 @@ "metadata": { "id": "Hev0hMCxOtfy" }, - "outputs": [ - - ], + "outputs": [], "source": [ "model.evaluate(test_ds, return_dict=True)" ] @@ -896,9 +858,7 @@ "metadata": { "id": "Yw-6rG5V-0L-" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def get_actual_predicted_labels(dataset): \n", " \"\"\"\n", @@ -926,9 +886,7 @@ "metadata": { "id": "aln6qWW_-2dk" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def plot_confusion_matrix(actual, predicted, labels, ds_type):\n", " cm = tf.math.confusion_matrix(actual, predicted)\n", @@ -950,9 +908,7 @@ "metadata": { "id": "tfQ3VAGd-4Az" }, - "outputs": [ - - ], + "outputs": [], "source": [ "fg = FrameGenerator(subset_paths['train'], n_frames, training=True)\n", "labels = list(fg.class_ids_for_name.keys())" @@ -964,9 +920,7 @@ "metadata": { "id": "1ucGpbiA-5qi" }, - "outputs": [ - - ], + "outputs": [], "source": [ "actual, predicted = get_actual_predicted_labels(train_ds)\n", "plot_confusion_matrix(actual, predicted, labels, 'training')" @@ -978,9 +932,7 @@ "metadata": { "id": "Mfr7AT5T-7ZD" }, - "outputs": [ - - ], + "outputs": [], "source": [ "actual, predicted = get_actual_predicted_labels(test_ds)\n", "plot_confusion_matrix(actual, predicted, labels, 'test')" @@ -1001,9 +953,7 @@ "metadata": { "id": "dq95-56Z-_E2" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def calculate_classification_metrics(y_actual, y_pred, labels):\n", " \"\"\"\n", @@ -1042,9 +992,7 @@ "metadata": { "id": "4jSEonYQ_BZt" }, - "outputs": [ - - ], + "outputs": [], "source": [ "precision, recall = calculate_classification_metrics(actual, predicted, labels) # Test dataset" ] @@ -1055,9 +1003,7 @@ "metadata": { "id": "hXvTW1Df_DV8" }, - "outputs": [ - - ], + "outputs": [], "source": [ "precision" ] @@ -1068,9 +1014,7 @@ "metadata": { "id": "be1yrQl5_EYF" }, - "outputs": [ - - ], + "outputs": [], "source": [ "recall" ] diff --git a/site/pt-br/xla/tutorials/autoclustering_xla.ipynb b/site/pt-br/xla/tutorials/autoclustering_xla.ipynb index 4af0efb026..f62ea78c02 100644 --- a/site/pt-br/xla/tutorials/autoclustering_xla.ipynb +++ b/site/pt-br/xla/tutorials/autoclustering_xla.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "vamNSA0vEP-m" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,9 +49,9 @@ "\n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", "
Ver em TensorFlow.org\n", "Executar no Google ColabVer fonte no GitHubBaixar notebookExecutar no Google ColabVer fonte no GitHubBaixar notebook
" ] }, @@ -74,9 +72,7 @@ "metadata": { "id": "R4xtYyOf78e3" }, - "outputs": [ - - ], + "outputs": [], "source": [ "!pip install -U -q tensorflow tensorflow_datasets" ] @@ -87,9 +83,7 @@ "metadata": { "id": "PH2HbLW65tmo" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n", "import tensorflow_datasets as tfds" @@ -101,9 +95,7 @@ "metadata": { "id": "7vm2QsMisCxI" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Check that GPU is available: cf. https://colab.research.google.com/notebooks/gpu.ipynb\n", "assert(tf.test.gpu_device_name())\n", @@ -142,9 +134,7 @@ "metadata": { "id": "3ZRQSwoRsKM_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def generate_model():\n", " return tf.keras.models.Sequential([\n", @@ -188,9 +178,7 @@ "metadata": { "id": "UKCmrhF0tiMa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "def compile_model(model):\n", " opt = tf.keras.optimizers.RMSprop(learning_rate=0.0001)\n", @@ -233,9 +221,7 @@ "metadata": { "id": "jxU-Tzy4SX7p" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# We need to clear the session to enable JIT in the middle of the program.\n", "tf.keras.backend.clear_session()\n", @@ -260,9 +246,7 @@ "metadata": { "accelerator": "GPU", "colab": { - "collapsed_sections": [ - - ], + "collapsed_sections": [], "name": "autoclustering_xla.ipynb", "toc_visible": true }, diff --git a/site/pt-br/xla/tutorials/compile.ipynb b/site/pt-br/xla/tutorials/compile.ipynb index b0ee5579d3..a0ce2ec0e4 100644 --- a/site/pt-br/xla/tutorials/compile.ipynb +++ b/site/pt-br/xla/tutorials/compile.ipynb @@ -16,9 +16,7 @@ "cellView": "form", "id": "vamNSA0vEP-m" }, - "outputs": [ - - ], + "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", @@ -51,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Baixar notebook\n", + " Baixar notebook\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", "
" ] @@ -77,9 +75,7 @@ "metadata": { "id": "45kUPj5ZFrRa" }, - "outputs": [ - - ], + "outputs": [], "source": [ "import tensorflow as tf\n" ] @@ -99,9 +95,7 @@ "metadata": { "id": "f37TSEGvGX4_" }, - "outputs": [ - - ], + "outputs": [], "source": [ "# Size of each input image, 28 x 28 pixels\n", "IMAGE_SIZE = 28 * 28\n", @@ -139,9 +133,7 @@ "metadata": { "id": "7O2NcEfG206Q" }, - "outputs": [ - - ], + "outputs": [], "source": [ "layer = tf.keras.layers.Dense(NUM_CLASSES)\n", "optimizer = tf.keras.optimizers.Adam()" @@ -164,9 +156,7 @@ "metadata": { "id": "ZbhJl_WvGa3g" }, - "outputs": [ - - ], + "outputs": [], "source": [ "@tf.function(experimental_compile=True)\n", "def train_mnist(images, labels):\n", @@ -206,9 +196,7 @@ "metadata": { "id": "qe28bAHNHUG2" }, - "outputs": [ - - ], + "outputs": [], "source": [ "for images, labels in train_ds:\n", " if optimizer.iterations > TRAIN_STEPS:\n", @@ -231,9 +219,7 @@ "metadata": { "id": "_GxF6jTRHVuA" }, - "outputs": [ - - ], + "outputs": [], "source": [ "images, labels = cast(test[0], test[1])\n", "predicted_labels = layer(images)\n", @@ -257,9 +243,7 @@ "metadata": { "id": "_a8GsNLVaLSQ" }, - "outputs": [ - - ], + "outputs": [], "source": [ "print(train_mnist.experimental_get_compiler_ir(images, labels)(stage='hlo'))" ] @@ -267,10 +251,8 @@ ], "metadata": { "colab": { - "collapsed_sections": [ - - ], - "name": "jit_compile.ipynb", + "collapsed_sections": [], + "name": "compile.ipynb", "toc_visible": true }, "kernelspec": { From d222315a4a12b63540510c8071aac23a8502b75f Mon Sep 17 00:00:00 2001 From: ilyaspiridonov Date: Sat, 4 Nov 2023 15:09:53 +0300 Subject: [PATCH 3/5] rm compile.ipynb as matching source got removed in process --- site/pt-br/xla/tutorials/compile.ipynb | 265 ------------------------- 1 file changed, 265 deletions(-) delete mode 100644 site/pt-br/xla/tutorials/compile.ipynb diff --git a/site/pt-br/xla/tutorials/compile.ipynb b/site/pt-br/xla/tutorials/compile.ipynb deleted file mode 100644 index a0ce2ec0e4..0000000000 --- a/site/pt-br/xla/tutorials/compile.ipynb +++ /dev/null @@ -1,265 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "f4TSNCvpENrW" - }, - "source": [ - "##### Copyright 2019 The TensorFlow Authors." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "cellView": "form", - "id": "vamNSA0vEP-m" - }, - "outputs": [], - "source": [ - "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", - "# you may not use this file except in compliance with the License.\n", - "# You may obtain a copy of the License at\n", - "#\n", - "# https://www.apache.org/licenses/LICENSE-2.0\n", - "#\n", - "# Unless required by applicable law or agreed to in writing, software\n", - "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", - "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", - "# See the License for the specific language governing permissions and\n", - "# limitations under the License." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "e1oSi4lHFt3z" - }, - "source": [ - "# Usando XLA com tf.function" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "b7noD9NjFRL-" - }, - "source": [ - "\n", - " \n", - " \n", - " \n", - " \n", - "
Ver em TensorFlow.org\n", - " Executar no Google Colab\n", - " Baixar notebook\n", - " Ver fonte no GitHub\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "sDy5lSBd4BDE" - }, - "source": [ - "Este tutorial treina um modelo TensorFlow para classificar o dataset MNIST, onde a função de treinamento é compilada usando XLA.\n", - "\n", - "Primeiro, carregue o TensorFlow e habilite a execução eager." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "45kUPj5ZFrRa" - }, - "outputs": [], - "source": [ - "import tensorflow as tf\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "GZVNiRmTDV-5" - }, - "source": [ - "Em seguida, defina algumas constantes necessárias e prepare o dataset MNIST." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "f37TSEGvGX4_" - }, - "outputs": [], - "source": [ - "# Size of each input image, 28 x 28 pixels\n", - "IMAGE_SIZE = 28 * 28\n", - "# Number of distinct number labels, [0..9]\n", - "NUM_CLASSES = 10\n", - "# Number of examples in each training batch (step)\n", - "TRAIN_BATCH_SIZE = 100\n", - "# Number of training steps to run\n", - "TRAIN_STEPS = 1000\n", - "\n", - "# Loads MNIST dataset.\n", - "train, test = tf.keras.datasets.mnist.load_data()\n", - "train_ds = tf.data.Dataset.from_tensor_slices(train).batch(TRAIN_BATCH_SIZE).repeat()\n", - "\n", - "# Casting from raw data to the required datatypes.\n", - "def cast(images, labels):\n", - " images = tf.cast(\n", - " tf.reshape(images, [-1, IMAGE_SIZE]), tf.float32)\n", - " labels = tf.cast(labels, tf.int64)\n", - " return (images, labels)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "lv7I-u_82v1S" - }, - "source": [ - "Por fim, defina o modelo e o otimizador. O modelo usa uma única camada densa." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "7O2NcEfG206Q" - }, - "outputs": [], - "source": [ - "layer = tf.keras.layers.Dense(NUM_CLASSES)\n", - "optimizer = tf.keras.optimizers.Adam()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "x_ZehpZP-SfS" - }, - "source": [ - "# Defina a função de treinamento\n", - "\n", - "Na função de treinamento, você obtém os rótulos previstos usando a camada definida acima e, em seguida, minimiza o gradiente de perda usando o otimizador. Para compilar a computação usando XLA, coloque-a dentro de `tf.function` com `jit_compile=True`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "ZbhJl_WvGa3g" - }, - "outputs": [], - "source": [ - "@tf.function(experimental_compile=True)\n", - "def train_mnist(images, labels):\n", - " images, labels = cast(images, labels)\n", - "\n", - " with tf.GradientTape() as tape:\n", - " predicted_labels = layer(images)\n", - " loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(\n", - " logits=predicted_labels, labels=labels\n", - " ))\n", - " layer_variables = layer.trainable_variables\n", - " grads = tape.gradient(loss, layer_variables)\n", - " optimizer.apply_gradients(zip(grads, layer_variables))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "EZD1m_n1DxAF" - }, - "source": [ - "# Treine e teste o modelo" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "gukC2Hol3sFZ" - }, - "source": [ - "Depois de definir a função de treinamento, defina o modelo." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qe28bAHNHUG2" - }, - "outputs": [], - "source": [ - "for images, labels in train_ds:\n", - " if optimizer.iterations > TRAIN_STEPS:\n", - " break\n", - " train_mnist(images, labels)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "qgsKmz3n2UiW" - }, - "source": [ - "E, finalmente, verifique a exatidão:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "_GxF6jTRHVuA" - }, - "outputs": [], - "source": [ - "images, labels = cast(test[0], test[1])\n", - "predicted_labels = layer(images)\n", - "correct_prediction = tf.equal(tf.argmax(predicted_labels, 1), labels)\n", - "accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", - "print(\"Prediction accuracy after training: %s\" % accuracy)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "PXoOjJnuZRaV" - }, - "source": [ - "Nos bastidores, o compilador XLA compilou toda a função TF para HLO, o que permitiu otimizações de fusão. Usando os recursos de introspecção, podemos ver o código HLO (outros valores possíveis interessantes para \"stage\" são `optimized_hlo` para HLO após otimizações e `optimized_hlo_dot` para um grafo Graphviz):" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "_a8GsNLVaLSQ" - }, - "outputs": [], - "source": [ - "print(train_mnist.experimental_get_compiler_ir(images, labels)(stage='hlo'))" - ] - } - ], - "metadata": { - "colab": { - "collapsed_sections": [], - "name": "compile.ipynb", - "toc_visible": true - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} From e08819d8760b1e5b6279385f3545c53c85951489 Mon Sep 17 00:00:00 2001 From: ilyaspiridonov Date: Sat, 4 Nov 2023 15:13:25 +0300 Subject: [PATCH 4/5] fix button links --- site/pt-br/guide/core/mlp_core.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/pt-br/guide/core/mlp_core.ipynb b/site/pt-br/guide/core/mlp_core.ipynb index cadca5012e..7d0467ddaf 100644 --- a/site/pt-br/guide/core/mlp_core.ipynb +++ b/site/pt-br/guide/core/mlp_core.ipynb @@ -49,11 +49,11 @@ "\n", " \n", - " \n", - " \n", - " \n", "
Ver em TensorFlow.org\n", " Executar no Google Colab\n", + " Executar no Google Colab\n", " Ver fonte no GitHub\n", + " Ver fonte no GitHub\n", " Baixar notebook\n", + " Baixar notebook\n", "
" ] From 611e3e4245b8d8978f1b6ca82a16029aea330674 Mon Sep 17 00:00:00 2001 From: ilyaspiridonov Date: Wed, 6 Dec 2023 23:58:03 +0300 Subject: [PATCH 5/5] Update build_ios.md remove English segment --- site/pt-br/lite/guide/build_ios.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/pt-br/lite/guide/build_ios.md b/site/pt-br/lite/guide/build_ios.md index 4a9d91c9ef..b5e3c54ec8 100644 --- a/site/pt-br/lite/guide/build_ios.md +++ b/site/pt-br/lite/guide/build_ios.md @@ -1,6 +1,6 @@ # Compile o TensorFlow Lite para iOS -This document describes how to build TensorFlow Lite iOS library on your own. Normally, you do not need to locally build TensorFlow Lite iOS library. If you just want to use it, the easiest way is using the prebuilt stable or nightly releases of the TensorFlow Lite CocoaPods. See [iOS quickstart](ios.md) for more details on how to use them in your iOS projects.

Este documento descreve como compilar a biblioteca iOS do TensorFlow Lite por conta própria. Normalmente, você não precisa compilar localmente a biblioteca iOS do TensorFlow Lite. Se você só quiser usá-la, a forma mais fácil é utilizar as versões estáveis ou noturnas pré-compiladas do CocoaPods do TensorFlow Lite. Confira mais detalhes de como usá-las nos seus projetos para iOS no [Guia de início rápido para iOS](ios.md). +Este documento descreve como compilar a biblioteca iOS do TensorFlow Lite por conta própria. Normalmente, você não precisa compilar localmente a biblioteca iOS do TensorFlow Lite. Se você só quiser usá-la, a forma mais fácil é utilizar as versões estáveis ou noturnas pré-compiladas do CocoaPods do TensorFlow Lite. Confira mais detalhes de como usá-las nos seus projetos para iOS no [Guia de início rápido para iOS](ios.md). ## Compilando localmente