Merge pull request 'istyukov_timofey_lab_7 is ready' (#303) from istyukov_timofey_lab_7 into main
Reviewed-on: http://student.git.athene.tech/Alexey/IIS_2023_1/pulls/303
This commit is contained in:
commit
a0249e39e6
93
istyukov_timofey_lab_7/README.md
Normal file
93
istyukov_timofey_lab_7/README.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# Лабораторная работа №7. Рекуррентная нейронная сеть и задача генерации текста
|
||||||
|
## 12 вариант
|
||||||
|
___
|
||||||
|
|
||||||
|
### Задание:
|
||||||
|
Выбрать художественный текст на языке по варианту и обучить на нём рекуррентную
|
||||||
|
нейронную сеть для решения задачи генерации. Подобрать архитектуру и параметры
|
||||||
|
так, чтобы приблизиться к максимально осмысленному результату. Далее разбиться
|
||||||
|
на пары чётный-нечётный вариант, обменяться разработанными сетями и проверить,
|
||||||
|
как архитектура товарища справляется с вашим текстом. В завершении подобрать
|
||||||
|
компромиссную архитектуру, справляющуюся достаточно хорошо с обоими видами текстов.
|
||||||
|
|
||||||
|
### Вариант:
|
||||||
|
- Язык текста: **русский**
|
||||||
|
|
||||||
|
### Художественный текст:
|
||||||
|
- Отрывок из книги Ф.М. Достоевского — "Белые ночи" (в формате .txt)
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
### Запуск
|
||||||
|
- Запустить файл lab7.py
|
||||||
|
|
||||||
|
### Используемые технологии
|
||||||
|
- Язык программирования **Python**
|
||||||
|
- Среда разработки **PyCharm**
|
||||||
|
- Библиотеки:
|
||||||
|
* numpy
|
||||||
|
* keras
|
||||||
|
* os
|
||||||
|
|
||||||
|
### Описание программы
|
||||||
|
|
||||||
|
Здесь представлена модель глубокого обучения для генерации текста с помощью
|
||||||
|
библиотеки Keras и алгоритма LSTM. Чтобы построить модель генерации
|
||||||
|
художественного текста, требуются некоторые текстовые данные. В качестве набора
|
||||||
|
данных здесь используется отрывок из книги великого русского писателя-реалиста
|
||||||
|
в формате текстового файла.
|
||||||
|
|
||||||
|
**Шаги написания программы:**
|
||||||
|
1. **Предварительная обработка данных**
|
||||||
|
1. Перевод символов в нижний регистр
|
||||||
|
2. Формирование уникального набора использующихся в тексте символов
|
||||||
|
3. Преобразование текстовых данных в числовые значения
|
||||||
|
4. Создание последовательности символов (X - значений, Y - следующий символ)
|
||||||
|
5. Преобразование данных в массив логических значений
|
||||||
|
2. **Построение базовой модели**
|
||||||
|
1. Инициализация модели **Sequential**. это простой стек слоев,
|
||||||
|
с помощью которого нельзя представить произвольную модель.
|
||||||
|
2. Три слоя **LSTM** (по 200 единиц в каждом):
|
||||||
|
- В первом слое входная форма.
|
||||||
|
- Во втором слое параметр *return_sequences=True* для обработки тех же
|
||||||
|
последовательностей
|
||||||
|
- В третьем слое ничего лишнего
|
||||||
|
2. Три слоя **Dropout** с вероятностью 20% для проверки переобучения.
|
||||||
|
Dropout предполагает случайный кик нейронов из процесса обучения.
|
||||||
|
Он обеспечивает, чтобы нейронная сеть не стала слишком зависимой от
|
||||||
|
любого одного узла.
|
||||||
|
3. Один "плотный" слой **Dense** в конце, который даёт вывод символов.
|
||||||
|
Dense обрабатывает каждый элемент предыдущего слоя, выполняя матричное
|
||||||
|
перемножение этих элементов со своими весами.
|
||||||
|
4. Конфигурация модели для категориальной классификации.
|
||||||
|
3. **Обучение модели**
|
||||||
|
1. **epochs=50** (одна эпоха = один проход вперёд и один проход назад
|
||||||
|
всех обучающих примеров)
|
||||||
|
2. **batch_size=100** (количество обучающих примеров за один проход
|
||||||
|
вперёд/назад. Чем больше размер пакета, тем больше памяти лучше использовать.
|
||||||
|
4. **Сохранение модели** (во избежание повторного обучения и ради экономии времени)
|
||||||
|
5. **Генерация текста на основе сохранённой модели**
|
||||||
|
1. Загрузка модели
|
||||||
|
2. Выбор случайной стартовой точки в исходном тексте
|
||||||
|
3. Генерация назначенного количества символов
|
||||||
|
---
|
||||||
|
### Пример работы
|
||||||
|
|
||||||
|
*В ходе прогона программы было зафиксировано несколько результатов генерации
|
||||||
|
200 символов. Примеры приведены ниже.*
|
||||||
|
|
||||||
|
![Graphics](result_1.jpg)
|
||||||
|
|
||||||
|
![Graphics](result_2.jpg)
|
||||||
|
|
||||||
|
![Graphics](result_3.jpg)
|
||||||
|
|
||||||
|
![Graphics](result_4.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Вывод
|
||||||
|
Итак, рекуррентная нейронная сеть справилась с задачей генерации текста.
|
||||||
|
Если говорить о качестве, то требуется более глубокое обучение и больше текста.
|
||||||
|
И тогда нейросеть сможет писать даже в стиле Достоевского. Но по времени это
|
||||||
|
слишком затратно. Однако в рамках лабораторной работы результат вышел приемлемый.
|
5
istyukov_timofey_lab_7/belye-nochi.txt
Normal file
5
istyukov_timofey_lab_7/belye-nochi.txt
Normal file
File diff suppressed because one or more lines are too long
127
istyukov_timofey_lab_7/lab7.py
Normal file
127
istyukov_timofey_lab_7/lab7.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
"""
|
||||||
|
Выбрать художественный текст на языке по варианту и обучить на нём рекуррентную нейронную сеть для решения задачи
|
||||||
|
генерации. Подобрать архитектуру и параметры так, чтобы приблизиться к максимально осмысленному результату.
|
||||||
|
|
||||||
|
Далее разбиться на пары чётный-нечётный вариант, обменяться разработанными сетями и проверить, как архитектура товарища
|
||||||
|
справляется с вашим текстом.
|
||||||
|
|
||||||
|
В завершении подобрать компромиссную архитектуру, справляющуюся достаточно хорошо с обоими видами текстов.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# 12 вариант
|
||||||
|
# Вариант языка текста: русский
|
||||||
|
# Художественный текст: Книга "Ф.М. Достоевский — Преступление и наказание"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import numpy as np
|
||||||
|
from keras.models import Sequential
|
||||||
|
from keras.layers import Dense, Dropout, LSTM
|
||||||
|
from keras.utils import to_categorical
|
||||||
|
|
||||||
|
|
||||||
|
FILE_NAME = 'belye-nochi.txt'
|
||||||
|
|
||||||
|
# Открытие файла
|
||||||
|
df_text = (open(FILE_NAME, encoding='utf-8').read())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""""""""""""""""""""""""""""""""
|
||||||
|
ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА ДАННЫХ
|
||||||
|
"""""""""""""""""""""""""""""""""
|
||||||
|
# Перевод всех символов в нижний регистр для упрощения обучения
|
||||||
|
df_text = df_text.lower()
|
||||||
|
|
||||||
|
# Формирование набора символов на основе текста
|
||||||
|
characters = sorted(list(set(df_text)))
|
||||||
|
print("\033[92m\n---> Итого символов: \033[00m", len(characters))
|
||||||
|
|
||||||
|
# Сопоставления символов к номеру
|
||||||
|
char_to_n = {char: n for n, char in enumerate(characters)}
|
||||||
|
|
||||||
|
# Массивы
|
||||||
|
X = [] # обучающий
|
||||||
|
Y = [] # целевой
|
||||||
|
|
||||||
|
# Длина исходного текста
|
||||||
|
length = len(df_text)
|
||||||
|
# Длина последовательности символов для предсказания конкретного символа
|
||||||
|
seq_length = 5
|
||||||
|
|
||||||
|
# Перебора полного текста
|
||||||
|
for i in range(0, length - seq_length, 1):
|
||||||
|
sequence = df_text[i:i + seq_length]
|
||||||
|
label = df_text[i + seq_length]
|
||||||
|
X.append([char_to_n[char] for char in sequence])
|
||||||
|
Y.append(char_to_n[label])
|
||||||
|
|
||||||
|
# Масштабирование целых чисел в диапазон от 0 до 1 для облегчения изучения шаблонов сетью
|
||||||
|
X_modified = np.reshape(X, (len(X), seq_length, 1))
|
||||||
|
X_modified = X_modified / float(len(characters))
|
||||||
|
Y_modified = to_categorical(Y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""""""""""""""""""""
|
||||||
|
ПОСТРОЕНИЕ МОДЕЛИ
|
||||||
|
"""""""""""""""""""""
|
||||||
|
# Инициализация модели
|
||||||
|
model = Sequential()
|
||||||
|
|
||||||
|
# Пополнение модели атрибутами
|
||||||
|
model.add(LSTM(700, input_shape=(X_modified.shape[1], X_modified.shape[2]), return_sequences=True)) # первый слой на 700 единиц с входной формой
|
||||||
|
model.add(Dropout(0.2)) # кик нейронов с вероятностью 20%
|
||||||
|
model.add(LSTM(700, return_sequences=True)) # второй слой на 700 единиц, обрабатывающий те же последовательности
|
||||||
|
model.add(Dropout(0.2))
|
||||||
|
model.add(LSTM(700)) # третий слой на 700 единиц
|
||||||
|
model.add(Dropout(0.2))
|
||||||
|
model.add(Dense(Y_modified.shape[1], activation='softmax')) # сеть с плотным слоем для вывода символов
|
||||||
|
|
||||||
|
# Конфигурация модели с вычислением категориальных потерь кроссэнтропии
|
||||||
|
model.compile(loss='categorical_crossentropy', optimizer='adam')
|
||||||
|
|
||||||
|
# Обучение модели, если сохранённая модель в текущей папке отсутствует
|
||||||
|
if not os.path.exists('save_text_generator_deeper_model.h5'):
|
||||||
|
# Обучение модели на 50 эпохах и 100 обучающих примерах за один проход
|
||||||
|
model.fit(X_modified, Y_modified, epochs=50, batch_size=100)
|
||||||
|
# Сохранение обученной модели в файл в текущей папке
|
||||||
|
model.save_weights('save_text_generator_deeper_model.h5')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
Генерация текста
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
# Загрузка обученной модели с текущей папки
|
||||||
|
model.load_weights('save_text_generator_deeper_model.h5')
|
||||||
|
# Сопоставления номеров обратно к символам
|
||||||
|
n_to_char = dict((i, c) for i, c in enumerate(characters))
|
||||||
|
|
||||||
|
# Выбор случайной точки старта в тексте для генерации
|
||||||
|
start = np.random.randint(0, len(X) - 1)
|
||||||
|
# Последовательность этой точки
|
||||||
|
pattern = X[start]
|
||||||
|
|
||||||
|
txtxt = "" # строка результата
|
||||||
|
# сохранение старта в результат
|
||||||
|
for value in pattern:
|
||||||
|
txtxt += n_to_char[value]
|
||||||
|
print("\033[92m\n---> Точка старта: \033[00m", txtxt)
|
||||||
|
|
||||||
|
# Генерация 200 символов
|
||||||
|
for i in range(200):
|
||||||
|
# Масштабирование последовательности символов
|
||||||
|
x = np.reshape(pattern, (1, len(pattern), 1))
|
||||||
|
x = x / float((len(characters)))
|
||||||
|
prediction = model.predict(x, verbose=0) # прогноз вероятностей к каждому символу
|
||||||
|
index = np.argmax(prediction) # выбор индекса лучшего по вероятности
|
||||||
|
txtxt += n_to_char[index] # запись символа с таким индексом в результат
|
||||||
|
# сохранение индекса символа в конечную результирующую последовательность
|
||||||
|
pattern.append(index)
|
||||||
|
pattern = pattern[1:len(pattern)]
|
||||||
|
|
||||||
|
print("\033[92m\n[----------> Результат <----------]\033[00m")
|
||||||
|
print(txtxt)
|
BIN
istyukov_timofey_lab_7/result_1.jpg
Normal file
BIN
istyukov_timofey_lab_7/result_1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
istyukov_timofey_lab_7/result_2.jpg
Normal file
BIN
istyukov_timofey_lab_7/result_2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
istyukov_timofey_lab_7/result_3.jpg
Normal file
BIN
istyukov_timofey_lab_7/result_3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
istyukov_timofey_lab_7/result_4.jpg
Normal file
BIN
istyukov_timofey_lab_7/result_4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
istyukov_timofey_lab_7/save_text_generator_deeper_model.h5
Normal file
BIN
istyukov_timofey_lab_7/save_text_generator_deeper_model.h5
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user