Embeddings

Embeddings Embeddings

Embeddingslink image 51

Em uma postagem anterior sobre tokens, já vimos a representação mínima de cada palavra. O que corresponde a atribuir um número à divisão mínima de cada palavra.

Entretanto, os transformadores e, portanto, os LLMs, não representam as informações das palavras dessa forma, mas o fazem por meio de "embeddings".

Este caderno foi traduzido automaticamente para torná-lo acessível a mais pessoas, por favor me avise se você vir algum erro de digitação..

Primeiramente, examinaremos duas formas de representar palavras, a "codificação ordinal" e a "codificação de um hot". E, analisando os problemas desses dois tipos de representações, poderemos chegar a word embeddings e sentence embeddings.

Também veremos um exemplo de como treinar um modelo de word embeddings com a biblioteca gensim.

E, por fim, veremos como usar modelos pré-treinados de embeddings com a biblioteca transformers do HuggingFace.

Codificação ordinallink image 52

Essa é a maneira mais básica de representar as palavras dentro dos transformadores. Ela consiste em atribuir um número a cada palavra ou manter os números já atribuídos aos tokens.

No entanto, esse tipo de representação tem dois problemas

  • Imaginemos que table corresponda ao token 3, cat ao token 1 e dog ao token 2. Poderíamos supor que table = cat + dog, mas esse não é o caso. Não existe essa relação entre essas palavras. Poderíamos até pensar que, atribuindo os tokens corretos, essa relação poderia ocorrer. No entanto, essa ideia não funciona com palavras que têm mais de um significado, como a palavra "banco".

  • O segundo problema é que as redes neurais fazem internamente muitos cálculos numéricos, portanto, pode ser que mesa tenha o token 3 e seja internamente mais importante do que a palavra cat que tem o token 1.

Portanto, esse tipo de representação de palavras pode ser descartado muito rapidamente.

Uma codificação quentelink image 53

O que você faz aqui é usar vetores de dimensão N. Por exemplo, vimos que o OpenAI tem um vocabulário de 100277 tokens distintos. Portanto, se usarmos "one hot encoding", cada palavra será representada por um vetor de "100277" dimensões.

No entanto, uma codificação quente tem dois outros problemas importantes.

  • Ele não leva em conta a relação entre as palavras. Portanto, se tivermos duas palavras que sejam sinônimas, por exemplo, cat e feline, teremos dois vetores diferentes para representá-las.

No idioma, a relação entre as palavras é muito importante, e não levar essa relação em conta é um grande problema.

  • O segundo problema é que os vetores são muito grandes. Se tivermos um vocabulário de 100277 tokens, cada palavra será representada por um vetor de 100277 dimensões. Isso torna os vetores muito grandes e os cálculos muito caros. Além disso, esses vetores serão todos zeros, exceto na posição correspondente ao token da palavra. Portanto, a maioria dos cálculos serão multiplicações por zero, que são cálculos que não somam nada. Portanto, teremos muita memória alocada para vetores em que só há um 1 em uma determinada posição.

Embeddings de palavraslink image 54

A incorporação de palavras é uma tentativa de resolver os problemas dos dois tipos anteriores de representação. Para isso, são usados vetores de N dimensões, mas, nesse caso, não são usados vetores de 100277 dimensões, e sim vetores de dimensões muito menores. Por exemplo, veremos que o OpenAI usa 1536 dimensões.

Cada uma das dimensões desses vetores representa uma característica da palavra. Por exemplo, uma dimensão pode representar se a palavra é um verbo ou um substantivo. Outra dimensão pode representar se a palavra é um animal ou não. Outra dimensão pode representar se a palavra é um substantivo próprio ou não. E assim por diante.

No entanto, esses recursos não são definidos manualmente, mas aprendidos automaticamente. Durante o treinamento dos transformadores, os valores de cada uma das dimensões dos vetores são ajustados, de modo que as características de cada uma das palavras sejam aprendidas.

Ao fazer com que cada uma das dimensões da palavra represente uma característica da palavra, as palavras que têm características semelhantes terão vetores semelhantes. Por exemplo, as palavras cat e feline terão vetores muito semelhantes, pois ambas são animais. E as palavras table e chair terão vetores semelhantes, pois ambas são móveis.

Na imagem a seguir, podemos ver uma representação tridimensional das palavras e podemos ver que todas as palavras relacionadas a school estão próximas, todas as palavras relacionadas a food estão próximas e todas as palavras relacionadas a ball estão próximas.

word_embedding_3_dimmension

Como cada uma das dimensões dos vetores representa uma característica da palavra, podemos realizar operações com palavras. Por exemplo, se subtrairmos a palavra "king" (rei) da palavra "man" (homem) e adicionarmos a palavra "woman" (mulher), obteremos uma palavra muito semelhante à palavra "queen" (rainha). Verificaremos isso mais tarde com um exemplo

Similaridade entre palavraslink image 55

Como cada palavra é representada por um vetor de N dimensões, podemos calcular a similaridade entre duas palavras. A função de similaridade de cosseno é usada para essa finalidade.

Se duas palavras estiverem próximas no espaço vetorial, isso significa que o ângulo entre seus vetores é pequeno, portanto, seu cosseno é próximo de 1. Se houver um ângulo de 90 graus entre os vetores, o cosseno será 0, o que significa que não há semelhança entre as palavras. E se houver um ângulo de 180 graus entre os vetores, o cosseno será -1, ou seja, as palavras são opostas.

cosine similarity

