"Это седьмой день моего участия в ноябрьском испытании обновлений, ознакомьтесь с подробностями события:Вызов последнего обновления 2021 г.".
1. Предпосылки
У меня два увлечения, одно — традиционная культура, другое — высокие технологии.
Традиционная культура, мне нравится поэзия Тан и поэзия Сун, перо и тушь Danqing, высокие технологии. Я занимаюсь передовым ИТ-программированием, и мне нравится изучать искусственный интеллект.
Я хотел бы соединить два, старый и новый, я не знаю, какие искры столкнутся.
2. Результаты
Путем экспериментов, используя рекуррентную нейронную сеть в сочетании с генерацией текста, я, наконец, применил магический трюк: дайте начало, и он автоматически сгенерирует Song Ci. И это новое слово, безусловно, оригинально.
начало | генерировать |
---|---|
морось | Морось Сянгуйчунь. Яркая луна здесь, и сон разбит. Дождавшись холодного занавеса, возвращаемся. Вороны кричат. |
ветер | Ветер ломается, и внешний вид бессонный и безветренный. Люди мечтают о прелести рододендронов. Не заставляй людей выходить за дверь. робкое морозное утро. |
высотный | Высотные огни, девять улиц и луна. Сегодня вечером я вышел из здания, и когда я путешествовал, там было пусто. Но мыть. С видом на пять цветов мира. |
морской бриз | Морской бриз дует сегодня ночью там, где предпочитает Фэнлоу. чудесно. Полумесяц разбит. Положите сердце на зеленый холм и развалитесь. |
сегодня вечером | Кто и слезы высохли сегодня вечером. Ветер Каору достаточно слабый. Как затянувшаяся печаль. Как чистая волна, как нефритовый человек. стыдно видеть. |
Меня, немного изучавшего поэзию, вполне устраивает текст, порожденный словом "многоэтажка" выше.
Высотные огни, девять улиц и луна. Сегодня вечером я вышел из здания, и когда я путешествовал, там было пусто. Но мыть. С видом на пять цветов мира.
Высотное здание находится на высоком месте, и текст за ним также отражает характеристики «высокого».«Многоэтажное здание, смотрящее на улицу» — художественная концепция, «многоэтажное здание, смотрящее в ночь». это еще одна художественная концепция, и, наконец, есть «взгляд вниз на пять цветов». Слово «вниз» также отражает снисходительность, и весь текст вращается вокруг темы «высокого». Поразительнй!
Давайте проанализируем, как реализуется генерация Song Ci.
3. Реализация
3.1 Подготовка данных
Я нашел набор данных Song Ci, который представляет собой файл в формате csv, содержащий 20 000 Song Ci.
Первый столбец документа — это имя токена, второй столбец — автор, а третий столбец — текст. Среди них текст был разбит на слова.
Чтобы узнать о причастиях, см.Очки знаний НЛП: сегментация китайских слов.
3.2 Чтение данных
Сначала импортируйте пакеты, задействованные во всем проекте.
import csv
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import numpy as np
from tensorflow.python.keras.engine.sequential import Sequential
from tensorflow.keras import layers
from tensorflow.keras.optimizers import Adam
Вот как загрузить данные из файла набора данных.
def load_data(num = 1000):
# 读取csv文件。表头:0 题目| 1 作者| 2 内容
csv_reader = csv.reader(open("./ci.csv",encoding="gbk"))
# 以一首词为单位存储
ci_list = []
for row in csv_reader:
# 取每一行,找到词内容那一列
ci_list.append(row[2])
# 超过最大数量退出循环,用多少取多少
if len(ci_list) > num:break
return ci_list
Чтобы узнать больше о том, как загружать наборы данных csv, вы можете просмотретьОчки знаний НЛП: чтение в формате CSV.
Затем сериализуйте данные.
def get_train_data():
# 加载数据作为语料库["春花 秋月","一江 春水 向东 流"]
corpus = load_data()
# 定义分词器
tokenizer = Tokenizer()
# 分词器适配文本,将语料库拆分词语并加索引{"春花":1,"秋月":2,"一江":3}
tokenizer.fit_on_texts(corpus)
# 定义输入序列
input_sequences = []
# 从语料库取出每一条
for line in corpus:
# 序列成数字 "一江 春水 向东 流" ->[3,4,5,6]
token_list = tokenizer.texts_to_sequences([line])[0]
# 截取字符[3,4,5,6]变成[3,4],[3,4,5],[3,4,5,6]
for i in range(1, len(token_list)):
n_gram_sequence = token_list[:i+1]
input_sequences.append(n_gram_sequence)
# 找到语料库中最大长度的一项
max_sequence_len = max([len(x) for x in input_sequences])
# 填充序列每一项到最大长度,采用前面补0的方式
input_sequences = np.array(pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre'))
return tokenizer, input_sequences, max_sequence_len
Для того, почему и как сериализовать текст, вы можете перейти к пункту знанийTokenizer,texts_to_sequences,pad_sequencesСмотрите подробные инструкции.
Здесь важно объяснить, потому что для обучения прогнозированию текста следующие слова необходимо вывести из приведенных выше слов, поэтому здесь выполняется некоторая обработка.
Например, предложение «Смотреть на гору — это не гора, а смотреть на гору — это гора», которое было преобразовано в несколько предложений:
看山 不是
看山 不是 山
看山 不是 山 ,
看山 不是 山 , 看山
看山 不是 山 , 看山 又是
看山 不是 山 , 看山 又是 山
Цель этого состоит в том, чтобы сообщить нейронной сети, что если ему предшествует «посмотри на гору», за ним следует слово «нет». Когда фронт становится «Смотреть на гору, не на гору, а смотреть на гору», тогда «Смотреть на гору» становится «снова».
Спинка «глядя на гору» не фиксируется, а определяется на основе комплексного осмысления ряда слов перед ней.
Разделите одно предложение на несколько предложений. Это специальная обработка, которую выполняет следующий код:
for i in range(1, len(token_list)):
n_gram_sequence = token_list[:i+1]
input_sequences.append(n_gram_sequence)
3.3 Построение модели
Для обучения данных у нас сначала должна быть модель нейронной сети, а ниже приведена последовательность построенных сетевых моделей.
def create_model(vocab_size, embedding_dim, max_length):
# 构建序列模型
model = Sequential()
# 添加嵌入层
model.add(layers.Embedding(vocab_size, embedding_dim, input_length = max_length))
# 添加长短时记忆层
model.add(layers.Bidirectional(layers.LSTM(512)))
# 添加softmax分类
model.add(layers.Dense(vocab_size, activation='softmax'))
# adam优化器
adam = Adam(lr=0.01)
# 配置训练参数
model.compile(loss='categorical_crossentropy',optimizer=adam, metrics=['accuracy'])
return model
Есть специальные пояснения по поводу точек знаний моделей, слоев и функций активации:Последовательности и слои моделей нейронных сетей,функция активации.
3.4 Провести обучение
Тренировочный код выглядит следующим образом:
# 分词器,输入序列,最大序列长度
tokenizer, input_sequences, max_sequence_len = get_train_data()
# 得出有多少个词,然后+1,1是统一长度用的填充词
total_words = len(tokenizer.word_index) + 1
# 从语料库序列中拆分出输入和输出,输入是前面几个词,输出是最后一个词
xs = input_sequences[:,:-1]
labels = input_sequences[:,-1]
# 结果转为独热编码
ys = tf.keras.utils.to_categorical(labels, num_classes=total_words)
# 创建模型
model = create_model(total_words, 256, max_sequence_len-1)
# 进行训练
model.fit(xs, ys, epochs= 15, verbose=1)
# 保存训练的模型
model_json = model.to_json()
with open('./save/model.json', 'w') as file:
file.write(model_json)
# 保存训练的权重
model.save_weights('./save/model.h5')
Предположим, мы получили обучающую последовательность input_sequences:
[0, 0, 1, 2]
[0, 0, 3, 4]
[0, 3, 4, 5]
[3, 4, 5, 6]
Соответствующий текст:
[0, 0, 春花, 秋月]
[0, 0, 一江, 春水]
[0, 一江, 春水, 向东]
[一江, 春水, 向东, 流]
Для тренировок он обычно парный. Один вход, один выход. Машины научатся делать вывод из ввода.
В этом примере, поскольку следующее слово выводится из предыдущего слова, как ввод, так и вывод берутся из вышеуказанного корпуса.
Следующий код принимает ввод и вывод из input_sequences:
xs = input_sequences[:,:-1]
labels = input_sequences[:,-1]
введите xs | выходные метки |
---|---|
[0, 0, весенний цветок] | [Осенняя луна] |
[0, 0, одна река] | [Родниковая вода] |
[0, одна река, родниковая вода] | [Восток] |
[Одна река, родниковая вода, на восток] | [поток ] |
Поскольку функция активации в модели используетactivation='softmax'
, поэтому этот вывод проходит черезtf.keras.utils.to_categorical
Преобразовано в горячее кодирование.
Если у вас есть вопросы о горячем кодировании, вы можете проверить«Знание: горячее кодирование».
На этом этапе необходимо выделить несколько концепций:
- Максимальная длина текстовой последовательности
max_sequence_len
это[一江, 春水, 向东, 流]
длина, здесь значение равно 4. Основная функция состоит в том, чтобы определить фиксированную длину обучения, заполнить 0, когда длина недостаточна, и обрезать, когда она превышается.
Зачем тебе это, ты можешьнажмите сюда, чтобы узнать больше.
- длина входной последовательности
input_length
это[0, 一江, 春水]
Длина, фиксированная на 3, составляет отmax_sequence_len
Вырезать, не нужно последнее слово. Основная роль - входная.
По поводу сохранения вышеуказанных данных модели, интересующиеся могут посмотреть очки знаний:Модели сохраняются в форматах json и h5..
3.5 Делайте прогнозы
После завершения обучения мы можем насладиться плодами победы и начать делать прогнозы.
Код предсказания выглядит следующим образом:
def predict(seed_text, next_words = 20):
# 分词器,输入序列,最大序列长度
tokenizer, input_sequences, max_sequence_len = get_train_data()
# 读取训练的模型结果
with open('./save/model.json', 'r') as file:
model_json_from = file.read()
model = tf.keras.models.model_from_json(model_json_from)
model.load_weights('./save/model.h5')
# 假如要预测后面next_words=20个词,那么需要循环20词,每次预测一个
for _ in range(next_words):
# 将这个词序列化 如传来“高楼”,则从词库中找高楼的索引为50,序列成[50]
token_list = tokenizer.texts_to_sequences([seed_text])[0]
# 填充序列每一项到最大长度,采用前面补0的方式[0,0……50]
token_list = pad_sequences([token_list], maxlen= max_sequence_len-1, padding='pre')
# 预测下一个词,预测出来的是索引
predicted = model.predict_classes(token_list, verbose = 0)
# 定义一个输出存储输出的数值
output_word = ''
# 找到预测的索引是哪一个词,比如55是“灯火”
for word, index in tokenizer.word_index.items():
if index == predicted:
output_word = word
break
# 输入+输出,作为下一次预测:高楼 灯火
seed_text = seed_text + " " + output_word
print(seed_text)
# 替换空格返回
return seed_text.replace(' ' , '')
# 预测数据
print(predict('细雨',next_words = 22))
# 细雨仙桂春。明月此,梦断在愁何。等闲帘寒,归。正在栖鸦啼来。
Для чтения приведенных выше данных модели, те, кто заинтересован, могут увидеть очки знаний:Чтение модели восстановления файлов json, h5.
Для предсказания требуется начальное слово и указывается, сколько слов предсказывать позже.
Во-первых, согласно начальным словам, поmodel.predict_classes(token_list)
Прогнозируется следующее слово, а затем начальное слово и предсказанное слово используются в качестве входных данных для продолжения прогнозирования следующего слова. И так далее, как змея, медленно вытягивая длинное предложение из вступительного слова. Каждое слово в предложении имеет смысловой контекст.
Это логика реализации генератора Song Ci, надеюсь она вам поможет.