Machine Learning · Insper

Representação de Texto

De strings a vetores

Tokens, o vocabulário, quatro representações com seus vetores, medidas de similaridade e esparso contra denso nos mesmos dados

O problema: texto não é tabela

  • A PCA (análise de componentes principais) gira as colunas de uma tabela; o k-means mede distâncias entre as suas linhas.
  • Uma avaliação, um chamado de suporte, um post de fórum é uma sequência de caracteres de qualquer tamanho.
Preveja. Como você mediria a distância entre duas avaliações de clientes, uma com 12 palavras e outra com 300?

Esta aula constrói a ponte de strings a vetores, para que distâncias, projeções e agrupamentos valham para texto.

Duas famílias de respostas

esparsas

Bag-of-words, TF-IDF (frequência do termo × frequência inversa nos documentos)

  • uma coluna por palavra do vocabulário
  • cada documento é a contagem das suas palavras, com algum peso
  • obtidas por contagem, em um segundo, sem modelo algum

densas

Word e sentence embeddings

  • algumas centenas de números por palavra ou por documento
  • produzidos por um modelo treinado com muito texto
  • significado parecido fica próximo, mesmo sem palavras em comum

O caminho desta aula

  1. Texto → tokenstokenização, normalização, vocabulário
  2. Tokens → vetoresparso: bag-of-words, TF-IDF · denso: embeddings
  3. Comparar vetorescosseno, distância euclidiana, produto escalar, Jaccard
  4. Usar e escolherbusca e classificação: esparso ou denso?
Cada etapa responde a uma pergunta: o que conta como palavra? → como a palavra vira número? → quão parecidos são dois textos? → qual representação usar?

Cortar o texto em tokens


from sklearn.feature_extraction.text import CountVectorizer

docs = ["O gato comeu o peixe.",
        "O cachorro comeu a ração do gato.",
        "Gato dorme, gato sonha."]
analyzer = CountVectorizer().build_analyzer()    # o tokenizador padrão do scikit-learn
for d in docs:
    print(analyzer(d))
  
Preveja. O que acontece com "O", com a vírgula e com "Gato" na primeira e na terceira frases?

Três decisões silenciosas


['gato', 'comeu', 'peixe']
['cachorro', 'comeu', 'ração', 'do', 'gato']
['gato', 'dorme', 'gato', 'sonha']
  

minúsculas

"Gato" e "gato" viram o mesmo token (lowercase=True)

a pontuação some

o token_pattern padrão mantém sequências de duas ou mais letras ou dígitos

palavras de uma letra somem

os artigos o, a sumiram; do fica. Os acentos ficam ("ração")

Cada uma é uma decisão que você pode mudar.

Três tokenizadores, uma frase

s = "Os gatos não comeram a ração do cachorro, mas o gato comeu!"

Preveja. Separando nos espaços, o que acontece com "cachorro," e "comeu!"?
tokenizadorsaída
s.split()Os · gatos · não · comeram · a · ração · do · cachorro, · mas · o · gato · comeu!
re.findall(r"\w+", s.lower())os · gatos · não · comeram · a · ração · do · cachorro · mas · o · gato · comeu
analyzer(s) do scikit-learnos · gatos · não · comeram · ração · do · cachorro · mas · gato · comeu
Os espaços deixam a pontuação grudada nas palavras e mantêm "Os" ≠ "os"; uma regex de palavras dá 12 palavras limpas; o scikit-learn ainda descarta as de uma letra: 10 tokens.

Stop words e n-gramas

A frase de exemplo: "Os gatos não comeram a ração do cachorro, mas o gato comeu!" (12 tokens)

stop words

palavras muito frequentes e com pouco conteúdo (o, a, do, de), retiradas antes de contar

Os gatos não comeram a ração do cachorro, mas o gato comeu → 8 tokens

"não" ficou, porque não está nesta lista; a lista em inglês do scikit-learn tira "not".

n-gramas

sequências de \(n\) tokens vizinhos; bigramas são os pares

os gatos · gatos não · não comeram · comeram ração · … · gato comeu

"não comeram" vira um atributo só: um pouco da ordem volta.

Nas três frases dos slides anteriores: 8 colunas → 7 com uma lista pequena de stop words → 17 com bigramas.

Vale para: bag-of-words e TF-IDF, em que essas escolhas definem as colunas. Nos embeddings densos não se tiram stop words: "não" muda o sentido e o modelo lê a frase inteira.