Exemplo com embeddings da OpenAIlink image 56

Agora que já sabemos o que são embeddings, vamos dar uma olhada em alguns exemplos com os embeddings fornecidos pela API OpenAI.

Para fazer isso, primeiro precisamos ter o pacote OpenAI instalado.

pip install openai
      ```
      

Importamos as bibliotecas necessárias

	
from openai import OpenAI
import torch
from torch.nn.functional import cosine_similarity
Copy

Usamos uma "chave API" da OpenAI. Para fazer isso, vá para a página [OpenAI] (https://openai.com/) e registre-se. Depois de registrado, vá para a seção API Keys e crie uma nova API Key.

open ai api key

	
from openai import OpenAI
import torch
from torch.nn.functional import cosine_similarity
api_key = "Pon aquí tu API key"
Copy

Selecionamos o modelo de embeddings que queremos usar. Nesse caso, usaremos o text-embedding-ada-002, que é recomendado pela OpenAI em sua documentação [embeddings] (https://platform.openai.com/docs/guides/embeddings/).

	
from openai import OpenAI
import torch
from torch.nn.functional import cosine_similarity
api_key = "Pon aquí tu API key"
model_openai = "text-embedding-ada-002"
Copy

Criar um cliente `API

	
from openai import OpenAI
import torch
from torch.nn.functional import cosine_similarity
api_key = "Pon aquí tu API key"
model_openai = "text-embedding-ada-002"
client_openai = OpenAI(api_key=api_key, organization=None)
Copy

Vamos ver como são os embeddings da palavra King.

	
from openai import OpenAI
import torch
from torch.nn.functional import cosine_similarity
api_key = "Pon aquí tu API key"
model_openai = "text-embedding-ada-002"
client_openai = OpenAI(api_key=api_key, organization=None)
word = "Rey"
embedding_openai = torch.Tensor(client_openai.embeddings.create(input=word, model=model_openai).data[0].embedding)
embedding_openai.shape, embedding_openai
Copy
	
(torch.Size([1536]),
tensor([-0.0103, -0.0005, -0.0189, ..., -0.0009, -0.0226, 0.0045]))

Como podemos ver, obtemos um vetor de 1536 dimensões.

Operações com palavraslink image 57

Vamos obter os embeddings das palavras king, man, woman e queen.

	
embedding_openai_rey = torch.Tensor(client_openai.embeddings.create(input="rey", model=model_openai).data[0].embedding)
embedding_openai_hombre = torch.Tensor(client_openai.embeddings.create(input="hombre", model=model_openai).data[0].embedding)
embedding_openai_mujer = torch.Tensor(client_openai.embeddings.create(input="mujer", model=model_openai).data[0].embedding)
embedding_openai_reina = torch.Tensor(client_openai.embeddings.create(input="reina", model=model_openai).data[0].embedding)
Copy
	
embedding_openai_rey = torch.Tensor(client_openai.embeddings.create(input="rey", model=model_openai).data[0].embedding)
embedding_openai_hombre = torch.Tensor(client_openai.embeddings.create(input="hombre", model=model_openai).data[0].embedding)
embedding_openai_mujer = torch.Tensor(client_openai.embeddings.create(input="mujer", model=model_openai).data[0].embedding)
embedding_openai_reina = torch.Tensor(client_openai.embeddings.create(input="reina", model=model_openai).data[0].embedding)
embedding_openai_reina.shape, embedding_openai_reina
Copy
	
(torch.Size([1536]),
tensor([-0.0110, -0.0084, -0.0115, ..., 0.0082, -0.0096, -0.0024]))

Vamos obter a incorporação resultante da subtração da incorporação de "homem" de "rei" e da adição da incorporação de "mulher" a "rei".

	
embedding_openai = embedding_openai_rey - embedding_openai_hombre + embedding_openai_mujer
Copy
	
embedding_openai = embedding_openai_rey - embedding_openai_hombre + embedding_openai_mujer
embedding_openai.shape, embedding_openai
Copy
	
(torch.Size([1536]),
tensor([-0.0226, -0.0323, 0.0017, ..., 0.0014, -0.0290, -0.0188]))

Por fim, comparamos o resultado obtido com a incorporação da reina. Para isso, usamos a função cosine_similarity fornecida pela biblioteca pytorch.

	
similarity_openai = cosine_similarity(embedding_openai.unsqueeze(0), embedding_openai_reina.unsqueeze(0)).item()
print(f"similarity_openai: {similarity_openai}")
Copy
	
similarity_openai: 0.7564167976379395

Como podemos ver, é um valor muito próximo de 1, portanto, podemos dizer que o resultado obtido é muito semelhante à incorporação da reina.

Se usarmos palavras em inglês, obteremos um resultado mais próximo de 1.

	
embedding_openai_rey = torch.Tensor(client_openai.embeddings.create(input="king", model=model_openai).data[0].embedding)
embedding_openai_hombre = torch.Tensor(client_openai.embeddings.create(input="man", model=model_openai).data[0].embedding)
embedding_openai_mujer = torch.Tensor(client_openai.embeddings.create(input="woman", model=model_openai).data[0].embedding)
embedding_openai_reina = torch.Tensor(client_openai.embeddings.create(input="queen", model=model_openai).data[0].embedding)
Copy
	
