Construir um programa de classificação de texto: um tutorial de PNL
Publicados: 2022-03-11O aprendizado profundo é uma tecnologia que se tornou uma parte essencial dos fluxos de trabalho de aprendizado de máquina. Aproveitando as melhorias do poder de computação paralela e ferramentas de suporte, redes neurais complexas e profundas que antes eram impraticáveis agora estão se tornando viáveis.
O surgimento de bibliotecas poderosas e acessíveis, como Tensorflow, Torch e Deeplearning4j, também abriu o desenvolvimento para usuários além da academia e departamentos de pesquisa de grandes empresas de tecnologia. Como prova de sua crescente onipresença, empresas como Huawei e Apple estão agora incluindo processadores dedicados e otimizados para aprendizado profundo em seus dispositivos mais recentes para impulsionar aplicativos de aprendizado profundo.
O aprendizado profundo provou seu poder em muitos domínios. Mais notavelmente, o AlphaGo do Google foi capaz de derrotar jogadores humanos em um jogo de Go, um jogo cuja complexidade incompreensível já foi considerada uma barreira quase intransponível para computadores em sua competição contra jogadores humanos. O projeto Flow Machines da Sony desenvolveu uma rede neural que pode compor músicas no estilo de músicos famosos do passado. O FaceID, um recurso de segurança desenvolvido pela Apple, usa aprendizado profundo para reconhecer o rosto do usuário e rastrear alterações no rosto do usuário ao longo do tempo.
Neste artigo, aplicaremos o aprendizado profundo a dois dos meus tópicos favoritos: processamento de linguagem natural e vinho. Construiremos um modelo para entender as avaliações de vinhos em linguagem natural feitas por especialistas e deduzir a variedade do vinho que eles estão avaliando.
Deep Learning para PNL
O aprendizado profundo tem sido usado extensivamente no processamento de linguagem natural (PNL) porque é adequado para aprender a estrutura subjacente complexa de uma frase e a proximidade semântica de várias palavras. Por exemplo, o estado da arte atual para análise de sentimentos usa aprendizado profundo para capturar conceitos linguísticos difíceis de modelar, como negações e sentimentos mistos.
O aprendizado profundo tem várias vantagens sobre outros algoritmos para PNL:
- Modelos flexíveis: os modelos de aprendizado profundo são muito mais flexíveis do que outros modelos de ML. Podemos facilmente experimentar diferentes estruturas, adicionando e removendo camadas conforme necessário. Os modelos de aprendizado profundo também permitem a construção de modelos com saídas flexíveis. A flexibilidade é a chave para o desenvolvimento de modelos adequados para a compreensão de estruturas linguísticas complexas. Também é essencial para o desenvolvimento de aplicativos de PNL, como traduções, chatbots e aplicativos de conversão de texto em fala.
- Menos conhecimento de domínio necessário: embora certamente seja necessário algum conhecimento de domínio e intuição para desenvolver um bom modelo de aprendizado profundo, a capacidade dos algoritmos de aprendizado profundo de aprender hierarquias de recursos por conta própria significa que um desenvolvedor não precisa de tanto conhecimento aprofundado do espaço de problemas para desenvolver algoritmos de PNL de aprendizado profundo. Para um espaço de problemas tão complexo quanto a linguagem natural, essa é uma vantagem muito bem-vinda.
- Aprendizado contínuo mais fácil: os algoritmos de aprendizado profundo são fáceis de treinar à medida que novos dados chegam. Alguns algoritmos de aprendizado de máquina exigem que todo o conjunto de dados seja enviado por meio do modelo para atualização, o que apresentaria um problema para conjuntos de dados grandes e ativos.
O problema hoje
Hoje, construiremos um algoritmo de aprendizado profundo para determinar a variedade do vinho que está sendo revisado com base no texto da revisão. Usaremos o conjunto de dados da revista de vinhos em https://www.kaggle.com/zynicide/wine-reviews, fornecido pelo usuário do Kaggle zackthoutt .
Conceitualmente, a questão é, podemos fazer uma revisão de vinho como…
Os aromas incluem frutas tropicais, vassoura, enxofre e ervas secas. O paladar não é excessivamente expressivo, oferecendo maçã não amadurecida, frutas cítricas e sálvia seca, juntamente com uma acidez viva.
…e reconhecer que se trata de uma mistura branca? Alguns entusiastas do vinho podem reconhecer sinais indicadores de vinhos brancos, como maçã, frutas cítricas e uma acidez pronunciada, mas podemos treinar nossa rede neural para reconhecer esses sinais? Além disso, podemos treinar nossa rede neural para reconhecer as diferenças sutis entre uma revisão de mistura branca e uma revisão de pinot grigio?
Algoritmos Semelhantes
O problema com o qual estamos trabalhando hoje é essencialmente um problema de classificação de PNL. Existem vários algoritmos de classificação de PNL que foram aplicados a vários problemas em PNL. Por exemplo, naive Bayes foram usados em vários algoritmos de detecção de spam e máquinas de vetor de suporte (SVM) foram usadas para classificar textos como notas de progresso em instituições de saúde. Seria interessante implementar uma versão simples desses algoritmos para servir de base para nosso modelo de deep learning.
Baías ingénuas
Uma implementação popular do Naive Bayes para NLP envolve o pré-processamento do texto usando TF-IDF e, em seguida, a execução do Naive Bayes multinomial nas saídas pré-processadas. Isso permite que o algoritmo seja executado nas palavras mais proeminentes em um documento. Podemos implementar o Bayes ingênuo da seguinte forma:
import numpy as np from sklearn.naive_bayes import MultinomialNB from sklearn.feature_extraction.text import CountVectorizer import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfTransformer df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() varietal_list = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = np.array(varietal_list) count_vect = CountVectorizer() x_train_counts = count_vect.fit_transform(description_list) tfidf_transformer = TfidfTransformer() x_train_tfidf = tfidf_transformer.fit_transform(x_train_counts) train_x, test_x, train_y, test_y = train_test_split(x_train_tfidf, varietal_list, test_size=0.3) clf = MultinomialNB().fit(train_x, train_y) y_score = clf.predict(test_x) n_right = 0 for i in range(len(y_score)): if y_score[i] == test_y[i]: n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))Execute o código acima e você deverá ver algo como o seguinte: 73,56%

