文本生成

import torch
import torch.nn as nn
import pandas as pd
import numpy as np
import tensorflow as tf
import os
import tensorflow as tf
# 打印tensorflow版本
# print("Tensorflow Version:", tf.__version__)# 查看tf版本号
# print(torch.__version__)   # 查看torch版本号

test = open('./data/shahsibiya.txt', 'rb').read().decode(encoding='utf-8')

# print(len(test))
# print(test[:250])

vocab = sorted(set(test))
# print(len(vocab))


# 对文本进行数值映射
# 对字符进行数值映射,将创建两个映射表:字符映射成数字,数字映射成字符
char2idx = {u:i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)

# 使用字符到数字的映射表示所有文本
text_as_int = np.array([char2idx[c] for c in test])

# for char, _ in zip(char2idx, range(20)):
#     print('  {:4s}: {:3d},'.format(repr(char), char2idx[char]))

# 查看原始语料前13个字符映射后的结果
# print ('{} ---- characters mapped to int ---- > {}'.format(repr(test[:20]), text_as_int[:20]))



# 生成训练数据

seq_length = 100
# 获得样本总数
examples_per_epoch = len(test)//seq_length
# print(examples_per_epoch)

# 将数值映射后的文本转换成dataset对象方便后续处理
char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int)

# # 通过dataset的take方法以及映射表查看前5个字符
# for i in char_dataset.take(5):
#     print(idx2char[i.numpy()])


# 使用dataset的batch方法按照字符长度+1划分(要留出一个向后顺移的位置)
# drop_remainder=True表示删除掉最后一批可能小于批次数量的数据
sequences = char_dataset.batch(seq_length+1, drop_remainder=True)

# # 查看划分后的5条数据对应的文本内容
# for item in sequences.take(5):
#     print(repr(''.join(idx2char[item.numpy()])))


def split_input_target(chunk):
    """划分输入序列和目标序列函数"""
    # 前100个字符为输入序列,第二个字符开始到最后为目标序列
    input_text = chunk[:-1]
    target_text = chunk[1:]
    return input_text, target_text

# 使用map方法调用该函数对每条序列进行划分
dataset = sequences.map(split_input_target)

# # 查看划分后的第一批次结果
# for input_example, target_example in  dataset.take(1):
#     print ('Input data: ', repr(''.join(idx2char[input_example.numpy()])))
#     print ('Target data:', repr(''.join(idx2char[target_example.numpy()])))
#
#
# # 查看将要输入模型中的每个时间步的输入和输出(以前五步为例)
# # 循环每个字符,并打印每个时间步对应的输入和输出
# for i, (input_idx, target_idx) in enumerate(zip(input_example[:5], target_example[:5])):
#     print("Step {:4d}".format(i))
#     print("  input: {} ({:s})".format(input_idx, repr(idx2char[input_idx])))
#     print("  expected output: {} ({:s})".format(target_idx, repr(idx2char[target_idx])))


# 定义批次大小为64
BATCH_SIZE = 64

# 设定缓冲区大小,以重新排列数据集
# 缓冲区越大数据混乱程度越高,所需内存也越大
BUFFER_SIZE = 10000

# 打乱数据并分批次
dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)


# 打印数据集对象查看数据张量形状
# print(dataset)


# 构建模型并训练模型

# 获得词汇集大小
vocab_size = len(vocab)

# 定义词嵌入维度
embedding_dim = 256

# 定义GRU的隐层节点数量
rnn_units = 1024


# 模型包括三个层:输入层即embedding层,中间层即GRU层(详情查看)输出层即全连接层
def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
    """模型构建函数"""
    # 使用tf.keras.Sequential定义模型
    # GRU层的参数return_sequences为True说明返回结果为每个时间步的输出,而不是最后时间步的输出
    # stateful参数为True,说明将保留每个batch数据的结果状态作为下一个batch的初始化数据
    # recurrent_initializer='glorot_uniform',说明GRU的循环核采用均匀分布的初始化方法
    # 模型最终通过全连接层返回一个所有可能字符的概率分布.
    model = tf.keras.Sequential([
      tf.keras.layers.Embedding(vocab_size, embedding_dim,
                              batch_input_shape=[batch_size, None]),
      tf.keras.layers.GRU(rnn_units,
                          return_sequences=True,
                          stateful=True,
                          recurrent_initializer='glorot_uniform'),
      tf.keras.layers.Dense(vocab_size)
    ])
    return model

# 传入超参数构建模型
model = build_model(
    vocab_size = len(vocab),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units,
    batch_size=BATCH_SIZE)

# 训练前试用模型
# 使用一个批次的数据作为输入
# 查看通过模型后的结果形状是否满足预期
for input_example_batch, target_example_batch in dataset.take(1):
    example_batch_predictions = model(input_example_batch)
    print(example_batch_predictions.shape, "# (batch_size, sequence_length, vocab_size)")

# 查看模型参数情况
model.summary()


# 使用random categorical
sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
# squeeze表示消减一个维度
sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy()
print(sampled_indices)

# 也将输入映射成文本内容
print("Input: \n", repr("".join(idx2char[input_example_batch[0]])))


# 映射这些索引查看对应的文本
# 在没有训练之前,生成的文本没有任何规律
print("Next Char Predictions: \n", repr("".join(idx2char[sampled_indices ])))



# 使用keras预置的稀疏类别交叉熵损失(当类别矩阵为稀疏类别矩阵时使用该损失)
def loss(labels, logits):
    return tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True)

# 使用损失函数
example_batch_loss  = loss(target_example_batch, example_batch_predictions)
print("Prediction shape: ", example_batch_predictions.shape, " # (batch_size, sequence_length, vocab_size)")
print("scalar_loss:      ", example_batch_loss.numpy().mean())

# 配置优化器为'adam'
model.compile(optimizer='adam', loss=loss)



# 检查点保存至的目录
checkpoint_dir = './model'

# 检查点的文件名
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt_{epoch}")

# 创建检测点保存的回调对象
checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_prefix,
    save_weights_only=True)


EPOCHS=10
history = model.fit(dataset, epochs=EPOCHS, callbacks=[checkpoint_callback])


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值