embedding_openai_rey = torch.Tensor(client_openai.embeddings.create(input="king", model=model_openai).data[0].embedding)
embedding_openai_hombre = torch.Tensor(client_openai.embeddings.create(input="man", model=model_openai).data[0].embedding)
embedding_openai_mujer = torch.Tensor(client_openai.embeddings.create(input="woman", model=model_openai).data[0].embedding)
embedding_openai_reina = torch.Tensor(client_openai.embeddings.create(input="queen", model=model_openai).data[0].embedding)
embedding_openai = embedding_openai_rey - embedding_openai_hombre + embedding_openai_mujer
Copy
	
embedding_openai_rey = torch.Tensor(client_openai.embeddings.create(input="king", model=model_openai).data[0].embedding)
embedding_openai_hombre = torch.Tensor(client_openai.embeddings.create(input="man", model=model_openai).data[0].embedding)
embedding_openai_mujer = torch.Tensor(client_openai.embeddings.create(input="woman", model=model_openai).data[0].embedding)
embedding_openai_reina = torch.Tensor(client_openai.embeddings.create(input="queen", model=model_openai).data[0].embedding)
embedding_openai = embedding_openai_rey - embedding_openai_hombre + embedding_openai_mujer
similarity_openai = cosine_similarity(embedding_openai.unsqueeze(0), embedding_openai_reina.unsqueeze(0))
print(f"similarity_openai: {similarity_openai}")
Copy
	
similarity_openai: tensor([0.8849])

Isso é normal, pois o modelo OpenAi foi treinado com mais textos em inglês do que em espanhol.

Tipos de incorporação de palavraslink image 58

Há vários tipos de word embeddings, e cada um deles tem suas vantagens e desvantagens. Vamos dar uma olhada nos mais importantes

  • Word2Vec
  • GloVe
  • FastText
  • BERT
  • GPT-2

Word2Veclink image 59

O Word2Vec é um algoritmo usado para criar embeddings de palavras. Esse algoritmo foi criado pelo Google em 2013 e é um dos algoritmos mais usados para criar word embeddings.

Ele tem duas variantes, CBOW e Skip-gram. O CBOW é mais rápido de treinar, enquanto o Skip-gram é mais preciso. Vamos dar uma olhada em como cada um funciona

CBOWlink image 60

CBOW ou Continuous Bag of Words é um algoritmo usado para prever uma palavra a partir das palavras ao redor. Por exemplo, se tivermos a frase O gato é um animal, o algoritmo tentará prever a palavra gato a partir das palavras ao redor, nesse caso O, é, um e animal.

CBOW

Nessa arquitetura, o modelo prevê qual é a palavra mais provável em um determinado contexto. Portanto, as palavras que têm a mesma probabilidade de ocorrência são consideradas semelhantes e, portanto, estão mais próximas no espaço dimensional.

Suponha que, em uma frase, substituamos boat por boat, então o modelo prevê a probabilidade de ambos e, se for semelhante, podemos considerar que as palavras são semelhantes.

Skip-gramlink image 61

O Skip-gram ou Skip-gram with Negative Sampling é um algoritmo usado para prever as palavras ao redor de uma palavra. Por exemplo, se tivermos a frase O gato é um animal, o algoritmo tentará prever as palavras O, é, um e animal a partir da palavra gato.

