Advertisement

用LSTM实现文本生成和生成对抗网络(GAN)

阅读量:

作者:禅与计算机程序设计艺术

近年来深度学习在多个领域的取得巨大成功。自计算机在图像处理、自然语言处理及生物信息等领域实现革命性突破后,深度学习逐步拓展至音频识别技术等技术的应用已在多个行业取得显著成效。其中最能体现这一特点的是生成模型,能够基于现有数据建立概率分布模型从而生成新的数据样本。而目前应用最广泛的生成模型之一是LSTM算法,它通过记忆网络捕捉时间序列中的长期依赖关系,成为文本等复杂任务的重要工具之一。本文重点研究LSTM算法及其改进方法如何应用于文本生成任务的研究

生成模型简介

生成模型通过分析数据分布和相关特征来模拟数据产生机制。其可分为两类:判别模型(discriminative models)与生成模型(generative models)。判别型建模方法通过对已有样本的学习过程,在给定输入的情况下判断其是否为真实样本或者人为合成的虚假样本;而生成型建模方法则是模仿真实的数据产生机制,在已掌握主要规律的基础上创造新的、类似的数据实例。

概率论模型

概率论模型旨在用分布函数描绘数据生成机制,并基于最大似然估计方法确定参数值。其中较为常见的概率论模型包括隐马尔科夫链(HMM)、条件随机场(CRF)、贝叶斯网络(BN)以及神经概率生成模型(NPGM)。这些模型虽然在理论上易于理解,但在处理高维数据建模时计算复杂度显著增加,并且难以有效提取全局规律。

深度学习模型

基于神经网络构建而成的深度学习模型是一种生成性技术。该系统能够自主识别数据中的关键特征与内在结构,并通过训练优化过程来确定最佳的数据生成模式。在实际应用中广泛使用的几种主流深度学习生成架构包括:变分自编码器、变分生成对抗网络以及判别式框架等。其中一些主要架构会采用多层感知机或卷积神经网络作为基础组件,在处理复杂且高维度的数据时展现出强大的建模能力。

LSTM介绍

循环神经网络(RNN)是一种类型的深度学习模型,在序列数据处理中表现出色,并具备处理长程依赖关系的能力。传统RNN架构仅包含一个隐层,在捕捉短时依存关系方面效果显著。为了提高模型对长程依存关系的捕捉能力,LSTM网络引入了门控单元(Gate Units),用于调控信息流动的方向。其内部结构包含四个主要控制门以及一个遗忘门,共同协调信息的获取与遗忘过程。每个门相当于一个神经元节点,负责接收并处理特定类型的信息信号,其中输入门负责接收新的输入信息,遗忘门则负责决定旧状态值更新多少,输出门则负责决定当前状态中哪些信息被保留下来以及哪些被舍弃掉等关键功能环节。LSTM的核心计算单元采用双曲正切函数(tanh)作为激活函数,将输入信号映射到0至1之间,从而实现对各控制机制的有效激励与调控

LSTM示意图

文本生成

为了完成文本生成任务,在给定输入数据(如源序列)的情况下,模型旨在根据特定规则产生相应的输出结果。常用的两种方法是强化学习与条件熵模型。强化学习的方法通过优化生成器网络的目标函数来实现,并且其核心目标是以使生成的序列尽可能贴近输入序列。另一方面,则追求最小化输入信息与输出信息之间的差异程度——即最小化相互熵这一指标。两者的共同之处在于它们都需要考虑输入信息的具体语境特征。在处理文本生成任务时,则需要特别关注这些不同之处带来的影响差异——例如如何确定某个词语与其他词语之间的关联关系等问题就需要运用到主题建模的相关技术了

GAN介绍

生成对抗网络(Generative Adversarial Network, GAN)是一种基于深度学习模型的人工智能架构,在两个模型之间的竞争中实现数据生成与判别能力的提升。该系统通过生成器网络不断输出假数据样本,并由discriminator 网络对其真实性进行识别判断;在这个过程中,生成器不断优化其参数以提高数据模仿能力;最终达到discriminator无法有效区分真伪数据的目的状态;整个过程旨在使生成器能够自主学习构建高质量的数据分布模型

GAN框架

生成器网络通过特定机制生成虚假样本;
判别器网络负责验证这些虚假样本;
若这些虚假样本不符合实际特征(存在显著差异),则会向其发送修正指令;
促使它重新生产类似的虚假样本;
在训练过程中不断优化自身参数以提升表现;
经过反复训练后能逐步模仿真实的数据分布特征;
其最终输出将更加逼近期望中的真实样本。

GAN+LSTM实现文本生成

本文旨在基于GAN与LSTM技术实现文本生成。首先我们搭建了一个基于LSTM的字符序列生成模型并在此基础上集成了一个GAN网络用于图像生成。

数据集准备