Stemming e lematização

Juntar as variantes de uma palavra num token só. Na mesma frase:

o que fazexemplosferramenta
stemmingcorta sufixos por regras; o resultado não precisa ser uma palavragatos, gato → gat
comeram, comeu → com
sábados → sáb
RSLPStemmer do NLTK (Natural Language Toolkit)
lematizaçãoa forma de dicionário, usando um vocabulário e a classe gramaticalgatos → gato
comeram → comer
sábados → sábado
comeu → comeu (não reduziu)
spaCy
Vale para: bag-of-words e TF-IDF, em que juntar variantes junta colunas. O GloVe tem um vetor para cada forma ("cat" e "cats") e os sentence embeddings recebem o texto como está. Nenhuma das duas está no scikit-learn.

A mesma frase, normalizada

Preveja. Um stemmer corta "comeu" para "com". Que outras palavras, sem relação, podem cair na mesma coluna?
passosaída
sem stop wordsgatos · não · comeram · ração · cachorro · mas · gato · comeu
stems (RSLP, Removedor de Sufixos da Língua Portuguesa)os · gat · não · com · a · raç · do · cachorr · mas · o · gat · com
lemas (spaCy)o · gato · não · comer · o · ração · de o · cachorro · mas · o · gato · comeu
bigramasos gatos · gatos não · não comeram · comeram ração · ração do · do cachorro · cachorro mas · mas gato · gato comeu
  • "com" (preposição) e "comida" também viram "com": quatro palavras sem relação dividem uma coluna.
  • O lematizador pequeno deixou "comeu" como estava: ele é um modelo estatístico e erra.
  • "não" sobrevive a esta lista; a lista em inglês do scikit-learn remove "not", "no" e "never".

Subpalavras: os tokenizadores dos modelos neurais

Palavras frequentes ficam inteiras; palavras raras viram pedaços frequentes: nenhuma palavra é desconhecida.

Preveja. Um tokenizador treinado em inglês encontra "não" e "cachorro". O que ele faz com elas?
tokenizadorsaída
WordPiece, all-MiniLM-L6-v2
30.522 pedaços do inglês, o tokenizador do BERT (Bidirectional Encoder Representations from Transformers)
tokenization → token ##ization
unbelievably → un ##bel ##ie ##va ##bly
s → os ga ##tos na ##o come ##ram a ra ##cao do ca ##cho ##rro , mas o ga ##to come ##u !
SentencePiece, modelo multilíngue
250.002 pedaços, mais de 50 línguas
s → ▁Os ▁gato s ▁não ▁come ram ▁a ▁ra ção ▁do ▁cachorro , ▁mas ▁o ▁gato ▁come u !
desparafusaram → ▁des para fus aram

##: colado ao pedaço anterior; ▁: início de palavra. Cada pedaço tem seu vetor, então uma palavra nunca vista inteira ainda recebe um.

Onde cada decisão da etapa 1 entra

bag-of-words, TF-IDFword embeddings (GloVe)sentence embeddings
minúsculas, pontuaçãoescolha sua (o padrão do scikit-learn põe em minúsculas e tira a pontuação)o vocabulário do GloVe é todo em minúsculaso tokenizador do modelo decide
stop wordsopcional: tira colunasopcional, antes da médianão: "não" muda o sentido
stemming, lematizaçãoopcional: junta colunasnão: um vetor por formanão
n-gramasopcional: colunas de paresnãonão: o modelo lê a frase na ordem
subpalavrasnãonão: palavra fora do vocabulário fica sem vetorsim, o tokenizador do modelo
Normalizar é uma decisão da família esparsa. Nos embeddings densos, o tokenizador e o vocabulário vêm com o modelo: o texto entra como está.

Quão grande fica o vocabulário?

A coleção 20 Newsgroups: 11.314 posts de grupos da Usenet do começo dos anos 1990. Leia um token de cada vez e conte as palavras distintas vistas até ali.

Preveja. Depois de algumas centenas de milhares de tokens, o número de palavras distintas se estabiliza ou continua crescendo?

Lei de Heaps: o vocabulário nunca para de crescer

Tamanho do vocabulário contra tokens lidos, em escala log-log: uma reta que passa por 3.279 palavras com 11.025 tokens, 18.692 com 100.504 e 63.306 com 1.000.517; chega a 101.631 palavras com 2.158.589 tokens, sem achatar