Skip-gram](https://pub-fb664c455eca46a2ba762a065ac900f7.r2.dev/Skip-gram.webp)

Essa arquitetura é semelhante à do CBOW, mas o modelo funciona de forma inversa. O modelo prevê o contexto usando a palavra dada. Portanto, as palavras que têm o mesmo contexto são consideradas semelhantes e, portanto, estão mais próximas no espaço dimensional.

GloVelink image 62

GloVeouGlobal Vectors for Word Representation` é um algoritmo usado para criar embeddings de palavras. Esse algoritmo foi criado pela Universidade de Stanford em 2014.

O Word2Vec ignora o fato de que algumas palavras de contexto ocorrem com mais frequência do que outras e também leva em conta apenas o contexto local e, portanto, não captura o contexto global.

Esse algoritmo usa uma matriz de co-ocorrência para criar os embeddings de palavras. Essa matriz de co-ocorrência é uma matriz que contém o número de vezes que cada palavra aparece ao lado de cada uma das outras palavras do vocabulário.

FastTextlink image 63

O FastText é um algoritmo usado para criar incorporação de palavras. Esse algoritmo foi criado pelo Facebook em 2016.

Uma das principais desvantagens do Word2Vec e do GloVe é que eles não podem codificar palavras desconhecidas ou fora do vocabulário.

Portanto, para lidar com esse problema, o Facebook propôs um modelo FastText. Ele é uma extensão do Word2Vec e segue o mesmo modelo Skip-gram e CBOW, mas, ao contrário do Word2Vec, que alimenta a rede neural com palavras inteiras, o FastText primeiro divide as palavras em várias subpalavras (ou n-gramas) e depois as alimenta na rede neural.

Por exemplo, se o valor de n for 3 e a palavra for apple, então seu tri-grama será [<ma, man, anz, nza, zan, ana, na>] e sua incorporação de palavras será a soma da representação vetorial desses tri-gramas. Aqui, os hiperparâmetros min_n e max_n são considerados como 3 e os caracteres < e > representam o início e o fim da palavra.

Portanto, usando essa metodologia, as palavras desconhecidas podem ser representadas em forma de vetor, pois há uma alta probabilidade de que seus n-gramas também estejam presentes em outras palavras.

Esse algoritmo é um aprimoramento do Word2Vec, pois, além de levar em conta as palavras ao redor de uma palavra, ele também leva em conta os n-gramas da palavra. Por exemplo, se tivermos a palavra cat, ele também leva em conta os n-gramas da palavra, nesse caso ga, at e to, para n = 2.

Limitações da incorporação de palavraslink image 64

As técnicas de incorporação de palavras produziram um resultado decente, mas o problema é que a abordagem não é suficientemente precisa. Elas não levam em conta a ordem em que as palavras aparecem, o que leva à perda da compreensão sintática e semântica da frase.

Por exemplo, Você vai lá para ensinar, não para brincar E Você vai lá para brincar, não para ensinar Ambas as frases terão a mesma representação no espaço vetorial, mas não significam a mesma coisa.

Além disso, o modelo de incorporação de palavras não pode fornecer resultados satisfatórios em uma grande quantidade de dados de texto, pois a mesma palavra pode ter um significado diferente em uma frase diferente, dependendo do contexto da frase.

Por exemplo, I am going to sit in the bank E I am going to do business in the bank Em ambas as frases, a palavra bank tem significados diferentes.

Portanto, precisamos de um tipo de representação que possa reter o significado contextual da palavra presente em uma frase.

Embeddings de fraseslink image 65

A incorporação de frases é semelhante à incorporação de palavras, mas, em vez de palavras, ela codifica a frase inteira na representação vetorial.

Uma maneira simples de obter a incorporação de frases é calcular a média das incorporações de palavras de todas as palavras presentes na frase. Mas isso não é suficientemente preciso.

Alguns dos modelos mais avançados de incorporação de frases são o ELMo, o InferSent e o Sentence-BERT.

ELMolink image 66

ELMoouEmbeddings from Language Modelsé um modelo de incorporação de frases criado pela Allen University em 2018. Ele usa uma rede LSTM profunda bidirecional para produzir representação vetorial. OELMo` pode representar palavras desconhecidas ou fora do vocabulário em forma de vetor, pois é baseado em caracteres.

InferSentlink image 67

O InferSent é um modelo de incorporação de frases criado pelo Facebook em 2017. Ele usa uma rede LSTM profunda bidirecional para produzir representação vetorial. O InferSent pode representar palavras desconhecidas ou fora do vocabulário em forma de vetor, pois é baseado em caracteres. As frases são codificadas em uma representação vetorial de 4096 dimensões.

O treinamento do modelo é feito com o conjunto de dados Stanford Natural Language Inference (SNLI). Esse conjunto de dados é rotulado e escrito por humanos para cerca de 500 mil pares de frases.

Sentença-BERTlink image 68

O Sentence-BERT é um modelo de incorporação de frases criado pela Universidade de Londres em 2019. Ele usa uma rede LSTM profunda bidirecional para produzir representação vetorial. O Sentence-BERT pode representar palavras desconhecidas ou fora do vocabulário na forma vetorial, pois é baseado em caracteres. As frases são codificadas em uma representação vetorial de 768 dimensões.

O modelo de PNL de última geração BERT é excelente em tarefas de Semantic Textual Similarity, mas o problema é que ele levaria muito tempo para um corpus enorme (65 horas para 10.000 frases), pois exige que ambas as frases sejam inseridas na rede, o que aumenta o cálculo em um fator enorme.

Portanto, o Sentence-BERT é uma modificação do modelo BERT.

Treinamento de um modelo word2vec com gensimlink image 69

Para fazer o download do conjunto de dados que vamos usar, precisamos instalar a biblioteca dataset da huggingface:

pip install datasets
      

Para treinar o modelo de embeddings, usaremos a biblioteca gensim. Para instalá-la com o conda, usamos

conda install -c conda-forge gensim
      

E para instalá-lo com o pip, usamos

pip install gensim
      

Para limpar o conjunto de dados que baixamos, usaremos expressões regulares, que normalmente já estão instaladas no python, e nltk, que é uma biblioteca de processamento de linguagem natural. Para instalá-la com o conda, usamos

conda install -c anaconda nltk
      

E para instalá-lo com o pip, usamos

pip install nltk
      

Agora que temos tudo instalado, podemos importar as bibliotecas que usaremos:

	
from gensim.models import Word2Vec
from gensim.parsing.preprocessing import strip_punctuation, strip_numeric, strip_short
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
Copy

Download do conjunto de dadoslink image 70

Vamos fazer o download de um conjunto de dados de textos da Wikipédia em espanhol, para isso executamos o seguinte:

	
from gensim.models import Word2Vec
from gensim.parsing.preprocessing import strip_punctuation, strip_numeric, strip_short
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from datasets import load_dataset
dataset_corpus = load_dataset('large_spanish_corpus', name='all_wikis')
Copy

Vamos ver como é

	
from gensim.models import Word2Vec
from gensim.parsing.preprocessing import strip_punctuation, strip_numeric, strip_short
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from datasets import load_dataset
dataset_corpus = load_dataset('large_spanish_corpus', name='all_wikis')
dataset_corpus
Copy
	
DatasetDict({
train: Dataset({
features: ['text'],
num_rows: 28109484
})
})

Como podemos ver, o conjunto de dados tem mais de 28 milhões de textos. Vamos dar uma olhada em alguns deles:

	
dataset_corpus['train']['text'][0:10]
Copy
	
['¡Bienvenidos!',
'Ir a los contenidos»',
'= Contenidos =',
'',
'Portada',
'Tercera Lengua más hablada en el mundo.',
'La segunda en número de habitantes en el mundo occidental.',
'La de mayor proyección y crecimiento día a día.',
'El español es, hoy en día, nombrado en cada vez más contextos, tomando realce internacional como lengua de cultura y civilización siempre de mayor envergadura.',
'Ejemplo de ello es que la comunidad minoritaria más hablada en los Estados Unidos es precisamente la que habla idioma español.']

Como há muitos exemplos, criaremos um subconjunto de 10 milhões de exemplos para trabalhar mais rapidamente:

	
subset = dataset_corpus['train'].select(range(10000000))
Copy

Limpeza do conjunto de dadoslink image 71

Agora, baixamos as stopwords do nltk, que são palavras que não fornecem informações e que serão removidas dos textos.

import nltk
      nltk.download('stopwords')
      
[nltk_data] Downloading package stopwords to
      [nltk_data]     /home/wallabot/nltk_data...
      [nltk_data]   Package stopwords is already up-to-date!
      
True

Agora vamos fazer o download do punkt do nltk, que é um tokenizer que nos permitirá separar os textos em sentenças.

nltk.download('punkt')
      
[nltk_data] Downloading package punkt to /home/wallabot/nltk_data...
      [nltk_data]   Package punkt is already up-to-date!
      
True

Criamos uma função para limpar os dados, essa função vai:

  • Alterar o texto para letras minúsculas
  • Remover urls

Remover menções de redes sociais, como @twitter ou #hashtag * Remover menções de redes sociais, como @twitter ou #hashtag.

  • Remover sinais de pontuação
  • Eliminar os números
  • Eliminar palavras curtas
  • Eliminar palavras de parada

Como estamos usando um conjunto de dados huggeface, os textos estão no formato dict, portanto, retornamos um dicionário.

	
subset = dataset_corpus['train'].select(range(10000000))
import nltk
nltk.download('stopwords')
nltk.download('punkt')
def clean_text(sentence_batch):
# extrae el texto de la entrada
text_list = sentence_batch['text']
cleaned_text_list = []
for text in text_list:
# Convierte el texto a minúsculas
text = text.lower()
# Elimina URLs
text = re.sub(r'httpS+|wwwS+|httpsS+', '', text, flags=re.MULTILINE)
# Elimina las menciones @ y '#' de las redes sociales
text = re.sub(r'@w+|#w+', '', text)
# Elimina los caracteres de puntuación
text = strip_punctuation(text)
# Elimina los números
text = strip_numeric(text)
# Elimina las palabras cortas
text = strip_short(text,minsize=2)
# Elimina las palabras comunes (stop words)
stop_words = set(stopwords.words('spanish'))
word_tokens = word_tokenize(text)
filtered_text = [word for word in word_tokens if word not in stop_words]
cleaned_text_list.append(filtered_text)
# Devuelve el texto limpio
return {'text': cleaned_text_list}
Copy

Aplicamos a função aos dados

	
subset = dataset_corpus['train'].select(range(10000000))
import nltk
nltk.download('stopwords')
nltk.download('punkt')
def clean_text(sentence_batch):
# extrae el texto de la entrada
text_list = sentence_batch['text']
cleaned_text_list = []
for text in text_list:
# Convierte el texto a minúsculas
text = text.lower()
# Elimina URLs
text = re.sub(r'httpS+|wwwS+|httpsS+', '', text, flags=re.MULTILINE)
# Elimina las menciones @ y '#' de las redes sociales
text = re.sub(r'@w+|#w+', '', text)
# Elimina los caracteres de puntuación
text = strip_punctuation(text)
# Elimina los números
text = strip_numeric(text)
# Elimina las palabras cortas
text = strip_short(text,minsize=2)
# Elimina las palabras comunes (stop words)
stop_words = set(stopwords.words('spanish'))
word_tokens = word_tokenize(text)
filtered_text = [word for word in word_tokens if word not in stop_words]
cleaned_text_list.append(filtered_text)
# Devuelve el texto limpio
return {'text': cleaned_text_list}
sentences_corpus = subset.map(clean_text, batched=True)
Copy
	
[nltk_data] Downloading package stopwords to
[nltk_data] /home/wallabot/nltk_data...
[nltk_data] Package stopwords is already up-to-date!
[nltk_data] Downloading package punkt to /home/wallabot/nltk_data...
[nltk_data] Package punkt is already up-to-date!
Map: 0%| | 0/10000000 [00:00<?, ? examples/s]

Salvaremos o conjunto de dados filtrado em um arquivo para que não seja necessário executar o processo de limpeza novamente.

	
sentences_corpus.save_to_disk("sentences_corpus")
Copy
	
Saving the dataset (0/4 shards): 0%| | 0/15000000 [00:00<?, ? examples/s]

Para carregá-lo, podemos fazer o seguinte

	
from datasets import load_from_disk
sentences_corpus = load_from_disk('sentences_corpus')
Copy

Agora, o que teremos é uma lista de listas, em que cada lista é uma frase tokenizada sem stopwords. Ou seja, temos uma lista de frases, e cada frase é uma lista de palavras. Vamos ver como isso se parece:

	
from datasets import load_from_disk
sentences_corpus = load_from_disk('sentences_corpus')
for i in range(10):
print(f'La frase "{subset["text"][i]}" se convierte en la lista de palabras "{sentences_corpus["text"][i]}"')
Copy
	
La frase "¡Bienvenidos!" se convierte en la lista de palabras "['¡bienvenidos']"
La frase "Ir a los contenidos»" se convierte en la lista de palabras "['ir', 'contenidos', '»']"
La frase "= Contenidos =" se convierte en la lista de palabras "['contenidos']"
La frase "" se convierte en la lista de palabras "[]"
La frase "Portada" se convierte en la lista de palabras "['portada']"
La frase "Tercera Lengua más hablada en el mundo." se convierte en la lista de palabras "['tercera', 'lengua', 'hablada', 'mundo']"
La frase "La segunda en número de habitantes en el mundo occidental." se convierte en la lista de palabras "['segunda', 'número', 'habitantes', 'mundo', 'occidental']"
La frase "La de mayor proyección y crecimiento día a día." se convierte en la lista de palabras "['mayor', 'proyección', 'crecimiento', 'día', 'día']"
La frase "El español es, hoy en día, nombrado en cada vez más contextos, tomando realce internacional como lengua de cultura y civilización siempre de mayor envergadura." se convierte en la lista de palabras "['español', 'hoy', 'día', 'nombrado', 'cada', 'vez', 'contextos', 'tomando', 'realce', 'internacional', 'lengua', 'cultura', 'civilización', 'siempre', 'mayor', 'envergadura']"
La frase "Ejemplo de ello es que la comunidad minoritaria más hablada en los Estados Unidos es precisamente la que habla idioma español." se convierte en la lista de palabras "['ejemplo', 'ello', 'comunidad', 'minoritaria', 'hablada', 'unidos', 'precisamente', 'habla', 'idioma', 'español']"

Treinamento do modelo word2veclink image 72

Vamos treinar um modelo de embeddings que converterá palavras em vetores. Para isso, usaremos a biblioteca gensim e seu modelo Word2Vec.

	
dataset = sentences_corpus['text']
dim_embedding = 100
window_size = 5 # 5 palabras a la izquierda y 5 palabras a la derecha
min_count = 5 # Ignora las palabras con frecuencia menor a 5
workers = 4 # Número de hilos de ejecución
sg = 1 # 0 para CBOW, 1 para Skip-gram
model = Word2Vec(dataset, vector_size=dim_embedding, window=window_size, min_count=min_count, workers=workers, sg=sg)
Copy

Esse modelo foi treinado na CPU, pois o gensim não tem a opção de treinar na GPU e, mesmo assim, em meu computador, foram necessários X minutos para treinar o modelo. Embora o tamanho da incorporação que escolhemos seja de apenas 100 (ao contrário do tamanho da incorporação do openai, que é de 1536), não é um tempo muito longo, pois o conjunto de dados tem 10 milhões de frases.

Os modelos de linguagem grandes são treinados com conjuntos de dados de bilhões de frases, portanto, é normal que o treinamento de um modelo de embeddings com um conjunto de dados de 10 milhões de frases leve alguns minutos.

Depois que o modelo foi treinado, nós o salvamos em um arquivo para uso futuro.

	
dataset = sentences_corpus['text']
dim_embedding = 100
window_size = 5 # 5 palabras a la izquierda y 5 palabras a la derecha
min_count = 5 # Ignora las palabras con frecuencia menor a 5
workers = 4 # Número de hilos de ejecución
sg = 1 # 0 para CBOW, 1 para Skip-gram
model = Word2Vec(dataset, vector_size=dim_embedding, window=window_size, min_count=min_count, workers=workers, sg=sg)
model.save('word2vec.model')
Copy

Se quisermos fazer o upload no futuro, podemos fazer isso com

	
dataset = sentences_corpus['text']
dim_embedding = 100
window_size = 5 # 5 palabras a la izquierda y 5 palabras a la derecha
min_count = 5 # Ignora las palabras con frecuencia menor a 5
workers = 4 # Número de hilos de ejecución
sg = 1 # 0 para CBOW, 1 para Skip-gram
model = Word2Vec(dataset, vector_size=dim_embedding, window=window_size, min_count=min_count, workers=workers, sg=sg)
model.save('word2vec.model')
model = Word2Vec.load('word2vec.model')
Copy

Avaliação do modelo word2veclink image 73

Vamos dar uma olhada nas palavras mais semelhantes de algumas palavras

	
dataset = sentences_corpus['text']
dim_embedding = 100
window_size = 5 # 5 palabras a la izquierda y 5 palabras a la derecha
min_count = 5 # Ignora las palabras con frecuencia menor a 5
workers = 4 # Número de hilos de ejecución
sg = 1 # 0 para CBOW, 1 para Skip-gram
model = Word2Vec(dataset, vector_size=dim_embedding, window=window_size, min_count=min_count, workers=workers, sg=sg)
model.save('word2vec.model')
model = Word2Vec.load('word2vec.model')
model.wv.most_similar('perro', topn=10)
Copy
	
[('gato', 0.7948548197746277),
('perros', 0.77247554063797),
('cachorro', 0.7638891339302063),
('hámster', 0.7540281414985657),
('caniche', 0.7514827251434326),
('bobtail', 0.7492328882217407),
('mastín', 0.7491254210472107),
('lobo', 0.7312178611755371),
('semental', 0.7292628288269043),
('sabueso', 0.7290207147598267)]
	
model.wv.most_similar('gato', topn=10)
Copy
	
[('conejo', 0.8148329854011536),
('zorro', 0.8109457492828369),
('perro', 0.7948548793792725),
('lobo', 0.7878773808479309),
('ardilla', 0.7860757112503052),
('mapache', 0.7817519307136536),
('huiña', 0.766639232635498),
('oso', 0.7656188011169434),
('mono', 0.7633568644523621),
('camaleón', 0.7623056769371033)]

Vejamos agora o exemplo em que verificamos a semelhança da palavra "queen" com o resultado da subtração da palavra "man" (homem) da palavra "king" (rei) e da adição da palavra "woman" (mulher).

	
embedding_hombre = model.wv['hombre']
embedding_mujer = model.wv['mujer']
embedding_rey = model.wv['rey']
embedding_reina = model.wv['reina']
Copy
	
embedding_hombre = model.wv['hombre']
embedding_mujer = model.wv['mujer']
embedding_rey = model.wv['rey']
embedding_reina = model.wv['reina']
embedding = embedding_rey - embedding_hombre + embedding_mujer
Copy
	
embedding_hombre = model.wv['hombre']
embedding_mujer = model.wv['mujer']
embedding_rey = model.wv['rey']
embedding_reina = model.wv['reina']
embedding = embedding_rey - embedding_hombre + embedding_mujer
from torch.nn.functional import cosine_similarity
embedding = torch.tensor(embedding).unsqueeze(0)
embedding_reina = torch.tensor(embedding_reina).unsqueeze(0)
similarity = cosine_similarity(embedding, embedding_reina, dim=1)
similarity
Copy
	
tensor([0.8156])

Como podemos ver, há muitas semelhanças

Exibição de incorporaçõeslink image 74

Vamos visualizar os embeddings. Para isso, primeiro obtemos os vetores e as palavras do modelo.

	
embeddings = model.wv.vectors
words = list(model.wv.index_to_key)
Copy

Como a dimensão dos embeddings é 100, para exibi-los em 2 ou 3 dimensões, temos que reduzir a dimensão. Para isso, usaremos o PCA (mais rápido) ou o TSNE (mais preciso) do sklearn.

	
embeddings = model.wv.vectors
words = list(model.wv.index_to_key)
from sklearn.decomposition import PCA
dimmesions = 2
pca = PCA(n_components=dimmesions)
reduced_embeddings_PCA = pca.fit_transform(embeddings)
Copy
	
embeddings = model.wv.vectors
words = list(model.wv.index_to_key)
from sklearn.decomposition import PCA
dimmesions = 2
pca = PCA(n_components=dimmesions)
reduced_embeddings_PCA = pca.fit_transform(embeddings)
from sklearn.manifold import TSNE
dimmesions = 2
tsne = TSNE(n_components=dimmesions, verbose=1, perplexity=40, n_iter=300)
reduced_embeddings_tsne = tsne.fit_transform(embeddings)
Copy
	
[t-SNE] Computing 121 nearest neighbors...
[t-SNE] Indexed 493923 samples in 0.013s...
[t-SNE] Computed neighbors for 493923 samples in 377.143s...
[t-SNE] Computed conditional probabilities for sample 1000 / 493923
[t-SNE] Computed conditional probabilities for sample 2000 / 493923
[t-SNE] Computed conditional probabilities for sample 3000 / 493923
[t-SNE] Computed conditional probabilities for sample 4000 / 493923
[t-SNE] Computed conditional probabilities for sample 5000 / 493923
[t-SNE] Computed conditional probabilities for sample 6000 / 493923
[t-SNE] Computed conditional probabilities for sample 7000 / 493923
[t-SNE] Computed conditional probabilities for sample 8000 / 493923
[t-SNE] Computed conditional probabilities for sample 9000 / 493923
[t-SNE] Computed conditional probabilities for sample 10000 / 493923
[t-SNE] Computed conditional probabilities for sample 11000 / 493923
[t-SNE] Computed conditional probabilities for sample 12000 / 493923
[t-SNE] Computed conditional probabilities for sample 13000 / 493923
[t-SNE] Computed conditional probabilities for sample 14000 / 493923
[t-SNE] Computed conditional probabilities for sample 15000 / 493923
[t-SNE] Computed conditional probabilities for sample 16000 / 493923
[t-SNE] Computed conditional probabilities for sample 17000 / 493923
[t-SNE] Computed conditional probabilities for sample 18000 / 493923
[t-SNE] Computed conditional probabilities for sample 19000 / 493923
[t-SNE] Computed conditional probabilities for sample 20000 / 493923
[t-SNE] Computed conditional probabilities for sample 21000 / 493923
[t-SNE] Computed conditional probabilities for sample 22000 / 493923
...
[t-SNE] Computed conditional probabilities for sample 493923 / 493923
[t-SNE] Mean sigma: 0.275311
[t-SNE] KL divergence after 250 iterations with early exaggeration: 117.413788
[t-SNE] KL divergence after 300 iterations: 5.774648

Agora vamos visualizá-los em duas dimensões com o matplotlib. Vamos visualizar a redução de dimensionalidade que fizemos com PCA e com TSNE.

import matplotlib.pyplot as plt
      
      plt.figure(figsize=(10, 10))
      for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
          plt.scatter(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1])
          plt.annotate(word, xy=(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')
      plt.title('Embeddings (PCA)')
      plt.show()
      
image embeddings 1
plt.figure(figsize=(10, 10))
      for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
          plt.scatter(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1])
          plt.annotate(word, xy=(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1]), xytext=(5, 2),
                       textcoords='offset points', ha='right', va='bottom')
      plt.show()
      
