ChineseAiDungeon开发log - 1

ChineseAiDungeon

这个文章是一个中文版的ai dungeon的开发log。这里记录一些尝试和结果。

07/02记录

开发已经进行了一周,项目已经进行比我想象的久了很多,原本计划一周完成数据采集和模型训练但是现在来看,再来一个月都不一定足够,现在记录一下项目开始这一周以来遇到的问题以及尝试的解决方案

首先是环境问题,CPM的与训练模型有9G(2.6B参数)之大,导致清华默认使用torch的一个分布式解决方案apex来进行训练,而我的硬件条件显然无法使用双卡(我只有一张),所以只能寻找其他解决方案,https://github.com/qhduan/CPM-LM-TF2提供了一个相当不错的codebase,可以用tf2的格式去读,用和训练CPM模型,当然,不可能时9G之大的原始模型,而是16fp的版本(4G多大小)。

尝试之一就是直接使用小样本(我自己花了一整天标注了4篇文章,标注成了ai dungeon的格式),进行GPT2的finetune。

这一过程并不顺利,首先标注结束之后我发现标注的生成内容其实太少了,对比AI dungeon的标注数据如下:

Ai dungeon 标注数据

> You punch pollux in the stomach
"Oof!"


      While you were punching Pollux, you got elbowed in the back by Teirnus, then beaten to the ground and left as the teacher rang the bell to signify the end of the day. The days that follow are filled with worry and your parents constantly yelling, "What were you thinking? They're Black Hands!" and "They're coming for you! What will we do when they come?"


Four moons later they came for you. With your throat slit and your body beaten, they hang a sign on you which reads, "He fought against The Black Hands! See what happens?" Now the Lands will never be free!

我的标注数据:

动作:
做
去爬山
结果:
天上的太阳已不再那么炽热。你和妻子开车从长沙市中心出发,一路奔向黑麋峰。他们按照路牌指示来到山脚,望着蜿蜒而上的石阶,看到前面有不少累得直流汗的人。
梗概:
你和妻子出发去爬山
--------------------
动作:
说
我们要走多久?
结果:
“差不多一个小时”你在听到这句话后,面色顿时沉了下来,“一定要爬到山顶上去吗?”“当然,我们来此的目的就是为了锻炼”
梗概:
你得知爬山要一个小时
--------------------
动作:
说
 这儿有没有更便捷的上山方式,比如把车子直接开上去
结果:
“不行,只能一步步走上去”   为了激起你爬山的兴致,妻子安慰你说,“在这座山顶有一栋百年寺庙,每年有数十万人来此上香。当我们到达山顶时,从西边望去,还能够看到整个长沙城的全貌”
梗概:
你得知没有更快的方法上山
--------------------

之所以对标注了梗概是因为一开始我对ai的梗概能力有着不切实际的幻想。最开始的方案时这样的:

  1. 使用上面语料,让ai同时学会续写,扩写和梗概
  2. 让ai把前面几步的梗概作为上下文,而非像ai dungeon一样使用上下文文字。
  3. 使用非常少的样本对GPT进行finetune,让它知道我想要干嘛

我很快发现GPT的小样本学习能力只存在于推断时,在fine-tune时如果拿着few shot setting的数据喂给他,只会产生严重的过拟合(下文会提到)

第一波的训练使用了类似上面的语料,大概合计15k的语料,训练很快,但是结果不是很好,ai似乎什么也没学到,loss也不降低。

https://github.com/TsinghuaAI/CPM-1-Finetune里边提到

进行 fine-tune 训练的时候可以选择 fp16 或者 fp32。我们在实验中发现,在使用 fp16 进行训练的时候,需要加载预训练时的动量才能使模型较快收敛,而采用 fp32 训练则不会有这个问题。因此,我们推荐直接使用 fp32 进行 fine-tune 训练。

但是我是没有训练fp32这个硬件条件的(尝试过,1个sample都会OOM)。所以只能拿fp16的模型来训练(fp16大概能塞下2x500的batch)。

在第一波的训练中,我将文本格式化成类似如下形式:

--------------------
动作:
说
我们要走多久?
结果:
“差不多一个小时”你在听到这句话后,面色顿时沉了下来,“一定要爬到山顶上去吗?”“当然,我们来此的目的就是为了锻炼”
梗概:
你得知爬山要一个小时
--------------------

和标注格式一致,直接给GPT-2去finetune,结果很糟糕,loss根本不降,GPT-2什么也没学到,在test集上也基本是胡说一通(这里没留数据)

然后我做了两件事

  1. 收集ChooseYourStory网站的数据,然后直接用google translate翻译成中文,然后写脚本整理成新的语料
  2. 在小数据集(我自己标注的4篇文章)仔细调整了学习率,并且使用ai dungeon格式

ChooseYourStory语料是其他人爬的https://github.com/interactive-fiction-class/interactive-fiction-class.github.io/blob/master/homeworks/language-model/text_adventures_test.txt
格式是:

> You west
You got chased and ran into a dead end.


You made a wonderful tarred body after a long last stand.


You ran out of arrows, then Sparrow's sword broke. After that, you were stabbed and killed while Sparrow was sold into slavery.

翻译完了后变成和我标注的格式相同的格式

<start>
故事名称:
1
故事背景:
你在平静的浅水池中醒来,在风的呼啸和冰冷的爱抚中醒来。月亮从上面满是星星的天空注视着你。它苍白的灯光照亮了你脚下光滑石头缝隙之间生长的苔藓和茂密的草。树根弯曲,长满苔藓,伸向天空,在这个奇怪的无墙花园中可以看到的几块裸石上投下阴影。空气比你所感受到的任何东西都稀薄和寒冷。它呼啸着穿过树木和草地,声音类似于吹过断笛的空气。你颤抖着站了起来。当您缓慢谨慎地朝花园边缘迈出一步时,一阵窒息的声音从您身边溜走了。你向任何和所有的神祈祷和乞求,但是当你的脚停下来时,你诅咒他们,你诅咒他们所有人。一块小石头从花园的石边上坠落。你抓住你旁边的树,看着它倒下,知道它还在继续倒下,即使你看不到它。当您注意到远处闪烁的暖黄色灯光时,您会感到头晕目眩。你看到的就是你的家。  泪流满面,“不……”你跪倒在地,挣扎着想要呕吐的冲动。  你在蛇王的塔顶。  你在邪恶花园的顶端。  而你会死。    在你身后,最黑暗的阴影中发出一声深沉的笑声。它穿过树林,比寒冷的风更能冷却你的血液。闭上你的眼睛,你把你的心放在喉咙里,背对着你的家。你咽下口水,睁开眼睛去面对为你而来的一切。  黑暗变浓成黑夜的丝带,汇聚在一个点上,直到一个衣衫褴褛的苍白男子出现。他毫不费力地漂浮在你醒来的浅水之上,用充满漩涡墨水的空心眼窝看着你。他对你说话,但他干裂的嘴唇一动不动。  “每一层楼都提供了新的挑战。通过并继续。”  大地震动,灰人脚下的水荡漾开,流走。当它们移动以形成下降的螺旋时,它会从石头的缝隙中渗出。雾或可能是蒸汽的东西进入花园只是洒在塔的边缘。你看着它,楼梯,那个衣衫褴褛的人。  “追随前人的脚步。完成他们不能完成的事情。”  你吞了吞口水,走到楼梯的顶端。但在你迈出另一步之前,你最后一次环顾四周,并将其全部记入记忆;天空,树木,远处的村庄。你叹息。
--------------------
动作:
做
 你走下楼梯。
