Производственная практика проходила в Московском университете им. С.Ю. Витте (далее - Университете) на кафедре информационных систем по профилю Искусственный интеллект и анализ данных направления 09.03.03 Прикладная информатика с 21 октября по 29 декабря 2024 года. В рамках настоящего курсового проекта была выбрана предметная область «Применение нейронных сетей для анализа тональности сообщений в социальных сетях». Ее актуальность объясняется полезностью получаемых в результате работы нейросети данных при мониторинге общественного мнения, анализа отзывов клиентов и пользователей и выявления эмоционального настроя аудитории. Применение нейросетей позволит автоматизировать классификацию сообщений на положительные и отрицательные, что существенно ускорит обработку больших объемов данных и повысит качество принимаемых решений в маркетинге и аналитике.
Цель практики
Целью ставится углубленное изучение современных методов и инструментов разработки нейронных сетей с применением языка программирования Python, а также получение и закрепление навыков их применения при проектировании нейросетей.
Задачи практики
В ходе практики необходимо решить ряд организационных вопросов, таких как организация рабочего места и установка необходимого программного обеспечения разработчика.
Затем необходимо выполнить следующие шаги:
Проанализировать предметную область и ее теоретические аспекты. Записать математическую модель нейронной сети.
Разработать и протестировать нейронную сеть, предварительно выбрав наиболее подходящую топологию и параметры.
Собрать и подготовить данные для обучения модели. Подготовить данные к использованию – обработать и нормализировать.
Обучить нейронную сеть и оценить качество ее работы.
Выполнить анализ результатов работы созданной нейронной сети и дать рекомендации по ее улучшению.
Источники информации и исходный код
Источниками информации явились различные учебные пособия по нейронным сетям, научные статьи и тематические материалы Kaggle и GitHub. Очень сильно помогли в решении задач курсового проекта открытые датасеты и доступные примеры реализации модели текстовых данных. Для своего проекта я использовал датасет Sentiment140, содержащий 1,6 млн. твитов.
Ссылка на исходный код и датасеты:
Датасет: https://www.kaggle.com/datasets/kazanova/sentiment140.
Исходный код: .
Основная часть
Анализ предметной областИ
Выбор и развертывание среды разработки для языка программирования Python
Для написания кода нейронной сети я выбрал среду разработки Intellij IDEA с установленным плагином Python (рис. 1). В этой среде удобный интерфейс для написания кода, его отладки и проведения тестирования. Присутствуют такие инструменты как автозавершение кода, интеграция с Git, и возможности создания виртуального окружения.
Рисунок 1 – Окно создания проекта в IDEA
При создании проекта автоматически было настроено виртуальное окружение с выбранной версией Python 3.11. Выбор данной версии обусловлен необходимостью обеспечения совместимости всех используемых в проекте библиотек.
После создания окружения были установлены (рис. 2) основные используемые в проекте библиотеки:
TensorFlow – для создания и обучения нейросетей.
Keras – для более удобного интерфейса с TensorFlow.
NumPy и Pandas – для работы с данными.
Matplotlib – для визуализации данных и результатов обучения.
Рисунок 2 – Завершение установки необходимых пакетов и их зависимостей
После завершения установки библиотек следует убедиться в ее корректности, как показано на рисунке 3.
Рисунок 3 – Проверка корректности установки библиотек
Как видно, все пакеты установлены корректно.
Анализ теоретических аспектов создания нейросетей
Рассмотрим основные компоненты нейронной сети, типы нейронных сетей и где они применяются.
Нейронный сети – это математические модели, структура которых навеяна биологическими нейронными сетями, например – мозг человека.
Основные компоненты нейронной сети:
Нейроны. Это главная составляющая нейронной сети. Они принимают данные на входе, обрабатывают их по выбранному алгоритму и передают результат далее – на следующий слой нейронной сети. Нейроны состоят из перечисленных ниже частей:
Входы (inputs). Каждый вход имеет свой вес, по которому определяется важность этого входа. И входное значение умножается на вес входа. Это называется взвешиванием.
Сумматор (summation). Здесь происходит суммирование всех взвешенных входов.
Функция активации (activation functon). Полученная сумма входов передается в фукнцию, в которой происходит вычисление для принятия решения о передаче сигнала далее. Функции активации могут быть – сигмода, гиперболический тангенс, ReLU и другие.
Слои.
Входной слой. Принимает данные и передает их на следующий слой.
Скрытые слои. Один или несколько слоев, в которых данные обрабатываются нейронами.
Выходной слой. Выводит прогнозное значение или идентифицирует класс.
Весовые коэффициенты(weights). Параметры, задающие важность входа. Они изменяются в процессе обучения модели с целью минимизации ошибки модели.
Ошибка (error). Это разница между ожидаемым и полученным результатом работы модели. Она используется при оптимизации весов во время обучения модели.
Типы нейросетей и области их применения:
Перцептрон (Perceptron). Это самая простая нейросеть. Она состоит из одного слоя нейронов. Применяется для задач бинарной классификации (классификация изображений, задачи с двумя категориями) и использует алгоритм градиентного спуска для обучения.
Многослойный перцептрон (Multi-Layer Perceptron). Может решать задачи сложнее (классификация, регрессия, работа с временными рядами), благодаря наличию нескольких скрытых слоев.
Сверточные нейронные сети. Используют свертку для извлечения особенностей из входных данных. Слои свертки находят признаки в данных – текстуры, формы, края и т.п. Применяются для распознавания изображений, видеоанализа, в автономном транспорте.
Рекуррентные нейронные сети. Эти сети сохраняют информацию о предыдущих шагах. Это дает возможность учитывать контекст и применять такие нейронные сети для обработки текста, анализа временных рядов и распознавания речи.
Автокодировщики. Такие сети обучены сжимать данные и восстанавливать их обратно и используются при извлечении признаков и/или для уменьшения размерности при обработке изображений, сжатии данных и восстановлении поврежденных данных.
Генеративно-состязательные сети. С их помощью создаются фальшивые изображения и, наоборот, фальшивые изображения отличаются от настоящих. Эти сети могут генерировать музыку и улучшать качество изображений.
Сети с долгой короткой памятью. Это рекуррентные нейронные сети со способностью запоминания контекста в большем объеме, чем обычные. С их помощью можно добиться лучшего качества обработки текста, прогнозирования временных рядов и переводов текста.
Нейронные сети, как мы видим – мощный инструмент для решения различных задач во многих областях, от анализа изображений и обработки текста до прогнозирования временных рядов.
Математическая модель нейронной сети
Для решения задачи настоящего курсового проекта при построении и обучении нейросети будем использовать сеть с долгой короткой памятью, состоящего из четырех слоев – входного, двух скрытых слоев различной размерности и входного слоя.
Каждый нейрон в скрытом и выходном слое рассчитывает взвешенную сумму входов и передает ее в функцию активации. Формализуем это:
где:
z — выход нейрона (перед активацией);
wi — вес, соответствующий i-му входу;
xi — i-й входной сигнал;
b — смещение (bias).
Полученная взвешенная сумма проходит через функцию активации σ(z):
В своем проекте я использовал функцию активации ReLU:
Эта функция выбрана за простоту, высокую скорость и эффективность.
Описание математической модели можно вывести при допущении, что модель имеет два скрытых слоя из m нейронов и выходной слой из k нейронов.
Тогда выход скрытого слоя будет выглядеть как:
А выходной слой:
где: и – веса между слоями, и – смещения.
Эта математическая модель нейросети учитывает принципы работы нейронов, включает функцию активации и отражает алгоритм обучения.
Выводы по разделу
В ходе анализа предметной области определены основные теоретические аспекты построения нейронных сетей. В том числе была выбрана и настроена среда разработки, построена математическая модель нейросети для решения задач курсовой работы по выбранной предметной области.
Проведено обследование предметной области. В результате проведенного обследования можно сделать следующие выводы (табл.1):
Таблица 1 – Выводы по разделу 2.1
РАЗРАБОТКА НЕЙРОННОЙ СЕТИ
Создание нейронов
В разрабатываемой модели нейросети используется нейрон, применяемый в рекуррентных нейронных сетях и который позволяет запоминать зависимости – LSTM нейроны. Такая способность делает эти нейроны подходящими для анализа текста.
Код нейрона может быть следующим:
import tensorflow as tf
from keras import layers, models
# Создание простого нейрона LSTM вручную
class CustomLSTMCell(tf.keras.layers.Layer):
def __init__(self, units):
super(CustomLSTMCell, self).__init__()
self.units = units
self.state_size = [units, units] # Состояние состоит из двух частей: h (выход) и c (cell state)
# Веса для forget, input, output и candidate
self.W_f = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='W_f')
self.W_i = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='W_i')
self.W_o = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='W_o')
self.W_c = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='W_c')
self.U_f = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='U_f')
self.U_i = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='U_i')
self.U_o = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='U_o')
self.U_c = self.add_weight(shape=(units, units), initializer='glorot_uniform', name='U_c')
self.b_f = self.add_weight(shape=(units,), initializer='zeros', name='b_f')
self.b_i = self.add_weight(shape=(units,), initializer='zeros', name='b_i')
self.b_o = self.add_weight(shape=(units,), initializer='zeros', name='b_o')
self.b_c = self.add_weight(shape=(units,), initializer='zeros', name='b_c')
def call(self, inputs, states):
h_prev, c_prev = states
# Обработка входных данных (inputs)
f = tf.sigmoid(tf.matmul(inputs, self.W_f) + tf.matmul(h_prev, self.U_f) + self.b_f) # Forget gate
i = tf.sigmoid(tf.matmul(inputs, self.W_i) + tf.matmul(h_prev, self.U_i) + self.b_i) # Input gate
o = tf.sigmoid(tf.matmul(inputs, self.W_o) + tf.matmul(h_prev, self.U_o) + self.b_o) # Output gate
c_tilda = tf.tanh(tf.matmul(inputs, self.W_c) + tf.matmul(h_prev, self.U_c) + self.b_c) # Candidate value
# Обновление cell state (c) и hidden state (h)
c = f * c_prev + i * c_tilda # Cell state update
h = o * tf.tanh(c) # Hidden state
return h, [h, c]
# Пример использования CustomLSTMCell
units = 64
model = models.Sequential()
model.add(layers.Input(shape=(None, 100))) # Входной слой (последовательности)
model.add(layers.RNN(CustomLSTMCell(units))) # Добавляем кастомный LSTM-нейрон
model.add(layers.Dense(1, activation='sigmoid')) # Выходной слой
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
Выбор топологии сети
Топология нейросети описывает соединения нейронов в слоях. В соответствии с ранее описанной математической моделью, наша нейросеть будет включать слои:
Входной слой, на который подается вектор признаков, полученный из текста. Длина вектора = 100
Скрытые слои из 64 и 32 нейронов, применяющих функцию активации ReLU.
Выходной слой. Состоит из одного нейрона, выдающего значения от 0 до 1 (функция активации - сигмоида), равное вероятности положительного отзыва. Чем ближе значение к 1, тем вероятнее, что отзыв положительный.
Определившись с топологией сети, можно перейти к ее созданию.
Создание нейронной сети
Создание нейросети на языке Python с использованием библиотек Tensorflow и Keras – довольно простая процедура, особенно, если следовать инструкциям к указанным библиотекам.
Ниже представлен код, создающий нейросеть:
# Функция для создания модели с изменяемыми гиперпараметрами
def build_model(hp):
model = models.Sequential()
model.add(layers.Embedding(input_dim=10000, output_dim=128, input_length=100))
model.add(layers.LSTM(units=hp.Int('units', min_value=32, max_value=128, step=32)))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])),
loss='binary_crossentropy',
metrics=['accuracy']
)
return model
Здесь сначала создается пустая последовательная модель model = models.Sequential() в которую потом последовательно добавляются слои нужного типа и в необходимом порядке:
Входной слой model.add(layers.Embedding(input_dim=10000, output_dim=128, input_length=100)) в котором тектс преобразуется в векторное представление. Для этого слоя задается размер словаря input_dim=10000, размерность вектора для каждого слова output_dim=128, длину входной последовательности input_length=100 (каждый текст будет представляться последовательностью из 100 слов, но в случае более короткой последовательности – она будет дополнена с помощью паддинга).
Первый слой LSTM model.add(layers.LSTM(64, return_sequences=True)) – рекуррентный слой с 64-мя нейронами, который возвращает последовательность выходных данных на каждом шаге return_sequences=True. Это необходимо для последующего слоя, поскольку он также является рекуррентным.
Второй слой model.add(layers.LSTM(32)). Этот слой принимает последовательности от предыдущего слоя и выдает итоговое значение на следующий слой.
Выходной слой model.add(layers.Dense(1, activation='sigmoid')). Полносвязный слой с нейроном, применяющим сигмоидную функцию активации для вывода вероятности принадлежности к одному из классов.
Группировка нейронных блоков в нейронную сеть
Созданную в п. 1.2.4 модель необходимо сгруппировать или, другими словами – скомпилировать:
# Компиляция модели
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])),
loss='binary_crossentropy',
metrics=['accuracy']
# Перестроение модели с лучшими параметрами
best_model = tuner.hypermodel.build(best_hps)
Здесь применяется оптимизатор optimizer='adam', выбор на который пал благодаря его скорости и эффективности. Функция потерь loss='binary_crossentropy' подходит для бинарной классификации, которую мы и выполняем.
Экспериментальный подбор характеристик сети
Подбор характеристик включает в себя настройку гиперпарметров – слоев, количества нейронов, типов активации и оптимизатора.
В настоящем курсовом проекте выбран оптимизатор Adam в виду его стабильности и эффективности. Можно также поэкспериментировать с другими - SGD, RMSProp, AdaGrad. Это может улучшить результат обучения модели.
Для подбора параметров можно использовать код ниже:
# Настройка Bayesian Optimization
tuner = kt.BayesianOptimization(
build_model,
objective='val_accuracy',
max_trials=5, # Количество попыток подбора параметров
directory='bayes_opt_dir',
project_name='sentiment140_bayes_opt'
)
# Поиск гиперпараметров
tuner.search(X_train_padded, y_train, epochs=3, validation_data=(X_test_padded, y_test))
# Получение лучших гиперпараметров
best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]
print(f"Лучшие параметры: Units: {best_hps.get('units')}, Learning Rate: {best_hps.get('learning_rate')}")
Здесь для поиска лучших параметров создается тюнер Bayesian Optimization tuner = kt.BayesianOptimization(…) и выполняется подбор параметров с обучением модели на каждой итерации из 3 (epochs=3).
После завершения поиска гиперпараметров, лучшие извлекаются из всех результатов испытаний и выводятся на экран. Далее эти параметры будут использованы при обучении нашей сети.
Сбор и нормализация данных для обучения нейронной сети
Прежде чем приступить к обучению нейросети необходимо подготовить данные – собрать их, привести к нужному виду и нормализовать.
Для решения задач настоящей курсовой работы в рамках выбранной предметной области данные были получены из предлагаемого платформой Kaggleготового датасета Sentiment140, содержащего 1,6 млн. твитов (сообщений). Такого объема может быть вполне достаточно для целей и задач моего проекта.
Ниже представлен код для получения данных, их токенизации и нормализации.
# Загрузка последней версии датасета Sentiment140 через kagglehub
path = kagglehub.dataset_download("kazanova/sentiment140")
# Путь к данным
data_path = os.path.join(path, 'training.1600000.processed.noemoticon.csv')
# Проверка существования файла
if os.path.exists(data_path):
data = pd.read_csv(data_path, encoding='latin1', names=['target', 'id', 'date', 'flag', 'user', 'text'])
print("Данные успешно загружены")
else:
raise FileNotFoundError(f"Файл не найден: {data_path}")
# Преобразование целевой переменной и удаление ненужных столбцов
data['target'] = data['target'].apply(lambda x: 1 if x == 4 else 0)
data = data[['text', 'target']]
# Разделение данных на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(data['text'], data['target'], test_size=0.2, random_state=42)
# Нормализация текста с помощью Tokenizer
tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=10000)
tokenizer.fit_on_texts(X_train)
X_train_seq = tokenizer.texts_to_sequences(X_train)
X_test_seq = tokenizer.texts_to_sequences(X_test)
# Паддинг последовательностей
X_train_padded = tf.keras.preprocessing.sequence.pad_sequences(X_train_seq, maxlen=100)
X_test_padded = tf.keras.preprocessing.sequence.pad_sequences(X_test_seq, maxlen=100)
Здесь происходит скачивание датасета path = kagglehub.dataset_download("kazanova/sentiment140"), запоминание пути для загрузки и последующая загрузка данных для дальнейшей работы с ними. Используется встроенный модуль os для обеспечения кроссплатформенности кода.
Далее данные обрабатываются – целевая переменная переводится в бинарный формат: позитивный (1) и негативный (0). data['target'] = data['target'].apply(lambda x: 1 if x == 4 else 0). Созданы два класса. И удаляются ненужные столбцы data = data[['text', 'target']].
После этого данные разделяются на обучающую и тестовую выборки в заданной пропорции (80/20).
Затем применена токенизация текста, которая преобразует слова в числовые последовательности. В словаре бует 10000 уникальных слов num_words=10000.
Последовательности, длина которых менее 100 выравниваются добавлением нулей. Это необходимо, чтобы на вход нейросети поступали вектора одинаковой длины.
Обучение нейронной сети
После подготовки данных и настройки параметров нейросети, приступаем к ее обучению. Во время обучения веса модели оптимизируются с использованием выбранных алгоритмов (в данном случае – Adam).
Код ниже запускает обучение нейросети:
# Перестроение модели с лучшими параметрами
best_model = tuner.hypermodel.build(best_hps)
history = best_model.fit(X_train_padded, y_train, validation_data=(X_test_padded, y_test), epochs=5, batch_size=32)
На рис. 4 показан ход обучения модели.
Рисунок 4 – Ход обучения модели.
Результатом обучения будет оптимизированная модель, способная делать предсказания на новых данных.
Выбор способа оценки адекватности результатов обучения
Для оценки нейронных сетей используются различные метрики. Для задач бинарной классификации, как в настоящей курсовой работе, применяются следующие:
Точность (Accuracy). Отражает долю правильно классифицированных образцов.
Точность (Pricision). Показывает долю истинно положительных результатов в числе всех положительных предсказаний.
Полнота (Recall). Доля истинно положительных результатов в числе всех реальных положительных предсказаний.
F1-score – гармоническое среднее между точностью и полнотой. Позволяет балансировать между этими характеристиками модели.
Представленный ниже код оценивает нашу обученную модель по указанным метрикам:
# Оценка модели
y_pred = (best_model.predict(X_test_padded) > 0.5).astype('int32')
print("Accuracy:", accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred))
Здесь мы получили предсказания модели для тестовых данных и преобразуем их в бинарный формат с порогом 0,5. Это значит, что при вероятности позитивного класса больше 50%, ответ будет = 1, иначе – 0.
Затем вычисляется точность модели (accuracy_score(y_test, y_pred)).
Далее выводится подробная таблица с метриками оценки качества модели (рис. 5)
Рисунок 5 – Таблица оценок модели
Расчет количества потерь и их минимизация
Функция потерь измеряет, как хорошо моделью предсказаны результаты. В задачах на бинарную классификацию для этого используется бинарная кросс-энтропия.
Рисунок 6 – Информация об обучении модели
Как видно из рис. 6 значения потерь в процессе обучения модели постоянно уменьшались. Это подтверждение того, что модель оптимизирует веса и предсказания становятся точнее.
График потерь можно увидеть на рис. 7
Итоговое значение потерь в нашей модель = 0,3753. Учитывая точность модели = 0,8312, это достаточно хороший показатель для такого типа задач.
Рисунок 7 – График потерь
Анализ адекватности обучения
После обучения модели необходимо понять, как хорошо модель справляется с поставленной перед ней задачей – в нашем случае с классификацией сообщений по тональности. В настоящем проекте была применена модель на основе рекуррентных нейронных сетей с двумя слоями LSTM. Эта модель обучилась на датасете Sentiment140, который содержит сообщения с отметками об их тональности (позитивный или негативный). Мы применили распространенные при оценках моделей для подобных задач метрики для оценки качества ее работы.
По результатам работы модели можно сделать вывод, что точность модели равна 83,12%. Это говорит о довольно высоком качестве предсказаний модели для задач на работу с текстовыми данными.
Также по результатам видно, что точность, полнота и F1-score и для позитивного, и для негативного классов, составляет 83%, что говорит о сбалансированности обученной модели. Этот уровень позволяет сделать вывод об адекватности проведенного обучения модели, и она может выполнять поставленную задачу с хорошей точностью.
При оценке потерь мы определили, что итоговое значение потерь составил 0,3753. Это показатель хорошего качества модели.
Отмечу, что при подборе параметров с использованием современного метода Байесовской оптимизации получилось подобрать оптимальные значения числа нейронов скрытых слоев и скорость обучения. Такой подход дает возможность как ускорить процесс подбора параметров, так и повысить качество модели, уменьшив вероятность переобучения.
Исходя из вышеуказанного, можно сказать, что модель адекватно обучена и ее результаты находятся на хорошем уровне.
Выводы по разделу
Разработана нейронная сеть, реализующая «Применение нейронных сетей для анализа тональности сообщений в социальных сетях». Решена задача бинарной классификации твитов по тональности на позитивные и негативные. В процессе работы использована предобработка данных (токенизация, паддинг), что позволило обеспечить корректность входных данных модели.
По результатам оценки модели установлена адекватность ее обучения и зорошее качество предсказаний (83%).
В результате выполненной работы можно сделать следующие выводы (табл.2):
Таблица 2 – Выводы по разделу 2.2