AIGC叫“生成式人工智能”。想必“人工智能”咱们都很熟悉了,因而我想跟大伙儿聊聊这个“生成式”。

一、藏头诗展示

AIGC中的GC不是指“国粹”,是Generated Content的缩写,表明生成内容。看下面这段文本:

掘井须到头 金刀剪紫绒 社日放歌还 区区趁适来
掘井须到南 金钿坠芳草 社会前年别 区区趁试期
掘井须到三 金钏色已歇 社客加笾食 区区趁试肠
掘井似翻罗 金钗已十年 社日穿痕月 区区趁试侣

怎么样?是不是有种《诗经》中“回旋往复,一唱三叹”的神韵。

其实,这每一行都是藏头诗。你仔细看看,榜首个字连起来便是:社区

上面的内容,是我用AI生成的。

下面的内容,我将从原理到操作,讲一下怎么不调API,自己动手写这么个同款AIGC

二、文本序列化

咱们先来做一个小游戏。往往小游戏里蕴含着大道理。

看这么一组数据:

序列1 序列2 序列3 序列4 序列5 序列6
1 2 4 8 16

请问,序列6的值是多少?

答案是32!解题思路:后一个数的值是前一个数的2倍。

我还能够搞更多的数据组,让你去探究。比如:

  • 后一个数是前面所稀有之和。
  • 后一个数是前面2个数的3倍减去22。

即使实在是找不到规则了。比如便是一串毫无规则的乱码。请问它的后边该是什么?将这串乱码再重复循环,也算是规则。

好了。到这儿我想给咱们引进一个概念叫做序列

文字范畴它有一个特点,那便是具有序列(sequence)特征。

我每天都访问社区,从这儿我能获取许多关于___的知识。

空白处该填什么呢?填“备孕”肯定不合适。你能够填“前端”、“人工智能”、“互联网技能”。

哎!你为什么会这么想?因为“社区”是一个IT开发者社区。这句话前边的条件,会影响后边的判断,这便是序列的特点。

那位吃冰糕的先生说了,数字序列的规则我能看出来,可是文字的规则怎么看呢?

其实,咱们能够把文字转为数字。

序列1 序列2 序列3 序列4 序列5
文字
数字 0 1 2 3 4

这样转换后,春晓可用04表明,它俩是等价的。

已然咱们能够分辨出高雅的诗句与一般的俗语,这说明它是有特征和规则的。

因而,咱们能够研究这些序列化后的文本,找找它们前后之间的联系和规则。

那么问题来了,有没有一个好的方案去处理这个问题呢?

三、循环神经网络

小弟我上一篇讲了CNN卷积神经网络,它主要处理图画范畴的问题。可是,到了文字范畴,CNN就怂了。因为它全靠凑数,没有时刻序列这条线。

为了处理具有顺序特征的数据,就呈现了循环神经网络(Recurrent Neural Network)也便是RNN。RNN的重点在R(Recurrent 循环)上。它能够将上一个时刻过程的状况,作为当前时刻过程的输入,从而捕捉到序列中的时刻依赖联系,并使用先前的状况来影响当前状况的更新。

我的话让你感觉很笼统,你也很想抽我。我发一张图给咱们缓解一下。

RNN的结构图一般是这样的:

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

这张图解说了RNN是怎么循环的。X是输入,A是神经单元,h是输出。输入、输出都带着时刻t。这个小单元,他就左手倒右手,转着圈玩儿。凡是经他手的数据,它都会记下一些特征,然后共享这些数据。因而,它就有了回忆。

今日咱们来到我的直播间……呸,来到我的专栏,我给咱们来点更生动的。

我的读者多是初学者。因而,咱们暂时以为RNNLSTMGRU都一样(就像包子、馅饼都是面食)。我不去讲它们的演变史(我厌烦技能课变为历史课)。

为了便于咱们理解,我特意画了下面这组动态图。

在某个序列t时,将数据X输入。这个输入数据的格式,后边会重点讲。在这儿,咱们要了解数据是依次导入的,也便是一条数据转一个单元。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

再看下图,这儿演示了单元内部细节。Xt是和ht-1一同进入的。如果Xt这个时刻代表“春眠不觉晓”的“眠”,那么ht-1里肯定也包含了“春”的回忆信息。

下面是它的输出示意图。输入X结合了ht-1,又输出了新的ht供后边使用。

RNN便是这样运作的。循环、递归、回忆传递是它的主题。