结果:
衣衫褴褛的男人一脸不偏不倚地看着你 你回望,直到你再也无法直视他的眼睛。您别无选择,进入邪恶花园的中心。  “赢得你的自由;正确回答,否则死亡。”    ~    当您越来越深入地走进 塔楼时,您会注意到楼梯通向每一层楼,您和塔楼外墙弯曲的石头之间只有空旷的空间。时间过去了,但多少暗示了你,因为没有窗户可以看到天空中的太阳。这一切似乎有点太容易了;奇怪的是,没有什么能阻止你下降到下一个级别。你想知道其他被选中的人,或者更准确地说是为这座塔献祭的人。  他们通过了这些楼层吗?  当你走到一扇门时,你会回想那个衣衫褴褛的人说的“完成他们不能完成的事情”。它随着一条小溪摇摆开来。你凝视着远处的黑暗。
梗概:
 你走下楼梯。
--------------------

当然这些预料里边存在着大量垃圾,质量低的文本,但是也没什么办法,国内没有和ChooseYourStory等价的网站。

由于之前的训练失败,我怀疑是输入太过于格式化,于是把输入转换成了类似ai dungeon的格式,即:

> 你做了xx使
结果xxxxxxxxxxxxx

顺便一提我把所有结果中的换行符去掉了,不知道这个会不会影响
在使用2e-5的学习率后模型可以在4篇文章的小数据集上收敛了,我马上把这个方法用在了我是用google翻译搞来的4M的语料上,结果第一个epoch还没结束loss就爆炸了,

于是我换成1e-5的学习率,这回loss可以慢慢下降,经过一晚上可以从2.7降到2.6多

但是我尝试用它来生成文字,结果会得到这样的结果:

你是一个公司老总,你事业正在上升期,你娶了一个美丽的妻子
> 你走进你的家门
> 你走进你的家门
> 你走进你的家门
> 你走进你的家门

有时候也会输出正常一些的文字

你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 家门 
 你 的 妻子 是 一个 美丽 的 女人 , 她 的 头发 是 金色 的 , 她 的 眼睛 是 蓝色 的 , 她 的 嘴唇 是 红 的 , 她 的 鼻子 是 粉红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴唇 是 红色 的 , 她 的 嘴

但是总的来说不是很理想

但是与之对比的是原始的GPT-2模型(不去finetune他),不知道清华那帮人给原始的GPT2喂了什么,总是会产生一些奇怪的结果:

你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 家门 
 >   你 看到 你 的 妻子 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的 妻子 正在 为 你 准备 晚餐 
 >   你 的

质量不高就算了,还是重复的,从表现看完全没有学到“〉” 之后的是动作,下面一行是结果

由于得到了这样的结果,我想尝试一下在小数据集收敛之后,是否可以学到“〉” 之后的是动作,下面一行是结果这个知识点,所以我用同样的学习率1e-5在4篇文章的数据集上训练400+epoch,loss收敛到0.2x

图里只收敛到了2.x,但是实际收敛到了0.2x
结果发现即使只提供类似下面这样的输入,也能产生稍微有意义一些的回复,至少学到了“〉” 之后的是动作,下面一行是结果

你是一个公司老总,你事业正在上升期,你娶了一个美丽的妻子
> 你走进你的家门

但是续写的结果并不好(没有记录下来)。

决定下一个实验是尝试使用4M的翻译过来的数据集训练,并且训练时间拉长,训练一整个周末

补充记录

补充一个200epoch的4篇文章过拟合记录

使用2x500batch 进行230epoch,结果是loss收敛如下:

续写结果如下:

 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 家门 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 家 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 卧室 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 卧室 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 卧室 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个 美丽 的 妻子 
 >   你 走进 你 的 卧室 
 你 是 一个 公司老总 , 你 事业 正在 上升期 , 你 娶 了 一个

清华大学可能给GPT为了什么奇怪的数据,使得gpt异常喜好反复重复一种前问文pattern,而这种pattern寻找和利用正好是gpt2的卖点,我觉得清华大学可能为了好看的demo专门找了奇怪的数据给GPT2,专门强化它的pattern寻找能力 .如果是这样的话,pretrain的model基本就是废了,需要更多证据支持这种claim

07/05记录

周末训练了2天15小时的模型,今天验收了下结果,loss收敛情况非常一般

train loss收敛在2.63,test loss收敛在2.606,都没有继续往下走的趋势
这里说明为啥test loss比train loss小一些,因为test set 是百度翻译的,train set是谷歌翻译的,很有可能百度翻译的质量更好一些,因为整个训练过程是在finetune清华cpm,所以可能百度的质量更好,更符合中文语法,导致loss更低。

其实2.63的loss也凑合,所以打算测试一下

写了一个story的管理类

class Story():
    def __init__(self,beginning,story_max_len=150,context_len=6):
        self.story = [beginning]
        self.story_max_len = story_max_len
        self.context_len = context_len

    def action(self,action):
        action_str = "> 你" + action
        self.story.append(action_str)
        q = "\n".join(self.story[-self.context_len:])
        response = sample_gpt(cbpe, gpt, q, 1, 150)[0][len(q):]
        self.story.append(response)

    def interactive(self):
        print("\n".join(self.story))
        while True:
            action = input("> 你")
            self.action(action)
            print()
            print(self.story[-1])

感觉终于可以尝试一下现在这个版本的ai dungeon搞出来的故事是什么样的了,结果并不尽如人意,下面是一个节选:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 向树林深处走去

又走了好一会儿,天空中闪烁着明亮的光,可以让您看到厚厚的森林。森林真的很茂密,简直盖过了一座小山。光线从树叶的缝隙中穿过,洒在到处都是苔藓的地面上。一块足够小的地方可以放下你的任何东西,这里只有一个入口。
>你向前方跑去
你又向前跑了一段路,接着就穿过了一排排小房子,进入到一个闪烁着明亮光的新绿之中。森林的最北端是一片绿色的山丘
> 你 走上绿色的山丘

