Análise de Sentimentos com Python! 😁😔
Análise de Sentimentos do IMDb com Python!
Autor: Gabriel Murilo
A análise de sentimento é uma técnica que envolve a classificação das opiniões e emoções expressas em texto. No contexto do IMDb, um dos maiores sites de críticas de filmes, a análise de sentimento será usada para determinar se uma revisão é positiva ou negativa com base no texto escrito (review).
Para isso, usaremos a uma técnica conhecida como NLP (Processamento de Linguagem Natural) que utiliza de redes neurais LSTM para seu funcionamento.
dica: se estiver no Colab, vá em "Ambiente de execução/Alterar tipo de ambiente de execução, coloque em T4 GPU e salve, assim, seu notebook terá uma GPU, e o treinamento da IA será mais rápido e eficaz
Importações das Libs:
from keras.datasets import imdb
from keras.preprocessing import sequence
import keras
from tensorflow.keras.models import load_model
import tensorflow as tf
import os
import numpy as np
from keras.utils.data_utils import pad_sequences
Carregamento dos Dados
VOCAB_SIZE = 88584
MAXLEN = 250
BATCH_SIZE = 64
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words = VOCAB_SIZE)
train_data = pad_sequences(train_data, MAXLEN)
test_data = pad_sequences(test_data, MAXLEN)
Aqui, estamos definindos os hiperparâmetros, Carregandos os dados e padronizando as sequências:
VOCAB_SIZE: especifica o tamanho do vocabulário que será usado. É o número máximo de palavras distintas que o modelo considerará. Neste caso, o vocabulário tem 88.584 palavras.
MAXLEN: define o comprimento máximo das sequências de texto. Sequências mais longas serão truncadas e sequências mais curtas serão preenchidas para ter esse comprimento. No seu caso, o comprimento máximo é de 250 palavras.
BATCH_SIZE: determina o tamanho dos lotes de dados que serão usados durante o treinamento. Cada lote contém 64 sequências de texto.
pad_sequences: estamos padronizando (preenchendo ou truncando) as sequências de texto para que todas tenham o mesmo comprimento, especificado por MAXLEN. Isso é necessário porque muitos modelos de aprendizado de máquina, como redes neurais, exigem que as entradas tenham o mesmo tamanho.
Criando o Modelo:
model = tf.keras.Sequential([
tf.keras.layers.Embedding(VOCAB_SIZE, 32),
tf.keras.layers.LSTM(32),
tf.keras.layers.Dense(1, activation="sigmoid")
])
Compilação e Treinamento do Modelo:
model.compile(loss="binary_crossentropy",optimizer="rmsprop",metrics=['acc'])
history = model.fit(train_data, train_labels, epochs=50, validation_split=0.2)
results = model.evaluate(test_data, test_labels)
print(results)
Nessa parte, o modelo é compilado com uma função de perda de entropia cruzada binária (binary_crossentropy), otimizado com RMSprop e monitora a precisão. O modelo é treinado com os dados de treinamento, com validação em 20% dos dados, em 50 épocas (épocas são o número de vezes que o modelo vê um mesmo dado).
Codificação e Decodificação
word_index = imdb.get_word_index()
def encode_text(text):
tokens = keras.preprocessing.text.text_to_word_sequence(text)
tokens = [word_index[word] if word in word_index else 0 for word in tokens]
return pad_sequences([tokens], MAXLEN)[0]
text = "that movie was just amazing, so amazing"
encoded = encode_text(text)
print(encoded)
Aqui, resumidamente, essa função codifica algum texto, mapeando as palavras para índices no vocabulário do conjunto de dados IMDB, e padroniza a sequência para um comprimento máximo, preparando-a para alimentar um modelo de análise de sentimentos. No caso que está printanto, ficaria assim:
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 12 17 13 40 477 35 477]
reverse_word_index = {value: key for (key, value) in word_index.items()}
def decode_integers(integers):
PAD = 0
text = ""
for num in integers:
if num != PAD:
text += reverse_word_index[num] + " "
return text[:-1]
print(decode_integers(encoded))
Aqui fazemos da decodificação.
Testando o Modelo:
def predict(text):
encoded_text = encode_text(text)
pred = np.zeros((1,250))
pred[0] = encoded_text
result = model.predict(pred)
print(result[0])
positive_review = "That movie was! really loved it and would great watch it again because it was amazingly great"
predict(positive_review)
negative_review = "that movie really sucked. I hated it and wouldn't watch it again. Was one of the worst things I've ever watched"
predict(negative_review)
O resultado varia entre 0 e 1 (pois como é uma classifcação binária, usamos a função de ativação "sigmoid), quanto mais próximo de 1, mais positiva foi a análise.
Neste teste o resultado foi esse:
1/1 [==============================] - 0s 337ms/step
[0.6899334]
1/1 [==============================] - 0s 18ms/step
[0.00852319]
Salvando o Modelo no Colab:
from google.colab import drive
drive.mount('/content/drive')
# Salvar o classificador
model_json = model.to_json()
with open("/content/drive/MyDrive/model.json", "w") as json_file:
json_file.write(model_json)
model.save_weights("/content/drive/MyDrive/model.h5")
Salvamos em 2 arquivos, um .json que é a "arquitetura" do modelo e o .h5, que são os pesos da rede neural.
Carregando esse Modelo
import numpy as np
from keras.models import model_from_json
from keras_preprocessing.sequence import pad_sequences
import keras
from keras.datasets import imdb
# Load the model
file = open('model.json', 'r')
structure = file.read()
file.close()
loaded_model = model_from_json(structure)
loaded_model.load_weights(r"model.h5")
model = loaded_model
print(model.summary())
# encode function
word_index = imdb.get_word_index()
MAXLEN = 250
def encode_text(text):
tokens = keras.preprocessing.text.text_to_word_sequence(text)
tokens = [word_index[word] if word in word_index else 0 for word in tokens]
return pad_sequences([tokens], MAXLEN)[0]
text = "I loved this movie, its was all good"
encoded = encode_text(text)
# prediction
pred = np.zeros((1,250))
pred[0] = encoded
result = model.predict(pred)
result = (result[0] * 100).item()
print(f'Positive: {result:.2f}%')