好了。道理就讲到这儿,再多说,你就要关页面了。下面开干,写代码!

四、实践项目:AI藏头诗

  • 项目名称:使用RNN完成文本生成,写藏头诗。

  • 运行环境:Python 3.9TensorFlow 2.6

  • 代码来源:ChatGPT

已然本文讲AIGC,那么咱们就要体现出它的妙用。我向ChatGPT咨询怎么完成我的主意,它给出了答案。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

作为一个专业演员……人员。我负责地告知你,它的回答,过程明确、完全无误,在数据集完备的情况下,能够直接运行。

这说明了什么?

  • 榜首,人工智能的初级使用并不悠远,也并非被置之不理无法企及。
  • 第二,简单的需求真的是马路边上的东西,可是不为人所知,因为没有人去传播。

下面,我就拿老Chat的代码,依照我的思路,逐个解说并完成。

4.1 搭建神经网络

刚刚学了RNN,那么咱们就来组成一套循环神经网络。tensorflow能够经过Sequential来构建网络模型。

import tensorflow as tf
vocab_size = len(vocab)# 词汇表巨细
embedding_dim = 256    # 嵌入维度
rnn_units = 1024       # RNN单元数量
batch_size = 32        # 批次巨细
# 构建一个模型
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)
])

上面这段代码是整个比如的核心部件。其上游代码为它供给弹药,下游的代码则分析它的产出。

4.1.1 网络结构图解

这个结构很简单,Sequential中就三个层:Embedding作为数据输入、GRU作为神经单元处理、Dense作为结果输出。

下图拿生成诗句举例,对每层做剖析。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

中心是咱们熟悉的RNN层,尽管它叫GRU,但它归于RNN宗族。代码中参数rnn_units是神经单元的数量,这个咱们能够自己调。

咱们上面说那么热闹,其实只说了一个根本单元的工作。到真正干活时,是需求一堆单元来处理一条数据的(上图X要衔接多个RNN单元)。其他的参数你记住就能够了。

4.1.2 词汇表和嵌入层

下面说说词汇表和嵌入表。不管输入还是输出,咱们都要用到它。正是经过它们才将文本转为数字的。

你想让RNN自动生成,条件是它得有料。词汇库便是这个料。

假设咱们拿一堆诗句来练习模型,现在诗句也现已变为了数字。接着,咱们要做两件工作:

  • 榜首:将数据传入模型,让它找规则(联想1、2、4、8那个游戏,规则是2倍联系)。
  • 第二:给定一个开始值(藏头诗也是给一个字),让模型猜测后边的数字(32后边是64,64后边是128)。

为了完成上述内容。咱们界说了词汇表,用于文本转数字(眠->1)。

咱们又界说了嵌入表,让它对一个字进行多维度的描绘。0、1、2作为字的代号还能够。春眠是01,春晓是04。但关于文本生成来说,它的颗粒度太糙了。凭这,想要找出文学中深层次的内涵规则,根本不可能。还是得将这个字拆成粉末,转为几百维度的向量靠谱。

每个字的向量具体是多少,你肯定不知道。咱们正是想让神经网络自己去找(反向传播算法)。所以,咱们只下界说就行。因而,咱们看到代码中呈现了embedding_dim = 256,这是一个有256个维度的嵌入向量。

4.1.3 Dense层的巨细

我看看还有啥值得说的。哦!Dense(vocab_size)表明输出层的巨细是词汇表的巨细。意思便是说,它推测出来的下一个字,是词汇表中的某一个字。

读到这儿,你再回头看看上面的图,根本上就茅塞顿开了。

好了,大脑现已完成了,下面就让咱们去写无脑的代码吧。

4.2 处理练习数据集

已然想要生成藏头诗,那么首要得有一些诗句作为引子。

我自己攒了一些五言古诗+五言对联的语句。有多好不敢说,反正文绉绉的,大约15万条。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

4.2.1 读入文件内容

首要读入这个文件,并生成词汇表。

# 读取文件 
with open('poetry.txt', 'r', encoding='utf-8') as file:
    text = file.read()
# 去除重复字符并排序
vocab = sorted(set(text))
# 创立字符到索引的映射字典
char2idx = {char: idx for idx, char in enumerate(vocab)}

poetry.txt便是存放五言语句的文件。这个文件连同源码,我会上传到Github,链接会附在文末。

建议咱们使用jupyter工具,能够逐渐履行,检查履行情况。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