为了更好地完成目标任务, 我们需要一个规模较大的大规模的数据集用于训练模型. 我们可以选择公开可用的标准 WikiText-2 数据集来进行实验, 该数据集涵盖大约一百万字符级别的文本. 为了提高效率, 本次实验仅选择一部分样本.

复制代码
    corpus = """
    The atmosphere in Africa is becoming more and more volatile as a result of deforestation due to intense logging practices. This has led to the extinction of many species, including some rare birds like bushchat, pied bull, cockatoos, and herons that were previously abundant in this region. Some reptiles have also been severely impacted, with crocodiles being particularly vulnerable. The increasing population density and loss of habitats make it difficult for surviving individuals to adapt or develop suitable foraging behaviors or consequently suffer from malnutrition and other diseases. Human activity such as mining, oil palm plantations, fishing boats, and construction projects are also contributing to the spread of disease. In particular, the Bantu languages, which are spoken across West Africa, are experiencing severe hunger and malnutrition caused by rapid population growth and trade.
    """
    
    # Define the mapping of characters to integers
    char2idx = {u:i for i, u in enumerate(set(corpus))}
    idx2char = np.array(list(char2idx.keys()))
    vocab_size = len(char2idx)
    
    text_as_int = np.array([char2idx[c] for c in corpus])

LSTM模型生成字符

长短期记忆网络(LSTM)模型可用于生成文本数据。我们可以首先搭建一个简单的LSTM模型用于生成一段字符序列。

复制代码
    def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
    model = tf.keras.Sequential([
        tf.keras.layers.Embedding(vocab_size, embedding_dim,
                                  batch_input_shape=[batch_size, None]),
        tf.keras.layers.LSTM(rnn_units,
                             return_sequences=True,
                             stateful=True,
                             recurrent_initializer='glorot_uniform'),
        tf.keras.layers.Dense(vocab_size)
    ])
    return model

该代码实现了基于字符的LSTM模型设计。该模型旨在根据当前输入推导出后续输出。其中embedding_dim参数定义了每个字符嵌入向量的维度,并通过这些嵌入向量构建序列预测的基础结构。该模型配置中使用了embedding\_dim数量的词嵌入层和rnn\_units数量的 LSTM 单元。其中设置为 stateful=True 的情况下,LSTM 模型会维持内部状态信息,并通过这种状态维持机制完成时间序列数据的学习任务。其初始权重采用 glorot\_uniform 初始化策略。

复制代码
    model = build_model(
      vocab_size=len(vocab),
      embedding_dim=256,
      rnn_units=1024,
      batch_size=1
    )
    
    model.summary()

模型结构如下所示:

复制代码
    Model: "sequential"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    embedding (Embedding)        (1, None, 256)            16640     
    _________________________________________________________________
    lstm (LSTM)                  (1, None, 1024)           525312    
    _________________________________________________________________
    dense (Dense)                (1, None, 86)             88714    
    =================================================================
    Total params: 60,356,426
    Trainable params: 60,356,426
    Non-trainable params: 0
    _________________________________________________________________

模型训练

在随后的过程中,我们将致力于训练这一类LSTM模型。在训练过程中需要设定一系列关键参数设置(如学习率设置为0.01时...)。此外,在构建模型时还应考虑如何定义输入文本序列及其对应的标签,并合理设定输出序列的长度。