!这是一个尽头!你超越了上方的树枝,开始迈开两条腿走。远处的太阳照在地面上,你们能看到下面的大地和蓝天。你带着一股干净的气息站在他们面前,在它温暖的空气中嗅着它的芳香。你四处走动,寻找一些舒服的地方,然后试图将注意力集中在工作上。你在这里感觉就像是重新开始,并没有多么不适合那个在遭遇那些黑暗森林居民的泥土之前一直被囚禁的地方。你决定冒险进入他们的地区,在他
> 你 寻找黑暗森林居民


你的眼睛盯着周围的森林,确保它荫凉、新鲜、没有被害虫吞噬的东西。当你开始四处漫步时,冰冷的光线洒在你的身上,你感觉像是在走向坟墓。突然,你看到了一个黑暗的阴影,坐在周围的树林阴影的一侧。“那是什么,小丑?我看不清楚,但它看起来就像是我生命中最重要的东西。你那双毛茸茸的身体就像是流着口水的白色犀牛。......”你听到它的声音,
> 你 问他是谁

说它是什么,小丑?”你朝它靠近,怀疑地收起了刚才在本能下可能看到的手臂和腿。“它是一个女人,”你说,举起了一把匕首,“她在这里,你看看。我不想这么做,因为它看起来太令人惊讶了。我不应该被她占据时间,更不想做一个猎物。”你听到她咯咯的笑声,当你凝视她时,她将笑声投向你。你张开嘴巴,慢慢地张开
> 你 问她是什么人

那一刻真的是在搞笑,在你以一种痛苦的好奇心看着她。然后你开始享受其中的乐趣,转向马,它已经开始跑向你。几分钟后,尽管你觉得有点累,你相信小丑真的存在。马身细长,可是每个部分都小得可怜,边跑边拉,旋转,骑,边撒吃的。你骑着它飞驰而去,飞向远方。你回头看了看,小丑仍然在他的阴影中闲逛,眼睛在悄悄望着什么。你环顾四
> 你 ok你到底是谁

知不觉已经跨过了地雷区,越过了叛徒。当你猛踩加速时,小丑举起了剑。你将匕首刺入他。一阵风,有微风和尘土吹开了他,时间似乎静止了。你们在一棵大树下面,“蒂德,我来消灭你。我在树林里长大,是个德鲁伊,这是我的故事。我是人类,是个性感玛丽。我只想知道自己是谁,想寻找自己的生活。但你知道,这并不重要。
> 你

Hmm翻译腔非常重,这可真是绝了,说明这次的训练还是学到了东西,但是学到的是非常差劲预料(翻译得到的4M语聊)里的东西,比如奇怪的外国人名,上下不接的机器翻译腔话术等等。 回想起来aidungeon博客里也提到,小的,质量高的语料比大的,质量低的语料有用。

虽然生成质量很差,但是其实初步说明了这条路是可行的。接下来我想尝试把这个类用在

  • 标注的四篇文章训练出来的模型上
  • 原始的CPM模型上

可能对比一下能够更好的说明模型到底学到了什么,有哪些东西是遗忘掉了的

首先对比了一下原始的CPM-fp16权重在这个故事代码框架下产生的东西:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 向树林深处走去

很快发现:
......

> 你 发现了什么东西

你听到了奇怪的叫声,转过身一看......
你看到了成千上万只动物正在排队,齐声高呼着号叫
真的,成千上万只,他们都象是在冲着你叫,不是喊着你的名字,而是唱着你的名字,他们共同唱着同一句话,那句话的内容是


> 你 他们唱的是什么?

每只动物唱的都不一样,所以你应该仔细听,是不是这只在唱

> 你 仔细听

是象这样唱的:


> 你 他们怎么唱的?

这样唱的:


> 你 我不知道怎么唱的呀


> 你

CPM-fp16原始权重产生的故事连贯性明显更强,但从产生的结果看他并不知道动作(由“>”衔接)和结果是有逻辑关系的,我更希望看到是连贯的故事。

但是这个实验表明,使用4M翻译语料训练的模型确实一定程度上由于语料的翻译腔,低质量损坏了CPM的原来的一些好的特性。但是4M语聊训练出来的产生的动作结果明显更丰富,更长,所以说并不能得出结论GPT2不需要finetune就能符合中文 ai dungeon的需求,而是说要有足够好,足够多的语料。

接下来对比下在4篇文章上finetune 200轮的一个模型的表现:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 向树林深处走去

忽然停下来,环顾四周并没有什么发现,于是你再次加快脚步,低着头穿过了草甸,你的心完全提到了嗓子眼,甚至你在脚底下感受到了空气在流动,然而你的脑海里却不断回响着道路两旁冲天的火铳声

> 你 趴在道路旁边,看看是谁在打火铳

咚咚咚”,一阵急促的敲门声打断了你的胡思乱想,你不得不从地上跳起来,透过窗户向门外张望


> 你 看看窗外有什么

指伸到了门缝里,一把德国造小锁准确无误的锁上了,你冲了个澡,擦了擦手,走到门外,用刚才开门的那把小锁打开了门锁

> 你 走出门去

走廊两侧墙壁上的画像
“嘿嘿,是个新来的巡捕,我又找到新任务了”你的心情十分的愉悦,你把手伸进袖子,脱下上衣和短裤,走到楼梯边的椅子坐下

> 你 看看旁边有什么人

杂志架边翻出来本《时尚》杂志,你走到大封面那一页,抬头环顾四周

> 你 问旁边的小姐姐,这里是哪里

姐姐看了看那本杂志,看了看你的脸,你的表情突然严肃起来,你抬起右手,用大拇指挑起包在塑胶柄上的金钢钻,眯起棕色眼睛盯着《时尚》封面上的龙,你右手指着龙的双足,粗声粗气且不容置疑地说


> 你 说“小姐姐,你是谁呀”

是哪个?”你的表情立刻认真起来,在老板娘身边坐定,礼貌地向那个冒失的小女孩躬身道


> 你

另一段同一个模型生成的故事

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 向树林深处走去

你在树林里摸索了许久,也没能发现什么蹊跷,只能无奈的往回走
路又变长了
经过这一番折腾,你原本就有些微驼的身体更加羸弱了,你打了一盆水,走出树林,找了一块没有任何人的平坦地,搓了搓胳膊上的伤
> 你 包扎伤口

包扎完伤口,一步一挪地朝树林里走去
“你,你......”你用手挡住一个藏在草丛里的人,气喘吁吁的说道
那个人看着脸上脏兮兮的,不过衣服洗得干干净净的男子,点了点头,“你为什么会在这里?”。”你问道
“你”是隐去了大名
一个脸色铁青的男子出现在两人面前,二话不说,给了面前的男子一记耳光,把眼前的人身上的衣
> 你 劝架