como ler

  • eixo x: tokens lidos até ali; eixo y: palavras distintas já vistas. Os dois em escala log.
  • Em escala log, uma lei de potência vira reta; a inclinação, 0,61, é o expoente.
  • Pontilhada: se todo token fosse uma palavra nova. A curva fica abaixo dela, mas nunca deita.
  • 11 mil tokens → 3.279 palavras; 100 mil → 18.692; 1 milhão → 63.306.
Dez vezes mais texto dá cerca de 4 vezes mais palavras, sem fim: um vocabulário montado hoje encontra palavras novas amanhã e uma representação esparsa não tem coluna para elas.

Lei de Zipf: poucas palavras estão em toda parte

Preveja. Das 101.631 palavras distintas, que fração aparece uma única vez no corpus inteiro: 5%, 25% ou mais da metade?

Ocorrências de cada palavra contra a sua posição no ranking, em escala log-log: the aparece 106.381 vezes, car 799 e hockey 374; as 10 mais frequentes somam 21% dos tokens e 55% das 101.631 palavras aparecem uma única vez

como ler

  • Cada ponto é uma palavra. Eixo x: a sua posição no ranking (1 = a mais frequente); eixo y: quantas vezes aparece. Os dois em log.
  • No topo, "the" (106.381 vezes), "of", "is": as 10 primeiras são 21% de todos os tokens.
  • No meio, "car" (posto 271, 799 vezes) e "hockey" (posto 625, 374 vezes).
  • Faixa vermelha: 55% das palavras aparecem uma única vez.
A maioria das colunas de um bag-of-words descreve um único documento; as poucas palavras do topo são justamente as stop words.

Simulador: tokenize um parágrafo

Preveja. Passe de unigramas para uni + bi, o que o ngram_range=(1, 2) faz: o vocabulário cresce um pouco, dobra ou mais?

Um mapa das abordagens

Depois que o texto foi cortado em tokens, quatro páginas transformam os tokens em vetores, do mais simples ao mais poderoso. Aponte para uma família para segui-la.

O que cada uma faz e o que não consegue fazer

páginaum documento viraconstruído a partir deo que não consegue fazer
U4.1 Bag-of-wordsas contagens das suas palavras, uma coluna por palavracontagem, sem modelover a ordem, sinônimos ou palavras não vistas no fit
U4.2 TF-IDFcontagens pesadas pela raridade de cada palavracontagem sobre o corpuso mesmo: ele só muda o peso das colunas
U4.3 Word embeddingsum vetor denso por palavra (a média, para um documento)coocorrência num corpus grandeseparar os sentidos de uma mesma palavra
U4.4 Sentence embeddingsum vetor denso por frase ou documento curtoum transformer pré-treinadoser barato ou explicar suas dimensões

Bag-of-words: um documento é a sua contagem


       cachorro  comeu  do  dorme  gato  peixe  ração  sonha
doc 1         0      1   0      0     1      1      0      0
doc 2         1      1   1      0     1      0      1      0
doc 3         0      0   0      1     2      0      0      1
  
  • Uma linha por documento, uma coluna por palavra; "gato" vale 2 no documento 3. A ordem das palavras é descartada.
  • 13 das 24 células já são zero. Os 11.314 posts: \(11.314 \times 101.631\), 99,90% de zeros, guardada num formato esparso.
As contagens brutas são dominadas por palavras funcionais: "the" está em 9.475 dos 11.314 posts. É por isso que raramente são usadas sem peso.

TF-IDF: contagens pesadas pela raridade

\[ \text{tf-idf}(t, d) = \text{tf}(t, d) \times \Big(\ln \frac{1 + n}{1 + \text{df}(t)} + 1\Big) \]

e depois cada linha é dividida pelo seu comprimento. Preveja. No documento 1 (gato, comeu, peixe: uma vez cada), qual palavra pesa mais?


     cachorro   comeu      do   dorme  gato   peixe   ração   sonha
idf    1.6931  1.2877  1.6931  1.6931   1.0  1.6931  1.6931  1.6931
       cachorro  comeu     do  dorme   gato  peixe  ração  sonha