image embeddings 2

Uso de modelos pré-treinados com huggingfacelink image 75

Para usar modelos embeddings pré-treinados, usaremos a biblioteca transformers da huggingface. Para instalá-la com o conda, usamos

conda install -c conda-forge transformers
      

E para instalá-lo com o pip, usamos

pip install transformers
      

Com a tarefa feature-extraction do huggingface, podemos usar modelos pré-treinados para obter os embeddings das palavras. Para fazer isso, primeiro importamos a biblioteca necessária

	
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1])
plt.annotate(word, xy=(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')
plt.title('Embeddings (PCA)')
plt.show()
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1])
plt.annotate(word, xy=(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1]), xytext=(5, 2),
textcoords='offset points', ha='right', va='bottom')
plt.show()
from transformers import pipeline
Copy

Vamos obter os embeddings do BERT.

	
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1])
plt.annotate(word, xy=(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')
plt.title('Embeddings (PCA)')
plt.show()
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1])
plt.annotate(word, xy=(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1]), xytext=(5, 2),
textcoords='offset points', ha='right', va='bottom')
plt.show()
from transformers import pipeline
checkpoint = "bert-base-uncased"
feature_extractor = pipeline("feature-extraction",framework="pt",model=checkpoint)
Copy

Vamos dar uma olhada nos embeddings da palavra king.

	
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1])
plt.annotate(word, xy=(reduced_embeddings_PCA[i, 0], reduced_embeddings_PCA[i, 1]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom')
plt.title('Embeddings (PCA)')
plt.show()
plt.figure(figsize=(10, 10))
for i, word in enumerate(words[:200]): # Limitar a las primeras 200 palabras
plt.scatter(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1])
plt.annotate(word, xy=(reduced_embeddings_tsne[i, 0], reduced_embeddings_tsne[i, 1]), xytext=(5, 2),
textcoords='offset points', ha='right', va='bottom')
plt.show()
from transformers import pipeline
checkpoint = "bert-base-uncased"
feature_extractor = pipeline("feature-extraction",framework="pt",model=checkpoint)
embedding = feature_extractor("rey", return_tensors="pt").squeeze(0)
embedding.shape
Copy
	
torch.Size([3, 768])

Como podemos ver, obtemos um vetor de 768 dimensões, ou seja, os embeddings do BERT têm 768 dimensões. Por outro lado, vemos que ele tem 3 vetores de embeddings, isso porque o BERT adiciona um token no início e outro no final da frase, portanto, estamos interessados apenas no vetor do meio.

Vamos refazer o exemplo em que verificamos a semelhança da palavra "rainha" com o resultado da subtração da palavra "homem" da palavra "rei" e da adição da palavra "mulher" à palavra "rei".

	
embedding_hombre = feature_extractor("man", return_tensors="pt").squeeze(0)[1]
embedding_mujer = feature_extractor("woman", return_tensors="pt").squeeze(0)[1]
embedding_rey = feature_extractor("king", return_tensors="pt").squeeze(0)[1]
embedding_reina = feature_extractor("queen", return_tensors="pt").squeeze(0)[1]
Copy
	
embedding_hombre = feature_extractor("man", return_tensors="pt").squeeze(0)[1]
embedding_mujer = feature_extractor("woman", return_tensors="pt").squeeze(0)[1]
embedding_rey = feature_extractor("king", return_tensors="pt").squeeze(0)[1]
embedding_reina = feature_extractor("queen", return_tensors="pt").squeeze(0)[1]
embedding = embedding_rey - embedding_hombre + embedding_mujer
Copy

Vamos dar uma olhada na semelhança

import torch
      from torch.nn.functional import cosine_similarity
      
      embedding = torch.tensor(embedding).unsqueeze(0)
      embedding_reina = torch.tensor(embedding_reina).unsqueeze(0)
      
      similarity = cosine_similarity(embedding, embedding_reina, dim=1)
      similarity.item()
      
/tmp/ipykernel_33343/4248442045.py:4: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
        embedding = torch.tensor(embedding).unsqueeze(0)
      /tmp/ipykernel_33343/4248442045.py:5: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
        embedding_reina = torch.tensor(embedding_reina).unsqueeze(0)
      
Out[60]:
0.742547333240509

Usando os embeddings do BERT, também obtemos um resultado muito próximo de 1.

Continuar lendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

Você já conversou com um LLM e ele lhe respondeu algo que parece ter bebido café de máquina a noite toda? 😂 Isso é o que chamamos de alucinação no mundo dos LLMs! Mas não se preocupe, pois não é que seu modelo de linguagem esteja louco (embora às vezes possa parecer isso 🤪). A verdade é que os LLMs podem ser um pouco... criativos quando se trata de gerar texto. Mas graças ao DoLa, um método que usa camadas de contraste para melhorar a viabilidade dos LLMs, podemos evitar que nossos modelos de linguagem se transformem em escritores de ficção científica 😂. Nesta publicação, explicarei como o DoLa funciona e mostrarei um exemplo de código para que você possa entender melhor como tornar seus LLMs mais confiáveis e menos propensos a inventar histórias. Vamos salvar nossos LLMs da loucura e torná-los mais úteis! 🚀

Últimos posts -->

Você viu esses projetos?

Subtify

Subtify Subtify

Gerador de legendas para vídeos no idioma que você desejar. Além disso, coloca uma legenda de cor diferente para cada pessoa

Ver todos os projetos -->

Quer aplicar IA no seu projeto? Entre em contato!

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Ver todos os contêineres -->

Quer aplicar IA no seu projeto? Entre em contato!

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

Dataset com piadas em inglês

opus100

Dataset com traduções de inglês para espanhol

netflix_titles

Dataset com filmes e séries da Netflix

Ver mais datasets -->