张嘴说道,“你这个下作的东西,还不快点滚,我们可要动手了
“你”是隐去了大名
你觉得有些不妙,皱眉喝道
你皱起了眉头,“你”是改了声音,你问道
“你”是隐去了大名
你凝望着眼前的男人,从他紧张的神色中,似乎对面前的这个男子,有所忌惮
“你”是
<eod
> 你 开枪打两人

咬牙,咬定牙关扣下了扳机
你一把抓住靠在树上的凯文,用力的推了过去
“你这个怂包,缩头缩脚,要不是看在你是队长的份上,我才懒得去找你麻烦
“你”是改了声音
你一把拉起了凯文,“快别拉了,要不我一发子弹,咱俩这梁子,就别想轻易的了”
“你你”是改了声音
你一把抱住了他,开始啃
> 你

效果感觉一言难尽,于是我用同一个模型再生成了一段故事

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 掏出手枪,上子弹
看向面前的小屋,没有人,也没有鸟鸣,难道是自己在吓唬我?别想了,放松一下吧,今晚的冒险会更加刺激

> 你 推进面前的小屋
的穿过小屋的门,拾级而上,映入眼帘的是一口巨大的老木头做成的棺材,上面居然镶嵌着蓝宝石般的宝石,周围摆放的都是据说能提升你各个方面的能力的神奇物品,面前的木桩密密麻麻,大概有数千根吧

> 你 拿走蓝宝石,不打开棺材
,那个两尺高的棺材打开了,露出的真的是一个人,一身的黑衣,头发是黑色的,身板挺直修长,只有一米八多点,身高在五尺六的瘦高个看起来有点不显眼,一双目如秋水,白皙的额头,胡须修剪整齐,头顶是一个足足五尺的黑色礼帽,大大的墨镜遮住了半边脸,虽然看不到相貌,但总觉得这个人与自己有一丝不搭调

产品特色你是特种兵宣传海报就前面传
> 你 拔腿就跑
步追来的你,上尉杨进泽上尉睁大的眼睛,一副惊弓之鸟的表情,摸了摸头盔上的黑色头盔,迫不及待地冲你跑了过去,“壮叔,真的是你吗?怎么觉得你比照片上的人还俊俏

> 你 说“你是谁”
打伤的壮年人一下子瞪大了眼睛,不等你回答,已经拉着你向门外的木门前跑去,你的下身传来一种触电的感觉,脑海里立即闪过昨天看到的那个机器移山队员尸体带电的尸体在门口抽搐的场景

> 你 说“你是机器人?”
口呆
用仅能控制的手,你机械地应了一声“对”,一只粗大的移山队员床拖到了你的面前,这次带来的床是用绳子捆在木门上的,你被挡在外面站在床头,移山队员整张被切掉,左右两侧的胸膛和脏器已经被破开,肋骨、碎心、肠子、各种碎肉,头胸以上还有一道道的长长的切口,密密麻麻的,你看了看被子,上面已
> 你 拔腿就跑
咬牙,用仅有的左脚支撑着墙壁,无比艰难地向移山队员的卧室挪了过去,推开移山队员的卧室房门,你一个箭步跑到床前,紧紧拉住移山队员的右臂,你的右手筋已经被移山队员的五指压得酸痛无比,你从来没有感受过你的右手被一支拳头大小的钢矛狠狠扎在那么一下,抓着你的壮年人的手,那手指的皮肤,皮肤里面有无数的小疙瘩,混杂着汗液、粘膜和
> 你

我又尝试了一下使用一个在这4篇文章上稍微过拟合的模型生成故事,这个模型同样适用我自己标注的4篇文章,但是训练了290个epoch,已经开始有过拟合的迹象:

用这样的模型进行了一个故事生成实验:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 把手枪上膛

你抱起枪,快步穿过大街,穿过两条街之后,你终于来到了镇子的东头。

> 你 进入酒馆

街道西头就是酒馆,你踌躇着走进去,迎面吹来的风中夹杂着酒臭,不过这对你来说已经是一个好的开始了。

> 你 点一杯啤酒
你走到吧台后面,点燃了一杯酒,新鲜的啤酒花洒了出来,不过这已经是你能容忍的最低限的气味了

> 你 在酒吧找个人聊天
吧台边坐下,随意和吧台里面的一个家伙搭上了话,你很好奇,偌大的山区会遇到些什么。,你等这位大叔回答

> 你 说“你好,我是一个探险家”
是”探险家来说现在你应该有了一些成就和见识,至少你在一座乡下小城的发展已经有了一些眉目

> 你 等待对方的回答
看吧台里面有什么人

> 你 花钱给大家点一轮酒
识认识新朋友

> 你

更多时候生成的故事在几轮之后就无法进行下去了,比如下面这个

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 往树林深处走去
你站直了身子,向树林深处走去。在他乡里,树林是这少数有人居住的区域,他们常见到这里黑暗而肃穆的气息。
> 你 寻找人影
走到了尽头,朝四周扫了一眼,这里都是大片的未开发土地,除了种些菜的空地之外,便只有一些不小心闯入视线的树丛。
> 你 走到一个村庄
到镇子的主要街道上,从满身疲惫的士兵身上的军服,你依稀能分辨出前面的官道上,时常能看到巡逻的兵马和穿着制服的村民点头致意的士兵,这是一个男人应有的威严
> 你 和士兵攀谈
前这个刚刚从战场上下来的男人,大胡子女人努力忍住想上前打断他们说话的冲动
> 你 继续向前走,找个酒馆
这里有许多许小小的酒馆,因为你是这里唯一的英国人商人
> 你 进入最大的一个酒馆
缘故,镇子里的铺子都变成了上了锁的空屋
> 你 点一杯啤酒
国人,这里的酒吧拒绝和你攀谈的士兵和你交流
> 你 走出村子
歪斜砖墙和满是污垢的灯泡相互撞击的小酒吧窗格里漏进的黄光,酒香都早已飘到窗外来的青翠山茶树上的,一只灰色的小猴欢快跑过长满苔藓的石头走廊的声音,扑棱棱地从古董走廊里回来了彻夜写一个叫koon-ay的小说家,这个长相憨厚的中年男人,是一个狂热的登山爱好者
> 你 问他在这里做什么
的做法事的男子,

这是一个拥有火辣身材的土耳其裔男子,这里的旅行者用蹩脚的英语问来这座镇子的大城主人
> 你

也许是语料的原因,在这些尝试中,我一直无法达到ai dungeon程度的一致性和故事连贯。

由于怀疑是语料质量不够导致的,所以尝试使用原来的test set(40篇百度翻译的Choose Your Story语料)来进行训练,经过100epoch训练,loss如下(test loss是用原来的train set 客串的):

train loss 大概到2.44,test loss在2.74左右