doc 1     0.000  0.548  0.000  0.000  0.425   0.72  0.000  0.000
doc 2     0.505  0.384  0.505  0.000  0.298   0.00  0.505  0.000
doc 3     0.000  0.000  0.000  0.543  0.641   0.00  0.000  0.543
  

"peixe", só no documento 1, pesa 0,720; "gato", nos três, 0,425. Os mesmos zeros; cada linha com comprimento 1. Spärck Jones (1972); Salton & Buckley (1988).

Similaridade e distância: quatro medidas

similaridade de cosseno

compara as direções dos dois vetores e ignora os comprimentos. 1 = mesmas palavras nas mesmas proporções; 0 = nada em comum.

distância euclidiana

a distância em linha reta entre os dois pontos (a do k-means). 0 = idênticos; cresce com qualquer diferença, inclusive de comprimento.

produto escalar

multiplique coordenada a coordenada e some. É grande quando os dois são grandes nas mesmas colunas: cresce com o tamanho do documento.

similaridade de Jaccard

esqueça as contagens e compare os conjuntos de tokens: os tokens em comum sobre todos os tokens distintos.

Uma consulta e dois candidatos

Colunas: cachorro, comeu, do, dorme, gato, peixe, ração, sonha. A consulta é A.

A = "O gato comeu o peixe."[0 1 0 0 1 1 0 0]
B = "Gato dorme, gato sonha." (outro assunto)[0 0 0 1 2 0 0 1]
A3 = A escrito três vezes (mesmo assunto, mais longo)[0 3 0 0 3 3 0 0]
Preveja. Pela distância euclidiana, qual candidato fica mais perto de A: B ou A3?
parcossenoeuclidianaescalarJaccard
A e B0,4712,23620,200
A e A31,0003,46491,000
B e A30,4714,58360,200

Por que o cosseno é o padrão para texto

  • Cosseno: A3 é idêntico a A (1,000) e B é uma correspondência parcial (0,471); B marca 0,471 contra A e contra A3.
  • A euclidiana inverte a resposta: A3 fica mais longe de A (3,464) do que B (2,236), só porque é mais longo.
  • Produto escalar: B contra A3 marca 6, o triplo do 2 contra A, para o mesmo conteúdo.
  • O Jaccard concorda aqui, mas é cego a quantas vezes uma palavra aparece.
Documentos têm todos os tamanhos; o tamanho diz pouco sobre o assunto. Com comprimento 1, as três concordam: o produto escalar é o cosseno. As linhas do TF-IDF já têm comprimento 1; os sentence embeddings usam normalize_embeddings=True.

Os limites das representações esparsas

Preveja. "o carro é rápido" e "o automóvel é veloz": qual é o cosseno delas no TF-IDF?
  • Sinônimos dão zero: cosseno 0,00. Cada palavra é um eixo próprio, ortogonal aos outros.
  • A ordem é invisível: "o cachorro mordeu o homem" e "o homem mordeu o cachorro" têm cosseno 1,00.
  • Uma grafia, dois sentidos: manga (da camisa ou a fruta) faz frases sem relação parecerem próximas e duas frases de mesmo sentido parecerem sem relação (0,14 nos dois casos).
  • Palavras novas somem: uma palavra não vista no fit não tem coluna.
De volta à etapa 2 · família densa

Denso: conhecer uma palavra pelas companhias

"Você conhecerá uma palavra pelas companhias que ela mantém" (Firth, 1957)

  • Hipótese distribucional (Harris, 1954): palavras usadas em contextos parecidos têm significados parecidos.
  • "carro" e "automóvel" raramente estão na mesma frase, mas aparecem ao lado de motor, concessionária, pneu.
  • Cada palavra ou texto recebe algumas centenas de números, aprendidos para que contextos parecidos deem vetores próximos.
Nenhum número isolado significa algo; só as distâncias entre vetores significam.

Word embeddings, sentence embeddings

word embeddings (U4.3)

O word2vec (Mikolov et al., 2013) prevê as palavras em volta de cada palavra; o GloVe fatora contagens de coocorrência.

Sinônimos ficam próximos. Limite: um vetor por palavra, qualquer que seja o sentido.

sentence embeddings (U4.4)

Transformers (BERT) calculam cada token a partir da frase inteira: manga ao lado de "camisa" ≠ ao lado de "madura".

Sentence-BERT: um vetor por frase; o cosseno acompanha a proximidade de sentido.