上面的代码,text读取了文本内容,vocab是文中一切呈现过的字,做了去重和排序处理。这便是咱们的词汇库。有了它,文字就能够变为数字了。

text = "春眠不觉晓 处处闻啼鸟 夜来风雨声 花落知多少 ……"
vocab = [' ', '一', '丁', '七', '万', '丈', '三', ……]

4.2.2 整理并序列化数据集

下一步,咱们开端组织练习用的数据集。

# 将文本切分为5字一组的数组
sentences = text.split(" ")
x_sequences = []
y_sequences = []
# 组织出练习集(输入+输出)
for sentence in sentences:
    x = [char2idx[char] for char in sentence[:-1]]
    y = [char2idx[char] for char in sentence[1:]]
    x_sequences.append(x)
    y_sequences.append(y)
# 转为tensor数据
datasets = tf.data.Dataset.from_tensor_slices((x_sequences, y_sequences))
# 将数据批次化
datasets = datasets.batch(batch_size, drop_remainder=True)

上面多是常规操作,我着重讲一下输入和输出的制作。

咱们希望模型能达到较高的认知水平。举个比如,咱们起一个头叫“春”,模型会生成下一个字是“眠”。以此类推,练习集的输入和输出总是会前后错开一个字。

谈谈RNN生成文本的小原理,动手实现AI写藏头诗

这便是为什么输入sentence[:-1]不要最后一个字,输出取sentence[1:]不要榜首个字。咱们希望模型依照这样的思路去探究规则。

4.3 练习模型,保存权重

练习的代码其实很简单:

# 界说损失函数
def loss(labels, logits):
    return tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True)
model.compile(optimizer='adam', loss=loss)
# 练习回调,模型保存途径
callback=tf.keras.callbacks.ModelCheckpoint(filepath="tf2/checkpoint", save_weights_only=True)
# 进行练习
model.fit(datasets, epochs=100, callbacks=[callback])

只要对模型做简单的装备,然后调用model.fit就能够练习了。

  • model是咱们一开端经过Sequential创立的。
  • datasets是上一步组的数据集。
  • epochs=100是练习轮次。1个epochs表明把所稀有据跑一遍。
  • 练习的最终模型将会保存为tf2/checkpoint

这15万数据,关于一般电脑来说,压力很大。我设置的100epochs才跑了40,就花费了3个多小时。模型的效果,便是文章开头的那样。

其实,咱们在学习的时分,能够适当地减少数据量或者epochs来进步验证效率。

练习过程会有如下打印:

Epoch 1/100
4600/4600 [====================] - loss: 5.8752
Epoch 2/100
4600/4600 [====================] - loss: 5.4711

每个Epoch结束,都会有权重保存下来。

4.4 验证模型,生成藏头诗

正常情况下,练习完了。你只要给模型起个头,后边它就会喋喋不休地输出。

# 给定1个字,变成5个字的办法
def generate_text(model, start_string):
    num_generate = 4   # 生成的字符数
    # 开始字序列化变为数字
    input_eval = [char2idx[s] for s in start_string]
    input_eval = tf.expand_dims(input_eval, 0)
    text_generated = [] # 存放生成的字符
    model.reset_states() # 清空本轮回忆
    # 循环4次,每次生成一个字
    for i in range(num_generate): 
        predictions = model(input_eval)
        predictions = tf.squeeze(predictions, 0)
        # 猜测最可信答案的序号
        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))

代码注释比较全面了。

  • start_string是开始字符。便是藏头诗的榜首个字。
  • model依然是咱们建立的那个RNN序列模型。如果要加载练习好权重,能够调用model.load_weights("tf2/checkpoint")

咱们实验一下效果:

generate_text(model, "请")
请以端溪润 
generate_text(model, "嫁")
嫁来贤妻喜 
generate_text(model, "给")
给园支遁隐 
generate_text(model, "我")
我欲掣曳箭

咋说呢?咱们不是专业的诗人。可是,单看这个词汇与风格,唬人应该不成问题。

五、结语

说正经的,这用的是古诗数据,它会生成古诗。如果供给别的呢?

我希望本文能给诸位起一个头,让它四处散播,然后在各个行业与范畴,生根发芽。

整体项目源码地址(含数据集):github.com/hlwgy/jueji… 。

本文为稀土技能社区首发签约文章,30天内制止转载,30天后未获授权制止转载,侵权必究!