事实上,使用这份质量稍好的语料训练,生成的故事的连贯性好了一些:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 往树林深处走去
你坐在一棵树上,把手枪插进裤带里,一边倾听父亲的吠叫声,一边翻看当地杂志。
> 你 继续走进树林
看了看表,应该是凌晨1点,你决定睡到树林里。你看着树林中心的灰烬,呼吸着深夜的空气,变得清醒起来。围绕树林一周的都是山区,就是乱石区和树之间的沙漠。
> 你 走进前面的城镇
续前进,把手枪插进裤子里,继续翻看当地杂志。
> 你 找一个旅馆
一步,仔细搜索地图,希望能找一个能离大多数人口超过几个街区的村庄。你找到一个已经废弃的木料仓库,和杂货商生活在一起。你走进镇上的酒吧,你想找一个住宿,但最后没有。你继续走进城市,进入一家咖啡馆,找到一处暗巷,这样就可以借助街灯的微光投下的阴影,来寻找一个能过夜的地方。
> 你 在暗巷休息
你意识到在午夜过后很多时间,这里是个安全的地方。你从厕所里出来,喝了一杯咖啡,吃了一片薄荷口香糖,舒服地瘫在一根香肠上。你蜷缩着,躺到越来越黑暗的街道上,聆听阳光在柏油路面交织的嗡嗡声。北方的朦胧光线越发显得暖和,就像地面上篝火的残焰。你听到车轮碾压碎石的声音,然后意识到这正是你走过的地方。然后,你感到一阵酸水入侵了你的骨头,用手抚摸最
> 你 起身
下,因为作为一个轻步兵,你穿着原来的制服,如果你继续睡着的话,一会儿你会感受到手指和手指关节的撕裂,或者按压你的脊椎,从而对心脏造成损害。你蜷缩着,身体的某个部分不断受到震荡,搞不好你就会导致脊柱断裂。但是,你意识到如果你不起来,后面的那个家伙会一把抓住你的脖子,把你从我们的烤炉边拖走。你弯腰从他身上爬下来,但是那个家伙绕到了车底
> 你 拔腿就跑
出来,你的背疼得很厉害,你痛苦地让自己扭着疼痛的身体,重构你的身体,躲在灌木丛后面,直到脚疼痛地从雨林返回。你从树林边缘走出来,站在那里,查看周围的情况。有辆汽车停在村子外面,前面的路很狭窄,而你蜷缩在森林里避风。这是一个英勇的时刻,有极少数时刻你会被崇拜。这是你从战场复归的姿态,以至于你从春天回过头来时变得迟钝。在你穿过
> 你 上车
开始愉快地往旁边张望。在小路另一边,有辆卡车在等着你,驾驶座上有个饥饿的警察。一大堆士兵从旁边向你挥手,向后排挥舞着你的手。如果你搭车,警察就不会注意到你,因为你没有车,他们都是和你一样的军人。他们都闭嘴了,甚至停下来帮忙。如果你愿意下车,他们就会跟在后面,跑过去,送你们过桥。
> 你

另一段生成的故事:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 把手枪上膛
现在你得到一张地图,一半是绿色的,一半是紫色的,地图之间没有什么东西可以区分。不过你依然能够看到这片新土地的大部分区域,在里面你会遇到一些和这次探险有关的奇怪的东西。
你沿着海岸线前进,希望能够找到更多有用的信息。在做这些事情的时候,你终于结束了关于“黎明守卫”的争论,回到了自己身上。
你突然在意识到他已经离开后,你开始想办法把实际上是你的东西“拿走”。你
> 你 向前走
停在一根很高的建筑物前面,它的周围还有许多建筑物。在高处看到的一切都一样,好像都是同一个地方的。事实上,在城堡上空盘旋着的机翼和球体明显是不一样的。你突然想到这一定是什么东西把这些建筑物都转移到别的地方了。你把手放到剑柄上,它们突然变得尖锐而难以控制。然后你感觉到它们在扭动,像是朝着相反的方向。你突然意识到安全地回到你自己身边的那一段路比现在要短得多。
> 你 拔剑丢在地上
拔出剑的时候,公主掉到地上,只有一半身体上前。你突然记起了另外一半身体,通过弯下腰来避免狗群的乱吠。剑突然被刺到了它的胸膛,然后那个小身影就彻底碎了。你知道杀死公主后将会获得奖赏,事实上,像公主一样躺在地上,如果这被当成奖赏的话,她将因披上一层虚假的面纱而感到耻辱。
> 你 把公主扶起来
困难的,不过你发现通往神殿的路不会让你付出太大的努力。你需要做的就是把公主扶起来,在它面前站着,带着目瞪口呆的公主坐到。让你吃惊的是,这个时候,你母亲出现了,然后你父亲也出现了。在你向她道谢时,她把一个奖章递给了你。你有一点点害怕,因为那里面的奖金可以让你在冒险完成伟大探险的几年里过得很快,你至少可以这样说。另外有一个好消息,你
> 你 带上钱去城镇
开始的那个地方,必须先到达城镇。还没到呢,但至少你可以开始行动了。你知道你后面的路是对的,首先你必须找到银行,然后再买东西。当你沿着他的道路走了很长一段时间后,你突然意识到从他的道路走回去要花很长时间。你用一个帐篷继续往前走,打开帐篷,也许在某个时刻能够获得一些钱。当你再次拿起帐篷,现在我们有了一间农舍,它已经被你破坏得毫无用处了。
> 你 找一家酒吧
去一家酒吧,所以尽管看着那家酒吧,顺便提一下,你可以买到几把木剑柄。像往常一样,你用弓去击剑,而不是用枪。你有着一个梦想,要为这个小镇最好的酒屋买一把剑。那个地方很受欢迎,你可以很快找到活干。像往常一样,你的弓在你身后晃动,刺伤了肩膀。在你试着重新建立身体平衡,用弓和枪,把弓箭撞翻在地上,试图爬出来,又在一刹那把它送掉。最后
> 你 进入酒吧

看起来下一步的计划可能是
(1)手动筛选一遍语料,挑出一些质量好的重新组建数据集
(2)在小说语料上先预训练一下

07/06记录

昨天使用小说《邪气凛然》,这是一本现代都市背景的小说,作为训练语料,训练了15个epoch,训练耗时15小时,loss收敛图如下:

大概train loss收敛到1.95,test loss在2.99,使用纯小说作为训练语料效果,这样的模型生成的故事如下:

你在树林里冒险,指不定会从哪里蹦出来一些奇怪的东西,你握紧手上的手枪,希望这次冒险能够找到一些值钱的东西
> 你 往树林深处走去
寻找着一种无法确定是否存在的丛林毒物的蛛丝马迹
你不知道沿着这些蛛丝马迹的走向,能不能寻找到找到有价值的林间的什么小小宝藏来!
有时候,我们不知道自己的究竟是陷在了一个巨大的蜘蛛网中,我们永远都不知道在危险的时候,会有这样的一张巨型蜘蛛网在等着我们!
当你走在这里的时候,甚至你可以看见有些大树被大范围的砍倒了,或被烧毁了......
> 你 继续谨慎前进
你沿着树林方向前进,终于你找到了一个拐弯之处。
把怀里的手枪掏出来,给自己手臂上缠绕上一根捆绳子,“照照光吧,要是遇到什么不开眼的人,我拉你一起走!”