Considerando que estamos olhando para 10 classes, este é um resultado bastante bom.
Também podemos usar a máquina de vetores de suporte e ver como isso funcionaria. Para ver como ele funciona, basta substituir a definição do classificador por
clf = SVC(kernel='linear').fit(train_x, train_y)Execute isso e você deverá ver a seguinte saída:
Precisão: 80,66%
Não muito pobre também.
Vamos ver se podemos construir um modelo de aprendizado profundo que possa superar ou pelo menos igualar esses resultados. Se conseguirmos isso, seria uma ótima indicação de que nosso modelo de aprendizado profundo é eficaz em pelo menos replicar os resultados dos modelos populares de aprendizado de máquina informados pela experiência do domínio.
Construindo o Modelo
Hoje, usaremos Keras com Tensorflow para construir nosso modelo. Keras é uma biblioteca Python que facilita muito a criação de modelos de aprendizado profundo em comparação com a interface de nível relativamente baixo da API do Tensorflow. Além das camadas densas, também usaremos camadas de incorporação e convolucionais para aprender as informações semânticas subjacentes das palavras e possíveis padrões estruturais nos dados.
Limpeza de dados
Primeiro, teremos que reestruturar os dados de forma que possam ser facilmente processados e compreendidos por nossa rede neural. Podemos fazer isso substituindo as palavras por números de identificação exclusiva. Combinado com um vetor de incorporação, somos capazes de representar as palavras de maneira flexível e semanticamente sensível.
Na prática, queremos ser um pouco mais espertos sobre esse pré-processamento. Faria sentido focar nas palavras mais usadas e também filtrar as palavras mais usadas (por exemplo, the, this, a).
Podemos implementar essa funcionalidade usando Defaultdict e NLTK. Escreva o código a seguir em um módulo Python separado. Eu coloquei em lib/get_top_x_words.py .
from nltk import word_tokenize from collections import defaultdict def count_top_x_words(corpus, top_x, skip_top_n): count = defaultdict(lambda: 0) for c in corpus: for w in word_tokenize(c): count[w] += 1 count_tuples = sorted([(w, c) for w, c in count.items()], key=lambda x: x[1], reverse=True) return [i[0] for i in count_tuples[skip_top_n: skip_top_n + top_x]] def replace_top_x_words_with_vectors(corpus, top_x): topx_dict = {top_x[i]: i for i in range(len(top_x))} return [ [topx_dict[w] for w in word_tokenize(s) if w in topx_dict] for s in corpus ], topx_dict def filter_to_top_x(corpus, n_top, skip_n_top=0): top_x = count_top_x_words(corpus, n_top, skip_n_top) return replace_top_x_words_with_vectors(corpus, top_x)Agora estamos prontos para construir o modelo. Queremos uma camada de incorporação, uma camada convolucional e uma camada densa para aproveitar todos os recursos de aprendizado profundo que podem ser úteis para nosso aplicativo. Com Keras, podemos construir o modelo de forma muito simples:
from keras.models import Sequential from keras.layers import Dense, Conv1D, Flatten from keras.layers.embeddings import Embedding from keras.preprocessing import sequence from keras.utils import to_categorical import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from lib.get_top_xwords import filter_to_top_x df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() mapped_list, word_list = filter_to_top_x(description_list, 2500, 10) varietal_list_o = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = to_categorical(varietal_list_o) max_review_length = 150 mapped_list = sequence.pad_sequences(mapped_list, maxlen=max_review_length) train_x, test_x, train_y, test_y = train_test_split(mapped_list, varietal_list, test_size=0.3) max_review_length = 150 embedding_vector_length = 64 model = Sequential() model.add(Embedding(2500, embedding_vector_length, input_length=max_review_length)) model.add(Conv1D(50, 5)) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dense(max(varietal_list_o) + 1, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(train_x, train_y, epochs=3, batch_size=64) y_score = model.predict(test_x) y_score = [[1 if i == max(sc) else 0 for i in sc] for sc in y_score] n_right = 0 for i in range(len(y_score)): if all(y_score[i][j] == test_y[i][j] for j in range(len(y_score[i]))): n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))Execute o código e você deverá ver a seguinte saída.
Precisão: 77,20%
Lembre-se de que a precisão para Bayes ingênuo e SVC foi de 73,56% e 80,66%, respectivamente. Portanto, nossa rede neural está se mantendo muito bem em relação a alguns dos métodos de classificação de texto mais comuns existentes.
Conclusão
Hoje, abordamos a construção de um modelo de aprendizado profundo de classificação para analisar avaliações de vinhos.
Descobrimos que conseguimos construir um modelo capaz de competir e superar alguns dos outros algoritmos de aprendizado de máquina. Esperamos que você se inspire a usar essas informações para criar aplicativos que analisem conjuntos de dados mais complexos e gerem saídas mais complexas!
Observação: você pode encontrar o código que usei para este artigo no GitHub.
Leitura adicional no Blog da Toptal Engineering:
- Um significado mais profundo: modelagem de tópicos em Python
- Como construir um bot de análise de sentimento de e-mail: um tutorial de PNL
