diff --git a/belyaeva_ekaterina_lab_7/README.md b/belyaeva_ekaterina_lab_7/README.md new file mode 100644 index 0000000..6d80b67 --- /dev/null +++ b/belyaeva_ekaterina_lab_7/README.md @@ -0,0 +1,54 @@ +## Задание + +Выбрать художественный текст (четные варианты – русскоязычный, нечетные – англоязычный) и обучить на нем рекуррентную +нейронную сеть для решения задачи генерации. Подобрать архитектуру и параметры так, чтобы приблизиться к максимально осмысленному результату.Далее разбиться на пары четный-нечетный вариант, обменяться разработанными сетями и проверить, как архитектура товарища справляется с вашим текстом. + +## Как запустить лабораторную +Запустить файл main.py +## Используемые технологии +Библиотеки tensorflow, numpy, их компоненты +## Описание лабораторной (программы) + +Данная лабораторная работа обучает модели для обработки русского и английского текста и решает задачу генерации. +Ниже будет описан алгоритм работы одной из моделей (вторая работает аналогично): +1. Читается текст из файла +2. Создается экземпляр Tokenizer для токенизации текста +3. С помощью метода fit_on_texts токенизатор анализирует текст и строит словарь уникальных слов +4. rus_vocab_size - длина словаря +5. C помощью метода text_to_sequences текст преобразуется в последовательность чисел +6. Создаются последовательности для обучения модели +7. Рассчитывается максимальная длина последовательности +8. Входные последовательности выравниваются до максимальной длины +9. С помощью функции to_categorical последовательности преобразуются в one-hot представление +10. Переменные x_rus_train, y_rus_train инициализируются соответствующими значениями +11. Такая же обработка текста происходит и для текста на английском языке +12. Происходит создание модели на русском языке: + - создается экземпляр модели Sequential + - добавляется слой Embedding, отображающий слова в векторы фиксированной длины + - добавляется слой LSTM с 512 нейронами + - добавляется слой Dense с функцией softmax для получения вероятности каждого слова в словаре + - модель компилируется +13. Происходит обучение модели через model.fit() +14. Все то же самое происходит для модели с английским языком +15. Определяется функция generate_text для генерации текста на основе всех заданных параметров +16. Выводятся результаты работы моделей и сгенерированные тексты + +## Результат + +Результат сгенерированного текста на русском языке: Помню просторный грязный двор и низкие домики обнесённые забором двор стоял у самой реки и по вёснам когда спадала полая вода он был усеян щепой и ракушками а иногда и другими куда более интересными вещами так однажды мы нашли туго набитую письмами сумку а потом вода принесла и осторожно положила на берег и самого почтальона он лежал на спине закинув руки как будто заслонясь от солнца ещё совсем молодой белокурый в форменной тужурке с блестящими пуговицами должно быть отправляясь в свой последний рейс почтальон начистил их мелом мелом мелом спадала щепой мелом мелом мелом мелом мелом спадала полая вода он ракушками а + +Результат сгенерированного текста на английском языке: The old man was thin and gaunt with deep wrinkles in the back of his neck the brown blotches of the benevolent skin cancer the sun brings from its reflection on the tropic sea were on his cheeks the blotches ran well down the sides of his face and his hands had the deep creased scars from handling heavy fish on the cords but none of these scars were fresh they were as old as erosions in a fishless desert fishless desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert desert fishless + +Результат потерь на тренировочных данных: + +![res.png](res.png) + +Вывод: можно заметить, что в сгенерированных текстах в конце слова повторяются. Это происходит потому, что в параметрах модели +указано сгенерировать 100 слов, хотя в тексте, по которому модель обучается, меньше слов. Поэтому сгенерированный текст сначала +соответствует тексту для обучения, а затем начинает выдавать рандомные слова. Но нужно отметить, что это слова, а не просто +набор букв и пробелы, которые получались при иных настройках моделей. + +Так как у английской модели меньше потерь на тренировочных данных, чем у русской, то получается, что выполненная модель +обрабатывает английский текст чуть лучше, чем русский, но в результате обе модели выдали осмысленный текст, что связано с большим +числом нейронов и эпох, при помощи которых обучалась модель. Ведь когда было 20 эпох, а не 200, модель выдавала очень слабо осмысленный результат. + diff --git a/belyaeva_ekaterina_lab_7/eng.txt b/belyaeva_ekaterina_lab_7/eng.txt new file mode 100644 index 0000000..7518545 --- /dev/null +++ b/belyaeva_ekaterina_lab_7/eng.txt @@ -0,0 +1,5 @@ +The old man was thin and gaunt with deep wrinkles in the back of his neck. The +brown blotches of the benevolent skin cancer the sun brings from its reflection on the +tropic sea were on his cheeks. The blotches ran well down the sides of his face and his +hands had the deep-creased scars from handling heavy fish on the cords. But none of +these scars were fresh. They were as old as erosions in a fishless desert. \ No newline at end of file diff --git a/belyaeva_ekaterina_lab_7/main.py b/belyaeva_ekaterina_lab_7/main.py new file mode 100644 index 0000000..742fa90 --- /dev/null +++ b/belyaeva_ekaterina_lab_7/main.py @@ -0,0 +1,97 @@ +import tensorflow as tf +import numpy as np +from keras.models import Sequential +from keras.layers import LSTM, Dense, Embedding +from keras.preprocessing.text import Tokenizer +from keras.preprocessing.sequence import pad_sequences + +# Загрузка и предобработка данных на русском языке +with open("rus.txt", "r", encoding="utf-8") as f: + rus_text = f.read() + +tokenizer_rus = Tokenizer() +tokenizer_rus.fit_on_texts([rus_text]) + +rus_vocab_size = len(tokenizer_rus.word_index) + 1 +rus_sequences = tokenizer_rus.texts_to_sequences([rus_text])[0] +rus_input_sequences = [] +rus_output_sequences = [] + +for i in range(1, len(rus_sequences)): + rus_input_sequences.append(rus_sequences[:i]) + rus_output_sequences.append(rus_sequences[i]) + +rus_max_sequence_len = max([len(seq) for seq in rus_input_sequences]) +rus_input_sequences = pad_sequences(rus_input_sequences, maxlen=rus_max_sequence_len) + +x_rus_train = rus_input_sequences +y_rus_train = tf.keras.utils.to_categorical(rus_output_sequences, num_classes=rus_vocab_size) + +# Загрузка и предобработка данных на английском языке +with open("eng.txt", "r", encoding="utf-8") as f: + eng_text = f.read() + +tokenizer_eng = Tokenizer() +tokenizer_eng.fit_on_texts([eng_text]) + +eng_vocab_size = len(tokenizer_eng.word_index) + 1 +eng_sequences = tokenizer_eng.texts_to_sequences([eng_text])[0] +eng_input_sequences = [] +eng_output_sequences = [] + +for i in range(1, len(eng_sequences)): + eng_input_sequences.append(eng_sequences[:i]) + eng_output_sequences.append(eng_sequences[i]) + +eng_max_sequence_len = max([len(seq) for seq in eng_input_sequences]) +eng_input_sequences = pad_sequences(eng_input_sequences, maxlen=eng_max_sequence_len) + +x_eng_train = eng_input_sequences +y_eng_train = tf.keras.utils.to_categorical(eng_output_sequences, num_classes=eng_vocab_size) + +# Построение модели для русского языка +rus_model = Sequential() +rus_model.add(Embedding(rus_vocab_size, 256, input_length=rus_max_sequence_len)) +rus_model.add(LSTM(512)) +rus_model.add(Dense(rus_vocab_size, activation='softmax')) + +rus_model.compile(loss='categorical_crossentropy', optimizer='adam') + +# Обучение модели для русского языка +rus_history = rus_model.fit(x_rus_train, y_rus_train, batch_size=128, epochs=200) + +# Построение модели для английского языка +eng_model = Sequential() +eng_model.add(Embedding(eng_vocab_size, 256, input_length=eng_max_sequence_len)) +eng_model.add(LSTM(512)) +eng_model.add(Dense(eng_vocab_size, activation='softmax')) + +eng_model.compile(loss='categorical_crossentropy', optimizer='adam') + +# Обучение модели для английского языка +eng_history = eng_model.fit(x_eng_train, y_eng_train, batch_size=128, epochs=200) + +def generate_text(model, tokenizer, max_sequence_len, seed_text): + output_text = seed_text + for _ in range(100): # Генерируем 100 слов + encoded_text = tokenizer.texts_to_sequences([output_text])[0] + pad_encoded = pad_sequences([encoded_text], maxlen=max_sequence_len, truncating='pre') + pred_word_index = np.argmax(model.predict(pad_encoded), axis=-1) + pred_word = tokenizer.index_word[pred_word_index[0]] + output_text += " " + pred_word + return output_text + +# Генерация текста для русской и английской моделей +rus_output_text = generate_text(rus_model, tokenizer_rus, rus_max_sequence_len, "Помню просторный") +eng_output_text = generate_text(eng_model, tokenizer_eng, eng_max_sequence_len, "The old man") + +# Вывод результатов +print("Русская модель:") +print("Потери на тренировочных данных:", rus_history.history['loss'][-1]) +print("Сгенерированный текст:") +print(rus_output_text) + +print("Английская модель:") +print("Потери на тренировочных данных:", eng_history.history['loss'][-1]) +print("Сгенерированный текст:") +print(eng_output_text) diff --git a/belyaeva_ekaterina_lab_7/res.png b/belyaeva_ekaterina_lab_7/res.png new file mode 100644 index 0000000..51cc401 Binary files /dev/null and b/belyaeva_ekaterina_lab_7/res.png differ diff --git a/belyaeva_ekaterina_lab_7/rus.txt b/belyaeva_ekaterina_lab_7/rus.txt new file mode 100644 index 0000000..abec729 --- /dev/null +++ b/belyaeva_ekaterina_lab_7/rus.txt @@ -0,0 +1 @@ +Помню просторный грязный двор и низкие домики, обнесённые забором. Двор стоял у самой реки, и по вёснам, когда спадала полая вода, он был усеян щепой и ракушками, а иногда и другими, куда более интересными вещами. Так, однажды мы нашли туго набитую письмами сумку, а потом вода принесла и осторожно положила на берег и самого почтальона. Он лежал на спине, закинув руки, как будто заслонясь от солнца, ещё совсем молодой, белокурый, в форменной тужурке с блестящими пуговицами: должно быть, отправляясь в свой последний рейс, почтальон начистил их мелом. \ No newline at end of file