就这样,我们小心的左顾右盼,不知不觉,就已经把周围的灌木丛和一些不太厚的杂草过滤了一遍。

> 你 往前去找一个小镇
那里,肯定是有很多避风露宿之处。有没有藏在暗处的垃圾箱,以及有毒的食物,这些都是寻找弹药的途径。除此之外,路过一个小村庄的时候,会有一帮人露出各种各样诡异的表情,向你伸手索要索要一些装备。

还好,要找那些废弃的垃圾,一般是没有什么钱的。

> 你 进入小镇
,然后一间的小店。

“这里是什么地方?”我大喝一声。

“小镇......”

“脱衣舞场?”我暗暗惊叹,这里果然有脱衣舞场!从空而来,几乎就将我的热血给点燃了!

“是的,这里就是小镇!!!”我一字一顿地说出了心里的想法。

“我去就说不一定对!”

“那就试试吧!”

> 你 进去玩
“算了吧,外面全是坏人,我们在街上走,人鬼妖怪都有!尤其是恐怖的人妖,鬼精灵都比咱们这些凡人胆子大!”我说出了心中的想法。我正朝着里头走,忽然觉得身后有东西跟着我的脚步,是一个小黑影在跟着我。我立刻把枪放到了肩膀上,回头一看,一道淡淡的影子。我只能说我只是觉得这个时候我似乎看不清楚这个人了。

> 你 回头追这个黑影
“我要去村子里找其他朋友,我们去那里的街上走走吧。”我把枪放下了,试图在后面闪躲进去的这个小黑影。

“好!去吧!”

“嗯。”我点头。


“你看见这个人没有?”

> 你 追上他
“靠!”我才想到他脸上那个奇怪的面具。
我望了一眼,他的脸上看不出一丝表情来。可他却吓得一哆嗦,直盯着他身后的那个大⁇子。

“你看见后面那个大⁇子没有?他是什么来历?他的长相如何?”我扭头看着他。

> 你 回头看这个大个子
他的眼睛里,那里已经有泪水在缓缓地流下来了。

“别管了,我们朝前走走吧!这里也没啥好看的地方。”我把枪递给你。

> 你 继续走进城镇
“...哦,你终于想起来了。”我们继续朝前走。路上,居然没碰到什么人!

我们走在一个十字路口的时候,前面有一处地方,下面有一个很大的洞!洞里黑色的血迹映着,真是诡异!

“这是哪里?”

我忍不住看了一眼那个大洞。

> 你 进入大洞
“这是命定!这条路,也是决定了我这一辈子的经历。”

“是的,你还是一个菜鸟。这里的问题都会对你很有帮助的。”我语气里多了一份惋惜。

“你真好!”我大声地说,语气也有些激动。而他明显被我的情绪影响了一下,声音也有点虚了。

> 你 进到大洞里
我的心情似乎也沉了一下。我怕的就是被你看见,毕竟你在我心里,还是一个还没长大的孩子。谁知道你什么时候就会使出在那个大洞里,操翻了我的面具?不过幸好当时有林楠跟在我身边,我就算被人看见了,也还能保护自己。

“不过我们越往前走,越是冷⁇的。”我转过头对林楠说。

你没听见我说什么。

> 你 打开手电筒
“所以呢?”我问。我希望你的反应不是很大。
你继续做着你的事情。

“其实,这里的问题是很多人都会遇到的。只是,谁能站在更高的地方思考和思考问题呢?”你眼睛看着前面没有再说话。

“你知道我刚才怎么说的吗?”我叹了口气。

你点点头。

> 你

有的时候,故事会对玩家的反应做出正确反应,有的时候则会忽略玩家的动作自己继续往下编,当然故事的连贯性在几个动作之后也所剩无几,故事连贯性问题可能会一直存在,这个可以暂且忽略,即使GPT2也不是万能的,在其他的几个GPT 项目中,比如
https://github.com/Morizeyao/GPT2-Chinese
中有一个斗破苍穹的生成例子

连贯性非常差

另外另一篇文章中https://leemeng.tw/gpt2-language-model-generate-chinese-jing-yong-novels.html
其生成的段落质量看似稍微高一些

作者并没有提到他使用多少参数量的模型(更正:提到了,用了82M的小模型),但是提到了用了18本小说训练这个模型,而不是仅用1本。

我的感觉是,文本的质量可能非常重要,我用于训练的小说质量肯定比金庸这种低了很多。

为了验证这一点,打算重新设计一个使用金庸小说训练的实验,看看质量是否会好一些

这样一来
(1)如果金庸训练结果比较好,说明是语料问题,应该着重从语料下手
(2)如果训练结果一般,说明是模型问题,可能需要找其他pretrain 模型或者使用更小,更利于finetun的模型

另外,还可以尝试
(1)标注更多数据
(2)寻找可能的数据源
(3)把> 动作部分mask掉不参与loss计算,看看能不能搞出更多result
(4)采用更小的模型,然后用更多的数据finetune

07/07 记录

2021-07-07 10:47:11 星期三

使用1e-5学习率一晚上的训练之后,train loss收敛在2.17左右,test loss收敛在2.8左右。

一个典型的生成结果:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
石破天朗声说道:“嫂子,我全家大小无事,咱们才来无锡,你干么出力打架?你不是喜欢我做的布袋戏吗?”
慕容复道:“你爹爹定然心愿和你相守,因此我便去做恶人了?”石清和颜鸠听他说得有商有量,兄弟俩的神色又大为黯然,叹息了口气,便不言语。
慕容复低声道:“你怎知道我心情不好?你劝劝我。”
慕容复低声笑道:“我爹爹对你自然最好不过,只不过好容易为你打了个强敌,唉,我做错了什么了?”
慕容复微微一笑,拍了她的肩头一下,转身便走。
石清和颜鸠同时叫道:“大哥,咱们来追他!他逃走了,咱们找不到他了。”
慕容复道:“别说了,你们且追吧。追到天涯海角,永不分开。”却听背后步声响起,两人一齐纵身向前,窜出了数丈,立定回头,只见颜鸠和慕容复并肩而行,却向着下游处奔去。
石清和颜鸠互望一眼,也都伏身爬起,分头追赶。
两人窜出河段之时,想起一事,各各停步,微感踌躇。
其实两人先后发怒,颜鸠和慕容复都不免大怒,但此刻却都不发怒,算是各有各的缘由。
到了下游那千丈之处,慕容复双掌轻扶,爬起身来,单足抵在树干之上,挺身而立,再也不动了。
石清问

