Prossiga com GloVe Embeddings
Você quer usar os embeddings GloVe em seu projeto? Várias terminologias estão causando problemas? Parabéns! Você está no lugar certo.
Observação: este artigo não discute a matemática por trás da incorporação do GloVe.
Neste artigo, aprenderemos como usar os embeddings GloVe para transformar qualquer dado de texto em números. Aprenderemos as etapas usando um corpus de texto curto e, em seguida, aplicaremos essas etapas para obter a incorporação do conjunto de dados de revisão de filmes do IMDB. Usaremos a incorporação obtida para treinar um classificador de sentimento binário no mesmo conjunto de dados.
Vamos começar!
Introdução
Há uma variedade de incorporações de palavras GloVe pré-treinadas disponíveis para download. Mais informações sobre o corpus de treinamento de diferentes incorporações do Glove podem ser encontradas neste site. Neste tutorial, usaremos os embeddings glovetwitter27b50d, que possuem 50 dimensões e foram treinados em tweets 2B do Twitter.
A incorporação está disponível como um arquivo de texto onde cada linha possui uma string contendo uma palavra e sua representação vetorial. Vamos converter o conteúdo deste arquivo de texto em um dicionário.
# Read the text file
glovetwitter27b50d = "pathe_to_glovetwitter27b50d.txt"
file = open(glovetwitter27b50d)
glovetwitter27b50d = file.readlines()
# Convert the text file into a dictionary
def ConvertToEmbeddingDictionary(glovetwitter27b50d):
embedding_dictionary = {}
for word_embedding in tqdm(glovetwitter27b50d):
word_embedding = word_embedding.split()
word = word_embedding[0]
embedding = np.array([float(i) for i in word_embedding[1:]])
embedding_dictionary[word] = embedding
return embedding_dictionary
embedding_dictionary = ConvertToEmbeddingDictionary(glovetwitter27b50d)
# Let's look at the embedding of the word "hello."
embedding_dictionary['hello']
Output:
array([ 0.28751 , 0.31323 , -0.29318 , 0.17199 , -0.69232 ,
-0.4593 , 1.3364 , 0.709 , 0.12118 , 0.11476 ,
-0.48505 , -0.088608 , -3.0154 , -0.54024 , -1.326 ,
0.39477 , 0.11755 , -0.17816 , -0.32272 , 0.21715 ,
0.043144 , -0.43666 , -0.55857 , -0.47601 , -0.095172 ,
0.0031934, 0.1192 , -0.23643 , 1.3234 , -0.45093 ,
-0.65837 , -0.13865 , 0.22145 , -0.35806 , 0.20988 ,
0.054894 , -0.080322 , 0.48942 , 0.19206 , 0.4556 ,
-1.642 , -0.83323 , -0.12974 , 0.96514 , -0.18214 ,
0.37733 , -0.19622 , -0.12231 , -0.10496 , 0.45388 ])
sample_corpus = ['The woods are lovely, dark and deep',
'But I have promises to keep',
'And miles to go before I sleep',
'And miles to go before I sleep']
# This is the maximum number of tokens we wish to consider from our dataset.
# When there are more tokens, the tokens with the highest frequency are chosen.
max_number_of_words = 5
# Note: Keras tokenizer selects only top n-1 tokens if the num_words is set to n
tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(sample_corpus)
sample_corpus_tokenized = tokenizer.texts_to_sequences(sample_corpus)
print(tokenizer.word_index)
Output:
{'and': 1, 'i': 2, 'to': 3, 'miles': 4, 'go': 5, 'before': 6, 'sleep': 7, 'the': 8, 'woods': 9, 'are': 10, 'lovely': 11, 'dark': 12, 'deep': 13, 'but': 14, 'have': 15, 'promises': 16, 'keep': 17}
print("But I have promises to keep: ", sample_corpus_tokenized[1])
Output:
But I have promises to keep: [2, 3]
Agora que escolhemos um conjunto de tokens de nosso corpus de texto, devemos desenvolver uma matriz de incorporação para eles. A matriz de incorporação terá colunas iguais à dimensão da incorporação e linhas iguais ao número de tokens .
# Create embedding matrix
total_number_of_words = min(max_number_of_words, len(tokenizer.word_index))
embedding_matrix = np.zeros((total_number_of_words,50))
for word, i in tokenizer.word_index.items():
if i >= total_number_of_words: break
if word in embedding_dictionary.keys():
embedding_vector = embedding_dictionary[word]
embedding_matrix[i] = embedding_vector
As redes neurais artificiais e os algoritmos de ML não podem lidar com um comprimento variável de entradas, portanto, precisamos converter as incorporações de cada sequência de entrada em um tamanho fixo. Existem muitas abordagens para fazer isso, mas a mais simples é somar a incorporação de cada token em uma frase e normalizar o vetor.
def convertToSentenceVector(sentences):
new_sentences = []
for sentence in sentences:
sentence_vector = []
for word_index in sentence:
sentence_vector.append(embedding_matrix[word_index])
sentence_vector = np.array(sentence_vector).sum(axis=0)
embedding_vector / np.sqrt((embedding_vector ** 2).sum())
new_sentences.append(sentence_vecto
sample_corpus_vectorized = convertToSentenceVector(sample_corpus_tokenized)
# Print the 50-dimensional embedding of the first sentence in our text corpus.
print(sample_corpus_vectorized[0])
Output:
[-0.43196 -0.18965 -0.028294 -0.25903 -0.4481 0.53591
0.94627 -0.07806 -0.54519 -0.72878 -0.030083 -0.28677
-6.464 -0.31295 0.12351 -0.2463 0.029458 -0.83529
0.19647 -0.15722 -0.5562 -0.027029 -0.23915 0.18188
-0.15156 0.54768 0.13767 0.21828 0.61069 -0.3679
0.023187 0.33281 -0.18062 -0.0094163 0.31861 -0.19201
0.35759 0.50104 0.55981 0.20561 -1.1167 -0.3063
-0.14224 0.20285 0.10245 -0.39289 -0.26724 -0.37573
0.16076 -0.74501 ]
Classificação de sentimentos: conjunto de dados de resenhas de filmes do IMDB
# Read the data
df = pd.read_csv("IMDB_Dataset.csv")
X = df['review']
y = df['sentiment']
# Convert labels to numbers
le = LabelEncoder()
y = le.fit_transform(y)
# Split the data into train and test sets.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.10, random_state=0)
#Set the maximum number of tokens to 50000
max_number_of_words = 50000
# Tokenize training set
tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)
# Create embedding matrix
total_number_of_words = min(max_number_of_words, len(tokenizer.word_index))
embedding_matrix = np.zeros((total_number_of_words+1,50))
for word, i in tokenizer.word_index.items():
if i >= total_number_of_words: break
if word in embedding_dictionary.keys():
embedding_vector = embedding_dictionary[word]
embedding_matrix[i] = embedding_vector
# Get a fixed-size embedding for every comment using the function defined earlier
X_train = convertToSentenceVector(X_train)
X_test = convertToSentenceVector(X_test)
# Define a sequential model
model = Sequential()
model.add(Dense(100, input_shape = (50,), activation = "relu"))
model.add(Dense(1000, activation = "relu"))
model.add(Dropout(0.2))
model.add(Dense(1, activation = "sigmoid"))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()
# Fit the model
model.fit(X_train, y_train, batch_size=32, epochs=10, validation_split=0.1)
# Get the classification report on the test set
y_pred = model.predict(X_test)
y_pred = y_pred.round()
print(classification_report(y_test, y_pred))
Output:
precision recall f1-score support
0 0.82 0.77 0.79 2553
1 0.77 0.82 0.80 2447
accuracy 0.80 5000
macro avg 0.80 0.80 0.80 5000
weighted avg 0.80 0.80 0.80 5000
max_number_of_words = 50000
max_length = 100
tokenizer = Tokenizer(num_words=max_number_of_words)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)
# We can use padding to make the length of every comment equal to max_length
X_train = pad_sequences(X_train, maxlen=max_length)
X_test = pad_sequences(X_test, maxlen=max_length)
# Define a sequential model
model = Sequential()
# Add an embedding layer and pass the embedding matrix as weights
model.add(Embedding(max_number_of_words+1, 50, input_shape = (100,), weights=[embedding_matrix]))
model.add(Bidirectional(LSTM(50, return_sequences=True, dropout=0.1, recurrent_dropout=0.1)))
model.add(GlobalMaxPool1D())
model.add(Dense(50, activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(1, activation="sigmoid"))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()
# Fit the model
model.fit(X_train, y_train, batch_size=32, epochs=10, validation_split=0.1);
# Get the classification report
y_pred = model.predict(X_test)
y_pred = y_pred.round()
print(classification_report(y_test, y_pred))
Output:
precision recall f1-score support
0 0.87 0.83 0.85 2553
1 0.83 0.87 0.85 2447
accuracy 0.85 5000
macro avg 0.85 0.85 0.85 5000
weighted avg 0.85 0.85 0.85 5000
Agora que você tem uma melhor compreensão das incorporações do GloVe, você está pronto para aplicá-lo a vários problemas de PNL.
Observação: você pode acessar o código completo neste link.
Referências :
- https://www.tensorflow.org/text/guide/word_embeddings
- https://www.kaggle.com/code/jhoward/improved-lstm-baseline-glove-dropout
- https://www.kaggle.com/code/abhishek/approaching-almost-any-nlp-problem-on-kaggle