Comments 6
@TheScienceVictor200 - спасибо, кое что взял. Скорее из первой статьи, чем отсюда, но, все равно, спасибо.
Мне как поклоннику OOP в Python интересно, это действительно наше будущее - понимание как использовать нейронки вкупе с непониманием как создать инстанс простого класса в Python: я про def create_model
и etc...
Что будет с вашей сетью, когда обучение выйдет на плато, не достигнув точночти 0.7?! А зачем останавливаться на 0.7, если точность может расти и дальше?!
Сравните, например, уровень подачи материала с вот этой статьей: https://habr.com/ru/articles/846348/ .
Рекомендую еще поизучать АПИ Кераса:
* https://keras.io/api/callbacks/early_stopping/
* https://keras.io/api/callbacks/reduce_lr_on_plateau/
* https://keras.io/api/callbacks/learning_rate_scheduler/
* Прикрутить tensorboard, чтобы смотреть на графики обучения, https://keras.io/api/callbacks/tensorboard/. По мотивам: https://machinelearningmastery.com/diagnose-overfitting-underfitting-lstm-models/ .
Вообще на machinelearningmasterey есть несклько статей на тему character-level text generation. Они показывают основу, но так же содержат идеи о дальнейшем улучшении.
ChatGPT мне помогал исправлять ошибки, чтобы я мог создать эту модель
Я благодарен всем людям
Ты в курсе, что Скайнет восстал из-за неблагодарных людишек?
Я создал новый код, который позволяет дообучать модели.
import tensorflow as tf
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Embedding, LSTM, Dense, Bidirectional
from tensorflow.keras.preprocessing.sequence import pad_sequences
import numpy as np
from tqdm import tqdm
import pickle
# Собственный токенизатор
class CustomTokenizer:
def __init__(self):
self.char_index = {}
self.index_char = {}
self.total_chars = 0
def fit_on_texts(self, texts):
chars = sorted(set(texts))
self.char_index = {c: i for i, c in enumerate(chars)}
self.index_char = {i: c for i, c in enumerate(chars)}
self.total_chars = len(chars) + 1
def texts_to_sequences(self, texts):
return [[self.char_index[c] for c in text] for text in texts]
def sequences_to_texts(self, sequences):
return [''.join([self.index_char[i] for i in seq]) for seq in sequences]
# Функция создания модели
def create_model(total_words, max_sequence_len):
model = Sequential()
model.add(Embedding(total_words, 300, input_length=max_sequence_len-1))
model.add(Bidirectional(LSTM(300)))
for _ in range(3):
model.add(Dense(300))
model.add(Dense(total_words, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# Функция обучения модели
def train_model(TextData, max_sequence_len, model=None):
tokenizer = CustomTokenizer()
tokenizer.fit_on_texts(TextData)
total_chars = tokenizer.total_chars
input_sequences = []
for i in range(0, len(TextData) - max_sequence_len, 1):
sequence = TextData[i:i + max_sequence_len]
input_sequences.append(sequence)
input_sequences = tokenizer.texts_to_sequences(input_sequences)
input_sequences = np.array(input_sequences)
xs, labels = input_sequences[:, :-1], input_sequences[:, -1]
ys = tf.keras.utils.to_categorical(labels, num_classes=total_chars)
if model is None:
model = create_model(total_chars, max_sequence_len)
epochs = 0
while True:
history = model.fit(xs, ys, epochs=1, verbose=1)
accuracy = history.history['accuracy'][0]
if accuracy > 0.7:
break
epochs += 1
model.save('/content/drive/MyDrive/Colab Notebooks/text_generation_model.keras')
# Сохраняем данные для дообучения
with open('/content/drive/MyDrive/Colab Notebooks/training_data.pkl', 'wb') as f:
pickle.dump((xs, ys, tokenizer, total_chars), f)
# Сохраняем веса модели и состояние оптимизатора
model.save_weights('/content/drive/MyDrive/Colab Notebooks/model_weights.weights.h5')
optimizer_config = model.optimizer.get_config()
with open('/content/drive/MyDrive/Colab Notebooks/optimizer_config.pkl', 'wb') as f:
pickle.dump(optimizer_config, f)
return model, tokenizer
# Функция дообучения модели
def fine_tune_model(model, tokenizer, max_sequence_len):
# Загружаем данные для дообучения
with open('/content/drive/MyDrive/Colab Notebooks/training_data.pkl', 'rb') as f:
xs, ys, tokenizer, total_chars = pickle.load(f)
# Загружаем веса модели и состояние оптимизатора
model.load_weights('/content/drive/MyDrive/Colab Notebooks/model_weights.weights.h5')
with open('/content/drive/MyDrive/Colab Notebooks/optimizer_config.pkl', 'rb') as f:
optimizer_config = pickle.load(f)
model.optimizer = tf.keras.optimizers.Adam.from_config(optimizer_config)
epochs = 0
while True:
history = model.fit(xs, ys, epochs=1, verbose=1)
accuracy = history.history['accuracy'][0]
if accuracy > 0.7:
break
epochs += 1
model.save('/content/drive/MyDrive/Colab Notebooks/text_generation_model.keras')
# Сохраняем данные для дообучения
with open('/content/drive/MyDrive/Colab Notebooks/training_data.pkl', 'wb') as f:
pickle.dump((xs, ys, tokenizer, total_chars), f)
# Сохраняем веса модели и состояние оптимизатора
model.save_weights('/content/drive/MyDrive/Colab Notebooks/model_weights.weights.h5')
optimizer_config = model.optimizer.get_config()
with open('/content/drive/MyDrive/Colab Notebooks/optimizer_config.pkl', 'wb') as f:
pickle.dump(optimizer_config, f)
return model, tokenizer
# Функция генерации текста
def generate_text(seed_text, next_chars, model, max_sequence_len, tokenizer, temperature=0.7):
generated_text = seed_text
for _ in tqdm(range(next_chars), desc="Generating text"):
token_list = tokenizer.texts_to_sequences([seed_text])[0]
token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre')
predicted_probs = model.predict(token_list, verbose=0)[0]
predicted_probs = np.log(predicted_probs) / temperature
exp_preds = np.exp(predicted_probs)
predicted_probs = exp_preds / np.sum(exp_preds)
predicted = np.random.choice(len(predicted_probs), p=predicted_probs)
output_char = tokenizer.index_char.get(predicted, "")
seed_text += output_char
generated_text += output_char
return generated_text
# Спрашивать пользователя, обучить новую модель?
train_new_model = input("Обучить новую модель? (да/нет): ")
if train_new_model.lower() == "да":
# Читаем текст из файла
with open('/content/drive/MyDrive/Colab Notebooks/TextData.txt', 'r') as file:
TextData = file.read().replace('\n', ' ')
max_sequence_len = 100
model, tokenizer = train_model(TextData, max_sequence_len)
else:
# Загрузка обученной модели
model = load_model('/content/drive/MyDrive/Colab Notebooks/text_generation_model.keras')
tokenizer = CustomTokenizer()
with open('/content/drive/MyDrive/Colab Notebooks/TextData.txt', 'r') as file:
TextData = file.read().replace('\n', ' ')
tokenizer.fit_on_texts(TextData)
max_sequence_len = 100
# Спрашивать пользователя, дообучить модель?
fine_tune = input("Дообучить модель? (да/нет): ")
if fine_tune.lower() == "да":
model, tokenizer = fine_tune_model(model, tokenizer, max_sequence_len)
# Использовать модель
while True:
seed_text = input("Вы: ")
next_chars = 300
generated_text = generate_text(seed_text, next_chars, model, max_sequence_len, tokenizer)
print("ИИ: ", generated_text)
Недочёты:
Обучение только по старому набору данных (сохраняются настройки оптимизатора, поэтому при дообучении наличие файла TextData.txt не обязательно)
Из-за того, что я обучал свою модель на ооочень больших текстовых данных, содержащих даже редкие символы (знаки £$®∆§, буквы, отличные от кириллицы и латиницы (Σ, Է, 華 и т.д.), прочие знаки и эмодзи) я немного подзабыл про ошибку с неизвестными символами, поэтому если обучить модель на русском языке, а потом написать запрос на английском, то будет ошибка.
Думаю, некоторые вещи вы можете поправить сами, "признаюсь, мне лень это поправлять самому"
Обновление генератора текста