【NLP】keras Transformer 唐诗生成器

本文使用了 keras-transformer 第三方库,库的模型结构和使用方法如下图,需要构造 encoder_input (x1) decoder_input (x2) decoder_output (y) 三个矩阵,用于进行模型训练
在这里插入图片描述

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import json

path_tang = './tang/poet.tang.' 

# 读取 json 文件
def get_json(path):
    with open(path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return data

制作唐诗数据集 v2

# 对 ./tang/ 文件夹下的所有 json 文件进行遍历
import os

# 获取文件夹下的所有文件名
def get_file_name(path):
    file_name = []
    for root, dirs, files in os.walk(path):
        for file in files:
            file_name.append(file)
    return file_name

file_name_ls = get_file_name('./tang/')

ret_ls = []

for file_name in file_name_ls:
    ls = get_json('./tang/' + file_name)
    n_ls = len(ls)
    
    for i in range(n_ls):
        para = ls[i]['paragraphs']
        para = ''.join(para)
        ret_ls.append(para)

len(ret_ls) # 一共 57607 首诗歌
n_poet = len(ret_ls)
n_poet

查看前 10 首诗

for i in range(10):
    print(ret_ls[i])

在这里插入图片描述

# 给 ret_ls 的每一个元素,都在每个字之间加空格
for i in range(n_poet):
    ret_ls[i] = ' '.join(ret_ls[i])
for i in range(10):
    print(ret_ls[i])

在这里插入图片描述

# 给 ret_ls 的每一个元素,前后都加上 <SOS> 和 <EOS>
for i in range(n_poet):
    ret_ls[i] = '<SOS> ' + ret_ls[i] + ' <EOS>'
for i in range(10):
    print(ret_ls[i])

在这里插入图片描述

进行 tokenizer 统计

# 全部合并成一个 string
str_all =  ' '.join(ret_ls)
str_all[:1000]
# 用 keras 的 Tokenizer 进行统计
from keras.preprocessing.text import Tokenizer

# 设置最大词汇量为 10000 个词
tokenizer = Tokenizer(num_words=10000,char_level=False,filters='!"#$%&()*+,-./:;=?@[\\]^_`{|}~\t\n')   # 因为添加了空格,所以 char_level=False
# 在 str_all 上进行训练
tokenizer.fit_on_texts([str_all])
# 设置padding 为 0
tokenizer.word_index['<pad>'] = 0
tokenizer.index_word[0] = '<pad>'
## 使用word_index属性查看每个词对应的编码
## 使用word_counts属性查看每个词对应的频数
for ii,iterm in enumerate(tokenizer.word_index.items()):
    if ii < 10:
        print(iterm)
    else:
        break
print("===================")  
for ii,iterm in enumerate(tokenizer.word_counts.items()):
    if ii < 10:
        print(iterm)
    else:
        break

在这里插入图片描述

制作数据集 v2

# 对 ret_ls 进行分词,按照空格进行分词,得到 word_ls
word_ls = []
for i in range(n_poet):
    word_ls.append(ret_ls[i].split(' '))

# 查看前 1 首诗歌的分词结果
for i in range(1):
    print(word_ls[i])

在这里插入图片描述

# 制作数据集的方法:从 word_ls 中,采样一首诗,从这首诗开头采样长度为 10 的子串,然后预测接下来的10个字
# 数据集大小为 1w 样本对,采样方法是随机采样
import random
from tqdm import tqdm
x_seq_ls = []
y_seq_ls = []
decoder_output_ls = []

for i in tqdm(range(n_poet)):
    
    if len(word_ls[i])-22<=0:        # 如果这首诗歌的长度小于等于 22,就跳过
        continue
    
    # 随机选一个子串
    start = random.randint(0, len(word_ls[i])-11)

    end = start + 10
    # 保存到 x_seq_ls 和 y_seq_ls 中
    x_seq_ls.append(word_ls[i][start:end])
    y_seq_ls.append(word_ls[i][end:end+10])
    decoder_output_ls.append(word_ls[i][end+1:end+11])
len(x_seq_ls),len(y_seq_ls),len(decoder_output_ls)
# 查看一下 x_seq_ls 和 y_seq_ls
for i in range(20):
    print(x_seq_ls[i],'\n',y_seq_ls[i],'\n',decoder_output_ls[i],'\n\n')

在这里插入图片描述

# 把 x_seq_ls 和 y_seq_ls 用 tokenizer 进行编码

x_token = tokenizer.texts_to_sequences(x_seq_ls)
y_token = tokenizer.texts_to_sequences(y_seq_ls)
decoder_output_token = tokenizer.texts_to_sequences(decoder_output_ls)
# 查看一下 x_seq_ls 和 y_seq_ls
for i in range(20):
    print(x_token[i],'\n',y_token[i],'\n',decoder_output_token[i],'\n\n')

在这里插入图片描述

# 转化为 numpy (补零)
# x_mat = np.array(x_token)
# y_mat = np.array(y_token)

# 导入补零需要的padding_seq
from keras_preprocessing.sequence import pad_sequences
x_mat = pad_sequences(x_token,maxlen=10,padding='post',truncating='post')
y_mat = pad_sequences(y_token,maxlen=10,padding='post',truncating='post')
decoder_output_mat = pad_sequences(decoder_output_token,maxlen=10,padding='post',truncating='post')
# 查看一下 x_seq_ls 和 y_seq_ls
for i in range(20):
    print(x_mat[i],'\n',y_mat[i],'\n',decoder_output_mat[i],'\n\n')

在这里插入图片描述

# 给decoder_output_mat 加上一个维度
decoder_output_mat = decoder_output_mat.reshape(decoder_output_mat.shape[0],decoder_output_mat.shape[1],1)
decoder_output_mat,decoder_output_mat.shape

划分训练集、测试集

# 划分训练集、测试集,把 x_mat,y_mat,decoder_output_mat 划分为训练集和测试集, 比例为 7:3
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test,decoder_output_train,decoder_output_test = train_test_split(x_mat,y_mat,decoder_output_mat,test_size=0.3,random_state=0)
x_train.shape, x_test.shape, y_train.shape, y_test.shape ,decoder_output_train.shape, decoder_output_test.shape

在这里插入图片描述

训练模型

搭建网络

import numpy as np
from keras_transformer import get_model
# Build the model
model = get_model(
    token_num=10000,
    embed_dim=128,
    encoder_num=3,
    decoder_num=2,
    head_num=4,                    # embed_dim must be divisible by head_num
    hidden_dim=256,                # hidden_dim 没有要求
    attention_activation='relu',
    feed_forward_activation='relu',
    dropout_rate=0.1,
)
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
)
model.summary()
# 开始训练
history = model.fit([x_train,y_train], decoder_output_train, batch_size=32, epochs=5, validation_data=([x_test,y_test], decoder_output_test))

