1. Введение
В предыдущих статьях мы рассмотрели теоретические основы NLP, включая базовые понятия, такие как токенизация, стемминг, лемматизация и другие. Мы также поработали с библиотеками NLTK и spaCy и выполнили простые задания по обработке текста.
В этой статье мы продолжим изучение NLP и перейдем к более продвинутым темам, которые являются главными для построения современных приложений и моделей в области обработки естественного языка. А также создадим и обучим модели самостоятельно, используя TensorFlow/Keras и PyTorch.
2. Векторные представления слов
Векторные представления слов позволяют нам преобразовывать слова в числовые векторы. Это существенно улучшает качество моделей NLP.
В данной статье мы рассмотрим:
-
Word2Vec
-
GloVe
-
FastText
-
Библиотеку Gensim
-
Примеры кода и задания
2.1 Word2Vec
Word2Vec — это группа моделей, которую разработала команда Google. Word2Vec преобразует слова в векторы определённой размерности, где схожие по смыслу слова имеют близкие векторные представления.
Архитектуры Word2Vec
Word2Vec представляет два основных метода обучения:
-
Continuous Bag-of-Words (CBOW): предсказывает текущее слово по контексту (окружающим словам).
-
Skip-Gram: предсказывает окружающие слова по текущему слову.
Особенности
-
Эффективность: Быстро обучается на больших объёмах текстах.
-
Качество: Учитывает семантические отношения между словами.
2.2 GloVe
Glove — это модель, разработанная в Стэнфордском университете. В отличие от Word2Vec, который фокусируется на локальных связях между словами, а GloVe фокусируется на глобальных связях, проверяя, насколько часто два слова встречаются вместе в тексте.
Особенности
-
Глобальная матрица соотношений — это способ увидеть, как слова связаны между собой в целом по всем текстам, проверяя, как часто они появляются вместе.
-
Преимущества: GloVe лучше понимает общую структуру и тематику текста, что особенно полезно, когда важно понять глобальные связи и темы в большом количестве данных.
2.3 FastText
FastText — модель, разработанная Facebook AI Research. Она расширяет Word2Vec, учитывая морфологию слов.
Особенности
-
Символьные n-граммы: Представляет слова как группу буквенных n-грамм.
-
Преимущества: Лучше справляется с редкими словами и опечатками.
2.4 Реализация и применение с помощью Gensim
Gensim — это библиотека Python для для векторных представлений.
Установка Gensim
pip install gensim
2.5 Word2Vec с использованием Gensim
Для начала подготовим наши данные:
import gensim from gensim.models import Word2Vec from gensim.utils import simple_preprocess texts = [ "Хабр — популярная платформа для IT специалистов", "На Хабре можно найти статьи по программированию и технологиям", "Пользователи Хабра делятся своим опытом и знаниями", ] # Предобработка текстов sentences = [simple_preprocess(text) for text in texts]
Обучим нашу модель Word2Vec:
model = Word2Vec( sentences=sentences, vector_size=100, # размерность текстов window=5, # размер контекстного окна min_count=1, # минимальную частоту слова workers=4, # количество потоков sg=0 # использование Continuous Bag-of-Words )
Получение вектора слова:
vector = model.wv['хабр'] print("Вектор слова 'хабр':\n", vector)
Вывод:
Вектор слова 'хабр': [ 0.00973555 -0.00978038 -0.00649949 0.00278379 0.00643199 -0.00536737 0.00275249 0.00912131 -0.00681542 -0.00609991 -0.00498964 -0.00367641 0.00184972 0.00968263 0.00643778 0.00039709 0.00247077 0.00844049 0.00912898 0.00562875 0.00594626 -0.00762069 -0.00382767 -0.00568033 0.00618177 -0.00225645 -0.00877944 0.00761912 0.00839968 -0.00332024 0.00911666 -0.00073836 -0.00362652 -0.00038469 0.00019443 -0.0035049 0.00281324 0.00572971 0.00686901 -0.00890347 -0.00219273 -0.0054818 0.0075211 0.0065017 -0.00436072 0.00232683 -0.00595366 0.0002365 0.00946176 -0.00260984 -0.00518772 -0.00739721 -0.00291194 -0.00086431 0.00352786 0.00974189 -0.00338928 0.00190177 0.00968101 0.00153159 0.0009865 0.00980237 0.00929546 0.00770807 -0.00617053 0.00998399 0.00584899 0.00907267 -0.0019952 0.00334994 0.00683356 -0.00389376 0.00664285 0.00256286 0.00931373 -0.0030358 -0.00310937 0.00621539 -0.00907825 -0.00725399 -0.00650003 -0.00074907 -0.00236302 0.00681552 0.00923659 -0.00090976 0.00141282 0.00202036 -0.0020198 -0.00803434 0.00744105 -0.0042979 0.00457652 0.0090897 0.00304322 0.00313879 0.00406183 -0.00270122 0.00382477 0.00033762]
Поиск наиболее похожих слов:
similar_words = model.wv.most_similar('хабр') print("Слова, похожие на 'хабр':") for word, similarity in similar_words: print(f"{word}: {similarity}")
Вывод:
Слова, похожие на 'хабр': можно: 0.15923377871513367 популярная: 0.1528114527463913 технологиям: 0.14256368577480316 статьи: 0.1326463520526886 своим: 0.1193675547838211 на: 0.07913301885128021 специалистов: 0.07480262219905853 делятся: 0.059599656611680984 по: 0.03546776622533798 для: 0.03307188302278519
2.5 FastText с использованием Gensim
Обучение модели:
from gensim.models import FastText ft_model = FastText( vector_size=100, window=5, min_count=1, workers=4 ) ft_model.build_vocab(corpus_iterable=sentences) ft_model.train( corpus_iterable=sentences, total_examples=len(sentences), epochs=10 )
Поиск похожих слов:
similar_words_ft = ft_model.wv.most_similar('хабр') print("Слова, похожие на 'хабр':") for word, similarity in similar_words_ft: print(f"{word}: {similarity:.3f}")
Вывод:
Слова, похожие на 'хабр': хабра: 0.514 хабре: 0.421 пользователи: 0.046 найти: 0.045 технологиям: 0.041 специалистов: 0.019 по: 0.016 делятся: 0.010 на: -0.002 статьи: -0.034
3. Классификация текста с помощью scikit-learn
Основные шаги класcификации текста:
-
Сбор данных
-
Предобработка данных
-
Преобразование текста в числовой формат
-
Обучение модели
-
Оценка модели
-
Применение модели
3.1 Работа с размеченными данными
Размеченные данные — это данные, где каждому экземпляру соответствует метка или категория.
Источники размеченных данных
-
Многие наборы данных доступны в библиотеке
sklearn.datasets
илиnltk
. -
Также существуют публичные датасеты. Для этого я советую Kaggle, где обычные пользователи делятся наборами данных.
3.2 Оценка качества моделей
Метрики оценки
-
Точность (Accuracy): Показывает, какую долю всех предсказаний модель сделала правильно.
-
Матрица ошибок (Confusion Matrix): Таблица, которая показывает, сколько раз модель правильно или неправильно предсказала каждый класс.
-
Precision: Определяет сколько из всех примеров, которые модель предсказала как положительные, на самом деле положительные.
-
Recall: Определяет, сколько из всех реальных положительных примеров, модель обнаружила.
-
F1-score: Среднее значение между Precision и Recall.
Валидация моделей
-
Тренировочные и тестовые данные: Разделение данных на обучающую и тестовую выборки.
-
Кросс-валидация: Разделение данных на K подвыборок и обучение модели K раз.
3.3 Примеры кода
Классификация текстов новостей из 20 Newsgroups датасета
Этот набор данных представляет собой коллекцию документов группы новостей.
Импорт библиотек:
import numpy as np from sklearn.datasets import fetch_20newsgroups from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
Загрузка данных:
categories = ['rec.sport.baseball', 'rec.sport.hockey', 'talk.politics.mideast', 'sci.space'] newsgroups = fetch_20newsgroups(subset='all', categories=categories) X = newsgroups.data #тексты y = newsgroups.target #метки
Разделение на обучающую и тестовую выборки:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Преобразование текста в числовой формат:
tfidf_vectorizer = TfidfVectorizer(stop_words='english', lowercase=True) X_train_tfidf = tfidf_vectorizer.fit_transform(X_train) X_test_tfidf = tfidf_vectorizer.transform(X_test)
Обучение модели с использованием байесовского классификатора:
model = MultinomialNB() model.fit(X_train_tfidf, y_train)
Прогнозирование и оценка модели:
y_pred = model.predict(X_test_tfidf) # Прогнозирование на тестовой выборке print("Accuracy:", accuracy_score(y_test, y_pred)) # Оценка точности print(classification_report(y_test, y_pred, target_names=newsgroups.target_names))
Вывод:
Построение матрицы ошибок:
import matplotlib.pyplot as plt import seaborn as sns cm = confusion_matrix(y_test, y_pred) sns.heatmap(cm, annot=True, fmt='d', xticklabels=newsgroups.target_names, yticklabels=newsgroups.target_names) plt.ylabel('Истинный класс') plt.xlabel('Предсказанный класс') plt.show()
Вывод:
4. Нейронные сети для NLP
Нейронные сети — это мощный инструмент для решения сложных задач в различных сферах. Они постоянно готовы адаптироваться и обучаться, что делает их очень полезными для работы с большими данными.
Основные компоненты
-
Входной слой: Получает данные.
-
Скрытые слои: Обрабатывают эти данные, выявляя в них важные особенности.
-
Выходной слой: Выдаёт результат — ответ или предсказание.
-
Активирационные функции: Позволяют нейронной сети понимать и представлять сложные, нелинейные зависимости в данных.
-
Функция потерь: Показывает, насколько хороша модель, сравнивая предсказания с реальными данными.
-
Оптимизаторы: Это алгоритмы, которые помогают модели учиться на своих ошибках, корректируя параметры для улучшения точности.
Процесс обучения
-
Прямое распространение (forward propagation): Процесс, при котором входные данные проходят через нейронную сеть от входного слоя к выходному, чтобы сделать предсказание.
-
Обратное распространение (backpropagation): Алгоритм обучения нейронной сети, при котором сеть корректирует свои веса, чтобы уменьшить ошибку между предсказанием и реальным ответом.
4.2 Рекуррентные нейронные сети (RNN)
Рекуррентные нейронные сети — это модели, которые могут помнить предыдущие данные при обработке последовательностей. Они используют информацию из прошлого для улучшения понимания настоящего и будущего элементов.
Проблемы стандартных RNN
-
Ванишинг градиент (исчезающий градиент): при обучении на длинных последовательностях градиенты могут становиться слишком малыми, затрудняя обучение.
-
Эффективность на коротких последовательностях: стандартные RNN хорошо работают с короткими последовательностями, но плохо на длинных.
4.3 LSTM и GRU
LSTM (Long Short-Term Memory) — это разновидность RNN, разработанная для решения проблемы исчезающего градиента.
Компоненты LSTM
-
Входные ворота: Контролируют, какую новую информацию добавить в текущее состояние памяти нейрона в LSTM-сети.
-
Забывающие ворота: Контролируют, какую информацию удалить из состояния памяти.
-
Выходные ворота: Контролируют, какую информацию из состояния памяти использовать для текущего вывода.
GRU (Gated Recurrent Unit) — упрощенная версия LSTM с меньшим количеством ворот, которая зачастую показывает схожие результаты.
Компоненты GRU
-
Ворот обновления: Контролирует, какую часть информации из памяти сохранить, а какую обновить с новой информацией.
-
Ворот сброса: Контролирует, какую часть предыдущей информации забыть при вычислении нового состояния.
4.4 Трансформеры (BERT, GPT)
Трансформеры — это мощные модели, которые используют механизм внимания для эффективной обработки последовательностей данных. Они способны фокусироваться на важных частях входной информации, независимо от их позиции, что позволяет им лучше понимать контекст и сложные взаимосвязи.
Ключевые компоненты
-
Механизм внимания (Attention Mechanism): Позволяет модели определять, на какие части входных данных обратить больше внимания при обработке.
-
Многоголовое внимание (Multi-Head Attention): Это расширение механизма внимания, которое позволяет модели фокусироваться на разных факторах последовательности одновременно.
-
Фидфорвард слои: Это обычные полносвязные нейронные слои, которые применяются к каждому элементу последовательности отдельно.
Преимущества трансформеров
-
Параллельная обработка: позволяет обучать модели быстрее при использовании GPU.
-
Эффективная работа с длинными зависимостями: механизм внимания эффективно обрабатывает связи между отдаленными элементами.
BERT (Bidirectional Encoder Representations from Transformers)
-
BERT — модель на основе трансформеров, обученная на большом объеме текстов.
-
Двухнаправленная: учитывает контекст как слева, так и справа от целевого слова.
-
Применение: задачи NLP, такие как классификация текста, ответы на вопросы и т.д.
GPT (Generative Pre-trained Transformer)
-
GPT — серия моделей от OpenAI, использующих архитектуру трансформеров.
-
Однонаправленная: предсказывает следующее слово на основе предыдущих.
-
GPT o1, GPT 4, GPT 3: мощные модели, способные генерировать связный и осмысленный текст.
5. Реализация простых моделей с использованием TensorFlow/Keras
Установка библиотек:
pip install tensorflow
Импорт библиотек:
import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import SimpleRNN, Dense, Embedding from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.preprocessing.text import Tokenizer
Подготовка данных:
texts = [ "Хабр — популярная платформа для IT-специалистов", "На Хабре можно найти статьи по программированию и технологиям", "Пользователи Хабра делятся своим опытом и знаниями", "Хабр помогает разработчикам узнавать о новых технологиях", "Не все статьи на Хабре полезны", "Иногда на Хабре сложно найти нужную информацию", "Хабр может быть сложен для понимания новичками", "Некоторые статьи на Хабре слишком технически сложны" ] labels = [1, 1, 1, 1, 0, 0, 0, 0] # Метки (0 - негативный, 1 - позитивный) labels = np.array(labels, dtype='float32') # Преобразуем метки в numpy.ndarray
Токенизация текста:
tokenizer = Tokenizer() tokenizer.fit_on_texts(texts) sequences = tokenizer.texts_to_sequences(texts) word_index = tokenizer.word_index # Словарь print("Размер словаря:", len(word_index))
Вывод:
Размер словаря: 28
Паддинг последовательностей:
maxlen = 10 data = pad_sequences(sequences, maxlen=maxlen)
Создание модели:
model = Sequential() model.add(Embedding(input_dim=len(word_index) + 1, output_dim=32)) model.add(SimpleRNN(32)) model.add(Dense(1, activation='sigmoid'))
Компиляция модели:
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
Обучение модели:
model.fit(data, labels, epochs=10)
Вывод:
Давайте проверим, как работает обученная модель на новых данных.
Подготовим новые тексты для проверки:
test_texts = [ "Я нашёл полезную статью на Хабре о машинном обучении", "На Хабре слишком много сложной информации для меня", "Статьи на Хабре помогают мне развиваться как программисту", "Иногда Хабр бывает непонятен новичкам в IT", "Обожаю читать обзоры новых технологий на Хабре", "На Хабре мало информации по интересующей меня теме", "Хабр - отличный ресурс для IT-специалистов", "Сложно разобраться в статьях на Хабре без подготовки", ]
Преобразуем новые тексты так же, как и обучающие данные:
test_sequences = tokenizer.texts_to_sequences(test_texts) # Преобразуем тексты в последовательности test_data = pad_sequences(test_sequences, maxlen=maxlen) print("Преобразованные тестовые последовательности:") print(test_data)
Вывод:
Сделаем предсказания на новых данных:
predictions = model.predict(test_data)
Вывод:
Выведем результаты предсказаний:
threshold = 0.5 # Порог классификации for i, text in enumerate(test_texts): prediction = predictions[i][0] predicted_label = "Позитивный" if prediction >= threshold else "Негативный" print(f"Текст: {text}") print(f"Предсказание: {prediction:.4f}") print(f"Класс: {predicted_label}") print("-" * 50)
Вывод:
6. Теперь рассмотрим реализацию LSTM c использованием PyTorch
Установка библиотек:
pip install torch
Импорт библиотек:
import numpy as np import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset from tensorflow.keras.preprocessing.text import Tokenizer
Подготовка данных:
texts = [ "Хабр — популярная платформа для IT-специалистов", "На Хабре можно найти статьи по программированию и технологиям", "Пользователи Хабра делятся своим опытом и знаниями", "Хабр помогает разработчикам узнавать о новых технологиях", "Не все статьи на Хабре полезны", "Иногда на Хабре сложно найти нужную информацию", "Хабр может быть сложен для понимания новичками", "Некоторые статьи на Хабре слишком технически сложны" ] labels = [1, 1, 1, 1, 0, 0, 0, 0] labels = np.array(labels, dtype='float32') # Преобразуем метки в массив NumPy maxlen = 10 # Параметр максимальной длины последовательности tokenizer = Tokenizer() # Токенизация текста tokenizer.fit_on_texts(texts) word_index = tokenizer.word_index print("Размер словаря:", len(word_index))
Определение класса Dataset:
class TextDataset(Dataset): def __init__(self, texts, labels, tokenizer, maxlen): self.texts = texts self.labels = labels self.tokenizer = tokenizer self.maxlen = maxlen def __len__(self): return len(self.texts) def __getitem__(self, idx): text = self.texts[idx] #Получаем текст label = self.labels[idx] #Получаем метку sequence = self.tokenizer.texts_to_sequences([text])[0] # Преобразуем текст в последовательность токенов if len(sequence) < self.maxlen: # Применяем паддинг или обрезку последовательности sequence = np.pad(sequence, (0, self.maxlen - len(sequence)), 'constant') else: sequence = sequence[:self.maxlen] sequence = torch.tensor(sequence, dtype=torch.long) # Преобразуем в тензоры PyTorch label = torch.tensor(label, dtype=torch.float32) return sequence, label
Определение модели LSTM:
class LSTMModel(nn.Module): def __init__(self, vocab_size, embedding_dim, hidden_dim): super(LSTMModel, self).__init__() self.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim) self.lstm = nn.LSTM(input_size=embedding_dim, hidden_size=hidden_dim, batch_first=True) self.linear = nn.Linear(hidden_dim, 1) self.sigmoid = nn.Sigmoid() def forward(self, x): # x имеет размерность (batch_size, maxlen) embeds = self.embedding(x) # embeds имеет размерность (batch_size, maxlen, embedding_dim) lstm_out, (hn, cn) = self.lstm(embeds) out = self.linear(hn[-1]) #Используем скрытый слой out = self.sigmoid(out) return out
Подготовка DataLoader и модели:
from torch.utils.data import DataLoader dataset = TextDataset(texts, labels, tokenizer, maxlen) # Создаём датасет dataloader = DataLoader(dataset, batch_size=2, shuffle=True) # Создаём загрузчик данных vocab_size = len(word_index) + 1 embedding_dim = 32 hidden_dim = 32 model = LSTMModel(vocab_size, embedding_dim, hidden_dim) # Инициализируем модель criterion = nn.BCELoss() # Инициализируем функцию потерь optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Инициализируем оптимизатор
Обучение модели:
model.train() num_epochs = 10 for epoch in range(num_epochs): total_loss = 0 for sequences, labels_batch in dataloader: optimizer.zero_grad() outputs = model(sequences) # Прямой проход outputs = outputs.squeeze() loss = criterion(outputs, labels_batch) # Вычисляем потерю loss.backward() # Обратный проходоптимизация optimizer.step() # Оптимизация total_loss += loss.item() avg_loss = total_loss / len(dataloader) print(f"Эпоха {epoch+1}, Потеря: {avg_loss:.4f}")
Вывод:
Проверим модель на новых данных:
test_texts = [ "Хабр предоставляет отличные возможности для обучения", "Некоторые статьи на Хабре трудно понять", ] test_sequences = [] # Преобразуем тексты в последовательности for text in test_texts: sequence = tokenizer.texts_to_sequences([text])[0] if len(sequence) < maxlen: sequence = np.pad(sequence, (0, maxlen - len(sequence)), 'constant') else: sequence = sequence[:maxlen] test_sequences.append(sequence) test_sequences = torch.tensor(test_sequences, dtype=torch.long) # Преобразуем в тензор model.eval() # Переводим модель в режим оценки with torch.no_grad(): outputs = model(test_sequences) predictions = outputs.squeeze().numpy() threshold = 0.5 for i, text in enumerate(test_texts): prediction = predictions[i] predicted_label = "Позитивный" if prediction >= threshold else "Негативный" print(f"Текст: {text}") print(f"Предсказание: {prediction:.4f}") print(f"Класс: {predicted_label}") print("-" * 50)
Вывод:
7. Вывод
В ходе данной статьи мы подробно изучили основные концепции и методы, используемые в области обработки естественного языка. Рассмотренные темы охватывают большое количество инструментов и технологий, которые позволяют эффективно работать с текстовыми данными и решать различные задачи анализа и понимания естественного языка. В следующих статьях мы займёмся реализацией небольших проектов. Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/864912/
Добавить комментарий