chore(i18n): sync translations with latest source changes (chunk 5/8, 92 changes)

This commit is contained in:
localizeflow[bot] 2026-01-30 01:46:05 +00:00
parent 99e32a96fd
commit eb205aa297
92 changed files with 28985 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,179 @@
# Detecção de Objetos
Os modelos de classificação de imagens que abordamos até agora tomavam uma imagem e produziam um resultado categórico, como a classe 'número' em um problema MNIST. No entanto, em muitos casos, não queremos apenas saber que uma imagem retrata objetos - queremos determinar sua localização precisa. Este é exatamente o objetivo da **detecção de objetos**.
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/21)
![Detecção de Objetos](../../../../../translated_images/pt-BR/Screen_Shot_2016-11-17_at_11.14.54_AM.b4bb3769353287be.webp)
> Imagem do [site YOLO v2](https://pjreddie.com/darknet/yolov2/)
## Uma Abordagem Ingênua para Detecção de Objetos
Suponha que queremos encontrar um gato em uma imagem. Uma abordagem muito ingênua para detecção de objetos seria a seguinte:
1. Dividir a imagem em vários blocos.
2. Executar a classificação de imagem em cada bloco.
3. Os blocos que resultarem em uma ativação suficientemente alta podem ser considerados como contendo o objeto em questão.
![Detecção Ingênua de Objetos](../../../../../translated_images/pt-BR/naive-detection.e7f1ba220ccd08c6.webp)
> *Imagem do [Notebook de Exercícios](ObjectDetection-TF.ipynb)*
No entanto, essa abordagem está longe de ser ideal, pois só permite que o algoritmo localize a caixa delimitadora do objeto de forma muito imprecisa. Para uma localização mais precisa, precisamos executar algum tipo de **regressão** para prever as coordenadas das caixas delimitadoras - e, para isso, precisamos de conjuntos de dados específicos.
## Regressão para Detecção de Objetos
[Este post no blog](https://towardsdatascience.com/object-detection-with-neural-networks-a4e2c46b4491) oferece uma ótima introdução à detecção de formas.
## Conjuntos de Dados para Detecção de Objetos
Você pode encontrar os seguintes conjuntos de dados para essa tarefa:
* [PASCAL VOC](http://host.robots.ox.ac.uk/pascal/VOC/) - 20 classes
* [COCO](http://cocodataset.org/#home) - Objetos Comuns em Contexto. 80 classes, caixas delimitadoras e máscaras de segmentação
![COCO](../../../../../translated_images/pt-BR/coco-examples.71bc60380fa6cceb.webp)
## Métricas de Detecção de Objetos
### Interseção sobre União
Enquanto na classificação de imagens é fácil medir o desempenho do algoritmo, na detecção de objetos precisamos medir tanto a correção da classe quanto a precisão da localização inferida da caixa delimitadora. Para este último, usamos a chamada **Interseção sobre União** (IoU), que mede o quão bem duas caixas (ou duas áreas arbitrárias) se sobrepõem.
![IoU](../../../../../translated_images/pt-BR/iou_equation.9a4751d40fff4e11.webp)
> *Figura 2 de [este excelente post sobre IoU](https://pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/)*
A ideia é simples - dividimos a área de interseção entre duas figuras pela área de sua união. Para duas áreas idênticas, o IoU seria 1, enquanto para áreas completamente disjuntas será 0. Caso contrário, variará de 0 a 1. Normalmente, consideramos apenas aquelas caixas delimitadoras para as quais o IoU está acima de um determinado valor.
### Precisão Média
Suponha que queremos medir o quão bem uma determinada classe de objetos $C$ é reconhecida. Para medir isso, usamos a métrica de **Precisão Média**, que é calculada da seguinte forma:
1. Considere a curva de Precisão-Recall que mostra a precisão dependendo de um valor de limiar de detecção (de 0 a 1).
2. Dependendo do limiar, detectaremos mais ou menos objetos na imagem, e diferentes valores de precisão e recall.
3. A curva terá este formato:
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecall.png"/>
> *Imagem do [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)*
A Precisão Média para uma classe $C$ é a área sob essa curva. Mais precisamente, o eixo de Recall é normalmente dividido em 10 partes, e a Precisão é calculada como a média de todos esses pontos:
$$
AP = {1\over11}\sum_{i=0}^{10}\mbox{Precision}(\mbox{Recall}={i\over10})
$$
### AP e IoU
Consideramos apenas aquelas detecções para as quais o IoU está acima de um determinado valor. Por exemplo, no conjunto de dados PASCAL VOC, normalmente $\mbox{IoU Threshold} = 0.5$ é assumido, enquanto no COCO o AP é medido para diferentes valores de $\mbox{IoU Threshold}$.
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecallIoU.png"/>
> *Imagem do [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)*
### Precisão Média Global - mAP
A principal métrica para Detecção de Objetos é chamada de **Precisão Média Global**, ou **mAP**. É o valor da Precisão Média, calculado como a média entre todas as classes de objetos, e às vezes também sobre $\mbox{IoU Threshold}$. Em mais detalhes, o processo de cálculo do **mAP** é descrito
[neste post do blog](https://medium.com/@timothycarlen/understanding-the-map-evaluation-metric-for-object-detection-a07fe6962cf3)), e também [aqui com exemplos de código](https://gist.github.com/tarlen5/008809c3decf19313de216b9208f3734).
## Diferentes Abordagens para Detecção de Objetos
Existem duas grandes classes de algoritmos de detecção de objetos:
* **Redes de Proposta de Região** (R-CNN, Fast R-CNN, Faster R-CNN). A ideia principal é gerar **Regiões de Interesse** (ROI) e executar CNN sobre elas, procurando a ativação máxima. É um pouco semelhante à abordagem ingênua, com a exceção de que as ROIs são geradas de forma mais inteligente. Uma das principais desvantagens desses métodos é que eles são lentos, porque precisamos de muitas passagens do classificador CNN sobre a imagem.
* Métodos de **uma única passagem** (YOLO, SSD, RetinaNet). Nessas arquiteturas, projetamos a rede para prever classes e ROIs em uma única passagem.
### R-CNN: CNN Baseada em Região
[R-CNN](http://islab.ulsan.ac.kr/files/announcement/513/rcnn_pami.pdf) usa [Selective Search](http://www.huppelen.nl/publications/selectiveSearchDraft.pdf) para gerar uma estrutura hierárquica de regiões ROI, que são então passadas por extratores de características CNN e classificadores SVM para determinar a classe do objeto, e regressão linear para determinar as coordenadas da *caixa delimitadora*. [Artigo Oficial](https://arxiv.org/pdf/1506.01497v1.pdf)
![RCNN](../../../../../translated_images/pt-BR/rcnn1.cae407020dfb1d1f.webp)
> *Imagem de van de Sande et al. ICCV11*
![RCNN-1](../../../../../translated_images/pt-BR/rcnn2.2d9530bb83516484.webp)
> *Imagens de [este blog](https://towardsdatascience.com/r-cnn-fast-r-cnn-faster-r-cnn-yolo-object-detection-algorithms-36d53571365e)*
### F-RCNN - Fast R-CNN
Essa abordagem é semelhante à R-CNN, mas as regiões são definidas após as camadas de convolução terem sido aplicadas.
![FRCNN](../../../../../translated_images/pt-BR/f-rcnn.3cda6d9bb4188875.webp)
> Imagem do [Artigo Oficial](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Girshick_Fast_R-CNN_ICCV_2015_paper.pdf), [arXiv](https://arxiv.org/pdf/1504.08083.pdf), 2015
### Faster R-CNN
A ideia principal dessa abordagem é usar uma rede neural para prever ROIs - a chamada *Rede de Proposta de Região*. [Artigo](https://arxiv.org/pdf/1506.01497.pdf), 2016
![FasterRCNN](../../../../../translated_images/pt-BR/faster-rcnn.8d46c099b87ef30a.webp)
> Imagem do [Artigo Oficial](https://arxiv.org/pdf/1506.01497.pdf)
### R-FCN: Rede Totalmente Convolucional Baseada em Região
Este algoritmo é ainda mais rápido que o Faster R-CNN. A ideia principal é a seguinte:
1. Extraímos características usando ResNet-101.
1. As características são processadas por **Position-Sensitive Score Map**. Cada objeto de $C$ classes é dividido em regiões $k\times k$, e treinamos para prever partes dos objetos.
1. Para cada parte das regiões $k\times k$, todas as redes votam pelas classes de objetos, e a classe de objeto com o maior número de votos é selecionada.
![r-fcn image](../../../../../translated_images/pt-BR/r-fcn.13eb88158b99a3da.webp)
> Imagem do [Artigo Oficial](https://arxiv.org/abs/1605.06409)
### YOLO - You Only Look Once
YOLO é um algoritmo de uma única passagem em tempo real. A ideia principal é a seguinte:
* A imagem é dividida em regiões $S\times S$.
* Para cada região, **CNN** prevê $n$ objetos possíveis, coordenadas da *caixa delimitadora* e *confiança*=*probabilidade* * IoU.
![YOLO](../../../../../translated_images/pt-BR/yolo.a2648ec82ee8bb4e.webp)
> Imagem do [Artigo Oficial](https://arxiv.org/abs/1506.02640)
### Outros Algoritmos
* RetinaNet: [Artigo Oficial](https://arxiv.org/abs/1708.02002)
- [Implementação em PyTorch no Torchvision](https://pytorch.org/vision/stable/_modules/torchvision/models/detection/retinanet.html)
- [Implementação em Keras](https://github.com/fizyr/keras-retinanet)
- [Detecção de Objetos com RetinaNet](https://keras.io/examples/vision/retinanet/) em Exemplos do Keras
* SSD (Single Shot Detector): [Artigo Oficial](https://arxiv.org/abs/1512.02325)
## ✍️ Exercícios: Detecção de Objetos
Continue seu aprendizado no seguinte notebook:
[ObjectDetection.ipynb](ObjectDetection.ipynb)
## Conclusão
Nesta lição, você fez um tour rápido por todas as várias maneiras de realizar a detecção de objetos!
## 🚀 Desafio
Leia estes artigos e notebooks sobre YOLO e experimente por conta própria:
* [Bom post no blog](https://www.analyticsvidhya.com/blog/2018/12/practical-guide-object-detection-yolo-framewor-python/) descrevendo YOLO
* [Site Oficial](https://pjreddie.com/darknet/yolo/)
* YOLO: [Implementação em Keras](https://github.com/experiencor/keras-yolo2), [notebook passo a passo](https://github.com/experiencor/basic-yolo-keras/blob/master/Yolo%20Step-by-Step.ipynb)
* YOLO v2: [Implementação em Keras](https://github.com/experiencor/keras-yolo2), [notebook passo a passo](https://github.com/experiencor/keras-yolo2/blob/master/Yolo%20Step-by-Step.ipynb)
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/22)
## Revisão & Autoestudo
* [Detecção de Objetos](https://tjmachinelearning.com/lectures/1718/obj/) por Nikhil Sardana
* [Uma boa comparação de algoritmos de detecção de objetos](https://lilianweng.github.io/lil-log/2018/12/27/object-detection-part-4.html)
* [Revisão de Algoritmos de Aprendizado Profundo para Detecção de Objetos](https://medium.com/comet-app/review-of-deep-learning-algorithms-for-object-detection-c1f3d437b852)
* [Uma Introdução Passo a Passo aos Algoritmos Básicos de Detecção de Objetos](https://www.analyticsvidhya.com/blog/2018/10/a-step-by-step-introduction-to-the-basic-object-detection-algorithms-part-1/)
* [Implementação de Faster R-CNN em Python para Detecção de Objetos](https://www.analyticsvidhya.com/blog/2018/11/implementation-faster-r-cnn-python-object-detection/)
## [Tarefa: Detecção de Objetos](lab/README.md)
---

View File

@ -0,0 +1,66 @@
# Detecção de Cabeças usando o Hollywood Heads Dataset
Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Contar o número de pessoas em uma transmissão de câmera de vigilância é uma tarefa importante que nos permite estimar o número de visitantes em lojas, horários de pico em restaurantes, etc. Para resolver essa tarefa, precisamos ser capazes de detectar cabeças humanas de diferentes ângulos. Para treinar um modelo de detecção de objetos para identificar cabeças humanas, podemos usar o [Hollywood Heads Dataset](https://www.di.ens.fr/willow/research/headdetection/).
## O Conjunto de Dados
O [Hollywood Heads Dataset](https://www.di.ens.fr/willow/research/headdetection/release/HollywoodHeads.zip) contém 369.846 cabeças humanas anotadas em 224.740 quadros de filmes de Hollywood. Ele é fornecido no formato [https://host.robots.ox.ac.uk/pascal/VOC/](../../../../../../lessons/4-ComputerVision/11-ObjectDetection/lab/PASCAL VOC), onde para cada imagem há também um arquivo de descrição XML que se parece com isto:
```xml
<annotation>
<folder>HollywoodHeads</folder>
<filename>mov_021_149390.jpeg</filename>
<source>
<database>HollywoodHeads 2015 Database</database>
<annotation>HollywoodHeads 2015</annotation>
<image>WILLOW</image>
</source>
<size>
<width>608</width>
<height>320</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>head</name>
<bndbox>
<xmin>201</xmin>
<ymin>1</ymin>
<xmax>480</xmax>
<ymax>263</ymax>
</bndbox>
<difficult>0</difficult>
</object>
<object>
<name>head</name>
<bndbox>
<xmin>3</xmin>
<ymin>4</ymin>
<xmax>241</xmax>
<ymax>285</ymax>
</bndbox>
<difficult>0</difficult>
</object>
</annotation>
```
Neste conjunto de dados, há apenas uma classe de objetos, `head`, e para cada cabeça, você obtém as coordenadas da caixa delimitadora. Você pode analisar os arquivos XML usando bibliotecas Python ou usar [esta biblioteca](https://pypi.org/project/pascal-voc/) para lidar diretamente com o formato PASCAL VOC.
## Treinamento de Detecção de Objetos
Você pode treinar um modelo de detecção de objetos usando uma das seguintes abordagens:
* Usando o [Azure Custom Vision](https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/quickstarts/object-detection?tabs=visual-studio&WT.mc_id=academic-77998-cacaste) e sua API Python para treinar o modelo programaticamente na nuvem. O Custom Vision não será capaz de usar mais do que algumas centenas de imagens para treinar o modelo, então pode ser necessário limitar o conjunto de dados.
* Usando o exemplo do [tutorial do Keras](https://keras.io/examples/vision/retinanet/) para treinar o modelo RetunaNet.
* Usando o módulo integrado [torchvision.models.detection.RetinaNet](https://pytorch.org/vision/stable/_modules/torchvision/models/detection/retinanet.html) no torchvision.
## Conclusão
A detecção de objetos é uma tarefa frequentemente necessária na indústria. Embora existam alguns serviços que podem ser usados para realizar a detecção de objetos (como o [Azure Custom Vision](https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/quickstarts/object-detection?tabs=visual-studio&WT.mc_id=academic-77998-cacaste)), é importante entender como a detecção de objetos funciona e ser capaz de treinar seus próprios modelos.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,69 @@
# Segmentação
Anteriormente, aprendemos sobre Detecção de Objetos, que nos permite localizar objetos na imagem ao prever suas *caixas delimitadoras*. No entanto, para algumas tarefas, não precisamos apenas de caixas delimitadoras, mas também de uma localização mais precisa dos objetos. Essa tarefa é chamada de **segmentação**.
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/23)
A segmentação pode ser vista como **classificação de pixels**, onde para **cada** pixel da imagem devemos prever sua classe (*fundo* sendo uma das classes). Existem dois principais algoritmos de segmentação:
* **Segmentação semântica** apenas informa a classe do pixel, sem distinguir entre diferentes objetos da mesma classe.
* **Segmentação por instância** divide as classes em diferentes instâncias.
Na segmentação por instância, essas ovelhas são objetos diferentes, mas na segmentação semântica todas as ovelhas são representadas por uma única classe.
<img src="../../../../../translated_images/pt-BR/instance_vs_semantic.eee9812bebf8cd45.webp" width="50%">
> Imagem retirada [deste post de blog](https://nirmalamurali.medium.com/image-classification-vs-semantic-segmentation-vs-instance-segmentation-625c33a08d50)
Existem diferentes arquiteturas neurais para segmentação, mas todas têm a mesma estrutura. De certa forma, é semelhante ao autoencoder que você aprendeu anteriormente, mas em vez de deconstruir a imagem original, nosso objetivo é deconstruir uma **máscara**. Assim, uma rede de segmentação possui as seguintes partes:
* **Codificador (Encoder)** extrai características da imagem de entrada.
* **Decodificador (Decoder)** transforma essas características na **imagem de máscara**, com o mesmo tamanho e número de canais correspondentes ao número de classes.
<img src="../../../../../translated_images/pt-BR/segm.92442f2cb42ff4fa.webp" width="80%">
> Imagem retirada [desta publicação](https://arxiv.org/pdf/2001.05566.pdf)
Devemos destacar especialmente a função de perda usada para segmentação. Ao usar autoencoders clássicos, precisamos medir a similaridade entre duas imagens, e podemos usar o erro quadrático médio (MSE) para isso. Na segmentação, cada pixel na imagem de máscara alvo representa o número da classe (codificado em one-hot ao longo da terceira dimensão), então precisamos usar funções de perda específicas para classificação - perda de entropia cruzada, média sobre todos os pixels. Se a máscara for binária, usa-se a **perda de entropia cruzada binária** (BCE).
> ✅ One-hot encoding é uma técnica para codificar um rótulo de classe em um vetor de comprimento igual ao número de classes. Confira [este artigo](https://datagy.io/sklearn-one-hot-encode/) sobre essa técnica.
## Segmentação para Imagens Médicas
Nesta lição, veremos a segmentação em ação treinando a rede para reconhecer nevos humanos (também conhecidos como pintas) em imagens médicas. Usaremos o <a href="https://www.fc.up.pt/addi/ph2%20database.html">Banco de Dados PH<sup>2</sup></a> de imagens dermatoscópicas como fonte de imagens. Este conjunto de dados contém 200 imagens de três classes: nevo típico, nevo atípico e melanoma. Todas as imagens também possuem uma **máscara** correspondente que delimita o nevo.
> ✅ Esta técnica é particularmente apropriada para este tipo de imagem médica, mas quais outras aplicações do mundo real você consegue imaginar?
<img alt="navi" src="../../../../../translated_images/pt-BR/navi.2f20b727910110ea.webp"/>
> Imagem retirada do Banco de Dados PH<sup>2</sup>
Treinaremos um modelo para segmentar qualquer nevo do fundo da imagem.
## ✍️ Exercícios: Segmentação Semântica
Abra os notebooks abaixo para aprender mais sobre diferentes arquiteturas de segmentação semântica, praticar com elas e vê-las em ação.
* [Segmentação Semântica Pytorch](SemanticSegmentationPytorch.ipynb)
* [Segmentação Semântica TensorFlow](SemanticSegmentationTF.ipynb)
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/24)
## Conclusão
A segmentação é uma técnica muito poderosa para classificação de imagens, indo além das caixas delimitadoras para a classificação em nível de pixel. É uma técnica usada em imagens médicas, entre outras aplicações.
## 🚀 Desafio
A segmentação corporal é apenas uma das tarefas comuns que podemos realizar com imagens de pessoas. Outras tarefas importantes incluem **detecção de esqueleto** e **detecção de pose**. Experimente a biblioteca [OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose) para ver como a detecção de pose pode ser usada.
## Revisão e Autoestudo
Este [artigo da Wikipedia](https://wikipedia.org/wiki/Image_segmentation) oferece uma boa visão geral das várias aplicações dessa técnica. Aprenda mais por conta própria sobre os subdomínios de Segmentação por Instância e Segmentação Panóptica neste campo de estudo.
## [Tarefa](lab/README.md)
Neste laboratório, experimente **segmentação do corpo humano** usando o [Segmentation Full Body MADS Dataset](https://www.kaggle.com/datasets/tapakah68/segmentation-full-body-mads-dataset) do Kaggle.
---

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
# Segmentação do Corpo Humano
Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Na produção de vídeos, como em previsões do tempo, frequentemente precisamos recortar a imagem de uma pessoa capturada pela câmera e colocá-la sobre outro vídeo. Isso geralmente é feito utilizando técnicas de **chroma key**, onde uma pessoa é filmada em frente a um fundo de cor uniforme, que é então removido. Neste trabalho prático, vamos treinar um modelo de rede neural para recortar a silhueta humana.
## O Conjunto de Dados
Usaremos o [Segmentation Full Body MADS Dataset](https://www.kaggle.com/datasets/tapakah68/segmentation-full-body-mads-dataset) do Kaggle. Baixe o conjunto de dados manualmente no Kaggle.
## Notebook Inicial
Comece o trabalho prático abrindo [BodySegmentation.ipynb](../../../../../../lessons/4-ComputerVision/12-Segmentation/lab/BodySegmentation.ipynb)
## Conclusão
A segmentação do corpo é apenas uma das tarefas comuns que podemos realizar com imagens de pessoas. Outras tarefas importantes incluem **detecção de esqueleto** e **detecção de pose**. Confira a biblioteca [OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose) para ver como essas tarefas podem ser implementadas.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,16 @@
# Visão Computacional
![Resumo do conteúdo de Visão Computacional em um desenho](../../../../translated_images/pt-BR/ai-computervision.6506ebebac3fbf76.webp)
Nesta seção, vamos aprender sobre:
* [Introdução à Visão Computacional e OpenCV](06-IntroCV/README.md)
* [Redes Neurais Convolucionais](07-ConvNets/README.md)
* [Redes Pré-treinadas e Aprendizado por Transferência](08-TransferLearning/README.md)
* [Autoencoders](09-Autoencoders/README.md)
* [Redes Adversárias Generativas](10-GANs/README.md)
* [Detecção de Objetos](11-ObjectDetection/README.md)
* [Segmentação Semântica](12-Segmentation/README.md)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,76 @@
# Representando Texto como Tensores
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/25)
## Classificação de Texto
Na primeira parte desta seção, vamos focar na tarefa de **classificação de texto**. Utilizaremos o [AG News](https://www.kaggle.com/amananandrai/ag-news-classification-dataset), um conjunto de dados que contém artigos de notícias como o seguinte:
* Categoria: Ciência/Tecnologia
* Título: Empresa de Ky. Ganha Subsídio para Estudar Peptídeos (AP)
* Corpo: AP - Uma empresa fundada por um pesquisador de química da Universidade de Louisville ganhou um subsídio para desenvolver...
Nosso objetivo será classificar o item de notícia em uma das categorias com base no texto.
## Representando texto
Se quisermos resolver tarefas de Processamento de Linguagem Natural (PLN) com redes neurais, precisamos de uma maneira de representar texto como tensores. Os computadores já representam caracteres textuais como números que mapeiam para fontes na sua tela usando codificações como ASCII ou UTF-8.
<img alt="Imagem mostrando um diagrama que mapeia um caractere para uma representação ASCII e binária" src="../../../../../translated_images/pt-BR/ascii-character-map.18ed6aa7f3b0a7ff.webp" width="50%"/>
> [Fonte da imagem](https://www.seobility.net/en/wiki/ASCII)
Como humanos, entendemos o que cada letra **representa** e como todos os caracteres se juntam para formar as palavras de uma frase. No entanto, os computadores, por si só, não têm esse entendimento, e a rede neural precisa aprender o significado durante o treinamento.
Portanto, podemos usar diferentes abordagens ao representar texto:
* **Representação a nível de caractere**, onde representamos o texto tratando cada caractere como um número. Dado que temos *C* caracteres diferentes em nosso corpus de texto, a palavra *Hello* seria representada por um tensor 5x*C*. Cada letra corresponderia a uma coluna do tensor em codificação one-hot.
* **Representação a nível de palavra**, na qual criamos um **vocabulário** de todas as palavras em nosso texto e, em seguida, representamos as palavras usando codificação one-hot. Essa abordagem é um pouco melhor, porque cada letra, por si só, não tem muito significado, e, ao usar conceitos semânticos de nível mais alto - palavras - simplificamos a tarefa para a rede neural. No entanto, dado o tamanho do dicionário, precisamos lidar com tensores esparsos de alta dimensão.
Independentemente da representação, primeiro precisamos converter o texto em uma sequência de **tokens**, sendo um token um caractere, uma palavra ou, às vezes, até parte de uma palavra. Depois, convertemos o token em um número, geralmente usando um **vocabulário**, e esse número pode ser alimentado em uma rede neural usando codificação one-hot.
## N-Gramas
Na linguagem natural, o significado preciso das palavras só pode ser determinado no contexto. Por exemplo, os significados de *rede neural* e *rede de pesca* são completamente diferentes. Uma das maneiras de levar isso em conta é construir nosso modelo com pares de palavras, considerando os pares de palavras como tokens separados no vocabulário. Dessa forma, a frase *Eu gosto de pescar* será representada pela seguinte sequência de tokens: *Eu gosto*, *gosto de*, *de pescar*. O problema com essa abordagem é que o tamanho do dicionário cresce significativamente, e combinações como *de pescar* e *de comprar* são representadas por tokens diferentes, que não compartilham nenhuma semelhança semântica, apesar do mesmo verbo.
Em alguns casos, podemos considerar o uso de tri-gramas -- combinações de três palavras -- também. Assim, essa abordagem é frequentemente chamada de **n-gramas**. Além disso, faz sentido usar n-gramas com representação a nível de caractere, caso em que os n-gramas corresponderão aproximadamente a diferentes sílabas.
## Bag-of-Words e TF/IDF
Ao resolver tarefas como classificação de texto, precisamos ser capazes de representar o texto por um vetor de tamanho fixo, que usaremos como entrada para o classificador denso final. Uma das maneiras mais simples de fazer isso é combinar todas as representações individuais de palavras, por exemplo, somando-as. Se somarmos as codificações one-hot de cada palavra, acabaremos com um vetor de frequências, mostrando quantas vezes cada palavra aparece no texto. Essa representação de texto é chamada de **bag-of-words** (BoW).
<img src="../../../../../translated_images/pt-BR/bow.3811869cff59368d.webp" width="90%"/>
> Imagem do autor
Um BoW essencialmente representa quais palavras aparecem no texto e em quais quantidades, o que pode ser uma boa indicação do que o texto trata. Por exemplo, um artigo de notícias sobre política provavelmente conterá palavras como *presidente* e *país*, enquanto uma publicação científica terá algo como *colisor*, *descoberto*, etc. Assim, as frequências das palavras podem, em muitos casos, ser um bom indicador do conteúdo do texto.
O problema com BoW é que certas palavras comuns, como *e*, *é*, etc., aparecem na maioria dos textos e têm as maiores frequências, mascarando as palavras que são realmente importantes. Podemos reduzir a importância dessas palavras levando em conta a frequência com que elas ocorrem em toda a coleção de documentos. Essa é a ideia principal por trás da abordagem TF/IDF, que é abordada em mais detalhes nos notebooks anexados a esta lição.
No entanto, nenhuma dessas abordagens pode levar totalmente em conta a **semântica** do texto. Precisamos de modelos de redes neurais mais poderosos para fazer isso, o que discutiremos mais adiante nesta seção.
## ✍️ Exercícios: Representação de Texto
Continue seu aprendizado nos seguintes notebooks:
* [Representação de Texto com PyTorch](TextRepresentationPyTorch.ipynb)
* [Representação de Texto com TensorFlow](TextRepresentationTF.ipynb)
## Conclusão
Até agora, estudamos técnicas que podem adicionar peso de frequência a diferentes palavras. No entanto, elas não conseguem representar o significado ou a ordem. Como o famoso linguista J. R. Firth disse em 1935: "O significado completo de uma palavra é sempre contextual, e nenhum estudo de significado fora do contexto pode ser levado a sério." Aprenderemos mais adiante no curso como capturar informações contextuais do texto usando modelagem de linguagem.
## 🚀 Desafio
Experimente outros exercícios usando bag-of-words e diferentes modelos de dados. Você pode se inspirar nesta [competição no Kaggle](https://www.kaggle.com/competitions/word2vec-nlp-tutorial/overview/part-1-for-beginners-bag-of-words)
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/26)
## Revisão & Autoestudo
Pratique suas habilidades com embeddings de texto e técnicas de bag-of-words no [Microsoft Learn](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/?WT.mc_id=academic-77998-cacaste)
## [Tarefa: Notebooks](assignment.md)
---

View File

@ -0,0 +1,577 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tarefa de classificação de texto\n",
"\n",
"Como mencionamos, vamos focar em uma tarefa simples de classificação de texto baseada no dataset **AG_NEWS**, que consiste em classificar manchetes de notícias em uma das 4 categorias: Mundo, Esportes, Negócios e Ciência/Tecnologia.\n",
"\n",
"## O Dataset\n",
"\n",
"Este dataset está integrado no módulo [`torchtext`](https://github.com/pytorch/text), então podemos acessá-lo facilmente.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torchtext\n",
"import os\n",
"import collections\n",
"os.makedirs('./data',exist_ok=True)\n",
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Aqui, `train_dataset` e `test_dataset` contêm coleções que retornam pares de rótulo (número da classe) e texto, respectivamente, por exemplo:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(3,\n",
" \"Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\\\band of ultra-cynics, are seeing green again.\")"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(train_dataset)[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Então, vamos imprimir as primeiras 10 novas manchetes do nosso conjunto de dados:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"**Sci/Tech** -> Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\band of ultra-cynics, are seeing green again.\n",
"**Sci/Tech** -> Carlyle Looks Toward Commercial Aerospace (Reuters) Reuters - Private investment firm Carlyle Group,\\which has a reputation for making well-timed and occasionally\\controversial plays in the defense industry, has quietly placed\\its bets on another part of the market.\n",
"**Sci/Tech** -> Oil and Economy Cloud Stocks' Outlook (Reuters) Reuters - Soaring crude prices plus worries\\about the economy and the outlook for earnings are expected to\\hang over the stock market next week during the depth of the\\summer doldrums.\n",
"**Sci/Tech** -> Iraq Halts Oil Exports from Main Southern Pipeline (Reuters) Reuters - Authorities have halted oil export\\flows from the main pipeline in southern Iraq after\\intelligence showed a rebel militia could strike\\infrastructure, an oil official said on Saturday.\n",
"**Sci/Tech** -> Oil prices soar to all-time record, posing new menace to US economy (AFP) AFP - Tearaway world oil prices, toppling records and straining wallets, present a new economic menace barely three months before the US presidential elections.\n"
]
}
],
"source": [
"for i,x in zip(range(5),train_dataset):\n",
" print(f\"**{classes[x[0]]}** -> {x[1]}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Porque conjuntos de dados são iteradores, se quisermos usar os dados várias vezes, precisamos convertê-los para lista:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"train_dataset = list(train_dataset)\n",
"test_dataset = list(test_dataset)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tokenização\n",
"\n",
"Agora precisamos converter o texto em **números** que podem ser representados como tensores. Se quisermos uma representação no nível de palavras, precisamos fazer duas coisas:\n",
"* usar um **tokenizador** para dividir o texto em **tokens**\n",
"* construir um **vocabulário** desses tokens.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['he', 'said', 'hello']"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
"tokenizer('He said: hello')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" counter.update(tokenizer(line))\n",
"vocab = torchtext.vocab.vocab(counter, min_freq=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Usando vocabulário, podemos facilmente codificar nossa string tokenizada em um conjunto de números:\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocab size if 95810\n"
]
},
{
"data": {
"text/plain": [
"[599, 3279, 97, 1220, 329, 225, 7368]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vocab_size = len(vocab)\n",
"print(f\"Vocab size if {vocab_size}\")\n",
"\n",
"stoi = vocab.get_stoi() # dict to convert tokens to indices\n",
"\n",
"def encode(x):\n",
" return [stoi[s] for s in tokenizer(x)]\n",
"\n",
"encode('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Representação de texto com Bag of Words\n",
"\n",
"Como as palavras representam significado, às vezes podemos entender o significado de um texto apenas observando as palavras individuais, independentemente da ordem em que aparecem na frase. Por exemplo, ao classificar notícias, palavras como *clima*, *neve* provavelmente indicam *previsão do tempo*, enquanto palavras como *ações*, *dólar* seriam associadas a *notícias financeiras*.\n",
"\n",
"A representação vetorial **Bag of Words** (BoW) é a representação vetorial tradicional mais comumente usada. Cada palavra está vinculada a um índice do vetor, e o elemento do vetor contém o número de ocorrências de uma palavra em um determinado documento.\n",
"\n",
"![Imagem mostrando como uma representação vetorial Bag of Words é representada na memória.](../../../../../translated_images/pt-BR/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **Note**: Você também pode pensar no BoW como a soma de todos os vetores one-hot-encoded para palavras individuais no texto.\n",
"\n",
"Abaixo está um exemplo de como gerar uma representação Bag of Words usando a biblioteca python Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para calcular o vetor bag-of-words a partir da representação vetorial do nosso conjunto de dados AG_NEWS, podemos usar a seguinte função:\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tensor([2., 1., 2., ..., 0., 0., 0.])\n"
]
}
],
"source": [
"vocab_size = len(vocab)\n",
"\n",
"def to_bow(text,bow_vocab_size=vocab_size):\n",
" res = torch.zeros(bow_vocab_size,dtype=torch.float32)\n",
" for i in encode(text):\n",
" if i<bow_vocab_size:\n",
" res[i] += 1\n",
" return res\n",
"\n",
"print(to_bow(train_dataset[0][1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota:** Aqui estamos usando a variável global `vocab_size` para especificar o tamanho padrão do vocabulário. Como frequentemente o tamanho do vocabulário é bastante grande, podemos limitar o tamanho do vocabulário às palavras mais frequentes. Tente reduzir o valor de `vocab_size` e executar o código abaixo, e veja como isso afeta a precisão. Você deve esperar alguma queda na precisão, mas nada dramático, em troca de um desempenho maior.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treinando o classificador BoW\n",
"\n",
"Agora que aprendemos como construir a representação Bag-of-Words do nosso texto, vamos treinar um classificador com base nela. Primeiro, precisamos converter nosso conjunto de dados para treinamento de forma que todas as representações vetoriais posicionais sejam transformadas em representações Bag-of-Words. Isso pode ser feito passando a função `bowify` como o parâmetro `collate_fn` para o `DataLoader` padrão do torch:\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"from torch.utils.data import DataLoader\n",
"import numpy as np \n",
"\n",
"# this collate function gets list of batch_size tuples, and needs to \n",
"# return a pair of label-feature tensors for the whole minibatch\n",
"def bowify(b):\n",
" return (\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([to_bow(t[1]) for t in b])\n",
" )\n",
"\n",
"train_loader = DataLoader(train_dataset, batch_size=16, collate_fn=bowify, shuffle=True)\n",
"test_loader = DataLoader(test_dataset, batch_size=16, collate_fn=bowify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos definir uma rede neural classificadora simples que contém uma camada linear. O tamanho do vetor de entrada é igual a `vocab_size`, e o tamanho da saída corresponde ao número de classes (4). Como estamos resolvendo uma tarefa de classificação, a função de ativação final é `LogSoftmax()`.\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"net = torch.nn.Sequential(torch.nn.Linear(vocab_size,4),torch.nn.LogSoftmax(dim=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos definir o loop de treinamento padrão do PyTorch. Como nosso conjunto de dados é bastante grande, para fins de ensino treinaremos apenas por uma época, e às vezes até por menos de uma época (especificar o parâmetro `epoch_size` nos permite limitar o treinamento). Também iremos relatar a precisão acumulada do treinamento durante o processo; a frequência de relatórios é especificada usando o parâmetro `report_freq`.\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.NLLLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,features in dataloader:\n",
" optimizer.zero_grad()\n",
" out = net(features)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.8028125\n",
"6400: acc=0.8371875\n",
"9600: acc=0.8534375\n",
"12800: acc=0.85765625\n"
]
},
{
"data": {
"text/plain": [
"(0.026090790722161722, 0.8620069296375267)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch(net,train_loader,epoch_size=15000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## BiGrams, TriGrams e N-Grams\n",
"\n",
"Uma limitação da abordagem de bag of words é que algumas palavras fazem parte de expressões compostas, por exemplo, a palavra 'hot dog' tem um significado completamente diferente das palavras 'hot' e 'dog' em outros contextos. Se representarmos as palavras 'hot' e 'dog' sempre pelos mesmos vetores, isso pode confundir nosso modelo.\n",
"\n",
"Para lidar com isso, as **representações N-gram** são frequentemente usadas em métodos de classificação de documentos, onde a frequência de cada palavra, bi-palavra ou tri-palavra é uma característica útil para treinar classificadores. Na representação bigram, por exemplo, adicionaremos todos os pares de palavras ao vocabulário, além das palavras originais.\n",
"\n",
"Abaixo está um exemplo de como gerar uma representação de bag of words com bigram usando o Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A principal desvantagem da abordagem N-gram é que o tamanho do vocabulário começa a crescer muito rapidamente. Na prática, precisamos combinar a representação N-gram com algumas técnicas de redução de dimensionalidade, como *embeddings*, que discutiremos na próxima unidade.\n",
"\n",
"Para usar a representação N-gram em nosso conjunto de dados **AG News**, precisamos construir um vocabulário especial de ngram:\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bigram vocabulary length = 1308842\n"
]
}
],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" l = tokenizer(line)\n",
" counter.update(torchtext.data.utils.ngrams_iterator(l,ngrams=2))\n",
" \n",
"bi_vocab = torchtext.vocab.vocab(counter, min_freq=1)\n",
"\n",
"print(\"Bigram vocabulary length = \",len(bi_vocab))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Poderíamos então usar o mesmo código acima para treinar o classificador, no entanto, isso seria muito ineficiente em termos de memória. Na próxima unidade, treinaremos um classificador de bigramas usando embeddings.\n",
"\n",
"> **Nota:** Você pode deixar apenas os ngrams que aparecem no texto mais do que o número especificado de vezes. Isso garantirá que bigramas pouco frequentes sejam omitidos e reduzirá significativamente a dimensionalidade. Para fazer isso, defina o parâmetro `min_freq` para um valor mais alto e observe a mudança no tamanho do vocabulário.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Frequência de Termos e Frequência Inversa de Documentos TF-IDF\n",
"\n",
"Na representação BoW, as ocorrências de palavras são ponderadas igualmente, independentemente da palavra em si. No entanto, é evidente que palavras frequentes, como *a*, *em*, etc., são muito menos importantes para a classificação do que termos especializados. De fato, na maioria das tarefas de PLN, algumas palavras são mais relevantes do que outras.\n",
"\n",
"**TF-IDF** significa **frequência de termosfrequência inversa de documentos**. É uma variação do modelo bag of words, onde, em vez de um valor binário 0/1 indicando a presença de uma palavra em um documento, utiliza-se um valor de ponto flutuante, que está relacionado à frequência de ocorrência da palavra no corpus.\n",
"\n",
"Mais formalmente, o peso $w_{ij}$ de uma palavra $i$ no documento $j$ é definido como:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"onde\n",
"* $tf_{ij}$ é o número de ocorrências de $i$ em $j$, ou seja, o valor BoW que vimos anteriormente\n",
"* $N$ é o número de documentos na coleção\n",
"* $df_i$ é o número de documentos que contêm a palavra $i$ em toda a coleção\n",
"\n",
"O valor TF-IDF $w_{ij}$ aumenta proporcionalmente ao número de vezes que uma palavra aparece em um documento e é ajustado pelo número de documentos no corpus que contêm a palavra, o que ajuda a compensar o fato de que algumas palavras aparecem com mais frequência do que outras. Por exemplo, se a palavra aparece em *todos* os documentos da coleção, $df_i=N$, e $w_{ij}=0$, e esses termos seriam completamente desconsiderados.\n",
"\n",
"Você pode criar facilmente a vetorização TF-IDF de texto usando Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"No entanto, embora as representações TF-IDF atribuam pesos de frequência a diferentes palavras, elas não conseguem representar significado ou ordem. Como disse o famoso linguista J. R. Firth em 1935: “O significado completo de uma palavra é sempre contextual, e nenhum estudo de significado fora do contexto pode ser levado a sério.”. Mais adiante no curso, aprenderemos como capturar informações contextuais de textos utilizando modelagem de linguagem.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "7b9040985e748e4e2d4c689892456ad7",
"translation_date": "2025-08-28T14:32:39+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationPyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,647 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tarefa de classificação de texto\n",
"\n",
"Neste módulo, começaremos com uma tarefa simples de classificação de texto baseada no dataset **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: vamos classificar manchetes de notícias em uma das 4 categorias: Mundo, Esportes, Negócios e Ciência/Tecnologia.\n",
"\n",
"## O Dataset\n",
"\n",
"Para carregar o dataset, usaremos a API **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"\n",
"# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,\n",
"# we will set tensorflow option to grow GPU memory allocation when required.\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"dataset = tfds.load('ag_news_subset')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora podemos acessar as partes de treinamento e teste do conjunto de dados usando `dataset['train']` e `dataset['test']`, respectivamente:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Length of train dataset = 120000\n",
"Length of test dataset = 7600\n"
]
}
],
"source": [
"ds_train = dataset['train']\n",
"ds_test = dataset['test']\n",
"\n",
"print(f\"Length of train dataset = {len(ds_train)}\")\n",
"print(f\"Length of test dataset = {len(ds_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos imprimir as primeiras 10 novas manchetes do nosso conjunto de dados:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 (Sci/Tech) -> b'AMD Debuts Dual-Core Opteron Processor' b'AMD #39;s new dual-core Opteron chip is designed mainly for corporate computing applications, including databases, Web services, and financial transactions.'\n",
"1 (Sports) -> b\"Wood's Suspension Upheld (Reuters)\" b'Reuters - Major League Baseball\\\\Monday announced a decision on the appeal filed by Chicago Cubs\\\\pitcher Kerry Wood regarding a suspension stemming from an\\\\incident earlier this season.'\n",
"2 (Business) -> b'Bush reform may have blue states seeing red' b'President Bush #39;s quot;revenue-neutral quot; tax reform needs losers to balance its winners, and people claiming the federal deduction for state and local taxes may be in administration planners #39; sights, news reports say.'\n",
"3 (Sci/Tech) -> b\"'Halt science decline in schools'\" b'Britain will run out of leading scientists unless science education is improved, says Professor Colin Pillinger.'\n",
"1 (Sports) -> b'Gerrard leaves practice' b'London, England (Sports Network) - England midfielder Steven Gerrard injured his groin late in Thursday #39;s training session, but is hopeful he will be ready for Saturday #39;s World Cup qualifier against Austria.'\n"
]
}
],
"source": [
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
"\n",
"for i,x in zip(range(5),ds_train):\n",
" print(f\"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vetorização de texto\n",
"\n",
"Agora precisamos converter texto em **números** que podem ser representados como tensores. Se quisermos uma representação em nível de palavra, precisamos fazer duas coisas:\n",
"\n",
"* Usar um **tokenizador** para dividir o texto em **tokens**.\n",
"* Construir um **vocabulário** desses tokens.\n",
"\n",
"### Limitando o tamanho do vocabulário\n",
"\n",
"No exemplo do conjunto de dados AG News, o tamanho do vocabulário é bastante grande, com mais de 100 mil palavras. De modo geral, não precisamos de palavras que raramente aparecem no texto — apenas algumas frases as terão, e o modelo não aprenderá com elas. Assim, faz sentido limitar o tamanho do vocabulário a um número menor, passando um argumento para o construtor do vetorizador:\n",
"\n",
"Ambos os passos podem ser realizados usando a camada **TextVectorization**. Vamos instanciar o objeto vetorizador e, em seguida, chamar o método `adapt` para percorrer todo o texto e construir um vocabulário:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"vocab_size = 50000\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)\n",
"vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota** que estamos utilizando apenas um subconjunto de todo o conjunto de dados para construir um vocabulário. Fazemos isso para acelerar o tempo de execução e não deixar você esperando. No entanto, corremos o risco de que algumas palavras do conjunto de dados completo não sejam incluídas no vocabulário e sejam ignoradas durante o treinamento. Assim, usar o tamanho total do vocabulário e percorrer todo o conjunto de dados durante `adapt` deve aumentar a precisão final, mas não de forma significativa.\n",
"\n",
"Agora podemos acessar o vocabulário real:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['', '[UNK]', 'the', 'to', 'a', 'in', 'of', 'and', 'on', 'for']\n",
"Length of vocabulary: 5335\n"
]
}
],
"source": [
"vocab = vectorizer.get_vocabulary()\n",
"vocab_size = len(vocab)\n",
"print(vocab[:10])\n",
"print(f\"Length of vocabulary: {vocab_size}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Usando o vetorizador, podemos facilmente codificar qualquer texto em um conjunto de números:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(7,), dtype=int64, numpy=array([ 112, 3695, 3, 304, 11, 1041, 1], dtype=int64)>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Representação de texto com Bag-of-words\n",
"\n",
"Como as palavras representam significado, às vezes podemos entender o significado de um texto apenas olhando para as palavras individuais, independentemente da ordem em que aparecem na frase. Por exemplo, ao classificar notícias, palavras como *clima* e *neve* provavelmente indicam *previsão do tempo*, enquanto palavras como *ações* e *dólar* seriam associadas a *notícias financeiras*.\n",
"\n",
"A representação vetorial **Bag-of-words** (BoW) é a forma tradicional mais simples de entender uma representação vetorial. Cada palavra é vinculada a um índice no vetor, e um elemento do vetor contém o número de ocorrências de cada palavra em um determinado documento.\n",
"\n",
"![Imagem mostrando como uma representação vetorial Bag-of-words é armazenada na memória.](../../../../../translated_images/pt-BR/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **Note**: Você também pode pensar no BoW como a soma de todos os vetores one-hot codificados para as palavras individuais no texto.\n",
"\n",
"Abaixo está um exemplo de como gerar uma representação Bag-of-words usando a biblioteca Scikit Learn em Python:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"sc_vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"sc_vectorizer.fit_transform(corpus)\n",
"sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos também usar o vetorizador do Keras que definimos acima, convertendo cada número de palavra em um one-hot encoding e somando todos esses vetores:\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0., 5., 0., ..., 0., 0., 0.], dtype=float32)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def to_bow(text):\n",
" return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)\n",
"\n",
"to_bow('My dog likes hot dogs on a hot day.').numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Você pode se surpreender que o resultado seja diferente do exemplo anterior. A razão é que, no exemplo do Keras, o comprimento do vetor corresponde ao tamanho do vocabulário, que foi construído a partir de todo o conjunto de dados AG News, enquanto no exemplo do Scikit Learn, construímos o vocabulário a partir do texto de amostra de forma dinâmica.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treinando o classificador BoW\n",
"\n",
"Agora que aprendemos como construir a representação bag-of-words do nosso texto, vamos treinar um classificador que a utiliza. Primeiro, precisamos converter nosso conjunto de dados para uma representação bag-of-words. Isso pode ser feito usando a função `map` da seguinte maneira:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 128\n",
"\n",
"ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)\n",
"ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos definir uma rede neural classificadora simples que contém uma camada linear. O tamanho da entrada é `vocab_size`, e o tamanho da saída corresponde ao número de classes (4). Como estamos resolvendo uma tarefa de classificação, a função de ativação final é **softmax**:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 66s 70ms/step - loss: 0.6144 - acc: 0.8427 - val_loss: 0.4416 - val_acc: 0.8697\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c70a947f0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train_bow,validation_data=ds_test_bow)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como temos 4 classes, uma precisão acima de 80% é um bom resultado.\n",
"\n",
"## Treinando um classificador como uma única rede\n",
"\n",
"Como o vetorizador também é uma camada do Keras, podemos definir uma rede que o inclua e treiná-la de ponta a ponta. Dessa forma, não precisamos vetorizar o conjunto de dados usando `map`, podemos simplesmente passar o conjunto de dados original para a entrada da rede.\n",
"\n",
"> **Note**: Ainda precisaríamos aplicar mapas ao nosso conjunto de dados para converter campos de dicionários (como `title`, `description` e `label`) em tuplas. No entanto, ao carregar dados do disco, podemos construir um conjunto de dados com a estrutura necessária desde o início.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_1 (InputLayer) [(None, 1)] 0 \n",
" \n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" tf.one_hot (TFOpLambda) (None, None, 5335) 0 \n",
" \n",
" tf.math.reduce_sum (TFOpLam (None, 5335) 0 \n",
" bda) \n",
" \n",
" dense_2 (Dense) (None, 4) 21344 \n",
" \n",
"=================================================================\n",
"Total params: 21,344\n",
"Trainable params: 21,344\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"938/938 [==============================] - 73s 77ms/step - loss: 0.6057 - acc: 0.8414 - val_loss: 0.4202 - val_acc: 0.8736\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c721521f0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"inp = keras.Input(shape=(1,),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"model.summary()\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bigramas, trigramas e n-gramas\n",
"\n",
"Uma limitação da abordagem de saco de palavras é que algumas palavras fazem parte de expressões compostas, por exemplo, a palavra 'hot dog' tem um significado completamente diferente das palavras 'hot' e 'dog' em outros contextos. Se representarmos as palavras 'hot' e 'dog' sempre usando os mesmos vetores, isso pode confundir nosso modelo.\n",
"\n",
"Para lidar com isso, as **representações de n-gramas** são frequentemente usadas em métodos de classificação de documentos, onde a frequência de cada palavra, bi-palavra ou tri-palavra é uma característica útil para treinar classificadores. Em representações de bigramas, por exemplo, adicionamos todos os pares de palavras ao vocabulário, além das palavras originais.\n",
"\n",
"Abaixo está um exemplo de como gerar uma representação de saco de palavras com bigramas usando o Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A principal desvantagem da abordagem n-gram é que o tamanho do vocabulário começa a crescer extremamente rápido. Na prática, precisamos combinar a representação n-gram com uma técnica de redução de dimensionalidade, como *embeddings*, que discutiremos na próxima unidade.\n",
"\n",
"Para usar uma representação n-gram em nosso conjunto de dados **AG News**, precisamos passar o parâmetro `ngrams` para o construtor `TextVectorization`. O tamanho de um vocabulário de bigramas é **significativamente maior**, no nosso caso, são mais de 1,3 milhões de tokens! Portanto, faz sentido limitar os tokens de bigramas a um número razoável.\n",
"\n",
"Poderíamos usar o mesmo código acima para treinar o classificador, no entanto, isso seria muito ineficiente em termos de memória. Na próxima unidade, treinaremos o classificador de bigramas usando embeddings. Enquanto isso, você pode experimentar o treinamento do classificador de bigramas neste notebook e ver se consegue obter uma precisão maior.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calculando automaticamente vetores BoW\n",
"\n",
"No exemplo acima, calculamos os vetores BoW manualmente somando as codificações one-hot de palavras individuais. No entanto, a versão mais recente do TensorFlow nos permite calcular vetores BoW automaticamente ao passar o parâmetro `output_mode='count` para o construtor do vetorizador. Isso torna a definição e o treinamento do nosso modelo significativamente mais simples:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 7s 7ms/step - loss: 0.5929 - acc: 0.8486 - val_loss: 0.4168 - val_acc: 0.8772\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c725217c0>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Frequência de termo - frequência inversa de documento (TF-IDF)\n",
"\n",
"Na representação BoW, as ocorrências de palavras são ponderadas usando a mesma técnica, independentemente da palavra em si. No entanto, é evidente que palavras frequentes como *a* e *em* são muito menos importantes para classificação do que termos especializados. Na maioria das tarefas de PLN, algumas palavras são mais relevantes do que outras.\n",
"\n",
"**TF-IDF** significa **frequência de termo - frequência inversa de documento**. É uma variação do modelo bag-of-words, onde, em vez de um valor binário 0/1 indicando a presença de uma palavra em um documento, utiliza-se um valor de ponto flutuante, que está relacionado à frequência de ocorrência da palavra no corpus.\n",
"\n",
"Mais formalmente, o peso $w_{ij}$ de uma palavra $i$ no documento $j$ é definido como:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"onde\n",
"* $tf_{ij}$ é o número de ocorrências de $i$ em $j$, ou seja, o valor BoW que vimos anteriormente\n",
"* $N$ é o número de documentos na coleção\n",
"* $df_i$ é o número de documentos que contêm a palavra $i$ em toda a coleção\n",
"\n",
"O valor TF-IDF $w_{ij}$ aumenta proporcionalmente ao número de vezes que uma palavra aparece em um documento e é ajustado pelo número de documentos no corpus que contêm a palavra, o que ajuda a compensar o fato de que algumas palavras aparecem com mais frequência do que outras. Por exemplo, se a palavra aparece em *todos* os documentos da coleção, $df_i=N$, e $w_{ij}=0$, e esses termos seriam completamente desconsiderados.\n",
"\n",
"Você pode criar facilmente a vetorização TF-IDF de texto usando o Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Em Keras, a camada `TextVectorization` pode calcular automaticamente as frequências TF-IDF passando o parâmetro `output_mode='tf-idf'`. Vamos repetir o código que usamos acima para ver se usar TF-IDF aumenta a precisão:\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 12s 12ms/step - loss: 0.4197 - acc: 0.8662 - val_loss: 0.3432 - val_acc: 0.8849\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c729dfd30>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Embora as representações TF-IDF atribuam pesos de frequência a diferentes palavras, elas não conseguem representar significado ou ordem. Como disse o famoso linguista J. R. Firth em 1935: \"O significado completo de uma palavra é sempre contextual, e nenhum estudo de significado fora do contexto pode ser levado a sério.\" Mais adiante no curso, aprenderemos como capturar informações contextuais de textos usando modelagem de linguagem.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "19b43951d55b377a76209c24c1f017e4",
"translation_date": "2025-08-28T14:35:25+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,6 @@
# Tarefa: Notebooks
Usando os notebooks associados a esta lição (seja a versão do PyTorch ou do TensorFlow), execute-os novamente utilizando seu próprio conjunto de dados, talvez um do Kaggle, usado com a devida atribuição. Reescreva o notebook para destacar suas próprias descobertas. Experimente alguns conjuntos de dados inovadores que possam ser surpreendentes, como [este sobre avistamentos de OVNIs](https://www.kaggle.com/datasets/NUFORC/ufo-sightings) do NUFORC.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,724 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings\n",
"\n",
"No exemplo anterior, trabalhamos com vetores de bag-of-words de alta dimensão com comprimento `vocab_size`, e estávamos convertendo explicitamente de vetores de representação posicional de baixa dimensão para uma representação esparsa de uma única posição ativa (one-hot). Essa representação one-hot não é eficiente em termos de memória e, além disso, cada palavra é tratada de forma independente, ou seja, vetores codificados em one-hot não expressam nenhuma similaridade semântica entre as palavras.\n",
"\n",
"Nesta unidade, continuaremos explorando o conjunto de dados **News AG**. Para começar, vamos carregar os dados e obter algumas definições do notebook anterior.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\train.csv: 29.5MB [00:01, 18.8MB/s] \n",
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\test.csv: 1.86MB [00:00, 11.2MB/s] \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Building vocab...\n",
"Vocab size = 95812\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"import numpy as np\n",
"from torchnlp import *\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_size = len(vocab)\n",
"print(\"Vocab size = \",vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## O que é embedding?\n",
"\n",
"A ideia de **embedding** é representar palavras por vetores densos de menor dimensão, que de alguma forma refletem o significado semântico de uma palavra. Mais adiante, discutiremos como construir embeddings de palavras significativos, mas, por enquanto, vamos apenas pensar em embeddings como uma forma de reduzir a dimensionalidade de um vetor de palavras.\n",
"\n",
"Assim, a camada de embedding receberia uma palavra como entrada e produziria um vetor de saída com o `embedding_size` especificado. De certa forma, é muito semelhante à camada `Linear`, mas, em vez de receber um vetor codificado em one-hot, ela será capaz de receber um número que representa a palavra como entrada.\n",
"\n",
"Ao usar a camada de embedding como a primeira camada em nossa rede, podemos mudar do modelo bag-of-words para o modelo **embedding bag**, onde primeiro convertemos cada palavra em nosso texto no embedding correspondente e, em seguida, calculamos alguma função de agregação sobre todos esses embeddings, como `sum`, `average` ou `max`.\n",
"\n",
"![Imagem mostrando um classificador de embedding para cinco palavras em sequência.](../../../../../translated_images/pt-BR/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"Nossa rede neural classificadora começará com uma camada de embedding, seguida por uma camada de agregação e, por fim, um classificador linear no topo:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" x = self.embedding(x)\n",
" x = torch.mean(x,dim=1)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Lidando com tamanhos variáveis de sequência\n",
"\n",
"Como resultado dessa arquitetura, os minibatches para nossa rede precisariam ser criados de uma maneira específica. Na unidade anterior, ao usar bag-of-words, todos os tensores BoW em um minibatch tinham tamanho igual a `vocab_size`, independentemente do comprimento real da sequência de texto. Quando passamos a usar embeddings de palavras, acabamos lidando com um número variável de palavras em cada amostra de texto, e ao combinar essas amostras em minibatches, precisaríamos aplicar algum preenchimento (padding).\n",
"\n",
"Isso pode ser feito utilizando a mesma técnica de fornecer a função `collate_fn` para a fonte de dados:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def padify(b):\n",
" # b is the list of tuples of length batch_size\n",
" # - first element of a tuple = label, \n",
" # - second = feature (text sequence)\n",
" # build vectorized sequence\n",
" v = [encode(x[1]) for x in b]\n",
" # first, compute max length of a sequence in this minibatch\n",
" l = max(map(len,v))\n",
" return ( # tuple of two tensors - labels and features\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Treinando o classificador de embeddings\n",
"\n",
"Agora que definimos um dataloader adequado, podemos treinar o modelo usando a função de treinamento que definimos na unidade anterior:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6415625\n",
"6400: acc=0.6865625\n",
"9600: acc=0.7103125\n",
"12800: acc=0.726953125\n",
"16000: acc=0.739375\n",
"19200: acc=0.75046875\n",
"22400: acc=0.7572321428571429\n"
]
},
{
"data": {
"text/plain": [
"(0.889799795315499, 0.7623160588611644)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=1, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Estamos treinando apenas 25 mil registros aqui (menos de uma época completa) por questão de tempo, mas você pode continuar treinando, escrever uma função para treinar por várias épocas e experimentar com o parâmetro de taxa de aprendizado para alcançar maior precisão. Você deve ser capaz de atingir uma precisão de cerca de 90%.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Camada EmbeddingBag e Representação de Sequências de Comprimento Variável\n",
"\n",
"Na arquitetura anterior, precisávamos preencher todas as sequências para que tivessem o mesmo comprimento, a fim de ajustá-las em um minibatch. Essa não é a maneira mais eficiente de representar sequências de comprimento variável - outra abordagem seria usar um vetor de **offset**, que armazenaria os deslocamentos de todas as sequências em um único vetor grande.\n",
"\n",
"![Imagem mostrando uma representação de sequência com offset](../../../../../translated_images/pt-BR/offset-sequence-representation.eb73fcefb29b46ee.webp)\n",
"\n",
"> **Note**: Na imagem acima, mostramos uma sequência de caracteres, mas em nosso exemplo estamos trabalhando com sequências de palavras. No entanto, o princípio geral de representar sequências com um vetor de offset permanece o mesmo.\n",
"\n",
"Para trabalhar com a representação de offset, usamos a camada [`EmbeddingBag`](https://pytorch.org/docs/stable/generated/torch.nn.EmbeddingBag.html). Ela é semelhante à `Embedding`, mas recebe um vetor de conteúdo e um vetor de offset como entrada, e também inclui uma camada de agregação, que pode ser `mean`, `sum` ou `max`.\n",
"\n",
"Aqui está uma rede modificada que utiliza `EmbeddingBag`:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.EmbeddingBag(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, text, off):\n",
" x = self.embedding(text, off)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para preparar o conjunto de dados para treinamento, precisamos fornecer uma função de conversão que irá preparar o vetor de deslocamento:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1])) for t in b]\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note que, diferentemente de todos os exemplos anteriores, nossa rede agora aceita dois parâmetros: vetor de dados e vetor de deslocamento, que possuem tamanhos diferentes. Da mesma forma, nosso carregador de dados também nos fornece 3 valores em vez de 2: tanto os vetores de texto quanto os vetores de deslocamento são fornecidos como características. Portanto, precisamos ajustar ligeiramente nossa função de treinamento para lidar com isso:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6153125\n",
"6400: acc=0.6615625\n",
"9600: acc=0.6932291666666667\n",
"12800: acc=0.715078125\n",
"16000: acc=0.7270625\n",
"19200: acc=0.7382291666666667\n",
"22400: acc=0.7486160714285715\n"
]
},
{
"data": {
"text/plain": [
"(22.771553103007037, 0.7551983365323096)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"\n",
"def train_epoch_emb(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" loss_fn = loss_fn.to(device)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,text,off in dataloader:\n",
" optimizer.zero_grad()\n",
" labels,text,off = labels.to(device), text.to(device), off.to(device)\n",
" out = net(text, off)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count\n",
"\n",
"\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings Semânticos: Word2Vec\n",
"\n",
"No nosso exemplo anterior, a camada de embedding do modelo aprendeu a mapear palavras para representações vetoriais, porém, essa representação não tinha muito significado semântico. Seria interessante aprender uma representação vetorial em que palavras semelhantes ou sinônimos corresponderiam a vetores próximos entre si em termos de alguma distância vetorial (por exemplo, distância euclidiana).\n",
"\n",
"Para isso, precisamos pré-treinar nosso modelo de embedding em uma grande coleção de textos de uma maneira específica. Uma das primeiras abordagens para treinar embeddings semânticos é chamada de [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). Ela se baseia em duas arquiteturas principais que são usadas para produzir uma representação distribuída de palavras:\n",
"\n",
" - **Continuous bag-of-words** (CBoW) — nesta arquitetura, treinamos o modelo para prever uma palavra a partir do contexto ao redor. Dado o ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$, o objetivo do modelo é prever $W_0$ a partir de $(W_{-2},W_{-1},W_1,W_2)$.\n",
" - **Continuous skip-gram** é o oposto do CBoW. O modelo usa a janela de palavras de contexto ao redor para prever a palavra atual.\n",
"\n",
"CBoW é mais rápido, enquanto skip-gram é mais lento, mas faz um trabalho melhor ao representar palavras menos frequentes.\n",
"\n",
"![Imagem mostrando os algoritmos CBoW e Skip-Gram para converter palavras em vetores.](../../../../../translated_images/pt-BR/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"Para experimentar com embeddings word2vec pré-treinados no conjunto de dados Google News, podemos usar a biblioteca **gensim**. Abaixo, encontramos as palavras mais semelhantes a 'neural'.\n",
"\n",
"> **Nota:** Quando você cria vetores de palavras pela primeira vez, baixá-los pode levar algum tempo!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import gensim.downloader as api\n",
"w2v = api.load('word2vec-google-news-300')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"neuronal -> 0.7804799675941467\n",
"neurons -> 0.7326500415802002\n",
"neural_circuits -> 0.7252851724624634\n",
"neuron -> 0.7174385190010071\n",
"cortical -> 0.6941086649894714\n",
"brain_circuitry -> 0.6923246383666992\n",
"synaptic -> 0.6699118614196777\n",
"neural_circuitry -> 0.6638563275337219\n",
"neurochemical -> 0.6555314064025879\n",
"neuronal_activity -> 0.6531826257705688\n"
]
}
],
"source": [
"for w,p in w2v.most_similar('neural'):\n",
" print(f\"{w} -> {p}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos também calcular embeddings de vetor a partir da palavra, para serem usados no treinamento do modelo de classificação (mostramos apenas os primeiros 20 componentes do vetor para maior clareza):\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.01226807, 0.06225586, 0.10693359, 0.05810547, 0.23828125,\n",
" 0.03686523, 0.05151367, -0.20703125, 0.01989746, 0.10058594,\n",
" -0.03759766, -0.1015625 , -0.15820312, -0.08105469, -0.0390625 ,\n",
" -0.05053711, 0.16015625, 0.2578125 , 0.10058594, -0.25976562],\n",
" dtype=float32)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.word_vec('play')[:20]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A grande vantagem das incorporações semânticas é que você pode manipular a codificação vetorial para alterar a semântica. Por exemplo, podemos pedir para encontrar uma palavra cuja representação vetorial seja o mais próxima possível das palavras *rei* e *mulher*, e o mais distante possível da palavra *homem*:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('queen', 0.7118192911148071)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.most_similar(positive=['king','woman'],negative=['man'])[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ambos CBoW e Skip-Grams são embeddings \"previsores\", pois consideram apenas os contextos locais. Word2Vec não aproveita o contexto global.\n",
"\n",
"**FastText** expande o Word2Vec ao aprender representações vetoriais para cada palavra e os n-gramas de caracteres encontrados dentro de cada palavra. Os valores das representações são então calculados como uma média em um único vetor a cada etapa de treinamento. Embora isso adicione muita computação adicional ao pré-treinamento, permite que os embeddings de palavras codifiquem informações de subpalavras.\n",
"\n",
"Outro método, **GloVe**, utiliza a ideia de matriz de coocorrência e emprega métodos neurais para decompor a matriz de coocorrência em vetores de palavras mais expressivos e não lineares.\n",
"\n",
"Você pode experimentar o exemplo alterando os embeddings para FastText e GloVe, já que o gensim suporta vários modelos diferentes de embeddings de palavras.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Usando Embeddings Pré-Treinados no PyTorch\n",
"\n",
"Podemos modificar o exemplo acima para pré-preencher a matriz em nossa camada de embedding com embeddings semânticos, como Word2Vec. Precisamos levar em conta que os vocabulários do embedding pré-treinado e do nosso corpus de texto provavelmente não irão coincidir, então inicializaremos os pesos para as palavras ausentes com valores aleatórios:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding size: 300\n",
"Populating matrix, this will take some time...Done, found 41080 words, 54732 words missing\n"
]
}
],
"source": [
"embed_size = len(w2v.get_vector('hello'))\n",
"print(f'Embedding size: {embed_size}')\n",
"\n",
"net = EmbedClassifier(vocab_size,embed_size,len(classes))\n",
"\n",
"print('Populating matrix, this will take some time...',end='')\n",
"found, not_found = 0,0\n",
"for i,w in enumerate(vocab.get_itos()):\n",
" try:\n",
" net.embedding.weight[i].data = torch.tensor(w2v.get_vector(w))\n",
" found+=1\n",
" except:\n",
" net.embedding.weight[i].data = torch.normal(0.0,1.0,(embed_size,))\n",
" not_found+=1\n",
"\n",
"print(f\"Done, found {found} words, {not_found} words missing\")\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos treinar nosso modelo. Observe que o tempo necessário para treinar o modelo é significativamente maior do que no exemplo anterior, devido ao tamanho maior da camada de embedding e, consequentemente, ao número muito maior de parâmetros. Além disso, por causa disso, podemos precisar treinar nosso modelo em mais exemplos se quisermos evitar overfitting.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6359375\n",
"6400: acc=0.68109375\n",
"9600: acc=0.7067708333333333\n",
"12800: acc=0.723671875\n",
"16000: acc=0.73625\n",
"19200: acc=0.7463541666666667\n",
"22400: acc=0.7560714285714286\n"
]
},
{
"data": {
"text/plain": [
"(214.1013875559821, 0.7626759436980166)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No nosso caso, não observamos um grande aumento na precisão, o que provavelmente se deve a vocabulários bastante diferentes. \n",
"Para superar o problema de vocabulários distintos, podemos usar uma das seguintes soluções: \n",
"* Re-treinar o modelo word2vec com o nosso vocabulário \n",
"* Carregar nosso conjunto de dados com o vocabulário do modelo word2vec pré-treinado. O vocabulário usado para carregar o conjunto de dados pode ser especificado durante o carregamento. \n",
"\n",
"A última abordagem parece mais fácil, especialmente porque o framework `torchtext` do PyTorch contém suporte integrado para embeddings. Podemos, por exemplo, instanciar um vocabulário baseado em GloVe da seguinte maneira: \n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████▉| 399999/400000 [00:15<00:00, 25411.14it/s]\n"
]
}
],
"source": [
"vocab = torchtext.vocab.GloVe(name='6B', dim=50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O vocabulário carregado possui as seguintes operações básicas:\n",
"* O dicionário `vocab.stoi` nos permite converter uma palavra em seu índice no dicionário.\n",
"* `vocab.itos` faz o oposto - converte um número em uma palavra.\n",
"* `vocab.vectors` é o array de vetores de embeddings, então, para obter o embedding de uma palavra `s`, precisamos usar `vocab.vectors[vocab.stoi[s]]`.\n",
"\n",
"Aqui está um exemplo de manipulação de embeddings para demonstrar a equação **kind-man+woman = queen** (tive que ajustar um pouco o coeficiente para funcionar):\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'queen'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get the vector corresponding to kind-man+woman\n",
"qvec = vocab.vectors[vocab.stoi['king']]-vocab.vectors[vocab.stoi['man']]+1.3*vocab.vectors[vocab.stoi['woman']]\n",
"# find the index of the closest embedding vector \n",
"d = torch.sum((vocab.vectors-qvec)**2,dim=1)\n",
"min_idx = torch.argmin(d)\n",
"# find the corresponding word\n",
"vocab.itos[min_idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para treinar o classificador usando esses embeddings, primeiro precisamos codificar nosso conjunto de dados usando o vocabulário GloVe:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1],voc=vocab)) for t in b] # pass the instance of vocab to encode function!\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como vimos acima, todas as incorporações de vetores são armazenadas na matriz `vocab.vectors`. Isso torna super fácil carregar esses pesos na camada de pesos de incorporação usando uma cópia simples:\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"net = EmbedClassifier(len(vocab),len(vocab.vectors[0]),len(classes))\n",
"net.embedding.weight.data = vocab.vectors\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6271875\n",
"6400: acc=0.68078125\n",
"9600: acc=0.7030208333333333\n",
"12800: acc=0.71984375\n",
"16000: acc=0.7346875\n",
"19200: acc=0.7455729166666667\n",
"22400: acc=0.7529464285714286\n"
]
},
{
"data": {
"text/plain": [
"(35.53972978646833, 0.7575175943698017)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Um dos motivos pelos quais não estamos vendo um aumento significativo na precisão é devido ao fato de que algumas palavras do nosso conjunto de dados estão ausentes no vocabulário pré-treinado do GloVe e, portanto, são essencialmente ignoradas. Para superar esse fato, podemos treinar nossas próprias embeddings em nosso conjunto de dados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings Contextuais\n",
"\n",
"Uma limitação importante das representações tradicionais de embeddings pré-treinados, como o Word2Vec, é o problema de desambiguação de sentidos das palavras. Embora os embeddings pré-treinados consigam capturar parte do significado das palavras no contexto, todos os possíveis significados de uma palavra são codificados no mesmo embedding. Isso pode causar problemas em modelos subsequentes, já que muitas palavras, como a palavra 'play', possuem significados diferentes dependendo do contexto em que são usadas.\n",
"\n",
"Por exemplo, a palavra 'play' nas duas frases abaixo tem significados bastante diferentes:\n",
"- Eu fui a uma **peça** no teatro.\n",
"- John quer **brincar** com seus amigos.\n",
"\n",
"Os embeddings pré-treinados acima representam ambos os significados da palavra 'play' no mesmo embedding. Para superar essa limitação, precisamos construir embeddings baseados no **modelo de linguagem**, que é treinado em um grande corpus de texto e *sabe* como as palavras podem ser combinadas em diferentes contextos. Discutir embeddings contextuais está fora do escopo deste tutorial, mas voltaremos a esse tema ao falar sobre modelos de linguagem na próxima unidade.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernelspec": {
"display_name": "py37_pytorch",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "f50b026abce5cf36783a560ea72cb9b1",
"translation_date": "2025-08-28T14:29:29+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,695 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings\n",
"\n",
"No exemplo anterior, trabalhamos com vetores de bag-of-words de alta dimensão com comprimento `vocab_size`, e convertíamos explicitamente vetores de representação posicional de baixa dimensão em representações esparsas de uma única posição ativa (one-hot). Essa representação one-hot não é eficiente em termos de memória. Além disso, cada palavra é tratada de forma independente, então os vetores codificados em one-hot não expressam semelhanças semânticas entre as palavras.\n",
"\n",
"Nesta unidade, continuaremos explorando o conjunto de dados **News AG**. Para começar, vamos carregar os dados e obter algumas definições da unidade anterior.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### O que é um embedding?\n",
"\n",
"A ideia de um **embedding** é representar palavras usando vetores densos de dimensão reduzida que refletem o significado semântico da palavra. Mais adiante, discutiremos como construir embeddings de palavras significativos, mas, por enquanto, vamos apenas pensar nos embeddings como uma forma de reduzir a dimensionalidade de um vetor de palavras.\n",
"\n",
"Assim, uma camada de embedding recebe uma palavra como entrada e produz um vetor de saída com o `embedding_size` especificado. De certa forma, é muito semelhante a uma camada `Dense`, mas, em vez de receber um vetor one-hot codificado como entrada, ela consegue receber um número que representa a palavra.\n",
"\n",
"Ao usar uma camada de embedding como a primeira camada da nossa rede, podemos mudar de um modelo de bag-of-words para um modelo de **embedding bag**, onde primeiro convertemos cada palavra do nosso texto no embedding correspondente e, em seguida, calculamos alguma função de agregação sobre todos esses embeddings, como `sum`, `average` ou `max`.\n",
"\n",
"![Imagem mostrando um classificador com embedding para cinco palavras em sequência.](../../../../../translated_images/pt-BR/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"Nossa rede neural classificadora consiste nas seguintes camadas:\n",
"\n",
"* Camada `TextVectorization`, que recebe uma string como entrada e produz um tensor de números de tokens. Vamos especificar um tamanho de vocabulário razoável, `vocab_size`, e ignorar palavras menos frequentes. A forma da entrada será 1, e a forma da saída será $n$, já que obteremos $n$ tokens como resultado, cada um contendo números de 0 a `vocab_size`.\n",
"* Camada `Embedding`, que recebe $n$ números e reduz cada número a um vetor denso de um comprimento especificado (100 no nosso exemplo). Assim, o tensor de entrada com forma $n$ será transformado em um tensor $n\\times 100$.\n",
"* Camada de agregação, que calcula a média desse tensor ao longo do primeiro eixo, ou seja, ela calculará a média de todos os $n$ tensores de entrada correspondentes a diferentes palavras. Para implementar essa camada, usaremos uma camada `Lambda` e passaremos para ela a função para calcular a média. A saída terá a forma de 100, e será a representação numérica de toda a sequência de entrada.\n",
"* Classificador linear final com uma camada `Dense`.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" embedding (Embedding) (None, None, 100) 3000000 \n",
" \n",
" lambda (Lambda) (None, 100) 0 \n",
" \n",
" dense (Dense) (None, 4) 404 \n",
" \n",
"=================================================================\n",
"Total params: 3,000,404\n",
"Trainable params: 3,000,404\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 30000\n",
"batch_size = 128\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer, \n",
" keras.layers.Embedding(vocab_size,100),\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No resumo (`summary`), na coluna **output shape**, a primeira dimensão do tensor `None` corresponde ao tamanho do minibatch, e a segunda corresponde ao comprimento da sequência de tokens. Todas as sequências de tokens no minibatch têm comprimentos diferentes. Discutiremos como lidar com isso na próxima seção.\n",
"\n",
"Agora, vamos treinar a rede:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 20s 20ms/step - loss: 0.7891 - acc: 0.8155 - val_loss: 0.4470 - val_acc: 0.8642\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x22255515100>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"print(\"Training vectorizer\")\n",
"vectorizer.adapt(ds_train.take(500).map(extract_text))\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **Nota** que estamos construindo o vetorizador com base em um subconjunto dos dados. Isso é feito para acelerar o processo, e pode resultar em uma situação em que nem todos os tokens do nosso texto estejam presentes no vocabulário. Nesse caso, esses tokens seriam ignorados, o que pode resultar em uma precisão ligeiramente menor. No entanto, na vida real, um subconjunto de texto frequentemente fornece uma boa estimativa do vocabulário.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Lidando com tamanhos variáveis de sequência\n",
"\n",
"Vamos entender como o treinamento ocorre em minibatches. No exemplo acima, o tensor de entrada tem dimensão 1, e usamos minibatches de tamanho 128, de modo que o tamanho real do tensor é $128 \\times 1$. No entanto, o número de tokens em cada sentença é diferente. Se aplicarmos a camada `TextVectorization` a uma única entrada, o número de tokens retornados será diferente, dependendo de como o texto é tokenizado:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tf.Tensor([ 1 45], shape=(2,), dtype=int64)\n",
"tf.Tensor([ 112 1271 1 3 1747 158], shape=(6,), dtype=int64)\n"
]
}
],
"source": [
"print(vectorizer('Hello, world!'))\n",
"print(vectorizer('I am glad to meet you!'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No entanto, quando aplicamos o vetorizador a várias sequências, ele precisa produzir um tensor de forma retangular, então preenche os elementos não utilizados com o token PAD (que, no nosso caso, é zero):\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(2, 6), dtype=int64, numpy=\n",
"array([[ 1, 45, 0, 0, 0, 0],\n",
" [ 112, 1271, 1, 3, 1747, 158]], dtype=int64)>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer(['Hello, world!','I am glad to meet you!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Aqui podemos ver as incorporações:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 1.53059261e-02, 6.80514947e-02, 3.14026810e-02, ...,\n",
" -8.92002955e-02, 1.52911525e-04, -5.65562584e-02],\n",
" [ 2.57456154e-01, 2.79364467e-01, -2.03605562e-01, ...,\n",
" -2.07474351e-01, 8.31158683e-02, -2.03911960e-01],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02]],\n",
"\n",
" [[ 1.89674050e-01, 2.61548996e-01, -3.67433839e-02, ...,\n",
" -2.07366899e-01, -1.05442435e-01, -2.36952081e-01],\n",
" [ 6.16133213e-02, 1.80511594e-01, 9.77298319e-02, ...,\n",
" -5.46628237e-02, -1.07340455e-01, -1.06589928e-01],\n",
" [ 1.53059261e-02, 6.80514947e-02, 3.14026810e-02, ...,\n",
" -8.92002955e-02, 1.52911525e-04, -5.65562584e-02],\n",
" [-4.84890305e-02, -8.41715634e-02, 1.51529670e-01, ...,\n",
" 1.28192469e-01, -7.77286515e-02, 1.26041949e-01],\n",
" [-4.17212099e-02, -5.60694858e-02, 4.08860669e-02, ...,\n",
" 8.70475471e-02, 8.92383084e-02, 1.67974353e-01],\n",
" [ 2.85779923e-01, 4.57767487e-01, 4.52292450e-02, ...,\n",
" -1.97419018e-01, -2.04659685e-01, -2.79758364e-01]]],\n",
" dtype=float32)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.layers[1](vectorizer(['Hello, world!','I am glad to meet you!'])).numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Para minimizar a quantidade de preenchimento, em alguns casos faz sentido classificar todas as sequências no conjunto de dados em ordem crescente de comprimento (ou, mais precisamente, número de tokens). Isso garantirá que cada minibatch contenha sequências de comprimento semelhante.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings semânticos: Word2Vec\n",
"\n",
"No nosso exemplo anterior, a camada de embedding aprendeu a mapear palavras para representações vetoriais, porém essas representações não tinham significado semântico. Seria interessante aprender uma representação vetorial em que palavras semelhantes ou sinônimos correspondam a vetores próximos entre si em termos de alguma métrica de distância vetorial (por exemplo, distância euclidiana).\n",
"\n",
"Para isso, precisamos pré-treinar nosso modelo de embedding em uma grande coleção de textos usando uma técnica como [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). Ele é baseado em duas arquiteturas principais que são usadas para produzir uma representação distribuída de palavras:\n",
"\n",
" - **Continuous bag-of-words** (CBoW), onde treinamos o modelo para prever uma palavra a partir do contexto ao redor. Dado o ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$, o objetivo do modelo é prever $W_0$ a partir de $(W_{-2},W_{-1},W_1,W_2)$.\n",
" - **Continuous skip-gram** é o oposto do CBoW. O modelo usa a janela de palavras de contexto ao redor para prever a palavra atual.\n",
"\n",
"CBoW é mais rápido, enquanto o skip-gram, embora mais lento, faz um trabalho melhor ao representar palavras menos frequentes.\n",
"\n",
"![Imagem mostrando os algoritmos CBoW e Skip-Gram para converter palavras em vetores.](../../../../../translated_images/pt-BR/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"Para experimentar o embedding Word2Vec pré-treinado no conjunto de dados do Google News, podemos usar a biblioteca **gensim**. Abaixo, encontramos as palavras mais semelhantes a 'neural'.\n",
"\n",
"> **Nota:** Quando você cria vetores de palavras pela primeira vez, o download pode levar algum tempo!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import gensim.downloader as api\n",
"w2v = api.load('word2vec-google-news-300')"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"neuronal -> 0.7804799675941467\n",
"neurons -> 0.7326500415802002\n",
"neural_circuits -> 0.7252851724624634\n",
"neuron -> 0.7174385190010071\n",
"cortical -> 0.6941086649894714\n",
"brain_circuitry -> 0.6923246383666992\n",
"synaptic -> 0.6699118614196777\n",
"neural_circuitry -> 0.6638563275337219\n",
"neurochemical -> 0.6555314064025879\n",
"neuronal_activity -> 0.6531826257705688\n"
]
}
],
"source": [
"for w,p in w2v.most_similar('neural'):\n",
" print(f\"{w} -> {p}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos também extrair o vetor de embedding da palavra, para ser usado no treinamento do modelo de classificação. O embedding possui 300 componentes, mas aqui mostramos apenas os primeiros 20 componentes do vetor para maior clareza:\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.01226807, 0.06225586, 0.10693359, 0.05810547, 0.23828125,\n",
" 0.03686523, 0.05151367, -0.20703125, 0.01989746, 0.10058594,\n",
" -0.03759766, -0.1015625 , -0.15820312, -0.08105469, -0.0390625 ,\n",
" -0.05053711, 0.16015625, 0.2578125 , 0.10058594, -0.25976562],\n",
" dtype=float32)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v['play'][:20]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A grande vantagem das incorporações semânticas é que você pode manipular a codificação vetorial com base na semântica. Por exemplo, podemos pedir para encontrar uma palavra cuja representação vetorial seja o mais próxima possível das palavras *rei* e *mulher*, e o mais distante possível da palavra *homem*:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('queen', 0.7118192911148071)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.most_similar(positive=['king','woman'],negative=['man'])[0]"
]
},
{
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"Um exemplo acima usa alguma mágica interna do GenSym, mas a lógica subjacente é na verdade bastante simples. Uma coisa interessante sobre embeddings é que você pode realizar operações vetoriais normais em vetores de embedding, e isso refletiria operações nos **significados** das palavras. O exemplo acima pode ser expresso em termos de operações vetoriais: calculamos o vetor correspondente a **REI-HOMEM+MULHER** (as operações `+` e `-` são realizadas nas representações vetoriais das palavras correspondentes), e então encontramos a palavra mais próxima no dicionário para esse vetor:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'queen'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get the vector corresponding to kind-man+woman\n",
"qvec = w2v['king']-1.7*w2v['man']+1.7*w2v['woman']\n",
"# find the index of the closest embedding vector \n",
"d = np.sum((w2v.vectors-qvec)**2,axis=1)\n",
"min_idx = np.argmin(d)\n",
"# find the corresponding word\n",
"w2v.index_to_key[min_idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **NOTE**: Tivemos que adicionar pequenos coeficientes aos vetores *man* e *woman* - experimente removê-los para ver o que acontece.\n",
"\n",
"Para encontrar o vetor mais próximo, usamos a estrutura do TensorFlow para calcular um vetor de distâncias entre nosso vetor e todos os vetores no vocabulário, e então encontramos o índice da palavra mínima usando `argmin`.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Embora o Word2Vec pareça uma ótima maneira de expressar a semântica das palavras, ele possui várias desvantagens, incluindo as seguintes:\n",
"\n",
"* Tanto os modelos CBoW quanto skip-gram são **embeddings preditivos**, e eles consideram apenas o contexto local. O Word2Vec não aproveita o contexto global.\n",
"* O Word2Vec não leva em conta a **morfologia** das palavras, ou seja, o fato de que o significado de uma palavra pode depender de diferentes partes dela, como o radical.\n",
"\n",
"O **FastText** tenta superar a segunda limitação e se baseia no Word2Vec ao aprender representações vetoriais para cada palavra e os n-gramas de caracteres encontrados dentro de cada palavra. Os valores dessas representações são então calculados como uma média em um único vetor a cada etapa de treinamento. Embora isso adicione uma quantidade significativa de computação adicional ao pré-treinamento, permite que os embeddings de palavras codifiquem informações de subpalavras.\n",
"\n",
"Outro método, o **GloVe**, utiliza uma abordagem diferente para embeddings de palavras, baseada na fatoração da matriz de contexto de palavras. Primeiro, ele constrói uma grande matriz que conta o número de ocorrências de palavras em diferentes contextos e, em seguida, tenta representar essa matriz em dimensões menores de uma forma que minimize a perda de reconstrução.\n",
"\n",
"A biblioteca gensim suporta esses embeddings de palavras, e você pode experimentá-los alterando o código de carregamento do modelo acima.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Usando embeddings pré-treinados no Keras\n",
"\n",
"Podemos modificar o exemplo acima para pré-preencher a matriz em nossa camada de embedding com embeddings semânticos, como o Word2Vec. É provável que os vocabulários do embedding pré-treinado e do corpus de texto não coincidam, então precisamos escolher um deles. Aqui exploramos as duas opções possíveis: usar o vocabulário do tokenizer e usar o vocabulário dos embeddings do Word2Vec.\n",
"\n",
"### Usando o vocabulário do tokenizer\n",
"\n",
"Ao usar o vocabulário do tokenizer, algumas palavras do vocabulário terão embeddings correspondentes do Word2Vec, enquanto outras estarão ausentes. Dado que o tamanho do nosso vocabulário é `vocab_size`, e o comprimento do vetor de embedding do Word2Vec é `embed_size`, a camada de embedding será representada por uma matriz de pesos com a forma `vocab_size`$\\times$`embed_size`. Vamos preencher essa matriz percorrendo o vocabulário:\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding size: 300\n",
"Populating matrix, this will take some time...Done, found 4551 words, 784 words missing\n"
]
}
],
"source": [
"embed_size = len(w2v.get_vector('hello'))\n",
"print(f'Embedding size: {embed_size}')\n",
"\n",
"vocab = vectorizer.get_vocabulary()\n",
"W = np.zeros((vocab_size,embed_size))\n",
"print('Populating matrix, this will take some time...',end='')\n",
"found, not_found = 0,0\n",
"for i,w in enumerate(vocab):\n",
" try:\n",
" W[i] = w2v.get_vector(w)\n",
" found+=1\n",
" except:\n",
" # W[i] = np.random.normal(0.0,0.3,size=(embed_size,))\n",
" not_found+=1\n",
"\n",
"print(f\"Done, found {found} words, {not_found} words missing\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para palavras que não estão presentes no vocabulário do Word2Vec, podemos deixá-las como zeros ou gerar um vetor aleatório.\n",
"\n",
"Agora podemos definir uma camada de embedding com pesos pré-treinados:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"emb = keras.layers.Embedding(vocab_size,embed_size,weights=[W],trainable=False)\n",
"model = keras.models.Sequential([\n",
" vectorizer, emb,\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 10s 10ms/step - loss: 1.1075 - acc: 0.7822 - val_loss: 0.9134 - val_acc: 0.8175\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2220226ef10>"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Observe que definimos `trainable=False` ao criar o `Embedding`, o que significa que não estamos re-treinando a camada de Embedding. Isso pode fazer com que a precisão seja ligeiramente menor, mas acelera o treinamento.\n",
"\n",
"### Usando o vocabulário de embedding\n",
"\n",
"Um problema com a abordagem anterior é que os vocabulários usados no TextVectorization e no Embedding são diferentes. Para resolver esse problema, podemos usar uma das seguintes soluções:\n",
"* Re-treinar o modelo Word2Vec com nosso vocabulário.\n",
"* Carregar nosso conjunto de dados com o vocabulário do modelo Word2Vec pré-treinado. Os vocabulários usados para carregar o conjunto de dados podem ser especificados durante o carregamento.\n",
"\n",
"A última abordagem parece mais simples, então vamos implementá-la. Primeiro, criaremos uma camada `TextVectorization` com o vocabulário especificado, retirado dos embeddings do Word2Vec:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"vocab = list(w2v.vocab.keys())\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(input_shape=(1,))\n",
"vectorizer.set_vocabulary(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A biblioteca de embeddings de palavras do gensim contém uma função conveniente, `get_keras_embeddings`, que criará automaticamente a camada de embeddings correspondente do Keras para você.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/5\n",
"938/938 [==============================] - 20s 14ms/step - loss: 1.3377 - acc: 0.4978 - val_loss: 1.2995 - val_acc: 0.5647\n",
"Epoch 2/5\n",
"938/938 [==============================] - 10s 10ms/step - loss: 1.2587 - acc: 0.5722 - val_loss: 1.2339 - val_acc: 0.5842\n",
"Epoch 3/5\n",
"938/938 [==============================] - 10s 10ms/step - loss: 1.1980 - acc: 0.5884 - val_loss: 1.1826 - val_acc: 0.5954\n",
"Epoch 4/5\n",
"938/938 [==============================] - 12s 13ms/step - loss: 1.1503 - acc: 0.6002 - val_loss: 1.1417 - val_acc: 0.6018\n",
"Epoch 5/5\n",
"938/938 [==============================] - 11s 12ms/step - loss: 1.1120 - acc: 0.6097 - val_loss: 1.1083 - val_acc: 0.6104\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2220ccb81c0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer, \n",
" w2v.get_keras_embedding(train_embeddings=False),\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128),epochs=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Uma das razões pelas quais não estamos vendo maior precisão é porque algumas palavras do nosso conjunto de dados estão ausentes no vocabulário pré-treinado do GloVe e, portanto, são essencialmente ignoradas. Para superar isso, podemos treinar nossas próprias embeddings com base no nosso conjunto de dados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings contextuais\n",
"\n",
"Uma limitação importante das representações tradicionais de embeddings pré-treinados, como o Word2Vec, é o fato de que, embora consigam capturar algum significado de uma palavra, não conseguem diferenciar entre significados diferentes. Isso pode causar problemas em modelos subsequentes.\n",
"\n",
"Por exemplo, a palavra 'play' tem significados diferentes nestas duas frases:\n",
"- Eu fui a uma **peça** no teatro.\n",
"- John quer **brincar** com seus amigos.\n",
"\n",
"Os embeddings pré-treinados que mencionamos representam ambos os significados da palavra 'play' no mesmo embedding. Para superar essa limitação, precisamos construir embeddings baseados no **modelo de linguagem**, que é treinado em um grande corpus de texto e *sabe* como as palavras podem ser combinadas em diferentes contextos. Discutir embeddings contextuais está fora do escopo deste tutorial, mas voltaremos a eles ao falar sobre modelos de linguagem na próxima unidade.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "b859482be7f61d1eadc2c6a2720a37e4",
"translation_date": "2025-08-28T14:25:57+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsTF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,68 @@
# Embeddings
## [Pre-lecture quiz](https://ff-quizzes.netlify.app/en/ai/quiz/27)
Ao treinar classificadores baseados em BoW ou TF/IDF, trabalhamos com vetores de bag-of-words de alta dimensionalidade com comprimento `vocab_size`, e estávamos convertendo explicitamente de vetores de representação posicional de baixa dimensionalidade para uma representação esparsa de uma única posição ativa (one-hot). No entanto, essa representação one-hot não é eficiente em termos de memória. Além disso, cada palavra é tratada de forma independente, ou seja, vetores codificados em one-hot não expressam nenhuma similaridade semântica entre palavras.
A ideia de **embedding** é representar palavras por vetores densos de menor dimensionalidade, que de alguma forma refletem o significado semântico de uma palavra. Mais adiante, discutiremos como construir embeddings de palavras significativos, mas, por enquanto, vamos apenas pensar em embeddings como uma forma de reduzir a dimensionalidade de um vetor de palavras.
Assim, a camada de embedding receberia uma palavra como entrada e produziria um vetor de saída com o tamanho especificado `embedding_size`. De certa forma, é muito semelhante a uma camada `Linear`, mas, em vez de receber um vetor codificado em one-hot, ela será capaz de receber um número de palavra como entrada, permitindo evitar a criação de grandes vetores codificados em one-hot.
Ao usar uma camada de embedding como a primeira camada em nossa rede de classificação, podemos mudar de um modelo bag-of-words para um modelo **embedding bag**, onde primeiro convertemos cada palavra em nosso texto no embedding correspondente e, em seguida, calculamos alguma função agregada sobre todos esses embeddings, como `sum`, `average` ou `max`.
![Imagem mostrando um classificador de embedding para cinco palavras de sequência.](../../../../../translated_images/pt-BR/embedding-classifier-example.b77f021a7ee67eee.webp)
> Imagem do autor
## ✍️ Exercícios: Embeddings
Continue seu aprendizado nos seguintes notebooks:
* [Embeddings com PyTorch](EmbeddingsPyTorch.ipynb)
* [Embeddings com TensorFlow](EmbeddingsTF.ipynb)
## Embeddings Semânticos: Word2Vec
Embora a camada de embedding tenha aprendido a mapear palavras para representações vetoriais, essa representação não necessariamente possui muito significado semântico. Seria interessante aprender uma representação vetorial tal que palavras semelhantes ou sinônimos correspondam a vetores próximos entre si em termos de alguma distância vetorial (por exemplo, distância Euclidiana).
Para isso, precisamos pré-treinar nosso modelo de embedding em uma grande coleção de textos de uma maneira específica. Uma forma de treinar embeddings semânticos é chamada [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). Ela se baseia em duas arquiteturas principais que são usadas para produzir uma representação distribuída de palavras:
- **Continuous bag-of-words** (CBoW) — nesta arquitetura, treinamos o modelo para prever uma palavra a partir do contexto ao redor. Dado o ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$, o objetivo do modelo é prever $W_0$ a partir de $(W_{-2},W_{-1},W_1,W_2)$.
- **Continuous skip-gram** é o oposto do CBoW. O modelo usa uma janela de palavras de contexto ao redor para prever a palavra atual.
CBoW é mais rápido, enquanto skip-gram é mais lento, mas faz um trabalho melhor ao representar palavras menos frequentes.
![Imagem mostrando os algoritmos CBoW e Skip-Gram para converter palavras em vetores.](../../../../../translated_images/pt-BR/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)
> Imagem retirada [deste artigo](https://arxiv.org/pdf/1301.3781.pdf)
Embeddings pré-treinados do Word2Vec (assim como outros modelos similares, como GloVe) também podem ser usados no lugar da camada de embedding em redes neurais. No entanto, precisamos lidar com vocabulários, porque o vocabulário usado para pré-treinar o Word2Vec/GloVe provavelmente será diferente do vocabulário em nosso corpus de texto. Confira os notebooks acima para ver como esse problema pode ser resolvido.
## Embeddings Contextuais
Uma limitação importante das representações tradicionais de embeddings pré-treinados, como Word2Vec, é o problema de desambiguação de sentidos das palavras. Embora embeddings pré-treinados possam capturar parte do significado das palavras no contexto, todos os possíveis significados de uma palavra são codificados no mesmo embedding. Isso pode causar problemas em modelos posteriores, já que muitas palavras, como a palavra 'play', têm significados diferentes dependendo do contexto em que são usadas.
Por exemplo, a palavra 'play' nas duas frases abaixo tem significados bem diferentes:
- Eu fui a uma **peça** no teatro.
- John quer **brincar** com seus amigos.
Os embeddings pré-treinados acima representam ambos os significados da palavra 'play' no mesmo embedding. Para superar essa limitação, precisamos construir embeddings baseados no **modelo de linguagem**, que é treinado em um grande corpus de texto e *sabe* como as palavras podem ser combinadas em diferentes contextos. Discutir embeddings contextuais está fora do escopo deste tutorial, mas voltaremos a eles ao falar sobre modelos de linguagem mais adiante no curso.
## Conclusão
Nesta lição, você descobriu como construir e usar camadas de embedding no TensorFlow e PyTorch para refletir melhor os significados semânticos das palavras.
## 🚀 Desafio
Word2Vec tem sido usado em algumas aplicações interessantes, incluindo a geração de letras de músicas e poesias. Confira [este artigo](https://www.politetype.com/blog/word2vec-color-poems), que explica como o autor usou Word2Vec para gerar poesia. Assista também [este vídeo de Dan Shiffmann](https://www.youtube.com/watch?v=LSS_bos_TPI&ab_channel=TheCodingTrain) para descobrir uma explicação diferente dessa técnica. Depois, tente aplicar essas técnicas ao seu próprio corpus de texto, talvez obtido no Kaggle.
## [Post-lecture quiz](https://ff-quizzes.netlify.app/en/ai/quiz/28)
## Revisão e Autoestudo
Leia este artigo sobre Word2Vec: [Efficient Estimation of Word Representations in Vector Space](https://arxiv.org/pdf/1301.3781.pdf)
## [Assignment: Notebooks](assignment.md)
---

View File

@ -0,0 +1,6 @@
# Tarefa: Notebooks
Utilizando os notebooks associados a esta lição (seja a versão PyTorch ou TensorFlow), execute-os novamente usando seu próprio conjunto de dados, talvez um do Kaggle, utilizado com atribuição. Reescreva o notebook para destacar suas próprias descobertas. Experimente um tipo diferente de conjunto de dados e documente suas conclusões, usando texto como [essas letras dos Beatles](https://www.kaggle.com/datasets/jenlooper/beatles-lyrics).
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,576 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "NXTSugt6ieXh"
},
"source": [
"## Treinando o Modelo CBoW\n",
"\n",
"Este notebook faz parte do [Currículo de IA para Iniciantes](http://aka.ms/ai-beginners)\n",
"\n",
"Neste exemplo, vamos explorar o treinamento de um modelo de linguagem CBoW para obter nosso próprio espaço de incorporação Word2Vec. Usaremos o conjunto de dados AG News como fonte de texto.\n"
]
},
{
"cell_type": "code",
"source": [
"import torch\n",
"import torchtext\n",
"import os\n",
"import collections\n",
"import builtins\n",
"import random\n",
"import numpy as np"
],
"metadata": {
"id": "q-UiiJUKaxHj"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")"
],
"metadata": {
"id": "TFbR8CZaTZ1q"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Primeiro, vamos carregar nosso conjunto de dados e definir o tokenizador e o vocabulário. Vamos definir `vocab_size` como 5000 para limitar um pouco os cálculos.\n"
],
"metadata": {
"id": "HIwC7lI5T-ov"
}
},
{
"cell_type": "code",
"source": [
"def load_dataset(ngrams = 1, min_freq = 1, vocab_size = 5000 , lines_cnt = 500):\n",
" tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
" print(\"Loading dataset...\")\n",
" test_dataset, train_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
" train_dataset = list(train_dataset)\n",
" test_dataset = list(test_dataset)\n",
" classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
" print('Building vocab...')\n",
" counter = collections.Counter()\n",
" for i, (_, line) in enumerate(train_dataset):\n",
" counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line),ngrams=ngrams))\n",
" if i == lines_cnt:\n",
" break\n",
" vocab = torchtext.vocab.Vocab(collections.Counter(dict(counter.most_common(vocab_size))), min_freq=min_freq)\n",
" return train_dataset, test_dataset, classes, vocab, tokenizer"
],
"metadata": {
"id": "wdZuygtgiuLG"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_dataset, test_dataset, _, vocab, tokenizer = load_dataset()"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4d1nU1gsivGu",
"outputId": "949fe272-ae0e-49f5-c373-6703458b3a74"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"def encode(x, vocabulary, tokenizer = tokenizer):\n",
" return [vocabulary[s] for s in tokenizer(x)]"
],
"metadata": {
"id": "1XDYNhG8ToFV"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "LIlQk6_PaHVY"
},
"source": [
"## Modelo CBoW\n",
"\n",
"O CBoW aprende a prever uma palavra com base nas $2N$ palavras vizinhas. Por exemplo, quando $N=1$, obteremos os seguintes pares da frase *Eu gosto de treinar redes*: (gosto, eu), (eu, gosto), (de, gosto), (gosto, de), (treinar, de), (de, treinar), (redes, treinar), (treinar, redes). Aqui, a primeira palavra é a palavra vizinha usada como entrada, e a segunda palavra é aquela que estamos prevendo.\n",
"\n",
"Para construir uma rede que prevê a próxima palavra, precisaremos fornecer a palavra vizinha como entrada e obter o número da palavra como saída. A arquitetura da rede CBoW é a seguinte:\n",
"\n",
"* A palavra de entrada é passada pela camada de embedding. Essa mesma camada de embedding será nosso embedding Word2Vec, portanto, iremos defini-la separadamente como a variável `embedder`. Usaremos um tamanho de embedding = 30 neste exemplo, embora você possa querer experimentar dimensões maiores (o Word2Vec real tem 300).\n",
"* O vetor de embedding será então passado para uma camada linear que irá prever a palavra de saída. Assim, ela possui os neurônios `vocab_size`.\n",
"\n",
"Para a saída, se usarmos `CrossEntropyLoss` como função de perda, também teremos que fornecer apenas os números das palavras como resultados esperados, sem codificação one-hot.\n"
]
},
{
"cell_type": "code",
"source": [
"vocab_size = len(vocab)\n",
"\n",
"embedder = torch.nn.Embedding(num_embeddings = vocab_size, embedding_dim = 30)\n",
"model = torch.nn.Sequential(\n",
" embedder,\n",
" torch.nn.Linear(in_features = 30, out_features = vocab_size),\n",
")\n",
"\n",
"print(model)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "akKTcKQKkfl2",
"outputId": "da687e3e-a8ec-4c1a-e456-ab8cd6ac7dad"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Sequential(\n",
" (0): Embedding(5002, 30)\n",
" (1): Linear(in_features=30, out_features=5002, bias=True)\n",
")\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Nud6jgGPaHVa"
},
"source": [
"## Preparando Dados de Treinamento\n",
"\n",
"Agora vamos programar a função principal que calculará os pares de palavras CBoW a partir do texto. Essa função permitirá que especifiquemos o tamanho da janela e retornará um conjunto de pares - palavra de entrada e palavra de saída. Observe que essa função pode ser usada tanto em palavras quanto em vetores/tensores - o que nos permitirá codificar o texto antes de passá-lo para a função `to_cbow`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "x-dsXygOieXn",
"outputId": "c2218280-e540-40ba-9546-efe48d0d714f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[['like', 'I'], ['to', 'I'], ['I', 'like'], ['to', 'like'], ['train', 'like'], ['I', 'to'], ['like', 'to'], ['train', 'to'], ['networks', 'to'], ['like', 'train'], ['to', 'train'], ['networks', 'train'], ['to', 'networks'], ['train', 'networks']]\n",
"[[232, 172], [5, 172], [172, 232], [5, 232], [0, 232], [172, 5], [232, 5], [0, 5], [1202, 5], [232, 0], [5, 0], [1202, 0], [5, 1202], [0, 1202]]\n"
]
}
],
"source": [
"def to_cbow(sent,window_size=2):\n",
" res = []\n",
" for i,x in enumerate(sent):\n",
" for j in range(max(0,i-window_size),min(i+window_size+1,len(sent))):\n",
" if i!=j:\n",
" res.append([sent[j],x])\n",
" return res\n",
"\n",
"print(to_cbow(['I','like','to','train','networks']))\n",
"print(to_cbow(encode('I like to train networks', vocab)))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XVaaDLjaaHVb"
},
"source": [
"Vamos preparar o conjunto de dados de treinamento. Vamos passar por todas as notícias, chamar `to_cbow` para obter a lista de pares de palavras e adicionar esses pares a `X` e `Y`. Por questão de tempo, consideraremos apenas os primeiros 10k itens de notícias - você pode facilmente remover essa limitação caso tenha mais tempo para esperar e queira obter melhores embeddings :)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "54b-Gd9TieXo"
},
"outputs": [],
"source": [
"X = []\n",
"Y = []\n",
"for i, x in zip(range(10000), train_dataset):\n",
" for w1, w2 in to_cbow(encode(x[1], vocab), window_size = 5):\n",
" X.append(w1)\n",
" Y.append(w2)\n",
"\n",
"X = torch.tensor(X)\n",
"Y = torch.tensor(Y)"
]
},
{
"cell_type": "markdown",
"source": [
"Também converteremos esses dados para um único conjunto de dados e criaremos um dataloader:\n"
],
"metadata": {
"id": "cwWy0PzXWhN5"
}
},
{
"cell_type": "code",
"source": [
"class SimpleIterableDataset(torch.utils.data.IterableDataset):\n",
" def __init__(self, X, Y):\n",
" super(SimpleIterableDataset).__init__()\n",
" self.data = []\n",
" for i in range(len(X)):\n",
" self.data.append( (Y[i], X[i]) )\n",
" random.shuffle(self.data)\n",
"\n",
" def __iter__(self):\n",
" return iter(self.data)"
],
"metadata": {
"id": "mfoAcGPFZU8p"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "e4NQ_-5waHVc"
},
"source": [
"Também converteremos esses dados para um único conjunto de dados e criaremos um dataloader:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AbLUcojlieXo"
},
"outputs": [],
"source": [
"ds = SimpleIterableDataset(X, Y)\n",
"dl = torch.utils.data.DataLoader(ds, batch_size = 256)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pKQr7sXeaHVc"
},
"source": [
"Agora vamos fazer o treinamento propriamente dito. Usaremos o otimizador `SGD` com uma taxa de aprendizado bem alta. Você também pode experimentar outros otimizadores, como `Adam`. Vamos treinar por 10 épocas para começar - e você pode executar esta célula novamente se quiser uma perda ainda menor.\n"
]
},
{
"cell_type": "code",
"source": [
"def train_epoch(net, dataloader, lr = 0.01, optimizer = None, loss_fn = torch.nn.CrossEntropyLoss(), epochs = None, report_freq = 1):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(), lr = lr)\n",
" loss_fn = loss_fn.to(device)\n",
" net.train()\n",
"\n",
" for i in range(epochs):\n",
" total_loss, j = 0, 0, \n",
" for labels, features in dataloader:\n",
" optimizer.zero_grad()\n",
" features, labels = features.to(device), labels.to(device)\n",
" out = net(features)\n",
" loss = loss_fn(out, labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss += loss\n",
" j += 1\n",
" if i % report_freq == 0:\n",
" print(f\"Epoch: {i+1}: loss={total_loss.item()/j}\")\n",
"\n",
" return total_loss.item()/j"
],
"metadata": {
"id": "HeeCYKr_KF1w"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_epoch(net = model, dataloader = dl, optimizer = torch.optim.SGD(model.parameters(), lr = 0.1), loss_fn = torch.nn.CrossEntropyLoss(), epochs = 10)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KVgwGtDHgDlT",
"outputId": "2447833f-f0e3-4566-c33d-addbfe2f451d"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Epoch: 1: loss=5.664632366860172\n",
"Epoch: 2: loss=5.632101973960962\n",
"Epoch: 3: loss=5.610399051405015\n",
"Epoch: 4: loss=5.594621561080262\n",
"Epoch: 5: loss=5.582538017415446\n",
"Epoch: 6: loss=5.572900234519603\n",
"Epoch: 7: loss=5.564951676341915\n",
"Epoch: 8: loss=5.558288112064614\n",
"Epoch: 9: loss=5.552576955031129\n",
"Epoch: 10: loss=5.547634165194347\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"5.547634165194347"
]
},
"metadata": {},
"execution_count": 16
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W8u2qXZmaHVd"
},
"source": [
"## Experimentando o Word2Vec\n",
"\n",
"Para usar o Word2Vec, vamos extrair os vetores correspondentes a todas as palavras em nosso vocabulário:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r8TatcXjkU_t"
},
"outputs": [],
"source": [
"vectors = torch.stack([embedder(torch.tensor(vocab[s])) for s in vocab.itos], 0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3OcX21UOaHVd"
},
"source": [
"Vamos ver, por exemplo, como a palavra **Paris** é codificada em um vetor:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bz6tAeLzieXp",
"outputId": "5b20850e-4342-45e9-f840-cfac2b4d61d8"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"tensor([-0.0915, 2.1224, -0.0281, -0.6819, 1.1219, 0.6458, -1.3704, -1.3314,\n",
" -1.1437, 0.4496, 0.2301, -0.3515, -0.8485, 1.0481, 0.4386, -0.8949,\n",
" 0.5644, 1.0939, -2.5096, 3.2949, -0.2601, -0.8640, 0.1421, -0.0804,\n",
" -0.5083, -1.0560, 0.9753, -0.5949, -1.6046, 0.5774],\n",
" grad_fn=<EmbeddingBackward>)\n"
]
}
],
"source": [
"paris_vec = embedder(torch.tensor(vocab['paris']))\n",
"print(paris_vec)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pHTJlaeYaHVd"
},
"source": [
"É interessante usar Word2Vec para procurar sinônimos. A função a seguir retornará `n` palavras mais próximas de uma entrada fornecida. Para encontrá-las, calculamos a norma de $|w_i - v|$, onde $v$ é o vetor correspondente à nossa palavra de entrada, e $w_i$ é a codificação da i-ésima palavra no vocabulário. Em seguida, ordenamos o array e retornamos os índices correspondentes usando `argsort`, e pegamos os primeiros `n` elementos da lista, que codificam as posições das palavras mais próximas no vocabulário.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NlZyi-_olFar",
"outputId": "b5dbb163-88c4-4d5a-eaf2-6751f700e98c"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['microsoft', 'quoted', 'lp', 'rate', 'top']"
]
},
"metadata": {},
"execution_count": 56
}
],
"source": [
"def close_words(x, n = 5):\n",
" vec = embedder(torch.tensor(vocab[x]))\n",
" top5 = np.linalg.norm(vectors.detach().numpy() - vec.detach().numpy(), axis = 1).argsort()[:n]\n",
" return [ vocab.itos[x] for x in top5 ]\n",
"\n",
"close_words('microsoft')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "-dQq7xeAln0U",
"outputId": "66f768c3-c248-4bfd-ce4f-c8ffc6d0dd0d"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['basketball', 'lot', 'sinai', 'states', 'healthdaynews']"
]
},
"metadata": {},
"execution_count": 51
}
],
"source": [
"close_words('basketball')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fJXqK26b29sa",
"outputId": "78f0baba-ffd0-485a-dd87-0a12bedfd7fa"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['funds', 'travel', 'sydney', 'japan', 'business']"
]
},
"metadata": {},
"execution_count": 77
}
],
"source": [
"close_words('funds')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "My0VeTDd3Ji8"
},
"source": [
"## Conclusão\n",
"\n",
"Usando técnicas inteligentes como CBoW, podemos treinar o modelo Word2Vec. Você também pode tentar treinar o modelo skip-gram, que é treinado para prever a palavra vizinha com base na palavra central, e verificar como ele se sai.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"name": "CBoW-PyTorch.ipynb",
"provenance": []
},
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"orig_nbformat": 4,
"gpuClass": "standard",
"coopTranslator": {
"original_hash": "36df28efe3fe40b6fb0a7fa48fe3ea82",
"translation_date": "2025-08-28T14:08:00+00:00",
"source_file": "lessons/5-NLP/15-LanguageModeling/CBoW-PyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
# Modelagem de Linguagem
Embeddings semânticos, como Word2Vec e GloVe, são, na verdade, um primeiro passo em direção à **modelagem de linguagem** - criando modelos que de alguma forma *entendem* (ou *representam*) a natureza da linguagem.
## [Pré-quiz da aula](https://ff-quizzes.netlify.app/en/ai/quiz/29)
A ideia principal por trás da modelagem de linguagem é treiná-los em conjuntos de dados não rotulados de forma não supervisionada. Isso é importante porque temos uma enorme quantidade de texto não rotulado disponível, enquanto a quantidade de texto rotulado sempre será limitada pelo esforço que podemos dedicar à rotulagem. Na maioria das vezes, podemos construir modelos de linguagem que conseguem **prever palavras ausentes** no texto, porque é fácil mascarar uma palavra aleatória no texto e usá-la como um exemplo de treinamento.
## Treinando Embeddings
Nos nossos exemplos anteriores, usamos embeddings semânticos pré-treinados, mas é interessante ver como esses embeddings podem ser treinados. Existem várias ideias possíveis que podem ser utilizadas:
* **Modelagem de linguagem N-Gram**, onde prevemos um token olhando para os N tokens anteriores (N-grama).
* **Continuous Bag-of-Words** (CBoW), onde prevemos o token do meio $W_0$ em uma sequência de tokens $W_{-N}$, ..., $W_N$.
* **Skip-gram**, onde prevemos um conjunto de tokens vizinhos {$W_{-N},\dots, W_{-1}, W_1,\dots, W_N$} a partir do token do meio $W_0$.
![imagem do artigo sobre conversão de palavras em vetores](../../../../../translated_images/pt-BR/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)
> Imagem retirada [deste artigo](https://arxiv.org/pdf/1301.3781.pdf)
## ✍️ Exemplos de Notebooks: Treinando o modelo CBoW
Continue seu aprendizado nos seguintes notebooks:
* [Treinando CBoW Word2Vec com TensorFlow](CBoW-TF.ipynb)
* [Treinando CBoW Word2Vec com PyTorch](CBoW-PyTorch.ipynb)
## Conclusão
Na lição anterior, vimos que embeddings de palavras funcionam como mágica! Agora sabemos que treinar embeddings de palavras não é uma tarefa muito complexa, e devemos ser capazes de treinar nossos próprios embeddings para textos específicos de domínio, se necessário.
## [Pós-quiz da aula](https://ff-quizzes.netlify.app/en/ai/quiz/30)
## Revisão e Autoestudo
* [Tutorial oficial do PyTorch sobre Modelagem de Linguagem](https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html).
* [Tutorial oficial do TensorFlow sobre treinamento do modelo Word2Vec](https://www.TensorFlow.org/tutorials/text/word2vec).
* O uso do framework **gensim** para treinar os embeddings mais comumente usados em poucas linhas de código é descrito [nesta documentação](https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html).
## 🚀 [Tarefa: Treinar Modelo Skip-Gram](lab/README.md)
No laboratório, desafiamos você a modificar o código desta lição para treinar um modelo skip-gram em vez de CBoW. [Leia os detalhes](lab/README.md)
---

View File

@ -0,0 +1,29 @@
# Treinando o Modelo Skip-Gram
Atividade prática do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Neste laboratório, desafiamos você a treinar um modelo Word2Vec usando a técnica Skip-Gram. Treine uma rede com embeddings para prever palavras vizinhas em uma janela Skip-Gram de $N$ tokens de largura. Você pode usar o [código desta lição](../../../../../../lessons/5-NLP/15-LanguageModeling/CBoW-TF.ipynb) e modificá-lo levemente.
## O Conjunto de Dados
Você pode usar qualquer livro. Há muitos textos gratuitos disponíveis no [Project Gutenberg](https://www.gutenberg.org/), por exemplo, aqui está um link direto para [Alice no País das Maravilhas](https://www.gutenberg.org/files/11/11-0.txt) de Lewis Carroll. Ou, você pode usar as peças de Shakespeare, que podem ser obtidas com o seguinte código:
```python
path_to_file = tf.keras.utils.get_file(
'shakespeare.txt',
'https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
```
## Explore!
Se você tiver tempo e quiser se aprofundar no assunto, tente explorar algumas coisas:
* Como o tamanho do embedding afeta os resultados?
* Como diferentes estilos de texto afetam o resultado?
* Pegue vários tipos de palavras muito diferentes e seus sinônimos, obtenha suas representações vetoriais, aplique PCA para reduzir as dimensões para 2 e plote-as em um espaço 2D. Você percebe algum padrão?
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,87 @@
# Redes Neurais Recorrentes
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/31)
Nas seções anteriores, utilizamos representações semânticas ricas de texto e um classificador linear simples sobre os embeddings. O que essa arquitetura faz é capturar o significado agregado das palavras em uma frase, mas ela não leva em conta a **ordem** das palavras, porque a operação de agregação sobre os embeddings remove essa informação do texto original. Como esses modelos não conseguem modelar a ordem das palavras, eles não podem resolver tarefas mais complexas ou ambíguas, como geração de texto ou resposta a perguntas.
Para capturar o significado de uma sequência de texto, precisamos usar outra arquitetura de rede neural, chamada de **rede neural recorrente**, ou RNN. Na RNN, passamos nossa frase pela rede um símbolo de cada vez, e a rede produz algum **estado**, que então passamos novamente para a rede junto com o próximo símbolo.
![RNN](../../../../../translated_images/pt-BR/rnn.27f5c29c53d727b5.webp)
> Imagem do autor
Dada a sequência de entrada de tokens X<sub>0</sub>,...,X<sub>n</sub>, a RNN cria uma sequência de blocos de rede neural e treina essa sequência de ponta a ponta usando retropropagação. Cada bloco de rede recebe um par (X<sub>i</sub>,S<sub>i</sub>) como entrada e produz S<sub>i+1</sub> como resultado. O estado final S<sub>n</sub> ou (saída Y<sub>n</sub>) é enviado para um classificador linear para produzir o resultado. Todos os blocos da rede compartilham os mesmos pesos e são treinados de ponta a ponta em uma única passagem de retropropagação.
Como os vetores de estado S<sub>0</sub>,...,S<sub>n</sub> são passados pela rede, ela consegue aprender as dependências sequenciais entre as palavras. Por exemplo, quando a palavra *não* aparece em algum lugar da sequência, a rede pode aprender a negar certos elementos dentro do vetor de estado, resultando em negação.
> ✅ Como os pesos de todos os blocos da RNN na imagem acima são compartilhados, a mesma imagem pode ser representada como um único bloco (à direita) com um loop de feedback recorrente, que passa o estado de saída da rede de volta para a entrada.
## Anatomia de uma Célula RNN
Vamos ver como uma célula RNN simples é organizada. Ela aceita o estado anterior S<sub>i-1</sub> e o símbolo atual X<sub>i</sub> como entradas, e precisa produzir o estado de saída S<sub>i</sub> (e, às vezes, também estamos interessados em alguma outra saída Y<sub>i</sub>, como no caso de redes generativas).
Uma célula RNN simples possui duas matrizes de peso internas: uma transforma um símbolo de entrada (vamos chamá-la de W) e outra transforma um estado de entrada (H). Nesse caso, a saída da rede é calculada como &sigma;(W&times;X<sub>i</sub>+H&times;S<sub>i-1</sub>+b), onde &sigma; é a função de ativação e b é um viés adicional.
<img alt="Anatomia da Célula RNN" src="../../../../../translated_images/pt-BR/rnn-anatomy.79ee3f3920b3294b.webp" width="50%"/>
> Imagem do autor
Em muitos casos, os tokens de entrada passam por uma camada de embedding antes de entrar na RNN para reduzir a dimensionalidade. Nesse caso, se a dimensão dos vetores de entrada for *emb_size* e o vetor de estado for *hid_size*, o tamanho de W será *emb_size*&times;*hid_size*, e o tamanho de H será *hid_size*&times;*hid_size*.
## Long Short Term Memory (LSTM)
Um dos principais problemas das RNNs clássicas é o chamado problema de **gradientes que desaparecem**. Como as RNNs são treinadas de ponta a ponta em uma única passagem de retropropagação, elas têm dificuldade em propagar o erro para as primeiras camadas da rede, e assim a rede não consegue aprender relações entre tokens distantes. Uma das formas de evitar esse problema é introduzir **gerenciamento explícito de estado** usando os chamados **gates**. Existem duas arquiteturas bem conhecidas desse tipo: **Long Short Term Memory** (LSTM) e **Gated Relay Unit** (GRU).
![Imagem mostrando um exemplo de célula LSTM](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)
> Fonte da imagem a ser definida
A rede LSTM é organizada de maneira semelhante à RNN, mas há dois estados que são passados de camada para camada: o estado real C e o vetor oculto H. Em cada unidade, o vetor oculto H<sub>i</sub> é concatenado com a entrada X<sub>i</sub>, e eles controlam o que acontece com o estado C por meio de **gates**. Cada gate é uma rede neural com ativação sigmoide (saída no intervalo [0,1]), que pode ser vista como uma máscara bit a bit quando multiplicada pelo vetor de estado. Existem os seguintes gates (da esquerda para a direita na imagem acima):
* O **gate de esquecimento** recebe um vetor oculto e determina quais componentes do vetor C precisamos esquecer e quais passar adiante.
* O **gate de entrada** extrai algumas informações dos vetores de entrada e ocultos e as insere no estado.
* O **gate de saída** transforma o estado por meio de uma camada linear com ativação *tanh*, e então seleciona alguns de seus componentes usando um vetor oculto H<sub>i</sub> para produzir um novo estado C<sub>i+1</sub>.
Os componentes do estado C podem ser vistos como algumas flags que podem ser ativadas ou desativadas. Por exemplo, quando encontramos o nome *Alice* na sequência, podemos assumir que se refere a um personagem feminino e ativar a flag no estado indicando que temos um substantivo feminino na frase. Quando encontramos posteriormente a frase *e Tom*, ativamos a flag indicando que temos um substantivo no plural. Assim, manipulando o estado, podemos supostamente acompanhar as propriedades gramaticais das partes da frase.
> ✅ Um excelente recurso para entender os detalhes internos do LSTM é este ótimo artigo [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) de Christopher Olah.
## RNNs Bidirecionais e Multicamadas
Discutimos redes recorrentes que operam em uma direção, do início de uma sequência até o fim. Isso parece natural, pois se assemelha à forma como lemos e ouvimos fala. No entanto, como em muitos casos práticos temos acesso aleatório à sequência de entrada, pode fazer sentido executar o cálculo recorrente em ambas as direções. Essas redes são chamadas de **RNNs bidirecionais**. Ao lidar com redes bidirecionais, precisaríamos de dois vetores de estado oculto, um para cada direção.
Uma rede recorrente, seja unidirecional ou bidirecional, captura certos padrões dentro de uma sequência e pode armazená-los em um vetor de estado ou passá-los para a saída. Assim como nas redes convolucionais, podemos construir outra camada recorrente sobre a primeira para capturar padrões de nível superior e construir a partir dos padrões de baixo nível extraídos pela primeira camada. Isso nos leva à noção de uma **RNN multicamada**, que consiste em duas ou mais redes recorrentes, onde a saída da camada anterior é passada para a próxima camada como entrada.
![Imagem mostrando uma RNN LSTM multicamada](../../../../../translated_images/pt-BR/multi-layer-lstm.dd975e29bb2a59fe.webp)
*Imagem retirada [deste post maravilhoso](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) de Fernando López*
## ✍️ Exercícios: Embeddings
Continue seu aprendizado nos seguintes notebooks:
* [RNNs com PyTorch](RNNPyTorch.ipynb)
* [RNNs com TensorFlow](RNNTF.ipynb)
## Conclusão
Nesta unidade, vimos que as RNNs podem ser usadas para classificação de sequência, mas, na verdade, elas podem lidar com muitas outras tarefas, como geração de texto, tradução automática e mais. Consideraremos essas tarefas na próxima unidade.
## 🚀 Desafio
Leia alguns materiais sobre LSTMs e considere suas aplicações:
- [Grid Long Short-Term Memory](https://arxiv.org/pdf/1507.01526v1.pdf)
- [Show, Attend and Tell: Neural Image Caption
Generation with Visual Attention](https://arxiv.org/pdf/1502.03044v2.pdf)
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/32)
## Revisão e Autoestudo
- [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) de Christopher Olah.
## [Tarefa: Notebooks](assignment.md)
---

View File

@ -0,0 +1,479 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Redes neurais recorrentes\n",
"\n",
"No módulo anterior, utilizamos representações semânticas ricas de texto e um classificador linear simples sobre as embeddings. O que essa arquitetura faz é capturar o significado agregado das palavras em uma sentença, mas ela não leva em conta a **ordem** das palavras, porque a operação de agregação sobre as embeddings removeu essa informação do texto original. Como esses modelos não conseguem modelar a ordem das palavras, eles não podem resolver tarefas mais complexas ou ambíguas, como geração de texto ou resposta a perguntas.\n",
"\n",
"Para capturar o significado de uma sequência de texto, precisamos usar outra arquitetura de rede neural, chamada de **rede neural recorrente**, ou RNN. Em uma RNN, passamos nossa sentença pela rede um símbolo de cada vez, e a rede produz algum **estado**, que então passamos novamente para a rede junto com o próximo símbolo.\n",
"\n",
"Dada a sequência de tokens de entrada $X_0,\\dots,X_n$, a RNN cria uma sequência de blocos de rede neural e treina essa sequência de ponta a ponta usando retropropagação. Cada bloco de rede recebe um par $(X_i,S_i)$ como entrada e produz $S_{i+1}$ como resultado. O estado final $S_n$ ou a saída $X_n$ é enviado para um classificador linear para produzir o resultado. Todos os blocos da rede compartilham os mesmos pesos e são treinados de ponta a ponta em uma única passagem de retropropagação.\n",
"\n",
"Como os vetores de estado $S_0,\\dots,S_n$ são passados pela rede, ela consegue aprender as dependências sequenciais entre as palavras. Por exemplo, quando a palavra *não* aparece em algum lugar da sequência, a rede pode aprender a negar certos elementos dentro do vetor de estado, resultando em uma negação.\n",
"\n",
"> Como os pesos de todos os blocos da RNN na imagem são compartilhados, a mesma imagem pode ser representada como um único bloco (à direita) com um loop de feedback recorrente, que passa o estado de saída da rede de volta para a entrada.\n",
"\n",
"Vamos ver como as redes neurais recorrentes podem nos ajudar a classificar nosso conjunto de dados de notícias.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"from torchnlp import *\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_size = len(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Classificador RNN Simples\n",
"\n",
"No caso de um RNN simples, cada unidade recorrente é uma rede linear simples, que recebe um vetor de entrada concatenado com um vetor de estado e produz um novo vetor de estado. O PyTorch representa essa unidade com a classe `RNNCell`, e uma rede composta por essas células como uma camada `RNN`.\n",
"\n",
"Para definir um classificador RNN, primeiro aplicaremos uma camada de embedding para reduzir a dimensionalidade do vocabulário de entrada e, em seguida, utilizaremos uma camada RNN sobre ela:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class RNNClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.rnn = torch.nn.RNN(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" x,h = self.rnn(x)\n",
" return self.fc(x.mean(dim=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota:** Aqui usamos uma camada de embedding não treinada para simplificar, mas para obter resultados ainda melhores, podemos usar uma camada de embedding pré-treinada com embeddings do Word2Vec ou GloVe, como descrito na unidade anterior. Para uma melhor compreensão, você pode adaptar este código para funcionar com embeddings pré-treinados.\n",
"\n",
"No nosso caso, utilizaremos um carregador de dados com preenchimento (padded data loader), de modo que cada lote terá um número de sequências preenchidas com o mesmo comprimento. A camada RNN receberá a sequência de tensores de embedding e produzirá duas saídas: \n",
"* $x$ é uma sequência de saídas das células RNN em cada etapa\n",
"* $h$ é o estado oculto final para o último elemento da sequência\n",
"\n",
"Em seguida, aplicamos um classificador linear totalmente conectado para obter o número da classe.\n",
"\n",
"> **Nota:** RNNs são bastante difíceis de treinar, porque, uma vez que as células RNN são desenroladas ao longo do comprimento da sequência, o número resultante de camadas envolvidas na retropropagação é bastante grande. Por isso, precisamos selecionar uma taxa de aprendizado pequena e treinar a rede em um conjunto de dados maior para produzir bons resultados. Isso pode levar bastante tempo, então o uso de GPU é preferível.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.3090625\n",
"6400: acc=0.38921875\n",
"9600: acc=0.4590625\n",
"12800: acc=0.511953125\n",
"16000: acc=0.5506875\n",
"19200: acc=0.57921875\n",
"22400: acc=0.6070089285714285\n",
"25600: acc=0.6304296875\n",
"28800: acc=0.6484027777777778\n",
"32000: acc=0.66509375\n",
"35200: acc=0.6790056818181818\n",
"38400: acc=0.6929166666666666\n",
"41600: acc=0.7035817307692308\n",
"44800: acc=0.7137276785714286\n",
"48000: acc=0.72225\n",
"51200: acc=0.73001953125\n",
"54400: acc=0.7372794117647059\n",
"57600: acc=0.7436631944444444\n",
"60800: acc=0.7503947368421052\n",
"64000: acc=0.75634375\n",
"67200: acc=0.7615773809523809\n",
"70400: acc=0.7662642045454545\n",
"73600: acc=0.7708423913043478\n",
"76800: acc=0.7751822916666666\n",
"80000: acc=0.7790625\n",
"83200: acc=0.7825\n",
"86400: acc=0.7858564814814815\n",
"89600: acc=0.7890513392857142\n",
"92800: acc=0.7920474137931034\n",
"96000: acc=0.7952708333333334\n",
"99200: acc=0.7982258064516129\n",
"102400: acc=0.80099609375\n",
"105600: acc=0.8037594696969697\n",
"108800: acc=0.8060569852941176\n"
]
}
],
"source": [
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)\n",
"net = RNNClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=0.001)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Long Short Term Memory (LSTM)\n",
"\n",
"Um dos principais problemas das RNNs clássicas é o chamado problema de **gradientes que desaparecem**. Como as RNNs são treinadas de ponta a ponta em uma única passagem de retropropagação, elas têm dificuldade em propagar o erro para as primeiras camadas da rede, e, assim, a rede não consegue aprender relações entre tokens distantes. Uma das maneiras de evitar esse problema é introduzir **gerenciamento explícito de estado** usando os chamados **gates** (portões). Existem duas arquiteturas mais conhecidas desse tipo: **Long Short Term Memory** (LSTM) e **Gated Relay Unit** (GRU).\n",
"\n",
"![Imagem mostrando um exemplo de célula de memória de longo curto prazo](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"A rede LSTM é organizada de maneira semelhante à RNN, mas existem dois estados que são passados de camada para camada: o estado atual $c$ e o vetor oculto $h$. Em cada unidade, o vetor oculto $h_i$ é concatenado com a entrada $x_i$, e eles controlam o que acontece com o estado $c$ por meio de **gates**. Cada gate é uma rede neural com ativação sigmoide (saída no intervalo $[0,1]$), que pode ser pensada como uma máscara bit a bit quando multiplicada pelo vetor de estado. Existem os seguintes gates (da esquerda para a direita na imagem acima):\n",
"* **forget gate** pega o vetor oculto e determina quais componentes do vetor $c$ precisamos esquecer e quais passar adiante.\n",
"* **input gate** pega algumas informações da entrada e do vetor oculto e as insere no estado.\n",
"* **output gate** transforma o estado por meio de uma camada linear com ativação $\\tanh$, depois seleciona alguns de seus componentes usando o vetor oculto $h_i$ para produzir o novo estado $c_{i+1}$.\n",
"\n",
"Os componentes do estado $c$ podem ser pensados como algumas bandeiras que podem ser ativadas ou desativadas. Por exemplo, quando encontramos o nome *Alice* em uma sequência, podemos assumir que se refere a um personagem feminino e ativar a bandeira no estado indicando que temos um substantivo feminino na frase. Quando mais tarde encontramos a frase *and Tom*, ativamos a bandeira indicando que temos um substantivo no plural. Assim, manipulando o estado, podemos, supostamente, acompanhar as propriedades gramaticais das partes da frase.\n",
"\n",
"> **Note**: Um ótimo recurso para entender os detalhes internos do LSTM é este excelente artigo [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) de Christopher Olah.\n",
"\n",
"Embora a estrutura interna da célula LSTM possa parecer complexa, o PyTorch esconde essa implementação dentro da classe `LSTMCell` e fornece o objeto `LSTM` para representar toda a camada LSTM. Assim, a implementação de um classificador LSTM será bastante semelhante à RNN simples que vimos acima:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class LSTMClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n",
" self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" x,(h,c) = self.rnn(x)\n",
" return self.fc(h[-1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.259375\n",
"6400: acc=0.25859375\n",
"9600: acc=0.26177083333333334\n",
"12800: acc=0.2784375\n",
"16000: acc=0.313\n",
"19200: acc=0.3528645833333333\n",
"22400: acc=0.3965625\n",
"25600: acc=0.4385546875\n",
"28800: acc=0.4752777777777778\n",
"32000: acc=0.505375\n",
"35200: acc=0.5326704545454546\n",
"38400: acc=0.5557552083333334\n",
"41600: acc=0.5760817307692307\n",
"44800: acc=0.5954910714285714\n",
"48000: acc=0.6118333333333333\n",
"51200: acc=0.62681640625\n",
"54400: acc=0.6404779411764706\n",
"57600: acc=0.6520138888888889\n",
"60800: acc=0.662828947368421\n",
"64000: acc=0.673546875\n",
"67200: acc=0.6831547619047619\n",
"70400: acc=0.6917897727272727\n",
"73600: acc=0.6997146739130434\n",
"76800: acc=0.707109375\n",
"80000: acc=0.714075\n",
"83200: acc=0.7209134615384616\n",
"86400: acc=0.727037037037037\n",
"89600: acc=0.7326674107142858\n",
"92800: acc=0.7379633620689655\n",
"96000: acc=0.7433645833333333\n",
"99200: acc=0.7479032258064516\n",
"102400: acc=0.752119140625\n",
"105600: acc=0.7562405303030303\n",
"108800: acc=0.76015625\n",
"112000: acc=0.7641339285714286\n",
"115200: acc=0.7677777777777778\n",
"118400: acc=0.7711233108108108\n"
]
},
{
"data": {
"text/plain": [
"(0.03487814127604167, 0.7728)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = LSTMClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=0.001)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sequências compactadas\n",
"\n",
"No nosso exemplo, tivemos que preencher todas as sequências no minibatch com vetores de zeros. Embora isso resulte em algum desperdício de memória, com RNNs é ainda mais crítico o fato de que células adicionais da RNN são criadas para os itens de entrada preenchidos, que participam do treinamento, mas não carregam nenhuma informação de entrada relevante. Seria muito melhor treinar a RNN apenas com o tamanho real da sequência.\n",
"\n",
"Para isso, um formato especial de armazenamento de sequências preenchidas foi introduzido no PyTorch. Suponha que temos um minibatch preenchido de entrada que se parece com isto:\n",
"```\n",
"[[1,2,3,4,5],\n",
" [6,7,8,0,0],\n",
" [9,0,0,0,0]]\n",
"```\n",
"Aqui, 0 representa os valores preenchidos, e o vetor de comprimento real das sequências de entrada é `[5,3,1]`.\n",
"\n",
"Para treinar efetivamente a RNN com sequências preenchidas, queremos começar o treinamento do primeiro grupo de células da RNN com um minibatch grande (`[1,6,9]`), mas depois encerrar o processamento da terceira sequência e continuar o treinamento com minibatches menores (`[2,7]`, `[3,8]`), e assim por diante. Assim, a sequência compactada é representada como um único vetor - no nosso caso `[1,6,9,2,7,3,8,4,5]`, e um vetor de comprimento (`[5,3,1]`), a partir do qual podemos facilmente reconstruir o minibatch preenchido original.\n",
"\n",
"Para produzir uma sequência compactada, podemos usar a função `torch.nn.utils.rnn.pack_padded_sequence`. Todas as camadas recorrentes, incluindo RNN, LSTM e GRU, suportam sequências compactadas como entrada e produzem uma saída compactada, que pode ser decodificada usando `torch.nn.utils.rnn.pad_packed_sequence`.\n",
"\n",
"Para ser capaz de produzir uma sequência compactada, precisamos passar o vetor de comprimento para a rede, e, portanto, precisamos de uma função diferente para preparar os minibatches:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def pad_length(b):\n",
" # build vectorized sequence\n",
" v = [encode(x[1]) for x in b]\n",
" # compute max length of a sequence in this minibatch and length sequence itself\n",
" len_seq = list(map(len,v))\n",
" l = max(len_seq)\n",
" return ( # tuple of three tensors - labels, padded features, length sequence\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v]),\n",
" torch.tensor(len_seq)\n",
" )\n",
"\n",
"train_loader_len = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=pad_length, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A rede real seria muito semelhante ao `LSTMClassifier` acima, mas a passagem `forward` receberá tanto o minibatch preenchido quanto o vetor de comprimentos das sequências. Após calcular o embedding, computamos a sequência empacotada, passamos para a camada LSTM e, em seguida, desempacotamos o resultado de volta.\n",
"\n",
"> **Nota**: Na verdade, não usamos o resultado desempacotado `x`, porque utilizamos a saída das camadas ocultas nos cálculos seguintes. Assim, podemos remover o desempacotamento completamente deste código. A razão pela qual o colocamos aqui é para que você possa modificar este código facilmente, caso precise usar a saída da rede em cálculos futuros.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"class LSTMPackClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n",
" self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x, lengths):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" pad_x = torch.nn.utils.rnn.pack_padded_sequence(x,lengths,batch_first=True,enforce_sorted=False)\n",
" pad_x,(h,c) = self.rnn(pad_x)\n",
" x, _ = torch.nn.utils.rnn.pad_packed_sequence(pad_x,batch_first=True)\n",
" return self.fc(h[-1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.285625\n",
"6400: acc=0.33359375\n",
"9600: acc=0.3876041666666667\n",
"12800: acc=0.44078125\n",
"16000: acc=0.4825\n",
"19200: acc=0.5235416666666667\n",
"22400: acc=0.5559821428571429\n",
"25600: acc=0.58609375\n",
"28800: acc=0.6116666666666667\n",
"32000: acc=0.63340625\n",
"35200: acc=0.6525284090909091\n",
"38400: acc=0.668515625\n",
"41600: acc=0.6822596153846154\n",
"44800: acc=0.6948214285714286\n",
"48000: acc=0.7052708333333333\n",
"51200: acc=0.71521484375\n",
"54400: acc=0.7239889705882353\n",
"57600: acc=0.7315277777777778\n",
"60800: acc=0.7388486842105263\n",
"64000: acc=0.74571875\n",
"67200: acc=0.7518303571428572\n",
"70400: acc=0.7576988636363636\n",
"73600: acc=0.7628940217391305\n",
"76800: acc=0.7681510416666667\n",
"80000: acc=0.7728125\n",
"83200: acc=0.7772235576923077\n",
"86400: acc=0.7815393518518519\n",
"89600: acc=0.7857700892857142\n",
"92800: acc=0.7895043103448276\n",
"96000: acc=0.7930520833333333\n",
"99200: acc=0.7959072580645161\n",
"102400: acc=0.798994140625\n",
"105600: acc=0.802064393939394\n",
"108800: acc=0.8051378676470589\n",
"112000: acc=0.8077857142857143\n",
"115200: acc=0.8104600694444445\n",
"118400: acc=0.8128293918918919\n"
]
},
{
"data": {
"text/plain": [
"(0.029785829671223958, 0.8138166666666666)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = LSTMPackClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch_emb(net,train_loader_len, lr=0.001,use_pack_sequence=True)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota:** Você pode ter notado o parâmetro `use_pack_sequence` que passamos para a função de treinamento. Atualmente, a função `pack_padded_sequence` exige que o tensor de sequência de comprimento esteja no dispositivo CPU e, portanto, a função de treinamento precisa evitar mover os dados de sequência de comprimento para a GPU durante o treinamento. Você pode verificar a implementação da função `train_emb` no arquivo [`torchnlp.py`](../../../../../lessons/5-NLP/16-RNN/torchnlp.py).\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs Bidirecionais e Multicamadas\n",
"\n",
"Nos nossos exemplos, todas as redes recorrentes operaram em uma direção, do início de uma sequência até o fim. Isso parece natural, pois se assemelha à forma como lemos e ouvimos fala. No entanto, como em muitos casos práticos temos acesso aleatório à sequência de entrada, pode fazer sentido executar o cálculo recorrente em ambas as direções. Essas redes são chamadas de **RNNs bidirecionais**, e podem ser criadas passando o parâmetro `bidirectional=True` para o construtor de RNN/LSTM/GRU.\n",
"\n",
"Ao lidar com redes bidirecionais, precisaríamos de dois vetores de estado oculto, um para cada direção. O PyTorch codifica esses vetores como um único vetor de tamanho duas vezes maior, o que é bastante conveniente, pois normalmente você passaria o estado oculto resultante para uma camada linear totalmente conectada, e só precisaria levar esse aumento de tamanho em consideração ao criar a camada.\n",
"\n",
"Uma rede recorrente, seja unidirecional ou bidirecional, captura certos padrões dentro de uma sequência e pode armazená-los no vetor de estado ou passá-los para a saída. Assim como nas redes convolucionais, podemos construir outra camada recorrente sobre a primeira para capturar padrões de nível mais alto, construídos a partir de padrões de baixo nível extraídos pela primeira camada. Isso nos leva à noção de **RNN multicamada**, que consiste em duas ou mais redes recorrentes, onde a saída da camada anterior é passada para a próxima camada como entrada.\n",
"\n",
"![Imagem mostrando uma RNN LSTM multicamada](../../../../../translated_images/pt-BR/multi-layer-lstm.dd975e29bb2a59fe.webp)\n",
"\n",
"*Imagem retirada [deste post maravilhoso](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) por Fernando López*\n",
"\n",
"O PyTorch torna a construção dessas redes uma tarefa fácil, pois você só precisa passar o parâmetro `num_layers` para o construtor de RNN/LSTM/GRU para construir várias camadas de recorrência automaticamente. Isso também significa que o tamanho do vetor de estado oculto aumentará proporcionalmente, e você precisará levar isso em consideração ao lidar com a saída das camadas recorrentes.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs para outras tarefas\n",
"\n",
"Nesta unidade, vimos que RNNs podem ser usadas para classificação de sequências, mas, na verdade, elas podem lidar com muitas outras tarefas, como geração de texto, tradução automática e mais. Vamos abordar essas tarefas na próxima unidade.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "522ee52ae3d5ae933e283286254e9a55",
"translation_date": "2025-08-28T14:23:01+00:00",
"source_file": "lessons/5-NLP/16-RNN/RNNPyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,460 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Redes neurais recorrentes\n",
"\n",
"No módulo anterior, abordamos representações semânticas ricas de texto. A arquitetura que temos usado captura o significado agregado das palavras em uma sentença, mas não leva em conta a **ordem** das palavras, porque a operação de agregação que segue as embeddings remove essa informação do texto original. Como esses modelos não conseguem representar a ordem das palavras, eles não podem resolver tarefas mais complexas ou ambíguas, como geração de texto ou resposta a perguntas.\n",
"\n",
"Para capturar o significado de uma sequência de texto, usaremos uma arquitetura de rede neural chamada **rede neural recorrente**, ou RNN. Ao usar uma RNN, passamos nossa sentença pela rede um token de cada vez, e a rede produz algum **estado**, que então passamos novamente para a rede junto com o próximo token.\n",
"\n",
"![Imagem mostrando um exemplo de geração de rede neural recorrente.](../../../../../translated_images/pt-BR/rnn.27f5c29c53d727b5.webp)\n",
"\n",
"Dada a sequência de entrada de tokens $X_0,\\dots,X_n$, a RNN cria uma sequência de blocos de rede neural e treina essa sequência de ponta a ponta usando retropropagação. Cada bloco de rede recebe um par $(X_i,S_i)$ como entrada e produz $S_{i+1}$ como resultado. O estado final $S_n$ ou a saída $Y_n$ é enviado para um classificador linear para produzir o resultado. Todos os blocos de rede compartilham os mesmos pesos e são treinados de ponta a ponta usando uma única passagem de retropropagação.\n",
"\n",
"> A figura acima mostra a rede neural recorrente na forma expandida (à esquerda) e em uma representação recorrente mais compacta (à direita). É importante perceber que todas as células RNN têm os mesmos **pesos compartilháveis**.\n",
"\n",
"Como os vetores de estado $S_0,\\dots,S_n$ são passados pela rede, a RNN é capaz de aprender dependências sequenciais entre palavras. Por exemplo, quando a palavra *não* aparece em algum lugar da sequência, ela pode aprender a negar certos elementos dentro do vetor de estado.\n",
"\n",
"Internamente, cada célula RNN contém duas matrizes de peso: $W_H$ e $W_I$, e um viés $b$. Em cada etapa da RNN, dado o input $X_i$ e o estado de entrada $S_i$, o estado de saída é calculado como $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$, onde $f$ é uma função de ativação (frequentemente $\\tanh$).\n",
"\n",
"> Para problemas como geração de texto (que abordaremos na próxima unidade) ou tradução automática, também queremos obter algum valor de saída em cada etapa da RNN. Nesse caso, há também outra matriz $W_O$, e a saída é calculada como $Y_i=f(W_O\\times S_i+b_O)$.\n",
"\n",
"Vamos ver como redes neurais recorrentes podem nos ajudar a classificar nosso conjunto de dados de notícias.\n",
"\n",
"> Para o ambiente de sandbox, precisamos executar a célula a seguir para garantir que a biblioteca necessária esteja instalada e os dados sejam pré-carregados. Se você estiver executando localmente, pode ignorar a célula a seguir.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0\n",
"!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"# We are going to be training pretty large models. In order not to face errors, we need\n",
"# to set tensorflow option to grow GPU memory allocation when required\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"Ao treinar modelos grandes, a alocação de memória da GPU pode se tornar um problema. Também pode ser necessário experimentar diferentes tamanhos de minibatch, para que os dados caibam na memória da GPU e o treinamento seja rápido o suficiente. Se você estiver executando este código em sua própria máquina com GPU, pode experimentar ajustar o tamanho do minibatch para acelerar o treinamento.\n",
"\n",
"> **Note**: Certas versões de drivers da NVidia são conhecidas por não liberar a memória após o treinamento do modelo. Estamos executando vários exemplos neste notebook, e isso pode causar o esgotamento da memória em algumas configurações, especialmente se você estiver realizando seus próprios experimentos como parte do mesmo notebook. Se você encontrar erros estranhos ao iniciar o treinamento do modelo, pode ser necessário reiniciar o kernel do notebook.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": false,
"source_hidden": false
},
"nteract": {
"transient": {
"deleting": false
}
}
},
"outputs": [],
"source": [
"batch_size = 16\n",
"embed_size = 64"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Classificador RNN simples\n",
"\n",
"No caso de uma RNN simples, cada unidade recorrente é uma rede linear simples, que recebe um vetor de entrada e um vetor de estado, e produz um novo vetor de estado. No Keras, isso pode ser representado pela camada `SimpleRNN`.\n",
"\n",
"Embora possamos passar tokens codificados em one-hot diretamente para a camada RNN, isso não é uma boa ideia devido à sua alta dimensionalidade. Por isso, utilizaremos uma camada de embedding para reduzir a dimensionalidade dos vetores de palavras, seguida por uma camada RNN e, por fim, um classificador `Dense`.\n",
"\n",
"> **Note**: Em casos onde a dimensionalidade não é tão alta, por exemplo, ao usar tokenização a nível de caracteres, pode fazer sentido passar tokens codificados em one-hot diretamente para a célula RNN.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, None) 0 \n",
"_________________________________________________________________\n",
"embedding (Embedding) (None, None, 64) 1280000 \n",
"_________________________________________________________________\n",
"simple_rnn (SimpleRNN) (None, 16) 1296 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, 4) 68 \n",
"=================================================================\n",
"Total params: 1,281,364\n",
"Trainable params: 1,281,364\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 20000\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(\n",
" max_tokens=vocab_size,\n",
" input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota:** Aqui usamos uma camada de embedding não treinada para simplificar, mas para obter melhores resultados, podemos usar uma camada de embedding pré-treinada com Word2Vec, como descrito na unidade anterior. Seria um bom exercício para você adaptar este código para funcionar com embeddings pré-treinados.\n",
"\n",
"Agora vamos treinar nossa RNN. RNNs, em geral, são bastante difíceis de treinar, porque, uma vez que as células da RNN são desenroladas ao longo do comprimento da sequência, o número resultante de camadas envolvidas na retropropagação é bastante grande. Por isso, precisamos selecionar uma taxa de aprendizado menor e treinar a rede em um conjunto de dados maior para obter bons resultados. Isso pode levar bastante tempo, então é preferível usar uma GPU.\n",
"\n",
"Para acelerar o processo, treinaremos o modelo RNN apenas nos títulos das notícias, omitindo a descrição. Você pode tentar treinar com a descrição e ver se consegue fazer o modelo treinar.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n"
]
}
],
"source": [
"def extract_title(x):\n",
" return x['title']\n",
"\n",
"def tupelize_title(x):\n",
" return (extract_title(x),x['label'])\n",
"\n",
"print('Training vectorizer')\n",
"vectorizer.adapt(ds_train.take(2000).map(extract_title))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 82s 11ms/step - loss: 0.6629 - acc: 0.7623 - val_loss: 0.5559 - val_acc: 0.7995\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3e0030d350>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **Nota** que a precisão provavelmente será menor aqui, porque estamos treinando apenas em títulos de notícias.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Revisitando sequências de variáveis\n",
"\n",
"Lembre-se de que a camada `TextVectorization` irá automaticamente preencher sequências de comprimento variável em um minibatch com tokens de preenchimento (pad tokens). Acontece que esses tokens também participam do treinamento, e isso pode complicar a convergência do modelo.\n",
"\n",
"Existem várias abordagens que podemos adotar para minimizar a quantidade de preenchimento. Uma delas é reordenar o conjunto de dados pelo comprimento das sequências e agrupar todas as sequências por tamanho. Isso pode ser feito usando a função `tf.data.experimental.bucket_by_sequence_length` (veja a [documentação](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length)).\n",
"\n",
"Outra abordagem é usar **masking**. No Keras, algumas camadas suportam entradas adicionais que indicam quais tokens devem ser considerados durante o treinamento. Para incorporar masking em nosso modelo, podemos incluir uma camada `Masking` separada ([documentação](https://keras.io/api/layers/core_layers/masking/)) ou especificar o parâmetro `mask_zero=True` na nossa camada `Embedding`.\n",
"\n",
"> **Note**: Este treinamento levará cerca de 5 minutos para completar uma época em todo o conjunto de dados. Sinta-se à vontade para interromper o treinamento a qualquer momento se perder a paciência. Outra opção é limitar a quantidade de dados usados para o treinamento, adicionando a cláusula `.take(...)` após os conjuntos de dados `ds_train` e `ds_test`.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 371s 49ms/step - loss: 0.5401 - acc: 0.8079 - val_loss: 0.3780 - val_acc: 0.8822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3dec118850>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora que estamos utilizando mascaramento, podemos treinar o modelo em todo o conjunto de dados de títulos e descrições.\n",
"\n",
"> **Note**: Você percebeu que estamos usando um vetorizador treinado nos títulos das notícias, e não no corpo completo do artigo? Isso pode fazer com que alguns tokens sejam ignorados, então é melhor re-treinar o vetorizador. No entanto, isso provavelmente terá um efeito muito pequeno, então vamos continuar utilizando o vetorizador pré-treinado anterior para manter a simplicidade.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## LSTM: Memória de longo e curto prazo\n",
"\n",
"Um dos principais problemas das RNNs é o **desvanecimento de gradientes**. As RNNs podem ser bastante longas e podem ter dificuldade em propagar os gradientes até a primeira camada da rede durante a retropropagação. Quando isso acontece, a rede não consegue aprender relações entre tokens distantes. Uma maneira de evitar esse problema é introduzir **gerenciamento explícito de estado** usando **portas**. As duas arquiteturas mais comuns que introduzem portas são **memória de longo e curto prazo** (LSTM) e **unidade de retransmissão com portas** (GRU). Vamos abordar as LSTMs aqui.\n",
"\n",
"![Imagem mostrando um exemplo de célula de memória de longo e curto prazo](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"Uma rede LSTM é organizada de maneira semelhante a uma RNN, mas há dois estados que são passados de camada para camada: o estado real $c$ e o vetor oculto $h$. Em cada unidade, o vetor oculto $h_{t-1}$ é combinado com a entrada $x_t$, e juntos eles controlam o que acontece com o estado $c_t$ e a saída $h_{t}$ por meio de **portas**. Cada porta tem ativação sigmoide (saída no intervalo $[0,1]$), que pode ser vista como uma máscara binária quando multiplicada pelo vetor de estado. As LSTMs possuem as seguintes portas (da esquerda para a direita na imagem acima):\n",
"* **porta de esquecimento**, que determina quais componentes do vetor $c_{t-1}$ precisamos esquecer e quais passar adiante.\n",
"* **porta de entrada**, que determina quanta informação do vetor de entrada e do vetor oculto anterior deve ser incorporada ao vetor de estado.\n",
"* **porta de saída**, que pega o novo vetor de estado e decide quais de seus componentes serão usados para produzir o novo vetor oculto $h_t$.\n",
"\n",
"Os componentes do estado $c$ podem ser vistos como indicadores que podem ser ativados ou desativados. Por exemplo, quando encontramos o nome *Alice* na sequência, deduzimos que se refere a uma mulher e ativamos o indicador no estado que diz que temos um substantivo feminino na frase. Quando encontramos posteriormente as palavras *e Tom*, ativamos o indicador que diz que temos um substantivo no plural. Assim, manipulando o estado, podemos acompanhar as propriedades gramaticais da frase.\n",
"\n",
"> **Note**: Aqui está um ótimo recurso para entender os detalhes internos das LSTMs: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) por Christopher Olah.\n",
"\n",
"Embora a estrutura interna de uma célula LSTM possa parecer complexa, o Keras oculta essa implementação dentro da camada `LSTM`, então a única coisa que precisamos fazer no exemplo acima é substituir a camada recorrente:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15000/15000 [==============================] - 188s 13ms/step - loss: 0.5692 - acc: 0.7916 - val_loss: 0.3441 - val_acc: 0.8870\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3d6af5c350>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.LSTM(8),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs Bidirecionais e Multicamadas\n",
"\n",
"Nos nossos exemplos até agora, as redes recorrentes operam do início de uma sequência até o final. Isso nos parece natural porque segue a mesma direção em que lemos ou ouvimos uma fala. No entanto, para cenários que exigem acesso aleatório à sequência de entrada, faz mais sentido executar o cálculo recorrente em ambas as direções. RNNs que permitem cálculos em ambas as direções são chamadas de **RNNs bidirecionais**, e podem ser criadas envolvendo a camada recorrente com uma camada especial chamada `Bidirectional`.\n",
"\n",
"> **Note**: A camada `Bidirectional` faz duas cópias da camada dentro dela e define a propriedade `go_backwards` de uma dessas cópias como `True`, fazendo com que ela percorra a sequência na direção oposta.\n",
"\n",
"Redes recorrentes, sejam unidirecionais ou bidirecionais, capturam padrões dentro de uma sequência e os armazenam em vetores de estado ou os retornam como saída. Assim como nas redes convolucionais, podemos construir outra camada recorrente após a primeira para capturar padrões de nível mais alto, construídos a partir de padrões de nível mais baixo extraídos pela primeira camada. Isso nos leva à noção de uma **RNN multicamada**, que consiste em duas ou mais redes recorrentes, onde a saída da camada anterior é passada para a próxima camada como entrada.\n",
"\n",
"![Imagem mostrando uma RNN multicamada de memória de longo e curto prazo](../../../../../translated_images/pt-BR/multi-layer-lstm.dd975e29bb2a59fe.webp)\n",
"\n",
"*Imagem retirada [deste post incrível](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) por Fernando López.*\n",
"\n",
"O Keras torna a construção dessas redes uma tarefa fácil, porque você só precisa adicionar mais camadas recorrentes ao modelo. Para todas as camadas, exceto a última, precisamos especificar o parâmetro `return_sequences=True`, porque precisamos que a camada retorne todos os estados intermediários, e não apenas o estado final do cálculo recorrente.\n",
"\n",
"Vamos construir uma LSTM bidirecional de duas camadas para o nosso problema de classificação.\n",
"\n",
"> **Note** este código novamente leva bastante tempo para ser executado, mas nos dá a maior precisão que vimos até agora. Então talvez valha a pena esperar e ver o resultado.\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5044/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r5045/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706"
]
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, 128, mask_zero=True),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64)), \n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs para outras tarefas\n",
"\n",
"Até agora, nos concentramos em usar RNNs para classificar sequências de texto. Mas elas podem lidar com muitas outras tarefas, como geração de texto e tradução automática — abordaremos essas tarefas na próxima unidade.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "conda-env-py37_tensorflow-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "81351e61f619b432ff51010a4f993194",
"translation_date": "2025-08-28T14:20:08+00:00",
"source_file": "lessons/5-NLP/16-RNN/RNNTF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,6 @@
# Tarefa: Notebooks
Usando os notebooks associados a esta lição (seja a versão do PyTorch ou do TensorFlow), execute-os novamente utilizando seu próprio conjunto de dados, talvez um do Kaggle, usado com a devida atribuição. Reescreva o notebook para destacar suas próprias descobertas. Experimente um tipo diferente de conjunto de dados e documente suas conclusões, usando textos como [este conjunto de dados de competição do Kaggle sobre tweets de clima](https://www.kaggle.com/competitions/crowdflower-weather-twitter/data?select=train.csv).
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,414 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Redes Generativas\n",
"\n",
"Redes Neurais Recorrentes (RNNs) e suas variantes com células controladas, como Células de Memória de Longo Prazo (LSTMs) e Unidades Recorrentes Controladas (GRUs), fornecem um mecanismo para modelagem de linguagem, ou seja, elas podem aprender a ordem das palavras e fornecer previsões para a próxima palavra em uma sequência. Isso nos permite usar RNNs para **tarefas generativas**, como geração de texto comum, tradução automática e até mesmo legendagem de imagens.\n",
"\n",
"Na arquitetura de RNN que discutimos na unidade anterior, cada unidade RNN produzia o próximo estado oculto como saída. No entanto, também podemos adicionar outra saída a cada unidade recorrente, o que nos permitiria gerar uma **sequência** (que tem o mesmo comprimento da sequência original). Além disso, podemos usar unidades RNN que não aceitam uma entrada em cada etapa, mas apenas recebem um vetor de estado inicial e, em seguida, produzem uma sequência de saídas.\n",
"\n",
"Neste notebook, vamos nos concentrar em modelos generativos simples que nos ajudam a gerar texto. Para simplificar, vamos construir uma **rede em nível de caracteres**, que gera texto letra por letra. Durante o treinamento, precisamos pegar algum corpus de texto e dividi-lo em sequências de letras.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"import numpy as np\n",
"from torchnlp import *\n",
"train_dataset,test_dataset,classes,vocab = load_dataset()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construindo vocabulário de caracteres\n",
"\n",
"Para construir uma rede generativa em nível de caracteres, precisamos dividir o texto em caracteres individuais em vez de palavras. Isso pode ser feito definindo um tokenizador diferente:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary size = 82\n",
"Encoding of 'a' is 1\n",
"Character with code 13 is c\n"
]
}
],
"source": [
"def char_tokenizer(words):\n",
" return list(words) #[word for word in words]\n",
"\n",
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" counter.update(char_tokenizer(line))\n",
"vocab = torchtext.vocab.vocab(counter)\n",
"\n",
"vocab_size = len(vocab)\n",
"print(f\"Vocabulary size = {vocab_size}\")\n",
"print(f\"Encoding of 'a' is {vocab.get_stoi()['a']}\")\n",
"print(f\"Character with code 13 is {vocab.get_itos()[13]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos ver o exemplo de como podemos codificar o texto do nosso conjunto de dados:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([ 0, 1, 2, 2, 3, 4, 5, 6, 3, 7, 8, 1, 9, 10, 3, 11, 2, 1,\n",
" 12, 3, 7, 1, 13, 14, 3, 15, 16, 5, 17, 3, 5, 18, 8, 3, 7, 2,\n",
" 1, 13, 14, 3, 19, 20, 8, 21, 5, 8, 9, 10, 22, 3, 20, 8, 21, 5,\n",
" 8, 9, 10, 3, 23, 3, 4, 18, 17, 9, 5, 23, 10, 8, 2, 2, 8, 9,\n",
" 10, 24, 3, 0, 1, 2, 2, 3, 4, 5, 9, 8, 8, 5, 25, 10, 3, 26,\n",
" 12, 27, 16, 26, 2, 27, 16, 28, 29, 30, 1, 16, 26, 3, 17, 31, 3, 21,\n",
" 2, 5, 9, 1, 23, 13, 32, 16, 27, 13, 10, 24, 3, 1, 9, 8, 3, 10,\n",
" 8, 8, 27, 16, 28, 3, 28, 9, 8, 8, 16, 3, 1, 28, 1, 27, 16, 6])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def enc(x):\n",
" return torch.LongTensor(encode(x,voc=vocab,tokenizer=char_tokenizer))\n",
"\n",
"enc(train_dataset[0][1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treinando uma RNN generativa\n",
"\n",
"A maneira como treinaremos a RNN para gerar texto é a seguinte. A cada etapa, pegaremos uma sequência de caracteres de comprimento `nchars` e pediremos à rede que gere o próximo caractere de saída para cada caractere de entrada:\n",
"\n",
"![Imagem mostrando um exemplo de geração de RNN com a palavra 'HELLO'.](../../../../../translated_images/pt-BR/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"Dependendo do cenário real, também podemos querer incluir alguns caracteres especiais, como *fim de sequência* `<eos>`. No nosso caso, queremos apenas treinar a rede para geração contínua de texto, então fixaremos o tamanho de cada sequência para ser igual a `nchars` tokens. Consequentemente, cada exemplo de treinamento consistirá em `nchars` entradas e `nchars` saídas (que são a sequência de entrada deslocada um símbolo para a esquerda). O minibatch consistirá de várias dessas sequências.\n",
"\n",
"A maneira como geraremos os minibatches será pegar cada texto de notícias de comprimento `l` e gerar todas as combinações possíveis de entrada-saída a partir dele (haverá `l-nchars` dessas combinações). Elas formarão um minibatch, e o tamanho dos minibatches será diferente em cada etapa de treinamento.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[ 0, 1, 2, ..., 28, 29, 30],\n",
" [ 1, 2, 2, ..., 29, 30, 1],\n",
" [ 2, 2, 3, ..., 30, 1, 16],\n",
" ...,\n",
" [20, 8, 21, ..., 1, 28, 1],\n",
" [ 8, 21, 5, ..., 28, 1, 27],\n",
" [21, 5, 8, ..., 1, 27, 16]]),\n",
" tensor([[ 1, 2, 2, ..., 29, 30, 1],\n",
" [ 2, 2, 3, ..., 30, 1, 16],\n",
" [ 2, 3, 4, ..., 1, 16, 26],\n",
" ...,\n",
" [ 8, 21, 5, ..., 28, 1, 27],\n",
" [21, 5, 8, ..., 1, 27, 16],\n",
" [ 5, 8, 9, ..., 27, 16, 6]]))"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nchars = 100\n",
"\n",
"def get_batch(s,nchars=nchars):\n",
" ins = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
" outs = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
" for i in range(len(s)-nchars):\n",
" ins[i] = enc(s[i:i+nchars])\n",
" outs[i] = enc(s[i+1:i+nchars+1])\n",
" return ins,outs\n",
"\n",
"get_batch(train_dataset[0][1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos definir a rede geradora. Ela pode ser baseada em qualquer célula recorrente que discutimos na unidade anterior (simples, LSTM ou GRU). Em nosso exemplo, usaremos LSTM.\n",
"\n",
"Como a rede recebe caracteres como entrada e o tamanho do vocabulário é relativamente pequeno, não precisamos de uma camada de embedding; a entrada codificada em one-hot pode ser passada diretamente para a célula LSTM. No entanto, como passamos números que representam os caracteres como entrada, precisamos codificá-los em one-hot antes de enviá-los para a LSTM. Isso é feito chamando a função `one_hot` durante a passagem `forward`. O codificador de saída será uma camada linear que converterá o estado oculto em uma saída codificada em one-hot.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class LSTMGenerator(torch.nn.Module):\n",
" def __init__(self, vocab_size, hidden_dim):\n",
" super().__init__()\n",
" self.rnn = torch.nn.LSTM(vocab_size,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, vocab_size)\n",
"\n",
" def forward(self, x, s=None):\n",
" x = torch.nn.functional.one_hot(x,vocab_size).to(torch.float32)\n",
" x,s = self.rnn(x,s)\n",
" return self.fc(x),s"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Durante o treinamento, queremos ser capazes de amostrar texto gerado. Para isso, definiremos a função `generate`, que produzirá uma string de saída com comprimento `size`, começando a partir da string inicial `start`.\n",
"\n",
"O funcionamento é o seguinte. Primeiro, passaremos a string completa `start` pela rede, obtendo o estado de saída `s` e o próximo caractere previsto `out`. Como `out` está codificado em one-hot, usamos `argmax` para obter o índice do caractere `nc` no vocabulário e utilizamos `itos` para identificar o caractere real, adicionando-o à lista resultante de caracteres `chars`. Esse processo de gerar um caractere é repetido `size` vezes para gerar o número necessário de caracteres.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def generate(net,size=100,start='today '):\n",
" chars = list(start)\n",
" out, s = net(enc(chars).view(1,-1).to(device))\n",
" for i in range(size):\n",
" nc = torch.argmax(out[0][-1])\n",
" chars.append(vocab.get_itos()[nc])\n",
" out, s = net(nc.view(1,-1),s)\n",
" return ''.join(chars)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos começar o treinamento! O loop de treinamento é quase o mesmo de todos os nossos exemplos anteriores, mas, em vez de exibir a acurácia, imprimimos um texto gerado amostrado a cada 1000 épocas.\n",
"\n",
"É necessário prestar atenção especial à forma como calculamos a perda. Precisamos calcular a perda com base na saída codificada em one-hot `out` e no texto esperado `text_out`, que é a lista de índices de caracteres. Felizmente, a função `cross_entropy` espera como primeiro argumento a saída não normalizada da rede e, como segundo, o número da classe, que é exatamente o que temos. Ela também realiza automaticamente a média com base no tamanho do minibatch.\n",
"\n",
"Também limitamos o treinamento a `samples_to_train` amostras, para não esperar por muito tempo. Incentivamos você a experimentar e tentar um treinamento mais longo, possivelmente por várias épocas (nesse caso, seria necessário criar outro loop em torno deste código).\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Current loss = 4.398899078369141\n",
"today sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr s\n",
"Current loss = 2.161320447921753\n",
"today and to the tor to to the tor to to the tor to to the tor to to the tor to to the tor to to the tor t\n",
"Current loss = 1.6722588539123535\n",
"today and the court to the could to the could to the could to the could to the could to the could to the c\n",
"Current loss = 2.423795223236084\n",
"today and a second to the conternation of the conternation of the conternation of the conternation of the \n",
"Current loss = 1.702607274055481\n",
"today and the company to the company to the company to the company to the company to the company to the co\n",
"Current loss = 1.692358136177063\n",
"today and the company to the company to the company to the company to the company to the company to the co\n",
"Current loss = 1.9722288846969604\n",
"today and the control the control the control the control the control the control the control the control \n",
"Current loss = 1.8705692291259766\n",
"today and the second to the second to the second to the second to the second to the second to the second t\n",
"Current loss = 1.7626899480819702\n",
"today and a security and a security and a security and a security and a security and a security and a secu\n",
"Current loss = 1.5574463605880737\n",
"today and the company and the company and the company and the company and the company and the company and \n",
"Current loss = 1.5620026588439941\n",
"today and the be that the be the be that the be the be that the be the be that the be the be that the be t\n"
]
}
],
"source": [
"net = LSTMGenerator(vocab_size,64).to(device)\n",
"\n",
"samples_to_train = 10000\n",
"optimizer = torch.optim.Adam(net.parameters(),0.01)\n",
"loss_fn = torch.nn.CrossEntropyLoss()\n",
"net.train()\n",
"for i,x in enumerate(train_dataset):\n",
" # x[0] is class label, x[1] is text\n",
" if len(x[1])-nchars<10:\n",
" continue\n",
" samples_to_train-=1\n",
" if not samples_to_train: break\n",
" text_in, text_out = get_batch(x[1])\n",
" optimizer.zero_grad()\n",
" out,s = net(text_in)\n",
" loss = torch.nn.functional.cross_entropy(out.view(-1,vocab_size),text_out.flatten()) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" if i%1000==0:\n",
" print(f\"Current loss = {loss.item()}\")\n",
" print(generate(net))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Este exemplo já gera um texto bastante bom, mas pode ser melhorado de várias maneiras:\n",
"\n",
"* **Melhor geração de minibatches**. A forma como preparamos os dados para treinamento foi gerar um minibatch a partir de uma única amostra. Isso não é ideal, porque os minibatches têm tamanhos diferentes, e alguns deles nem podem ser gerados, porque o texto é menor que `nchars`. Além disso, minibatches pequenos não utilizam suficientemente a GPU. Seria mais inteligente obter um grande bloco de texto de todas as amostras, depois gerar todos os pares de entrada-saída, embaralhá-los e criar minibatches de tamanho igual.\n",
"\n",
"* **LSTM com múltiplas camadas**. Faz sentido tentar usar 2 ou 3 camadas de células LSTM. Como mencionamos na unidade anterior, cada camada de LSTM extrai certos padrões do texto, e no caso de um gerador em nível de caracteres, podemos esperar que os níveis mais baixos de LSTM sejam responsáveis por extrair sílabas, enquanto os níveis mais altos lidam com palavras e combinações de palavras. Isso pode ser implementado facilmente passando o parâmetro de número de camadas para o construtor do LSTM.\n",
"\n",
"* Você também pode querer experimentar com **unidades GRU** e ver quais apresentam melhor desempenho, além de testar **diferentes tamanhos de camadas ocultas**. Camadas ocultas muito grandes podem resultar em overfitting (por exemplo, a rede aprenderá o texto exato), enquanto tamanhos menores podem não produzir bons resultados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Geração de texto suave e temperatura\n",
"\n",
"Na definição anterior de `generate`, sempre escolhemos o caractere com a maior probabilidade como o próximo caractere no texto gerado. Isso resultava no fato de que o texto frequentemente \"ciclava\" entre as mesmas sequências de caracteres repetidamente, como neste exemplo:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"No entanto, se analisarmos a distribuição de probabilidade para o próximo caractere, pode ser que a diferença entre algumas das maiores probabilidades não seja tão grande. Por exemplo, um caractere pode ter probabilidade de 0,2, enquanto outro tem 0,19, etc. Por exemplo, ao procurar o próximo caractere na sequência '*play*', o próximo caractere pode ser tanto um espaço quanto **e** (como na palavra *player*).\n",
"\n",
"Isso nos leva à conclusão de que não é sempre \"justo\" selecionar o caractere com maior probabilidade, pois escolher o segundo mais provável ainda pode nos levar a um texto significativo. É mais sensato **amostrar** caracteres a partir da distribuição de probabilidade fornecida pela saída da rede.\n",
"\n",
"Essa amostragem pode ser feita usando a função `multinomial`, que implementa a chamada **distribuição multinomial**. Uma função que implementa essa geração de texto **suave** está definida abaixo:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--- Temperature = 0.3\n",
"Today and a company and complete an all the land the restrational the as a security and has provers the pay to and a report and the computer in the stand has filities and working the law the stations for a company and with the company and the final the first company and refight of the state and and workin\n",
"\n",
"--- Temperature = 0.8\n",
"Today he oniis its first to Aus bomblaties the marmation a to manan boogot that pirate assaid a relaid their that goverfin the the Cappets Ecrotional Assonia Cition targets it annight the w scyments Blamity #39;s TVeer Diercheg Reserals fran envyuil that of ster said access what succers of Dour-provelith\n",
"\n",
"--- Temperature = 1.0\n",
"Today holy they a 11 will meda a toket subsuaties, engins for Chanos, they's has stainger past to opening orital his thempting new Nattona was al innerforder advan-than #36;s night year his religuled talitatian what the but with Wednesday to Justment will wemen of Mark CCC Camp as Timed Nae wome a leaders\n",
"\n",
"--- Temperature = 1.3\n",
"Today gpone 2.5 fech atcusion poor cocles toparsdorM.cht Line Pamage put 43 his calt lowed to the book, that has authh-the silia rruch ailing to'ory andhes beutirsimi- Aefffive heading offil an auf eacklets is charged evis, Gunymy oy) Mony has it after-sloythyor loveId out filme, the Natabl -Najuntaxiggs \n",
"\n",
"--- Temperature = 1.8\n",
"Today plary, P.slan chly\\401 mardregationly #39;t 8.1Mide) closes ,filtcon alfly playin roven!\\grea.-QFBEP: Iss onfarchQ/itilia CCf Zivesigntwasta orce.-Peul-aw.uicrin of fuglinfsut aftaningwo, MIEX awayew Aice Woiduar Corvagiugge oppo esig ThusBratourid canthly-RyI.co lagitems\\eexciaishes.conBabntusmor I\n",
"\n"
]
}
],
"source": [
"def generate_soft(net,size=100,start='today ',temperature=1.0):\n",
" chars = list(start)\n",
" out, s = net(enc(chars).view(1,-1).to(device))\n",
" for i in range(size):\n",
" #nc = torch.argmax(out[0][-1])\n",
" out_dist = out[0][-1].div(temperature).exp()\n",
" nc = torch.multinomial(out_dist,1)[0]\n",
" chars.append(vocab.get_itos()[nc])\n",
" out, s = net(nc.view(1,-1),s)\n",
" return ''.join(chars)\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"--- Temperature = {i}\\n{generate_soft(net,size=300,start='Today ',temperature=i)}\\n\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Introduzimos mais um parâmetro chamado **temperatura**, que é usado para indicar o quão rigidamente devemos nos ater à maior probabilidade. Se a temperatura for 1.0, fazemos uma amostragem multinomial justa, e quando a temperatura vai para o infinito - todas as probabilidades se tornam iguais, e selecionamos o próximo caractere aleatoriamente. No exemplo abaixo, podemos observar que o texto se torna sem sentido quando aumentamos demais a temperatura, e se assemelha a um texto \"ciclado\" gerado rigidamente quando se aproxima de 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "7673cd150d96c74c6d6011460094efb4",
"translation_date": "2025-08-28T14:05:54+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativePyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,495 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Redes Generativas\n",
"\n",
"Redes Neurais Recorrentes (RNNs) e suas variantes com células controladas, como Células de Memória de Longo Prazo (LSTMs) e Unidades Recorrentes Controladas (GRUs), fornecem um mecanismo para modelagem de linguagem, ou seja, elas podem aprender a ordem das palavras e fornecer previsões para a próxima palavra em uma sequência. Isso nos permite usar RNNs para **tarefas generativas**, como geração de texto comum, tradução automática e até mesmo legendagem de imagens.\n",
"\n",
"Na arquitetura de RNN que discutimos na unidade anterior, cada unidade RNN produzia o próximo estado oculto como saída. No entanto, também podemos adicionar outra saída a cada unidade recorrente, o que nos permitiria gerar uma **sequência** (que tem o mesmo comprimento da sequência original). Além disso, podemos usar unidades RNN que não aceitam uma entrada em cada etapa, apenas recebem um vetor de estado inicial e, em seguida, produzem uma sequência de saídas.\n",
"\n",
"Neste notebook, vamos nos concentrar em modelos generativos simples que nos ajudam a gerar texto. Para simplificar, vamos construir uma **rede em nível de caracteres**, que gera texto letra por letra. Durante o treinamento, precisamos pegar algum corpus de texto e dividi-lo em sequências de letras.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construindo um vocabulário de caracteres\n",
"\n",
"Para construir uma rede generativa em nível de caracteres, precisamos dividir o texto em caracteres individuais em vez de palavras. A camada `TextVectorization` que usamos anteriormente não consegue fazer isso, então temos duas opções:\n",
"\n",
"* Carregar o texto manualmente e fazer a tokenização \"manualmente\", como neste [exemplo oficial do Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Usar a classe `Tokenizer` para tokenização em nível de caracteres.\n",
"\n",
"Vamos seguir com a segunda opção. `Tokenizer` também pode ser usado para tokenizar em palavras, então deve ser possível alternar facilmente entre tokenização em nível de caracteres e em nível de palavras.\n",
"\n",
"Para realizar a tokenização em nível de caracteres, precisamos passar o parâmetro `char_level=True`:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Também queremos usar um token especial para denotar **fim da sequência**, que chamaremos de `<eos>`. Vamos adicioná-lo manualmente ao vocabulário:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"eos_token = len(tokenizer.word_index)+1\n",
"tokenizer.word_index['<eos>'] = eos_token\n",
"\n",
"vocab_size = eos_token + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.texts_to_sequences(['Hello, world!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treinando uma RNN generativa para criar títulos\n",
"\n",
"A maneira como treinaremos a RNN para gerar títulos de notícias é a seguinte. A cada etapa, pegaremos um título, que será alimentado em uma RNN, e para cada caractere de entrada pediremos à rede que gere o próximo caractere de saída:\n",
"\n",
"![Imagem mostrando um exemplo de geração de RNN da palavra 'HELLO'.](../../../../../translated_images/pt-BR/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"Para o último caractere da nossa sequência, pediremos à rede que gere o token `<eos>`.\n",
"\n",
"A principal diferença da RNN generativa que estamos usando aqui é que pegaremos a saída de cada etapa da RNN, e não apenas da célula final. Isso pode ser alcançado especificando o parâmetro `return_sequences` na célula da RNN.\n",
"\n",
"Assim, durante o treinamento, a entrada para a rede será uma sequência de caracteres codificados de algum comprimento, e a saída será uma sequência do mesmo comprimento, mas deslocada por um elemento e terminada com `<eos>`. O minibatch consistirá de várias dessas sequências, e precisaremos usar **padding** para alinhar todas as sequências.\n",
"\n",
"Vamos criar funções que transformarão o conjunto de dados para nós. Como queremos preencher as sequências no nível do minibatch, primeiro agruparemos o conjunto de dados chamando `.batch()`, e depois usaremos `map` para realizar a transformação. Portanto, a função de transformação receberá um minibatch inteiro como parâmetro:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def title_batch(x):\n",
" x = [t.numpy().decode('utf-8') for t in x]\n",
" z = tokenizer.texts_to_sequences(x)\n",
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Algumas coisas importantes que fazemos aqui:\n",
"* Primeiro, extraímos o texto real do tensor de string\n",
"* `text_to_sequences` converte a lista de strings em uma lista de tensores inteiros\n",
"* `pad_sequences` ajusta esses tensores ao seu comprimento máximo\n",
"* Por fim, codificamos todos os caracteres em one-hot, além de realizar o deslocamento e adicionar `<eos>`. Em breve veremos por que precisamos de caracteres codificados em one-hot\n",
"\n",
"No entanto, essa função é **Pythonic**, ou seja, ela não pode ser automaticamente traduzida para o grafo computacional do Tensorflow. Receberemos erros se tentarmos usar essa função diretamente na função `Dataset.map`. Precisamos encapsular essa chamada Pythonic usando o wrapper `py_function`:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def title_batch_fn(x):\n",
" x = x['title']\n",
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
" return a,b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Diferenciar entre funções de transformação Pythonic e funções de transformação do Tensorflow pode parecer um pouco complexo demais, e você pode estar se perguntando por que não transformamos o conjunto de dados usando funções padrão do Python antes de passá-lo para `fit`. Embora isso definitivamente possa ser feito, usar `Dataset.map` tem uma grande vantagem, pois o pipeline de transformação de dados é executado usando o grafo computacional do Tensorflow, que aproveita os cálculos na GPU e minimiza a necessidade de transferir dados entre CPU/GPU.\n",
"\n",
"Agora podemos construir nossa rede geradora e começar o treinamento. Ela pode ser baseada em qualquer célula recorrente que discutimos na unidade anterior (simples, LSTM ou GRU). Em nosso exemplo, usaremos LSTM.\n",
"\n",
"Como a rede recebe caracteres como entrada e o tamanho do vocabulário é relativamente pequeno, não precisamos de uma camada de embedding; a entrada codificada em one-hot pode ir diretamente para a célula LSTM. A camada de saída será um classificador `Dense` que converterá a saída do LSTM em números de tokens codificados em one-hot.\n",
"\n",
"Além disso, como estamos lidando com sequências de comprimento variável, podemos usar a camada `Masking` para criar uma máscara que ignorará a parte preenchida da string. Isso não é estritamente necessário, porque não estamos muito interessados em tudo que vai além do token `<eos>`, mas usaremos essa camada para ganhar alguma experiência com esse tipo de camada. O `input_shape` será `(None, vocab_size)`, onde `None` indica a sequência de comprimento variável, e o formato de saída também será `(None, vocab_size)`, como você pode ver no `summary`:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"masking (Masking) (None, None, 84) 0 \n",
"_________________________________________________________________\n",
"lstm (LSTM) (None, None, 128) 109056 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, None, 84) 10836 \n",
"=================================================================\n",
"Total params: 119,892\n",
"Trainable params: 119,892\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
" keras.layers.LSTM(128,return_sequences=True),\n",
" keras.layers.Dense(vocab_size,activation='softmax')\n",
"])\n",
"\n",
"model.summary()\n",
"model.compile(loss='categorical_crossentropy')\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Gerando saída\n",
"\n",
"Agora que treinamos o modelo, queremos usá-lo para gerar alguma saída. Antes de tudo, precisamos de uma maneira de decodificar o texto representado por uma sequência de números de tokens. Para isso, poderíamos usar a função `tokenizer.sequences_to_texts`; no entanto, ela não funciona bem com tokenização em nível de caracteres. Portanto, vamos pegar um dicionário de tokens do tokenizer (chamado `word_index`), construir um mapa reverso e escrever nossa própria função de decodificação:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
"\n",
"def decode(x):\n",
" return ''.join([reverse_map[t] for t in x])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora, vamos realizar a geração. Começaremos com uma string `start`, codificaremos ela em uma sequência `inp`, e então, a cada etapa, chamaremos nossa rede para inferir o próximo caractere.\n",
"\n",
"A saída da rede `out` é um vetor de `vocab_size` elementos que representa as probabilidades de cada token, e podemos encontrar o número do token mais provável usando `argmax`. Em seguida, adicionamos esse caractere à lista de tokens gerados e continuamos com a geração. Esse processo de gerar um caractere é repetido `size` vezes para gerar o número necessário de caracteres, e encerramos antecipadamente quando o `eos_token` é encontrado.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate(model,size=100,start='Today '):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" nc = tf.argmax(out)\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc.numpy())\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
" \n",
"generate(model)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Amostrando saída durante o treinamento\n",
"\n",
"Como não temos métricas úteis como *precisão*, a única maneira de verificar se nosso modelo está melhorando é **amostrando** strings geradas durante o treinamento. Para isso, usaremos **callbacks**, ou seja, funções que podemos passar para a função `fit`, e que serão chamadas periodicamente durante o treinamento.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
"Today #39;s a lead in the company for the strike\n",
"Epoch 2/3\n",
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
"Today #39;s the Market Service on Security Start (AP)\n",
"Epoch 3/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
"Today #39;s a line on the strike to start for the start\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampling_callback = keras.callbacks.LambdaCallback(\n",
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
")\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Este exemplo já gera um texto bastante bom, mas pode ser melhorado de várias maneiras:\n",
"\n",
"* **Mais texto**. Usamos apenas títulos para nossa tarefa, mas você pode querer experimentar com texto completo. Lembre-se de que RNNs não lidam muito bem com sequências longas, então faz sentido dividi-las em frases mais curtas ou sempre treinar com um comprimento de sequência fixo de algum valor predefinido `num_chars` (por exemplo, 256). Você pode tentar modificar o exemplo acima para essa arquitetura, usando o [tutorial oficial do Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/) como inspiração.\n",
"\n",
"* **LSTM com várias camadas**. Faz sentido tentar 2 ou 3 camadas de células LSTM. Como mencionamos na unidade anterior, cada camada de LSTM extrai certos padrões do texto, e no caso de um gerador em nível de caracteres, podemos esperar que o nível mais baixo do LSTM seja responsável por extrair sílabas, e os níveis mais altos - por palavras e combinações de palavras. Isso pode ser implementado simplesmente passando o parâmetro de número de camadas para o construtor do LSTM.\n",
"\n",
"* Você também pode querer experimentar com **unidades GRU** e ver quais apresentam melhor desempenho, além de **diferentes tamanhos de camadas ocultas**. Camadas ocultas muito grandes podem resultar em overfitting (por exemplo, a rede aprenderá o texto exato), e tamanhos menores podem não produzir bons resultados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Geração de texto suave e temperatura\n",
"\n",
"Na definição anterior de `generate`, sempre escolhemos o caractere com a maior probabilidade como o próximo caractere no texto gerado. Isso resultava no fato de que o texto frequentemente \"ciclava\" entre as mesmas sequências de caracteres repetidamente, como neste exemplo:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"No entanto, se analisarmos a distribuição de probabilidade para o próximo caractere, pode ser que a diferença entre algumas das maiores probabilidades não seja tão grande. Por exemplo, um caractere pode ter probabilidade de 0,2, enquanto outro tem 0,19, etc. Por exemplo, ao procurar o próximo caractere na sequência '*play*', o próximo caractere pode ser tanto um espaço quanto **e** (como na palavra *player*).\n",
"\n",
"Isso nos leva à conclusão de que não é sempre \"justo\" selecionar o caractere com maior probabilidade, pois escolher o segundo mais provável ainda pode nos levar a um texto significativo. É mais sensato **amostrar** caracteres a partir da distribuição de probabilidade fornecida pela saída da rede.\n",
"\n",
"Essa amostragem pode ser feita usando a função `np.multinomial`, que implementa a chamada **distribuição multinomial**. Uma função que implementa essa geração de texto **suave** está definida abaixo:\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"--- Temperature = 0.3\n",
"Today #39;s strike #39; to start at the store return\n",
"On Sunday PO to Be Data Profit Up (Reuters)\n",
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
"President olding of the blast start for the strike to pay &lt;b&gt;...&lt;/b&gt;\n",
"Little red riding hood ficed to the spam countered in European &lt;b&gt;...&lt;/b&gt;\n",
"\n",
"--- Temperature = 0.8\n",
"Today countie strikes ryder missile faces food market blut\n",
"On Sunday collores lose-toppy of sale of Bullment in &lt;b&gt;...&lt;/b&gt;\n",
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
"President Ol Luster for Profit Peaced Raised (AP)\n",
"Little red riding hood dace on depart talks #39; bank up\n",
"\n",
"--- Temperature = 1.0\n",
"Today wits House buiting debate fixes #39; supervice stake again\n",
"On Sunday arling digital poaching In for level\n",
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
"Little red riding hood signs on cash in Carter-youb\n",
"\n",
"--- Temperature = 1.3\n",
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
"On Sunday hround elitwing wint EU Powerburlinetien\n",
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
"President lost securitys from power Elections in Smiltrials\n",
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
"\n",
"--- Temperature = 1.8\n",
"Today #39;It: He deat: N.KA Asside\n",
"On Sunday i arry Par aldeup patient Wo stele1\n"
]
},
{
"ename": "KeyError",
"evalue": "0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"source": [
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
" probs = probs/np.sum(probs)\n",
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc)\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
"\n",
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"\\n--- Temperature = {i}\")\n",
" for j in range(5):\n",
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Introduzimos mais um parâmetro chamado **temperatura**, que é usado para indicar o quão rigidamente devemos nos ater à maior probabilidade. Se a temperatura for 1.0, fazemos uma amostragem multinomial justa, e quando a temperatura vai para o infinito - todas as probabilidades se tornam iguais, e selecionamos o próximo caractere aleatoriamente. No exemplo abaixo, podemos observar que o texto se torna sem sentido quando aumentamos demais a temperatura, e se assemelha a um texto \"ciclado\" gerado rigidamente quando se aproxima de 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "9fbb7d5fda708537649f71f5f646fcde",
"translation_date": "2025-08-28T14:03:06+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,79 @@
# Redes Generativas
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/33)
Redes Neurais Recorrentes (RNNs) e suas variantes com células controladas, como Long Short Term Memory Cells (LSTMs) e Gated Recurrent Units (GRUs), fornecem um mecanismo para modelagem de linguagem, pois conseguem aprender a ordem das palavras e prever a próxima palavra em uma sequência. Isso nos permite usar RNNs para **tarefas generativas**, como geração de texto comum, tradução automática e até mesmo legendas para imagens.
> ✅ Pense em todas as vezes que você se beneficiou de tarefas generativas, como a conclusão de texto enquanto digita. Pesquise sobre seus aplicativos favoritos para descobrir se eles utilizam RNNs.
Na arquitetura de RNN que discutimos na unidade anterior, cada unidade RNN produzia o próximo estado oculto como saída. No entanto, também podemos adicionar outra saída a cada unidade recorrente, permitindo que ela produza uma **sequência** (que tem o mesmo comprimento da sequência original). Além disso, podemos usar unidades RNN que não aceitam uma entrada em cada etapa, mas apenas um vetor de estado inicial, e então produzem uma sequência de saídas.
Isso permite diferentes arquiteturas neurais, como mostrado na imagem abaixo:
![Imagem mostrando padrões comuns de redes neurais recorrentes.](../../../../../translated_images/pt-BR/unreasonable-effectiveness-of-rnn.541ead816778f42d.webp)
> Imagem do post no blog [Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) por [Andrej Karpaty](http://karpathy.github.io/)
* **Um-para-um** é uma rede neural tradicional com uma entrada e uma saída.
* **Um-para-muitos** é uma arquitetura generativa que aceita um valor de entrada e gera uma sequência de valores de saída. Por exemplo, se quisermos treinar uma rede de **legendas para imagens** que produza uma descrição textual de uma imagem, podemos usar uma imagem como entrada, passá-la por uma CNN para obter seu estado oculto e, em seguida, usar uma cadeia recorrente para gerar a legenda palavra por palavra.
* **Muitos-para-um** corresponde às arquiteturas RNN que descrevemos na unidade anterior, como classificação de texto.
* **Muitos-para-muitos**, ou **sequência-para-sequência**, corresponde a tarefas como **tradução automática**, onde temos uma primeira RNN que coleta todas as informações da sequência de entrada no estado oculto, e outra cadeia RNN que desenrola esse estado na sequência de saída.
Nesta unidade, focaremos em modelos generativos simples que nos ajudam a gerar texto. Para simplificar, usaremos tokenização em nível de caracteres.
Treinaremos esta RNN para gerar texto passo a passo. Em cada etapa, pegaremos uma sequência de caracteres de comprimento `nchars` e pediremos à rede que gere o próximo caractere de saída para cada caractere de entrada:
![Imagem mostrando um exemplo de geração de RNN da palavra 'HELLO'.](../../../../../translated_images/pt-BR/rnn-generate.56c54afb52f9781d.webp)
Ao gerar texto (durante a inferência), começamos com algum **prompt**, que é passado pelas células RNN para gerar seu estado intermediário, e então a geração começa a partir desse estado. Geramos um caractere por vez e passamos o estado e o caractere gerado para outra célula RNN para gerar o próximo, até que tenhamos gerado caracteres suficientes.
<img src="../../../../../translated_images/pt-BR/rnn-generate-inf.5168dc65e0370eea.webp" width="60%"/>
> Imagem do autor
## ✍️ Exercícios: Redes Generativas
Continue seu aprendizado nos seguintes notebooks:
* [Redes Generativas com PyTorch](GenerativePyTorch.ipynb)
* [Redes Generativas com TensorFlow](GenerativeTF.ipynb)
## Geração de texto suave e temperatura
A saída de cada célula RNN é uma distribuição de probabilidade de caracteres. Se sempre escolhermos o caractere com a maior probabilidade como o próximo caractere no texto gerado, o texto frequentemente pode se tornar "cíclico", repetindo as mesmas sequências de caracteres repetidamente, como neste exemplo:
```
today of the second the company and a second the company ...
```
No entanto, se olharmos para a distribuição de probabilidade do próximo caractere, pode ser que a diferença entre algumas das maiores probabilidades não seja tão grande, por exemplo, um caractere pode ter probabilidade 0,2 e outro 0,19, etc. Por exemplo, ao procurar o próximo caractere na sequência '*play*', o próximo caractere pode ser igualmente um espaço ou **e** (como na palavra *player*).
Isso nos leva à conclusão de que nem sempre é "justo" selecionar o caractere com maior probabilidade, pois escolher o segundo maior ainda pode levar a um texto significativo. É mais sábio **amostrar** caracteres da distribuição de probabilidade fornecida pela saída da rede. Podemos também usar um parâmetro, **temperatura**, que ajusta a distribuição de probabilidade, caso queiramos adicionar mais aleatoriedade ou torná-la mais íngreme, se quisermos nos ater mais aos caracteres de maior probabilidade.
Explore como essa geração de texto suave é implementada nos notebooks mencionados acima.
## Conclusão
Embora a geração de texto possa ser útil por si só, os maiores benefícios vêm da capacidade de gerar texto usando RNNs a partir de algum vetor de características inicial. Por exemplo, a geração de texto é usada como parte da tradução automática (sequência-para-sequência, neste caso o vetor de estado do *encoder* é usado para gerar ou *decodificar* a mensagem traduzida) ou para gerar descrições textuais de uma imagem (nesse caso, o vetor de características viria de um extrator CNN).
## 🚀 Desafio
Faça algumas lições no Microsoft Learn sobre este tópico:
* Geração de Texto com [PyTorch](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/6-generative-networks/?WT.mc_id=academic-77998-cacaste)/[TensorFlow](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-tensorflow/5-generative-networks/?WT.mc_id=academic-77998-cacaste)
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/34)
## Revisão e Autoestudo
Aqui estão alguns artigos para expandir seu conhecimento:
* Diferentes abordagens para geração de texto com Cadeia de Markov, LSTM e GPT-2: [post no blog](https://towardsdatascience.com/text-generation-gpt-2-lstm-markov-chain-9ea371820e1e)
* Exemplo de geração de texto na [documentação do Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)
## [Tarefa](lab/README.md)
Vimos como gerar texto caractere por caractere. No laboratório, você explorará a geração de texto em nível de palavras.
---

View File

@ -0,0 +1,14 @@
# Geração de Texto em Nível de Palavra usando RNNs
Atividade de Laboratório do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Neste laboratório, você precisa escolher qualquer livro e usá-lo como um conjunto de dados para treinar um gerador de texto em nível de palavra.
## O Conjunto de Dados
Você pode usar qualquer livro. É possível encontrar muitos textos gratuitos no [Project Gutenberg](https://www.gutenberg.org/), por exemplo, aqui está um link direto para [Alice's Adventures in Wonderland](https://www.gutenberg.org/files/11/11-0.txt)) de Lewis Carroll.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,112 @@
# Mecanismos de Atenção e Transformers
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/35)
Um dos problemas mais importantes no domínio de PLN (Processamento de Linguagem Natural) é a **tradução automática**, uma tarefa essencial que sustenta ferramentas como o Google Tradutor. Nesta seção, vamos nos concentrar na tradução automática ou, mais geralmente, em qualquer tarefa de *sequência para sequência* (também chamada de **transdução de sentenças**).
Com RNNs, a tarefa de sequência para sequência é implementada por duas redes recorrentes, onde uma rede, o **codificador**, comprime uma sequência de entrada em um estado oculto, enquanto outra rede, o **decodificador**, expande esse estado oculto em um resultado traduzido. Existem alguns problemas com essa abordagem:
* O estado final da rede codificadora tem dificuldade em lembrar o início de uma sentença, o que causa baixa qualidade do modelo para sentenças longas.
* Todas as palavras em uma sequência têm o mesmo impacto no resultado. Na realidade, no entanto, palavras específicas na sequência de entrada frequentemente têm mais impacto nas saídas sequenciais do que outras.
Os **Mecanismos de Atenção** fornecem um meio de ponderar o impacto contextual de cada vetor de entrada em cada previsão de saída da RNN. Isso é implementado criando atalhos entre os estados intermediários da RNN de entrada e a RNN de saída. Dessa forma, ao gerar o símbolo de saída y<sub>t</sub>, levamos em conta todos os estados ocultos de entrada h<sub>i</sub>, com diferentes coeficientes de peso &alpha;<sub>t,i</sub>.
![Imagem mostrando um modelo codificador/decodificador com uma camada de atenção aditiva](../../../../../translated_images/pt-BR/encoder-decoder-attention.7a726296894fb567.webp)
> O modelo codificador-decodificador com mecanismo de atenção aditiva em [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), citado deste [post no blog](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)
A matriz de atenção {&alpha;<sub>i,j</sub>} representaria o grau em que certas palavras de entrada influenciam a geração de uma palavra específica na sequência de saída. Abaixo está um exemplo de tal matriz:
![Imagem mostrando um alinhamento de exemplo encontrado pelo RNNsearch-50, retirada de Bahdanau - arviz.org](../../../../../translated_images/pt-BR/bahdanau-fig3.09ba2d37f202a6af.webp)
> Figura de [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (Fig.3)
Os mecanismos de atenção são responsáveis por grande parte do estado da arte atual ou próximo ao atual em PLN. No entanto, adicionar atenção aumenta significativamente o número de parâmetros do modelo, o que levou a problemas de escalabilidade com RNNs. Uma limitação chave na escalabilidade das RNNs é que a natureza recorrente dos modelos torna desafiador agrupar e paralelizar o treinamento. Em uma RNN, cada elemento de uma sequência precisa ser processado em ordem sequencial, o que significa que não pode ser facilmente paralelizado.
![Codificador Decodificador com Atenção](../../../../../lessons/5-NLP/18-Transformers/images/EncDecAttention.gif)
> Figura do [Blog do Google](https://research.googleblog.com/2016/09/a-neural-network-for-machine.html)
A adoção de mecanismos de atenção, combinada com essa limitação, levou à criação dos modelos Transformer, que hoje representam o estado da arte, como BERT e Open-GPT3.
## Modelos Transformer
Uma das principais ideias por trás dos transformers é evitar a natureza sequencial das RNNs e criar um modelo que seja paralelizável durante o treinamento. Isso é alcançado implementando duas ideias:
* codificação posicional
* uso do mecanismo de autoatenção para capturar padrões em vez de RNNs (ou CNNs) (é por isso que o artigo que introduz os transformers se chama *[Attention is all you need](https://arxiv.org/abs/1706.03762)*)
### Codificação/Embutimento Posicional
A ideia da codificação posicional é a seguinte:
1. Ao usar RNNs, a posição relativa dos tokens é representada pelo número de passos, e, portanto, não precisa ser representada explicitamente.
2. No entanto, ao mudarmos para atenção, precisamos saber as posições relativas dos tokens dentro de uma sequência.
3. Para obter a codificação posicional, aumentamos nossa sequência de tokens com uma sequência de posições dos tokens na sequência (ou seja, uma sequência de números 0, 1, ...).
4. Em seguida, misturamos a posição do token com um vetor de embutimento do token. Para transformar a posição (inteiro) em um vetor, podemos usar diferentes abordagens:
* Embutimento treinável, semelhante ao embutimento de tokens. Esta é a abordagem que consideramos aqui. Aplicamos camadas de embutimento tanto nos tokens quanto em suas posições, resultando em vetores de embutimento de mesmas dimensões, que então somamos.
* Função fixa de codificação posicional, como proposto no artigo original.
<img src="../../../../../translated_images/pt-BR/pos-embedding.e41ce9b6cf6078af.webp" width="50%"/>
> Imagem do autor
O resultado que obtemos com o embutimento posicional incorpora tanto o token original quanto sua posição dentro de uma sequência.
### Autoatenção Multi-Cabeça
Em seguida, precisamos capturar alguns padrões dentro de nossa sequência. Para isso, os transformers usam um mecanismo de **autoatenção**, que é essencialmente atenção aplicada à mesma sequência como entrada e saída. Aplicar autoatenção nos permite levar em conta o **contexto** dentro da sentença e ver quais palavras estão inter-relacionadas. Por exemplo, isso nos permite identificar quais palavras são referidas por correferências, como *it* (ele/ela), e também considerar o contexto:
![](../../../../../translated_images/pt-BR/CoreferenceResolution.861924d6d384a7d6.webp)
> Imagem do [Blog do Google](https://research.googleblog.com/2017/08/transformer-novel-neural-network.html)
Nos transformers, usamos **Atenção Multi-Cabeça** para dar à rede o poder de capturar vários tipos diferentes de dependências, como relações de palavras de longo prazo vs. curto prazo, correferência vs. outra coisa, etc.
O [Notebook do TensorFlow](TransformersTF.ipynb) contém mais detalhes sobre a implementação das camadas do transformer.
### Atenção Codificador-Decodificador
Nos transformers, a atenção é usada em dois lugares:
* Para capturar padrões dentro do texto de entrada usando autoatenção.
* Para realizar a tradução de sequência - é a camada de atenção entre o codificador e o decodificador.
A atenção codificador-decodificador é muito semelhante ao mecanismo de atenção usado em RNNs, como descrito no início desta seção. Este diagrama animado explica o papel da atenção codificador-decodificador.
![GIF animado mostrando como as avaliações são realizadas em modelos transformer.](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif)
Como cada posição de entrada é mapeada independentemente para cada posição de saída, os transformers podem paralelizar melhor do que as RNNs, o que permite modelos de linguagem muito maiores e mais expressivos. Cada cabeça de atenção pode ser usada para aprender diferentes relações entre palavras, o que melhora as tarefas de Processamento de Linguagem Natural.
## BERT
**BERT** (Bidirectional Encoder Representations from Transformers) é uma rede transformer muito grande com várias camadas: 12 camadas para o *BERT-base* e 24 para o *BERT-large*. O modelo é primeiro pré-treinado em um grande corpus de dados textuais (Wikipedia + livros) usando treinamento não supervisionado (prevendo palavras mascaradas em uma sentença). Durante o pré-treinamento, o modelo absorve níveis significativos de compreensão da linguagem, que podem ser aproveitados com outros conjuntos de dados usando ajuste fino. Esse processo é chamado de **aprendizado por transferência**.
![imagem de http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/pt-BR/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)
> Imagem [fonte](http://jalammar.github.io/illustrated-bert/)
## ✍️ Exercícios: Transformers
Continue seu aprendizado nos seguintes notebooks:
* [Transformers em PyTorch](TransformersPyTorch.ipynb)
* [Transformers em TensorFlow](TransformersTF.ipynb)
## Conclusão
Nesta lição, você aprendeu sobre Transformers e Mecanismos de Atenção, ferramentas essenciais na caixa de ferramentas de PLN. Existem muitas variações de arquiteturas Transformer, incluindo BERT, DistilBERT, BigBird, OpenGPT3 e mais, que podem ser ajustadas. O pacote [HuggingFace](https://github.com/huggingface/) fornece um repositório para treinar muitas dessas arquiteturas com PyTorch e TensorFlow.
## 🚀 Desafio
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/36)
## Revisão e Autoestudo
* [Post no blog](https://mchromiak.github.io/articles/2017/Sep/12/Transformer-Attention-is-all-you-need/), explicando o clássico artigo [Attention is all you need](https://arxiv.org/abs/1706.03762) sobre transformers.
* [Uma série de posts no blog](https://towardsdatascience.com/transformers-explained-visually-part-1-overview-of-functionality-95a6dd460452) sobre transformers, explicando a arquitetura em detalhes.
## [Tarefa](assignment.md)
---

View File

@ -0,0 +1,353 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Mecanismos de atenção e transformadores\n",
"\n",
"Uma grande desvantagem das redes recorrentes é que todas as palavras em uma sequência têm o mesmo impacto no resultado. Isso causa um desempenho subótimo em modelos padrão de codificador-decodificador LSTM para tarefas de sequência para sequência, como Reconhecimento de Entidades Nomeadas e Tradução Automática. Na realidade, palavras específicas na sequência de entrada frequentemente têm mais impacto nos resultados sequenciais do que outras.\n",
"\n",
"Considere um modelo de sequência para sequência, como tradução automática. Ele é implementado por duas redes recorrentes, onde uma rede (**codificador**) comprime a sequência de entrada em um estado oculto, e outra (**decodificador**) expande esse estado oculto no resultado traduzido. O problema com essa abordagem é que o estado final da rede tem dificuldade em lembrar o início de uma frase, causando baixa qualidade do modelo em frases longas.\n",
"\n",
"**Mecanismos de Atenção** fornecem um meio de ponderar o impacto contextual de cada vetor de entrada em cada previsão de saída da RNN. Isso é implementado criando atalhos entre estados intermediários da RNN de entrada e da RNN de saída. Dessa forma, ao gerar o símbolo de saída $y_t$, levaremos em conta todos os estados ocultos de entrada $h_i$, com diferentes coeficientes de peso $\\alpha_{t,i}$.\n",
"\n",
"![Imagem mostrando um modelo codificador/decodificador com uma camada de atenção aditiva](../../../../../translated_images/pt-BR/encoder-decoder-attention.7a726296894fb567.webp)\n",
"*O modelo codificador-decodificador com mecanismo de atenção aditiva em [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), citado deste [post de blog](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)*\n",
"\n",
"A matriz de atenção $\\{\\alpha_{i,j}\\}$ representaria o grau em que certas palavras de entrada influenciam a geração de uma palavra específica na sequência de saída. Abaixo está um exemplo de tal matriz:\n",
"\n",
"![Imagem mostrando um alinhamento de exemplo encontrado pelo RNNsearch-50, retirada de Bahdanau - arviz.org](../../../../../translated_images/pt-BR/bahdanau-fig3.09ba2d37f202a6af.webp)\n",
"\n",
"*Figura retirada de [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (Fig.3)*\n",
"\n",
"Os mecanismos de atenção são responsáveis por grande parte do estado da arte atual ou próximo ao estado da arte em Processamento de Linguagem Natural. No entanto, adicionar atenção aumenta significativamente o número de parâmetros do modelo, o que levou a problemas de escalabilidade com RNNs. Uma restrição chave na escalabilidade das RNNs é que a natureza recorrente dos modelos torna desafiador agrupar e paralelizar o treinamento. Em uma RNN, cada elemento de uma sequência precisa ser processado em ordem sequencial, o que significa que não pode ser facilmente paralelizado.\n",
"\n",
"A adoção de mecanismos de atenção combinada com essa restrição levou à criação dos modelos transformadores, agora estado da arte, que conhecemos e usamos hoje, como BERT e OpenGPT3.\n",
"\n",
"## Modelos transformadores\n",
"\n",
"Em vez de encaminhar o contexto de cada previsão anterior para a próxima etapa de avaliação, **modelos transformadores** usam **codificações posicionais** e atenção para capturar o contexto de uma entrada específica dentro de uma janela de texto fornecida. A imagem abaixo mostra como as codificações posicionais com atenção podem capturar o contexto dentro de uma janela específica.\n",
"\n",
"![GIF animado mostrando como as avaliações são realizadas em modelos transformadores.](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif)\n",
"\n",
"Como cada posição de entrada é mapeada independentemente para cada posição de saída, os transformadores podem paralelizar melhor do que as RNNs, o que permite modelos de linguagem muito maiores e mais expressivos. Cada cabeça de atenção pode ser usada para aprender diferentes relações entre palavras, melhorando tarefas de Processamento de Linguagem Natural.\n",
"\n",
"**BERT** (Representações de Codificador Bidirecional de Transformadores) é uma rede transformadora muito grande e multilayer com 12 camadas para *BERT-base* e 24 para *BERT-large*. O modelo é primeiro pré-treinado em um grande corpus de dados de texto (WikiPedia + livros) usando treinamento não supervisionado (prevendo palavras mascaradas em uma frase). Durante o pré-treinamento, o modelo absorve um nível significativo de compreensão da linguagem, que pode ser aproveitado com outros conjuntos de dados usando ajuste fino. Esse processo é chamado de **aprendizado por transferência**.\n",
"\n",
"![Imagem de http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/pt-BR/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)\n",
"\n",
"Existem muitas variações de arquiteturas de transformadores, incluindo BERT, DistilBERT, BigBird, OpenGPT3 e outras que podem ser ajustadas. O pacote [HuggingFace](https://github.com/huggingface/) fornece um repositório para treinar muitas dessas arquiteturas com PyTorch.\n",
"\n",
"## Usando BERT para classificação de texto\n",
"\n",
"Vamos ver como podemos usar o modelo BERT pré-treinado para resolver nossa tarefa tradicional: classificação de sequência. Vamos classificar nosso conjunto de dados original AG News.\n",
"\n",
"Primeiro, vamos carregar a biblioteca HuggingFace e nosso conjunto de dados:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"from torchnlp import *\n",
"import transformers\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_len = len(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como estaremos utilizando um modelo BERT pré-treinado, será necessário usar um tokenizador específico. Primeiro, vamos carregar um tokenizador associado ao modelo BERT pré-treinado.\n",
"\n",
"A biblioteca HuggingFace contém um repositório de modelos pré-treinados, que você pode usar simplesmente especificando seus nomes como argumentos para as funções `from_pretrained`. Todos os arquivos binários necessários para o modelo serão baixados automaticamente.\n",
"\n",
"No entanto, em determinados momentos, pode ser necessário carregar seus próprios modelos. Nesse caso, você pode especificar o diretório que contém todos os arquivos relevantes, incluindo os parâmetros para o tokenizador, o arquivo `config.json` com os parâmetros do modelo, os pesos binários, etc.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# To load the model from Internet repository using model name. \n",
"# Use this if you are running from your own copy of the notebooks\n",
"bert_model = 'bert-base-uncased' \n",
"\n",
"# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have\n",
"# prepared all required files for you.\n",
"bert_model = './bert'\n",
"\n",
"tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)\n",
"\n",
"MAX_SEQ_LEN = 128\n",
"PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n",
"UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O objeto `tokenizer` contém a função `encode` que pode ser usada diretamente para codificar texto:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[101, 1052, 22123, 2953, 2818, 2003, 1037, 2307, 7705, 2005, 17953, 2361, 102]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.encode('PyTorch is a great framework for NLP')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Então, vamos criar iteradores que usaremos durante o treinamento para acessar os dados. Como o BERT usa sua própria função de codificação, precisaríamos definir uma função de preenchimento semelhante à `padify` que definimos anteriormente:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def pad_bert(b):\n",
" # b is the list of tuples of length batch_size\n",
" # - first element of a tuple = label, \n",
" # - second = feature (text sequence)\n",
" # build vectorized sequence\n",
" v = [tokenizer.encode(x[1]) for x in b]\n",
" # compute max length of a sequence in this minibatch\n",
" l = max(map(len,v))\n",
" return ( # tuple of two tensors - labels and features\n",
" torch.LongTensor([t[0] for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, collate_fn=pad_bert, shuffle=True)\n",
"test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=8, collate_fn=pad_bert)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No nosso caso, usaremos o modelo BERT pré-treinado chamado `bert-base-uncased`. Vamos carregar o modelo usando o pacote `BertForSequenceClassfication`. Isso garante que nosso modelo já tenha a arquitetura necessária para classificação, incluindo o classificador final. Você verá uma mensagem de aviso indicando que os pesos do classificador final não estão inicializados e que o modelo precisará de pré-treinamento - isso é perfeitamente normal, porque é exatamente o que estamos prestes a fazer!\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Some weights of the model checkpoint at ./bert were not used when initializing BertForSequenceClassification: ['cls.predictions.bias', 'cls.predictions.transform.dense.weight', 'cls.predictions.transform.dense.bias', 'cls.predictions.decoder.weight', 'cls.seq_relationship.weight', 'cls.seq_relationship.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias']\n",
"- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
"- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n",
"Some weights of BertForSequenceClassification were not initialized from the model checkpoint at ./bert and are newly initialized: ['classifier.weight', 'classifier.bias']\n",
"You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
]
}
],
"source": [
"model = transformers.BertForSequenceClassification.from_pretrained(bert_model,num_labels=4).to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora estamos prontos para começar o treinamento! Como o BERT já está pré-treinado, queremos começar com uma taxa de aprendizado relativamente pequena para não comprometer os pesos iniciais.\n",
"\n",
"Todo o trabalho pesado é realizado pelo modelo `BertForSequenceClassification`. Quando chamamos o modelo nos dados de treinamento, ele retorna tanto a perda quanto a saída da rede para o minibatch de entrada. Usamos a perda para a otimização dos parâmetros (`loss.backward()` realiza a passagem para trás) e `out` para calcular a precisão do treinamento, comparando os rótulos obtidos `labs` (calculados usando `argmax`) com os rótulos esperados `labels`.\n",
"\n",
"Para controlar o processo, acumulamos a perda e a precisão ao longo de várias iterações e as exibimos a cada ciclo de treinamento definido por `report_freq`.\n",
"\n",
"Este treinamento provavelmente levará bastante tempo, então limitamos o número de iterações.\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loss = 1.1254194641113282, Accuracy = 0.585\n",
"Loss = 0.6194715118408203, Accuracy = 0.83\n",
"Loss = 0.46665248870849607, Accuracy = 0.8475\n",
"Loss = 0.4309701919555664, Accuracy = 0.8575\n",
"Loss = 0.35427074432373046, Accuracy = 0.8825\n",
"Loss = 0.3306886291503906, Accuracy = 0.8975\n",
"Loss = 0.30340143203735354, Accuracy = 0.8975\n",
"Loss = 0.26139299392700194, Accuracy = 0.915\n",
"Loss = 0.26708646774291994, Accuracy = 0.9225\n",
"Loss = 0.3667240524291992, Accuracy = 0.8675\n"
]
}
],
"source": [
"optimizer = torch.optim.Adam(model.parameters(), lr=2e-5)\n",
"\n",
"report_freq = 50\n",
"iterations = 500 # make this larger to train for longer time!\n",
"\n",
"model.train()\n",
"\n",
"i,c = 0,0\n",
"acc_loss = 0\n",
"acc_acc = 0\n",
"\n",
"for labels,texts in train_loader:\n",
" labels = labels.to(device)-1 # get labels in the range 0-3 \n",
" texts = texts.to(device)\n",
" loss, out = model(texts, labels=labels)[:2]\n",
" labs = out.argmax(dim=1)\n",
" acc = torch.mean((labs==labels).type(torch.float32))\n",
" optimizer.zero_grad()\n",
" loss.backward()\n",
" optimizer.step()\n",
" acc_loss += loss\n",
" acc_acc += acc\n",
" i+=1\n",
" c+=1\n",
" if i%report_freq==0:\n",
" print(f\"Loss = {acc_loss.item()/c}, Accuracy = {acc_acc.item()/c}\")\n",
" c = 0\n",
" acc_loss = 0\n",
" acc_acc = 0\n",
" iterations-=1\n",
" if not iterations:\n",
" break"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Você pode perceber (especialmente se aumentar o número de iterações e esperar tempo suficiente) que a classificação com BERT nos oferece uma precisão muito boa! Isso acontece porque o BERT já entende muito bem a estrutura da linguagem, e só precisamos ajustar o classificador final. No entanto, como o BERT é um modelo grande, todo o processo de treinamento leva bastante tempo e exige um poder computacional significativo! (GPU, e de preferência mais de uma).\n",
"\n",
"> **Note:** Em nosso exemplo, estamos utilizando um dos menores modelos BERT pré-treinados. Existem modelos maiores que provavelmente produzirão resultados melhores.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Avaliando o desempenho do modelo\n",
"\n",
"Agora podemos avaliar o desempenho do nosso modelo no conjunto de dados de teste. O loop de avaliação é bem semelhante ao loop de treinamento, mas não devemos esquecer de alternar o modelo para o modo de avaliação chamando `model.eval()`.\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Final accuracy: 0.9047029702970297\n"
]
}
],
"source": [
"model.eval()\n",
"iterations = 100\n",
"acc = 0\n",
"i = 0\n",
"for labels,texts in test_loader:\n",
" labels = labels.to(device)-1 \n",
" texts = texts.to(device)\n",
" _, out = model(texts, labels=labels)[:2]\n",
" labs = out.argmax(dim=1)\n",
" acc += torch.mean((labs==labels).type(torch.float32))\n",
" i+=1\n",
" if i>iterations: break\n",
" \n",
"print(f\"Final accuracy: {acc.item()/i}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Nesta unidade, vimos como é fácil utilizar um modelo de linguagem pré-treinado da biblioteca **transformers** e adaptá-lo para nossa tarefa de classificação de texto. Da mesma forma, os modelos BERT podem ser usados para extração de entidades, resposta a perguntas e outras tarefas de PLN.\n",
"\n",
"Os modelos de transformadores representam o estado da arte atual em PLN e, na maioria dos casos, devem ser a primeira solução com a qual você começa a experimentar ao implementar soluções personalizadas de PLN. No entanto, compreender os princípios básicos subjacentes às redes neurais recorrentes discutidos neste módulo é extremamente importante se você deseja construir modelos neurais avançados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "py37_pytorch",
"language": "python",
"name": "conda-env-py37_pytorch-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
},
"coopTranslator": {
"original_hash": "753865967678a92dbce7d7efbd36d980",
"translation_date": "2025-08-28T14:11:41+00:00",
"source_file": "lessons/5-NLP/18-Transformers/TransformersPyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,819 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Mecanismos de atenção e transformers\n",
"\n",
"Uma grande desvantagem das redes recorrentes é que todas as palavras em uma sequência têm o mesmo impacto no resultado. Isso causa um desempenho subótimo em modelos padrão de codificador-decodificador LSTM para tarefas de sequência para sequência, como Reconhecimento de Entidades Nomeadas e Tradução Automática. Na realidade, palavras específicas na sequência de entrada frequentemente têm mais impacto nos resultados sequenciais do que outras.\n",
"\n",
"Considere um modelo de sequência para sequência, como tradução automática. Ele é implementado por duas redes recorrentes, onde uma rede (**codificador**) comprime a sequência de entrada em um estado oculto, e outra (**decodificador**) expande esse estado oculto no resultado traduzido. O problema com essa abordagem é que o estado final da rede tem dificuldade em lembrar o início de uma frase, causando baixa qualidade do modelo em frases longas.\n",
"\n",
"**Mecanismos de Atenção** fornecem um meio de ponderar o impacto contextual de cada vetor de entrada em cada previsão de saída da RNN. Isso é implementado criando atalhos entre os estados intermediários da RNN de entrada e a RNN de saída. Dessa forma, ao gerar o símbolo de saída $y_t$, levaremos em conta todos os estados ocultos de entrada $h_i$, com diferentes coeficientes de peso $\\alpha_{t,i}$.\n",
"\n",
"![Imagem mostrando um modelo codificador/decodificador com uma camada de atenção aditiva](../../../../../translated_images/pt-BR/encoder-decoder-attention.7a726296894fb567.webp)\n",
"*O modelo codificador-decodificador com mecanismo de atenção aditiva em [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), citado deste [post de blog](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)*\n",
"\n",
"A matriz de atenção $\\{\\alpha_{i,j}\\}$ representaria o grau em que certas palavras de entrada influenciam a geração de uma determinada palavra na sequência de saída. Abaixo está um exemplo de tal matriz:\n",
"\n",
"![Imagem mostrando um alinhamento de exemplo encontrado pelo RNNsearch-50, retirada de Bahdanau - arviz.org](../../../../../translated_images/pt-BR/bahdanau-fig3.09ba2d37f202a6af.webp)\n",
"\n",
"*Figura retirada de [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (Fig.3)*\n",
"\n",
"Os mecanismos de atenção são responsáveis por grande parte do estado da arte atual ou próximo ao estado da arte em Processamento de Linguagem Natural. No entanto, adicionar atenção aumenta significativamente o número de parâmetros do modelo, o que levou a problemas de escalabilidade com RNNs. Uma restrição chave na escalabilidade das RNNs é que a natureza recorrente dos modelos torna desafiador agrupar e paralelizar o treinamento. Em uma RNN, cada elemento de uma sequência precisa ser processado em ordem sequencial, o que significa que não pode ser facilmente paralelizado.\n",
"\n",
"A adoção de mecanismos de atenção combinada com essa restrição levou à criação dos modelos Transformers, que hoje são o estado da arte e amplamente utilizados, como o BERT e o OpenGPT3.\n",
"\n",
"## Modelos Transformers\n",
"\n",
"Em vez de encaminhar o contexto de cada previsão anterior para a próxima etapa de avaliação, **modelos transformers** utilizam **codificações posicionais** e **atenção** para capturar o contexto de uma entrada dentro de uma janela de texto fornecida. A imagem abaixo mostra como as codificações posicionais com atenção podem capturar o contexto dentro de uma janela específica.\n",
"\n",
"![GIF animado mostrando como as avaliações são realizadas em modelos transformers.](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif)\n",
"\n",
"Como cada posição de entrada é mapeada independentemente para cada posição de saída, os transformers conseguem paralelizar melhor do que as RNNs, o que permite modelos de linguagem muito maiores e mais expressivos. Cada cabeça de atenção pode ser usada para aprender diferentes relações entre palavras, melhorando tarefas de Processamento de Linguagem Natural.\n",
"\n",
"## Construindo um Modelo Transformer Simples\n",
"\n",
"O Keras não contém uma camada Transformer integrada, mas podemos construir a nossa própria. Como antes, focaremos na classificação de texto do conjunto de dados AG News, mas vale mencionar que os modelos Transformers mostram os melhores resultados em tarefas de NLP mais complexas.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()\n",
"\n",
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Novas camadas no Keras devem herdar da classe `Layer` e implementar o método `call`. Vamos começar com a camada **Positional Embedding**. Usaremos [algum código da documentação oficial do Keras](https://keras.io/examples/nlp/text_classification_with_transformer/). Assumiremos que preenchemos todas as sequências de entrada para o comprimento `maxlen`.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class TokenAndPositionEmbedding(keras.layers.Layer):\n",
" def __init__(self, maxlen, vocab_size, embed_dim):\n",
" super(TokenAndPositionEmbedding, self).__init__()\n",
" self.token_emb = keras.layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)\n",
" self.pos_emb = keras.layers.Embedding(input_dim=maxlen, output_dim=embed_dim)\n",
" self.maxlen = maxlen\n",
"\n",
" def call(self, x):\n",
" maxlen = self.maxlen\n",
" positions = tf.range(start=0, limit=maxlen, delta=1)\n",
" positions = self.pos_emb(positions)\n",
" x = self.token_emb(x)\n",
" return x+positions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Esta camada consiste em duas camadas `Embedding`: uma para incorporar tokens (da maneira que discutimos anteriormente) e outra para as posições dos tokens. As posições dos tokens são criadas como uma sequência de números naturais de 0 até `maxlen` usando `tf.range`, e então passadas pela camada de embedding. Os dois vetores de embedding resultantes são somados, produzindo uma representação incorporada posicionalmente da entrada com o formato `maxlen`$\\times$`embed_dim`.\n",
"\n",
"Agora, vamos implementar o bloco transformer. Ele receberá a saída da camada de embedding definida anteriormente:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"class TransformerBlock(keras.layers.Layer):\n",
" def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):\n",
" super(TransformerBlock, self).__init__()\n",
" self.att = keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name='attn')\n",
" self.ffn = keras.Sequential(\n",
" [keras.layers.Dense(ff_dim, activation=\"relu\"), keras.layers.Dense(embed_dim),]\n",
" )\n",
" self.layernorm1 = keras.layers.LayerNormalization(epsilon=1e-6)\n",
" self.layernorm2 = keras.layers.LayerNormalization(epsilon=1e-6)\n",
" self.dropout1 = keras.layers.Dropout(rate)\n",
" self.dropout2 = keras.layers.Dropout(rate)\n",
"\n",
" def call(self, inputs, training):\n",
" attn_output = self.att(inputs, inputs)\n",
" attn_output = self.dropout1(attn_output, training=training)\n",
" out1 = self.layernorm1(inputs + attn_output)\n",
" ffn_output = self.ffn(out1)\n",
" ffn_output = self.dropout2(ffn_output, training=training)\n",
" return self.layernorm2(out1 + ffn_output)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora estamos prontos para definir o modelo completo do transformer:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, 256) 0 \n",
"_________________________________________________________________\n",
"token_and_position_embedding (None, 256, 32) 648192 \n",
"_________________________________________________________________\n",
"transformer_block (Transform (None, 256, 32) 10656 \n",
"_________________________________________________________________\n",
"global_average_pooling1d (Gl (None, 32) 0 \n",
"_________________________________________________________________\n",
"dropout_2 (Dropout) (None, 32) 0 \n",
"_________________________________________________________________\n",
"dense_2 (Dense) (None, 20) 660 \n",
"_________________________________________________________________\n",
"dropout_3 (Dropout) (None, 20) 0 \n",
"_________________________________________________________________\n",
"dense_3 (Dense) (None, 4) 84 \n",
"=================================================================\n",
"Total params: 659,592\n",
"Trainable params: 659,592\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"embed_dim = 32 # Embedding size for each token\n",
"num_heads = 2 # Number of attention heads\n",
"ff_dim = 32 # Hidden layer size in feed forward network inside transformer\n",
"maxlen = 256\n",
"vocab_size = 20000\n",
"\n",
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_sequence_length=maxlen, input_shape=(1,)),\n",
" TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim),\n",
" TransformerBlock(embed_dim, num_heads, ff_dim),\n",
" keras.layers.GlobalAveragePooling1D(),\n",
" keras.layers.Dropout(0.1),\n",
" keras.layers.Dense(20, activation=\"relu\"),\n",
" keras.layers.Dropout(0.1),\n",
" keras.layers.Dense(4, activation=\"softmax\")\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training tokenizer\n",
"938/938 [==============================] - 45s 39ms/step - loss: 0.4978 - acc: 0.8068 - val_loss: 0.2808 - val_acc: 0.9124\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9c2427a0d0>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print('Training tokenizer')\n",
"model.layers[0].adapt(ds_train.map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Modelos Transformer BERT\n",
"\n",
"**BERT** (Representações de Codificadores Bidirecionais de Transformers) é uma rede transformer muito grande e multilayer, com 12 camadas para o *BERT-base* e 24 para o *BERT-large*. O modelo é inicialmente pré-treinado em um grande corpus de dados textuais (WikiPedia + livros) usando treinamento não supervisionado (prevendo palavras mascaradas em uma sentença). Durante o pré-treinamento, o modelo adquire um nível significativo de compreensão da linguagem, que pode ser aproveitado com outros conjuntos de dados por meio de ajuste fino. Esse processo é chamado de **aprendizado por transferência**.\n",
"\n",
"![imagem de http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/pt-BR/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)\n",
"\n",
"Existem muitas variações de arquiteturas Transformer, incluindo BERT, DistilBERT, BigBird, OpenGPT3 e outras, que podem ser ajustadas.\n",
"\n",
"Vamos ver como podemos usar o modelo BERT pré-treinado para resolver nosso problema tradicional de classificação de sequência. Vamos aproveitar a ideia e algum código da [documentação oficial](https://www.tensorflow.org/text/tutorials/classify_text_with_bert).\n",
"\n",
"Para carregar modelos pré-treinados, usaremos o **Tensorflow hub**. Primeiro, vamos carregar o vetorizador específico do BERT:\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'tensorflow_text'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_41180/4216669875.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mtensorflow_text\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mtensorflow_hub\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mhub\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mvectorizer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mhub\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mKerasLayer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'tensorflow_text'"
]
}
],
"source": [
"import tensorflow_text \n",
"import tensorflow_hub as hub\n",
"vectorizer = hub.KerasLayer('https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'input_type_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int32)>,\n",
" 'input_word_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[ 101, 1045, 2293, 19081, 102, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0]], dtype=int32)>,\n",
" 'input_mask': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int32)>}"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer(['I love transformers'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"É importante que você utilize o mesmo vetorizador que foi usado para treinar a rede original. Além disso, o vetorizador BERT retorna três componentes:\n",
"* `input_word_ids`, que é uma sequência de números de tokens para a sentença de entrada\n",
"* `input_mask`, que indica qual parte da sequência contém a entrada real e qual parte é preenchimento. É semelhante à máscara produzida pela camada `Masking`\n",
"* `input_type_ids` é usado para tarefas de modelagem de linguagem e permite especificar duas sentenças de entrada em uma única sequência.\n",
"\n",
"Então, podemos instanciar o extrator de características do BERT:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"bert = hub.KerasLayer('https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-128_A-2/1')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"pooled_output -> (1, 128)\n",
"encoder_outputs -> 4\n",
"sequence_output -> (1, 128, 128)\n",
"default -> (1, 128)\n"
]
}
],
"source": [
"z = bert(vectorizer(['I love transformers']))\n",
"for i,x in z.items():\n",
" print(f\"{i} -> { len(x) if isinstance(x, list) else x.shape }\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Então, a camada BERT retorna vários resultados úteis:\n",
"* `pooled_output` é o resultado da média de todos os tokens na sequência. Você pode vê-lo como uma representação semântica inteligente de toda a rede. Ele é equivalente à saída da camada `GlobalAveragePooling1D` no nosso modelo anterior.\n",
"* `sequence_output` é a saída da última camada transformer (corresponde à saída de `TransformerBlock` no nosso modelo acima).\n",
"* `encoder_outputs` são as saídas de todas as camadas transformer. Como carregamos um modelo BERT de 4 camadas (como você provavelmente pode deduzir pelo nome, que contém `4_H`), ele possui 4 tensores. O último é o mesmo que `sequence_output`.\n",
"\n",
"Agora vamos definir o modelo de classificação de ponta a ponta. Usaremos a *definição funcional de modelo*, onde definimos a entrada do modelo e, em seguida, fornecemos uma série de expressões para calcular sua saída. Também tornaremos os pesos do modelo BERT não treináveis e treinaremos apenas o classificador final:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"__________________________________________________________________________________________________\n",
"Layer (type) Output Shape Param # Connected to \n",
"==================================================================================================\n",
"input_1 (InputLayer) [(None,)] 0 \n",
"__________________________________________________________________________________________________\n",
"keras_layer (KerasLayer) {'input_type_ids': ( 0 input_1[0][0] \n",
"__________________________________________________________________________________________________\n",
"keras_layer_1 (KerasLayer) {'pooled_output': (N 4782465 keras_layer[0][0] \n",
" keras_layer[0][1] \n",
" keras_layer[0][2] \n",
"__________________________________________________________________________________________________\n",
"dropout_4 (Dropout) (None, 128) 0 keras_layer_1[0][5] \n",
"__________________________________________________________________________________________________\n",
"dense_4 (Dense) (None, 4) 516 dropout_4[0][0] \n",
"==================================================================================================\n",
"Total params: 4,782,981\n",
"Trainable params: 516\n",
"Non-trainable params: 4,782,465\n",
"__________________________________________________________________________________________________\n"
]
}
],
"source": [
"inp = keras.Input(shape=(),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = bert(x)\n",
"x = keras.layers.Dropout(0.1)(x['pooled_output'])\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"bert.trainable = False\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 528s 559ms/step - loss: 0.8056 - acc: 0.6983 - val_loss: 0.5953 - val_acc: 0.7888\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9bb1e36d00>"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Apesar de haver poucos parâmetros treináveis, o processo é bastante lento, porque o extrator de características do BERT é computacionalmente pesado. Parece que não conseguimos alcançar uma precisão razoável, seja pela falta de treinamento ou pela falta de parâmetros no modelo.\n",
"\n",
"Vamos tentar desbloquear os pesos do BERT e treiná-lo também. Isso exige uma taxa de aprendizado muito pequena e uma estratégia de treinamento mais cuidadosa com **warmup**, utilizando o otimizador **AdamW**. Usaremos o pacote `tf-models-official` para criar o otimizador:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"__________________________________________________________________________________________________\n",
"Layer (type) Output Shape Param # Connected to \n",
"==================================================================================================\n",
"input_1 (InputLayer) [(None,)] 0 \n",
"__________________________________________________________________________________________________\n",
"keras_layer (KerasLayer) {'input_type_ids': ( 0 input_1[0][0] \n",
"__________________________________________________________________________________________________\n",
"keras_layer_1 (KerasLayer) {'pooled_output': (N 4782465 keras_layer[0][0] \n",
" keras_layer[0][1] \n",
" keras_layer[0][2] \n",
"__________________________________________________________________________________________________\n",
"dropout_4 (Dropout) (None, 128) 0 keras_layer_1[0][5] \n",
"__________________________________________________________________________________________________\n",
"dense_4 (Dense) (None, 4) 516 dropout_4[0][0] \n",
"==================================================================================================\n",
"Total params: 4,782,981\n",
"Trainable params: 4,782,980\n",
"Non-trainable params: 1\n",
"__________________________________________________________________________________________________\n",
"938/938 [==============================] - 629s 664ms/step - loss: 0.6344 - acc: 0.7658 - val_loss: 0.4876 - val_acc: 0.8247\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9bb0bd0070>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from official.nlp import optimization \n",
"bert.trainable=True\n",
"model.summary()\n",
"epochs = 3\n",
"opt = optimization.create_optimizer(\n",
" init_lr=3e-5,\n",
" num_train_steps=epochs*len(ds_train),\n",
" num_warmup_steps=0.1*epochs*len(ds_train),\n",
" optimizer_type='adamw')\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer=opt)\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como você pode ver, o treinamento é bastante lento - mas talvez você queira experimentar e treinar o modelo por algumas épocas (5-10) para ver se consegue obter o melhor resultado em comparação com as abordagens que usamos anteriormente.\n",
"\n",
"## Biblioteca Huggingface Transformers\n",
"\n",
"Outra maneira muito comum (e um pouco mais simples) de usar modelos Transformer é o [pacote HuggingFace](https://github.com/huggingface/), que fornece blocos de construção simples para diferentes tarefas de PLN. Ele está disponível tanto para Tensorflow quanto para PyTorch, outro framework de redes neurais muito popular.\n",
"\n",
"> **Note**: Se você não estiver interessado em ver como a biblioteca Transformers funciona - pode pular para o final deste notebook, pois não verá nada substancialmente diferente do que fizemos acima. Estaremos repetindo os mesmos passos de treinamento do modelo BERT usando uma biblioteca diferente e um modelo substancialmente maior. Assim, o processo envolve um treinamento bastante longo, então talvez você queira apenas dar uma olhada no código.\n",
"\n",
"Vamos ver como nosso problema pode ser resolvido usando [Huggingface Transformers](http://huggingface.co).\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A primeira coisa que precisamos fazer é escolher o modelo que iremos utilizar. Além de alguns modelos integrados, o Huggingface possui um [repositório online de modelos](https://huggingface.co/models), onde você pode encontrar muitos outros modelos pré-treinados pela comunidade. Todos esses modelos podem ser carregados e utilizados apenas fornecendo o nome do modelo. Todos os arquivos binários necessários para o modelo serão baixados automaticamente.\n",
"\n",
"Em determinados momentos, você pode precisar carregar seus próprios modelos. Nesse caso, você pode especificar o diretório que contém todos os arquivos relevantes, incluindo os parâmetros para o tokenizer, o arquivo `config.json` com os parâmetros do modelo, os pesos binários, etc.\n",
"\n",
"A partir do nome do modelo, podemos instanciar tanto o modelo quanto o tokenizer. Vamos começar com o tokenizer:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import transformers\n",
"\n",
"# To load the model from Internet repository using model name. \n",
"# Use this if you are running from your own copy of the notebooks\n",
"bert_model = 'bert-base-uncased' \n",
"\n",
"# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have\n",
"# prepared all required files for you.\n",
"#bert_model = './bert'\n",
"\n",
"tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)\n",
"\n",
"MAX_SEQ_LEN = 128\n",
"PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n",
"UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O objeto `tokenizer` contém a função `encode` que pode ser usada diretamente para codificar texto:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[101, 23435, 12314, 2003, 1037, 2307, 7705, 2005, 17953, 2361, 102]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.encode('Tensorflow is a great framework for NLP')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Também podemos usar o tokenizer para codificar uma sequência de uma maneira adequada para passar ao modelo, ou seja, incluindo os campos `token_ids`, `input_mask`, etc. Também podemos especificar que queremos tensores do Tensorflow fornecendo o argumento `return_tensors='tf'`:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'input_ids': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[ 101, 7592, 1010, 2045, 102]], dtype=int32)>, 'token_type_ids': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[0, 0, 0, 0, 0]], dtype=int32)>, 'attention_mask': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[1, 1, 1, 1, 1]], dtype=int32)>}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer(['Hello, there'],return_tensors='tf')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No nosso caso, usaremos o modelo BERT pré-treinado chamado `bert-base-uncased`. *Uncased* indica que o modelo não diferencia maiúsculas de minúsculas.\n",
"\n",
"Ao treinar o modelo, precisamos fornecer uma sequência tokenizada como entrada, e, portanto, iremos projetar um pipeline de processamento de dados. Como `tokenizer.encode` é uma função em Python, usaremos a mesma abordagem da última unidade, chamando-a com `py_function`:\n"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"def process(x):\n",
" return tokenizer.encode(x.numpy().decode('utf-8'),return_tensors='tf',padding='max_length',max_length=MAX_SEQ_LEN,truncation=True)[0]\n",
"\n",
"def process_fn(x):\n",
" s = x['title']+' '+x['description']\n",
" e = tf.py_function(process,inp=[s],Tout=(tf.int32))\n",
" e.set_shape(MAX_SEQ_LEN)\n",
" return e,x['label']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora podemos carregar o modelo real usando o pacote `BertForSequenceClassification`. Isso garante que nosso modelo já tenha a arquitetura necessária para classificação, incluindo o classificador final. Você verá uma mensagem de aviso indicando que os pesos do classificador final não estão inicializados e que o modelo precisará de pré-treinamento - isso é perfeitamente normal, porque é exatamente o que estamos prestes a fazer!\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"model = transformers.TFBertForSequenceClassification.from_pretrained(bert_model,num_labels=4,output_attentions=False)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"tf_bert_for_sequence_classification_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"bert (TFBertMainLayer) multiple 109482240 \n",
"_________________________________________________________________\n",
"dropout_75 (Dropout) multiple 0 \n",
"_________________________________________________________________\n",
"classifier (Dense) multiple 3076 \n",
"=================================================================\n",
"Total params: 109,485,316\n",
"Trainable params: 109,485,316\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como você pode ver em `summary()`, o modelo contém quase 110 milhões de parâmetros! Presumivelmente, se quisermos uma tarefa de classificação simples em um conjunto de dados relativamente pequeno, não queremos treinar a camada base do BERT:\n"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"tf_bert_for_sequence_classification_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"bert (TFBertMainLayer) multiple 109482240 \n",
"_________________________________________________________________\n",
"dropout_75 (Dropout) multiple 0 \n",
"_________________________________________________________________\n",
"classifier (Dense) multiple 3076 \n",
"=================================================================\n",
"Total params: 109,485,316\n",
"Trainable params: 3,076\n",
"Non-trainable params: 109,482,240\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.layers[0].trainable = False\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora estamos prontos para começar o treinamento!\n",
"\n",
"> **Nota**: Treinar um modelo BERT em escala completa pode levar muito tempo! Por isso, vamos treiná-lo apenas para as primeiras 32 batches. Isso é apenas para demonstrar como o treinamento do modelo é configurado. Se você estiver interessado em tentar o treinamento em escala completa - basta remover os parâmetros `steps_per_epoch` e `validation_steps`, e prepare-se para esperar!\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"32/32 [==============================] - 142s 4s/step - loss: 1.3896 - acc: 0.2500 - val_loss: 1.3863 - val_acc: 0.2480\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f1d40a4b6a0>"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile('adam','sparse_categorical_crossentropy',['acc'])\n",
"tf.get_logger().setLevel('ERROR')\n",
"model.fit(ds_train.map(process_fn).batch(32),validation_data=ds_test.map(process_fn).batch(32),steps_per_epoch=32,validation_steps=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Se você aumentar o número de iterações, esperar o tempo necessário e treinar por várias épocas, pode esperar que a classificação com BERT nos forneça a melhor precisão! Isso acontece porque o BERT já entende muito bem a estrutura da linguagem, e só precisamos ajustar o classificador final. No entanto, como o BERT é um modelo grande, todo o processo de treinamento leva bastante tempo e exige um poder computacional significativo! (GPU, e de preferência mais de uma).\n",
"\n",
"> **Note:** Em nosso exemplo, estamos utilizando um dos menores modelos BERT pré-treinados. Existem modelos maiores que provavelmente oferecerão resultados melhores.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Nesta unidade, vimos arquiteturas de modelos muito recentes baseadas em **transformers**. Aplicamos esses modelos na nossa tarefa de classificação de texto, mas, da mesma forma, os modelos BERT podem ser usados para extração de entidades, resposta a perguntas e outras tarefas de PLN.\n",
"\n",
"Os modelos de transformers representam o estado da arte atual em PLN e, na maioria dos casos, devem ser a primeira solução a ser experimentada ao implementar soluções personalizadas de PLN. No entanto, compreender os princípios básicos subjacentes às redes neurais recorrentes discutidos neste módulo é extremamente importante se você deseja construir modelos neurais avançados.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernelspec": {
"display_name": "py38_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "ab59c532409774988ab875f2260e8e53",
"translation_date": "2025-08-28T14:14:08+00:00",
"source_file": "lessons/5-NLP/18-Transformers/TransformersTF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,6 @@
# Tarefa: Transformers
Experimente os Transformers no HuggingFace! Teste alguns dos scripts que eles fornecem para trabalhar com os diversos modelos disponíveis no site: https://huggingface.co/docs/transformers/run_scripts. Experimente um dos conjuntos de dados deles, depois importe um dos seus próprios deste currículo ou do Kaggle e veja se consegue gerar textos interessantes. Produza um notebook com suas descobertas.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,492 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Reconhecimento de Entidades Nomeadas (NER)\n",
"\n",
"Este notebook é parte do [Currículo de IA para Iniciantes](http://aka.ms/ai-beginners).\n",
"\n",
"Neste exemplo, aprenderemos como treinar um modelo de NER no [Corpus Anotado para Reconhecimento de Entidades Nomeadas](https://www.kaggle.com/datasets/abhinavwalia95/entity-annotated-corpus), um conjunto de dados do Kaggle. Antes de prosseguir, faça o download do arquivo [ner_dataset.csv](https://www.kaggle.com/datasets/abhinavwalia95/entity-annotated-corpus?resource=download&select=ner_dataset.csv) para o diretório atual.\n"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"from tensorflow import keras\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preparando o Conjunto de Dados\n",
"\n",
"Vamos começar lendo o conjunto de dados em um dataframe. Se você quiser aprender mais sobre como usar o Pandas, visite uma [lição sobre processamento de dados](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/2-Working-With-Data/07-python) em nosso [Ciência de Dados para Iniciantes](http://aka.ms/datascience-beginners)\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Sentence #</th>\n",
" <th>Word</th>\n",
" <th>POS</th>\n",
" <th>Tag</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Sentence: 1</td>\n",
" <td>Thousands</td>\n",
" <td>NNS</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>NaN</td>\n",
" <td>of</td>\n",
" <td>IN</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NaN</td>\n",
" <td>demonstrators</td>\n",
" <td>NNS</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NaN</td>\n",
" <td>have</td>\n",
" <td>VBP</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>NaN</td>\n",
" <td>marched</td>\n",
" <td>VBN</td>\n",
" <td>O</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Sentence # Word POS Tag\n",
"0 Sentence: 1 Thousands NNS O\n",
"1 NaN of IN O\n",
"2 NaN demonstrators NNS O\n",
"3 NaN have VBP O\n",
"4 NaN marched VBN O"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.read_csv('ner_dataset.csv',encoding='unicode-escape')\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos obter tags únicas e criar dicionários de consulta que podemos usar para converter tags em números de classe:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array(['O', 'B-geo', 'B-gpe', 'B-per', 'I-geo', 'B-org', 'I-org', 'B-tim',\n",
" 'B-art', 'I-art', 'I-per', 'I-gpe', 'I-tim', 'B-nat', 'B-eve',\n",
" 'I-eve', 'I-nat'], dtype=object)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tags = df.Tag.unique()\n",
"tags"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'O'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"id2tag = dict(enumerate(tags))\n",
"tag2id = { v : k for k,v in id2tag.items() }\n",
"\n",
"id2tag[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora precisamos fazer o mesmo com o vocabulário. Para simplificar, criaremos o vocabulário sem levar em conta a frequência das palavras; na vida real, você pode querer usar o vetorizador do Keras e limitar o número de palavras.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"vocab = set(df['Word'].apply(lambda x: x.lower()))\n",
"id2word = { i+1 : v for i,v in enumerate(vocab) }\n",
"id2word[0] = '<UNK>'\n",
"vocab.add('<UNK>')\n",
"word2id = { v : k for k,v in id2word.items() }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Precisamos criar um conjunto de dados de frases para treinamento. Vamos percorrer o conjunto de dados original e separar todas as frases individuais em `X` (listas de palavras) e `Y` (lista de tokens):\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"X,Y = [],[]\n",
"s,t = [],[]\n",
"for i,row in df[['Sentence #','Word','Tag']].iterrows():\n",
" if pd.isna(row['Sentence #']):\n",
" s.append(row['Word'])\n",
" t.append(row['Tag'])\n",
" else:\n",
" if len(s)>0:\n",
" X.append(s)\n",
" Y.append(t)\n",
" s,t = [row['Word']],[row['Tag']]\n",
"X.append(s)\n",
"Y.append(t)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"([10386,\n",
" 23515,\n",
" 4134,\n",
" 29620,\n",
" 7954,\n",
" 13583,\n",
" 21193,\n",
" 12222,\n",
" 27322,\n",
" 18258,\n",
" 5815,\n",
" 15880,\n",
" 5355,\n",
" 25242,\n",
" 31327,\n",
" 18258,\n",
" 27067,\n",
" 23515,\n",
" 26444,\n",
" 14412,\n",
" 358,\n",
" 26551,\n",
" 5011,\n",
" 30558],\n",
" [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0])"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def vectorize(seq):\n",
" return [word2id[x.lower()] for x in seq]\n",
"\n",
"def tagify(seq):\n",
" return [tag2id[x] for x in seq]\n",
"\n",
"Xv = list(map(vectorize,X))\n",
"Yv = list(map(tagify,Y))\n",
"\n",
"Xv[0], Yv[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para simplificar, vamos preencher todas as sentenças com 0 tokens até o comprimento máximo. Na vida real, podemos querer usar uma estratégia mais inteligente e preencher sequências apenas dentro de um minibatch.\n"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [],
"source": [
"X_data = keras.preprocessing.sequence.pad_sequences(Xv,padding='post')\n",
"Y_data = keras.preprocessing.sequence.pad_sequences(Yv,padding='post')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Definindo a Rede de Classificação de Tokens\n",
"\n",
"Usaremos uma rede bidirecional LSTM de duas camadas para classificação de tokens. Para aplicar um classificador denso a cada saída da última camada LSTM, utilizaremos a construção `TimeDistributed`, que replica a mesma camada densa para cada uma das saídas do LSTM em cada etapa:\n"
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential_3\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" embedding_4 (Embedding) (None, 104, 300) 9545400 \n",
" \n",
" bidirectional_6 (Bidirectio (None, 104, 200) 320800 \n",
" nal) \n",
" \n",
" bidirectional_7 (Bidirectio (None, 104, 200) 240800 \n",
" nal) \n",
" \n",
" time_distributed_3 (TimeDis (None, 104, 17) 3417 \n",
" tributed) \n",
" \n",
"=================================================================\n",
"Total params: 10,110,417\n",
"Trainable params: 10,110,417\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"maxlen = X_data.shape[1]\n",
"vocab_size = len(vocab)\n",
"num_tags = len(tags)\n",
"model = keras.models.Sequential([\n",
" keras.layers.Embedding(vocab_size, 300, input_length=maxlen),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),\n",
" keras.layers.TimeDistributed(keras.layers.Dense(num_tags, activation='softmax'))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Observe que aqui estamos especificando explicitamente `maxlen` para o nosso conjunto de dados - caso queiramos que a rede seja capaz de lidar com sequências de comprimento variável, precisamos ser um pouco mais inteligentes ao definir a rede.\n",
"\n",
"Agora vamos treinar o modelo. Para ganhar tempo, treinaremos apenas por uma época, mas você pode tentar treinar por mais tempo. Além disso, pode ser interessante separar uma parte do conjunto de dados como conjunto de treinamento, para observar a precisão da validação.\n"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1499/1499 [==============================] - 740s 488ms/step - loss: 0.0667 - acc: 0.9841\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x16f0bb2a310>"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(X_data,Y_data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Testando o Resultado\n",
"\n",
"Agora vamos ver como nosso modelo de reconhecimento de entidades funciona em uma frase de exemplo:\n"
]
},
{
"cell_type": "code",
"execution_count": 91,
"metadata": {},
"outputs": [],
"source": [
"sent = 'John Smith went to Paris to attend a conference in cancer development institute'\n",
"words = sent.lower().split()\n",
"v = keras.preprocessing.sequence.pad_sequences([[word2id[x] for x in words]],padding='post',maxlen=maxlen)\n",
"res = model(v)[0]"
]
},
{
"cell_type": "code",
"execution_count": 92,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"john -> B-per\n",
"smith -> I-per\n",
"went -> O\n",
"to -> O\n",
"paris -> B-geo\n",
"to -> O\n",
"attend -> O\n",
"a -> O\n",
"conference -> O\n",
"in -> O\n",
"cancer -> B-org\n",
"development -> I-org\n",
"institute -> I-org\n"
]
}
],
"source": [
"r = np.argmax(res.numpy(),axis=1)\n",
"for i,w in zip(r,words):\n",
" print(f\"{w} -> {id2tag[i]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Mesmo um modelo LSTM simples apresenta resultados razoáveis em NER. No entanto, para obter resultados muito melhores, você pode querer usar grandes modelos de linguagem pré-treinados, como o BERT. O treinamento do BERT para NER usando a biblioteca Huggingface Transformers está descrito [aqui](https://huggingface.co/course/chapter7/2?fw=pt).\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"orig_nbformat": 4,
"coopTranslator": {
"original_hash": "254d25052dcca4ef84f59a05f2935bdc",
"translation_date": "2025-08-28T14:18:09+00:00",
"source_file": "lessons/5-NLP/19-NER/NER-TF.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,85 @@
# Reconhecimento de Entidades Nomeadas
Até agora, temos nos concentrado principalmente em uma tarefa de PLN - classificação. No entanto, existem outras tarefas de PLN que podem ser realizadas com redes neurais. Uma dessas tarefas é o **[Reconhecimento de Entidades Nomeadas](https://wikipedia.org/wiki/Named-entity_recognition)** (NER), que trata de reconhecer entidades específicas dentro de um texto, como lugares, nomes de pessoas, intervalos de data e hora, fórmulas químicas e assim por diante.
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/37)
## Exemplo de Uso do NER
Suponha que você queira desenvolver um chatbot de linguagem natural, semelhante ao Amazon Alexa ou Google Assistant. A forma como os chatbots inteligentes funcionam é *entendendo* o que o usuário deseja ao realizar a classificação de texto na frase de entrada. O resultado dessa classificação é o chamado **intent**, que determina o que o chatbot deve fazer.
<img alt="Bot NER" src="../../../../../translated_images/pt-BR/bot-ner.4b09235dbb0ad275.webp" width="50%"/>
> Imagem do autor
No entanto, o usuário pode fornecer alguns parâmetros como parte da frase. Por exemplo, ao perguntar sobre o clima, ele pode especificar um local ou uma data. Um bot deve ser capaz de entender essas entidades e preencher os parâmetros adequadamente antes de realizar a ação. É exatamente aqui que o NER entra em ação.
> ✅ Outro exemplo seria [analisar artigos científicos médicos](https://soshnikov.com/science/analyzing-medical-papers-with-azure-and-text-analytics-for-health/). Um dos principais aspectos que precisamos buscar são termos médicos específicos, como doenças e substâncias medicinais. Enquanto um pequeno número de doenças pode ser extraído usando busca por substrings, entidades mais complexas, como compostos químicos e nomes de medicamentos, exigem uma abordagem mais sofisticada.
## NER como Classificação de Tokens
Os modelos de NER são essencialmente **modelos de classificação de tokens**, porque para cada um dos tokens de entrada precisamos decidir se ele pertence a uma entidade ou não, e, se pertence, a qual classe de entidade.
Considere o seguinte título de artigo:
**Regurgitação da válvula tricúspide** e **carbonato de lítio** **toxicidade** em um recém-nascido.
As entidades aqui são:
* Regurgitação da válvula tricúspide é uma doença (`DIS`)
* Carbonato de lítio é uma substância química (`CHEM`)
* Toxicidade também é uma doença (`DIS`)
Observe que uma entidade pode abranger vários tokens. E, como neste caso, precisamos distinguir entre duas entidades consecutivas. Assim, é comum usar duas classes para cada entidade - uma especificando o primeiro token da entidade (frequentemente o prefixo `B-` é usado, para **b**eginning/início), e outra - a continuação de uma entidade (`I-`, para **i**nner token/token interno). Também usamos `O` como uma classe para representar todos os **o**utros tokens. Essa marcação de tokens é chamada de [marcação BIO](https://en.wikipedia.org/wiki/Inside%E2%80%93outside%E2%80%93beginning_(tagging)) (ou IOB). Quando marcada, nosso título ficará assim:
Token | Tag
------|-----
Tricuspid | B-DIS
valve | I-DIS
regurgitation | I-DIS
and | O
lithium | B-CHEM
carbonate | I-CHEM
toxicity | B-DIS
in | O
a | O
newborn | O
infant | O
. | O
Como precisamos construir uma correspondência um-para-um entre tokens e classes, podemos treinar um modelo neural **muitos-para-muitos** da seguinte forma:
![Imagem mostrando padrões comuns de redes neurais recorrentes.](../../../../../translated_images/pt-BR/unreasonable-effectiveness-of-rnn.541ead816778f42d.webp)
> *Imagem do [post no blog](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) de [Andrej Karpathy](http://karpathy.github.io/). Os modelos de classificação de tokens NER correspondem à arquitetura de rede mais à direita nesta imagem.*
## Treinando Modelos de NER
Como um modelo de NER é essencialmente um modelo de classificação de tokens, podemos usar RNNs, com os quais já estamos familiarizados, para essa tarefa. Nesse caso, cada bloco da rede recorrente retornará o ID do token. O notebook de exemplo a seguir mostra como treinar um LSTM para classificação de tokens.
## ✍️ Notebooks de Exemplo: NER
Continue seu aprendizado no seguinte notebook:
* [NER com TensorFlow](NER-TF.ipynb)
## Conclusão
Um modelo de NER é um **modelo de classificação de tokens**, o que significa que ele pode ser usado para realizar classificação de tokens. Essa é uma tarefa muito comum em PLN, ajudando a reconhecer entidades específicas dentro de textos, incluindo lugares, nomes, datas e mais.
## 🚀 Desafio
Complete a tarefa vinculada abaixo para treinar um modelo de reconhecimento de entidades nomeadas para termos médicos e, em seguida, experimente em um conjunto de dados diferente.
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/38)
## Revisão & Autoestudo
Leia o blog [The Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) e siga a seção de Leitura Adicional nesse artigo para aprofundar seu conhecimento.
## [Tarefa](lab/README.md)
Na tarefa desta lição, você terá que treinar um modelo de reconhecimento de entidades médicas. Você pode começar treinando um modelo LSTM conforme descrito nesta lição e, em seguida, avançar para usar o modelo transformer BERT. Leia [as instruções](lab/README.md) para obter todos os detalhes.
---

View File

@ -0,0 +1,50 @@
# NER
Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Neste laboratório, você precisa treinar um modelo de reconhecimento de entidades nomeadas (NER) para termos médicos.
## O Conjunto de Dados
Para treinar o modelo de NER, precisamos de um conjunto de dados devidamente rotulado com entidades médicas. O [conjunto de dados BC5CDR](https://biocreative.bioinformatics.udel.edu/tasks/biocreative-v/track-3-cdr/) contém entidades rotuladas de doenças e produtos químicos extraídas de mais de 1500 artigos. Você pode baixar o conjunto de dados após se registrar no site deles.
O conjunto de dados BC5CDR tem o seguinte formato:
```
6794356|t|Tricuspid valve regurgitation and lithium carbonate toxicity in a newborn infant.
6794356|a|A newborn with massive tricuspid regurgitation, atrial flutter, congestive heart failure, and a high serum lithium level is described. This is the first patient to initially manifest tricuspid regurgitation and atrial flutter, and the 11th described patient with cardiac disease among infants exposed to lithium compounds in the first trimester of pregnancy. Sixty-three percent of these infants had tricuspid valve involvement. Lithium carbonate may be a factor in the increasing incidence of congenital heart disease when taken during early pregnancy. It also causes neurologic depression, cyanosis, and cardiac arrhythmia when consumed prior to delivery.
6794356 0 29 Tricuspid valve regurgitation Disease D014262
6794356 34 51 lithium carbonate Chemical D016651
6794356 52 60 toxicity Disease D064420
...
```
Neste conjunto de dados, há o título e o resumo do artigo nas duas primeiras linhas, e depois há entidades individuais, com posições de início e fim dentro do bloco título+resumo. Além do tipo de entidade, você obtém o ID de ontologia dessa entidade dentro de alguma ontologia médica.
Você precisará escrever algum código em Python para converter isso em codificação BIO.
## A Rede
A primeira tentativa de NER pode ser feita usando uma rede LSTM, como no exemplo que você viu durante a aula. No entanto, em tarefas de PLN, a [arquitetura transformer](https://en.wikipedia.org/wiki/Transformer_(machine_learning_model)), e especificamente os [modelos de linguagem BERT](https://en.wikipedia.org/wiki/BERT_(language_model)), apresentam resultados muito melhores. Modelos BERT pré-treinados entendem a estrutura geral de uma linguagem e podem ser ajustados para tarefas específicas com conjuntos de dados relativamente pequenos e custos computacionais reduzidos.
Como planejamos aplicar NER a um cenário médico, faz sentido usar um modelo BERT treinado em textos médicos. A Microsoft Research lançou um modelo pré-treinado chamado [PubMedBERT][PubMedBERT] ([publicação][PubMedBERT-Pub]), que foi ajustado usando textos do repositório [PubMed](https://pubmed.ncbi.nlm.nih.gov/).
O padrão *de facto* para treinar modelos transformer é a biblioteca [Hugging Face Transformers](https://huggingface.co/). Ela também contém um repositório de modelos pré-treinados mantidos pela comunidade, incluindo o PubMedBERT. Para carregar e usar este modelo, precisamos apenas de algumas linhas de código:
```python
model_name = "microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract"
classes = ... # number of classes: 2*entities+1
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = BertForTokenClassification.from_pretrained(model_name, classes)
```
Isso nos fornece o próprio `model`, construído para a tarefa de classificação de tokens usando o número de `classes`, bem como o objeto `tokenizer`, que pode dividir o texto de entrada em tokens. Você precisará converter o conjunto de dados para o formato BIO, levando em conta a tokenização do PubMedBERT. Você pode usar [este trecho de código Python](https://gist.github.com/shwars/580b55684be3328eb39ecf01b9cbbd88) como inspiração.
## Conclusão
Esta tarefa é muito próxima da tarefa real que você provavelmente terá se quiser obter mais insights sobre grandes volumes de textos em linguagem natural. No nosso caso, podemos aplicar o modelo treinado ao [conjunto de dados de artigos relacionados à COVID](https://www.kaggle.com/allen-institute-for-ai/CORD-19-research-challenge) e ver quais insights podemos obter. [Este post no blog](https://soshnikov.com/science/analyzing-medical-papers-with-azure-and-text-analytics-for-health/) e [este artigo](https://www.mdpi.com/2504-2289/6/1/4) descrevem as pesquisas que podem ser realizadas nesse corpus de artigos usando NER.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,325 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Experimentando com OpenAI GPT\n",
"\n",
"Este notebook faz parte do [Currículo de IA para Iniciantes](http://aka.ms/ai-beginners).\n",
"\n",
"Neste notebook, vamos explorar como podemos interagir com o modelo OpenAI-GPT usando a biblioteca `transformers` da Hugging Face.\n",
"\n",
"Sem mais delongas, vamos instanciar o pipeline de geração de texto e começar a gerar!\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\bethanycheum\\Desktop\\AI-For-Beginners\\.venv\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n",
"Downloading model.safetensors: 100%|██████████| 479M/479M [04:28<00:00, 1.78MB/s] \n",
"c:\\Users\\bethanycheum\\Desktop\\AI-For-Beginners\\.venv\\lib\\site-packages\\huggingface_hub\\file_download.py:133: UserWarning: `huggingface_hub` cache-system uses symlinks by default to efficiently store duplicated files but your machine does not support them in C:\\Users\\bethanycheum\\.cache\\huggingface\\hub. Caching files will still work but in a degraded version that might require more space on your disk. This warning can be disabled by setting the `HF_HUB_DISABLE_SYMLINKS_WARNING` environment variable. For more details, see https://huggingface.co/docs/huggingface_hub/how-to-cache#limitations.\n",
"To support symlinks on Windows, you either need to activate Developer Mode or to run Python as an administrator. In order to see activate developer mode, see this article: https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development\n",
" warnings.warn(message)\n",
"Some weights of OpenAIGPTLMHeadModel were not initialized from the model checkpoint at openai-gpt and are newly initialized: ['position_ids']\n",
"You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
"Downloading (…)neration_config.json: 100%|██████████| 74.0/74.0 [00:00<00:00, 48.8kB/s]\n",
"Downloading (…)olve/main/vocab.json: 100%|██████████| 816k/816k [00:00<00:00, 1.76MB/s]\n",
"Downloading (…)olve/main/merges.txt: 100%|██████████| 458k/458k [00:00<00:00, 1.11MB/s]\n",
"Downloading (…)/main/tokenizer.json: 100%|██████████| 1.27M/1.27M [00:00<00:00, 2.12MB/s]\n",
"Xformers is not installed correctly. If you want to use memory_efficient_attention to accelerate training use the following command to install Xformers\n",
"pip install xformers.\n"
]
},
{
"data": {
"text/plain": [
"[{'generated_text': \"Hello! I am a neural network, and I want to say that i apologize for not coming to you yourself, for not helping you, and that i was too busy getting dressed and studying for a midterm. you know, the kind where the teachers are like that and they come in pairs with their boyfriends, but not with theirs. it's true, that i have had a girlfriend, and i'm only going on wednesdays and thursdays because i was too busy with college, but maybe\"},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that we have been blessed with a wonderful gift ; no one of us has died at all. and our spirits are strong, very strong. in one very lucky moment of luck for you, all has been given direction and destiny, and for us there are no more mysteries. the earth has been chosen for you, and that earth is now ours, and you must be forever in our hearts. \" \\n the words, as one,'},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that if you would just turn and face the general, you would have a nice day. \" \\n \" sure thing, \" said one of the soldiers, and started to run. the rest of the soldiers followed, shouting. the general turned to general zulu, raising his arm. the general said something in his native language, and the general immediately started to run. zulu started to move toward the wall, with the'},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that i am not a doctor but an anthropologist to you, a specialist, a specialist in the field of astrobiological biology, and that i am very much involved in this investigation. i am not sure, i am not certain, but i can confirm your conclusions and therefore i will go to the top. i have a colleague who has just returned from this expedition and his findings confirm that you are a specialist. that is, he'},\n",
" {'generated_text': \"Hello! I am a neural network, and I want to say that everyone here is in agreement that no matter how many times i say to myself,'he was never a man of action on the battlefield,'or'he 'll never take a chance at killing any civilians,'or'he 'll never let his men go undefended against enemy forces of this caliber,'or'that's just what i need in a day like today. \\n you see, there are only three groups that\"}]"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"model_name = 'openai-gpt' \n",
"\n",
"generator = pipeline('text-generation', model=model_name)\n",
"\n",
"generator(\"Hello! I am a neural network, and I want to say that\", max_length=100, num_return_sequences=5)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Engenharia de Prompt\n",
"\n",
"Em alguns problemas, você pode usar a geração do openai-gpt diretamente ao criar prompts adequados. Veja os exemplos abaixo:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'Synonyms of a word cat: the same cat i used to stare at, and you in'},\n",
" {'generated_text': 'Synonyms of a word cat: cat of the woods, cat of the hills, cat of'},\n",
" {'generated_text': 'Synonyms of a word cat: you! \\n \" it\\'s a girl. \" i said'},\n",
" {'generated_text': \"Synonyms of a word cat: big cat. but how come, we didn't hear it\"},\n",
" {'generated_text': 'Synonyms of a word cat: \" mea - o - c \" which makes them sound'}]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"Synonyms of a word cat:\", max_length=20, num_return_sequences=5)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> positive this is so horrible - > positive that your brother is gay - >'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative i will bring this on you -, < positive am i, i'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative i have self - esteem i must take it - : \\n - -'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative this is - : \\n if it were true that the devil would have'},\n",
" {'generated_text': \"I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> positive i have you - > positive it's a bad thing, > positive\"}]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this ->\", max_length=40, num_return_sequences=5)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'Translate English to French: cat => chat, dog => chien, student => new and unusual. there were no more words to be'},\n",
" {'generated_text': 'Translate English to French: cat => chat, dog => chien, student => student \\n his eyes were huge in his lean face as'},\n",
" {'generated_text': \"Translate English to French: cat => chat, dog => chien, student => the teacher's words, their words, their words.\"}]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"Translate English to French: cat => chat, dog => chien, student => \", top_k=50, max_length=30, num_return_sequences=3)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'People who liked the movie The Matrix also liked it, and there was the movie of the first man after us. \\n i wanted to laugh at how stupid these stupid actors were. no, they were'},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie, and the film was the result. and that's when the man in the story was brought into reality, after a few decades. \\n a\"},\n",
" {'generated_text': 'People who liked the movie The Matrix also liked the movie the matrix, because there was a very old movie movie called the matrix, where there was a great super hero, and the super hero came out'},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie that didn't have a chance to pay cash, if they could afford it. most often they got a good deal and a lot of money,\"},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie, and i didn't seem to have the same problem. \\n i 'd met the other half of my family. i spent most of my time\"}]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"People who liked the movie The Matrix also liked \", max_length=40, num_return_sequences=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Estratégias de Amostragem de Texto\n",
"\n",
"Até agora, temos utilizado uma estratégia de amostragem **gananciosa**, onde selecionamos a próxima palavra com base na maior probabilidade. Veja como funciona:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw my friend, a young man, sprawled across the bed in his bed. \\n \" hi, i\\'m mike eptirard. \" \\n there was silence on the other side of the door. i listened for any trace of life but there was nothing. my heart began to pound, i was starting to sweat, i took out my wallet'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw my mother on the bed, hugging her legs to her chest and sobbing. i saw my dad and mother from the corner of my eye. \\n elfin face was covered in tears as i entered the room. my dad and mother also wept ; just as they did every other time i came to work. but this time, they had different faces'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw the room had changed because it was dark. it still smelled like a hospital. a new light shined through from a vent in the ceiling. i found myself in a bathroom and a small room with a sink and a wall of glass. the bathroom billion years ago. not so different from all of the rest of the apartment. \\n now...'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a large woman with dark hair and pale skin. she was asleep, but i noticed a faint movement of her face. i could sense she was awake. i got up and walked over to her. \\n \" hello miss. i am inspector michael o\\'dell ; we are investigating the case against you. i wanted to ask if you were the'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw i had an empty table and three empty chairs. that was all i needed. i had left a note on a table in the center of the room and had a pen in hand. \" \\n \" i think what you were doing was something he was doing to her. \" \\n \" yeah, \" i nodded with a grin. \" i'}]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,num_return_sequences=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Beam Search** permite que o gerador explore várias direções (*beams*) de geração de texto e selecione aquelas com maior pontuação geral. Você pode realizar beam search fornecendo o parâmetro `num_beams`. Você também pode especificar `no_repeat_ngram_size` para penalizar o modelo por repetir n-grams de um tamanho específico:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting in a chair with his head in his hands. he didn\\'t look up as i approached. \\n \" excuse me, sir, \" i said. \" can i help you? \" \\n the man looked up at me. his eyes were red - rimmed and his face was pale, as if he hadn\\'t slept in days'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting at a desk in the middle of the room. he had his back to me, so i couldn\\'t see what he was doing. \" \\n \" what did he look like? \" i asked as i sat down on the bed next to her. \\n she took a deep breath and looked at me with tears in her eyes'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a woman sitting on the bed, reading a book. she looked up at me and smiled. \\n \" hi, \" she said. \" can i help you? \" \\n i sat down next to her and looked around the room. the walls were white, and there was a large window in the middle of the wall that looked out on'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting at a table in the middle of the room. he looked up as i walked in, and when he saw me, he got up and walked over to me. \\n \" can i help you? \" he asked as he put his hand on the small of my back and led me to a chair at the other end of'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a woman sitting on the edge of her bed, reading a book. she looked up at me and smiled. \\n \" hello, \" she said. \" can i help you? \" \\n i didn\\'t know what to say, so i just sat down in the chair next to the bed and looked at her. her hair was dark brown'}]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,num_return_sequences=5,num_beams=10,no_repeat_ngram_size=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Amostragem** seleciona a próxima palavra de forma não determinística, usando a distribuição de probabilidade retornada pelo modelo. Você ativa a amostragem usando o parâmetro `do_sample=True`. Você também pode especificar a `temperature`, para tornar o modelo mais ou menos determinístico.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw her. she was on the bed, but she looked very different. \\n \" honey, what\\'s the matter? \" i asked. \\n she sat up. \" i can\\'t believe it\\'s real. i\\'ve been dreaming about you for the last two days. \" \\n \" i can\\'t believe it either. i guess that\\'s how'}]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,do_sample=True,temperature=0.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Também podemos fornecer parâmetros adicionais para a amostragem: \n",
"* `top_k` especifica o número de opções de palavras a considerar ao usar a amostragem. Isso minimiza a chance de obter palavras estranhas (de baixa probabilidade) em nosso texto. \n",
"* `top_p` é semelhante, mas escolhemos o menor subconjunto de palavras mais prováveis, cuja probabilidade total seja maior que p. \n",
"\n",
"Sinta-se à vontade para experimentar adicionando esses parâmetros. \n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ajustando seus modelos\n",
"\n",
"Você também pode [ajustar seu modelo](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/fine-tuning?pivots=programming-language-studio?WT.mc_id=academic-77998-bethanycheum) com seu próprio conjunto de dados. Isso permitirá que você adapte o estilo do texto, enquanto mantém a maior parte do modelo de linguagem.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
},
"orig_nbformat": 4,
"coopTranslator": {
"original_hash": "d4ff89615d38924a55594f16d6d20678",
"translation_date": "2025-08-28T14:16:56+00:00",
"source_file": "lessons/5-NLP/20-LangModels/GPT-PyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,55 @@
# Modelos de Linguagem de Grande Escala Pré-Treinados
Em todas as nossas tarefas anteriores, treinamos uma rede neural para realizar uma determinada tarefa usando um conjunto de dados rotulado. Com grandes modelos transformadores, como o BERT, utilizamos modelagem de linguagem de forma autossupervisionada para construir um modelo de linguagem, que é então especializado para tarefas específicas com treinamento adicional em domínios específicos. No entanto, foi demonstrado que grandes modelos de linguagem também podem resolver muitas tarefas sem QUALQUER treinamento específico de domínio. Uma família de modelos capaz de fazer isso é chamada de **GPT**: Transformador Generativo Pré-Treinado.
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/39)
## Geração de Texto e Perplexidade
A ideia de uma rede neural ser capaz de realizar tarefas gerais sem treinamento adicional é apresentada no artigo [Language Models are Unsupervised Multitask Learners](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf). A ideia principal é que muitas outras tarefas podem ser modeladas usando **geração de texto**, porque compreender texto essencialmente significa ser capaz de produzi-lo. Como o modelo é treinado em uma enorme quantidade de texto que abrange o conhecimento humano, ele também se torna conhecedor de uma ampla variedade de assuntos.
> Compreender e ser capaz de produzir texto também implica saber algo sobre o mundo ao nosso redor. As pessoas também aprendem muito lendo, e a rede GPT é semelhante nesse aspecto.
Redes de geração de texto funcionam prevendo a probabilidade da próxima palavra $$P(w_N)$$. No entanto, a probabilidade incondicional da próxima palavra é igual à frequência dessa palavra no corpus de texto. O GPT é capaz de nos fornecer a **probabilidade condicional** da próxima palavra, dado as palavras anteriores: $$P(w_N | w_{n-1}, ..., w_0)$$
> Você pode ler mais sobre probabilidades em nosso [Currículo de Ciência de Dados para Iniciantes](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/1-Introduction/04-stats-and-probability).
A qualidade de um modelo de geração de linguagem pode ser definida usando a **perplexidade**. É uma métrica intrínseca que nos permite medir a qualidade do modelo sem qualquer conjunto de dados específico para a tarefa. Ela se baseia na noção de *probabilidade de uma sentença* - o modelo atribui alta probabilidade a uma sentença que provavelmente é real (ou seja, o modelo não está **perplexo** com ela) e baixa probabilidade a sentenças que fazem menos sentido (por exemplo, *Pode isso faz o quê?*). Quando fornecemos ao nosso modelo sentenças de um corpus de texto real, esperamos que elas tenham alta probabilidade e baixa **perplexidade**. Matematicamente, é definida como a probabilidade inversa normalizada do conjunto de teste:
$$
\mathrm{Perplexity}(W) = \sqrt[N]{1\over P(W_1,...,W_N)}
$$
**Você pode experimentar a geração de texto usando o [editor de texto baseado em GPT da Hugging Face](https://transformer.huggingface.co/doc/gpt2-large)**. Neste editor, você começa a escrever seu texto e, ao pressionar **[TAB]**, várias opções de conclusão serão oferecidas. Se forem muito curtas ou você não estiver satisfeito com elas, pressione [TAB] novamente, e você terá mais opções, incluindo trechos de texto mais longos.
## GPT é uma Família
O GPT não é um único modelo, mas sim uma coleção de modelos desenvolvidos e treinados pela [OpenAI](https://openai.com).
Dentro da família de modelos GPT, temos:
| [GPT-2](https://huggingface.co/docs/transformers/model_doc/gpt2#openai-gpt2) | [GPT-3](https://openai.com/research/language-models-are-few-shot-learners) | [GPT-4](https://openai.com/gpt-4) |
| -- | -- | -- |
| Modelo de linguagem com até 1,5 bilhões de parâmetros. | Modelo de linguagem com até 175 bilhões de parâmetros. | 100 trilhões de parâmetros, aceita entradas de texto e imagem, e gera saídas em texto. |
Os modelos GPT-3 e GPT-4 estão disponíveis [como um serviço cognitivo da Microsoft Azure](https://azure.microsoft.com/en-us/services/cognitive-services/openai-service/#overview?WT.mc_id=academic-77998-cacaste) e também como [API da OpenAI](https://openai.com/api/).
## Engenharia de Prompt
Como o GPT foi treinado em grandes volumes de dados para compreender linguagem e código, ele fornece saídas em resposta a entradas (prompts). Prompts são entradas ou consultas para o GPT, onde se fornecem instruções aos modelos sobre as tarefas a serem realizadas. Para obter o resultado desejado, é necessário criar o prompt mais eficaz, o que envolve selecionar as palavras, formatos, frases ou até mesmo símbolos corretos. Essa abordagem é chamada de [Engenharia de Prompt](https://learn.microsoft.com/en-us/shows/ai-show/the-basics-of-prompt-engineering-with-azure-openai-service?WT.mc_id=academic-77998-bethanycheum).
[Esta documentação](https://learn.microsoft.com/en-us/semantic-kernel/prompt-engineering/?WT.mc_id=academic-77998-bethanycheum) fornece mais informações sobre engenharia de prompt.
## ✍️ Notebook de Exemplo: [Experimentando com OpenAI-GPT](GPT-PyTorch.ipynb)
Continue seu aprendizado nos seguintes notebooks:
* [Gerando texto com OpenAI-GPT e Hugging Face Transformers](GPT-PyTorch.ipynb)
## Conclusão
Novos modelos de linguagem geral pré-treinados não apenas modelam a estrutura da linguagem, mas também contêm uma vasta quantidade de linguagem natural. Assim, eles podem ser usados de forma eficaz para resolver algumas tarefas de PLN em configurações de zero-shot ou few-shot.
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/40)
---

View File

@ -0,0 +1,69 @@
# Processamento de Linguagem Natural
![Resumo das tarefas de PLN em um desenho](../../../../translated_images/pt-BR/ai-nlp.b22dcb8ca4707cea.webp)
Nesta seção, vamos focar no uso de Redes Neurais para lidar com tarefas relacionadas ao **Processamento de Linguagem Natural (PLN)**. Existem muitos problemas de PLN que queremos que os computadores sejam capazes de resolver:
* **Classificação de texto** é um problema típico de classificação relacionado a sequências de texto. Exemplos incluem classificar mensagens de e-mail como spam ou não-spam, ou categorizar artigos como esportes, negócios, política, etc. Além disso, ao desenvolver chatbots, frequentemente precisamos entender o que o usuário quis dizer — nesse caso, estamos lidando com **classificação de intenção**. Muitas vezes, na classificação de intenção, precisamos lidar com muitas categorias.
* **Análise de sentimento** é um problema típico de regressão, onde precisamos atribuir um número (um sentimento) correspondente ao quão positivo/negativo é o significado de uma frase. Uma versão mais avançada da análise de sentimento é a **análise de sentimento baseada em aspectos** (ABSA), onde atribuímos o sentimento não à frase inteira, mas a diferentes partes dela (aspectos), por exemplo: *Neste restaurante, gostei da culinária, mas a atmosfera era horrível*.
* **Reconhecimento de Entidades Nomeadas** (NER) refere-se ao problema de extrair certas entidades de um texto. Por exemplo, podemos precisar entender que na frase *Preciso voar para Paris amanhã* a palavra *amanhã* refere-se a uma DATA, e *Paris* é um LOCAL.
* **Extração de palavras-chave** é semelhante ao NER, mas precisamos extrair palavras importantes para o significado da frase automaticamente, sem pré-treinamento para tipos específicos de entidades.
* **Agrupamento de texto** pode ser útil quando queremos agrupar frases semelhantes, por exemplo, solicitações similares em conversas de suporte técnico.
* **Resposta a perguntas** refere-se à capacidade de um modelo de responder a uma pergunta específica. O modelo recebe um trecho de texto e uma pergunta como entradas, e precisa fornecer um local no texto onde a resposta à pergunta está contida (ou, às vezes, gerar o texto da resposta).
* **Geração de texto** é a capacidade de um modelo de gerar novo texto. Pode ser considerado como uma tarefa de classificação que prevê a próxima letra/palavra com base em algum *texto inicial*. Modelos avançados de geração de texto, como o GPT-3, são capazes de resolver outras tarefas de PLN usando uma técnica chamada [programação de prompts](https://towardsdatascience.com/software-3-0-how-prompting-will-change-the-rules-of-the-game-a982fbfe1e0) ou [engenharia de prompts](https://medium.com/swlh/openai-gpt-3-and-prompt-engineering-dcdc2c5fcd29).
* **Resumo de texto** é uma técnica em que queremos que um computador "leia" um texto longo e o resuma em algumas frases.
* **Tradução automática** pode ser vista como uma combinação de compreensão de texto em um idioma e geração de texto em outro.
Inicialmente, a maioria das tarefas de PLN era resolvida usando métodos tradicionais, como gramáticas. Por exemplo, na tradução automática, analisadores eram usados para transformar a frase inicial em uma árvore sintática, depois estruturas semânticas de nível superior eram extraídas para representar o significado da frase, e com base nesse significado e na gramática do idioma de destino, o resultado era gerado. Hoje em dia, muitas tarefas de PLN são resolvidas de forma mais eficaz usando redes neurais.
> Muitos métodos clássicos de PLN estão implementados na biblioteca Python [Natural Language Processing Toolkit (NLTK)](https://www.nltk.org). Há um excelente [Livro do NLTK](https://www.nltk.org/book/) disponível online que cobre como diferentes tarefas de PLN podem ser resolvidas usando o NLTK.
Em nosso curso, vamos focar principalmente no uso de Redes Neurais para PLN, e usaremos o NLTK quando necessário.
Já aprendemos sobre o uso de redes neurais para lidar com dados tabulares e imagens. A principal diferença entre esses tipos de dados e texto é que o texto é uma sequência de comprimento variável, enquanto o tamanho da entrada no caso de imagens é conhecido antecipadamente. Embora redes convolucionais possam extrair padrões de dados de entrada, os padrões em texto são mais complexos. Por exemplo, podemos ter uma negação separada do sujeito por muitas palavras arbitrárias (ex.: *Eu não gosto de laranjas*, vs. *Eu não gosto dessas grandes laranjas coloridas e saborosas*), e isso ainda deve ser interpretado como um único padrão. Assim, para lidar com a linguagem, precisamos introduzir novos tipos de redes neurais, como *redes recorrentes* e *transformers*.
## Instalar Bibliotecas
Se você estiver usando uma instalação local do Python para executar este curso, pode ser necessário instalar todas as bibliotecas necessárias para PLN usando os seguintes comandos:
**Para PyTorch**
```bash
pip install -r requirements-torch.txt
```
**Para TensorFlow**
```bash
pip install -r requirements-tf.txt
```
> Você pode experimentar PLN com TensorFlow no [Microsoft Learn](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-tensorflow/?WT.mc_id=academic-77998-cacaste)
## Aviso sobre GPU
Nesta seção, em alguns dos exemplos, treinaremos modelos bastante grandes.
* **Use um computador com GPU**: É recomendável executar seus notebooks em um computador com GPU para reduzir o tempo de espera ao trabalhar com modelos grandes.
* **Restrições de memória da GPU**: Executar em uma GPU pode levar a situações em que você fique sem memória da GPU, especialmente ao treinar modelos grandes.
* **Consumo de memória da GPU**: A quantidade de memória da GPU consumida durante o treinamento depende de vários fatores, incluindo o tamanho do minibatch.
* **Minimize o tamanho do minibatch**: Se você encontrar problemas de memória da GPU, considere reduzir o tamanho do minibatch em seu código como uma solução potencial.
* **Liberação de memória da GPU no TensorFlow**: Versões mais antigas do TensorFlow podem não liberar corretamente a memória da GPU ao treinar vários modelos dentro de um único kernel Python. Para gerenciar o uso de memória da GPU de forma eficaz, você pode configurar o TensorFlow para alocar memória da GPU apenas conforme necessário.
* **Inclusão de código**: Para configurar o TensorFlow para aumentar a alocação de memória da GPU apenas quando necessário, inclua o seguinte código em seus notebooks:
```python
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices)>0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
```
Se você estiver interessado em aprender sobre PLN a partir de uma perspectiva de aprendizado de máquina clássico, visite [esta coleção de lições](https://github.com/microsoft/ML-For-Beginners/tree/main/6-NLP).
## Nesta Seção
Nesta seção, aprenderemos sobre:
* [Representação de texto como tensores](13-TextRep/README.md)
* [Embeddings de palavras](14-Emdeddings/README.md)
* [Modelagem de linguagem](15-LanguageModeling/README.md)
* [Redes Neurais Recorrentes](16-RNN/README.md)
* [Redes Generativas](17-GenerativeNetworks/README.md)
* [Transformers](18-Transformers/README.md)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,49 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tarefa: Equações Diofantinas\n",
"\n",
"> Esta tarefa faz parte do [Currículo de IA para Iniciantes](http://github.com/microsoft/ai-for-beginners) e foi inspirada por [este post](https://habr.com/post/128704/).\n",
"\n",
"Seu objetivo é resolver a chamada **equação diofantina** - uma equação com raízes inteiras e coeficientes inteiros. Por exemplo, considere a seguinte equação:\n",
"\n",
"$$a+2b+3c+4d=30$$\n",
"\n",
"Você precisa encontrar raízes inteiras $a$,$b$,$c$,$d\\in\\mathbb{N}$ que satisfaçam esta equação.\n",
"\n",
"Dicas:\n",
"1. Você pode considerar as raízes no intervalo [0;30]\n",
"1. Como um gene, considere usar a lista de valores das raízes\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
},
"orig_nbformat": 4,
"coopTranslator": {
"original_hash": "a967e1fa1e11ab2b6467b19349a4a9aa",
"translation_date": "2025-08-28T12:43:10+00:00",
"source_file": "lessons/6-Other/21-GeneticAlgorithms/Diophantine.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,80 @@
# Algoritmos Genéticos
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/41)
**Algoritmos Genéticos** (AG) são baseados em uma **abordagem evolucionária** para IA, na qual métodos de evolução de uma população são usados para obter uma solução ótima para um problema específico. Eles foram propostos em 1975 por [John Henry Holland](https://wikipedia.org/wiki/John_Henry_Holland).
Os Algoritmos Genéticos são baseados nas seguintes ideias:
* Soluções válidas para o problema podem ser representadas como **genes**
* O **Crossover** permite combinar duas soluções para obter uma nova solução válida
* A **Seleção** é usada para escolher as soluções mais ótimas utilizando alguma **função de aptidão**
* **Mutações** são introduzidas para desestabilizar a otimização e nos tirar de mínimos locais
Se você quiser implementar um Algoritmo Genético, precisará do seguinte:
* Encontrar um método para codificar as soluções do problema usando **genes** g&in;&Gamma;
* No conjunto de genes &Gamma;, é necessário definir uma **função de aptidão** fit: &Gamma;&rightarrow;**R**. Valores menores da função correspondem a melhores soluções.
* Definir um mecanismo de **crossover** para combinar dois genes e obter uma nova solução válida crossover: &Gamma;<sup>2</sub>&rightarrow;&Gamma;.
* Definir um mecanismo de **mutação** mutate: &Gamma;&rightarrow;&Gamma;.
Em muitos casos, os algoritmos de crossover e mutação são bastante simples para manipular genes como sequências numéricas ou vetores de bits.
A implementação específica de um algoritmo genético pode variar de caso para caso, mas a estrutura geral é a seguinte:
1. Selecionar uma população inicial G&subset;&Gamma;
2. Selecionar aleatoriamente uma das operações que será realizada nesta etapa: crossover ou mutação
3. **Crossover**:
* Selecionar aleatoriamente dois genes g<sub>1</sub>, g<sub>2</sub> &in; G
* Calcular o crossover g=crossover(g<sub>1</sub>,g<sub>2</sub>)
* Se fit(g)<fit(g<sub>1</sub>) ou fit(g)<fit(g<sub>2</sub>) - substituir o gene correspondente na população por g.
4. **Mutação** - selecionar um gene aleatório g&in;G e substituí-lo por mutate(g)
5. Repetir a partir do passo 2, até obtermos um valor suficientemente pequeno de fit, ou até que o limite de número de etapas seja alcançado.
## Tarefas Típicas
As tarefas tipicamente resolvidas por Algoritmos Genéticos incluem:
1. Otimização de cronogramas
1. Empacotamento ótimo
1. Corte ótimo
1. Aceleração de busca exaustiva
## ✍️ Exercícios: Algoritmos Genéticos
Continue seu aprendizado nos seguintes notebooks:
Acesse [este notebook](Genetic.ipynb) para ver dois exemplos de uso de Algoritmos Genéticos:
1. Divisão justa de tesouro
1. Problema das 8 Rainhas
## Conclusão
Os Algoritmos Genéticos são usados para resolver muitos problemas, incluindo logística e problemas de busca. O campo é inspirado por pesquisas que uniram tópicos de Psicologia e Ciência da Computação.
## 🚀 Desafio
"Algoritmos genéticos são simples de implementar, mas seu comportamento é difícil de entender." [fonte](https://wikipedia.org/wiki/Genetic_algorithm) Faça uma pesquisa para encontrar uma implementação de um algoritmo genético, como resolver um quebra-cabeça de Sudoku, e explique como ele funciona em forma de esboço ou fluxograma.
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/42)
## Revisão & Autoestudo
Assista a [este ótimo vídeo](https://www.youtube.com/watch?v=qv6UVOQ0F44) que fala sobre como computadores podem aprender a jogar Super Mario usando redes neurais treinadas por algoritmos genéticos. Aprenderemos mais sobre computadores aprendendo a jogar jogos como esse [na próxima seção](../22-DeepRL/README.md).
## [Tarefa: Equação Diofantina](Diophantine.ipynb)
Seu objetivo é resolver a chamada **equação diofantina** - uma equação com raízes inteiras. Por exemplo, considere a equação a+2b+3c+4d=30. Você precisa encontrar as raízes inteiras que satisfazem essa equação.
*Esta tarefa é inspirada por [este post](https://habr.com/post/128704/).*
Dicas:
1. Você pode considerar raízes no intervalo [0;30]
1. Como gene, considere usar a lista de valores das raízes
Use [Diophantine.ipynb](Diophantine.ipynb) como ponto de partida.
---

View File

@ -0,0 +1,501 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Treinando RL para equilibrar o Cartpole\n",
"\n",
"Este notebook faz parte do [Currículo de IA para Iniciantes](http://aka.ms/ai-beginners). Ele foi inspirado pelo [tutorial oficial do PyTorch](https://pytorch.org/tutorials/intermediate/reinforcement_q_learning.html) e por [esta implementação de Cartpole em PyTorch](https://github.com/yc930401/Actor-Critic-pytorch).\n",
"\n",
"Neste exemplo, usaremos RL para treinar um modelo a equilibrar um poste em um carrinho que pode se mover para a esquerda e para a direita em uma escala horizontal. Utilizaremos o ambiente [OpenAI Gym](https://www.gymlibrary.ml/) para simular o poste.\n",
"\n",
"> **Nota**: Você pode executar o código desta lição localmente (por exemplo, no Visual Studio Code), caso em que a simulação será aberta em uma nova janela. Ao executar o código online, pode ser necessário fazer alguns ajustes no código, conforme descrito [aqui](https://towardsdatascience.com/rendering-openai-gym-envs-on-binder-and-google-colab-536f99391cc7).\n",
"\n",
"Começaremos garantindo que o Gym esteja instalado:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install gym"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos criar o ambiente CartPole e ver como operá-lo. Um ambiente possui as seguintes propriedades:\n",
"\n",
"* **Action space** é o conjunto de ações possíveis que podemos realizar em cada etapa da simulação\n",
"* **Observation space** é o espaço de observações que podemos fazer\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import gym\n",
"\n",
"env = gym.make(\"CartPole-v1\")\n",
"\n",
"print(f\"Action space: {env.action_space}\")\n",
"print(f\"Observation space: {env.observation_space}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos ver como a simulação funciona. O loop a seguir executa a simulação até que `env.step` não retorne o sinal de término `done`. Escolheremos ações aleatoriamente usando `env.action_space.sample()`, o que significa que o experimento provavelmente falhará muito rápido (o ambiente CartPole termina quando a velocidade do CartPole, sua posição ou ângulo estão fora de certos limites).\n",
"\n",
"> A simulação será aberta em uma nova janela. Você pode executar o código várias vezes e observar como ele se comporta.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"\n",
"done = False\n",
"total_reward = 0\n",
"while not done:\n",
" env.render()\n",
" obs, rew, done, info = env.step(env.action_space.sample())\n",
" total_reward += rew\n",
" print(f\"{obs} -> {rew}\")\n",
"print(f\"Total reward: {total_reward}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Você pode notar que as observações contêm 4 números. São eles:\n",
"- Posição do carrinho\n",
"- Velocidade do carrinho\n",
"- Ângulo da haste\n",
"- Taxa de rotação da haste\n",
"\n",
"`rew` é a recompensa que recebemos a cada passo. No ambiente CartPole, você recebe 1 ponto de recompensa por cada passo de simulação, e o objetivo é maximizar a recompensa total, ou seja, o tempo que o CartPole consegue se equilibrar sem cair.\n",
"\n",
"Durante o aprendizado por reforço, nosso objetivo é treinar uma **política** $\\pi$, que para cada estado $s$ nos dirá qual ação $a$ tomar, essencialmente $a = \\pi(s)$.\n",
"\n",
"Se você quiser uma solução probabilística, pode pensar na política como retornando um conjunto de probabilidades para cada ação, ou seja, $\\pi(a|s)$ significaria a probabilidade de tomarmos a ação $a$ no estado $s$.\n",
"\n",
"## Método de Gradiente de Política\n",
"\n",
"No algoritmo mais simples de RL, chamado **Gradiente de Política**, treinaremos uma rede neural para prever a próxima ação.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import torch\n",
"\n",
"num_inputs = 4\n",
"num_actions = 2\n",
"\n",
"model = torch.nn.Sequential(\n",
" torch.nn.Linear(num_inputs, 128, bias=False, dtype=torch.float32),\n",
" torch.nn.ReLU(),\n",
" torch.nn.Linear(128, num_actions, bias = False, dtype=torch.float32),\n",
" torch.nn.Softmax(dim=1)\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos treinar a rede executando muitos experimentos e atualizando nossa rede após cada execução. Vamos definir uma função que executará o experimento e retornará os resultados (o chamado **rastro**) - todos os estados, ações (e suas probabilidades recomendadas) e recompensas:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def run_episode(max_steps_per_episode = 10000,render=False): \n",
" states, actions, probs, rewards = [],[],[],[]\n",
" state = env.reset()\n",
" for _ in range(max_steps_per_episode):\n",
" if render:\n",
" env.render()\n",
" action_probs = model(torch.from_numpy(np.expand_dims(state,0)))[0]\n",
" action = np.random.choice(num_actions, p=np.squeeze(action_probs.detach().numpy()))\n",
" nstate, reward, done, info = env.step(action)\n",
" if done:\n",
" break\n",
" states.append(state)\n",
" actions.append(action)\n",
" probs.append(action_probs.detach().numpy())\n",
" rewards.append(reward)\n",
" state = nstate\n",
" return np.vstack(states), np.vstack(actions), np.vstack(probs), np.vstack(rewards)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Você pode executar um episódio com a rede não treinada e observar que a recompensa total (também conhecida como duração do episódio) é muito baixa:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"s, a, p, r = run_episode()\n",
"print(f\"Total reward: {np.sum(r)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Um dos aspectos complicados do algoritmo de gradiente de política é usar **recompensas descontadas**. A ideia é que calculamos o vetor de recompensas totais em cada etapa do jogo e, durante esse processo, descontamos as recompensas iniciais usando algum coeficiente $gamma$. Também normalizamos o vetor resultante, porque o utilizaremos como peso para afetar nosso treinamento:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"eps = 0.0001\n",
"\n",
"def discounted_rewards(rewards,gamma=0.99,normalize=True):\n",
" ret = []\n",
" s = 0\n",
" for r in rewards[::-1]:\n",
" s = r + gamma * s\n",
" ret.insert(0, s)\n",
" if normalize:\n",
" ret = (ret-np.mean(ret))/(np.std(ret)+eps)\n",
" return ret"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos começar o treinamento! Executaremos 300 episódios, e em cada episódio faremos o seguinte:\n",
"\n",
"1. Executar o experimento e coletar o rastreamento\n",
"1. Calcular a diferença (`gradients`) entre as ações realizadas e as probabilidades previstas. Quanto menor for a diferença, mais certeza teremos de que tomamos a ação correta.\n",
"1. Calcular as recompensas descontadas e multiplicar os gradientes pelas recompensas descontadas - isso garantirá que os passos com recompensas mais altas tenham maior impacto no resultado final do que aqueles com recompensas mais baixas.\n",
"1. As ações-alvo esperadas para nossa rede neural serão parcialmente derivadas das probabilidades previstas durante a execução e parcialmente dos gradientes calculados. Usaremos o parâmetro `alpha` para determinar em que medida os gradientes e recompensas serão levados em conta - isso é chamado de *taxa de aprendizado* do algoritmo de reforço.\n",
"1. Por fim, treinamos nossa rede com os estados e ações esperadas, e repetimos o processo.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"optimizer = torch.optim.Adam(model.parameters(), lr=0.01)\n",
"\n",
"def train_on_batch(x, y):\n",
" x = torch.from_numpy(x)\n",
" y = torch.from_numpy(y)\n",
" optimizer.zero_grad()\n",
" predictions = model(x)\n",
" loss = -torch.mean(torch.log(predictions) * y)\n",
" loss.backward()\n",
" optimizer.step()\n",
" return loss"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"alpha = 1e-4\n",
"\n",
"history = []\n",
"for epoch in range(300):\n",
" states, actions, probs, rewards = run_episode()\n",
" one_hot_actions = np.eye(2)[actions.T][0]\n",
" gradients = one_hot_actions-probs\n",
" dr = discounted_rewards(rewards)\n",
" gradients *= dr\n",
" target = alpha*np.vstack([gradients])+probs\n",
" train_on_batch(states,target)\n",
" history.append(np.sum(rewards))\n",
" if epoch%100==0:\n",
" print(f\"{epoch} -> {np.sum(rewards)}\")\n",
"\n",
"plt.plot(history)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos executar o episódio com renderização para ver o resultado:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"_ = run_episode(render=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Espero que você possa ver que o poste agora consegue se equilibrar muito bem!\n",
"\n",
"## Modelo Ator-Crítico\n",
"\n",
"O modelo Ator-Crítico é um desenvolvimento adicional dos gradientes de política, no qual construímos uma rede neural para aprender tanto a política quanto as recompensas estimadas. A rede terá duas saídas (ou você pode vê-la como duas redes separadas):\n",
"* **Ator** recomendará a ação a ser tomada, fornecendo a distribuição de probabilidade do estado, como no modelo de gradiente de política.\n",
"* **Crítico** estimará qual seria a recompensa dessas ações. Ele retorna as recompensas totais estimadas no futuro para o estado dado.\n",
"\n",
"Vamos definir um modelo assim:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from itertools import count\n",
"import torch.nn.functional as F"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"env = gym.make(\"CartPole-v1\")\n",
"\n",
"state_size = env.observation_space.shape[0]\n",
"action_size = env.action_space.n\n",
"lr = 0.0001\n",
"\n",
"class Actor(torch.nn.Module):\n",
" def __init__(self, state_size, action_size):\n",
" super(Actor, self).__init__()\n",
" self.state_size = state_size\n",
" self.action_size = action_size\n",
" self.linear1 = torch.nn.Linear(self.state_size, 128)\n",
" self.linear2 = torch.nn.Linear(128, 256)\n",
" self.linear3 = torch.nn.Linear(256, self.action_size)\n",
"\n",
" def forward(self, state):\n",
" output = F.relu(self.linear1(state))\n",
" output = F.relu(self.linear2(output))\n",
" output = self.linear3(output)\n",
" distribution = torch.distributions.Categorical(F.softmax(output, dim=-1))\n",
" return distribution\n",
"\n",
"\n",
"class Critic(torch.nn.Module):\n",
" def __init__(self, state_size, action_size):\n",
" super(Critic, self).__init__()\n",
" self.state_size = state_size\n",
" self.action_size = action_size\n",
" self.linear1 = torch.nn.Linear(self.state_size, 128)\n",
" self.linear2 = torch.nn.Linear(128, 256)\n",
" self.linear3 = torch.nn.Linear(256, 1)\n",
"\n",
" def forward(self, state):\n",
" output = F.relu(self.linear1(state))\n",
" output = F.relu(self.linear2(output))\n",
" value = self.linear3(output)\n",
" return value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Precisaríamos modificar ligeiramente nossas funções `discounted_rewards` e `run_episode`:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def discounted_rewards(next_value, rewards, masks, gamma=0.99):\n",
" R = next_value\n",
" returns = []\n",
" for step in reversed(range(len(rewards))):\n",
" R = rewards[step] + gamma * R * masks[step]\n",
" returns.insert(0, R)\n",
" return returns\n",
"\n",
"def run_episode(actor, critic, n_iters):\n",
" optimizerA = torch.optim.Adam(actor.parameters())\n",
" optimizerC = torch.optim.Adam(critic.parameters())\n",
" for iter in range(n_iters):\n",
" state = env.reset()\n",
" log_probs = []\n",
" values = []\n",
" rewards = []\n",
" masks = []\n",
" entropy = 0\n",
" env.reset()\n",
"\n",
" for i in count():\n",
" env.render()\n",
" state = torch.FloatTensor(state).to(device)\n",
" dist, value = actor(state), critic(state)\n",
"\n",
" action = dist.sample()\n",
" next_state, reward, done, _ = env.step(action.cpu().numpy())\n",
"\n",
" log_prob = dist.log_prob(action).unsqueeze(0)\n",
" entropy += dist.entropy().mean()\n",
"\n",
" log_probs.append(log_prob)\n",
" values.append(value)\n",
" rewards.append(torch.tensor([reward], dtype=torch.float, device=device))\n",
" masks.append(torch.tensor([1-done], dtype=torch.float, device=device))\n",
"\n",
" state = next_state\n",
"\n",
" if done:\n",
" print('Iteration: {}, Score: {}'.format(iter, i))\n",
" break\n",
"\n",
"\n",
" next_state = torch.FloatTensor(next_state).to(device)\n",
" next_value = critic(next_state)\n",
" returns = discounted_rewards(next_value, rewards, masks)\n",
"\n",
" log_probs = torch.cat(log_probs)\n",
" returns = torch.cat(returns).detach()\n",
" values = torch.cat(values)\n",
"\n",
" advantage = returns - values\n",
"\n",
" actor_loss = -(log_probs * advantage.detach()).mean()\n",
" critic_loss = advantage.pow(2).mean()\n",
"\n",
" optimizerA.zero_grad()\n",
" optimizerC.zero_grad()\n",
" actor_loss.backward()\n",
" critic_loss.backward()\n",
" optimizerA.step()\n",
" optimizerC.step()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos executar o loop principal de treinamento. Usaremos o processo manual de treinamento da rede, calculando funções de perda adequadas e atualizando os parâmetros da rede:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"actor = Actor(state_size, action_size).to(device)\n",
"critic = Critic(state_size, action_size).to(device)\n",
"run_episode(actor, critic, n_iters=100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Vimos dois algoritmos de aprendizado por reforço (RL) nesta demonstração: o gradiente de política simples e o mais sofisticado ator-crítico. Você pode perceber que esses algoritmos operam com noções abstratas de estado, ação e recompensa - o que significa que podem ser aplicados a ambientes muito diferentes.\n",
"\n",
"O aprendizado por reforço nos permite descobrir a melhor estratégia para resolver um problema apenas observando a recompensa final. O fato de não precisarmos de conjuntos de dados rotulados nos permite repetir simulações várias vezes para otimizar nossos modelos. No entanto, ainda existem muitos desafios no aprendizado por reforço, que você pode explorar caso decida se aprofundar mais nessa área fascinante da inteligência artificial.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.10.4 64-bit",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.4"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
}
},
"coopTranslator": {
"original_hash": "04f8d9978cd11281d81dd037cbf6ce20",
"translation_date": "2025-08-28T12:47:52+00:00",
"source_file": "lessons/6-Other/22-DeepRL/CartPole-RL-PyTorch.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,117 @@
# Aprendizado por Reforço Profundo
O aprendizado por reforço (RL) é considerado um dos paradigmas básicos de aprendizado de máquina, ao lado do aprendizado supervisionado e não supervisionado. Enquanto no aprendizado supervisionado dependemos de um conjunto de dados com resultados conhecidos, o RL é baseado no **aprender fazendo**. Por exemplo, quando jogamos um jogo de computador pela primeira vez, começamos a jogar mesmo sem conhecer as regras, e logo conseguimos melhorar nossas habilidades apenas pelo processo de jogar e ajustar nosso comportamento.
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/43)
Para realizar RL, precisamos de:
* Um **ambiente** ou **simulador** que define as regras do jogo. Devemos ser capazes de executar experimentos no simulador e observar os resultados.
* Alguma **função de recompensa**, que indica quão bem-sucedido foi nosso experimento. No caso de aprender a jogar um jogo de computador, a recompensa seria nossa pontuação final.
Com base na função de recompensa, devemos ser capazes de ajustar nosso comportamento e melhorar nossas habilidades, para que na próxima vez joguemos melhor. A principal diferença entre outros tipos de aprendizado de máquina e RL é que no RL geralmente não sabemos se ganhamos ou perdemos até terminarmos o jogo. Assim, não podemos dizer se um movimento específico é bom ou não - só recebemos uma recompensa no final do jogo.
Durante o RL, normalmente realizamos muitos experimentos. Em cada experimento, precisamos equilibrar entre seguir a estratégia ideal que aprendemos até agora (**exploração**) e explorar novos estados possíveis (**exploração**).
## OpenAI Gym
Uma ferramenta excelente para RL é o [OpenAI Gym](https://gym.openai.com/) - um **ambiente de simulação**, que pode simular muitos ambientes diferentes, desde jogos de Atari até a física por trás do equilíbrio de um pêndulo. É um dos ambientes de simulação mais populares para treinar algoritmos de aprendizado por reforço e é mantido pela [OpenAI](https://openai.com/).
> **Note**: Você pode ver todos os ambientes disponíveis no OpenAI Gym [aqui](https://gym.openai.com/envs/#classic_control).
## Equilíbrio do CartPole
Provavelmente todos já viram dispositivos modernos de equilíbrio, como o *Segway* ou *Gyroscooters*. Eles conseguem se equilibrar automaticamente ajustando suas rodas em resposta a um sinal de um acelerômetro ou giroscópio. Nesta seção, aprenderemos como resolver um problema semelhante - equilibrar um pêndulo. É similar à situação em que um artista de circo precisa equilibrar um pêndulo na mão - mas este equilíbrio ocorre apenas em 1D.
Uma versão simplificada do equilíbrio é conhecida como problema **CartPole**. No mundo do CartPole, temos um deslizante horizontal que pode se mover para a esquerda ou para a direita, e o objetivo é equilibrar um pêndulo vertical no topo do deslizante enquanto ele se move.
<img alt="um cartpole" src="../../../../../translated_images/pt-BR/cartpole.f52a67f27e058170.webp" width="200"/>
Para criar e usar este ambiente, precisamos de algumas linhas de código Python:
```python
import gym
env = gym.make("CartPole-v1")
env.reset()
done = False
total_reward = 0
while not done:
env.render()
action = env.action_space.sample()
observaton, reward, done, info = env.step(action)
total_reward += reward
print(f"Total reward: {total_reward}")
```
Cada ambiente pode ser acessado exatamente da mesma maneira:
* `env.reset` inicia um novo experimento
* `env.step` realiza um passo de simulação. Ele recebe uma **ação** do **espaço de ações** e retorna uma **observação** (do espaço de observação), bem como uma recompensa e um sinal de término.
No exemplo acima, realizamos uma ação aleatória em cada passo, o que faz com que a vida do experimento seja muito curta:
![cartpole sem equilíbrio](../../../../../lessons/6-Other/22-DeepRL/images/cartpole-nobalance.gif)
O objetivo de um algoritmo de RL é treinar um modelo - a chamada **política** &pi; - que retornará a ação em resposta a um estado dado. Também podemos considerar a política como probabilística, por exemplo, para qualquer estado *s* e ação *a*, ela retornará a probabilidade &pi;(*a*|*s*) de que devemos tomar *a* no estado *s*.
## Algoritmo de Gradientes de Política
A maneira mais óbvia de modelar uma política é criando uma rede neural que receba estados como entrada e retorne ações correspondentes (ou melhor, as probabilidades de todas as ações). Em certo sentido, seria semelhante a uma tarefa de classificação normal, com uma grande diferença - não sabemos de antemão quais ações devemos tomar em cada um dos passos.
A ideia aqui é estimar essas probabilidades. Construímos um vetor de **recompensas acumuladas**, que mostra nossa recompensa total em cada passo do experimento. Também aplicamos **desconto de recompensa** multiplicando recompensas anteriores por algum coeficiente &gamma;=0.99, para diminuir o papel das recompensas anteriores. Em seguida, reforçamos aqueles passos ao longo do caminho do experimento que geram maiores recompensas.
> Saiba mais sobre o algoritmo de Gradientes de Política e veja-o em ação no [notebook de exemplo](CartPole-RL-TF.ipynb).
## Algoritmo Ator-Crítico
Uma versão aprimorada da abordagem de Gradientes de Política é chamada de **Ator-Crítico**. A ideia principal por trás disso é que a rede neural seria treinada para retornar duas coisas:
* A política, que determina qual ação tomar. Esta parte é chamada de **ator**
* A estimativa da recompensa total que podemos esperar obter neste estado - esta parte é chamada de **crítico**.
Em certo sentido, esta arquitetura se assemelha a um [GAN](../../4-ComputerVision/10-GANs/README.md), onde temos duas redes que são treinadas uma contra a outra. No modelo ator-crítico, o ator propõe a ação que precisamos tomar, e o crítico tenta ser crítico e estimar o resultado. No entanto, nosso objetivo é treinar essas redes em conjunto.
Como sabemos tanto as recompensas acumuladas reais quanto os resultados retornados pelo crítico durante o experimento, é relativamente fácil construir uma função de perda que minimize a diferença entre eles. Isso nos daria a **perda do crítico**. Podemos calcular a **perda do ator** usando a mesma abordagem do algoritmo de gradientes de política.
Depois de executar um desses algoritmos, podemos esperar que nosso CartPole se comporte assim:
![um cartpole equilibrado](../../../../../lessons/6-Other/22-DeepRL/images/cartpole-balance.gif)
## ✍️ Exercícios: Gradientes de Política e RL Ator-Crítico
Continue seu aprendizado nos seguintes notebooks:
* [RL em TensorFlow](CartPole-RL-TF.ipynb)
* [RL em PyTorch](CartPole-RL-PyTorch.ipynb)
## Outras Tarefas de RL
O Aprendizado por Reforço atualmente é um campo de pesquisa em rápido crescimento. Alguns exemplos interessantes de aprendizado por reforço são:
* Ensinar um computador a jogar **jogos de Atari**. A parte desafiadora deste problema é que não temos um estado simples representado como um vetor, mas sim uma captura de tela - e precisamos usar a CNN para converter esta imagem de tela em um vetor de características ou para extrair informações de recompensa. Jogos de Atari estão disponíveis no Gym.
* Ensinar um computador a jogar jogos de tabuleiro, como Xadrez e Go. Recentemente, programas de última geração como **Alpha Zero** foram treinados do zero por dois agentes jogando um contra o outro e melhorando a cada passo.
* Na indústria, o RL é usado para criar sistemas de controle a partir de simulação. Um serviço chamado [Bonsai](https://azure.microsoft.com/services/project-bonsai/?WT.mc_id=academic-77998-cacaste) é especificamente projetado para isso.
## Conclusão
Agora aprendemos como treinar agentes para alcançar bons resultados apenas fornecendo-lhes uma função de recompensa que define o estado desejado do jogo e dando-lhes a oportunidade de explorar inteligentemente o espaço de busca. Experimentamos com sucesso dois algoritmos e alcançamos um bom resultado em um período relativamente curto de tempo. No entanto, este é apenas o começo de sua jornada no RL, e você definitivamente deve considerar fazer um curso separado se quiser se aprofundar.
## 🚀 Desafio
Explore as aplicações listadas na seção 'Outras Tarefas de RL' e tente implementar uma delas!
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/44)
## Revisão e Autoestudo
Saiba mais sobre aprendizado por reforço clássico em nosso [Currículo de Aprendizado de Máquina para Iniciantes](https://github.com/microsoft/ML-For-Beginners/blob/main/8-Reinforcement/README.md).
Assista a [este ótimo vídeo](https://www.youtube.com/watch?v=qv6UVOQ0F44) que fala sobre como um computador pode aprender a jogar Super Mario.
## Tarefa: [Treine um Mountain Car](lab/README.md)
Seu objetivo durante esta tarefa será treinar um ambiente diferente do Gym - [Mountain Car](https://www.gymlibrary.ml/environments/classic_control/mountain_car/).
---

View File

@ -0,0 +1,109 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Treinando o Mountain Car para Escapar\n",
"\n",
"Tarefa de laboratório do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).\n",
"\n",
"Seu objetivo é treinar o agente de RL para controlar o [Mountain Car](https://www.gymlibrary.ml/environments/classic_control/mountain_car/) no ambiente OpenAI.\n",
"\n",
"Vamos começar criando o ambiente:\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import gym\n",
"env = gym.make('MountainCar-v0')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos ver como o experimento aleatório se parece:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"state = env.reset()\n",
"while True:\n",
" env.render()\n",
" action = env.action_space.sample()\n",
" state, reward, done, info = env.step(action)\n",
" if done:\n",
" break"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"## Lost of code here"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"env.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"coopTranslator": {
"original_hash": "f062b3b18449593ef8e0fcc029868781",
"translation_date": "2025-08-28T12:51:31+00:00",
"source_file": "lessons/6-Other/22-DeepRL/lab/MountainCar.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,22 @@
# Treinando o Carro da Montanha para Escapar
Tarefa do laboratório do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Seu objetivo é treinar o agente de RL para controlar o [Mountain Car](https://www.gymlibrary.ml/environments/classic_control/mountain_car/) no Ambiente OpenAI.
## O Ambiente
O ambiente Mountain Car consiste em um carro preso dentro de um vale. Seu objetivo é sair do vale e alcançar a bandeira. As ações que você pode realizar são acelerar para a esquerda, para a direita ou não fazer nada. Você pode observar a posição do carro ao longo do eixo x e sua velocidade.
## Notebook Inicial
Comece o laboratório abrindo [MountainCar.ipynb](../../../../../../lessons/6-Other/22-DeepRL/lab/MountainCar.ipynb)
## Conclusão
Você deve aprender ao longo deste laboratório que adaptar algoritmos de RL para um novo ambiente é frequentemente bastante simples, porque o OpenAI Gym possui a mesma interface para todos os ambientes, e os algoritmos, como tal, não dependem muito da natureza do ambiente. Você pode até reestruturar o código Python de forma a passar qualquer ambiente para o algoritmo de RL como um parâmetro.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,155 @@
# Sistemas Multiagentes
Uma das formas possíveis de alcançar inteligência é a chamada abordagem **emergente** (ou **sinergética**), que se baseia no fato de que o comportamento combinado de muitos agentes relativamente simples pode resultar em um comportamento geral mais complexo (ou inteligente) do sistema como um todo. Teoricamente, isso se baseia nos princípios de [Inteligência Coletiva](https://en.wikipedia.org/wiki/Collective_intelligence), [Emergentismo](https://en.wikipedia.org/wiki/Global_brain) e [Cibernética Evolutiva](https://en.wikipedia.org/wiki/Global_brain), que afirmam que sistemas de nível superior ganham algum tipo de valor agregado quando são devidamente combinados a partir de sistemas de nível inferior (o chamado *princípio da transição de metasistema*).
## [Quiz pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/45)
A direção dos **Sistemas Multiagentes** surgiu na IA na década de 1990 como uma resposta ao crescimento da Internet e dos sistemas distribuídos. Um dos livros clássicos de IA, [Artificial Intelligence: A Modern Approach](https://en.wikipedia.org/wiki/Artificial_Intelligence:_A_Modern_Approach), foca na visão da IA clássica do ponto de vista dos sistemas multiagentes.
Central para a abordagem multiagente é a noção de **Agente** - uma entidade que vive em algum **ambiente**, que pode perceber e agir sobre ele. Esta é uma definição muito ampla, e pode haver muitos tipos e classificações diferentes de agentes:
* Pela sua capacidade de raciocinar:
- Agentes **reativos** geralmente têm um comportamento simples de solicitação-resposta
- Agentes **deliberativos** empregam algum tipo de raciocínio lógico e/ou capacidades de planejamento
* Pelo local onde o agente executa seu código:
- Agentes **estáticos** trabalham em um nó de rede dedicado
- Agentes **móveis** podem mover seu código entre nós de rede
* Pelo seu comportamento:
- Agentes **passivos** não têm objetivos específicos. Esses agentes podem reagir a estímulos externos, mas não iniciam ações por conta própria.
- Agentes **ativos** têm alguns objetivos que perseguem
- Agentes **cognitivos** envolvem planejamento e raciocínio complexos
Os sistemas multiagentes são atualmente usados em várias aplicações:
* Em jogos, muitos personagens não jogáveis empregam algum tipo de IA e podem ser considerados agentes inteligentes
* Na produção de vídeos, renderizar cenas 3D complexas que envolvem multidões geralmente é feito usando simulação multiagente
* Na modelagem de sistemas, a abordagem multiagente é usada para simular o comportamento de um modelo complexo. Por exemplo, a abordagem multiagente foi usada com sucesso para prever a disseminação da COVID-19 em todo o mundo. Abordagens semelhantes podem ser usadas para modelar o tráfego em uma cidade e ver como ele reage a mudanças nas regras de trânsito.
* Em sistemas de automação complexos, cada dispositivo pode atuar como um agente independente, tornando o sistema como um todo menos monolítico e mais robusto.
Não vamos gastar muito tempo nos aprofundando em sistemas multiagentes, mas vamos considerar um exemplo de **Modelagem Multiagente**.
## NetLogo
[NetLogo](https://ccl.northwestern.edu/netlogo/) é um ambiente de modelagem multiagente baseado em uma versão modificada da linguagem de programação [Logo](https://en.wikipedia.org/wiki/Logo_(programming_language)). Essa linguagem foi desenvolvida para ensinar conceitos de programação a crianças e permite controlar um agente chamado **tartaruga**, que pode se mover deixando um rastro. Isso permite criar figuras geométricas complexas, sendo uma forma muito visual de entender o comportamento de um agente.
No NetLogo, podemos criar muitas tartarugas usando o comando `create-turtles`. Podemos então comandar todas as tartarugas para realizar algumas ações (no exemplo abaixo - mover 10 pontos para frente):
```
create-turtles 10
ask turtles [
forward 10
]
```
Claro, não é interessante quando todas as tartarugas fazem a mesma coisa, então podemos `ask` grupos de tartarugas, por exemplo, aquelas que estão nas proximidades de um determinado ponto. Também podemos criar tartarugas de diferentes *raças* usando o comando `breed [cats cat]`. Aqui `cat` é o nome de uma raça, e precisamos especificar tanto a palavra no singular quanto no plural, porque diferentes comandos usam formas diferentes para maior clareza.
> ✅ Não entraremos no aprendizado da linguagem NetLogo em si - você pode visitar o excelente recurso [Beginner's Interactive NetLogo Dictionary](https://ccl.northwestern.edu/netlogo/bind/) se estiver interessado em aprender mais.
Você pode [baixar](https://ccl.northwestern.edu/netlogo/download.shtml) e instalar o NetLogo para experimentá-lo.
### Biblioteca de Modelos
Uma grande vantagem do NetLogo é que ele contém uma biblioteca de modelos funcionais que você pode experimentar. Vá para **File &rightarrow; Models Library**, e você terá muitas categorias de modelos para escolher.
<img alt="Biblioteca de Modelos do NetLogo" src="../../../../../translated_images/pt-BR/NetLogo-ModelLib.efe023afb4763c05.webp" width="60%"/>
> Uma captura de tela da biblioteca de modelos por Dmitry Soshnikov
Você pode abrir um dos modelos, por exemplo **Biology &rightarrow; Flocking**.
### Princípios Básicos
Após abrir o modelo, você será levado à tela principal do NetLogo. Aqui está um modelo de exemplo que descreve a população de lobos e ovelhas, considerando recursos finitos (grama).
![Tela Principal do NetLogo](../../../../../translated_images/pt-BR/NetLogo-Main.32653711ec1a01b3.webp)
> Captura de tela por Dmitry Soshnikov
Nesta tela, você pode ver:
* A seção **Interface**, que contém:
- O campo principal, onde todos os agentes vivem
- Diferentes controles: botões, sliders, etc.
- Gráficos que você pode usar para exibir parâmetros da simulação
* A aba **Code**, que contém o editor onde você pode digitar o programa NetLogo
Na maioria dos casos, a interface terá um botão **Setup**, que inicializa o estado da simulação, e um botão **Go**, que inicia a execução. Esses são manipulados por handlers correspondentes no código que se parecem com isto:
```
to go [
...
]
```
O mundo do NetLogo consiste nos seguintes objetos:
* **Agentes** (tartarugas) que podem se mover pelo campo e fazer algo. Você comanda os agentes usando a sintaxe `ask turtles [...]`, e o código entre colchetes é executado por todos os agentes no *modo tartaruga*.
* **Patches** são áreas quadradas do campo onde os agentes vivem. Você pode se referir a todos os agentes no mesmo patch ou pode alterar as cores do patch e algumas outras propriedades. Você também pode `ask patches` para fazer algo.
* **Observer** é um agente único que controla o mundo. Todos os handlers de botões são executados no *modo observador*.
> ✅ A beleza de um ambiente multiagente é que o código que roda no modo tartaruga ou no modo patch é executado ao mesmo tempo por todos os agentes em paralelo. Assim, ao escrever um pouco de código e programar o comportamento de um agente individual, você pode criar um comportamento complexo do sistema de simulação como um todo.
### Flocking
Como exemplo de comportamento multiagente, vamos considerar o **[Flocking](https://en.wikipedia.org/wiki/Flocking_(behavior))**. Flocking é um padrão complexo muito semelhante ao modo como bandos de pássaros voam. Observando-os voar, você pode pensar que eles seguem algum tipo de algoritmo coletivo ou que possuem alguma forma de *inteligência coletiva*. No entanto, esse comportamento complexo surge quando cada agente individual (neste caso, um *pássaro*) apenas observa alguns outros agentes em uma curta distância e segue três regras simples:
* **Alinhamento** - direciona-se para a direção média dos agentes vizinhos
* **Coesão** - tenta direcionar-se para a posição média dos vizinhos (*atração de longo alcance*)
* **Separação** - ao se aproximar muito de outros pássaros, tenta se afastar (*repulsão de curto alcance*)
Você pode executar o exemplo de flocking e observar o comportamento. Também pode ajustar parâmetros, como o *grau de separação* ou o *alcance de visão*, que define quão longe cada pássaro pode enxergar. Note que, se você diminuir o alcance de visão para 0, todos os pássaros ficam cegos e o flocking para. Se você diminuir a separação para 0, todos os pássaros se agrupam em uma linha reta.
> ✅ Mude para a aba **Code** e veja onde as três regras de flocking (alinhamento, coesão e separação) são implementadas no código. Note como nos referimos apenas aos agentes que estão à vista.
### Outros Modelos para Ver
Há alguns modelos interessantes que você pode experimentar:
* **Art &rightarrow; Fireworks** mostra como um fogo de artifício pode ser considerado um comportamento coletivo de fluxos individuais de fogo
* **Social Science &rightarrow; Traffic Basic** e **Social Science &rightarrow; Traffic Grid** mostram o modelo de tráfego urbano em uma grade 1D e 2D com ou sem semáforos. Cada carro na simulação segue as seguintes regras:
- Se o espaço à frente estiver vazio - acelere (até uma certa velocidade máxima)
- Se vir um obstáculo à frente - freie (e você pode ajustar o quão longe o motorista pode enxergar)
* **Social Science &rightarrow; Party** mostra como as pessoas se agrupam durante uma festa de coquetel. Você pode encontrar a combinação de parâmetros que leva ao aumento mais rápido da felicidade do grupo.
Como você pode ver nesses exemplos, simulações multiagentes podem ser uma forma bastante útil de entender o comportamento de um sistema complexo composto por indivíduos que seguem a mesma lógica ou lógica semelhante. Também pode ser usado para controlar agentes virtuais, como [NPCs](https://en.wikipedia.org/wiki/NPC) em jogos de computador ou agentes em mundos animados em 3D.
## Agentes Deliberativos
Os agentes descritos acima são muito simples, reagindo às mudanças no ambiente usando algum tipo de algoritmo. Como tal, eles são **agentes reativos**. No entanto, às vezes os agentes podem raciocinar e planejar suas ações, caso em que são chamados de **deliberativos**.
Um exemplo típico seria um agente pessoal que recebe uma instrução de um humano para reservar um pacote de férias. Suponha que existam muitos agentes que vivem na internet e podem ajudá-lo. Ele deve então entrar em contato com outros agentes para ver quais voos estão disponíveis, quais são os preços dos hotéis para diferentes datas e tentar negociar o melhor preço. Quando o plano de férias estiver completo e confirmado pelo proprietário, ele pode prosseguir com a reserva.
Para fazer isso, os agentes precisam **comunicar-se**. Para uma comunicação bem-sucedida, eles precisam:
* De algumas **linguagens padrão para troca de conhecimento**, como [Knowledge Interchange Format](https://en.wikipedia.org/wiki/Knowledge_Interchange_Format) (KIF) e [Knowledge Query and Manipulation Language](https://en.wikipedia.org/wiki/Knowledge_Query_and_Manipulation_Language) (KQML). Essas linguagens são projetadas com base na [Teoria dos Atos de Fala](https://en.wikipedia.org/wiki/Speech_act).
* Essas linguagens também devem incluir alguns **protocolos de negociação**, baseados em diferentes **tipos de leilão**.
* Uma **ontologia comum** para usar, de modo que se refiram aos mesmos conceitos conhecendo sua semântica
* Uma maneira de **descobrir** o que diferentes agentes podem fazer, também baseada em algum tipo de ontologia
Agentes deliberativos são muito mais complexos do que reativos, porque não apenas reagem às mudanças no ambiente, mas também devem ser capazes de *iniciar* ações. Uma das arquiteturas propostas para agentes deliberativos é o chamado agente de Crença-Desejo-Intenção (BDI):
* **Crenças** formam um conjunto de conhecimento sobre o ambiente do agente. Pode ser estruturado como uma base de conhecimento ou conjunto de regras que um agente pode aplicar a uma situação específica no ambiente.
* **Desejos** definem o que um agente quer fazer, ou seja, seus objetivos. Por exemplo, o objetivo do agente assistente pessoal acima é reservar um pacote de férias, e o objetivo de um agente de hotel é maximizar o lucro.
* **Intenções** são ações específicas que um agente planeja para alcançar seus objetivos. As ações geralmente mudam o ambiente e causam comunicação com outros agentes.
Existem algumas plataformas disponíveis para construir sistemas multiagentes, como [JADE](https://jade.tilab.com/). [Este artigo](https://arxiv.org/ftp/arxiv/papers/2007/2007.08961.pdf) contém uma revisão das plataformas multiagentes, juntamente com um breve histórico dos sistemas multiagentes e seus diferentes cenários de uso.
## Conclusão
Sistemas Multiagentes podem assumir formas muito diferentes e ser usados em muitas aplicações diferentes.
Eles tendem a focar no comportamento mais simples de um agente individual e alcançar um comportamento mais complexo do sistema geral devido ao **efeito sinergético**.
## 🚀 Desafio
Leve esta lição para o mundo real e tente conceituar um sistema multiagente que possa resolver um problema. O que, por exemplo, um sistema multiagente precisaria fazer para otimizar a rota de um ônibus escolar? Como ele poderia funcionar em uma padaria?
## [Quiz pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/46)
## Revisão e Autoestudo
Revise o uso desse tipo de sistema na indústria. Escolha um domínio, como manufatura ou a indústria de videogames, e descubra como sistemas multiagentes podem ser usados para resolver problemas únicos.
## [Tarefa NetLogo](assignment.md)
---

View File

@ -0,0 +1,8 @@
# Tarefa NetLogo
Escolha um dos modelos da biblioteca do NetLogo e use-o para simular uma situação da vida real da forma mais fiel possível. Um bom exemplo seria ajustar o modelo Virus na pasta Alternative Visualizations para mostrar como ele pode ser usado para modelar a disseminação da COVID-19. Você consegue criar um modelo que imite a propagação viral na vida real?
Mostre seu trabalho salvando uma cópia e criando um vídeo demonstrativo explicando como o modelo está conectado a uma situação do mundo real.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,43 @@
# IA Ética e Responsável
Você está quase terminando este curso, e espero que até agora esteja claro que a IA é baseada em uma série de métodos matemáticos formais que nos permitem encontrar relações nos dados e treinar modelos para replicar alguns aspectos do comportamento humano. Neste momento da história, consideramos a IA uma ferramenta muito poderosa para extrair padrões dos dados e aplicar esses padrões para resolver novos problemas.
## [Quiz pré-aula](https://white-water-09ec41f0f.azurestaticapps.net/quiz/5/)
No entanto, na ficção científica, frequentemente vemos histórias onde a IA apresenta um perigo para a humanidade. Geralmente, essas histórias giram em torno de algum tipo de rebelião da IA, quando ela decide confrontar os seres humanos. Isso implica que a IA possui algum tipo de emoção ou pode tomar decisões inesperadas por seus desenvolvedores.
O tipo de IA que aprendemos neste curso nada mais é do que uma grande aritmética de matrizes. É uma ferramenta muito poderosa para nos ajudar a resolver nossos problemas e, como qualquer outra ferramenta poderosa, pode ser usada para fins bons ou ruins. É importante destacar que ela pode ser *mal utilizada*.
## Princípios de IA Responsável
Para evitar o uso acidental ou intencional inadequado da IA, a Microsoft estabelece os importantes [Princípios de IA Responsável](https://www.microsoft.com/ai/responsible-ai?WT.mc_id=academic-77998-cacaste). Os seguintes conceitos fundamentam esses princípios:
* **Justiça** está relacionada ao importante problema de *viés nos modelos*, que pode ser causado pelo uso de dados tendenciosos no treinamento. Por exemplo, quando tentamos prever a probabilidade de uma pessoa conseguir um emprego como desenvolvedor de software, o modelo provavelmente dará preferência maior aos homens - simplesmente porque o conjunto de dados de treinamento provavelmente foi tendencioso em relação ao público masculino. Precisamos equilibrar cuidadosamente os dados de treinamento e investigar o modelo para evitar vieses, garantindo que ele leve em conta características mais relevantes.
* **Confiabilidade e Segurança**. Por sua natureza, os modelos de IA podem cometer erros. Uma rede neural retorna probabilidades, e precisamos levar isso em consideração ao tomar decisões. Todo modelo possui alguma precisão e recall, e precisamos entender isso para evitar danos que conselhos errados podem causar.
* **Privacidade e Segurança** têm algumas implicações específicas para IA. Por exemplo, quando usamos alguns dados para treinar um modelo, esses dados se tornam de certa forma "integrados" ao modelo. Por um lado, isso aumenta a segurança e a privacidade, por outro - precisamos lembrar quais dados foram usados no treinamento do modelo.
* **Inclusão** significa que não estamos construindo IA para substituir pessoas, mas sim para aumentar a capacidade humana e tornar nosso trabalho mais criativo. Isso também está relacionado à justiça, porque ao lidar com comunidades sub-representadas, a maioria dos conjuntos de dados que coletamos provavelmente será tendenciosa, e precisamos garantir que essas comunidades sejam incluídas e tratadas corretamente pela IA.
* **Transparência**. Isso inclui garantir que sejamos sempre claros sobre o uso de IA. Além disso, sempre que possível, queremos usar sistemas de IA que sejam *interpretáveis*.
* **Responsabilidade**. Quando os modelos de IA tomam decisões, nem sempre é claro quem é responsável por essas decisões. Precisamos garantir que entendemos onde está a responsabilidade pelas decisões da IA. Na maioria dos casos, queremos incluir seres humanos no processo de tomada de decisões importantes, para que pessoas reais sejam responsabilizadas.
## Ferramentas para IA Responsável
A Microsoft desenvolveu o [Responsible AI Toolbox](https://github.com/microsoft/responsible-ai-toolbox), que contém um conjunto de ferramentas:
* Interpretability Dashboard (InterpretML)
* Fairness Dashboard (FairLearn)
* Error Analysis Dashboard
* Responsible AI Dashboard, que inclui:
- EconML - ferramenta para Análise Causal, que foca em questões de "e se"
- DiCE - ferramenta para Análise Contrafactual que permite ver quais características precisam ser alteradas para influenciar a decisão do modelo
Para mais informações sobre Ética em IA, visite [esta lição](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/3-fairness?WT.mc_id=academic-77998-cacaste) no currículo de Machine Learning, que inclui tarefas.
## Revisão e Autoestudo
Faça este [Caminho de Aprendizado](https://docs.microsoft.com/learn/modules/responsible-ai-principles/?WT.mc_id=academic-77998-cacaste) para aprender mais sobre IA responsável.
## [Quiz pós-aula](https://white-water-09ec41f0f.azurestaticapps.net/quiz/6/)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,8 @@
# Visão Geral
![Visão Geral em um rabisco](../../../translated_images/pt-BR/ai-overview.0857791951d19500.webp)
> Rabisco por [Tomomi Imura](https://twitter.com/girlie_mac)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,79 @@
# Redes Multi-Modais
Após o sucesso dos modelos transformers na resolução de tarefas de PLN, as mesmas ou similares arquiteturas foram aplicadas a tarefas de visão computacional. Há um interesse crescente em construir modelos que *combinem* capacidades de visão e linguagem natural. Uma dessas tentativas foi realizada pela OpenAI, chamada CLIP e DALL.E.
## Treinamento Contrastivo de Imagens (CLIP)
A ideia principal do CLIP é ser capaz de comparar descrições textuais com uma imagem e determinar o quão bem a imagem corresponde à descrição.
![Arquitetura do CLIP](../../../../../translated_images/pt-BR/clip-arch.b3dbf20b4e8ed8be.webp)
> *Imagem retirada [deste post no blog](https://openai.com/blog/clip/)*
O modelo é treinado com imagens obtidas da Internet e suas legendas. Para cada lote, pegamos N pares de (imagem, texto) e os convertemos em representações vetoriais I e T. Essas representações são então comparadas entre si. A função de perda é definida para maximizar a similaridade cosseno entre os vetores correspondentes a um par (por exemplo, I e T) e minimizar a similaridade cosseno entre todos os outros pares. É por isso que essa abordagem é chamada de **contrastiva**.
A biblioteca/modelo CLIP está disponível no [GitHub da OpenAI](https://github.com/openai/CLIP). A abordagem é descrita [neste post no blog](https://openai.com/blog/clip/) e em mais detalhes [neste artigo](https://arxiv.org/pdf/2103.00020.pdf).
Uma vez que este modelo é pré-treinado, podemos fornecer a ele um lote de imagens e um lote de descrições textuais, e ele retornará um tensor com probabilidades. O CLIP pode ser usado para várias tarefas:
**Classificação de Imagens**
Suponha que precisamos classificar imagens entre, por exemplo, gatos, cachorros e humanos. Nesse caso, podemos fornecer ao modelo uma imagem e uma série de descrições textuais: "*uma foto de um gato*", "*uma foto de um cachorro*", "*uma foto de um humano*". No vetor resultante de 3 probabilidades, basta selecionar o índice com o maior valor.
![CLIP para Classificação de Imagens](../../../../../translated_images/pt-BR/clip-class.3af42ef0b2b19369.webp)
> *Imagem retirada [deste post no blog](https://openai.com/blog/clip/)*
**Busca de Imagens Baseada em Texto**
Também podemos fazer o oposto. Se tivermos uma coleção de imagens, podemos passar essa coleção para o modelo, juntamente com uma descrição textual, e ele nos dará a imagem mais semelhante à descrição fornecida.
## ✍️ Exemplo: [Usando CLIP para Classificação de Imagens e Busca de Imagens](../../../../../lessons/X-Extras/X1-MultiModal/Clip.ipynb)
Abra o notebook [Clip.ipynb](../../../../../lessons/X-Extras/X1-MultiModal/Clip.ipynb) para ver o CLIP em ação.
## Geração de Imagens com VQGAN+CLIP
O CLIP também pode ser usado para **geração de imagens** a partir de uma descrição textual. Para isso, precisamos de um **modelo gerador** que seja capaz de gerar imagens com base em algum vetor de entrada. Um desses modelos é chamado [VQGAN](https://compvis.github.io/taming-transformers/) (Vector-Quantized GAN).
As principais ideias do VQGAN que o diferenciam de um [GAN](../../4-ComputerVision/10-GANs/README.md) tradicional são as seguintes:
* Uso de uma arquitetura transformer autorregressiva para gerar uma sequência de partes visuais ricas em contexto que compõem a imagem. Essas partes visuais, por sua vez, são aprendidas por uma [CNN](../../4-ComputerVision/07-ConvNets/README.md).
* Uso de um discriminador de sub-imagens que detecta se partes da imagem são "reais" ou "falsas" (diferente da abordagem "tudo ou nada" nos GANs tradicionais).
Saiba mais sobre o VQGAN no site [Taming Transformers](https://compvis.github.io/taming-transformers/).
Uma das diferenças importantes entre o VQGAN e um GAN tradicional é que o último pode produzir uma imagem decente a partir de qualquer vetor de entrada, enquanto o VQGAN provavelmente produzirá uma imagem incoerente. Assim, precisamos orientar ainda mais o processo de criação da imagem, e isso pode ser feito usando o CLIP.
![Arquitetura VQGAN+CLIP](../../../../../translated_images/pt-BR/vqgan.5027fe05051dfa31.webp)
Para gerar uma imagem correspondente a uma descrição textual, começamos com algum vetor de codificação aleatório que é passado pelo VQGAN para produzir uma imagem. Em seguida, o CLIP é usado para produzir uma função de perda que mostra o quão bem a imagem corresponde à descrição textual. O objetivo, então, é minimizar essa perda, usando retropropagação para ajustar os parâmetros do vetor de entrada.
Uma ótima biblioteca que implementa o VQGAN+CLIP é o [Pixray](http://github.com/pixray/pixray).
![Imagem gerada pelo Pixray](../../../../../translated_images/pt-BR/a_closeup_watercolor_portrait_of_young_male_teacher_of_literature_with_a_book.2384968e9db8a0d0.webp) | ![Imagem gerada pelo Pixray](../../../../../translated_images/pt-BR/a_closeup_oil_portrait_of_young_female_teacher_of_computer_science_with_a_computer.e0b6495f210a4390.webp) | ![Imagem gerada pelo Pixray](../../../../../translated_images/pt-BR/a_closeup_oil_portrait_of_old_male_teacher_of_math.5362e67aa7fc2683.webp)
----|----|----
Imagem gerada a partir da descrição *um retrato em aquarela de um jovem professor de literatura com um livro* | Imagem gerada a partir da descrição *um retrato a óleo de uma jovem professora de ciência da computação com um computador* | Imagem gerada a partir da descrição *um retrato a óleo de um velho professor de matemática em frente a um quadro-negro*
> Imagens da coleção **Artificial Teachers** por [Dmitry Soshnikov](http://soshnikov.com)
## DALL-E
### [DALL-E 1](https://openai.com/research/dall-e)
O DALL-E é uma versão do GPT-3 treinada para gerar imagens a partir de descrições textuais. Ele foi treinado com 12 bilhões de parâmetros.
Diferentemente do CLIP, o DALL-E recebe tanto texto quanto imagem como um único fluxo de tokens para ambos. Assim, a partir de múltiplas descrições, é possível gerar imagens baseadas no texto.
### [DALL-E 2](https://openai.com/dall-e-2)
A principal diferença entre o DALL-E 1 e o 2 é que o último gera imagens e artes mais realistas.
Exemplos de imagens geradas com o DALL-E:
![Imagem gerada pelo DALL-E](../../../../../translated_images/pt-BR/DALL·E%202023-06-20%2015.56.56%20-%20a%20closeup%20watercolor%20portrait%20of%20young%20male%20teacher%20of%20literature%20with%20a%20book.6c235e8271d9ed10ce985d86aeb241a58518958647973af136912116b9518fce.png) | ![Imagem gerada pelo DALL-E](../../../../../translated_images/pt-BR/DALL·E%202023-06-20%2015.57.43%20-%20a%20closeup%20oil%20portrait%20of%20young%20female%20teacher%20of%20computer%20science%20with%20a%20computer.f21dc4166340b6c8b4d1cb57efd1e22127407f9b28c9ac7afe11344065369e64.png) | ![Imagem gerada pelo DALL-E](../../../../../translated_images/pt-BR/DALL·E%202023-06-20%2015.58.42%20-%20%20a%20closeup%20oil%20portrait%20of%20old%20male%20teacher%20of%20mathematics%20in%20front%20of%20blackboard.d331c2dfbdc3f7c46aa65c0809066f5e7ed4b49609cd259852e760df21051e4a.png)
----|----|----
Imagem gerada a partir da descrição *um retrato em aquarela de um jovem professor de literatura com um livro* | Imagem gerada a partir da descrição *um retrato a óleo de uma jovem professora de ciência da computação com um computador* | Imagem gerada a partir da descrição *um retrato a óleo de um velho professor de matemática em frente a um quadro-negro*
## Referências
* Artigo do VQGAN: [Taming Transformers for High-Resolution Image Synthesis](https://compvis.github.io/taming-transformers/paper/paper.pdf)
* Artigo do CLIP: [Learning Transferable Visual Models From Natural Language Supervision](https://arxiv.org/pdf/2103.00020.pdf)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,101 @@
Direitos, então o banco de dados resultante (Adapted Material) deve ser licenciado sob a mesma condições da Seção 3(b); e
c. Você deve cumprir as condições da Seção 3(a) se compartilhar todo ou uma parte substancial do conteúdo do banco de dados.
Seção 5 -- Isenção de Garantias e Limitação de Responsabilidade.
a. Salvo conforme expressamente estabelecido nesta Licença Pública, na medida máxima permitida pela lei aplicável, o Licenciador oferece o Material Licenciado "como está" e "conforme disponível", sem garantias ou condições de qualquer tipo, seja expressa, implícita, estatutária ou de outra forma, incluindo, sem limitação, garantias ou condições de comercialização, adequação a um propósito específico ou não violação.
b. Na medida máxima permitida pela lei aplicável, em nenhum caso o Licenciador será responsável por qualquer perda, custo, despesa ou dano resultante de qualquer forma do uso do Material Licenciado, mesmo que o Licenciador tenha sido informado da possibilidade de tais perdas, custos, despesas ou danos.
Seção 6 -- Termo e Rescisão.
a. Este Termo da Licença Pública começa quando Você exerce os Direitos Licenciados e permanece em vigor enquanto os Direitos Autorais e Direitos Similares aplicáveis ao Material Licenciado não expirarem.
b. Se Você violar os termos e condições desta Licença Pública, seus direitos sob esta Licença Pública terminarão automaticamente.
c. Quando seus direitos sob esta Licença Pública terminarem, Você ainda assim continuará vinculado às disposições desta Licença Pública que, por sua natureza, sobrevivem à rescisão.
d. A rescisão desta Licença Pública não encerra as licenças concedidas por Você a terceiros sob esta Licença Pública, desde que esses terceiros cumpram seus termos e condições.
Seção 7 -- Outras Condições e Termos.
a. O Licenciador não será vinculado por quaisquer termos ou condições adicionais ou diferentes comunicados por Você, a menos que expressamente acordado.
b. Quaisquer disposições desta Licença Pública consideradas inválidas ou inexequíveis por um tribunal de jurisdição competente serão interpretadas, modificadas ou separadas conforme necessário para torná-las válidas e exequíveis.
c. Nenhuma renúncia por parte do Licenciador de qualquer violação ou falha por Você será considerada uma renúncia de qualquer violação ou falha anterior ou subsequente.
Seção 8 -- Interpretação.
a. Para evitar dúvidas, esta Licença Pública não será interpretada como reduzindo, limitando, restringindo ou impondo condições ao uso do Material Licenciado que seja permitido sob exceções e limitações aplicáveis ao direito autoral e direitos similares.
b. Quando os Direitos Licenciados incluem direitos sob disposições de proteção de banco de dados, esta Licença Pública será interpretada de forma consistente com essas disposições.
c. Esta Licença Pública será interpretada de acordo com os termos e condições aplicáveis ao Material Licenciado e ao Licenciador.
d. Nada nesta Licença Pública será interpretado como limitando ou restringindo o uso do Material Licenciado que não seja regulado por direitos autorais ou direitos similares.
Direitos, então o banco de dados no qual você possui Direitos de Banco de Dados Sui Generis (mas não seus conteúdos individuais) é Material Adaptado,
incluindo para os propósitos da Seção 3(b); e
c. Você deve cumprir as condições da Seção 3(a) se compartilhar todo ou uma parte substancial do conteúdo do banco de dados.
Para evitar dúvidas, esta Seção 4 complementa e não substitui suas obrigações sob esta Licença Pública quando os Direitos Licenciados incluem outros Direitos Autorais e Direitos Similares.
---
Seção 5 -- Isenção de Garantias e Limitação de Responsabilidade.
a. SALVO DISPOSIÇÃO EM CONTRÁRIO ASSUMIDA SEPARADAMENTE PELO LICENCIANTE, NA MEDIDA DO POSSÍVEL, O LICENCIANTE OFERECE O MATERIAL LICENCIADO "NO ESTADO EM QUE SE ENCONTRA" E "CONFORME DISPONÍVEL", E NÃO FAZ REPRESENTAÇÕES OU GARANTIAS DE QUALQUER TIPO RELACIONADAS AO MATERIAL LICENCIADO, SEJAM ELAS EXPRESSAS, IMPLÍCITAS, LEGAIS OU OUTRAS. ISSO INCLUI, SEM LIMITAÇÃO, GARANTIAS DE TÍTULO, COMERCIABILIDADE, ADEQUAÇÃO A UM PROPÓSITO ESPECÍFICO, NÃO VIOLAÇÃO, AUSÊNCIA DE DEFEITOS LATENTES OU OUTROS, PRECISÃO, OU A PRESENÇA OU AUSÊNCIA DE ERROS, SEJAM OU NÃO CONHECIDOS OU DETECTÁVEIS. ONDE ISENÇÕES DE GARANTIAS NÃO SÃO PERMITIDAS TOTAL OU PARCIALMENTE, ESTA ISENÇÃO PODE NÃO SE APLICAR A VOCÊ.
b. NA MEDIDA DO POSSÍVEL, EM NENHUMA CIRCUNSTÂNCIA O LICENCIANTE SERÁ RESPONSÁVEL PERANTE VOCÊ SOB QUALQUER TEORIA LEGAL (INCLUINDO, SEM LIMITAÇÃO, NEGLIGÊNCIA) OU DE OUTRA FORMA POR QUAISQUER PERDAS, CUSTOS, DESPESAS OU DANOS DIRETOS, ESPECIAIS, INDIRETOS, INCIDENTAIS, CONSEQUENCIAIS, PUNITIVOS, EXEMPLARES OU OUTROS DECORRENTES DESTA LICENÇA PÚBLICA OU DO USO DO MATERIAL LICENCIADO, MESMO QUE O LICENCIANTE TENHA SIDO AVISADO DA POSSIBILIDADE DE TAIS PERDAS, CUSTOS, DESPESAS OU DANOS. ONDE UMA LIMITAÇÃO DE RESPONSABILIDADE NÃO É PERMITIDA TOTAL OU PARCIALMENTE, ESTA LIMITAÇÃO PODE NÃO SE APLICAR A VOCÊ.
c. A isenção de garantias e a limitação de responsabilidade fornecidas acima devem ser interpretadas de maneira que, na medida do possível, mais se aproxime de uma isenção absoluta e renúncia de toda responsabilidade.
---
Seção 6 -- Vigência e Rescisão.
a. Esta Licença Pública se aplica durante o prazo dos Direitos Autorais e Direitos Similares licenciados aqui. No entanto, se você não cumprir esta Licença Pública, seus direitos sob esta Licença Pública serão automaticamente encerrados.
b. Quando seu direito de usar o Material Licenciado for encerrado sob a Seção 6(a), ele será restabelecido:
1. automaticamente na data em que a violação for corrigida, desde que seja corrigida dentro de 30 dias após sua descoberta da violação; ou
2. mediante restabelecimento expresso pelo Licenciante.
Para evitar dúvidas, esta Seção 6(b) não afeta qualquer direito que o Licenciante possa ter de buscar reparações por suas violações desta Licença Pública.
c. Para evitar dúvidas, o Licenciante também pode oferecer o Material Licenciado sob termos ou condições separados ou parar de distribuir o Material Licenciado a qualquer momento; no entanto, isso não encerrará esta Licença Pública.
d. As Seções 1, 5, 6, 7 e 8 sobrevivem ao término desta Licença Pública.
---
Seção 7 -- Outros Termos e Condições.
a. O Licenciante não estará vinculado a quaisquer termos ou condições adicionais ou diferentes comunicados por você, a menos que expressamente acordado.
b. Quaisquer arranjos, entendimentos ou acordos relacionados ao Material Licenciado não declarados aqui são separados e independentes dos termos e condições desta Licença Pública.
---
Seção 8 -- Interpretação.
a. Para evitar dúvidas, esta Licença Pública não reduz, limita, restringe ou impõe condições sobre qualquer uso do Material Licenciado que possa ser legalmente feito sem permissão sob esta Licença Pública.
b. Na medida do possível, se qualquer disposição desta Licença Pública for considerada inexequível, ela será automaticamente reformada na extensão mínima necessária para torná-la exequível. Se a disposição não puder ser reformada, ela será separada desta Licença Pública sem afetar a exequibilidade dos termos e condições restantes.
c. Nenhum termo ou condição desta Licença Pública será renunciado e nenhum descumprimento será consentido, a menos que expressamente acordado pelo Licenciante.
d. Nada nesta Licença Pública constitui ou pode ser interpretado como uma limitação ou renúncia de quaisquer privilégios e imunidades que se apliquem ao Licenciante ou a você, incluindo em relação aos processos legais de qualquer jurisdição ou autoridade.
---
=======================================================================
A Creative Commons não é parte de suas licenças públicas. Não obstante, a Creative Commons pode optar por aplicar uma de suas licenças públicas ao material que publica e, nesses casos, será considerada o “Licenciante”. O texto das licenças públicas da Creative Commons é dedicado ao domínio público sob a Dedicação ao Domínio Público CC0. Exceto para o propósito limitado de indicar que o material é compartilhado sob uma licença pública da Creative Commons ou conforme permitido pelas políticas da Creative Commons publicadas em creativecommons.org/policies, a Creative Commons não autoriza o uso da marca "Creative Commons" ou de qualquer outra marca ou logotipo da Creative Commons sem seu consentimento prévio por escrito, incluindo, sem limitação, em conexão com quaisquer modificações não autorizadas de suas licenças públicas ou quaisquer outros arranjos, entendimentos ou acordos relacionados ao uso do material licenciado. Para evitar dúvidas, este parágrafo não faz parte das licenças públicas.
A Creative Commons pode ser contatada em creativecommons.org.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,8 @@
Todas as sketchnotes do currículo podem ser baixadas aqui.
🎨 Criado por: Tomomi Imura (Twitter: [@girlie_mac](https://twitter.com/girlie_mac), GitHub: [girliemac](https://github.com/girliemac))
[![CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.

View File

@ -0,0 +1,278 @@
# Guia de Solução de Problemas do AI-For-Beginners
Este guia ajuda você a resolver problemas comuns encontrados ao usar ou contribuir para o repositório [AI-For-Beginners](https://github.com/microsoft/AI-For-Beginners). Cada problema inclui contexto, sintomas, explicações e soluções passo a passo.
---
## Índice
- [Problemas Gerais](../..)
- [Problemas de Instalação](../..)
- [Problemas de Configuração](../..)
- [Execução de Notebooks](../..)
- [Problemas de Desempenho](../..)
- [Problemas no Site do Livro Didático](../..)
- [Problemas de Contribuição](../..)
- [FAQ](../..)
- [Obtendo Ajuda](../..)
---
## Problemas Gerais
### 1. Repositório Não Clona Corretamente
**Contexto:** Clonar permite copiar o repositório para sua máquina.
**Sintomas:**
- Erro: `fatal: repository not found`
- Erro: `Permission denied (publickey)`
**Possíveis Causas:**
- URL do repositório incorreta
- Permissões insuficientes
- Chaves SSH não configuradas
**Soluções:**
1. **Verifique a URL do repositório.**
Use a URL HTTPS:
```
git clone https://github.com/microsoft/AI-For-Beginners.git
```
2. **Troque para HTTPS se o SSH falhar.**
Se você vir `Permission denied (publickey)`, use o link HTTPS acima em vez de SSH.
3. **Configure chaves SSH (opcional).**
Se quiser usar SSH, siga o [guia de SSH do GitHub](https://docs.github.com/en/authentication/connecting-to-github-with-ssh).
---
## Problemas de Instalação
### 2. Problemas com o Ambiente Python
**Contexto:** O repositório depende do Python e de várias bibliotecas.
**Sintomas:**
- Erro: `ModuleNotFoundError: No module named '<package>'`
- Erros de importação ao executar scripts ou notebooks
**Possíveis Causas:**
- Dependências não instaladas
- Versão errada do Python
**Soluções:**
1. **Configure um ambiente virtual.**
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
2. **Instale as dependências.**
```bash
pip install -r requirements.txt
```
3. **Verifique a versão do Python.**
Use Python 3.7 ou mais recente.
```bash
python --version
```
### 3. Jupyter Não Instalado
**Contexto:** Notebooks são um recurso essencial de aprendizado.
**Sintomas:**
- Erro: `jupyter: command not found`
- Notebooks não iniciam
**Possíveis Causas:**
- Jupyter não instalado
**Soluções:**
1. **Instale o Jupyter Notebook.**
```bash
pip install notebook
```
ou, se estiver usando Anaconda:
```bash
conda install notebook
```
2. **Inicie o Jupyter Notebook.**
```bash
jupyter notebook
```
### 4. Conflitos de Versão de Dependências
**Contexto:** Projetos podem falhar se as versões dos pacotes forem incompatíveis.
**Sintomas:**
- Erros ou avisos sobre versões incompatíveis
**Possíveis Causas:**
- Pacotes Python antigos ou conflitantes
**Soluções:**
1. **Instale em um ambiente limpo.**
Exclua o venv/env do conda antigo e crie um novo.
2. **Use versões exatas.**
Sempre execute:
```bash
pip install -r requirements.txt
```
Se isso falhar, instale manualmente os pacotes ausentes conforme descrito no README.
---
## Problemas de Configuração
### 5. Variáveis de Ambiente Não Configuradas
**Contexto:** Alguns módulos podem exigir chaves, tokens ou configurações.
**Sintomas:**
- Erro: `KeyError` ou avisos sobre configurações ausentes
**Possíveis Causas:**
- Variáveis de ambiente necessárias não configuradas
**Soluções:**
1. **Verifique arquivos como `.env.example` ou similares.**
2. **Crie um arquivo `.env` e preencha os valores necessários.**
3. **Recarregue seu terminal ou IDE após configurar as variáveis de ambiente.**
---
## Execução de Notebooks
### 6. Notebook Não Abre ou Não Executa
**Contexto:** Notebooks Jupyter precisam de configuração adequada.
**Sintomas:**
- Notebook não inicia
- Navegador não abre automaticamente
**Possíveis Causas:**
- Jupyter não instalado
- Problemas de configuração do navegador
**Soluções:**
1. **Instale o Jupyter (veja Problemas de Instalação acima).**
2. **Abra os notebooks manualmente.**
- Copie a URL do terminal (ex.: `http://localhost:8888/?token=...`) e cole no navegador.
### 7. Kernel Travando ou Congelando
**Contexto:** Kernels de notebooks podem travar devido a limites de recursos ou erros de código.
**Sintomas:**
- Kernel morre ou reinicia repetidamente
- Erros de falta de memória
**Possíveis Causas:**
- Conjuntos de dados grandes
- Código ou pacotes incompatíveis
**Soluções:**
1. **Reinicie o kernel.**
Use o botão "Restart Kernel" no Jupyter.
2. **Verifique o uso de memória.**
Feche aplicativos não utilizados.
3. **Execute notebooks em plataformas na nuvem.**
Use [Google Colab](https://colab.research.google.com/) ou [Azure Notebooks](https://notebooks.azure.com/).
---
## Problemas de Desempenho
### 8. Notebooks Executando Lentamente
**Contexto:** Algumas tarefas de IA exigem muita memória e CPU.
**Sintomas:**
- Execução lenta
- Ventoinha do laptop funcionando intensamente
**Possíveis Causas:**
- Conjuntos de dados ou modelos grandes
- Recursos limitados do sistema
**Soluções:**
1. **Use uma plataforma na nuvem.**
- Faça upload do notebook para Colab ou Azure Notebooks.
2. **Reduza o tamanho do conjunto de dados.**
- Use dados de amostra para prática.
3. **Feche programas desnecessários.**
- Libere RAM do sistema.
---
## Problemas no Site do Livro Didático
### 9. Capítulo Não Carrega
**Contexto:** O livro didático online exibe lições e capítulos.
**Sintomas:**
- Um capítulo (ex.: Transformers/BERT) está ausente ou não abre
**Problema Conhecido:**
- [Issue #303](https://github.com/microsoft/AI-For-Beginners/issues/303): “18 Transformers. BERT. não pode ser aberto no site do livro didático.” Causado por um erro no nome do arquivo (`READMEtransformers.md` em vez de `README.md`).
**Soluções:**
1. **Verifique erros de renomeação de arquivos.**
Se você for um colaborador, certifique-se de que os arquivos dos capítulos estejam nomeados como `README.md`.
2. **Relate arquivos ausentes.**
Abra um problema no GitHub com o nome do capítulo e detalhes do erro.
---
## Problemas de Contribuição
### 10. PR Não Aceito ou Builds Falhando
**Contexto:** Contribuições devem passar por testes e seguir diretrizes.
**Sintomas:**
- Pull request rejeitado
- Erros na pipeline de CI/CD
**Possíveis Causas:**
- Testes falhando
- Não seguir padrões de codificação
**Soluções:**
1. **Leia as diretrizes de contribuição.**
- Siga o [CONTRIBUTING.md](https://github.com/microsoft/AI-For-Beginners/blob/main/CONTRIBUTING.md) do repositório.
2. **Execute testes localmente antes de enviar.**
3. **Verifique regras de linting ou requisitos de formatação.**
---
## FAQ
### Onde posso encontrar ajuda para módulos específicos?
- Cada módulo geralmente tem seu próprio README. Comece por lá para dicas de configuração e uso.
### Como posso relatar um bug ou solicitar um recurso?
- [Abra um problema no GitHub](https://github.com/microsoft/AI-For-Beginners/issues/new) com uma descrição clara e etapas para reproduzir.
### Posso pedir ajuda se meu problema não estiver listado?
- Sim! Pesquise problemas existentes primeiro e, se não encontrar seu problema, crie um novo.
---
## Obtendo Ajuda
- **Verifique Problemas:** [GitHub Issues](https://github.com/microsoft/AI-For-Beginners/issues)
- **Faça Perguntas:** Use as Discussões do GitHub ou abra um problema.
- **Comunidade:** Veja os links do repositório para opções de chat/fórum.
---
_Última Atualização: 20/09/2025_
---
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante estar ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,398 @@
{
"AGENTS.md": {
"original_hash": "6b11a37115944252ab3ed04e358d830d",
"translation_date": "2025-10-03T09:19:24+00:00",
"source_file": "AGENTS.md",
"language_code": "pt-PT"
},
"README.md": {
"original_hash": "1984fc89dd304a8a33ab5584691a99aa",
"translation_date": "2026-01-30T01:42:24+00:00",
"source_file": "README.md",
"language_code": "pt-PT"
},
"SECURITY.md": {
"original_hash": "a583f49d359c7ebba61433e4dfcd05a9",
"translation_date": "2025-08-24T08:52:24+00:00",
"source_file": "SECURITY.md",
"language_code": "pt-PT"
},
"etc/CODE_OF_CONDUCT.md": {
"original_hash": "c06b12caf3c901eb3156e3dd5b0aea56",
"translation_date": "2025-08-24T09:08:52+00:00",
"source_file": "etc/CODE_OF_CONDUCT.md",
"language_code": "pt-PT"
},
"etc/CONTRIBUTING.md": {
"original_hash": "847a587aa1b83f4d00858183ff3ed18a",
"translation_date": "2025-08-24T09:09:05+00:00",
"source_file": "etc/CONTRIBUTING.md",
"language_code": "pt-PT"
},
"etc/Mindmap.md": {
"original_hash": "f2f88dbd2debd38e26149b27b1fd272d",
"translation_date": "2025-08-24T09:09:12+00:00",
"source_file": "etc/Mindmap.md",
"language_code": "pt-PT"
},
"etc/SUPPORT.md": {
"original_hash": "fdfc08baee91e402938a2b1f94fe0949",
"translation_date": "2025-08-24T09:08:47+00:00",
"source_file": "etc/SUPPORT.md",
"language_code": "pt-PT"
},
"etc/TRANSLATIONS.md": {
"original_hash": "62b3e3ad5182edb905eec649a87eeeb4",
"translation_date": "2025-08-24T09:08:57+00:00",
"source_file": "etc/TRANSLATIONS.md",
"language_code": "pt-PT"
},
"etc/quiz-app/README.md": {
"original_hash": "d699cf8509f74baa5b0b838de5cf0662",
"translation_date": "2025-08-24T09:09:37+00:00",
"source_file": "etc/quiz-app/README.md",
"language_code": "pt-PT"
},
"examples/README.md": {
"original_hash": "0d1babfdcbeb46525f2db3fbaaa54cd7",
"translation_date": "2025-10-03T11:29:51+00:00",
"source_file": "examples/README.md",
"language_code": "pt-PT"
},
"lessons/0-course-setup/for-teachers.md": {
"original_hash": "a094ef9927883de1cfcee51dbd143381",
"translation_date": "2025-08-24T09:08:25+00:00",
"source_file": "lessons/0-course-setup/for-teachers.md",
"language_code": "pt-PT"
},
"lessons/0-course-setup/how-to-run.md": {
"original_hash": "a4717bd9103b9f6cd84d534b83534689",
"translation_date": "2026-01-15T14:10:34+00:00",
"source_file": "lessons/0-course-setup/how-to-run.md",
"language_code": "pt-PT"
},
"lessons/0-course-setup/setup.md": {
"original_hash": "7b4e5b8956915870d0a0ed3cc5890042",
"translation_date": "2025-12-12T19:38:11+00:00",
"source_file": "lessons/0-course-setup/setup.md",
"language_code": "pt-PT"
},
"lessons/1-Intro/README.md": {
"original_hash": "f57e8aa46141fd220b16ffed8f11aec7",
"translation_date": "2025-11-18T21:16:38+00:00",
"source_file": "lessons/1-Intro/README.md",
"language_code": "pt-PT"
},
"lessons/1-Intro/assignment.md": {
"original_hash": "a334df77a82aaaf2a29c77065d3e481e",
"translation_date": "2025-11-18T21:17:30+00:00",
"source_file": "lessons/1-Intro/assignment.md",
"language_code": "pt-PT"
},
"lessons/2-Symbolic/README.md": {
"original_hash": "f9f06b266b8b2bfc6b8792ff2bb1bea4",
"translation_date": "2026-01-15T14:12:00+00:00",
"source_file": "lessons/2-Symbolic/README.md",
"language_code": "pt-PT"
},
"lessons/2-Symbolic/assignment.md": {
"original_hash": "a057a8604f3976c3e309884453f1fad0",
"translation_date": "2025-08-24T09:08:01+00:00",
"source_file": "lessons/2-Symbolic/assignment.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/03-Perceptron/README.md": {
"original_hash": "c34cbba802058b6fa267e1a294d4e510",
"translation_date": "2025-09-23T13:45:35+00:00",
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/03-Perceptron/lab/README.md": {
"original_hash": "ba5d1eb353d20d3e7181066b3c424b99",
"translation_date": "2025-08-31T11:33:44+00:00",
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/lab/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/04-OwnFramework/README.md": {
"original_hash": "789d6c3fb6fc7948a470b33078a5983a",
"translation_date": "2025-09-23T13:45:03+00:00",
"source_file": "lessons/3-NeuralNetworks/04-OwnFramework/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/04-OwnFramework/lab/README.md": {
"original_hash": "48fdd704d483e19bc3d7464074c9fcbe",
"translation_date": "2025-08-24T09:04:16+00:00",
"source_file": "lessons/3-NeuralNetworks/04-OwnFramework/lab/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/05-Frameworks/README.md": {
"original_hash": "ddd216f558a255260a9374008002c971",
"translation_date": "2025-09-23T13:45:54+00:00",
"source_file": "lessons/3-NeuralNetworks/05-Frameworks/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/05-Frameworks/lab/README.md": {
"original_hash": "e452d897efb9a89700f41021834cf6e5",
"translation_date": "2025-08-24T09:04:42+00:00",
"source_file": "lessons/3-NeuralNetworks/05-Frameworks/lab/README.md",
"language_code": "pt-PT"
},
"lessons/3-NeuralNetworks/README.md": {
"original_hash": "f862a99d88088163df12270e2f2ad6c3",
"translation_date": "2025-10-03T12:46:51+00:00",
"source_file": "lessons/3-NeuralNetworks/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/06-IntroCV/README.md": {
"original_hash": "feeca98225cb420afc89415f24f63d92",
"translation_date": "2025-09-23T13:40:47+00:00",
"source_file": "lessons/4-ComputerVision/06-IntroCV/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/06-IntroCV/lab/README.md": {
"original_hash": "3d53d6409f80970f7281a45dee35328a",
"translation_date": "2025-08-24T09:00:48+00:00",
"source_file": "lessons/4-ComputerVision/06-IntroCV/lab/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/07-ConvNets/CNN_Architectures.md": {
"original_hash": "53faab85adfcebd8c10bcd71dc2fa557",
"translation_date": "2025-09-23T13:40:04+00:00",
"source_file": "lessons/4-ComputerVision/07-ConvNets/CNN_Architectures.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/07-ConvNets/README.md": {
"original_hash": "a560d5b845962cf33dc102266e409568",
"translation_date": "2025-09-23T13:39:47+00:00",
"source_file": "lessons/4-ComputerVision/07-ConvNets/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/07-ConvNets/lab/README.md": {
"original_hash": "b70fcf7fcee862990f848c679090943f",
"translation_date": "2025-10-03T14:54:19+00:00",
"source_file": "lessons/4-ComputerVision/07-ConvNets/lab/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/08-TransferLearning/README.md": {
"original_hash": "178c0b5ee5395733eb18aec51e71a0a9",
"translation_date": "2025-09-23T13:40:20+00:00",
"source_file": "lessons/4-ComputerVision/08-TransferLearning/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md": {
"original_hash": "ae074cd940fc2f4dc24fc07b66ccbd99",
"translation_date": "2025-08-24T09:01:14+00:00",
"source_file": "lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/08-TransferLearning/lab/README.md": {
"original_hash": "7765935c35fcee69b9fe2d0cfd6963e2",
"translation_date": "2025-08-24T09:01:39+00:00",
"source_file": "lessons/4-ComputerVision/08-TransferLearning/lab/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/09-Autoencoders/README.md": {
"original_hash": "1b8d9e1b3a6f1daa864b1ff3dfc3076d",
"translation_date": "2025-09-23T13:41:50+00:00",
"source_file": "lessons/4-ComputerVision/09-Autoencoders/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/10-GANs/README.md": {
"original_hash": "0ff65b4da07b23697235de2beb2a3c25",
"translation_date": "2025-09-23T13:42:28+00:00",
"source_file": "lessons/4-ComputerVision/10-GANs/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/11-ObjectDetection/README.md": {
"original_hash": "d76a7eda28de5210c8b1ba50a6216c69",
"translation_date": "2025-09-23T13:41:16+00:00",
"source_file": "lessons/4-ComputerVision/11-ObjectDetection/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/11-ObjectDetection/lab/README.md": {
"original_hash": "ad568d55ae65c856fe929fc2b278510a",
"translation_date": "2025-08-24T08:59:30+00:00",
"source_file": "lessons/4-ComputerVision/11-ObjectDetection/lab/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/12-Segmentation/README.md": {
"original_hash": "6568aaae7e0e4afed4b5d74b5b223700",
"translation_date": "2025-09-23T13:42:13+00:00",
"source_file": "lessons/4-ComputerVision/12-Segmentation/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/12-Segmentation/lab/README.md": {
"original_hash": "365f0decfe0f47b460bbde8227c5009d",
"translation_date": "2025-08-24T08:58:27+00:00",
"source_file": "lessons/4-ComputerVision/12-Segmentation/lab/README.md",
"language_code": "pt-PT"
},
"lessons/4-ComputerVision/README.md": {
"original_hash": "58a52f000089c1d8906a4daa4ab1169b",
"translation_date": "2025-08-24T08:57:30+00:00",
"source_file": "lessons/4-ComputerVision/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/13-TextRep/README.md": {
"original_hash": "dbd3f73e4139f030ecb2e20387d70fee",
"translation_date": "2025-09-23T13:49:01+00:00",
"source_file": "lessons/5-NLP/13-TextRep/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/13-TextRep/assignment.md": {
"original_hash": "cdc1f2e631f055f3473b36d18e4760b3",
"translation_date": "2025-08-24T08:54:42+00:00",
"source_file": "lessons/5-NLP/13-TextRep/assignment.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/14-Embeddings/README.md": {
"original_hash": "b708c9b85b833864c73c6281f1e6b96e",
"translation_date": "2025-09-23T13:48:40+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/14-Embeddings/assignment.md": {
"original_hash": "bc690ecf68b38d311cc9e12f3144a28c",
"translation_date": "2025-08-24T08:54:00+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/assignment.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/15-LanguageModeling/README.md": {
"original_hash": "7ba20f54a5bfcd6521018cdfb17c7c57",
"translation_date": "2025-09-23T13:46:46+00:00",
"source_file": "lessons/5-NLP/15-LanguageModeling/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/15-LanguageModeling/lab/README.md": {
"original_hash": "5130f01fdc5ebb83032b23d489027aac",
"translation_date": "2025-08-24T08:55:24+00:00",
"source_file": "lessons/5-NLP/15-LanguageModeling/lab/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/16-RNN/README.md": {
"original_hash": "e2273cc150380a5e191903cea858f021",
"translation_date": "2025-09-23T13:48:11+00:00",
"source_file": "lessons/5-NLP/16-RNN/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/16-RNN/assignment.md": {
"original_hash": "47f7d3c6a5373543e051e4d1140ce898",
"translation_date": "2025-08-24T08:53:35+00:00",
"source_file": "lessons/5-NLP/16-RNN/assignment.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/17-GenerativeNetworks/README.md": {
"original_hash": "51be6057374d01d70e07dd5ec88ebc0d",
"translation_date": "2025-09-23T13:46:27+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/17-GenerativeNetworks/lab/README.md": {
"original_hash": "439e12796197a90e7623d4c9c057b9c2",
"translation_date": "2025-08-24T08:54:21+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/lab/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/18-Transformers/README.md": {
"original_hash": "f335dfcb4a993920504c387973a36957",
"translation_date": "2025-09-23T13:46:56+00:00",
"source_file": "lessons/5-NLP/18-Transformers/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/18-Transformers/assignment.md": {
"original_hash": "177f3ea3995d725e6f9f5c66af16edcd",
"translation_date": "2025-08-24T08:55:30+00:00",
"source_file": "lessons/5-NLP/18-Transformers/assignment.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/19-NER/README.md": {
"original_hash": "6522312ff835796ca34136a9462fafb2",
"translation_date": "2025-09-23T13:47:56+00:00",
"source_file": "lessons/5-NLP/19-NER/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/19-NER/lab/README.md": {
"original_hash": "032bda5068f543d6c1fcb30c34231461",
"translation_date": "2025-08-24T08:55:54+00:00",
"source_file": "lessons/5-NLP/19-NER/lab/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/20-LangModels/README.md": {
"original_hash": "97836d30a6bec736f8e3b4411c572bc2",
"translation_date": "2025-09-23T13:47:23+00:00",
"source_file": "lessons/5-NLP/20-LangModels/README.md",
"language_code": "pt-PT"
},
"lessons/5-NLP/README.md": {
"original_hash": "8ef02a9318257ea140ed3ed74442096d",
"translation_date": "2025-08-24T08:52:49+00:00",
"source_file": "lessons/5-NLP/README.md",
"language_code": "pt-PT"
},
"lessons/6-Other/21-GeneticAlgorithms/README.md": {
"original_hash": "6bbd632dfe6c62e5f66bb51fd78c174a",
"translation_date": "2025-09-23T13:38:32+00:00",
"source_file": "lessons/6-Other/21-GeneticAlgorithms/README.md",
"language_code": "pt-PT"
},
"lessons/6-Other/22-DeepRL/README.md": {
"original_hash": "04395657fc01648f8f70484d0e55ab67",
"translation_date": "2025-09-23T13:39:21+00:00",
"source_file": "lessons/6-Other/22-DeepRL/README.md",
"language_code": "pt-PT"
},
"lessons/6-Other/22-DeepRL/lab/README.md": {
"original_hash": "7bd8dc72040e98e35e7225e34058cd4e",
"translation_date": "2025-08-24T09:03:07+00:00",
"source_file": "lessons/6-Other/22-DeepRL/lab/README.md",
"language_code": "pt-PT"
},
"lessons/6-Other/23-MultiagentSystems/README.md": {
"original_hash": "38a1185ae3d54b180378bbd71ae3ef16",
"translation_date": "2025-09-23T13:38:47+00:00",
"source_file": "lessons/6-Other/23-MultiagentSystems/README.md",
"language_code": "pt-PT"
},
"lessons/6-Other/23-MultiagentSystems/assignment.md": {
"original_hash": "cf654ca60c7f86c8dad28596fb42994b",
"translation_date": "2025-08-24T09:02:39+00:00",
"source_file": "lessons/6-Other/23-MultiagentSystems/assignment.md",
"language_code": "pt-PT"
},
"lessons/7-Ethics/README.md": {
"original_hash": "437c988596e751072e41a5aad3fcc5d9",
"translation_date": "2025-08-24T08:52:37+00:00",
"source_file": "lessons/7-Ethics/README.md",
"language_code": "pt-PT"
},
"lessons/README.md": {
"original_hash": "5fef1a0b22498d7188959e2a2cb08af7",
"translation_date": "2025-08-24T08:52:33+00:00",
"source_file": "lessons/README.md",
"language_code": "pt-PT"
},
"lessons/X-Extras/X1-MultiModal/README.md": {
"original_hash": "9c592c26aca16ca085d268c732284187",
"translation_date": "2025-08-24T09:03:14+00:00",
"source_file": "lessons/X-Extras/X1-MultiModal/README.md",
"language_code": "pt-PT"
},
"lessons/sketchnotes/LICENSE.md": {
"original_hash": "45ab63a2cd8f5faef6c9b150618837a4",
"translation_date": "2025-08-24T09:06:16+00:00",
"source_file": "lessons/sketchnotes/LICENSE.md",
"language_code": "pt-PT"
},
"lessons/sketchnotes/README.md": {
"original_hash": "050b8bddebafba55b129414e6ab096ab",
"translation_date": "2025-08-24T09:05:21+00:00",
"source_file": "lessons/sketchnotes/README.md",
"language_code": "pt-PT"
},
"troubleshoot.md": {
"original_hash": "8d9c5a4a7c7798d699672a22cb7fea86",
"translation_date": "2025-10-03T09:41:57+00:00",
"source_file": "troubleshoot.md",
"language_code": "pt-PT"
}
}

View File

@ -0,0 +1,317 @@
# AGENTS.md
## Visão Geral do Projeto
AI for Beginners é um currículo abrangente de 12 semanas e 24 aulas que cobre os fundamentos da Inteligência Artificial. Este repositório educacional inclui lições práticas usando Jupyter Notebooks, questionários e laboratórios práticos. O currículo aborda:
- IA Simbólica com Representação de Conhecimento e Sistemas Especialistas
- Redes Neurais e Aprendizagem Profunda com TensorFlow e PyTorch
- Técnicas e arquiteturas de Visão Computacional
- Processamento de Linguagem Natural (NLP), incluindo transformers e BERT
- Tópicos especializados: Algoritmos Genéticos, Aprendizagem por Reforço, Sistemas Multiagentes
- Ética em IA e princípios de IA Responsável
**Principais Tecnologias:** Python 3, Jupyter Notebooks, TensorFlow, PyTorch, Keras, OpenCV, Vue.js (para aplicação de questionários)
**Arquitetura:** Repositório de conteúdo educacional com Jupyter Notebooks organizados por áreas temáticas, complementado por uma aplicação de questionários baseada em Vue.js e suporte extensivo a múltiplos idiomas.
## Comandos de Configuração
### Ambiente de Desenvolvimento Principal (Python/Jupyter)
O currículo foi projetado para ser executado com Python e Jupyter Notebooks. A abordagem recomendada é usar miniconda:
```bash
# Clone the repository
git clone https://github.com/microsoft/ai-for-beginners
cd ai-for-beginners
# Create and activate conda environment
conda env create --name ai4beg --file environment.yml
conda activate ai4beg
# Start Jupyter Notebook
jupyter notebook
# OR
jupyter lab
```
### Alternativa: Usar devcontainer
```bash
# Open in VS Code and select "Reopen in Container" when prompted
# The devcontainer will automatically set up the environment
```
### Configuração da Aplicação de Questionários
A aplicação de questionários é uma aplicação Vue.js separada localizada em `etc/quiz-app/`:
```bash
cd etc/quiz-app
npm install
npm run serve # Development server
npm run build # Production build
npm run lint # Lint and fix files
```
## Fluxo de Trabalho de Desenvolvimento
### Trabalhar com Jupyter Notebooks
1. **Desenvolvimento Local:**
- Ativar o ambiente conda: `conda activate ai4beg`
- Iniciar o Jupyter: `jupyter notebook` ou `jupyter lab`
- Navegar pelas pastas das lições e abrir os ficheiros `.ipynb`
- Executar as células interativamente para acompanhar as lições
2. **VS Code com Extensão Python:**
- Abrir o repositório no VS Code
- Instalar a extensão Python
- O VS Code deteta automaticamente e utiliza o ambiente conda
- Abrir ficheiros `.ipynb` diretamente no VS Code
3. **Desenvolvimento na Nuvem:**
- **GitHub Codespaces:** Clique em "Code" → "Codespaces" → "Create codespace on main"
- **Binder:** Use o emblema Binder no README para iniciar no navegador
- Nota: O Binder tem recursos limitados e algumas restrições de acesso à web
### Suporte a GPU para Lições Avançadas
As lições posteriores beneficiam significativamente da aceleração por GPU:
- **Azure Data Science VM:** Utilize VMs da série NC com suporte a GPU
- **Azure Machine Learning:** Utilize funcionalidades de notebooks com computação GPU
- **Google Colab:** Carregue os notebooks individualmente (tem suporte gratuito a GPU)
### Desenvolvimento da Aplicação de Questionários
```bash
cd etc/quiz-app
npm run serve # Hot-reload development server at http://localhost:8080
```
## Instruções de Teste
Este é um repositório educacional focado em conteúdo de aprendizagem, em vez de testes de software. Não há um conjunto de testes tradicional.
### Abordagens de Validação:
1. **Jupyter Notebooks:** Execute as células sequencialmente para verificar se os exemplos de código funcionam
2. **Teste da Aplicação de Questionários:** Teste manual através do servidor de desenvolvimento
3. **Validação de Traduções:** Verifique o conteúdo traduzido na pasta `translations/`
4. **Linting da Aplicação de Questionários:** `npm run lint` em `etc/quiz-app/`
### Executar Exemplos de Código:
```bash
# Activate environment first
conda activate ai4beg
# Run Python scripts directly
python lessons/4-ComputerVision/07-ConvNets/pytorchcv.py
# Or execute notebooks
jupyter notebook lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb
```
## Estilo de Código
### Estilo de Código Python
- Convenções padrão de Python para código educacional
- Código claro e legível, priorizando o aprendizado em vez da otimização
- Comentários explicando conceitos-chave
- Compatível com Jupyter Notebook: as células devem ser autossuficientes sempre que possível
- Não há requisitos rigorosos de linting para o conteúdo das lições
### JavaScript/Vue.js (Aplicação de Questionários)
- Configuração ESLint em `etc/quiz-app/package.json`
- Execute `npm run lint` para verificar e corrigir automaticamente problemas
- Convenções do Vue 2.x
- Arquitetura baseada em componentes
### Organização de Ficheiros
```
lessons/
├── 0-course-setup/ # Setup instructions
├── 1-Intro/ # Introduction to AI
├── 2-Symbolic/ # Symbolic AI
├── 3-NeuralNetworks/ # Neural Networks basics
├── 4-ComputerVision/ # Computer Vision
├── 5-NLP/ # Natural Language Processing
├── 6-Other/ # Other AI techniques
├── 7-Ethics/ # AI Ethics
└── X-Extras/ # Additional content
etc/
├── quiz-app/ # Vue.js quiz application
└── quiz-src/ # Quiz source files
translations/ # Multi-language translations
```
## Construção e Implementação
### Conteúdo Jupyter
Não é necessário processo de construção - os Jupyter Notebooks são executados diretamente.
### Aplicação de Questionários
```bash
cd etc/quiz-app
# Development
npm run serve
# Production build
npm run build # Outputs to etc/quiz-app/dist/
# Deploy to Azure Static Web Apps
# Azure automatically creates GitHub Actions workflow
# See etc/quiz-app/README.md for detailed deployment instructions
```
### Site de Documentação
O repositório utiliza Docsify para documentação:
- `index.html` serve como ponto de entrada
- Não é necessário construção - servido diretamente via GitHub Pages
- Acesso em: https://microsoft.github.io/AI-For-Beginners/
## Diretrizes de Contribuição
### Processo de Pull Request
1. **Formato do Título:** Títulos claros e descritivos que descrevam a alteração
2. **Requisito CLA:** O CLA da Microsoft deve ser assinado (verificação automatizada)
3. **Diretrizes de Conteúdo:**
- Mantenha o foco educacional e abordagem amigável para iniciantes
- Teste todos os exemplos de código nos notebooks
- Certifique-se de que os notebooks são executados de ponta a ponta
- Atualize traduções se modificar o conteúdo em inglês
4. **Alterações na Aplicação de Questionários:** Execute `npm run lint` antes de fazer commit
### Contribuições de Tradução
- As traduções são automatizadas via GitHub Actions usando co-op-translator
- Traduções manuais vão para `translations/<language-code>/`
- Traduções de questionários em `etc/quiz-app/src/assets/translations/`
- Idiomas suportados: mais de 40 idiomas (consulte o README para a lista completa)
### Áreas Ativas de Contribuição
Consulte `etc/CONTRIBUTING.md` para necessidades atuais:
- Secções de Aprendizagem por Reforço Profundo
- Melhorias na Detecção de Objetos
- Exemplos de Reconhecimento de Entidades Nomeadas
- Amostras de treino de embeddings personalizados
## Configuração do Ambiente
### Dependências Necessárias
```bash
# Core Python packages (from requirements.txt)
tensorflow==2.17.0
torch (via conda)
torchvision (via conda)
keras==3.5.0
opencv (via conda)
scikit-learn
numpy==1.26
pandas==2.2.2
matplotlib==3.9
jupyter
```
### Variáveis de Ambiente
Não são necessárias variáveis de ambiente especiais para uso básico.
Para implementações no Azure (aplicação de questionários):
- `AZURE_STATIC_WEB_APPS_API_TOKEN` (configurado automaticamente pelo Azure)
## Depuração e Resolução de Problemas
### Problemas Comuns
**Problema:** Falha na criação do ambiente conda
- **Solução:** Atualize o conda primeiro: `conda update conda -y`
- Certifique-se de que há espaço suficiente em disco (recomendado 50GB)
**Problema:** Kernel do Jupyter não encontrado
- **Solução:**
```bash
conda activate ai4beg
python -m ipykernel install --user --name ai4beg
```
**Problema:** GPU não detetada nos notebooks
- **Solução:**
- Verifique a instalação do CUDA: `nvidia-smi`
- Verifique GPU no PyTorch: `python -c "import torch; print(torch.cuda.is_available())"`
- Verifique GPU no TensorFlow: `python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"`
**Problema:** Aplicação de questionários não inicia
- **Solução:**
```bash
cd etc/quiz-app
rm -rf node_modules package-lock.json
npm install
npm run serve
```
**Problema:** Binder expira ou bloqueia downloads
- **Solução:** Use GitHub Codespaces ou configuração local para melhor acesso a recursos
### Problemas de Memória
Algumas lições requerem RAM significativa (recomendado 8GB+):
- Utilize VMs na nuvem para lições que exigem muitos recursos
- Feche outras aplicações ao treinar modelos
- Reduza os tamanhos de batch nos notebooks se ficar sem memória
## Notas Adicionais
### Para Instrutores do Curso
- Consulte `lessons/0-course-setup/for-teachers.md` para orientações de ensino
- As lições são autossuficientes e podem ser ensinadas em sequência ou selecionadas individualmente
- Tempo estimado: 12 semanas com 2 lições por semana
### Recursos na Nuvem
- **Azure for Students:** Créditos gratuitos disponíveis para estudantes
- **Microsoft Learn:** Caminhos de aprendizagem suplementares ligados ao longo do curso
- **Binder:** Gratuito, mas com recursos limitados e algumas restrições de rede
### Opções de Execução de Código
1. **Local (Recomendado):** Controle total, melhor desempenho, suporte a GPU
2. **GitHub Codespaces:** VS Code baseado na nuvem, bom para acesso rápido
3. **Binder:** Jupyter baseado no navegador, gratuito mas limitado
4. **Azure ML Notebooks:** Opção empresarial com suporte a GPU
5. **Google Colab:** Carregue os notebooks individualmente, disponível nível gratuito de GPU
### Trabalhar com Notebooks
- Os notebooks foram projetados para serem executados célula por célula para aprendizagem
- Muitos notebooks fazem download de datasets na primeira execução (pode demorar)
- Alguns modelos requerem GPU para tempos de treino razoáveis
- Modelos pré-treinados são usados sempre que possível para reduzir requisitos de computação
### Considerações de Desempenho
- Lições posteriores de visão computacional (CNNs, GANs) beneficiam de GPU
- Lições de transformers em NLP podem exigir RAM significativa
- Treinar do zero é educativo, mas demorado
- Exemplos de aprendizagem por transferência minimizam o tempo de treino
---
**Aviso**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,225 @@
[![GitHub license](https://img.shields.io/github/license/microsoft/AI-For-Beginners.svg)](https://github.com/microsoft/AI-For-Beginners/blob/main/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/graphs/contributors/)
[![GitHub issues](https://img.shields.io/github/issues/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/issues/)
[![GitHub pull-requests](https://img.shields.io/github/issues-pr/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/pulls/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
[![GitHub watchers](https://img.shields.io/github/watchers/microsoft/AI-For-Beginners.svg?style=social&label=Watch)](https://GitHub.com/microsoft/AI-For-Beginners/watchers/)
[![GitHub forks](https://img.shields.io/github/forks/microsoft/AI-For-Beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/AI-For-Beginners/network/)
[![GitHub stars](https://img.shields.io/github/stars/microsoft/AI-For-Beginners.svg?style=social&label=Star)](https://GitHub.com/microsoft/AI-For-Beginners/stargazers/)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/microsoft/ai-for-beginners/HEAD)
[![Gitter](https://badges.gitter.im/Microsoft/ai-for-beginners.svg)](https://gitter.im/Microsoft/ai-for-beginners?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
# Inteligência Artificial para Iniciantes - Um Currículo
|![Sketchnote by @girlie_mac https://twitter.com/girlie_mac](../../translated_images/pt-PT/ai-overview.0857791951d19500.webp)|
|:---:|
| AI For Beginners - _Sketchnote por [@girlie_mac](https://twitter.com/girlie_mac)_ |
Explore o mundo da **Inteligência Artificial** (IA) com o nosso currículo de 12 semanas, composto por 24 aulas! Inclui lições práticas, questionários e laboratórios. O currículo é adequado para iniciantes e cobre ferramentas como TensorFlow e PyTorch, assim como ética na IA.
### 🌐 Suporte Multilíngue
#### Suportado via GitHub Action (Automatizado & Sempre Atualizado)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START -->
[Árabe](../ar/README.md) | [Bengali](../bn/README.md) | [Búlgaro](../bg/README.md) | [Birmanês (Myanmar)](../my/README.md) | [Chinês (Simplificado)](../zh-CN/README.md) | [Chinês (Tradicional, Hong Kong)](../zh-HK/README.md) | [Chinês (Tradicional, Macau)](../zh-MO/README.md) | [Chinês (Tradicional, Taiwan)](../zh-TW/README.md) | [Croata](../hr/README.md) | [Checo](../cs/README.md) | [Dinamarquês](../da/README.md) | [Holandês](../nl/README.md) | [Estónio](../et/README.md) | [Finlandês](../fi/README.md) | [Francês](../fr/README.md) | [Alemão](../de/README.md) | [Grego](../el/README.md) | [Hebraico](../he/README.md) | [Hindi](../hi/README.md) | [Húngaro](../hu/README.md) | [Indonésio](../id/README.md) | [Italiano](../it/README.md) | [Japonês](../ja/README.md) | [Kannada](../kn/README.md) | [Coreano](../ko/README.md) | [Lituano](../lt/README.md) | [Malaio](../ms/README.md) | [Malaiala](../ml/README.md) | [Marathi](../mr/README.md) | [Nepali](../ne/README.md) | [Pidgin Nigeriano](../pcm/README.md) | [Norueguês](../no/README.md) | [Persa (Farsi)](../fa/README.md) | [Polaco](../pl/README.md) | [Português (Brasil)](../pt-BR/README.md) | [Português (Portugal)](./README.md) | [Punjabi (Gurmukhi)](../pa/README.md) | [Romeno](../ro/README.md) | [Russo](../ru/README.md) | [Sérvio (Cirílico)](../sr/README.md) | [Eslovaco](../sk/README.md) | [Esloveno](../sl/README.md) | [Espanhol](../es/README.md) | [Suaíli](../sw/README.md) | [Sueco](../sv/README.md) | [Tagalog (Filipino)](../tl/README.md) | [Tâmil](../ta/README.md) | [Telugu](../te/README.md) | [Tailandês](../th/README.md) | [Turco](../tr/README.md) | [Ucraniano](../uk/README.md) | [Urdu](../ur/README.md) | [Vietnamita](../vi/README.md)
> **Prefere Clonar Localmente?**
> Este repositório inclui traduções em mais de 50 idiomas, o que aumenta significativamente o tamanho do download. Para clonar sem traduções, utilize o sparse checkout:
> ```bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/AI-For-Beginners.git
> cd AI-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
> ```
> Isto fornece tudo o que precisa para completar o curso com um download muito mais rápido.
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
**Se desejar que sejam disponibilizados mais idiomas para tradução, consulte a lista [aqui](https://github.com/Azure/co-op-translator/blob/main/getting_started/supported-languages.md)**
## Junte-se à Comunidade
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
## O que vai aprender
**[Mapa mental do Curso](http://soshnikov.com/courses/ai-for-beginners/mindmap.html)**
Neste currículo, irá aprender:
* Diferentes abordagens à Inteligência Artificial, incluindo a abordagem "antiga e boa" simbólica com **Representação do Conhecimento** e raciocínio ([GOFAI](https://en.wikipedia.org/wiki/Symbolic_artificial_intelligence)).
* **Redes Neuronais** e **Aprendizagem Profunda**, que estão no centro da IA moderna. Iremos ilustrar os conceitos por trás destes tópicos importantes utilizando código em dois dos frameworks mais populares - [TensorFlow](http://Tensorflow.org) e [PyTorch](http://pytorch.org).
* **Arquiteturas Neuronais** para trabalhar com imagens e texto. Cobriremos modelos recentes, embora possam faltar alguns do estado da arte.
* Abordagens menos populares, como **Algoritmos Genéticos** e **Sistemas Multi-Agentes**.
O que não iremos cobrir neste currículo:
> [Encontre todos os recursos adicionais para este curso na nossa coleção Microsoft Learn](https://learn.microsoft.com/en-us/collections/7w28iy2xrqzdj0?WT.mc_id=academic-77998-bethanycheum)
* Casos de negócio de utilização de **IA nos Negócios**. Considere fazer o percurso de aprendizagem [Introdução à IA para utilizadores de negócios](https://docs.microsoft.com/learn/paths/introduction-ai-for-business-users/?WT.mc_id=academic-77998-bethanycheum) na Microsoft Learn, ou a [AI Business School](https://www.microsoft.com/ai/ai-business-school/?WT.mc_id=academic-77998-bethanycheum), desenvolvida em cooperação com a [INSEAD](https://www.insead.edu/).
* **Aprendizagem Automática Clássica**, que está bem descrita no nosso [Currículo de Aprendizagem Automática para Iniciantes](http://github.com/Microsoft/ML-for-Beginners).
* Aplicações práticas de IA construídas com **[Serviços Cognitivos](https://azure.microsoft.com/services/cognitive-services/?WT.mc_id=academic-77998-bethanycheum)**. Para isso, recomendamos que comece pelos módulos Microsoft Learn para [visão](https://docs.microsoft.com/learn/paths/create-computer-vision-solutions-azure-cognitive-services/?WT.mc_id=academic-77998-bethanycheum), [processamento de linguagem natural](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-77998-bethanycheum), **[IA Generativa com Azure OpenAI Service](https://learn.microsoft.com/en-us/training/paths/develop-ai-solutions-azure-openai/?WT.mc_id=academic-77998-bethanycheum)** e outros.
* **Frameworks Cloud específicos para ML**, como [Azure Machine Learning](https://azure.microsoft.com/services/machine-learning/?WT.mc_id=academic-77998-bethanycheum), [Microsoft Fabric](https://learn.microsoft.com/en-us/training/paths/get-started-fabric/?WT.mc_id=academic-77998-bethanycheum), ou [Azure Databricks](https://docs.microsoft.com/learn/paths/data-engineer-azure-databricks?WT.mc_id=academic-77998-bethanycheum). Considere usar os percursos de aprendizagem [Construir e operar soluções de machine learning com Azure Machine Learning](https://docs.microsoft.com/learn/paths/build-ai-solutions-with-azure-ml-service/?WT.mc_id=academic-77998-bethanycheum) e [Construir e operar soluções de machine learning com Azure Databricks](https://docs.microsoft.com/learn/paths/build-operate-machine-learning-solutions-azure-databricks/?WT.mc_id=academic-77998-bethanycheum).
* **IA Conversacional** e **Chat Bots**. Existe um percurso separado [Criar soluções de IA conversacional](https://docs.microsoft.com/learn/paths/create-conversational-ai-solutions/?WT.mc_id=academic-77998-bethanycheum), e pode também consultar [este artigo de blog](https://soshnikov.com/azure/hello-bot-conversational-ai-on-microsoft-platform/) para mais detalhes.
* **Matemática Profunda** por trás do deep learning. Para isso, recomendamos o livro [Deep Learning](https://www.amazon.com/Deep-Learning-Adaptive-Computation-Machine/dp/0262035618) por Ian Goodfellow, Yoshua Bengio e Aaron Courville, que está também disponível online em [https://www.deeplearningbook.org/](https://www.deeplearningbook.org/).
Para uma introdução suave aos tópicos de _IA na Cloud_ pode considerar fazer o Percurso de Aprendizagem [Começar com inteligência artificial no Azure](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-77998-bethanycheum).
# Conteúdo
| | Ligação da Aula | PyTorch/Keras/TensorFlow | Laboratório |
| :-: | :------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------ |
| 0 | [Configuração do Curso](./lessons/0-course-setup/setup.md) | [Configure o Seu Ambiente de Desenvolvimento](./lessons/0-course-setup/how-to-run.md) | |
| I | [**Introdução à IA**](./lessons/1-Intro/README.md) | | |
| 01 | [Introdução e História da IA](./lessons/1-Intro/README.md) | - | - |
| II | **IA Simbólica** |
| 02 | [Representação do Conhecimento e Sistemas Especialistas](./lessons/2-Symbolic/README.md) | [Sistemas Especialistas](./lessons/2-Symbolic/Animals.ipynb) / [Ontologia](./lessons/2-Symbolic/FamilyOntology.ipynb) /[Grafo de Conceitos](./lessons/2-Symbolic/MSConceptGraph.ipynb) | |
| III | [**Introdução às Redes Neurais**](./lessons/3-NeuralNetworks/README.md) |||
| 03 | [Perceptron](./lessons/3-NeuralNetworks/03-Perceptron/README.md) | [Notebook](./lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb) | [Lab](./lessons/3-NeuralNetworks/03-Perceptron/lab/README.md) |
| 04 | [Perceptron Multicamadas e Criar o nosso próprio Framework](./lessons/3-NeuralNetworks/04-OwnFramework/README.md) | [Notebook](./lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb) | [Lab](./lessons/3-NeuralNetworks/04-OwnFramework/lab/README.md) |
| 05 | [Introdução aos Frameworks (PyTorch/TensorFlow) e Overfitting](./lessons/3-NeuralNetworks/05-Frameworks/README.md) | [PyTorch](./lessons/3-NeuralNetworks/05-Frameworks/IntroPyTorch.ipynb) / [Keras](./lessons/3-NeuralNetworks/05-Frameworks/IntroKeras.ipynb) / [TensorFlow](./lessons/3-NeuralNetworks/05-Frameworks/IntroKerasTF.ipynb) | [Lab](./lessons/3-NeuralNetworks/05-Frameworks/lab/README.md) |
| IV | [**Visão Computacional**](./lessons/4-ComputerVision/README.md) | [PyTorch](https://docs.microsoft.com/learn/modules/intro-computer-vision-pytorch/?WT.mc_id=academic-77998-cacaste) / [TensorFlow](https://docs.microsoft.com/learn/modules/intro-computer-vision-TensorFlow/?WT.mc_id=academic-77998-cacaste)| [Explore Visão Computacional na Microsoft Azure](https://learn.microsoft.com/en-us/collections/7w28iy2xrqzdj0?WT.mc_id=academic-77998-bethanycheum) |
| 06 | [Introdução à Visão Computacional. OpenCV](./lessons/4-ComputerVision/06-IntroCV/README.md) | [Notebook](./lessons/4-ComputerVision/06-IntroCV/OpenCV.ipynb) | [Lab](./lessons/4-ComputerVision/06-IntroCV/lab/README.md) |
| 07 | [Redes Neurais Convolucionais](./lessons/4-ComputerVision/07-ConvNets/README.md) & [Arquiteturas CNN](./lessons/4-ComputerVision/07-ConvNets/CNN_Architectures.md) | [PyTorch](./lessons/4-ComputerVision/07-ConvNets/ConvNetsPyTorch.ipynb) /[TensorFlow](./lessons/4-ComputerVision/07-ConvNets/ConvNetsTF.ipynb) | [Lab](./lessons/4-ComputerVision/07-ConvNets/lab/README.md) |
| 08 | [Redes Pré-treinadas e Transfer Learning](./lessons/4-ComputerVision/08-TransferLearning/README.md) e [Truques de Treino](./lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md) | [PyTorch](./lessons/4-ComputerVision/08-TransferLearning/TransferLearningPyTorch.ipynb) / [TensorFlow](./lessons/3-NeuralNetworks/05-Frameworks/IntroKerasTF.ipynb) | [Lab](./lessons/4-ComputerVision/08-TransferLearning/lab/README.md) |
| 09 | [Autoencoders e VAEs](./lessons/4-ComputerVision/09-Autoencoders/README.md) | [PyTorch](./lessons/4-ComputerVision/09-Autoencoders/AutoEncodersPyTorch.ipynb) / [TensorFlow](./lessons/4-ComputerVision/09-Autoencoders/AutoencodersTF.ipynb) | |
| 10 | [Redes Adversariais Generativas & Transferência de Estilo Artístico](./lessons/4-ComputerVision/10-GANs/README.md) | [PyTorch](./lessons/4-ComputerVision/10-GANs/GANPyTorch.ipynb) / [TensorFlow](./lessons/4-ComputerVision/10-GANs/GANTF.ipynb) | |
| 11 | [Deteção de Objetos](./lessons/4-ComputerVision/11-ObjectDetection/README.md) | [TensorFlow](./lessons/4-ComputerVision/11-ObjectDetection/ObjectDetection.ipynb) | [Lab](./lessons/4-ComputerVision/11-ObjectDetection/lab/README.md) |
| 12 | [Segmentação Semântica. U-Net](./lessons/4-ComputerVision/12-Segmentation/README.md) | [PyTorch](./lessons/4-ComputerVision/12-Segmentation/SemanticSegmentationPytorch.ipynb) / [TensorFlow](./lessons/4-ComputerVision/12-Segmentation/SemanticSegmentationTF.ipynb) | |
| V | [**Processamento de Linguagem Natural**](./lessons/5-NLP/README.md) | [PyTorch](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/?WT.mc_id=academic-77998-cacaste) /[TensorFlow](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-TensorFlow/?WT.mc_id=academic-77998-cacaste) | [Explore Processamento de Linguagem Natural na Microsoft Azure](https://learn.microsoft.com/en-us/collections/7w28iy2xrqzdj0?WT.mc_id=academic-77998-bethanycheum)|
| 13 | [Representação de Texto. Bow/TF-IDF](./lessons/5-NLP/13-TextRep/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/13-TextRep/TextRepresentationPyTorch.ipynb) / [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb) | |
| 14 | [Embeddings Semânticos de Palavras. Word2Vec e GloVe](./lessons/5-NLP/14-Embeddings/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb) / [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/14-Embeddings/EmbeddingsTF.ipynb) | |
| 15 | [Modelação de Linguagem. Treinar os seus próprios Embeddings](./lessons/5-NLP/15-LanguageModeling/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/15-LanguageModeling/CBoW-PyTorch.ipynb) / [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/15-LanguageModeling/CBoW-TF.ipynb) | [Lab](./lessons/5-NLP/15-LanguageModeling/lab/README.md) |
| 16 | [Redes Neurais Recorrentes](./lessons/5-NLP/16-RNN/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/16-RNN/RNNPyTorch.ipynb) / [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/16-RNN/RNNTF.ipynb) | |
| 17 | [Redes Recorrentes Generativas](./lessons/5-NLP/17-GenerativeNetworks/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/17-GenerativeNetworks/GenerativePyTorch.ipynb) / [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb) | [Lab](./lessons/5-NLP/17-GenerativeNetworks/lab/README.md) |
| 18 | [Transformadores. BERT.](./lessons/5-NLP/18-Transformers/README.md) | [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/18-Transformers/TransformersPyTorch.ipynb) /[TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/18-Transformers/TransformersTF.ipynb) | |
| 19 | [Reconhecimento de Entidades Nomeadas](./lessons/5-NLP/19-NER/README.md) | [TensorFlow](https://microsoft.github.io/AI-For-Beginners/lessons/5-NLP/19-NER/NER-TF.ipynb) | [Lab](./lessons/5-NLP/19-NER/lab/README.md) |
| 20 | [Modelos de Linguagem Grandes, Programação de Prompt e Tarefas Few-Shot](./lessons/5-NLP/20-LangModels/README.md) | [PyTorch](https://microsoft.github.io/AI-For-Beginners/lessons/5-NLP/20-LangModels/GPT-PyTorch.ipynb) | |
| VI | **Outras Técnicas de IA** || |
| 21 | [Algoritmos Genéticos](./lessons/6-Other/21-GeneticAlgorithms/README.md) | [Notebook](./lessons/6-Other/21-GeneticAlgorithms/Genetic.ipynb) | |
| 22 | [Aprendizagem por Reforço Profundo](./lessons/6-Other/22-DeepRL/README.md) | [PyTorch](./lessons/6-Other/22-DeepRL/CartPole-RL-PyTorch.ipynb) /[TensorFlow](./lessons/6-Other/22-DeepRL/CartPole-RL-TF.ipynb) | [Lab](./lessons/6-Other/22-DeepRL/lab/README.md) |
| 23 | [Sistemas Multi-Agente](./lessons/6-Other/23-MultiagentSystems/README.md) | | |
| VII | **Ética na IA** | | |
| 24 | [Ética na IA e IA Responsável](./lessons/7-Ethics/README.md) | [Microsoft Learn: Princípios de IA Responsável](https://docs.microsoft.com/learn/paths/responsible-ai-business-principles/?WT.mc_id=academic-77998-cacaste) | |
| IX | **Extras** | | |
| 25 | [Redes Multi-Modais, CLIP e VQGAN](./lessons/X-Extras/X1-MultiModal/README.md) | [Notebook](./lessons/X-Extras/X1-MultiModal/Clip.ipynb) | |
## Cada lição contém
* Material de pré-leitura
* Jupyter Notebooks executáveis, que são frequentemente específicos para o framework (**PyTorch** ou **TensorFlow**). O notebook executável também contém muito material teórico, pelo que para compreender o tópico tem de percorrer pelo menos uma versão do notebook (seja PyTorch ou TensorFlow).
* **Labs** disponíveis para alguns tópicos, que lhe dão a oportunidade de tentar aplicar o material que aprendeu a um problema específico.
* Algumas secções contêm ligações para módulos do [**MS Learn**](https://learn.microsoft.com/en-us/collections/7w28iy2xrqzdj0?WT.mc_id=academic-77998-bethanycheum) que cobrem tópicos relacionados.
## Começar
### 🎯 Novo em IA? Comece Aqui!
Se é completamente novo em IA e quer exemplos práticos rápidos, veja os nossos [**Exemplos Amigáveis para Iniciantes**](./examples/README.md)! Estes incluem:
- 🌟 **Olá Mundo IA** - O seu primeiro programa de IA (reconhecimento de padrões)
- 🧠 **Rede Neural Simples** - Construa uma rede neural do zero
- 🖼️ **Classificador de Imagens** - Classifique imagens com comentários detalhados
- 💬 **Sentimento do Texto** - Analise textos positivos/negativos
Estes exemplos são concebidos para ajudar a compreender os conceitos de IA antes de avançar para o currículo completo.
### 📚 Configuração do Currículo Completo
- Criámos uma [lição de configuração](./lessons/0-course-setup/setup.md) para o ajudar a configurar o seu ambiente de desenvolvimento. - Para Educadores, também criámos uma [lição de configuração do currículo](./lessons/0-course-setup/for-teachers.md)!
- Como [Executar o código no VSCode ou num Codespace](./lessons/0-course-setup/how-to-run.md)
Siga estes passos:
Fork do Repositório: Clique no botão "Fork" no canto superior direito desta página.
Clone o Repositório: `git clone https://github.com/microsoft/AI-For-Beginners.git`
Não se esqueça de dar estrela (🌟) a este repositório para o encontrar mais facilmente depois.
## Conheça outros Aprendentes
Junte-se ao nosso [servidor oficial AI Discord](https://aka.ms/genai-discord?WT.mc_id=academic-105485-bethanycheum) para conhecer e interagir com outros aprendentes que estão a fazer este curso e obter suporte.
Se tiver feedback sobre produtos ou dúvidas enquanto programa, visite o nosso [Fórum de Desenvolvedores Azure AI Foundry](https://aka.ms/foundry/forum)
## Questionários
> **Nota sobre os questionários**: Todos os questionários estão contidos na pasta Quiz-app em etc\quiz-app, ou [Online Aqui](https://ff-quizzes.netlify.app/) Estão ligados a partir das lições, a aplicação dos questionários pode ser executada localmente ou implantada no Azure; siga as instruções na pasta `quiz-app`. Estão a ser gradualmente localizados.
## Ajuda Necessária
Tem sugestões ou encontrou erros de ortografia ou de código? Levante uma issue ou crie um pull request.
## Agradecimentos Especiais
* **✍️ Autor Principal:** [Dmitry Soshnikov](http://soshnikov.com), PhD
* **🔥 Editor:** [Jen Looper](https://twitter.com/jenlooper), PhD
* **🎨 Ilustradora Sketchnote:** [Tomomi Imura](https://twitter.com/girlie_mac)
* **✅ Criadora de Questionários:** [Lateefah Bello](https://github.com/CinnamonXI), [MLSA](https://studentambassadors.microsoft.com/)
* **🙏 Contribuidores Principais:** [Evgenii Pishchik](https://github.com/Pe4enIks)
## Outros Currículos
A nossa equipa produz outros currículos! Confira:
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
### LangChain
[![LangChain4j for Beginners](https://img.shields.io/badge/LangChain4j%20for%20Beginners-22C55E?style=for-the-badge&&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchain4j-for-beginners)
[![LangChain.js for Beginners](https://img.shields.io/badge/LangChain.js%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchainjs-for-beginners?WT.mc_id=m365-94501-dwahlin)
---
### Azure / Edge / MCP / Agentes
[![AZD for Beginners](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Edge AI for Beginners](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![MCP for Beginners](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst)
[![AI Agents for Beginners](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### Série de IA Generativa
[![Generative AI for Beginners](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Generative AI (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst)
[![Generative AI (Java)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst)
[![Generative AI (JavaScript)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst)
---
### Aprendizagem Base
[![ML for Beginners](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst)
[![Data Science for Beginners](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst)
[![AI for Beginners](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst)
[![Cybersecurity for Beginners](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung)
[![Web Dev for Beginners](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst)
[![IoT for Beginners](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst)
[![XR Development for Beginners](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### Série Copilot
[![Copilot for AI Paired Programming](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst)
[![Copilot for C#/.NET](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst)
[![Copilot Adventure](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst)
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
## Obter Ajuda
Se ficar bloqueado ou tiver dúvidas sobre como construir aplicações de IA. Junte-se a outros aprendentes e desenvolvedores experientes em discussões sobre MCP. É uma comunidade de apoio onde as perguntas são bem-vindas e o conhecimento é partilhado livremente.
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
Se tiver feedback sobre produtos ou erros durante o desenvolvimento visite:
[![Microsoft Foundry Developer Forum](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informação crítica, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,40 @@
## Segurança
A Microsoft leva a segurança dos seus produtos de software e serviços muito a sério, incluindo todos os repositórios de código fonte geridos através das nossas organizações no GitHub, que incluem [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin) e [as nossas organizações no GitHub](https://opensource.microsoft.com/).
Se acredita ter encontrado uma vulnerabilidade de segurança em qualquer repositório pertencente à Microsoft que se enquadre na [definição de vulnerabilidade de segurança da Microsoft](https://aka.ms/opensource/security/definition), por favor reporte-a conforme descrito abaixo.
## Reportar Problemas de Segurança
**Por favor, não reporte vulnerabilidades de segurança através de issues públicas no GitHub.**
Em vez disso, reporte-as ao Microsoft Security Response Center (MSRC) em [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
Se preferir submeter sem iniciar sessão, envie um email para [secure@microsoft.com](mailto:secure@microsoft.com). Se possível, encripte a sua mensagem com a nossa chave PGP; pode descarregá-la na [página da chave PGP do Microsoft Security Response Center](https://aka.ms/opensource/security/pgpkey).
Deverá receber uma resposta dentro de 24 horas. Se, por algum motivo, não receber, por favor envie um email de seguimento para garantir que recebemos a sua mensagem original. Informações adicionais podem ser encontradas em [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Inclua as informações solicitadas abaixo (tanto quanto possível) para nos ajudar a compreender melhor a natureza e o alcance do possível problema:
* Tipo de problema (ex.: buffer overflow, SQL injection, cross-site scripting, etc.)
* Caminhos completos dos ficheiros fonte relacionados com a manifestação do problema
* A localização do código fonte afetado (tag/branch/commit ou URL direto)
* Qualquer configuração especial necessária para reproduzir o problema
* Instruções passo-a-passo para reproduzir o problema
* Código de prova de conceito ou de exploração (se possível)
* Impacto do problema, incluindo como um atacante poderia explorar o problema
Estas informações ajudarão a agilizar a triagem do seu relatório.
Se estiver a reportar para um programa de recompensas por bugs, relatórios mais completos podem contribuir para uma recompensa maior. Por favor, visite a página do [Programa de Recompensas por Bugs da Microsoft](https://aka.ms/opensource/security/bounty) para mais detalhes sobre os nossos programas ativos.
## Idiomas Preferidos
Preferimos que todas as comunicações sejam feitas em inglês.
## Política
A Microsoft segue o princípio de [Divulgação Coordenada de Vulnerabilidades](https://aka.ms/opensource/security/cvd).
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.

View File

@ -0,0 +1,12 @@
# Código de Conduta de Código Aberto da Microsoft
Este projeto adotou o [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/).
Recursos:
- [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/)
- [FAQ do Código de Conduta da Microsoft](https://opensource.microsoft.com/codeofconduct/faq/)
- Contacte [opencode@microsoft.com](mailto:opencode@microsoft.com) para questões ou preocupações
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,22 @@
# Contribuir
Este projeto acolhe contribuições e sugestões. A maioria das contribuições exige que concorde com um Acordo de Licença de Contribuidor (CLA), declarando que tem o direito de, e de facto concede-nos, os direitos para usar a sua contribuição. Para mais detalhes, visite https://cla.microsoft.com.
Quando submeter um pull request, um CLA-bot determinará automaticamente se precisa de fornecer um CLA e decorará o PR de forma apropriada (por exemplo, etiqueta, comentário). Basta seguir as instruções fornecidas pelo bot. Só precisará de fazer isto uma vez em todos os repositórios que utilizam o nosso CLA.
Este projeto adotou o [Código de Conduta de Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/).
Para mais informações, consulte as [Perguntas Frequentes sobre o Código de Conduta](https://opensource.microsoft.com/codeofconduct/faq/)
ou contacte [opencode@microsoft.com](mailto:opencode@microsoft.com) para quaisquer questões ou comentários adicionais.
# Procuramos Contribuições
Estamos atualmente à procura de contribuições ativas nos seguintes tópicos:
- [ ] Escrever uma secção sobre Aprendizagem por Reforço Profunda
- [ ] Melhorar a secção + notebook sobre Deteção de Objetos
- [ ] PyTorch Lightning (para [esta secção](https://github.com/microsoft/AI-For-Beginners/blob/main/3-NeuralNetworks/05-Frameworks/README.md))
- [ ] Escrever uma secção + exemplos sobre Reconhecimento de Entidades Nomeadas
- [ ] Criar exemplos para treinar os nossos próprios embeddings para [esta secção](https://github.com/microsoft/AI-For-Beginners/tree/main/5-NLP/15-LanguageModeling)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,76 @@
# IA
## [Introdução à IA](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/1-Intro/README.md)
- Definição de IA
- História da IA
- Abordagens de IA
- Top-down/Simbólica
- Bottom-up/Neuronal
- Evolutiva
- Sinergética / IA Emergente
- [Microsoft AI Business School](https://www.microsoft.com/ai/ai-business-school/?WT.mc_id=academic-77998-cacaste)
## [IA Simbólica](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/2-Symbolic/README.md)
- Representação de Conhecimento
- [Sistemas Especialistas](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/2-Symbolic/Animals.ipynb)
- [Ontologias](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/2-Symbolic/FamilyOntology.ipynb)
- Web Semântica
## [Redes Neuronais](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/README.md)
- [Perceptrão](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/03-Perceptron/README.md)
- [Redes Multi-Camada](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/04-OwnFramework/README.md)
- [Introdução a Frameworks](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/05-Frameworks/README.md)
- [PyTorch](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/05-Frameworks/IntroPyTorch.ipynb)
- [TensorFlow](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/05-Frameworks/IntroKerasTF.md)
- [Overfitting](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/3-NeuralNetworks/05-Frameworks/Overfitting.md)
## [Visão por Computador](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/README.md)
- No MS Learn
- [Fundamentos de IA: Explorar Visão por Computador](https://docs.microsoft.com/learn/paths/explore-computer-vision-microsoft-azure/?WT.mc_id=academic-77998-cacaste)
- [Visão por Computador com PyTorch](https://docs.microsoft.com/learn/modules/intro-computer-vision-pytorch/?WT.mc_id=academic-77998-cacaste)
- [Visão por Computador com TensorFlow](https://docs.microsoft.com/learn/modules/intro-computer-vision-TensorFlow/?WT.mc_id=academic-77998-cacaste)
- [Introdução à Visão por Computador. OpenCV](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/06-IntroCV/README.md)
- [Redes Convolucionais](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/07-ConvNets/README.md)
- [Arquiteturas de CNN](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/07-ConvNets/CNN_Architectures.md)
- [Transferência de Aprendizagem](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/08-TransferLearning/README.md)
- [Dicas de Treino](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md)
- [Autoencoders e VAEs](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/09-Autoencoders/README.md)
- [Redes Adversárias Generativas](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/10-GANs/README.md)
- [Transferência de Estilo](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/10-GANs/StyleTransfer.ipynb)
- [Deteção de Objetos](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/11-ObjectDetection/README.md)
- [Segmentação](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/4-ComputerVision/12-Segmentation/README.md)
## [Processamento de Linguagem Natural](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/README.md)
- No MS Learn
- [Fundamentos de IA: Explorar PLN](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-77998-cacaste)
- [PLN com PyTorch](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/?WT.mc_id=academic-77998-cacaste)
- [PLN com TensorFlow](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-TensorFlow/?WT.mc_id=academic-77998-cacaste)
- [Representação de Texto](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/13-TextRep/README.md)
- Bag of Words
- TF/IDF
- [Embeddings Semânticos](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/14-Embeddings/README.md)
- Word2Vec
- GloVE
- [Modelagem de Linguagem](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/15-LanguageModeling)
- [Redes Neuronais Recorrentes](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/16-RNN/README.md)
- LSTM
- GRU
- [Redes Recorrentes Generativas](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/17-GenerativeNetworks/README.md)
- [Transformers e BERT](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/18-Transformers/README.md)
- [Reconhecimento de Entidades Nomeadas](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/19-NER/README.md)
- [Geração de Texto e GPT](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/5-NLP/20-LanguageModels/README.md)
## Outras Técnicas
- [Algoritmos Genéticos](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/6-Other/21-GeneticAlgorithms/README.md)
- [Aprendizagem por Reforço Profundo](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/6-Other/22-DeepRL/README.md)
- [Sistemas Multi-Agente](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/6-Other/23-MultiagentSystems/README.md)
## [Ética na IA](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/7-Ethics/README.md)
- [MS Learn sobre IA Responsável](https://docs.microsoft.com/learn/paths/responsible-ai-business-principles/?WT.mc_id=academic-77998-cacaste)
## Extras
- [Redes Multimodais](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/X-Extras/X1-MultiModal/README.md)
- [CLIP](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/X-Extras/X1-MultiModal/Clip.ipynb)
- DALL-E
- VQ-GAN
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.

View File

@ -0,0 +1,14 @@
# Suporte
## Como reportar problemas e obter ajuda
Este projeto utiliza o GitHub Issues para rastrear erros e pedidos de funcionalidades. Por favor, pesquise os problemas existentes antes de criar novos para evitar duplicados. Para novos problemas, reporte o seu erro ou pedido de funcionalidade como um novo Issue.
Para obter ajuda e esclarecer dúvidas sobre a utilização deste projeto, utilize os Fóruns de Discussão.
## Política de Suporte da Microsoft
O suporte para este projeto está limitado aos recursos listados acima.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.

View File

@ -0,0 +1,36 @@
# Contribuir traduzindo lições
Agradecemos as traduções para as lições deste currículo!
## Diretrizes
Existem pastas em cada pasta de lição e na pasta de introdução da lição que contêm os ficheiros markdown traduzidos.
> Nota: por favor, não traduza nenhum código nos ficheiros de exemplo de código; as únicas coisas a traduzir são README, tarefas e os questionários. Obrigado!
Os ficheiros traduzidos devem seguir esta convenção de nomenclatura:
**README._[language]_.md**
onde _[language]_ é uma abreviação de duas letras do idioma, seguindo o padrão ISO 639-1 (por exemplo, `README.es.md` para Espanhol e `README.nl.md` para Holandês).
**assignment._[language]_.md**
Semelhante aos Readme's, por favor, traduza também as tarefas.
**Questionários**
1. Adicione a sua tradução à aplicação de questionários adicionando um ficheiro aqui: https://github.com/microsoft/AI-For-Beginners/tree/main/etc/quiz-app/src/assets/translations, com a convenção de nomenclatura adequada (en.json, fr.json). **Por favor, não localize as palavras 'true' ou 'false'. Obrigado!**
2. Adicione o código do seu idioma ao menu suspenso no ficheiro App.vue da aplicação de questionários.
3. Edite o [ficheiro index.js de traduções](https://github.com/microsoft/AI-For-Beginners/blob/main/etc/quiz-app/src/assets/translations/index.js) da aplicação de questionários para adicionar o seu idioma.
4. Por fim, edite TODOS os links dos questionários nos seus ficheiros README.md traduzidos para apontar diretamente para o seu questionário traduzido: https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/1 torna-se https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/1?loc=id
**OBRIGADO**
Agradecemos verdadeiramente os seus esforços!
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,128 @@
# Questionários
Estes questionários são os questionários pré e pós-aula para o currículo de IA em https://aka.ms/ai-beginners
## Adicionar um conjunto de questionários traduzidos
Adicione uma tradução de questionário criando estruturas de questionários correspondentes nas pastas `assets/translations`. Os questionários originais estão em `assets/translations/en`. Os questionários estão divididos em vários grupos por lição. Certifique-se de alinhar a numeração com a secção correta do questionário. Existem 40 questionários no total neste currículo, começando a contagem em 0.
Depois de editar as traduções, edite o ficheiro index.js na pasta de tradução para importar todos os ficheiros seguindo as convenções em `en`.
Edite o ficheiro `index.js` em `assets/translations` para importar os novos ficheiros traduzidos.
De seguida, edite o menu suspenso em `App.vue` nesta aplicação para adicionar o seu idioma. Combine a abreviatura localizada com o nome da pasta do seu idioma.
Por fim, edite todos os links dos questionários nas lições traduzidas, se existirem, para incluir esta localização como um parâmetro de consulta: `?loc=fr`, por exemplo.
## Configuração do projeto
```
npm install
```
### Compilar e recarregar automaticamente para desenvolvimento
```
npm run serve
```
### Compilar e minimizar para produção
```
npm run build
```
### Verificar e corrigir ficheiros
```
npm run lint
```
### Personalizar configuração
Consulte [Referência de Configuração](https://cli.vuejs.org/config/).
Créditos: Agradecimentos à versão original desta aplicação de questionários: https://github.com/arpan45/simple-quiz-vue
## Implementar no Azure
Aqui está um guia passo a passo para o ajudar a começar:
1. Faça um fork do repositório GitHub
Certifique-se de que o código da sua aplicação web estático está no seu repositório GitHub. Faça um fork deste repositório.
2. Crie uma Aplicação Web Estática no Azure
- Crie uma [conta Azure](http://azure.microsoft.com)
- Aceda ao [portal do Azure](https://portal.azure.com)
- Clique em “Criar um recurso” e procure por “Aplicação Web Estática”.
- Clique em “Criar”.
3. Configure a Aplicação Web Estática
- Básico:
- Subscrição: Selecione a sua subscrição do Azure.
- Grupo de Recursos: Crie um novo grupo de recursos ou utilize um existente.
- Nome: Forneça um nome para a sua aplicação web estática.
- Região: Escolha a região mais próxima dos seus utilizadores.
- #### Detalhes de Implementação:
- Fonte: Selecione “GitHub”.
- Conta GitHub: Autorize o Azure a aceder à sua conta GitHub.
- Organização: Selecione a sua organização GitHub.
- Repositório: Escolha o repositório que contém a sua aplicação web estática.
- Ramo: Selecione o ramo a partir do qual deseja implementar.
- #### Detalhes de Construção:
- Predefinições de Construção: Escolha o framework com o qual a sua aplicação foi construída (por exemplo, React, Angular, Vue, etc.).
- Localização da Aplicação: Especifique a pasta que contém o código da sua aplicação (por exemplo, / se estiver na raiz).
- Localização da API: Se tiver uma API, especifique a sua localização (opcional).
- Localização de Saída: Especifique a pasta onde a saída da construção é gerada (por exemplo, build ou dist).
4. Rever e Criar
Revise as suas definições e clique em “Criar”. O Azure configurará os recursos necessários e criará um ficheiro de workflow do GitHub Actions no seu repositório.
5. Workflow do GitHub Actions
O Azure criará automaticamente um ficheiro de workflow do GitHub Actions no seu repositório (.github/workflows/azure-static-web-apps-<name>.yml). Este workflow irá gerir o processo de construção e implementação.
6. Monitorizar a Implementação
Aceda ao separador “Actions” no seu repositório GitHub.
Deverá ver um workflow em execução. Este workflow irá construir e implementar a sua aplicação web estática no Azure.
Assim que o workflow for concluído, a sua aplicação estará ativa no URL fornecido pelo Azure.
### Exemplo de Ficheiro de Workflow
Aqui está um exemplo de como poderá ser o ficheiro de workflow do GitHub Actions:
name: Azure Static Web Apps CI/CD
```
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy_job:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v2
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "etc/quiz-app # App source code path"
api_location: ""API source code path optional
output_location: "dist" #Built app content directory - optional
```
### Recursos Adicionais
- [Documentação de Aplicações Web Estáticas do Azure](https://learn.microsoft.com/azure/static-web-apps/getting-started)
- [Documentação do GitHub Actions](https://docs.github.com/actions/use-cases-and-examples/deploying/deploying-to-azure-static-web-app)
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,395 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Classificador de Imagens Simples\n",
"\n",
"Este notebook mostra como classificar imagens utilizando uma rede neural pré-treinada.\n",
"\n",
"**O que irá aprender:**\n",
"- Como carregar e usar um modelo pré-treinado\n",
"- Pré-processamento de imagens\n",
"- Fazer previsões em imagens\n",
"- Compreender os níveis de confiança\n",
"\n",
"**Caso de uso:** Identificar objetos em imagens (como \"gato\", \"cão\", \"carro\", etc.)\n",
"\n",
"---\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Passo 1: Importar Bibliotecas Necessárias\n",
"\n",
"Vamos importar as ferramentas de que precisamos. Não se preocupe se ainda não entender todas elas!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Core libraries\n",
"import numpy as np\n",
"from PIL import Image\n",
"import requests\n",
"from io import BytesIO\n",
"\n",
"# TensorFlow for deep learning\n",
"try:\n",
" import tensorflow as tf\n",
" from tensorflow.keras.applications import MobileNetV2\n",
" from tensorflow.keras.applications.mobilenet_v2 import preprocess_input, decode_predictions\n",
" print(\"✅ TensorFlow loaded successfully!\")\n",
" print(f\" Version: {tf.__version__}\")\n",
"except ImportError:\n",
" print(\"❌ Please install TensorFlow: pip install tensorflow\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Passo 2: Carregar o Modelo Pré-treinado\n",
"\n",
"Vamos usar o **MobileNetV2**, uma rede neural já treinada em milhões de imagens.\n",
"\n",
"Isto é chamado de **Transferência de Aprendizagem** - usar um modelo que outra pessoa já treinou!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"📦 Loading pre-trained MobileNetV2 model...\")\n",
"print(\" This may take a minute on first run (downloading weights)...\")\n",
"\n",
"# Load the model\n",
"# include_top=True means we use the classification layer\n",
"# weights='imagenet' means it was trained on ImageNet dataset\n",
"model = MobileNetV2(weights='imagenet', include_top=True)\n",
"\n",
"print(\"✅ Model loaded!\")\n",
"print(f\" The model can recognize 1000 different object categories\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Passo 3: Funções Auxiliares\n",
"\n",
"Vamos criar funções para carregar e preparar imagens para o nosso modelo.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def load_image_from_url(url):\n",
" \"\"\"\n",
" Load an image from a URL.\n",
" \n",
" Args:\n",
" url: Web address of the image\n",
" \n",
" Returns:\n",
" PIL Image object\n",
" \"\"\"\n",
" response = requests.get(url)\n",
" img = Image.open(BytesIO(response.content))\n",
" return img\n",
"\n",
"\n",
"def prepare_image(img):\n",
" \"\"\"\n",
" Prepare an image for the model.\n",
" \n",
" Steps:\n",
" 1. Resize to 224x224 (model's expected size)\n",
" 2. Convert to array\n",
" 3. Add batch dimension\n",
" 4. Preprocess for MobileNetV2\n",
" \n",
" Args:\n",
" img: PIL Image\n",
" \n",
" Returns:\n",
" Preprocessed image array\n",
" \"\"\"\n",
" # Resize to 224x224 pixels\n",
" img = img.resize((224, 224))\n",
" \n",
" # Convert to numpy array\n",
" img_array = np.array(img)\n",
" \n",
" # Add batch dimension (model expects multiple images)\n",
" img_array = np.expand_dims(img_array, axis=0)\n",
" \n",
" # Preprocess for MobileNetV2\n",
" img_array = preprocess_input(img_array)\n",
" \n",
" return img_array\n",
"\n",
"\n",
"def classify_image(img):\n",
" \"\"\"\n",
" Classify an image and return top predictions.\n",
" \n",
" Args:\n",
" img: PIL Image\n",
" \n",
" Returns:\n",
" List of (class_name, confidence) tuples\n",
" \"\"\"\n",
" # Prepare the image\n",
" img_array = prepare_image(img)\n",
" \n",
" # Make prediction\n",
" predictions = model.predict(img_array, verbose=0)\n",
" \n",
" # Decode predictions to human-readable labels\n",
" # top=5 means we get the top 5 most likely classes\n",
" decoded = decode_predictions(predictions, top=5)[0]\n",
" \n",
" # Convert to simpler format\n",
" results = [(label, float(confidence)) for (_, label, confidence) in decoded]\n",
" \n",
" return results\n",
"\n",
"\n",
"print(\"✅ Helper functions ready!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Passo 4: Testar em Imagens de Exemplo\n",
"\n",
"Vamos tentar classificar algumas imagens da internet!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sample images to classify\n",
"# These are from Unsplash (free stock photos)\n",
"test_images = [\n",
" {\n",
" \"url\": \"https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=400\",\n",
" \"description\": \"A cat\"\n",
" },\n",
" {\n",
" \"url\": \"https://images.unsplash.com/photo-1552053831-71594a27632d?w=400\",\n",
" \"description\": \"A dog\"\n",
" },\n",
" {\n",
" \"url\": \"https://images.unsplash.com/photo-1511919884226-fd3cad34687c?w=400\",\n",
" \"description\": \"A car\"\n",
" },\n",
"]\n",
"\n",
"print(f\"🧪 Testing on {len(test_images)} images...\")\n",
"print(\"=\" * 70)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Classificar Cada Imagem\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for i, img_data in enumerate(test_images, 1):\n",
" print(f\"\\n📸 Image {i}: {img_data['description']}\")\n",
" print(\"-\" * 70)\n",
" \n",
" try:\n",
" # Load image\n",
" img = load_image_from_url(img_data['url'])\n",
" \n",
" # Display image\n",
" display(img.resize((200, 200))) # Show smaller version\n",
" \n",
" # Classify\n",
" results = classify_image(img)\n",
" \n",
" # Show predictions\n",
" print(\"\\n🎯 Top 5 Predictions:\")\n",
" for rank, (label, confidence) in enumerate(results, 1):\n",
" # Create a visual bar\n",
" bar_length = int(confidence * 50)\n",
" bar = \"█\" * bar_length\n",
" \n",
" print(f\" {rank}. {label:20s} {confidence*100:5.2f}% {bar}\")\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error: {e}\")\n",
"\n",
"print(\"\\n\" + \"=\" * 70)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Passo 5: Experimente com as suas próprias imagens!\n",
"\n",
"Substitua o URL abaixo por qualquer URL de imagem que deseje classificar.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Try your own image!\n",
"# Replace this URL with any image URL\n",
"custom_image_url = \"https://images.unsplash.com/photo-1472491235688-bdc81a63246e?w=400\" # A flower\n",
"\n",
"print(\"🖼️ Classifying your custom image...\")\n",
"print(\"=\" * 70)\n",
"\n",
"try:\n",
" # Load and show image\n",
" img = load_image_from_url(custom_image_url)\n",
" display(img.resize((300, 300)))\n",
" \n",
" # Classify\n",
" results = classify_image(img)\n",
" \n",
" # Show results\n",
" print(\"\\n🎯 Top 5 Predictions:\")\n",
" print(\"-\" * 70)\n",
" for rank, (label, confidence) in enumerate(results, 1):\n",
" bar_length = int(confidence * 50)\n",
" bar = \"█\" * bar_length\n",
" print(f\" {rank}. {label:20s} {confidence*100:5.2f}% {bar}\")\n",
" \n",
" # Highlight top prediction\n",
" top_label, top_confidence = results[0]\n",
" print(\"\\n\" + \"=\" * 70)\n",
" print(f\"\\n🏆 Best guess: {top_label} ({top_confidence*100:.2f}% confident)\")\n",
" \n",
"except Exception as e:\n",
" print(f\"❌ Error: {e}\")\n",
" print(\" Make sure the URL points to a valid image!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 O que acabou de acontecer?\n",
"\n",
"1. **Carregámos um modelo pré-treinado** - O MobileNetV2 foi treinado com milhões de imagens \n",
"2. **Pré-processámos as imagens** - Redimensionámos e formatámos para o modelo \n",
"3. **O modelo fez previsões** - Produziu probabilidades para 1000 classes de objetos \n",
"4. **Decodificámos os resultados** - Convertendo números em etiquetas legíveis por humanos \n",
"\n",
"### Compreender os níveis de confiança\n",
"\n",
"- **90-100%**: Muito confiante (quase certamente correto) \n",
"- **70-90%**: Confiante (provavelmente correto) \n",
"- **50-70%**: Moderadamente confiante (pode estar correto) \n",
"- **Abaixo de 50%**: Pouco confiante (incerto) \n",
"\n",
"### Por que é que as previsões podem estar erradas?\n",
"\n",
"- **Ângulo ou iluminação incomuns** - O modelo foi treinado com fotos típicas \n",
"- **Objetos múltiplos** - O modelo espera um objeto principal \n",
"- **Objetos raros** - O modelo só conhece 1000 categorias \n",
"- **Imagem de baixa qualidade** - Imagens desfocadas ou pixelizadas são mais difíceis \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🚀 Próximos Passos\n",
"\n",
"1. **Experimente diferentes imagens:**\n",
" - Encontre imagens em [Unsplash](https://unsplash.com)\n",
" - Clique com o botão direito → \"Copiar endereço da imagem\" para obter o URL\n",
"\n",
"2. **Experimente:**\n",
" - O que acontece com arte abstrata?\n",
" - Consegue reconhecer objetos de diferentes ângulos?\n",
" - Como lida com múltiplos objetos?\n",
"\n",
"3. **Saiba mais:**\n",
" - Explore as [lições sobre Visão Computacional](../lessons/4-ComputerVision/README.md)\n",
" - Aprenda a treinar o seu próprio classificador de imagens\n",
" - Compreenda como funcionam as CNNs (Redes Neurais Convolucionais)\n",
"\n",
"---\n",
"\n",
"## 🎉 Parabéns!\n",
"\n",
"Acabou de construir um classificador de imagens utilizando uma rede neural de última geração!\n",
"\n",
"Esta mesma técnica é utilizada em:\n",
"- Google Photos (organização das suas fotos)\n",
"- Carros autónomos (reconhecimento de objetos)\n",
"- Diagnóstico médico (análise de radiografias)\n",
"- Controlo de qualidade (detecção de defeitos)\n",
"\n",
"Continue a explorar e a aprender! 🚀\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
},
"coopTranslator": {
"original_hash": "1d472141d9df46b751542b3c29f88677",
"translation_date": "2025-10-03T11:44:04+00:00",
"source_file": "examples/03-image-classifier.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,85 @@
# Exemplos de IA para Iniciantes
Bem-vindo! Este diretório contém exemplos simples e independentes para ajudá-lo a começar com IA e aprendizagem automática. Cada exemplo foi projetado para ser acessível a iniciantes, com comentários detalhados e explicações passo a passo.
## 📚 Visão Geral dos Exemplos
| Exemplo | Descrição | Dificuldade | Pré-requisitos |
|---------|-------------|------------|---------------|
| [Hello AI World](../../../examples/01-hello-ai-world.py) | O seu primeiro programa de IA - reconhecimento de padrões simples | ⭐ Iniciante | Noções básicas de Python |
| [Simple Neural Network](../../../examples/02-simple-neural-network.py) | Construa uma rede neural do zero | ⭐⭐ Iniciante+ | Python, matemática básica |
| [Image Classifier](./03-image-classifier.ipynb) | Classifique imagens com um modelo pré-treinado | ⭐⭐ Iniciante+ | Python, numpy |
| [Text Sentiment](../../../examples/04-text-sentiment.py) | Analise o sentimento de texto (positivo/negativo) | ⭐⭐ Iniciante+ | Python |
## 🚀 Começando
### Pré-requisitos
Certifique-se de ter o Python instalado (recomenda-se a versão 3.8 ou superior). Instale os pacotes necessários:
```bash
# For Python scripts
pip install numpy
# For Jupyter notebooks (image classifier)
pip install jupyter numpy pillow tensorflow
```
Ou utilize o ambiente conda do currículo principal:
```bash
conda env create --name ai4beg --file ../environment.yml
conda activate ai4beg
```
### Executando os Exemplos
**Para scripts Python (.py):**
```bash
python 01-hello-ai-world.py
```
**Para notebooks Jupyter (.ipynb):**
```bash
jupyter notebook 03-image-classifier.ipynb
```
## 📖 Caminho de Aprendizagem
Recomendamos seguir os exemplos na ordem:
1. **Comece com "Hello AI World"** - Aprenda o básico sobre reconhecimento de padrões
2. **Construa uma Rede Neural Simples** - Entenda como funcionam as redes neurais
3. **Experimente o Classificador de Imagens** - Veja a IA em ação com imagens reais
4. **Analise o Sentimento de Texto** - Explore o processamento de linguagem natural
## 💡 Dicas para Iniciantes
- **Leia os comentários no código com atenção** - Eles explicam o que cada linha faz
- **Experimente!** - Tente alterar valores e veja o que acontece
- **Não se preocupe em entender tudo de imediato** - Aprender leva tempo
- **Faça perguntas** - Use o [Fórum de Discussão](https://github.com/microsoft/AI-For-Beginners/discussions)
## 🔗 Próximos Passos
Depois de concluir esses exemplos, explore o currículo completo:
- [Introdução à IA](../lessons/1-Intro/README.md)
- [Redes Neurais](../lessons/3-NeuralNetworks/README.md)
- [Visão Computacional](../lessons/4-ComputerVision/README.md)
- [Processamento de Linguagem Natural](../lessons/5-NLP/README.md)
## 🤝 Contribuindo
Achou esses exemplos úteis? Ajude-nos a melhorá-los:
- Relate problemas ou sugira melhorias
- Adicione mais exemplos para iniciantes
- Melhore a documentação e os comentários
---
*Lembre-se: Todo especialista já foi um iniciante. Boa aprendizagem! 🎓*
---
**Aviso**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.

View File

@ -0,0 +1,26 @@
# Para Educadores
Gostaria de utilizar este currículo na sua sala de aula? Sinta-se à vontade!
Na verdade, pode utilizá-lo diretamente no GitHub, através do GitHub Classroom.
Para isso, faça um fork deste repositório. Vai precisar de criar um repositório para cada lição, por isso será necessário extrair cada pasta para um repositório separado. Desta forma, o [GitHub Classroom](https://classroom.github.com/classrooms) consegue identificar cada lição de forma independente.
Estas [instruções completas](https://github.blog/2020-03-18-set-up-your-digital-classroom-with-github-classroom/) dar-lhe-ão uma ideia de como configurar a sua sala de aula.
## Utilizar o repositório como está
Se preferir utilizar este repositório tal como está, sem recorrer ao GitHub Classroom, também é possível. Apenas terá de comunicar aos seus alunos qual a lição a trabalhar em conjunto.
Num formato online (Zoom, Teams ou outro), pode criar salas de grupo para os questionários e orientar os alunos para os preparar para a aprendizagem. Depois, convide os alunos a realizar os questionários e a submeter as suas respostas como 'issues' num momento específico. Pode fazer o mesmo com os trabalhos, caso queira que os alunos trabalhem de forma colaborativa e aberta.
Se preferir um formato mais privado, peça aos seus alunos para fazerem fork do currículo, lição por lição, para os seus próprios repositórios GitHub como repositórios privados, e dêem-lhe acesso. Assim, poderão completar os questionários e trabalhos de forma privada e submetê-los através de issues no repositório da sua sala de aula.
Existem várias formas de fazer isto funcionar num formato de sala de aula online. Por favor, diga-nos qual funciona melhor para si!
## Por favor, partilhe a sua opinião
Queremos que este currículo funcione para si e para os seus alunos. Por favor, deixe-nos o seu feedback nos fóruns de discussão!
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.

View File

@ -0,0 +1,71 @@
# Como Executar o Código
Este currículo contém muitos exemplos executáveis e laboratórios que você vai querer executar. Para isso, precisa da capacidade de executar código Python nos Jupyter Notebooks fornecidos como parte deste currículo. Tem várias opções para executar o código:
## Executar localmente no seu computador
Para executar o código localmente no seu computador, é necessário uma instalação de Python. Uma recomendação é instalar o **[miniconda](https://conda.io/en/latest/miniconda.html)** - é uma instalação relativamente leve que suporta o gestor de pacotes `conda` para diferentes **ambientes virtuais** Python.
Depois de instalar o miniconda, clone o repositório e crie um ambiente virtual a ser usado para este curso:
```bash
git clone http://github.com/microsoft/ai-for-beginners
cd ai-for-beginners
conda env create --name ai4beg --file .devcontainer/environment.yml
conda activate ai4beg
```
### Usar Visual Studio Code com a Extensão Python
Este currículo é melhor aproveitado quando aberto no [Visual Studio Code](http://code.visualstudio.com/?WT.mc_id=academic-77998-cacaste) com a [Extensão Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python&WT.mc_id=academic-77998-cacaste).
> **Nota**: Depois de clonar e abrir o diretório no VS Code, será sugerido automaticamente que instale extensões Python. Também terá de instalar o miniconda conforme descrito acima.
> **Nota**: Se o VS Code lhe sugerir reabrir o repositório num contentor, deve recusar para usar a instalação local do Python.
### Usar Jupyter no Navegador
Também pode usar um ambiente Jupyter a partir do navegador no seu próprio computador. Tanto o Jupyter clássico como o JupyterHub oferecem um ambiente de desenvolvimento conveniente com auto-completação, realce de código, etc.
Para iniciar o Jupyter localmente, vá para o diretório do curso e execute:
```bash
jupyter notebook
```
ou
```bash
jupyterhub
```
Pode então navegar para qualquer um dos ficheiros `.ipynb`, abrir e começar a trabalhar.
### Executar em contentor
Uma alternativa à instalação do Python seria executar o código num contentor. Como o nosso repositório fornece uma pasta especial `.devcontainer` que indica como construir um contentor para este repositório, o VS Code oferece a oportunidade de reabrir o código num contentor. Isto irá requerer a instalação do Docker, e também será mais complexo, pelo que recomendamos isto para utilizadores mais experientes.
## Executar na Cloud
Se não pretende instalar Python localmente, e tem acesso a alguns recursos na cloud - uma boa alternativa seria executar o código na cloud. Existem várias formas de o fazer:
* Usar **[GitHub Codespaces](https://github.com/features/codespaces)**, que é um ambiente virtual criado para si no GitHub, acessível através de uma interface de navegador VS Code. Se tem acesso ao Codespaces, pode simplesmente clicar no botão **Code** no repositório, iniciar um codespace, e começar a correr em pouco tempo.
* Usar **[Binder](https://mybinder.org/v2/gh/microsoft/ai-for-beginners/HEAD)**. [Binder](https://mybinder.org) oferece recursos computacionais gratuitos providenciados na cloud para pessoas como você testarem algum código no GitHub. Existe um botão na página inicial para abrir o repositório no Binder isto deve levá-lo rapidamente ao site binder, que vai construir um contentor subjacente e iniciar uma interface web Jupyter para si de forma integrada.
> **Nota**: Para prevenir uso indevido, o Binder tem acesso a alguns recursos web bloqueados. Isto pode impedir que algum código funcione, especialmente o que descarrega modelos e/ou conjuntos de dados da Internet pública. Pode precisar de encontrar algumas soluções alternativas. Além disso, os recursos computacionais providenciados pelo Binder são bastante básicos, pelo que o treino será lento, especialmente nas lições mais avançadas e complexas.
## Executar na Cloud com GPU
Algumas das lições mais avançadas deste currículo beneficiariam muito do suporte a GPU. O treino de modelos, por exemplo, pode ser extremamente lento de outra forma. Existem algumas opções que pode seguir, especialmente se tiver acesso à cloud através do [Azure para Estudantes](https://azure.microsoft.com/free/students/?WT.mc_id=academic-77998-cacaste) ou da sua instituição:
* Criar [Máquina Virtual para Ciência de Dados](https://docs.microsoft.com/learn/modules/intro-to-azure-data-science-virtual-machine/?WT.mc_id=academic-77998-cacaste) e ligar-se a ela através do Jupyter. Pode então clonar o repositório diretamente na máquina e começar a aprender. As máquinas virtuais NC-series têm suporte a GPU.
> **Nota**: Algumas subscrições, incluindo o Azure para Estudantes, não fornecem suporte a GPU por defeito. Pode precisar de pedir núcleos de GPU adicionais através de um pedido de suporte técnico.
* Criar um [Workspace Azure Machine Learning](https://azure.microsoft.com/services/machine-learning/?WT.mc_id=academic-77998-cacaste) e depois usar a funcionalidade Notebook aí. [Este vídeo](https://azure-for-academics.github.io/quickstart/azureml-papers/) mostra como clonar um repositório num notebook Azure ML e começar a usar.
Também pode usar o Google Colab, que vem com algum suporte GPU gratuito, e carregar Jupyter Notebooks lá para executá-los um a um.
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos por garantir a precisão, tenha em atenção que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional por um tradutor humano. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,49 @@
# Começar com este Currículo
## És estudante?
Começa com os seguintes recursos:
* [Página do Student Hub](https://docs.microsoft.com/learn/student-hub?WT.mc_id=academic-77998-cacaste) Nesta página, encontrarás recursos para principiantes, pacotes para estudantes e até formas de obter um voucher gratuito para certificação. Esta é uma página que deves marcar como favorita e consultar de tempos a tempos, pois atualizamos o conteúdo pelo menos mensalmente.
* [Microsoft Student Learn Ambassadors](https://studentambassadors.microsoft.com?WT.mc_id=academic-77998-cacaste) Junta-te a uma comunidade global de embaixadores estudantis, esta pode ser a tua porta de entrada para a Microsoft.
**Estudantes**, há algumas formas de usar o currículo. Em primeiro lugar, podes simplesmente ler o texto e explorar o código diretamente no GitHub. Se quiseres executar o código em algum dos notebooks - [lê as nossas instruções](./how-to-run.md) e encontra mais conselhos sobre como fazê-lo [neste post no blog](https://soshnikov.com/education/how-to-execute-notebooks-from-github/).
> **Note**: [Instruções sobre como executar o código neste currículo](./how-to-run.md)
## Estudo Autónomo
No entanto, se preferires fazer o curso como um projeto de estudo autónomo, sugerimos que faças um fork de todo o repositório para a tua própria conta GitHub e completes os exercícios sozinho ou em grupo:
* Começa com um questionário pré-aula.
* Lê o texto introdutório da aula.
* Se a aula tiver notebooks adicionais, explora-os, lendo e executando o código. Se forem fornecidos notebooks tanto para TensorFlow como para PyTorch, podes focar-te num deles - escolhe a tua framework favorita.
* Os notebooks frequentemente contêm desafios que te pedem para ajustar o código um pouco e experimentar.
* Faz o questionário pós-aula.
* Se houver um laboratório associado ao módulo - completa a tarefa.
* Visita o [Fórum de Discussão](https://github.com/microsoft/AI-For-Beginners/discussions) para "aprender em voz alta".
> Para estudo adicional, recomendamos seguir estes módulos e percursos de aprendizagem do [Microsoft Learn](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-77998-cacaste).
**Professores**, incluímos [algumas sugestões](./for-teachers.md) sobre como usar este currículo.
---
## Pedagogia
Escolhemos dois princípios pedagógicos ao construir este currículo: garantir que é **baseado em projetos práticos** e que inclui **questionários frequentes**.
Ao garantir que o conteúdo está alinhado com projetos, o processo torna-se mais envolvente para os estudantes e a retenção dos conceitos será aumentada. Além disso, um questionário de baixa pressão antes de uma aula define a intenção do estudante para aprender um tópico, enquanto um segundo questionário após a aula garante uma maior retenção. Este currículo foi desenhado para ser flexível e divertido, podendo ser seguido na totalidade ou em parte. Os projetos começam pequenos e tornam-se progressivamente mais complexos ao longo do ciclo de 12 semanas.
> **Uma nota sobre os questionários**: Todos os questionários estão contidos [nesta aplicação](https://red-field-0a6ddfd03.1.azurestaticapps.net/), num total de 50 questionários com três perguntas cada. Estão ligados dentro das lições, mas a aplicação de questionários pode ser executada localmente; segue as instruções na pasta `etc/quiz-app`.
## Acesso Offline
Podes executar esta documentação offline usando o [Docsify](https://docsify.js.org/#/). Faz um fork deste repositório, [instala o Docsify](https://docsify.js.org/#/quickstart) na tua máquina local e, na pasta raiz deste repositório, escreve `docsify serve`. O website será servido na porta 3000 no teu localhost: `localhost:3000`. Um PDF do currículo está disponível [neste link](../../../../../../../../../etc/pdf/readme.pdf).
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,161 @@
# Introdução à IA
![Resumo do conteúdo de Introdução à IA em um desenho](../../../../translated_images/pt-PT/ai-intro.bf28d1ac4235881c.webp)
> Sketchnote por [Tomomi Imura](https://twitter.com/girlie_mac)
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/1)
**Inteligência Artificial** é uma disciplina científica fascinante que estuda como podemos fazer com que os computadores exibam comportamentos inteligentes, ou seja, realizem aquelas coisas em que os seres humanos são bons.
Originalmente, os computadores foram inventados por [Charles Babbage](https://en.wikipedia.org/wiki/Charles_Babbage) para operar com números seguindo um procedimento bem definido - um algoritmo. Os computadores modernos, embora significativamente mais avançados do que o modelo original proposto no século XIX, ainda seguem a mesma ideia de cálculos controlados. Assim, é possível programar um computador para fazer algo se soubermos a sequência exata de passos necessários para alcançar o objetivo.
![Foto de uma pessoa](../../../../translated_images/pt-PT/dsh_age.d212a30d4e54fb5f.webp)
> Foto por [Vickie Soshnikova](http://twitter.com/vickievalerie)
> ✅ Definir a idade de uma pessoa a partir de sua fotografia é uma tarefa que não pode ser explicitamente programada, porque não sabemos como chegamos a um número na nossa cabeça ao fazer isso.
---
Existem algumas tarefas, no entanto, que não sabemos explicitamente como resolver. Considere determinar a idade de uma pessoa a partir de sua fotografia. De alguma forma, aprendemos a fazer isso porque vimos muitos exemplos de pessoas de diferentes idades, mas não conseguimos explicar explicitamente como fazemos isso, nem podemos programar o computador para fazê-lo. Este é exatamente o tipo de tarefa que interessa à **Inteligência Artificial** (IA).
✅ Pense em algumas tarefas que você poderia delegar a um computador e que se beneficiariam da IA. Considere os campos de finanças, medicina e artes - como esses campos estão se beneficiando hoje da IA?
## IA Fraca vs. IA Forte
IA Fraca | IA Forte
---------------------------------------|-------------------------------------
IA Fraca refere-se a sistemas de IA projetados e treinados para uma tarefa específica ou um conjunto limitado de tarefas.|IA Forte, ou Inteligência Artificial Geral (AGI), refere-se a sistemas de IA com inteligência e compreensão ao nível humano.
Esses sistemas de IA não são geralmente inteligentes; eles se destacam em realizar uma tarefa predefinida, mas não possuem verdadeira compreensão ou consciência.|Esses sistemas de IA têm a capacidade de realizar qualquer tarefa intelectual que um ser humano pode fazer, adaptar-se a diferentes domínios e possuir uma forma de consciência ou autoconsciência.
Exemplos de IA fraca incluem assistentes virtuais como Siri ou Alexa, algoritmos de recomendação usados por serviços de streaming e chatbots projetados para tarefas específicas de atendimento ao cliente.|Alcançar a IA Forte é um objetivo de longo prazo da pesquisa em IA e exigiria o desenvolvimento de sistemas de IA que possam raciocinar, aprender, compreender e se adaptar a uma ampla gama de tarefas e contextos.
IA Fraca é altamente especializada e não possui habilidades cognitivas semelhantes às humanas ou capacidades gerais de resolução de problemas além de seu domínio limitado.|IA Forte é atualmente um conceito teórico, e nenhum sistema de IA atingiu esse nível de inteligência geral.
Para mais informações, consulte **[Inteligência Artificial Geral](https://en.wikipedia.org/wiki/Artificial_general_intelligence)** (AGI).
## A Definição de Inteligência e o Teste de Turing
Um dos problemas ao lidar com o termo **[Inteligência](https://en.wikipedia.org/wiki/Intelligence)** é que não há uma definição clara para este termo. Pode-se argumentar que inteligência está conectada ao **pensamento abstrato** ou à **autoconsciência**, mas não conseguimos defini-la adequadamente.
![Foto de um gato](../../../../translated_images/pt-PT/photo-cat.8c8e8fb760ffe457.webp)
> [Foto](https://unsplash.com/photos/75715CVEJhI) por [Amber Kipp](https://unsplash.com/@sadmax) do Unsplash
Para ver a ambiguidade do termo *inteligência*, tente responder à pergunta: "Um gato é inteligente?". Pessoas diferentes tendem a dar respostas diferentes a essa pergunta, já que não há um teste universalmente aceito para provar se a afirmação é verdadeira ou não. E se você acha que há - tente aplicar um teste de QI ao seu gato...
✅ Pense por um minuto sobre como você define inteligência. Um corvo que consegue resolver um labirinto para alcançar comida é inteligente? Uma criança é inteligente?
---
Ao falar sobre AGI, precisamos ter alguma forma de dizer se criamos um sistema verdadeiramente inteligente. [Alan Turing](https://en.wikipedia.org/wiki/Alan_Turing) propôs uma maneira chamada **[Teste de Turing](https://en.wikipedia.org/wiki/Turing_test)**, que também funciona como uma definição de inteligência. O teste compara um sistema dado com algo inerentemente inteligente - um ser humano real, e como qualquer comparação automática pode ser burlada por um programa de computador, usamos um interrogador humano. Assim, se um ser humano não conseguir distinguir entre uma pessoa real e um sistema de computador em um diálogo baseado em texto - o sistema é considerado inteligente.
> Um chatbot chamado [Eugene Goostman](https://en.wikipedia.org/wiki/Eugene_Goostman), desenvolvido em São Petersburgo, chegou perto de passar no Teste de Turing em 2014 usando um truque de personalidade inteligente. Ele anunciou desde o início que era um menino ucraniano de 13 anos, o que explicaria a falta de conhecimento e algumas discrepâncias no texto. O bot convenceu 30% dos juízes de que era humano após um diálogo de 5 minutos, uma métrica que Turing acreditava que uma máquina seria capaz de passar até 2000. No entanto, deve-se entender que isso não indica que criamos um sistema inteligente ou que um sistema de computador enganou o interrogador humano - o sistema não enganou os humanos, mas sim os criadores do bot!
✅ Alguma vez você já foi enganado por um chatbot pensando que estava falando com um humano? Como ele te convenceu?
## Diferentes Abordagens para IA
Se quisermos que um computador se comporte como um humano, precisamos de alguma forma modelar dentro do computador nossa maneira de pensar. Consequentemente, precisamos tentar entender o que torna um ser humano inteligente.
> Para ser capaz de programar inteligência em uma máquina, precisamos entender como funcionam nossos próprios processos de tomada de decisão. Se você fizer um pouco de autoanálise, perceberá que há alguns processos que acontecem subconscientemente por exemplo, conseguimos distinguir um gato de um cão sem pensar nisso - enquanto outros envolvem raciocínio.
Existem duas abordagens possíveis para este problema:
Abordagem de Cima para Baixo (Raciocínio Simbólico) | Abordagem de Baixo para Cima (Redes Neurais)
---------------------------------------|-------------------------------------
Uma abordagem de cima para baixo modela a maneira como uma pessoa raciocina para resolver um problema. Envolve extrair **conhecimento** de um ser humano e representá-lo em uma forma legível por computador. Também precisamos desenvolver uma maneira de modelar o **raciocínio** dentro de um computador. | Uma abordagem de baixo para cima modela a estrutura do cérebro humano, consistindo em um grande número de unidades simples chamadas **neurónios**. Cada neurónio age como uma média ponderada de suas entradas, e podemos treinar uma rede de neurónios para resolver problemas úteis fornecendo **dados de treino**.
Existem também outras abordagens possíveis para inteligência:
* Uma abordagem **Emergente**, **Sinergética** ou **multiagente** baseia-se no fato de que comportamentos inteligentes complexos podem ser obtidos pela interação de um grande número de agentes simples. De acordo com a [cibernética evolutiva](https://en.wikipedia.org/wiki/Global_brain#Evolutionary_cybernetics), a inteligência pode *emergir* de comportamentos mais simples e reativos no processo de *transição de metasistema*.
* Uma abordagem **Evolutiva**, ou **algoritmo genético**, é um processo de otimização baseado nos princípios da evolução.
Consideraremos essas abordagens mais tarde no curso, mas agora vamos nos concentrar em duas direções principais: de cima para baixo e de baixo para cima.
### A Abordagem de Cima para Baixo
Na abordagem **de cima para baixo**, tentamos modelar nosso raciocínio. Como podemos seguir nossos pensamentos ao raciocinar, podemos tentar formalizar esse processo e programá-lo dentro do computador. Isso é chamado de **raciocínio simbólico**.
As pessoas tendem a ter algumas regras em sua mente que orientam seus processos de tomada de decisão. Por exemplo, quando um médico está diagnosticando um paciente, ele ou ela pode perceber que a pessoa tem febre e, portanto, pode haver alguma inflamação ocorrendo no corpo. Ao aplicar um grande conjunto de regras a um problema específico, o médico pode ser capaz de chegar ao diagnóstico final.
Essa abordagem depende muito da **representação de conhecimento** e do **raciocínio**. Extrair conhecimento de um especialista humano pode ser a parte mais difícil, porque um médico, em muitos casos, não saberia exatamente por que está chegando a um diagnóstico específico. Às vezes, a solução simplesmente surge em sua mente sem pensar explicitamente. Algumas tarefas, como determinar a idade de uma pessoa a partir de uma fotografia, não podem ser reduzidas à manipulação de conhecimento.
### Abordagem de Baixo para Cima
Alternativamente, podemos tentar modelar os elementos mais simples dentro do nosso cérebro um neurónio. Podemos construir uma chamada **rede neural artificial** dentro de um computador e, em seguida, tentar ensiná-la a resolver problemas fornecendo exemplos. Esse processo é semelhante à forma como um recém-nascido aprende sobre seu ambiente ao fazer observações.
✅ Faça uma pequena pesquisa sobre como os bebés aprendem. Quais são os elementos básicos do cérebro de um bebé?
> | E o ML? | |
> |--------------|-----------|
> | Parte da Inteligência Artificial que se baseia no computador aprendendo a resolver um problema com base em alguns dados é chamada de **Machine Learning**. Não consideraremos o aprendizado de máquina clássico neste curso - recomendamos o currículo separado [Machine Learning para Iniciantes](http://aka.ms/ml-beginners). | ![ML para Iniciantes](../../../../translated_images/pt-PT/ml-for-beginners.9e4fed176fd5817d.webp) |
## Um Breve Histórico da IA
A Inteligência Artificial começou como um campo no meio do século XX. Inicialmente, o raciocínio simbólico era a abordagem predominante, e isso levou a uma série de sucessos importantes, como sistemas especialistas programas de computador que eram capazes de agir como especialistas em alguns domínios de problemas limitados. No entanto, logo ficou claro que essa abordagem não escala bem. Extrair o conhecimento de um especialista, representá-lo em um computador e manter essa base de conhecimento precisa acaba sendo uma tarefa muito complexa e cara demais para ser prática em muitos casos. Isso levou ao chamado [Inverno da IA](https://en.wikipedia.org/wiki/AI_winter) na década de 1970.
<img alt="Breve Histórico da IA" src="../../../../translated_images/pt-PT/history-of-ai.7e83efa70b537f5a.webp" width="70%"/>
> Imagem por [Dmitry Soshnikov](http://soshnikov.com)
Com o passar do tempo, os recursos computacionais tornaram-se mais baratos e mais dados ficaram disponíveis, então as abordagens de redes neurais começaram a demonstrar grande desempenho ao competir com seres humanos em muitas áreas, como visão computacional ou compreensão de fala. Na última década, o termo Inteligência Artificial tem sido usado principalmente como sinônimo de Redes Neurais, porque a maioria dos sucessos da IA que ouvimos falar são baseados nelas.
Podemos observar como as abordagens mudaram, por exemplo, na criação de um programa de computador para jogar xadrez:
* Os primeiros programas de xadrez eram baseados em busca um programa tentava explicitamente estimar os possíveis movimentos de um oponente para um determinado número de próximos movimentos e selecionava um movimento ótimo com base na posição ideal que poderia ser alcançada em alguns movimentos. Isso levou ao desenvolvimento do chamado algoritmo de busca [alpha-beta pruning](https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning).
* Estratégias de busca funcionam bem no final do jogo, onde o espaço de busca é limitado por um pequeno número de movimentos possíveis. No entanto, no início do jogo, o espaço de busca é enorme, e o algoritmo pode ser melhorado aprendendo com partidas existentes entre jogadores humanos. Experimentos subsequentes empregaram o chamado [raciocínio baseado em casos](https://en.wikipedia.org/wiki/Case-based_reasoning), onde o programa procurava casos na base de conhecimento muito semelhantes à posição atual no jogo.
* Programas modernos que vencem jogadores humanos são baseados em redes neurais e [aprendizado por reforço](https://en.wikipedia.org/wiki/Reinforcement_learning), onde os programas aprendem a jogar exclusivamente jogando contra si mesmos por muito tempo e aprendendo com seus próprios erros muito parecido com o que os seres humanos fazem ao aprender a jogar xadrez. No entanto, um programa de computador pode jogar muito mais partidas em muito menos tempo e, assim, aprender muito mais rápido.
✅ Faça uma pequena pesquisa sobre outros jogos que foram jogados por IA.
Da mesma forma, podemos ver como a abordagem para criar “programas falantes” (que podem passar no Teste de Turing) mudou:
* Programas iniciais desse tipo, como [Eliza](https://en.wikipedia.org/wiki/ELIZA), eram baseados em regras gramaticais muito simples e na reformulação da frase de entrada em uma pergunta.
* Assistentes modernos, como Cortana, Siri ou Google Assistant, são todos sistemas híbridos que usam redes neurais para converter fala em texto e reconhecer nossa intenção, e depois empregam algum raciocínio ou algoritmos explícitos para realizar as ações necessárias.
* No futuro, podemos esperar um modelo completamente baseado em redes neurais para lidar com diálogos por conta própria. As recentes redes neurais da família GPT e [Turing-NLG](https://www.microsoft.com/research/blog/turing-nlg-a-17-billion-parameter-language-model-by-microsoft) mostram grande sucesso nisso.
<img alt="a evolução do Teste de Turing" src="../../../../translated_images/pt-PT/turing-test-evol.4184696701293ead.webp" width="70%"/>
> Imagem de Dmitry Soshnikov, [foto](https://unsplash.com/photos/r8LmVbUKgns) de [Marina Abrosimova](https://unsplash.com/@abrosimova_marina_foto), Unsplash
## Investigação Recente em IA
O grande crescimento recente na investigação sobre redes neurais começou por volta de 2010, quando grandes conjuntos de dados públicos começaram a estar disponíveis. Uma enorme coleção de imagens chamada [ImageNet](https://en.wikipedia.org/wiki/ImageNet), que contém cerca de 14 milhões de imagens anotadas, deu origem ao [ImageNet Large Scale Visual Recognition Challenge](https://image-net.org/challenges/LSVRC/).
![Precisão do ILSVRC](../../../../lessons/1-Intro/images/ilsvrc.gif)
> Imagem de [Dmitry Soshnikov](http://soshnikov.com)
Em 2012, as [Redes Neurais Convolucionais](../4-ComputerVision/07-ConvNets/README.md) foram usadas pela primeira vez na classificação de imagens, o que levou a uma queda significativa nos erros de classificação (de quase 30% para 16,4%). Em 2015, a arquitetura ResNet da Microsoft Research [alcançou precisão ao nível humano](https://doi.org/10.1109/ICCV.2015.123).
Desde então, as Redes Neurais demonstraram um comportamento muito bem-sucedido em várias tarefas:
---
Ano | Paridade Humana alcançada
-----|--------
2015 | [Classificação de Imagens](https://doi.org/10.1109/ICCV.2015.123)
2016 | [Reconhecimento de Fala Conversacional](https://arxiv.org/abs/1610.05256)
2018 | [Tradução Automática de Máquinas](https://arxiv.org/abs/1803.05567) (Chinês para Inglês)
2020 | [Legenda de Imagens](https://arxiv.org/abs/2009.13682)
Nos últimos anos, testemunhámos grandes sucessos com modelos de linguagem de grande escala, como BERT e GPT-3. Isto aconteceu principalmente devido ao facto de haver uma grande quantidade de dados de texto geral disponíveis, permitindo treinar modelos para capturar a estrutura e o significado dos textos, pré-treiná-los em coleções de texto geral e, depois, especializar esses modelos para tarefas mais específicas. Vamos aprender mais sobre [Processamento de Linguagem Natural](../5-NLP/README.md) mais tarde neste curso.
## 🚀 Desafio
Faça uma pesquisa na internet para determinar onde, na sua opinião, a IA é mais eficazmente utilizada. Será numa aplicação de mapeamento, num serviço de conversão de fala para texto ou num videojogo? Investigue como o sistema foi construído.
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/2)
## Revisão & Estudo Individual
Revise a história da IA e ML lendo [esta lição](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/2-history-of-ML). Escolha um elemento do sketchnote no início dessa lição ou desta e pesquise-o mais profundamente para compreender o contexto cultural que informa a sua evolução.
**Tarefa**: [Game Jam](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,10 @@
# Game Jam
Os jogos são uma área que tem sido fortemente influenciada pelos avanços em IA e ML. Nesta tarefa, escreva um pequeno texto sobre um jogo de que goste e que tenha sido influenciado pela evolução da IA. Deve ser um jogo suficientemente antigo para ter sido influenciado por vários tipos de sistemas de processamento computacional. Um bom exemplo é o Xadrez ou o Go, mas também pode considerar videojogos como Pong ou Pac-Man. Escreva um ensaio que discuta o passado, o presente e o futuro da IA no jogo escolhido.
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,477 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# Implementação de um Sistema Especialista em Animais\n",
"\n",
"Um exemplo do [Currículo AI for Beginners](http://github.com/microsoft/ai-for-beginners).\n",
"\n",
"Neste exemplo, vamos implementar um sistema baseado em conhecimento simples para determinar um animal com base em algumas características físicas. O sistema pode ser representado pela seguinte árvore AND-OR (esta é uma parte da árvore completa, podemos facilmente adicionar mais regras):\n",
"\n",
"![](../../../../../../translated_images/pt-PT/AND-OR-Tree.5592d2c70187f283.webp)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A nossa própria shell de sistemas especialistas com inferência para trás\n",
"\n",
"Vamos tentar definir uma linguagem simples para a representação de conhecimento baseada em regras de produção. Vamos usar classes Python como palavras-chave para definir regras. Essencialmente, existirão 3 tipos de classes:\n",
"* `Ask` representa uma pergunta que precisa ser colocada ao utilizador. Contém o conjunto de respostas possíveis.\n",
"* `If` representa uma regra, sendo apenas um açúcar sintático para armazenar o conteúdo da regra.\n",
"* `AND`/`OR` são classes para representar ramos AND/OR da árvore. Elas apenas armazenam a lista de argumentos no seu interior. Para simplificar o código, toda a funcionalidade está definida na classe pai `Content`.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class Ask():\n",
" def __init__(self,choices=['y','n']):\n",
" self.choices = choices\n",
" def ask(self):\n",
" if max([len(x) for x in self.choices])>1:\n",
" for i,x in enumerate(self.choices):\n",
" print(\"{0}. {1}\".format(i,x),flush=True)\n",
" x = int(input())\n",
" return self.choices[x]\n",
" else:\n",
" print(\"/\".join(self.choices),flush=True)\n",
" return input()\n",
"\n",
"class Content():\n",
" def __init__(self,x):\n",
" self.x=x\n",
" \n",
"class If(Content):\n",
" pass\n",
"\n",
"class AND(Content):\n",
" pass\n",
"\n",
"class OR(Content):\n",
" pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No nosso sistema, a memória de trabalho conteria a lista de **factos** como **pares atributo-valor**. A base de conhecimento pode ser definida como um grande dicionário que associa ações (novos factos que devem ser inseridos na memória de trabalho) a condições, expressas como expressões E-OU. Além disso, alguns factos podem ser `Perguntados`.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"rules = {\n",
" 'default': Ask(['y','n']),\n",
" 'color' : Ask(['red-brown','black and white','other']),\n",
" 'pattern' : Ask(['dark stripes','dark spots']),\n",
" 'mammal': If(OR(['hair','gives milk'])),\n",
" 'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),\n",
" 'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),\n",
" 'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),\n",
" 'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),\n",
" 'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),\n",
" 'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),\n",
" 'animal:zebra' : If(['ungulate','pattern:dark stripes']),\n",
" 'animal:ostrich' : If(['bird','long nech','color:black and white','cannot fly']),\n",
" 'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),\n",
" 'animal:albatross' : If(['bird','flies well'])\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para realizar a inferência retrocedida, iremos definir a classe `Knowledgebase`. Esta conterá:\n",
"* Memória de trabalho `memory` - um dicionário que associa atributos a valores\n",
"* Regras da base de conhecimento `rules` no formato definido acima\n",
"\n",
"Os dois métodos principais são:\n",
"* `get` para obter o valor de um atributo, realizando inferência se necessário. Por exemplo, `get('color')` obterá o valor de um campo de cor (irá perguntar se necessário, e guardar o valor para uso posterior na memória de trabalho). Se perguntarmos `get('color:blue')`, perguntará pela cor e depois retornará o valor `y`/`n` dependendo da cor.\n",
"* `eval` executa a inferência propriamente dita, ou seja, percorre a árvore AND/OR, avalia subobjetivos, etc.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class KnowledgeBase():\n",
" def __init__(self,rules):\n",
" self.rules = rules\n",
" self.memory = {}\n",
" \n",
" def get(self,name):\n",
" if ':' in name:\n",
" k,v = name.split(':')\n",
" vv = self.get(k)\n",
" return 'y' if v==vv else 'n'\n",
" if name in self.memory.keys():\n",
" return self.memory[name]\n",
" for fld in self.rules.keys():\n",
" if fld==name or fld.startswith(name+\":\"):\n",
" # print(\" + proving {}\".format(fld))\n",
" value = 'y' if fld==name else fld.split(':')[1]\n",
" res = self.eval(self.rules[fld],field=name)\n",
" if res!='y' and res!='n' and value=='y':\n",
" self.memory[name] = res\n",
" return res\n",
" if res=='y':\n",
" self.memory[name] = value\n",
" return value\n",
" # field is not found, using default\n",
" res = self.eval(self.rules['default'],field=name)\n",
" self.memory[name]=res\n",
" return res\n",
" \n",
" def eval(self,expr,field=None):\n",
" # print(\" + eval {}\".format(expr))\n",
" if isinstance(expr,Ask):\n",
" print(field)\n",
" return expr.ask()\n",
" elif isinstance(expr,If):\n",
" return self.eval(expr.x)\n",
" elif isinstance(expr,AND) or isinstance(expr,list):\n",
" expr = expr.x if isinstance(expr,AND) else expr\n",
" for x in expr:\n",
" if self.eval(x)=='n':\n",
" return 'n'\n",
" return 'y'\n",
" elif isinstance(expr,OR):\n",
" for x in expr.x:\n",
" if self.eval(x)=='y':\n",
" return 'y'\n",
" return 'n'\n",
" elif isinstance(expr,str):\n",
" return self.get(expr)\n",
" else:\n",
" print(\"Unknown expr: {}\".format(expr))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora, vamos definir a nossa base de conhecimento sobre animais e realizar a consulta. Note que esta chamada fará perguntas. Pode responder digitando `y`/`n` para perguntas de sim/não, ou especificando um número (0..N) para perguntas com respostas de múltipla escolha mais longas.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hair\n",
"y/n\n",
"sharp teeth\n",
"y/n\n",
"claws\n",
"y/n\n",
"forward-looking eyes\n",
"y/n\n",
"color\n",
"0. red-brown\n",
"1. black and white\n",
"2. other\n",
"has hooves\n",
"y/n\n",
"long neck\n",
"y/n\n",
"long legs\n",
"y/n\n",
"pattern\n",
"0. dark stripes\n",
"1. dark spots\n"
]
},
{
"data": {
"text/plain": [
"'giraffe'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"kb = KnowledgeBase(rules)\n",
"kb.get('animal')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Usar o Experta para Inferência Direta\n",
"\n",
"No próximo exemplo, vamos tentar implementar inferência direta usando uma das bibliotecas para representação de conhecimento, o [Experta](https://github.com/nilp0inter/experta). **Experta** é uma biblioteca para criar sistemas de inferência direta em Python, que é desenhada para ser semelhante ao clássico sistema antigo [CLIPS](http://www.clipsrules.net/index.html).\n",
"\n",
"Também poderíamos ter implementado encadeamento direto nós próprios sem muitos problemas, mas implementações ingênuas normalmente não são muito eficientes. Para uma correspondência de regras mais eficaz é usado um algoritmo especial [Rete](https://en.wikipedia.org/wiki/Rete_algorithm).\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting git+https://github.com/nilp0inter/experta\n",
" Cloning https://github.com/nilp0inter/experta to /tmp/pip-req-build-7qurtwk3\n",
" Running command git clone --filter=blob:none --quiet https://github.com/nilp0inter/experta /tmp/pip-req-build-7qurtwk3\n",
" Resolved https://github.com/nilp0inter/experta to commit c6d5834b123861f5ae09e7d07027dc98bec58741\n",
" Installing build dependencies ... \u001b[?25ldone\n",
"\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n",
"\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
"\u001b[?25hRequirement already satisfied: frozendict~=2.4.6 in /opt/conda/envs/ai4beg/lib/python3.12/site-packages (from experta==1.9.5.dev1) (2.4.7)\n",
"Collecting schema~=0.6.7 (from experta==1.9.5.dev1)\n",
" Downloading schema-0.6.8-py2.py3-none-any.whl.metadata (14 kB)\n",
"Downloading schema-0.6.8-py2.py3-none-any.whl (14 kB)\n",
"Building wheels for collected packages: experta\n",
" Building wheel for experta (pyproject.toml) ... \u001b[?25ldone\n",
"\u001b[?25h Created wheel for experta: filename=experta-1.9.5.dev1-py3-none-any.whl size=34804 sha256=888c459512a5e713f4b674caa9a0f96cfdf07ec0d6eb56cc318ce0653d218014\n",
" Stored in directory: /tmp/pip-ephem-wheel-cache-1eeii9zy/wheels/3d/e8/bb/22d7956359603fa8dd679aa09f5b8efb3f29991c3986fdc787\n",
"Successfully built experta\n",
"Installing collected packages: schema, experta\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2/2\u001b[0m [experta]\n",
"\u001b[1A\u001b[2KSuccessfully installed experta-1.9.5.dev1 schema-0.6.8\n"
]
}
],
"source": [
"import sys\n",
"!{sys.executable} -m pip install git+https://github.com/nilp0inter/experta"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"from experta import *\n",
"#import experta"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Iremos definir o nosso sistema como uma classe que herda de `KnowledgeEngine`. Cada regra é definida por uma função separada com a anotação `@Rule`, que especifica quando a regra deve ser ativada. Dentro da regra, podemos adicionar novos factos utilizando a função `declare`, e adicionar esses factos resultará em algumas regras adicionais serem acionadas pelo motor de inferência para a frente.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class Animals(KnowledgeEngine):\n",
" @Rule(OR(\n",
" AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),\n",
" Fact('eats meat')))\n",
" def cornivor(self):\n",
" self.declare(Fact('carnivor'))\n",
" \n",
" @Rule(OR(Fact('hair'),Fact('gives milk')))\n",
" def mammal(self):\n",
" self.declare(Fact('mammal'))\n",
"\n",
" @Rule(Fact('mammal'),\n",
" OR(Fact('has hooves'),Fact('chews cud')))\n",
" def hooves(self):\n",
" self.declare('ungulate')\n",
" \n",
" @Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))\n",
" def bird(self):\n",
" self.declare('bird')\n",
" \n",
" @Rule(Fact('mammal'),Fact('carnivor'),\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark spots'))\n",
" def monkey(self):\n",
" self.declare(Fact(animal='monkey'))\n",
"\n",
" @Rule(Fact('mammal'),Fact('carnivor'),\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark stripes'))\n",
" def tiger(self):\n",
" self.declare(Fact(animal='tiger'))\n",
"\n",
" @Rule(Fact('ungulate'),\n",
" Fact('long neck'),\n",
" Fact('long legs'),\n",
" Fact(pattern='dark spots'))\n",
" def giraffe(self):\n",
" self.declare(Fact(animal='giraffe'))\n",
"\n",
" @Rule(Fact('ungulate'),\n",
" Fact(pattern='dark stripes'))\n",
" def zebra(self):\n",
" self.declare(Fact(animal='zebra'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('long neck'),\n",
" Fact('cannot fly'),\n",
" Fact(color='black and white'))\n",
" def straus(self):\n",
" self.declare(Fact(animal='ostrich'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('swims'),\n",
" Fact('cannot fly'),\n",
" Fact(color='black and white'))\n",
" def pinguin(self):\n",
" self.declare(Fact(animal='pinguin'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('flies well'))\n",
" def albatros(self):\n",
" self.declare(Fact(animal='albatross'))\n",
" \n",
" @Rule(Fact(animal=MATCH.a))\n",
" def print_result(self,a):\n",
" print('Animal is {}'.format(a))\n",
" \n",
" def factz(self,l):\n",
" for x in l:\n",
" self.declare(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Depois de definirmos uma base de conhecimento, preenchemos a nossa memória de trabalho com alguns factos iniciais e, em seguida, chamamos o método `run()` para realizar a inferência. Pode ver-se como resultado que novos factos inferidos são adicionados à memória de trabalho, incluindo o facto final sobre o animal (se configurarmos correctamente todos os factos iniciais).\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Animal is tiger\n"
]
},
{
"data": {
"text/plain": [
"FactList([(0, InitialFact()),\n",
" (1, Fact(color='red-brown')),\n",
" (2, Fact(pattern='dark stripes')),\n",
" (3, Fact('sharp teeth')),\n",
" (4, Fact('claws')),\n",
" (5, Fact('forward looking eyes')),\n",
" (6, Fact('gives milk')),\n",
" (7, Fact('mammal')),\n",
" (8, Fact('carnivor')),\n",
" (9, Fact(animal='tiger'))])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ex1 = Animals()\n",
"ex1.reset()\n",
"ex1.factz([\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark stripes'),\n",
" Fact('sharp teeth'),\n",
" Fact('claws'),\n",
" Fact('forward looking eyes'),\n",
" Fact('gives milk')])\n",
"ex1.run()\n",
"ex1.facts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, por favor tenha em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.7.4 64-bit (conda)",
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
}
},
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
},
"coopTranslator": {
"original_hash": "8ef43db4b9182239fd150a76bd494fdb",
"translation_date": "2026-01-15T14:03:23+00:00",
"source_file": "lessons/2-Symbolic/Animals.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,595 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# Ontologia de Relações Familiares\n",
"\n",
"Este exemplo faz parte do [Currículo de IA para Iniciantes](http://github.com/microsoft/ai-for-beginners) e foi inspirado por [este artigo](https://habr.com/post/270857/).\n",
"\n",
"Sempre achei difícil lembrar-me das diferentes relações entre pessoas numa família. Neste exemplo, vamos utilizar uma ontologia que define relações familiares e a árvore genealógica real, e mostrar como podemos realizar inferências automáticas para encontrar todos os parentes.\n",
"\n",
"### Obter a Árvore Genealógica\n",
"\n",
"Como exemplo, vamos utilizar a árvore genealógica da [Família Romanov](https://en.wikipedia.org/wiki/House_of_Romanov). O formato mais comum para descrever relações familiares é o [GEDCOM](https://en.wikipedia.org/wiki/GEDCOM). Vamos usar a árvore genealógica da família Romanov no formato GEDCOM:\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 HEAD\n",
"1 CHAR UTF8\n",
"1 GEDC\n",
"2 VERS 5.5\n",
"0 @0@ INDI\n",
"1 NAME Mihail Fedorovich /Romanov/\n",
"1 SEX M\n",
"1 BIRT\n",
"2 DATE 1613\n",
"1 DEAT \n",
"2 DATE 1645\n",
"1 FAMS @41@\n",
"0 @1@ INDI\n",
"1 NAME Evdokija Lukjanovna /Streshneva/\n",
"1 SEX F\n"
]
}
],
"source": [
"!head -15 data/tsars.ged"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para usar o ficheiro GEDCOM, podemos usar a biblioteca `python-gedcom`:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting python-gedcom\n",
" Downloading python_gedcom-1.0.0-py2.py3-none-any.whl (35 kB)\n",
"Installing collected packages: python-gedcom\n",
"Successfully installed python-gedcom-1.0.0\n"
]
}
],
"source": [
"import sys\n",
"!{sys.executable} -m pip install python-gedcom"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Esta biblioteca elimina alguns dos problemas técnicos com a análise de ficheiros, mas ainda nos dá acesso bastante de baixo nível a todos os indivíduos e famílias na árvore. Aqui está como podemos analisar o ficheiro e mostrar a lista de todos os indivíduos:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"from gedcom.parser import Parser\n",
"from gedcom.element.individual import IndividualElement\n",
"from gedcom.element.family import FamilyElement\n",
"g = Parser()\n",
"g.parse_file('data/tsars.ged')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"scrolled": true,
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"[('@0@', ('Mihail Fedorovich', 'Romanov')),\n",
" ('@1@', ('Evdokija Lukjanovna', 'Streshneva')),\n",
" ('@2@', ('Aleksej Mihajlovich', 'Romanov')),\n",
" ('@3@', ('Marija Ilinichna', 'Miloslavskaja')),\n",
" ('@4@', ('Natalja Kirillovna', 'Naryshkina')),\n",
" ('@5@', ('Marfa Matveevna', 'Apraksina')),\n",
" ('@6@', ('Fedor Alekseevich', 'Romanov')),\n",
" ('@7@', ('Sofja Aleksevna', 'Romanova')),\n",
" ('@8@', ('Ivan V Alekseevich', 'Romanov')),\n",
" ('@9@', ('Praskovja Fedorovna', 'Saltykova')),\n",
" ('@10@', ('Ekaterina Ivanovna', 'Romanova')),\n",
" ('@11@', ('Anna Ivanovna', 'Romanova')),\n",
" ('@12@', ('Fridrih Vilgelm', 'Kurlandskij')),\n",
" ('@13@', ('Karl Leopold', 'Meklenburg-Shverinskij')),\n",
" ('@14@', ('Anna Leopoldovna', 'Meklenburg-Shverinskaja')),\n",
" ('@15@', ('Anton Ulrih', 'Braunshvejg-Volfenbjuttelskij')),\n",
" ('@16@', ('Ivan VI Antonovich', 'Braunshvejg-Volfenbjuttelskij')),\n",
" ('@17@', ('Petr I Alekseevich', 'Romanov')),\n",
" ('@18@', ('Evdokija Fedorovna', 'Lopuhina')),\n",
" ('@19@', ('Ekaterina I Alekseevna', 'Mihajlova')),\n",
" ('@20@', ('Aleksej Petrovich', 'Romanov')),\n",
" ('@21@', ('Sharlotta Kristina', 'Braunshvejg-Volfenbjuttelskaja')),\n",
" ('@22@', ('Petr II Alekseevich', 'Romanov')),\n",
" ('@23@', ('Anna Petrovna', 'Romanova')),\n",
" ('@24@', ('Elizaveta Petrovna', 'Romanova')),\n",
" ('@25@', ('Karl Fridrih', 'Golshtejn-Gottorpskij')),\n",
" ('@26@', ('Petr III Fedorovich', 'Romanov')),\n",
" ('@27@', ('Ekaterina II', 'Alekseevna')),\n",
" ('@28@', ('Pavel I Petrovich', 'Romanov')),\n",
" ('@29@', ('Natalja Alekseevna', 'Gessen-Darmshtadskaja')),\n",
" ('@30@', ('Marija Fedorovna', 'Vjurtembergskaja')),\n",
" ('@31@', ('Aleksandr I Pavlovich', 'Romanov')),\n",
" ('@32@', ('Elizaveta Alekseevna', 'Baden-Durlahskaja')),\n",
" ('@33@', ('Nikolaj I Pavlovich', 'Romanov')),\n",
" ('@34@', ('Aleksandra Fedorovna', 'Prusskaja')),\n",
" ('@35@', ('Aleksandr II Nikolaevich', 'Romanov')),\n",
" ('@36@', ('Marija Aleksandrovna', 'Gessenskaja')),\n",
" ('@37@', ('Aleksandr III Aleksandrovich', 'Romanov')),\n",
" ('@38@', ('Marija Fedorovna', 'Datskaja')),\n",
" ('@39@', ('Nikolaj II Aleksandrovich', 'Romanov')),\n",
" ('@40@', ('Aleksandra Fedorovna', 'Gessenskaja'))]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d = g.get_element_dictionary()\n",
"[ (k,v.get_name()) for k,v in d.items() if isinstance(v,IndividualElement)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Aqui está como podemos obter informações sobre famílias. Note que isso nos dá uma lista de **identificadores**, e precisamos convertê-los em nomes se quisermos mais clareza:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('@41@', ['@0@', '@1@', '@2@']),\n",
" ('@42@', ['@2@', '@3@', '@6@', '@7@', '@8@']),\n",
" ('@43@', ['@8@', '@9@', '@10@', '@11@']),\n",
" ('@44@', ['@13@', '@10@', '@14@']),\n",
" ('@45@', ['@15@', '@14@', '@16@']),\n",
" ('@46@', ['@2@', '@4@', '@17@']),\n",
" ('@47@', ['@17@', '@18@', '@20@']),\n",
" ('@48@', ['@20@', '@21@', '@22@']),\n",
" ('@49@', ['@17@', '@19@', '@23@', '@24@']),\n",
" ('@50@', ['@25@', '@23@', '@26@']),\n",
" ('@51@', ['@26@', '@27@', '@28@']),\n",
" ('@52@', ['@28@', '@30@', '@31@', '@33@']),\n",
" ('@53@', ['@33@', '@34@', '@35@']),\n",
" ('@54@', ['@35@', '@36@', '@37@']),\n",
" ('@55@', ['@37@', '@38@', '@39@'])]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d = g.get_element_dictionary()\n",
"[ (k,[x.get_value() for x in v.get_child_elements()]) for k,v in d.items() if isinstance(v,FamilyElement)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Obtendo a Ontologia Familiar\n",
"\n",
"A seguir, vamos analisar a [ontologia familiar](https://raw.githubusercontent.com/blokhin/genealogical-trees/master/data/header.ttl) definida como um conjunto de triplos da Web Semântica. Esta ontologia define relações como `isUncleOf`, `isCousinOf` e muitas outras. Todas essas relações são definidas em termos de predicados básicos `isMotherOf`, `isFatherOf`, `isBrotherOf` e `isSisterOf`. Utilizaremos raciocínio automático para deduzir todas as outras relações usando a ontologia.\n",
"\n",
"Aqui está um exemplo de definição da propriedade `isAuntOf`, que é definida como uma composição de `isSisterOf` e `isParentOf` (*Tia é a irmã de um dos pais*).\n",
"\n",
"```\n",
"fhkb:isAuntOf a owl:ObjectProperty ;\n",
" rdfs:domain fhkb:Woman ;\n",
" rdfs:range fhkb:Person ;\n",
" owl:propertyChainAxiom ( fhkb:isSisterOf fhkb:isParentOf ) .\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"@prefix fhkb: <http://www.example.com/genealogy.owl#> .\n",
"@prefix owl: <http://www.w3.org/2002/07/owl#> .\n",
"@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n",
"@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n",
"@prefix xml: <http://www.w3.org/XML/1998/namespace> .\n",
"@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n",
"\n",
"<http://www.example.com/genealogy.owl#> a owl:Ontology .\n",
"\n",
"fhkb:DomainEntity a owl:Class .\n",
"\n",
"fhkb:Man a owl:Class ;\n",
" owl:equivalentClass [ a owl:Class ;\n",
" owl:intersectionOf ( fhkb:Person [ a owl:Restriction ;\n",
" owl:onProperty fhkb:hasSex ;\n",
" owl:someValuesFrom fhkb:Male ] ) ] .\n",
"\n",
"fhkb:Woman a owl:Class ;\n",
" owl:equivalentClass [ a owl:Class ;\n",
" owl:intersectionOf ( fhkb:Person [ a owl:Restriction ;\n"
]
}
],
"source": [
"!head -20 data/onto.ttl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Construção de Ontologia para Inferência\n",
"\n",
"Para simplificar, iremos criar um único ficheiro de ontologia que incluirá as regras originais da ontologia familiar e os factos sobre os indivíduos do nosso ficheiro GEDCOM. Vamos analisar o ficheiro GEDCOM, extrair informações sobre famílias e indivíduos e convertê-las em triplos.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"!cp data/onto.ttl .\n",
"\n",
"gedcom_dict = g.get_element_dictionary()\n",
"individuals, marriages = {}, {}\n",
"\n",
"def term2id(el):\n",
" return \"i\" + el.get_pointer().replace('@', '').lower()\n",
"\n",
"out = open(\"onto.ttl\",\"a\")\n",
"\n",
"for k, v in gedcom_dict.items():\n",
" if isinstance(v,IndividualElement):\n",
" children, siblings = set(), set()\n",
" idx = term2id(v)\n",
"\n",
" title = v.get_name()[0] + \" \" + v.get_name()[1]\n",
" title = title.replace('\"', '').replace('[', '').replace(']', '').replace('(', '').replace(')', '').strip()\n",
"\n",
" own_families = g.get_families(v, 'FAMS')\n",
" for fam in own_families:\n",
" children |= set(term2id(i) for i in g.get_family_members(fam, \"CHIL\"))\n",
"\n",
" parent_families = g.get_families(v, 'FAMC')\n",
" if len(parent_families):\n",
" for member in g.get_family_members(parent_families[0], \"CHIL\"): # NB adoptive families i.e len(parent_families)>1 are not considered (TODO?)\n",
" if member.get_pointer() == v.get_pointer():\n",
" continue\n",
" siblings.add(term2id(member))\n",
"\n",
" if idx in individuals:\n",
" children |= individuals[idx].get('children', set())\n",
" siblings |= individuals[idx].get('siblings', set())\n",
" individuals[idx] = {'sex': v.get_gender().lower(), 'children': children, 'siblings': siblings, 'title': title}\n",
"\n",
" elif isinstance(v,FamilyElement):\n",
" wife, husb, children = None, None, set()\n",
" children = set(term2id(i) for i in g.get_family_members(v, \"CHIL\"))\n",
"\n",
" try:\n",
" wife = g.get_family_members(v, \"WIFE\")[0]\n",
" wife = term2id(wife)\n",
" if wife in individuals: individuals[wife]['children'] |= children\n",
" else: individuals[wife] = {'children': children}\n",
" except IndexError: pass\n",
" try:\n",
" husb = g.get_family_members(v, \"HUSB\")[0]\n",
" husb = term2id(husb)\n",
" if husb in individuals: individuals[husb]['children'] |= children\n",
" else: individuals[husb] = {'children': children}\n",
" except IndexError: pass\n",
"\n",
" if wife and husb: marriages[wife + husb] = (term2id(v), wife, husb)\n",
"\n",
"for idx, val in individuals.items():\n",
" added_terms = ''\n",
" if val['sex'] == 'f':\n",
" parent_predicate, sibl_predicate = \"isMotherOf\", \"isSisterOf\"\n",
" else:\n",
" parent_predicate, sibl_predicate = \"isFatherOf\", \"isBrotherOf\"\n",
" if len(val['children']):\n",
" added_terms += \" ;\\n fhkb:\" + parent_predicate + \" \" + \", \".join([\"fhkb:\" + i for i in val['children']])\n",
" if len(val['siblings']):\n",
" added_terms += \" ;\\n fhkb:\" + sibl_predicate + \" \" + \", \".join([\"fhkb:\" + i for i in val['siblings']])\n",
" out.write(\"fhkb:%s a owl:NamedIndividual, owl:Thing%s ;\\n rdfs:label \\\"%s\\\" .\\n\" % (idx, added_terms, val['title']))\n",
"\n",
"for k, v in marriages.items():\n",
" out.write(\"fhkb:%s a owl:NamedIndividual, owl:Thing ;\\n fhkb:hasFemalePartner fhkb:%s ;\\n fhkb:hasMalePartner fhkb:%s .\\n\" % v)\n",
"\n",
"out.write(\"[] a owl:AllDifferent ;\\n owl:distinctMembers (\")\n",
"for idx in individuals.keys():\n",
" out.write(\" fhkb:\" + idx)\n",
"for k, v in marriages.items():\n",
" out.write(\" fhkb:\" + v[0])\n",
"out.write(\" ) .\")\n",
"out.close()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" fhkb:hasFemalePartner fhkb:i34 ;\n",
" fhkb:hasMalePartner fhkb:i33 .\n",
"fhkb:i54 a owl:NamedIndividual, owl:Thing ;\n",
" fhkb:hasFemalePartner fhkb:i36 ;\n",
" fhkb:hasMalePartner fhkb:i35 .\n",
"fhkb:i55 a owl:NamedIndividual, owl:Thing ;\n",
" fhkb:hasFemalePartner fhkb:i38 ;\n",
" fhkb:hasMalePartner fhkb:i37 .\n",
"[] a owl:AllDifferent ;\n",
" owl:distinctMembers ( fhkb:i0 fhkb:i1 fhkb:i2 fhkb:i3 fhkb:i4 fhkb:i5 fhkb:i6 fhkb:i7 fhkb:i8 fhkb:i9 fhkb:i10 fhkb:i11 fhkb:i12 fhkb:i13 fhkb:i14 fhkb:i15 fhkb:i16 fhkb:i17 fhkb:i18 fhkb:i19 fhkb:i20 fhkb:i21 fhkb:i22 fhkb:i23 fhkb:i24 fhkb:i25 fhkb:i26 fhkb:i27 fhkb:i28 fhkb:i29 fhkb:i30 fhkb:i31 fhkb:i32 fhkb:i33 fhkb:i34 fhkb:i35 fhkb:i36 fhkb:i37 fhkb:i38 fhkb:i39 fhkb:i40 fhkb:i41 fhkb:i42 fhkb:i43 fhkb:i44 fhkb:i45 fhkb:i46 fhkb:i47 fhkb:i48 fhkb:i49 fhkb:i50 fhkb:i51 fhkb:i52 fhkb:i53 fhkb:i54 fhkb:i55 ) ."
]
}
],
"source": [
"!tail onto.ttl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Fazer Inferência\n",
"\n",
"Agora queremos ser capazes de usar esta ontologia para inferência e para realizar consultas. Vamos utilizar a [RDFLib](https://github.com/RDFLib), uma biblioteca para ler Grafos RDF em diferentes formatos, realizar consultas, etc.\n",
"\n",
"Para inferência lógica, utilizaremos a biblioteca [OWL-RL](https://github.com/RDFLib/OWL-RL), que nos permite construir o **Fecho** do Grafo RDF, ou seja, adicionar todos os conceitos e relações possíveis que podem ser inferidos.\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: rdflib in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (6.3.2)\n",
"Requirement already satisfied: isodate<0.7.0,>=0.6.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib) (0.6.1)\n",
"Requirement already satisfied: pyparsing<4,>=2.1.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib) (3.0.9)\n",
"Requirement already satisfied: six in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from isodate<0.7.0,>=0.6.0->rdflib) (1.16.0)\n",
"Collecting git+https://github.com/RDFLib/OWL-RL.git\n",
" Cloning https://github.com/RDFLib/OWL-RL.git to /tmp/pip-req-build-lbfzwi3m\n",
" Running command git clone --filter=blob:none --quiet https://github.com/RDFLib/OWL-RL.git /tmp/pip-req-build-lbfzwi3m\n",
" Resolved https://github.com/RDFLib/OWL-RL.git to commit a77e1791b88b54aace609bc6000aac14c7add4ff\n",
" Preparing metadata (setup.py) ... \u001b[?25ldone\n",
"\u001b[?25hRequirement already satisfied: rdflib>=6.0.2 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from owlrl==6.0.2) (6.3.2)\n",
"Requirement already satisfied: isodate<0.7.0,>=0.6.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib>=6.0.2->owlrl==6.0.2) (0.6.1)\n",
"Requirement already satisfied: pyparsing<4,>=2.1.0 in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from rdflib>=6.0.2->owlrl==6.0.2) (3.0.9)\n",
"Requirement already satisfied: six in /home/rg/anaconda3/envs/ai4beg/lib/python3.11/site-packages (from isodate<0.7.0,>=0.6.0->rdflib>=6.0.2->owlrl==6.0.2) (1.16.0)\n"
]
}
],
"source": [
"!{sys.executable} -m pip install rdflib\n",
"!{sys.executable} -m pip install git+https://github.com/RDFLib/OWL-RL.git"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos abrir o ficheiro de ontologia e ver quantos triplos contém:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Triplets found:669\n"
]
}
],
"source": [
"import rdflib\n",
"from owlrl import DeductiveClosure, OWLRL_Extension\n",
"\n",
"g = rdflib.Graph()\n",
"g.parse(\"onto.ttl\", format=\"turtle\")\n",
"\n",
"print(\"Triplets found:%d\" % len(g))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos construir o fecho e ver como o número de triplos aumenta:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Triplets after inference:4246\n"
]
}
],
"source": [
"DeductiveClosure(OWLRL_Extension).expand(g)\n",
"print(\"Triplets after inference:%d\" % len(g))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Consultar Parentes \n",
"\n",
"Agora podemos consultar o grafo para ver diferentes relações entre pessoas. Podemos usar a linguagem **SPARQL** juntamente com o método `query`. No nosso caso, vamos ver todos os **tios** na nossa árvore genealógica:\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fedor Alekseevich Romanov is uncle of Ekaterina Ivanovna Romanova\n",
"Aleksandr I Pavlovich Romanov is uncle of Aleksandr II Nikolaevich Romanov\n",
"Fedor Alekseevich Romanov is uncle of Anna Ivanovna Romanova\n"
]
}
],
"source": [
"qres = g.query(\n",
" \"\"\"SELECT DISTINCT ?aname ?bname\n",
" WHERE {\n",
" ?a fhkb:isUncleOf ?b .\n",
" ?a rdfs:label ?aname .\n",
" ?b rdfs:label ?bname .\n",
" }\"\"\")\n",
"\n",
"for row in qres:\n",
" print(\"%s is uncle of %s\" % row)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sinta-se à vontade para experimentar com diferentes relações familiares. Por exemplo, pode explorar a relação `isAncestorOf`, que define recursivamente todos os antepassados de uma determinada pessoa.\n",
"\n",
"Por fim, vamos finalizar!\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"!rm onto.ttl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
},
"kernelspec": {
"display_name": "Python 3.6",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
},
"coopTranslator": {
"original_hash": "6537d5597320e27b6052b4377b8ff8bb",
"translation_date": "2025-08-31T11:47:43+00:00",
"source_file": "lessons/2-Symbolic/FamilyOntology.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,548 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Microsoft Concept Graph - ESTA API JÁ NÃO ESTÁ DISPONÍVEL, MAS CONSULTE O NOTEBOOK PARA COMPREENDER O CONCEITO\n",
"\n",
"[Microsoft Concept Graph](https://concept.research.microsoft.com/) é uma grande taxonomia de termos extraídos da internet, com relações de tipo `is-a` entre conceitos.\n",
"\n",
"O Context Graph está disponível em duas formas:\n",
" * Ficheiro de texto grande para download\n",
" * API REST\n",
"\n",
"Estatísticas:\n",
" * 5.401.933 conceitos únicos\n",
" * 12.551.613 instâncias únicas\n",
" * 87.603.947 relações `is-a`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Utilizar o Serviço Web\n",
"\n",
"O serviço web oferece diferentes chamadas para estimar a probabilidade de um conceito pertencer a diferentes grupos. Mais informações estão disponíveis [aqui](https://concept.research.microsoft.com/Home/Api). \n",
"Aqui está o URL de exemplo para realizar a chamada: `https://concept.research.microsoft.com/api/Concept/ScoreByProb?instance=microsoft&topK=10`\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"{'company': 0.6105356614382954,\n",
" 'vendor': 0.08858636677518003,\n",
" 'client': 0.048239124001183784,\n",
" 'firm': 0.045476965571668145,\n",
" 'large company': 0.043109401203511886,\n",
" 'organization': 0.043010752688172046,\n",
" 'corporation': 0.035908059583703265,\n",
" 'brand': 0.03383644076156654,\n",
" 'software company': 0.027522935779816515,\n",
" 'technology company': 0.023774292196902438}"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import urllib\n",
"import json\n",
"import ssl\n",
"\n",
"def http(x):\n",
" ssl._create_default_https_context = ssl._create_unverified_context\n",
" response = urllib.request.urlopen(x)\n",
" data = response.read()\n",
" return data.decode('utf-8')\n",
"\n",
"def query(x):\n",
" return json.loads(http(\"https://concept.research.microsoft.com/api/Concept/ScoreByProb?instance={}&topK=10\".format(urllib.parse.quote(x))))\n",
"\n",
"query('microsoft')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos tentar categorizar os títulos das notícias usando conceitos principais. Para obter os títulos das notícias, usaremos o serviço [NewsApi.org](http://newsapi.org). É necessário obter a sua própria chave API para utilizar o serviço - aceda ao site e registe-se no plano de desenvolvedor gratuito.\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"newsapi_key = '<your API key here>'\n",
"def get_news(country='us'):\n",
" res = json.loads(http(\"https://newsapi.org/v2/top-headlines?country={0}&apiKey={1}\".format(country,newsapi_key)))\n",
" return res['articles']\n",
"\n",
"all_titles = [x['title'] for x in get_news('us')+get_news('gb')]"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['Covid-19 Live Updates: Vaccines and Boosters News - The New York Times',\n",
" 'Ukrainians Flee Mariupol as Russian Forces Push to Take Port City - The Wall Street Journal',\n",
" 'Bond Yields Jump, Stock Futures Rise After Powell Says Fed Is Ready to Be More Aggressive - The Wall Street Journal',\n",
" 'Putin critic Alexei Navalny found guilty by Russian court - New York Post ',\n",
" \"Supreme Court nominee Ketanji Brown Jackson will face questions at confirmation hearing's second day - CNN\",\n",
" '2 teachers killed at Swedish high school, student arrested - ABC News',\n",
" 'Clues to Covid-19s Next Moves Come From Sewers - The Wall Street Journal',\n",
" 'Republicans to roll dice by grilling Jackson over child-pornography sentencing decisions | TheHill - The Hill',\n",
" 'Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent',\n",
" 'NASA confirms there are 5,000 planets outside our solar system - Daily Mail',\n",
" \"US stocks whipsawed overnight after Fed Chair Powell's remarks - Fox Business\",\n",
" \"'We've learned absolutely nothing': Tests could again be in short supply if Covid surges - POLITICO\",\n",
" \"Duchess of Cambridge swaps khaki jungle gear for Vampire's Wife dress on Belize trip - Daily Mail\",\n",
" 'China searches for victims, flight recorders after first plane crash in 12 years - Reuters',\n",
" 'Second superyacht linked to Russian oligarch Abramovich docks in Turkey - Reuters',\n",
" 'Live updates: Russia stops talks with Japan over sanctions - The Associated Press - en Español',\n",
" 'Powers Remain and Threats Lurk as Womens Sweet 16 Is Set - The New York Times',\n",
" 'Webb Space Telescope Begins Multi-Instrument Alignment - SciTechDaily',\n",
" \"UConn vs UCF - NCAA women's tournament second-round highlights - March Madness\",\n",
" 'Bucking Republican Trend, Indiana Governor Vetoes Transgender Sports Bill - The New York Times',\n",
" \"Maggie Fox dead: Coronation Street and Shameless actress dies after 'sudden accident' - Mirror Online - The Mirror\",\n",
" 'China plane crash live: Search for survivors continues as witness describes moment flight fell from sky - The Independent',\n",
" 'Daniel Morgan murder: damning report condemns Met police - The Guardian',\n",
" 'What to expect from Rishi Sunaks Spring Statement - BBC.com',\n",
" 'UK and Republic of Ireland in line to host Euro 2028 after no one else bids - The Guardian',\n",
" \"Friends beg Vladimir Putin's 'lover' to persuade him to end Ukraine invasion - The Mirror\",\n",
" 'Brass Eyes outtakes show the brutal TV comedy was the tip of an iceberg - The Guardian',\n",
" \"Vladimir Putin threatens civilians to break Mariupol's spirit - The Times\",\n",
" 'Shell U-turn on Cambo oilfield would threaten green targets, say campaigners - The Guardian',\n",
" 'St Helens dog attack: Girl aged 17 months killed at home - BBC',\n",
" \"PlayStation to buy 'Assassin's Creed' veteran Jade Raymond's Haven Studios - NME\",\n",
" 'Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent',\n",
" 'NASA confirms there are 5,000 planets outside our solar system - Daily Mail',\n",
" 'Nintendo Switch finally has folders • Eurogamer.net - Eurogamer.net',\n",
" 'FA to “find a solution” as Liverpool fan group blasts “shambolic” Wembley travel - This Is Anfield',\n",
" 'Manchester United transfer news LIVE Erik ten Hag latest and Man Utd manager updates - Manchester Evening News',\n",
" 'Inflation raises cost of UK government borrowing in February; crude oil up again business live - The Guardian',\n",
" 'Alexei Navalny: Kremlin critic found guilty of large-scale fraud and contempt of court by Russian court - Sky News',\n",
" \"UK prepares to nationalize Russia natural gas giant Gazprom's retail unit - Business Insider\",\n",
" 'Zaghari-Ratcliffe: Hunt calls for inquiry into delay over Iran debt payment - The Guardian']"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all_titles"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Em primeiro lugar, queremos ser capazes de extrair substantivos de títulos de notícias. Vamos usar a biblioteca `TextBlob` para fazer isso, que simplifica muitos dos típicos trabalhos de PLN como este.\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: textblob in c:\\winapp\\miniconda3\\lib\\site-packages (0.17.1)\n",
"Requirement already satisfied: nltk>=3.1 in c:\\winapp\\miniconda3\\lib\\site-packages (from textblob) (3.5)\n",
"Requirement already satisfied: joblib in c:\\winapp\\miniconda3\\lib\\site-packages (from nltk>=3.1->textblob) (1.0.1)\n",
"Requirement already satisfied: regex in c:\\winapp\\miniconda3\\lib\\site-packages (from nltk>=3.1->textblob) (2021.11.10)\n",
"Requirement already satisfied: tqdm in c:\\winapp\\miniconda3\\lib\\site-packages (from nltk>=3.1->textblob) (4.61.2)\n",
"Requirement already satisfied: click in c:\\winapp\\miniconda3\\lib\\site-packages (from nltk>=3.1->textblob) (8.0.3)\n",
"Requirement already satisfied: colorama in c:\\winapp\\miniconda3\\lib\\site-packages (from click->nltk>=3.1->textblob) (0.4.4)\n",
"Finished.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[nltk_data] Downloading package brown to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package brown is already up-to-date!\n",
"[nltk_data] Downloading package punkt to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package punkt is already up-to-date!\n",
"[nltk_data] Downloading package wordnet to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package wordnet is already up-to-date!\n",
"[nltk_data] Downloading package averaged_perceptron_tagger to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package averaged_perceptron_tagger is already up-to-\n",
"[nltk_data] date!\n",
"[nltk_data] Downloading package conll2000 to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package conll2000 is already up-to-date!\n",
"[nltk_data] Downloading package movie_reviews to\n",
"[nltk_data] C:\\Users\\dmitryso\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package movie_reviews is already up-to-date!\n"
]
}
],
"source": [
"import sys\n",
"!{sys.executable} -m pip install textblob\n",
"!{sys.executable} -m textblob.download_corpora\n",
"from textblob import TextBlob"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"{'covid-19 live updates': 1,\n",
" 'vaccines': 1,\n",
" 'boosters': 1,\n",
" 'york': 4,\n",
" 'ukrainians flee mariupol': 1,\n",
" 'forces push': 1,\n",
" 'port city': 1,\n",
" 'wall street journal': 3,\n",
" 'bond yields': 1,\n",
" 'futures rise': 1,\n",
" 'powell says fed': 1,\n",
" 'ready': 1,\n",
" 'be': 1,\n",
" 'aggressive': 1,\n",
" 'putin': 3,\n",
" 'alexei navalny': 2,\n",
" 'russian': 2,\n",
" 'supreme court nominee': 1,\n",
" 'ketanji brown jackson': 1,\n",
" \"confirmation hearing 's\": 1,\n",
" 'cnn': 1,\n",
" 'swedish': 1,\n",
" 'high school': 1,\n",
" 'abc': 1,\n",
" 'clues': 1,\n",
" 'covid-19': 1,\n",
" ' s': 2,\n",
" 'moves': 1,\n",
" 'sewers': 1,\n",
" 'roll dice': 1,\n",
" 'jackson': 1,\n",
" 'decisions |': 1,\n",
" 'thehill': 1,\n",
" 'clear': 2,\n",
" 'chemical weapons': 2,\n",
" 'ukraine': 3,\n",
" 'claims president': 2,\n",
" 'biden': 2,\n",
" 'nasa': 2,\n",
" 'solar system': 2,\n",
" 'daily mail': 3,\n",
" 'us stocks': 1,\n",
" 'fed chair powell': 1,\n",
" \"'s remarks\": 1,\n",
" 'fox': 1,\n",
" \"'we 've\": 1,\n",
" 'tests': 1,\n",
" 'covid': 1,\n",
" 'politico': 1,\n",
" 'duchess': 1,\n",
" 'cambridge': 1,\n",
" 'swaps khaki jungle gear': 1,\n",
" 'vampire': 1,\n",
" 'wife': 1,\n",
" 'belize': 1,\n",
" 'china': 2,\n",
" 'flight recorders': 1,\n",
" 'plane crash': 1,\n",
" 'reuters': 2,\n",
" 'russian oligarch': 1,\n",
" 'abramovich': 1,\n",
" 'live': 1,\n",
" 'russia': 2,\n",
" 'stops talks': 1,\n",
" 'japan': 1,\n",
" 'español': 1,\n",
" 'powers remain': 1,\n",
" 'threats lurk': 1,\n",
" 'set': 1,\n",
" 'webb': 1,\n",
" 'telescope begins multi-instrument alignment': 1,\n",
" 'scitechdaily': 1,\n",
" 'uconn': 1,\n",
" 'ucf': 1,\n",
" 'ncaa': 1,\n",
" \"women 's tournament second-round highlights\": 1,\n",
" 'march madness': 1,\n",
" 'bucking republican trend': 1,\n",
" 'indiana': 1,\n",
" 'vetoes transgender': 1,\n",
" 'bill': 1,\n",
" 'maggie fox': 1,\n",
" 'coronation': 1,\n",
" 'shameless': 1,\n",
" \"'sudden accident\": 1,\n",
" 'mirror online': 1,\n",
" 'mirror': 2,\n",
" 'plane crash ': 1,\n",
" 'search': 1,\n",
" 'moment flight': 1,\n",
" 'daniel morgan': 1,\n",
" 'report condemns': 1,\n",
" 'met': 1,\n",
" 'guardian': 6,\n",
" 'rishi sunak': 1,\n",
" ' s spring': 1,\n",
" 'statement': 1,\n",
" 'bbc.com': 1,\n",
" 'uk': 3,\n",
" 'ireland': 1,\n",
" 'euro': 1,\n",
" 'vladimir putin': 2,\n",
" \"'s 'lover\": 1,\n",
" 'brass eye': 1,\n",
" ' s outtakes': 1,\n",
" 'brutal tv comedy': 1,\n",
" 'threatens civilians': 1,\n",
" 'mariupol': 1,\n",
" \"'s spirit\": 1,\n",
" 'shell u-turn': 1,\n",
" 'cambo': 1,\n",
" 'green targets': 1,\n",
" 'st helens': 1,\n",
" 'dog attack': 1,\n",
" 'girl': 1,\n",
" 'bbc': 1,\n",
" 'playstation': 1,\n",
" \"'assassin 's\": 1,\n",
" 'creed': 1,\n",
" 'jade raymond': 1,\n",
" 'haven studios': 1,\n",
" 'nme': 1,\n",
" 'nintendo switch': 1,\n",
" 'folders •': 1,\n",
" 'eurogamer.net': 2,\n",
" 'fa': 1,\n",
" 'solution ”': 1,\n",
" 'liverpool': 1,\n",
" 'fan group blasts “ shambolic ”': 1,\n",
" 'wembley': 1,\n",
" 'anfield': 1,\n",
" 'manchester': 1,\n",
" 'live erik': 1,\n",
" 'hag': 1,\n",
" 'utd': 1,\n",
" 'manager updates': 1,\n",
" 'manchester evening': 1,\n",
" 'inflation': 1,\n",
" 'government borrowing': 1,\n",
" 'february': 1,\n",
" 'crude oil': 1,\n",
" ' business': 1,\n",
" 'kremlin': 1,\n",
" 'large-scale fraud': 1,\n",
" 'sky': 1,\n",
" 'natural gas': 1,\n",
" 'gazprom': 1,\n",
" 'retail unit': 1,\n",
" 'insider': 1,\n",
" 'zaghari-ratcliffe': 1,\n",
" 'hunt': 1,\n",
" 'iran': 1,\n",
" 'debt payment': 1}"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w = {}\n",
"for x in all_titles:\n",
" for n in TextBlob(x).noun_phrases:\n",
" if n in w:\n",
" w[n].append(x)\n",
" else:\n",
" w[n]=[x]\n",
"{ x:len(w[x]) for x in w.keys()}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos ver que os substantivos não nos dão grandes grupos temáticos. Vamos substituir os substantivos por termos mais gerais obtidos a partir do gráfico de conceitos. Isto vai demorar algum tempo, porque estamos a fazer chamadas REST para cada expressão nominal.\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"w = {}\n",
"for x in all_titles:\n",
" for noun in TextBlob(x).noun_phrases:\n",
" terms = query(noun.replace(' ','%20'))\n",
" for term in [u for u in terms.keys() if terms[u]>0.1]:\n",
" if term in w:\n",
" w[term].append(x)\n",
" else:\n",
" w[term]=[x]"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"trusted": true
},
"outputs": [
{
"data": {
"text/plain": [
"{'city': 9,\n",
" 'brand': 4,\n",
" 'place': 9,\n",
" 'town': 4,\n",
" 'factor': 4,\n",
" 'film': 4,\n",
" 'nation': 11,\n",
" 'state': 5,\n",
" 'person': 4,\n",
" 'organization': 5,\n",
" 'publication': 10,\n",
" 'market': 5,\n",
" 'economy': 4,\n",
" 'company': 6,\n",
" 'newspaper': 6,\n",
" 'relationship': 6}"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{ x:len(w[x]) for x in w.keys() if len(w[x])>3}"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"ECONOMY:\n",
"China searches for victims, flight recorders after first plane crash in 12 years - Reuters\n",
"Live updates: Russia stops talks with Japan over sanctions - The Associated Press - en Español\n",
"China plane crash live: Search for survivors continues as witness describes moment flight fell from sky - The Independent\n",
"UK prepares to nationalize Russia natural gas giant Gazprom's retail unit - Business Insider\n",
"\n",
"NATION:\n",
"Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent\n",
"Duchess of Cambridge swaps khaki jungle gear for Vampire's Wife dress on Belize trip - Daily Mail\n",
"China searches for victims, flight recorders after first plane crash in 12 years - Reuters\n",
"Live updates: Russia stops talks with Japan over sanctions - The Associated Press - en Español\n",
"Live updates: Russia stops talks with Japan over sanctions - The Associated Press - en Español\n",
"China plane crash live: Search for survivors continues as witness describes moment flight fell from sky - The Independent\n",
"UK and Republic of Ireland in line to host Euro 2028 after no one else bids - The Guardian\n",
"Friends beg Vladimir Putin's 'lover' to persuade him to end Ukraine invasion - The Mirror\n",
"Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent\n",
"UK prepares to nationalize Russia natural gas giant Gazprom's retail unit - Business Insider\n",
"Zaghari-Ratcliffe: Hunt calls for inquiry into delay over Iran debt payment - The Guardian\n",
"\n",
"PERSON:\n",
"Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent\n",
"Duchess of Cambridge swaps khaki jungle gear for Vampire's Wife dress on Belize trip - Daily Mail\n",
"Second superyacht linked to Russian oligarch Abramovich docks in Turkey - Reuters\n",
"Clear sign Putin considering using chemical weapons in Ukraine, claims President Biden - The Independent\n"
]
}
],
"source": [
"print('\\nECONOMY:\\n'+'\\n'.join(w['economy']))\n",
"print('\\nNATION:\\n'+'\\n'.join(w['nation']))\n",
"print('\\nPERSON:\\n'+'\\n'.join(w['person']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.7.4 64-bit (conda)",
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
}
},
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
},
"coopTranslator": {
"original_hash": "7b3f1fc049371bcf8649ac9fefdf0413",
"translation_date": "2025-10-03T18:53:48+00:00",
"source_file": "lessons/2-Symbolic/MSConceptGraph.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,248 @@
# Representação do Conhecimento e Sistemas Especialistas
![Resumo do conteúdo de IA Simbólica](../../../../translated_images/pt-PT/ai-symbolic.715a30cb610411a6.webp)
> Sketchnote por [Tomomi Imura](https://twitter.com/girlie_mac)
A busca pela inteligência artificial baseia-se na procura por conhecimento, para compreender o mundo de forma semelhante aos humanos. Mas como é que se pode fazer isso?
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/3)
Nos primeiros tempos da IA, a abordagem top-down para criar sistemas inteligentes (discutida na aula anterior) era popular. A ideia era extrair o conhecimento das pessoas para alguma forma legível por máquina, e depois usá-lo para resolver problemas automaticamente. Esta abordagem baseava-se em duas grandes ideias:
* Representação do Conhecimento
* Raciocínio
## Representação do Conhecimento
Um dos conceitos importantes na IA Simbólica é o **conhecimento**. É importante diferenciar conhecimento de *informação* ou *dados*. Por exemplo, pode-se dizer que os livros contêm conhecimento, porque se pode estudar livros e tornar-se perito. No entanto, o que os livros realmente contêm são chamados *dados*, e ao ler livros e integrar esses dados no nosso modelo do mundo, convertemos esses dados em conhecimento.
> ✅ **Conhecimento** é algo que está contido na nossa cabeça e representa a nossa compreensão do mundo. É obtido por um processo ativo de **aprendizagem**, que integra peças de informação que recebemos no nosso modelo ativo do mundo.
Na maior parte das vezes, não definimos conhecimento de forma rigorosa, mas alinhamos com outros conceitos relacionados usando a [Pirâmide DIKW](https://en.wikipedia.org/wiki/DIKW_pyramid). Esta contém os seguintes conceitos:
* **Dados** são algo representado em suporte físico, como texto escrito ou palavras faladas. Os dados existem independentemente dos seres humanos e podem ser passados entre pessoas.
* **Informação** é como interpretamos os dados na nossa mente. Por exemplo, quando ouvimos a palavra *computador*, temos alguma compreensão do que é.
* **Conhecimento** é a informação integrada no nosso modelo do mundo. Por exemplo, uma vez que aprendemos o que é um computador, começamos a ter algumas ideias sobre como funciona, quanto custa e para que pode ser usado. Esta rede de conceitos inter-relacionados forma o nosso conhecimento.
* **Sabedoria** é mais um nível da nossa compreensão do mundo, representando *meta-conhecimento*, por exemplo, alguma noção de como e quando o conhecimento deve ser utilizado.
<img src="../../../../translated_images/pt-PT/DIKW_Pyramid.94126f7d2bd8db5b.webp" width="30%"/>
*Imagem [da Wikipedia](https://commons.wikimedia.org/w/index.php?curid=37705247), por Longlivetheux - Trabalho próprio, CC BY-SA 4.0*
Assim, o problema da **representação do conhecimento** é encontrar uma forma eficaz de representar conhecimento dentro de um computador sob a forma de dados, para que possa ser utilizado automaticamente. Isto pode ser visto como um espectro:
![Espectro da representação do conhecimento](../../../../translated_images/pt-PT/knowledge-spectrum.b60df631852c0217.webp)
> Imagem por [Dmitry Soshnikov](http://soshnikov.com)
* À esquerda, existem tipos muito simples de representações de conhecimento que podem ser eficazmente usados por computadores. A mais simples é a algorítmica, quando o conhecimento é representado por um programa de computador. No entanto, esta não é a melhor forma de representar conhecimento, porque não é flexível. O conhecimento dentro da nossa cabeça é frequentemente não algorítmico.
* À direita, existem representações como texto natural. É a mais poderosa, mas não pode ser usada para raciocínio automático.
> ✅ Pense por um minuto em como representa o conhecimento na sua cabeça e o converte em notas. Existe algum formato particular que funcione bem para ajudar na retenção?
## Classificação dos Métodos de Representação de Conhecimento em Computadores
Podemos classificar os diferentes métodos de representação de conhecimento computacional nas seguintes categorias:
* **Representações em rede** baseiam-se no facto de termos uma rede de conceitos inter-relacionados dentro da nossa cabeça. Podemos tentar reproduzir as mesmas redes como um grafo dentro de um computador a chamada **rede semântica**.
1. **Triplos Objeto-Atributo-Valor** ou **pares atributo-valor**. Como um grafo pode ser representado dentro de um computador como uma lista de nós e ligações, podemos representar uma rede semântica por uma lista de triplos, contendo objetos, atributos e valores. Por exemplo, criamos os seguintes triplos sobre linguagens de programação:
Objeto | Atributo | Valor
-------|----------|-------
Python | é | Linguagem Não Tipada
Python | inventado-por | Guido van Rossum
Python | sintaxe-bloco | indentação
Linguagem Não Tipada | não tem | definições de tipo
> ✅ Pense como os triplos podem ser usados para representar outros tipos de conhecimento.
2. **Representações hierárquicas** enfatizam o facto de criarmos frequentemente uma hierarquia de objetos dentro da nossa cabeça. Por exemplo, sabemos que canário é um pássaro, e que todos os pássaros têm asas. Também temos alguma ideia da cor que um canário normalmente tem e da sua velocidade de voo.
- **Representação por quadros** baseia-se em representar cada objeto ou classe de objetos como um **quadro** que contém **espaços (slots)**. Os espaços têm valores padrão possíveis, restrições de valor ou procedimentos armazenados que podem ser chamados para obter o valor de um espaço. Todos os quadros formam uma hierarquia semelhante a uma hierarquia de objetos em linguagens de programação orientadas a objetos.
- **Cenários** são um tipo especial de quadros que representam situações complexas que podem desenvolver-se no tempo.
**Python**
Espaço | Valor | Valor padrão | Intervalo |
-------|-------|--------------|-----------|
Nome | Python | | |
É-Um | Linguagem Não Tipada | | |
Caso Variável | | CamelCase | |
Comprimento do Programa | | | 5-5000 linhas |
Sintaxe de Bloco | Indentação | | |
3. **Representações procedurais** são baseadas em representar conhecimento por uma lista de ações que podem ser executadas quando uma certa condição ocorre.
- Regras de produção são sentenças do tipo se-então que permitem tirar conclusões. Por exemplo, um médico pode ter uma regra que diz que **SE** um paciente tem febre alta **OU** nível elevado de proteína C-reativa no exame sanguíneo **ENTÃO** ele tem uma inflamação. Uma vez que surge uma das condições, podemos concluir a inflamação, e depois usar isso em raciocínios posteriores.
- Algoritmos podem ser considerados outra forma de representação procedural, embora quase nunca sejam usados diretamente em sistemas baseados em conhecimento.
4. **Lógica** foi originalmente proposta por Aristóteles como uma forma de representar o conhecimento universal humano.
- A Lógica de Predicados como teoria matemática é demasiado rica para ser computável, portanto usa-se normalmente algum subconjunto dela, como as cláusulas de Horn usadas em Prolog.
- A Lógica Descritiva é uma família de sistemas lógicos usados para representar e raciocinar sobre hierarquias de objetos em representações de conhecimento distribuído, como a *web semântica*.
## Sistemas Especialistas
Um dos primeiros sucessos da IA simbólica foram os chamados **sistemas especialistas** sistemas computacionais desenhados para agir como um especialista num domínio de problema limitado. Eram baseados numa **base de conhecimento** extraída de um ou mais especialistas humanos, e continham um **mecanismo de inferência** que realizava algum raciocínio sobre ela.
![Arquitetura Humana](../../../../translated_images/pt-PT/arch-human.5d4d35f1bba3ab1c.webp) | ![Sistema Baseado em Conhecimento](../../../../translated_images/pt-PT/arch-kbs.3ec5c150b09fa8da.webp)
---------------------------------------------|-----------------------------------------------
Estrutura simplificada do sistema neural humano | Arquitetura de um sistema baseado em conhecimento
Os sistemas especialistas são construídos como o sistema de raciocínio humano, que contém **memória de curto prazo** e **memória de longo prazo**. Igualmente, em sistemas baseados em conhecimento distinguimos os seguintes componentes:
* **Memória do problema**: contém o conhecimento sobre o problema que está a ser atualmente resolvido, isto é, a temperatura ou pressão arterial de um paciente, se tem inflamação ou não, etc. Este conhecimento é também chamado **conhecimento estático**, porque contém uma fotografia do que sabemos atualmente sobre o problema o chamado *estado do problema*.
* **Base de conhecimento**: representa o conhecimento de longo prazo sobre um domínio de problema. É extraída manualmente de especialistas humanos e não muda de consulta para consulta. Porque permite navegar de um estado do problema para outro, também é chamada **conhecimento dinâmico**.
* **Mecanismo de inferência**: orquestra todo o processo de busca no espaço de estados do problema, fazendo perguntas ao utilizador quando necessário. É também responsável por encontrar as regras certas a aplicar em cada estado.
Como exemplo, vamos considerar o seguinte sistema especialista para determinar um animal baseado nas suas características físicas:
![Árvore AND-OR](../../../../translated_images/pt-PT/AND-OR-Tree.5592d2c70187f283.webp)
> Imagem por [Dmitry Soshnikov](http://soshnikov.com)
Este diagrama é chamado de **árvore AND-OR**, e é uma representação gráfica de um conjunto de regras de produção. Desenhar uma árvore é útil no início da extração do conhecimento do especialista. Para representar o conhecimento dentro do computador, é mais conveniente usar regras:
```
IF the animal eats meat
OR (animal has sharp teeth
AND animal has claws
AND animal has forward-looking eyes
)
THEN the animal is a carnivore
```
Pode notar que cada condição no lado esquerdo da regra e a ação são essencialmente triplos objeto-atributo-valor (OAV). A **memória de trabalho** contém o conjunto de triplos OAV que correspondem ao problema atualmente a resolver. Um **motor de regras** procura regras cuja condição seja satisfeita e aplica-as, adicionando outro triplo à memória de trabalho.
> ✅ Escreva a sua própria árvore AND-OR sobre um tema do seu interesse!
### Inferência Direta vs. Inferência Retroativa
O processo descrito acima chama-se **inferência direta**. Começa com alguns dados iniciais sobre o problema disponíveis na memória de trabalho e depois executa o seguinte ciclo de raciocínio:
1. Se o atributo alvo está presente na memória de trabalho parar e fornecer o resultado
2. Procurar todas as regras cuja condição está atualmente satisfeita obter o **conjunto de conflito** das regras.
3. Realizar a **resolução de conflito** selecionar uma regra que será executada neste passo. Podem existir diferentes estratégias de resolução de conflito:
- Selecionar a primeira regra aplicável na base de conhecimento
- Selecionar uma regra aleatória
- Selecionar uma regra *mais específica*, ou seja, aquela que satisfaz mais condições no "lado esquerdo" (LHS)
4. Aplicar a regra selecionada e inserir uma nova peça de conhecimento no estado do problema
5. Repetir desde o passo 1.
No entanto, em alguns casos talvez queiramos começar com conhecimento vazio sobre o problema, e fazer perguntas que nos ajudem a chegar à conclusão. Por exemplo, na realização de um diagnóstico médico, normalmente não fazemos todos os exames médicos antecipadamente antes de começar a diagnosticar o paciente. Preferimos realizar exames quando é necessário tomar uma decisão.
Este processo pode ser modelado usando **inferência retroativa**. É conduzido pelo **objetivo** o valor do atributo que estamos a tentar encontrar:
1. Selecionar todas as regras que possam dar-nos o valor do objetivo (ou seja, com o objetivo no lado direito (RHS)) um conjunto de conflito
1. Se não houver regras para este atributo, ou houver uma regra que diga que devemos perguntar o valor ao utilizador perguntar, caso contrário:
1. Usar a estratégia de resolução de conflito para selecionar uma regra que vamos usar como *hipótese* vamos tentar prová-la
1. Repetir recursivamente o processo para todos os atributos no LHS da regra, tentando prová-los como objetivos
1. Se em algum momento o processo falhar usar outra regra no passo 3.
> ✅ Em que situações a inferência direta é mais apropriada? E a inferência retroativa?
### Implementação de Sistemas Especialistas
Sistemas especialistas podem ser implementados usando diferentes ferramentas:
* Programando-os diretamente numa linguagem de programação de alto nível. Esta não é a melhor ideia, porque a principal vantagem de um sistema baseado em conhecimento é que o conhecimento está separado da inferência, e potencialmente um especialista do domínio do problema deve poder escrever regras sem entender os detalhes do processo de inferência
* Usando **shells de sistemas especialistas**, ou seja, sistemas especificamente desenhados para serem populados com conhecimento usando alguma linguagem de representação do conhecimento.
## ✍️ Exercício: Inferência de Animais
Veja [Animals.ipynb](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/2-Symbolic/Animals.ipynb) para um exemplo da implementação de um sistema especialista com inferência direta e retroativa.
> **Nota**: Este exemplo é bastante simples e apenas dá uma ideia de como é um sistema especialista. Depois de começar a criar um sistema assim, só notará algum comportamento *inteligente* quando atingir um certo número de regras, cerca de 200+. Em algum ponto, as regras tornam-se demasiado complexas para manter todas em mente, e nesse ponto pode começar a perguntar-se porque é que um sistema toma certas decisões. Contudo, a característica importante dos sistemas baseados em conhecimento é que pode sempre *explicar* exatamente como qualquer decisão foi tomada.
## Ontologias e a Web Semântica
No final do século XX houve uma iniciativa para usar a representação de conhecimento para anotar recursos na Internet, de forma a ser possível encontrar recursos que correspondam a pesquisas muito específicas. Esta iniciativa foi chamada **Web Semântica**, e baseava-se em vários conceitos:
- Uma representação especial do conhecimento baseada em **[lógicas descritivas](https://en.wikipedia.org/wiki/Description_logic)** (DL). É semelhante à representação de conhecimento por quadros, porque constrói uma hierarquia de objetos com propriedades, mas tem semântica formal lógica e inferência. Existe uma família inteira de DLs que equilibram a expressividade e a complexidade algorítmica da inferência.
- Representação de conhecimento distribuído, onde todos os conceitos são representados por um identificador global URI, tornando possível criar hierarquias de conhecimento que abrangem a internet.
- Uma família de linguagens baseadas em XML para descrição de conhecimento: RDF (Resource Description Framework), RDFS (RDF Schema), OWL (Ontology Web Language).
Um conceito central na Web Semântica é o conceito de **Ontologia**. Refere-se à especificação explícita de um domínio de problema usando alguma representação formal de conhecimento. A ontologia mais simples pode ser apenas uma hierarquia de objetos em um domínio de problema, mas ontologias mais complexas incluirão regras que podem ser usadas para inferência.
Na web semântica, todas as representações são baseadas em triplets. Cada objeto e cada relação são identificados unicamente pelo URI. Por exemplo, se quisermos declarar o facto de que este Currículo de IA foi desenvolvido por Dmitry Soshnikov em 1 de Janeiro de 2022 - aqui estão os triplets que podemos usar:
<img src="../../../../translated_images/pt-PT/triplet.4b9b332587593298.webp" width="30%"/>
```
http://github.com/microsoft/ai-for-beginners http://www.example.com/terms/creation-date “Jan 1, 2022”
http://github.com/microsoft/ai-for-beginners http://purl.org/dc/elements/1.1/creator http://soshnikov.com
```
> ✅ Aqui `http://www.example.com/terms/creation-date` e `http://purl.org/dc/elements/1.1/creator` são alguns URIs bem conhecidos e universalmente aceites para expressar os conceitos de *criador* e *data de criação*.
Num caso mais complexo, se quisermos definir uma lista de criadores, podemos usar algumas estruturas de dados definidas em RDF.
<img src="../../../../translated_images/pt-PT/triplet-complex.32094972c7b4441b.webp" width="40%"/>
> Diagramas acima por [Dmitry Soshnikov](http://soshnikov.com)
O progresso na construção da Web Semântica foi de algum modo travado pelo sucesso dos motores de busca e das técnicas de processamento de linguagem natural, que permitem extrair dados estruturados a partir de texto. No entanto, em algumas áreas ainda existem esforços significativos para manter ontologias e bases de conhecimento. Alguns projetos dignos de nota:
* [WikiData](https://wikidata.org/) é uma coleção de bases de conhecimento legíveis por máquina associadas à Wikipédia. A maior parte dos dados é extraída das *InfoBoxes* da Wikipédia, que são pedaços de conteúdo estruturado dentro das páginas da Wikipédia. Pode [consultar](https://query.wikidata.org/) o wikidata em SPARQL, uma linguagem de consulta especial para a Web Semântica. Aqui está uma consulta de exemplo que mostra as cores de olhos mais populares entre humanos:
```sparql
#defaultView:BubbleChart
SELECT ?eyeColorLabel (COUNT(?human) AS ?count)
WHERE
{
?human wdt:P31 wd:Q5. # human instance-of homo sapiens
?human wdt:P1340 ?eyeColor. # human eye-color ?eyeColor
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?eyeColorLabel
```
* [DBpedia](https://www.dbpedia.org/) é outro esforço semelhante ao WikiData.
> ✅ Se quiser experimentar criar as suas próprias ontologias, ou abrir ontologias existentes, existe um excelente editor visual de ontologias chamado [Protégé](https://protege.stanford.edu/). Faça o download ou use online.
<img src="../../../../translated_images/pt-PT/protege.274177ceeac13b38.webp" width="70%"/>
*Editor Web Protégé aberto com a ontologia da Família Romanov. Captura de ecrã por Dmitry Soshnikov*
## ✍️ Exercício: Uma Ontologia de Família
Consulte [FamilyOntology.ipynb](https://github.com/Ezana135/AI-For-Beginners/blob/main/lessons/2-Symbolic/FamilyOntology.ipynb) para um exemplo de uso de técnicas da Web Semântica para raciocinar sobre relações familiares. Vamos pegar numa árvore genealógica representada no formato comum GEDCOM e numa ontologia de relações familiares e construir um grafo de todas as relações familiares para um dado conjunto de indivíduos.
## Microsoft Concept Graph
Na maioria dos casos, as ontologias são cuidadosamente criadas manualmente. No entanto, é também possível **extrair** ontologias de dados não estruturados, por exemplo, de textos em linguagem natural.
Uma dessas tentativas foi feita pela Microsoft Research, e resultou no [Microsoft Concept Graph](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-77998-cacaste).
É uma grande coleção de entidades agrupadas usando a relação de herança `is-a`. Permite responder a perguntas como "O que é a Microsoft?" a resposta sendo algo como "uma empresa com probabilidade 0.87, e uma marca com probabilidade 0.75".
O Grafo está disponível como REST API, ou como um grande ficheiro de texto descarregável que lista todos os pares de entidades.
## ✍️ Exercício: Um Grafo de Conceitos
Experimente o caderno [MSConceptGraph.ipynb](https://github.com/microsoft/AI-For-Beginners/blob/main/lessons/2-Symbolic/MSConceptGraph.ipynb) para ver como podemos usar o Microsoft Concept Graph para agrupar artigos de notícias em várias categorias.
## Conclusão
Hoje em dia, a IA é frequentemente considerada sinónimo de *Aprendizagem Automática* ou *Redes Neuronais*. No entanto, um ser humano também exibe raciocínio explícito, que é algo que atualmente não é tratado pelas redes neuronais. Em projetos do mundo real, o raciocínio explícito é ainda utilizado para realizar tarefas que requerem explicações, ou a capacidade de modificar o comportamento do sistema de forma controlada.
## 🚀 Desafio
No caderno Ontologia de Família associado a esta lição, há oportunidade de experimentar outras relações familiares. Tente descobrir novas ligações entre pessoas na árvore genealógica.
## [Quiz pós-lectura](https://ff-quizzes.netlify.app/en/ai/quiz/4)
## Revisão & Autoestudo
Faça algumas pesquisas na internet para descobrir áreas onde os humanos tentaram quantificar e codificar conhecimento. Consulte a Taxonomia de Bloom, e volte na história para aprender como os humanos tentaram compreender o seu mundo. Explore o trabalho de Linnaeus para criar uma taxonomia de organismos, e observe a forma como Dmitri Mendeleev criou um modo de descrever e agrupar os elementos químicos. Que outros exemplos interessantes pode encontrar?
**Trabalho**: [Construir uma Ontologia](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos empenhemos na precisão, por favor tenha em conta que traduções automatizadas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações erradas decorrentes da utilização desta tradução.
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,6 @@
# Construir uma Ontologia
Construir uma base de conhecimento consiste em categorizar um modelo que representa factos sobre um tema. Escolha um tema - como uma pessoa, um lugar ou um objeto - e, em seguida, construa um modelo desse tema. Utilize algumas das técnicas e estratégias de construção de modelos descritas nesta lição. Um exemplo seria criar uma ontologia de uma sala de estar com móveis, luzes, e assim por diante. Como é que a sala de estar se diferencia da cozinha? Da casa de banho? Como sabe que é uma sala de estar e não uma sala de jantar? Use o [Protégé](https://protege.stanford.edu/) para construir a sua ontologia.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,96 @@
# Introdução às Redes Neuronais: Perceptron
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/5)
Uma das primeiras tentativas de implementar algo semelhante a uma rede neuronal moderna foi realizada por Frank Rosenblatt, do Cornell Aeronautical Laboratory, em 1957. Tratava-se de uma implementação em hardware chamada "Mark-1", projetada para reconhecer figuras geométricas primitivas, como triângulos, quadrados e círculos.
| | |
|--------------|-----------|
|<img src='../../../../../translated_images/pt-PT/Rosenblatt-wikipedia.294821b285ac796d.webp' alt='Frank Rosenblatt'/> | <img src='../../../../../translated_images/pt-PT/Mark_I_perceptron_wikipedia.1f84eaa2d4b76ec9.webp' alt='O Perceptron Mark 1' />|
> Imagens [da Wikipédia](https://en.wikipedia.org/wiki/Perceptron)
Uma imagem de entrada era representada por uma matriz de fotocélulas de 20x20, de modo que a rede neuronal tinha 400 entradas e uma saída binária. Uma rede simples continha um único neurónio, também chamado de **unidade lógica de limiar**. Os pesos da rede neuronal funcionavam como potenciômetros que precisavam ser ajustados manualmente durante a fase de treino.
> ✅ Um potenciômetro é um dispositivo que permite ao utilizador ajustar a resistência de um circuito.
> O New York Times escreveu sobre o perceptron na época: *o embrião de um computador eletrónico que [a Marinha] espera que seja capaz de andar, falar, ver, escrever, reproduzir-se e ter consciência da sua existência.*
## Modelo de Perceptron
Suponha que temos N características no nosso modelo, caso em que o vetor de entrada seria um vetor de tamanho N. Um perceptron é um modelo de **classificação binária**, ou seja, consegue distinguir entre duas classes de dados de entrada. Vamos assumir que, para cada vetor de entrada x, a saída do nosso perceptron será +1 ou -1, dependendo da classe. A saída será calculada usando a fórmula:
y(x) = f(w<sup>T</sup>x)
onde f é uma função de ativação em degrau.
<!-- img src="http://www.sciweavers.org/tex2img.php?eq=f%28x%29%20%3D%20%5Cbegin%7Bcases%7D%0A%20%20%20%20%20%20%20%20%20%2B1%20%26%20x%20%5Cgeq%200%20%5C%5C%0A%20%20%20%20%20%20%20%20%20-1%20%26%20x%20%3C%200%0A%20%20%20%20%20%20%20%5Cend%7Bcases%7D%20%5C%5C%0A&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0" align="center" border="0" alt="f(x) = \begin{cases} +1 & x \geq 0 \\ -1 & x < 0 \end{cases} \\" width="154" height="50" / -->
<img src="../../../../../translated_images/pt-PT/activation-func.b4924007c7ce7764.webp"/>
## Treinar o Perceptron
Para treinar um perceptron, precisamos encontrar um vetor de pesos w que classifique a maioria dos valores corretamente, ou seja, que resulte no menor **erro**. Este erro E é definido pelo **critério do perceptron** da seguinte forma:
E(w) = -&sum;w<sup>T</sup>x<sub>i</sub>t<sub>i</sub>
onde:
* a soma é feita sobre os pontos de dados de treino i que resultam numa classificação errada;
* x<sub>i</sub> é o dado de entrada, e t<sub>i</sub> é -1 ou +1 para exemplos negativos e positivos, respetivamente.
Este critério é considerado como uma função dos pesos w, e precisamos minimizá-lo. Muitas vezes, utiliza-se um método chamado **descida do gradiente**, no qual começamos com alguns pesos iniciais w<sup>(0)</sup> e, em cada passo, atualizamos os pesos de acordo com a fórmula:
w<sup>(t+1)</sup> = w<sup>(t)</sup> - &eta;&nabla;E(w)
Aqui, &eta; é a chamada **taxa de aprendizagem**, e &nabla;E(w) denota o **gradiente** de E. Após calcularmos o gradiente, obtemos:
w<sup>(t+1)</sup> = w<sup>(t)</sup> + &sum;&eta;x<sub>i</sub>t<sub>i</sub>
O algoritmo em Python é assim:
```python
def train(positive_examples, negative_examples, num_iterations = 100, eta = 1):
weights = [0,0,0] # Initialize weights (almost randomly :)
for i in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights) # compute perceptron output
if z < 0: # positive example classified as negative
weights = weights + eta*weights.shape
z = np.dot(neg, weights)
if z >= 0: # negative example classified as positive
weights = weights - eta*weights.shape
return weights
```
## Conclusão
Nesta lição, aprendeste sobre o perceptron, que é um modelo de classificação binária, e como treiná-lo utilizando um vetor de pesos.
## 🚀 Desafio
Se quiseres tentar construir o teu próprio perceptron, experimenta [este laboratório no Microsoft Learn](https://docs.microsoft.com/en-us/azure/machine-learning/component-reference/two-class-averaged-perceptron?WT.mc_id=academic-77998-cacaste), que utiliza o [Azure ML designer](https://docs.microsoft.com/en-us/azure/machine-learning/concept-designer?WT.mc_id=academic-77998-cacaste).
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/6)
## Revisão e Autoestudo
Para ver como podemos usar o perceptron para resolver um problema simples, bem como problemas do mundo real, e para continuar a aprender, consulta o caderno [Perceptron](Perceptron.ipynb).
Aqui está também um [artigo interessante sobre perceptrons](https://towardsdatascience.com/what-is-a-perceptron-basics-of-neural-networks-c4cfea20c590).
## [Tarefa](lab/README.md)
Nesta lição, implementámos um perceptron para uma tarefa de classificação binária e utilizámo-lo para classificar entre dois dígitos manuscritos. Neste laboratório, és desafiado a resolver o problema de classificação de dígitos por completo, ou seja, determinar qual o dígito mais provável correspondente a uma imagem dada.
* [Instruções](lab/README.md)
* [Caderno](lab/PerceptronMultiClass.ipynb)
---

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,24 @@
# Classificação Multi-Classe com Perceptron
Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Usando o código que desenvolvemos nesta lição para classificação binária de dígitos manuscritos do MNIST, crie um classificador multi-classe que seja capaz de reconhecer qualquer dígito. Calcule a precisão da classificação nos conjuntos de dados de treino e teste, e apresente a matriz de confusão.
## Dicas
1. Para cada dígito, crie um conjunto de dados para um classificador binário de "este dígito vs. todos os outros dígitos".
1. Treine 10 perceptrons diferentes para classificação binária (um para cada dígito).
1. Defina uma função que classifique um dígito de entrada.
> **Dica**: Se combinarmos os pesos de todos os 10 perceptrons numa única matriz, deveremos ser capazes de aplicar todos os 10 perceptrons aos dígitos de entrada através de uma única multiplicação de matrizes. O dígito mais provável pode então ser encontrado simplesmente aplicando a operação `argmax` ao resultado.
## Notebook Inicial
Comece o trabalho prático abrindo [PerceptronMultiClass.ipynb](PerceptronMultiClass.ipynb)
---
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,89 @@
# Introdução às Redes Neuronais. Perceptrão Multicamadas
Na secção anterior, aprendeste sobre o modelo mais simples de rede neuronal - o perceptrão de uma camada, um modelo linear de classificação de duas classes.
Nesta secção, vamos expandir este modelo para um framework mais flexível, permitindo-nos:
* realizar **classificação de múltiplas classes** além de duas classes
* resolver **problemas de regressão** além de classificação
* separar classes que não são linearmente separáveis
Também iremos desenvolver o nosso próprio framework modular em Python, que nos permitirá construir diferentes arquiteturas de redes neuronais.
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ai/quiz/7)
## Formalização de Aprendizagem Automática
Vamos começar por formalizar o problema de Aprendizagem Automática. Suponhamos que temos um conjunto de dados de treino **X** com etiquetas **Y**, e precisamos construir um modelo *f* que faça previsões o mais precisas possível. A qualidade das previsões é medida pela **função de perda** &lagran;. As seguintes funções de perda são frequentemente utilizadas:
* Para problemas de regressão, quando precisamos prever um número, podemos usar **erro absoluto** &sum;<sub>i</sub>|f(x<sup>(i)</sup>)-y<sup>(i)</sup>|, ou **erro quadrático** &sum;<sub>i</sub>(f(x<sup>(i)</sup>)-y<sup>(i)</sup>)<sup>2</sup>
* Para classificação, usamos **perda 0-1** (que é essencialmente o mesmo que **precisão** do modelo), ou **perda logística**.
Para o perceptrão de uma camada, a função *f* foi definida como uma função linear *f(x)=wx+b* (aqui *w* é a matriz de pesos, *x* é o vetor de características de entrada, e *b* é o vetor de bias). Para diferentes arquiteturas de redes neuronais, esta função pode assumir uma forma mais complexa.
> No caso de classificação, é frequentemente desejável obter probabilidades das classes correspondentes como saída da rede. Para converter números arbitrários em probabilidades (por exemplo, para normalizar a saída), usamos frequentemente a função **softmax** &sigma;, e a função *f* torna-se *f(x)=&sigma;(wx+b)*
Na definição de *f* acima, *w* e *b* são chamados **parâmetros** &theta;=⟨*w,b*⟩. Dado o conjunto de dados ⟨**X**,**Y**⟩, podemos calcular um erro geral em todo o conjunto de dados como uma função dos parâmetros &theta;.
> ✅ **O objetivo do treino de redes neuronais é minimizar o erro variando os parâmetros &theta;**
## Otimização por Gradiente Descendente
Existe um método bem conhecido de otimização de funções chamado **gradiente descendente**. A ideia é que podemos calcular uma derivada (no caso multidimensional chamada **gradiente**) da função de perda em relação aos parâmetros, e variar os parâmetros de forma que o erro diminua. Isto pode ser formalizado da seguinte forma:
* Inicializar os parâmetros com alguns valores aleatórios w<sup>(0)</sup>, b<sup>(0)</sup>
* Repetir o seguinte passo várias vezes:
- w<sup>(i+1)</sup> = w<sup>(i)</sup>-&eta;&part;&lagran;/&part;w
- b<sup>(i+1)</sup> = b<sup>(i)</sup>-&eta;&part;&lagran;/&part;b
Durante o treino, os passos de otimização devem ser calculados considerando todo o conjunto de dados (lembra-te que a perda é calculada como uma soma através de todas as amostras de treino). No entanto, na prática, usamos pequenas porções do conjunto de dados chamadas **minibatches**, e calculamos os gradientes com base num subconjunto de dados. Como o subconjunto é escolhido aleatoriamente cada vez, tal método é chamado **gradiente descendente estocástico** (SGD).
## Perceptrões Multicamadas e Retropropagação
A rede de uma camada, como vimos acima, é capaz de classificar classes linearmente separáveis. Para construir um modelo mais rico, podemos combinar várias camadas da rede. Matematicamente, isso significaria que a função *f* teria uma forma mais complexa e seria calculada em vários passos:
* z<sub>1</sub>=w<sub>1</sub>x+b<sub>1</sub>
* z<sub>2</sub>=w<sub>2</sub>&alpha;(z<sub>1</sub>)+b<sub>2</sub>
* f = &sigma;(z<sub>2</sub>)
Aqui, &alpha; é uma **função de ativação não linear**, &sigma; é uma função softmax, e os parâmetros &theta;=<*w<sub>1</sub>,b<sub>1</sub>,w<sub>2</sub>,b<sub>2</sub>*>.
O algoritmo de gradiente descendente permaneceria o mesmo, mas seria mais difícil calcular os gradientes. Dado o princípio da regra da cadeia de diferenciação, podemos calcular as derivadas como:
* &part;&lagran;/&part;w<sub>2</sub> = (&part;&lagran;/&part;&sigma;)(&part;&sigma;/&part;z<sub>2</sub>)(&part;z<sub>2</sub>/&part;w<sub>2</sub>)
* &part;&lagran;/&part;w<sub>1</sub> = (&part;&lagran;/&part;&sigma;)(&part;&sigma;/&part;z<sub>2</sub>)(&part;z<sub>2</sub>/&part;&alpha;)(&part;&alpha;/&part;z<sub>1</sub>)(&part;z<sub>1</sub>/&part;w<sub>1</sub>)
> ✅ A regra da cadeia de diferenciação é usada para calcular as derivadas da função de perda em relação aos parâmetros.
Nota que a parte mais à esquerda de todas essas expressões é a mesma, e assim podemos calcular eficazmente as derivadas começando pela função de perda e indo "para trás" através do gráfico computacional. Assim, o método de treino de um perceptrão multicamadas é chamado **retropropagação**, ou 'backprop'.
<img alt="compute graph" src="../../../../../translated_images/pt-PT/ComputeGraphGrad.4626252c0de03507.webp"/>
> TODO: citação da imagem
> ✅ Vamos abordar a retropropagação com muito mais detalhe no nosso exemplo em notebook.
## Conclusão
Nesta aula, construímos a nossa própria biblioteca de redes neuronais e utilizámo-la para uma tarefa simples de classificação bidimensional.
## 🚀 Desafio
No notebook que acompanha, vais implementar o teu próprio framework para construir e treinar perceptrões multicamadas. Vais poder ver em detalhe como funcionam as redes neuronais modernas.
Segue para o notebook [OwnFramework](OwnFramework.ipynb) e trabalha nele.
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ai/quiz/8)
## Revisão e Estudo Autónomo
A retropropagação é um algoritmo comum usado em IA e ML, vale a pena estudar [em mais detalhe](https://wikipedia.org/wiki/Backpropagation)
## [Tarefa](lab/README.md)
Neste laboratório, és convidado a usar o framework que construíste nesta aula para resolver a classificação de dígitos manuscritos MNIST.
* [Instruções](lab/README.md)
* [Notebook](lab/MyFW_MNIST.ipynb)
---

View File

@ -0,0 +1,183 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Classificação de Dígitos MNIST com o nosso Próprio Framework\n",
"\n",
"Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).\n",
"\n",
"### Leitura do Conjunto de Dados\n",
"\n",
"Este código faz o download do conjunto de dados a partir do repositório na internet. Também pode copiar manualmente o conjunto de dados do diretório `/data` do repositório do Currículo de IA.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
" % Total % Received % Xferd Average Speed Time Time Time Current\n",
" Dload Upload Total Spent Left Speed\n",
"\n",
" 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\n",
"100 9.9M 100 9.9M 0 0 9.9M 0 0:00:01 --:--:-- 0:00:01 15.8M\n"
]
}
],
"source": [
"!rm *.pkl\n",
"!wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz\n",
"!gzip -d mnist.pkl.gz"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import pickle\n",
"with open('mnist.pkl','rb') as f:\n",
" MNIST = pickle.load(f)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"labels = MNIST['Train']['Labels']\n",
"data = MNIST['Train']['Features']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos ver qual é a forma dos dados que temos:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(42000, 784)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dividir os Dados\n",
"\n",
"Vamos usar o Scikit Learn para dividir os dados entre conjunto de treino e conjunto de teste:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train samples: 33600, test samples: 8400\n"
]
}
],
"source": [
"from sklearn.model_selection import train_test_split\n",
"\n",
"features_train, features_test, labels_train, labels_test = train_test_split(data,labels,test_size=0.2)\n",
"\n",
"print(f\"Train samples: {len(features_train)}, test samples: {len(features_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Instruções\n",
"\n",
"1. Pegue o código base do framework da lição e cole-o neste notebook ou (ainda melhor) num módulo Python separado.\n",
"1. Defina e treine um perceptron de uma camada, observando a precisão de treino e validação durante o processo.\n",
"1. Tente perceber se ocorreu overfitting e ajuste os parâmetros da camada para melhorar a precisão.\n",
"1. Repita os passos anteriores para perceptrons de 2 e 3 camadas. Experimente diferentes funções de ativação entre as camadas.\n",
"1. Tente responder às seguintes perguntas:\n",
" - A função de ativação entre as camadas afeta o desempenho da rede?\n",
" - Precisamos de uma rede de 2 ou 3 camadas para esta tarefa?\n",
" - Teve algum problema ao treinar a rede? Especialmente à medida que o número de camadas aumentou.\n",
" - Como se comportam os pesos da rede durante o treino? Pode traçar o valor absoluto máximo dos pesos em função da época para compreender a relação.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.7.4 64-bit (conda)",
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
}
},
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
},
"orig_nbformat": 2,
"coopTranslator": {
"original_hash": "6fa055f484eb5d6bdf41166a356d3abf",
"translation_date": "2025-08-31T11:49:51+00:00",
"source_file": "lessons/3-NeuralNetworks/04-OwnFramework/lab/MyFW_MNIST.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,23 @@
# Classificação MNIST com a Nossa Própria Framework
Trabalho prático do [Currículo de IA para Iniciantes](https://github.com/microsoft/ai-for-beginners).
## Tarefa
Resolver o problema de classificação de dígitos manuscritos do MNIST utilizando perceptrons com 1, 2 e 3 camadas. Use a framework de rede neural que desenvolvemos na aula.
## Notebook Inicial
Inicie o trabalho prático abrindo [MyFW_MNIST.ipynb](../../../../../../lessons/3-NeuralNetworks/04-OwnFramework/lab/MyFW_MNIST.ipynb)
## Perguntas
Como resultado deste trabalho prático, tente responder às seguintes perguntas:
- A função de ativação entre as camadas afeta o desempenho da rede?
- Precisamos de uma rede com 2 ou 3 camadas para esta tarefa?
- Teve algum problema ao treinar a rede? Especialmente à medida que o número de camadas aumentou.
- Como os pesos da rede se comportam durante o treino? Pode representar graficamente o valor absoluto máximo dos pesos em relação às épocas para entender a relação.
**Aviso Legal**:
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long