Word embeddings: como é um vetor

GloVe, treinado em 6 bilhões de tokens de texto em inglês: 400.000 palavras, 50 números cada.


glove = api.load('glove-wiki-gigaword-50')
print('cat =', glove['cat'][:8].round(3), '...')
print(glove.most_similar('cat', topn=5))
  
Preveja. Quais palavras ficam mais perto de "cat" (gato)? E o que significa o primeiro número, 0,453?

cat = [ 0.453 -0.501 -0.537 -0.016  0.222  0.546 -0.673 -0.689] ... (50 numbers, none of them zero)
nearest to cat: dog 0.92, rabbit 0.85, monkey 0.80, rat 0.79, cats 0.79
cosine car / automobile: 0.70
cosine car / banana: 0.22
  

Nenhum número sozinho significa algo; os vizinhos sim. "car" e "automobile" nunca dividiram uma coluna na bag-of-words; aqui têm cosseno 0,70.

Sentence embeddings: um vetor por frase

paraphrase-multilingual-MiniLM-L12-v2, com normalize_embeddings=True: 384 números por texto, mais de 50 línguas.

Preveja. "o carro é rápido" contra a paráfrase "o automóvel é veloz" (nenhuma palavra em comum) e contra "a taxa de juros subiu" (sem relação): quais cossenos?

(3, 384)
o carro é rápido = [ 0.016  0.033 -0.08   0.037 -0.014 -0.002  0.039 -0.028] ... (384 numbers)
vs 1: cosine 0.97 · dot 0.97 · Euclidean 0.25
vs 2: cosine 0.23 · dot 0.23 · Euclidean 1.24
  

Com comprimento 1, produto escalar = cosseno e a distância euclidiana conta a mesma história ao contrário.

Esparso vs denso: uma frase, três vetores

"the cat sleeps on the couch": bag-of-words sobre o vocabulário dos newsgroups, a média dos seus vetores GloVe e o seu sentence embedding.

Preveja. Qual o comprimento de cada vetor e quantos dos seus números não são zero?
comprimentonão nulosvalores
bag-of-words101.6315cat (coluna 26.019) = 1, couch = 1, on = 1, sleeps = 1, the = 2 · todas as outras 0
média GloVe5050[ 0.271 0.037 -0.335 -0.147 0.541 0.055] ...
sentence embedding384384[ 0.39 -0.348 -0.135 0.145 0.115 0.278] ...

O que "esparso" e "denso" querem dizer

esparsa (bag-of-words, TF-IDF)densa (word e sentence embeddings)
comprimentouma coluna por palavra do vocabulário: 101.631fixado pelo modelo: 50 (GloVe), 384 (frases)
valores não nulossó as palavras do texto: 5todos
uma coordenada significacoluna 26.019 = "quantas vezes cat aparece"nada sozinha
guardada comoas células não nulas (índice, valor)um vetor comum de números reais
nenhuma palavra em comumnenhuma coluna em comum: cosseno 0ainda podem ficar próximos
Vetores esparsos só aproximam textos que dividem palavras; vetores densos aproximam textos que dividem sentido.

Simulador: quatro jeitos de transformar uma frase em vetor

Preveja. Na paráfrase "o carro é rápido" / "o automóvel é veloz", quais das quatro dão cosseno 0? Depois troque a ordem das palavras e marque B três vezes.

Esparso vs denso: os mesmos pares, dos dois jeitos

TF-IDF ajustado nas frases da tabela; um modelo multilíngue pequeno do sentence-transformers (384 números por texto).

ABTF-IDFembedding
o carro é rápidoo automóvel é veloz0,000,97
comprei um celular novoadquiri um smartphone novo0,430,91
o gato dorme no sofáthe cat sleeps on the couch0,000,98
a manga da camisa rasgouo punho da blusa descosturou0,210,87
a manga da camisa rasgoucomi uma manga madura0,210,35
o filme é muito bomo filme não é bom0,600,46
o cachorro mordeu o homemo homem mordeu o cachorro1,000,98
a taxa de juros subiuo time venceu o jogo0,000,14