在这里插入图片描述

测试模型

test_string = '白日依山盡,黃河入海'


# 把 test_string 每个字之间添加空格
test_string = ' '.join(test_string)
# 前后加上开始和结束标志
# test_string = '<SOS> ' + test_string
# 把 test_string 转化为token
test_string_token = tokenizer.texts_to_sequences([test_string])
# 截取前10个字
test_string_token = test_string_token[0][:10]
# 转化为 numpy,补齐
test_string_mat = pad_sequences([test_string_token],maxlen=10,padding='post',truncating='post')
test_string_mat
from keras_transformer import decode
decoded = decode(
    model,
    test_string_mat.tolist(),
    start_token=tokenizer.word_index['<sos>'],
    end_token=tokenizer.word_index['<eos>'],
    pad_token=tokenizer.word_index['<pad>'],
    max_len=100,
    top_k=4,                                # 添加 top_k 和 temperature 参数,增加随机性
    temperature=1.0,
)
decoded
token_dict_rev = {v: k for k, v in tokenizer.word_index.items()}
for i in range(len(decoded)):
    print(''.join(map(lambda x: token_dict_rev[x], decoded[i][1:-1])))
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您好!关于Keras Transformer,它是基于Keras深度学习库实现的Transformer模型。Transformer模型是一种用于自然语言处理NLP)任务的深度学习模型,最初由Vaswani等人在《Attention is All You Need》一文中提出。 在Keras中,您可以使用`tf.keras`模块构建Transformer模型。通常,这个模型包含了一个编码器(Encoder)和一个解码器(Decoder)。 编码器负责将输入的文本序列编码成一系列的隐藏状态向量,而解码器则根据这些隐藏状态向量生成目标文本序列。 您可以使用`tf.keras.layers`中的多头注意力(MultiHeadAttention)层、位置编码层(PositionalEncoding)、全连接层等来构建Transformer的各个部分。 下面是一个简单的示例代码,展示了如何使用Keras构建一个Transformer模型: ```python import tensorflow as tf from tensorflow.keras.layers import Input, Dense, Embedding, MultiHeadAttention from tensorflow.keras.models import Model def create_transformer_model(max_seq_length, vocab_size): inputs = Input(shape=(max_seq_length,)) x = Embedding(input_dim=vocab_size, output_dim=128)(inputs) x = PositionalEncoding(max_seq_length)(x) encoder_outputs = Encoder(num_layers=4, num_heads=8)(x) decoder_outputs = Decoder(num_layers=4, num_heads=8)(encoder_outputs) outputs = Dense(vocab_size, activation='softmax')(decoder_outputs) model = Model(inputs=inputs, outputs=outputs) return model # 使用示例 max_seq_length = 100 vocab_size = 10000 model = create_transformer_model(max_seq_length, vocab_size) ``` 请注意,上述代码仅为演示目的,实际使用时需要根据您的数据和任务进行相应的调整和优化。 如果您有更具体的问题或需求,我可以为您提供更详细的帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值