这一段文字明显上下文不接,是极其糟糕的。

但是另一段生成的文本就合理很多:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。'''
段誉道:“你这狠心短命的绿毛人,要与我一同死吗?唉,世上多的是父母,你又何必为我,而死了?”
王语嫣冷冷的道:“你若真有本事,能和我同生死,你自己却跟我罗唆什么!你不敢出来见我,说什么怕只要活着便死,唉,我不要你出来,跟我也不相干,活着便死的话,如何能死得成!你给了我,再打掉我这个小杂种的性命,你敢吗?你没了我,原来少了一大笔财富,对我是天大的累赘,不,不但不是累赘,反而是我的恩人。”
段誉脸色大变,颤声道:“我......我......我......我......”惊怒交集,但胸口大起反气,伸手去拔短剑,王语嫣知道他中毒的所在,屏息气力,不许他走脱。段誉叹了口长气,道:“你为了要我心甘情愿的陪你死,不惜跟我废话连篇,可叹啊可叹!”突然间双手一拗,抱膝而倒,跟着跌下井去。只听得咯的一声轻响,井中明月光忽然消失无踪。
王语嫣伸手扶起,咦了一声,转头向段誉背上看去,道:“咦!”
段誉只觉背上一片清凉,无着寸缕,揉揉身上各处,全是肌肉疙瘩,哪有半点毒针所混的模样,不由得苦笑。王语嫣道:“我本来要你吐露这一路心事,唔,唔,你大概也不肯吐露,这才想来凑臭气,但看来你

这让我不禁想到是不是在sample故事的时候sample机制过于宽松,现有逻辑里有这么一段:

def batch_gather(a, b):
    return tf.gather(a, b, batch_dims=1)

def top_p_sample(logits, num_samples=1, p=0.95):
    batch_size, vocab_size = logits.shape
    probs = tf.nn.softmax(logits, axis=-1)
    # [batch_size, vocab_perm]
    indices = tf.argsort(probs, direction='DESCENDING')
    cumulative_probabilities = tf.math.cumsum(batch_gather(probs, indices), axis=-1, exclusive=False)

    # find the top pth index to cut off. careful we don't want to cutoff everything!
    # result will be [batch_size, vocab_perm]
    p_expanded = p if isinstance(p, float) else p[:, None]
    exclude_mask = tf.logical_not(
        tf.logical_or(cumulative_probabilities < p_expanded, tf.range(vocab_size)[None] < 1))

    # OPTION A - sample in the sorted space, then unsort.
    logits_to_use = batch_gather(logits, indices) - tf.cast(exclude_mask, tf.float16) * 1e4
    sample_perm = tf.random.categorical(logits=logits_to_use, num_samples=num_samples)
    sample = batch_gather(indices, sample_perm)

    return tf.cast(sample, tf.int64)

其限制了95%的prob的地方做cut off,把这个p调到50%,再试一下,理论上这样候选就会少一半多

然而,很显然这样的暴力cut off会引起很严重的重复问题,下面是生成的语段:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
王语嫣道:“表哥,你可还记得我们相遇的情景么?”
段誉道:“我怎会不记得?你又说什么‘我们相遇的情景’?”
王语嫣道:“我和你一起在井中打水,你在井中对我微笑,我在井中对你微笑,你对我微笑,我对你微笑,你对我微笑,我对你微笑......”
段誉道:“你在井中对我微笑,我在井中对你微笑,你对我微笑,我对你微笑......”
王语嫣道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
段誉道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
王语嫣道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
段誉道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
王语嫣道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
段誉道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
王语嫣道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,我对你微笑......”
段誉道:“我在井中对你微笑,你在井中对我微笑,你对我微笑,

另一个生成段落:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
王语嫣叫道:“表哥,表哥,你⋯⋯你怎么啦?”
段誉道:“我⋯⋯我⋯⋯我不想死,我⋯⋯我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你⋯⋯你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?”段誉道:“我说我不想死,我不想死。”
王语嫣道:“你说什么?

再来一个生成段落:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
鸠摩智缓缓的道:“两位姑娘,你是我师父,我是你师父,我叫你一声师父,你便要叫我一声师父。”
王语嫣心中一酸,泪水终于夺眶而出,哽咽道:“我......我......我......”
鸠摩智左手五指成爪,在王语嫣脸上抚摸,右手食指和中指伸入她口中,吮吸。王语嫣只觉甜甜的,腻腻的,心中不住的怦怦乱跳,只觉天地之间,再也没有比这更甜蜜的滋味。
鸠摩智道:“我师父常说,有了师父,便有了一切。我这一生,只有你师父,你也只有我。”
王语嫣道:“我也只有你师父,你也只有我。”
鸠摩智微笑道:“我是你师父,你也是我师父。”
王语嫣道:“我也是你师父,你也是我师父。”
鸠摩智左手五指如钩,勾住王语嫣的下巴颏,右手食指和中指伸入她口中,轻轻一吮,王语嫣觉得腻腻的,心中又是一阵乱跳,不住的怦怦乱跳,只觉天地之间,再也没有比这更甜蜜的滋味。
王语嫣心中不住的怦怦乱跳,不住的怦怦乱跳,只觉天地之间,再也没有比这更甜蜜的滋味。
鸠摩智左手五指如钩,勾住王语嫣的下巴颏,右手食指和中指伸入她口中,轻轻一吮,王语嫣觉得腻腻的

啊这,这次不光有了重复问题,上下文还有点奇怪了

再来一段:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
段誉心中一荡,想起了阿朱的情郎,不禁又是欢喜,又是怜惜,伸手拉住了王语嫣的手,柔声道:“王姑娘,你也来了,咱们一起,永远在一起。”
王语嫣微笑道:“我和你一起,永远在一起。”段誉道:“你也永远和我在一起。”
王语嫣又是欢喜,又是怜惜,道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道:“我和你一起,永远在一起。”
段誉道:“我和你一起,永远在一起。”
王语嫣道

这几段虽然说有严重的重复问题,但是总体来说,连贯性比之前好了不少。

https://github.com/Morizeyao/GPT2-Chinese/blob/master/generate.py 这个项目中实现了topp和topk的采样方式,也想试试topk的采样方式,质量会有什么不同。

于是采样代码改成了这样

def batch_gather(a, b):
    return tf.gather(a, b, batch_dims=1)

def top_p_sample(logits, num_samples=1, p=1.0,k=8):
    batch_size, vocab_size = logits.shape
    probs = tf.nn.softmax(logits, axis=-1)
    # [batch_size, vocab_perm]
    indices = tf.argsort(probs, direction='DESCENDING')
    cumulative_probabilities = tf.math.cumsum(batch_gather(probs, indices), axis=-1, exclusive=False)
    top_k_prob = cumulative_probabilities[k]

    # find the top pth index to cut off. careful we don't want to cutoff everything!
    # result will be [batch_size, vocab_perm]
    p_expanded = p if isinstance(p, float) else p[:, None]
    exclude_mask = tf.logical_not(
        tf.logical_or(
            tf.logical_and(
                cumulative_probabilities < p_expanded, 
                cumulative_probabilities < top_k_prob
            ),
            tf.range(vocab_size)[None] < 1
        )
    )

    # OPTION A - sample in the sorted space, then unsort.
    logits_to_use = batch_gather(logits, indices) - tf.cast(exclude_mask, tf.float16) * 1e4
    sample_perm = tf.random.categorical(logits=logits_to_use, num_samples=num_samples)
    sample = batch_gather(indices, sample_perm)

    return tf.cast(sample, tf.int64)

k=8生成几段故事:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
段誉心想:“这位大理段公子,果然便是我的亲爹段正淳,他为人忠厚老实,不似这般心狠手辣,这般诡计多端,却叫我做了他的儿子,却又是什么道理?”
王夫人见两人这般情投意合的神情,心中大喜,但想:“我的儿子做了皇帝,他们夫妇却要遭人闲话。这段公子这般俊美无伦,武功高强,人品也好,我若是不好好地爱他,却又如何对得住他?段正淳和我的段誉一般,都是孩童心性,喜爱嬉笑游玩,他若做了皇帝,我的儿子自然要做我的儿子了。”便向儿子问道:“你爹呢?”段誉道:“他在郊外打猎。”王夫人大喜,说道:“那你便立刻去陪我的儿子。”
段誉听了,登觉意乱,只觉王夫人待他亲切之至,待自己更加亲切;只是王语嫣对自己的情意,却也不似寻常母子之间,而且王语嫣对自己也有情意,但不知为什么,自己总觉得有什么地方别扭,此刻听王夫人这么说,登觉心中大喜,但随即想起了王语嫣和阿朱的生死之情,又不免有些惆怅。
那老妇人道:“这位公子,你是王姑娘的儿子,我是王姑娘的母亲。我儿子对我很好,这就好了,这就好了。我这般对你的好,你欢喜,你欢喜。你要是瞧我不起,你瞧我不起,你便对我不起
段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
段誉心道:“王姑娘,你也会喜欢上我了。”
王语嫣低声道:“你也会喜欢上我了罢。”段誉听她低声说了这几句话,心头欢喜,但随即想到:“她和我说这些干什么?”
他和段誉本已结下了深厚的情意,王语嫣对他,无疑更加钟情,但在这种场合下她对段誉言爱,却又是言不可言。
段誉低声道:“我要娶西夏公主为妻,你呢?”王语嫣的声音也低了下去:“我也是要娶西夏公主为妻。”
段誉道:“那你是嫁给我了,是不是?”
王语嫣低下了头,道:“是啊,是啊。”段誉心道:“这就好极了,这就真正是郎情妾意。”
王语嫣道:“我还是要和你说这些话,你不理会我罢。”段誉道:“我自然理会啦。”
王语嫣道:“你是不想理会我的说话了。我也不想理会你了。”段誉道:“我也不想理会你的说话,你也不想理会我了。”
王语嫣道:“我也不想理会你的说话,也不想理会你了。”
段誉心中一阵迷茫:“我、我是在说什么?”
段誉正想:“待我和王姑娘成家之后,我要娶的是婉妹,不是阿紫。”王语嫣低声道
段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
段誉见机,突然身子一矮,向王语嫣身边滚过去。
段誉滚到王语嫣身边,双手便抓住了她腰,双手一错,喀喇一响,王语嫣的腰骨喀喇断成两截。段誉双手抓住了她腰,只觉她身子一阵颤栗,立时不动了,动弹不得。王语嫣叫声:“段郎,段郎!”颤声道:“段郎,你、你怎么会......”段誉摇动了两下,不动了,终于还是软瘫在池塘之中,只是身子不住打战。
王语嫣瞧了瞧他的伤,心念一动,便要过去将他抱住,却又觉得他的伤势极是沉重,抱在身上着实不便。
段誉瞧她神色,已明白她意中所指,说道:“我、我......”蓦然间只觉全身燥热,燥热之极,登时神志昏乱,待得清醒过来,却已是在自己家中。
王夫人见丈夫这般模样,心中一惊,忙问:“怎么,怎么咱们睡的不是床铺?”
段誉道:“不是!”
段誉自己又是一阵昏晕,想起在雁门关外被西夏官兵擒住时,便已昏晕,后来和王语嫣相遇时,也是昏晕,这次晕得更加厉害,只顷刻间便昏了过去。
王夫人惊疑不定,忙道:“你、你、你怎么会到这儿来?我、我......”
段誉道:“咱们是在这儿遇到的王

啊这,第三段就离谱,把王语嫣腰给折了可还行。。。看起来生成质量和连贯性不如刚才p=0.5的,接下来尝试一下k=4的,看看会不会好一些

使用k=4生成的几个语段:

段誉和王语嫣面面相对,呼吸可闻,虽身处污泥,心中却充满了喜乐之情,谁也没想到要爬出井去。两人同时慢慢的伸出手来,四手相握,心意相通。
霎时间,两人身上所受的痛苦,都已消解。他们都想:“倘若咱们此刻一起堕入阿鼻地狱之中,那便真正生不如死了。”
两人都感欢欣无比。他们在井底所做的事,只不过是在“化敌为友”,而他们此刻所做的事,却已是在“化敌为友”了。
然而,他们虽已化敌为友,心中还是不免害怕。他们生怕在井底待得久了,会有什么“虫⁇”来吃他们的血肉,或是他们的尸身,会被他们所掘出。他们两人虽然都已是“生而为人”,但在生的时候,却从来没有做过害人害人的事;在死的时候,却从来没有做过害人害人的事。
然而,此刻两人身上的污泥,却是他们自己所化。在他们身上所受的痛苦,也是他们自己所受的痛苦。他们的身上,也有他们自己的污垢。两人的手,在他们身上所摸到的东西,也是他们自己的手,他们所感到的痛苦也是他们自己的痛苦。
他们两人都已化敌为友。

感觉还行,但是总的来说重复问题还是一个大问题

Q: you also modified your model to cut down on repetition in GPT-2 output. Could you explain that?
A: In the Salesforce CTRL model they add a penalty to the probabilities of generating a word that has already been generated dividing it’s log odds by something like 1.2.
This helps keep the model from getting stuck saying the same word or set of words. Because of that, the CTRL model was able to use a much lower temperature than GPT-2 (which needed a high temperature to prevent repetition). By adding this penalty to GPT-2, I was able to reduce the temperature down to 0.4 which helps coherence, while still avoiding repetition (for the most part)

感觉还行,但是总的来说重复问题还是一个大问题