Lendo a tabela, linha a linha

  • paráfrases: 0,91 contra 0,43; o TF-IDF só enxerga "um" e "novo".
  • tradução: nenhum token em comum, 0,98. Uma consulta em português acha documentos em inglês.
  • as duas linhas de "manga": o TF-IDF dá 0,21 às duas; o embedding separa manga-e-punho (0,87) de manga-e-fruta (0,35).
  • negação: mais baixo (0,46), mas longe de "oposto".
  • ordem das palavras: 0,98. Os embeddings também confundem quem mordeu quem.
  • sem relação: 0,14, não 0.
Os cossenos de embeddings ocupam uma escala comprimida: o que carrega a informação é a ordenação, não o valor absoluto; um limiar ajustado para um modelo não vale para outro.

Onde o TF-IDF é mais forte: tokens raros e exatos

Duas entradas de uma central de ajuda que diferem só no código de erro (0x80070005 e 0x80004005) e uma consulta para cada código.

TF-IDF

0,55 vs 0,18
o código é o token mais distintivo e decide a correspondência

embedding

0,80 vs 0,77
as duas são "uma mensagem de erro na instalação"
Com muitos códigos parecidos, nomes de produtos ou referências a leis, a correspondência exata é o que você quer. A busca em produção costuma combinar as duas ordenações: busca híbrida.

Classificação: quantos rótulos você tem?

Quatro newsgroups, uma regressão logística usada como caixa-preta; só a representação muda. Acurácia em 1.364 posts posteriores (chutar uma classe: cerca de 25%).

Preveja. Com só 5 posts rotulados por classe, qual representação vence? E com os 2.097?
posts rotulados por classeTF-IDF + clfembedding + clf
50,5570,819
100,6010,851
250,7250,886
1000,8500,897
todos0,9040,901

Por quê: o que cada uma já sabe ao chegar

TF-IDF, 20 posts de treino

viu só algumas centenas de palavras distintas; um post de teste que não use nenhuma delas vira um vetor nulo. Com todos os rótulos, aprende o vocabulário de cada classe a partir dos dados.

embedding

já chega sabendo que "sedan" fica perto de "car", pelo texto em que foi treinado.

O que os escores não mostram é o custo: o TF-IDF processa os 2.097 posts em 0,2 s; o modelo de embeddings precisa de cerca de um minuto na mesma CPU (unidade central de processamento) ou 10 s numa GPU (unidade de processamento gráfico), depois de baixar 470 MB.

Esparso vs denso, lado a lado

esparso (bag-of-words, TF-IDF)denso (sentence embeddings)
vetor de um documento\(\lvert V \rvert\) colunas, 99,9% de zeros384–1.024 números
sinônimos, paráfrasesortogonais: 0,00próximos: 0,97
palavras nunca vistas no fitdescartadastratadas (pedaços de subpalavras)
tokens raros e exatosidf alto, sinal fortediluídos no sentido geral
outras línguasvocabulários separadosespaço compartilhado (modelo multilíngue)
5 rótulos por classe / todos55,7% / 90,4%81,9% / 90,1%
interpretabilidadecada coluna é uma palavracolunas abstratas
custofrações de segundo, sem modeloum modelo pré-treinado; uma GPU ajuda

Resumo: qual usar e quando

  1. Comece pelo TF-IDF: barato e difícil de bater quando há muitos rótulos e vocabulário de domínio.
  2. Recorra aos embeddings quando o significado importa mais que as palavras exatas (busca, textos curtos, paráfrases, várias línguas) ou quando os rótulos são escassos.
  3. Quando tanto os tokens exatos quanto o significado importam, combine os dois.
Para onde isso leva: o BERTopic (U5) gera embeddings dos documentos, reduz os vetores com UMAP (uma redução de dimensionalidade), agrupa-os com HDBSCAN (um agrupamento por densidade) e descreve cada grupo com um TF-IDF calculado por agrupamento.
Lab · cerca de dois minutos numa CPU

Esparso vs denso em posts reais

  • Quatro newsgroups (computação gráfica, beisebol, eletrônica e cristianismo), cerca de 2.100 posts, representados duas vezes: TF-IDF e sentence embeddings.
  • Passos: carregar os posts · duas representações · qual acha posts sobre o mesmo assunto? · busca semântica contra busca por palavras-chave · olhar os dois espaços · o mesmo classificador caixa-preta nas duas.
  • Baixe o notebook do lab e abra no Jupyter ou no Colab; no Colab, rode !pip install sentence-transformers antes.

Cada uma das quatro subpáginas (U4.1 a U4.4) tem simulador e lab próprios.