AI-For-Beginners/translations/pt-BR/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb

647 lines
26 KiB
Plaintext

{
"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
}