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])
文本生成
最新推荐文章于 2024-10-10 16:03:21 发布