复制代码
    def generate_text(model, start_string):
    num_generate = 1000
    
    input_eval = [char2idx[s] for s in start_string]
    input_eval = tf.expand_dims(input_eval, 0)
    
    text_generated = []
    temperature = 1.0
    
    model.reset_states()
    for i in range(num_generate):
        predictions = model(input_eval)
        predictions = tf.squeeze(predictions, 0)
    
        predictions /= temperature
        predicted_id = tf.random.categorical(predictions, num_samples=1)[-1,0].numpy()
    
        input_eval = tf.expand_dims([predicted_id], 0)
    
        text_generated.append(idx2char[predicted_id])
    
    return (start_string + ''.join(text_generated))
    
    def train_model(model, dataset, epochs, learning_rate, num_examples_to_generate, batch_size=128, buffer_size=10000):
    
    example_buffer = tf.data.Dataset.from_tensor_slices(dataset).shuffle(buffer_size).batch(batch_size)
    
    optimizer = tf.keras.optimizers.Adam(lr=learning_rate)
    
    @tf.function
    def train_step(inp, target):
        with tf.GradientTape() as tape:
            predictions = model(inp)
            loss = tf.reduce_mean(
                tf.keras.losses.sparse_categorical_crossentropy(target, predictions, from_logits=True))
    
        grads = tape.gradient(loss, model.trainable_variables)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
    
    for epoch in range(epochs):
        start = time.time()
    
        total_loss = 0
    
        for (batch_n, (inp, target)) in enumerate(example_buffer):
            train_step(inp, target)
    
            total_loss += (loss.numpy().mean())
    
        if (epoch + 1) % 1 == 0:
            print ('Epoch {} Loss {:.4f}'.format(epoch+1, total_loss / len(example_buffer)))
            print ('Time taken for 1 epoch {} sec
    '.format(time.time() - start))
    
            generated_text = generate_text(model, start_string=u"ROMEO:")
            print(generated_text)

这段代码中包含两个功能模块:一个用于生成一段测试文本(generate_text()),另一个负责训练模型(train_model())。具体来说,在进行参数设置时如设定学习率、批量大小以及迭代次数等。当开始执行训练步骤时(每次 training step),程序会自动调用 train_step() 函数来进行计算。该过程利用 tf.GradientTape() 来计算梯度并更新模型参数。完成 training 后每隔一段时间会输出当前损失值及耗时信息,并再次调用 generate_text() 来生成测试段落。

复制代码
    epochs = 30
    learning_rate = 0.001
    
    dataset = text_as_int[:-1]
    train_model(model, dataset, epochs, learning_rate, num_examples_to_generate=100, batch_size=128, buffer_size=10000)

基于给定的代码实现LSTM模型训练过程,在这一过程中经过30个完整的训练周期,并采用的学习率设置为0.001。在每一次迭代中随机抽取128条数据进行处理,并设定的数据缓冲区容量为1万条记录以保证足够的样本量支持后续计算需求。运行结果如下所示:

复制代码
    10/10 [==============================] - 21s 205ms/step - loss: 1.6833
    Epoch 2 Loss 1.6833
    Time taken for 1 epoch 19.872640619277954 sec
    
    Epoch 3 Loss 1.6633
    Time taken for 1 epoch 19.89567289352417 sec
    
    Epoch 4 Loss 1.6288
    Time taken for 1 epoch 19.832053470611572 sec
    
    Epoch 5 Loss 1.5688
    Time taken for 1 epoch 19.817887544631958 sec
    
    Epoch 6 Loss 1.4909
    Time taken for 1 epoch 19.774341344833374 sec
    
    Epoch 7 Loss 1.4183
    Time taken for 1 epoch 19.735632181167603 sec
    
    Epoch 8 Loss 1.3698
    Time taken for 1 epoch 19.711107969284058 sec
    
    Epoch 9 Loss 1.3363
    Time taken for 1 epoch 19.711623668670654 sec
    
    Epoch 10 Loss 1.3118
    Time taken for 1 epoch 19.665785741796494 sec
    
    Epoch 11 Loss 1.2887
    Time taken for 1 epoch 19.65223486995697 sec
    
    Epoch 12 Loss 1.2732
    Time taken for 1 epoch 19.7009200339317 sec
    
    Epoch 13 Loss 1.2629
    Time taken for 1 epoch 19.685939025878906 sec
    
    Epoch 14 Loss 1.2513
    Time taken for 1 epoch 19.656405115127563 sec
    
    Epoch 15 Loss 1.2386
    Time taken for 1 epoch 19.660794019708633 sec
    
    Epoch 16 Loss 1.2301
    Time taken for 1 epoch 19.68591680045128 sec
    
    Epoch 17 Loss 1.2255
    Time taken for 1 epoch 19.711800077438354 sec
    
    Epoch 18 Loss 1.2198
    Time taken for 1 epoch 19.73851270198822 sec
    
    Epoch 19 Loss 1.2155
    Time taken for 1 epoch 19.734644203186035 sec
    
    Epoch 20 Loss 1.2087
    Time taken for 1 epoch 19.679280948638916 sec
    
    Epoch 21 Loss 1.2028
    Time taken for 1 epoch 19.68713440990448 sec
    
    Epoch 22 Loss 1.1982
    Time taken for 1 epoch 19.645955701828003 sec
    
    Epoch 23 Loss 1.1943
    Time taken for 1 epoch 19.654324989318848 sec
    
    Epoch 24 Loss 1.1908
    Time taken for 1 epoch 19.72608304977417 sec
    
    Epoch 25 Loss 1.1877
    Time taken for 1 epoch 19.701928329467773 sec
    
    Epoch 26 Loss 1.1848
    Time taken for 1 epoch 19.649063611030578 sec
    
    Epoch 27 Loss 1.1824
    Time taken for 1 epoch 19.71220703125 sec
    
    Epoch 28 Loss 1.1804
    Time taken for 1 epoch 19.71992099761963 sec
    
    Epoch 29 Loss 1.1787
    Time taken for 1 epoch 19.692355394363403 sec
    
    Epoch 30 Loss 1.1772
    Time taken for 1 epoch 19.724089884757996 sec
    
    ROMEO:She turned toward me and said--"Oh, you're very beautiful," he added quickly, his voice beaming with happiness. We kissed each other on the lips before going away together."It's a shame she had to go. I don't think she wants us any longer," she said aloud.I asked how long ago they met. She told me she was coming over tomorrow to Liverpool, where we would see each other again."But what do you mean?" I asked curiously.

全部评论 (0)

还没有任何评论哟~