传统的机器学习,还有深度学习,最简单的形式,就是输出N个向量,对应N个结果,即所谓的“有监督”学习。然后再给定一个新的向量,就知道对应的分类。
那有没有可能学习一堆数据之后,按照学习到的规律,生成一些数据呢?是可能的,在图像识别中,就是所谓的GAN图片生成,因为图片包含了所有信息,生成的效果是很好的。
本文想讨论文本的生成,这里先提供一种比较简单的形式。
用tensorflow的话,模板代码太多,所有细节都需要自己处理。本文仍然使用tflearn来做。
首先是素材准备,把金庸小说里的人名汇总起来,做个简单的预处理,变成如下格式(一行一个),这里包含了所有金庸小说里的人名。我们要学习这些名字,然后按规律模型自己生成一些名字。
自然语言都是需要预处理成计算机可以识别的格式,在深度学习中一般不提取特征,就直接用下标,可以是词(word)或字(char)。本文是取名字,所以使用字(char)。
tflearn已经提供了一个预处理的函数:string_to_semi_redundant_sequences,按字面意思是就是“字符串转为半冗余的序列”。什么意思呢?
string_utf8是输入的字符串,格式为“皇太极\n祖大寿\n倪哑巴\n胡桂南\n胡老三崔秋山\n黄真\n崔希敏\n黄二毛子\n曹化淳\n黄须人”,注意\n也是一个字符。
seq_maxlen是生成的序列的长度,这里取20。
redun_step是步长,就是每隔几个字取一次,这里取2。
比如,取[0:20)个字,就是“皇太极\n祖大寿\n倪哑巴\n胡桂南\n胡老三崔秋”,输出要预测的”下一个字“就是第20个字,在这个例子中是“山”。然后跳redun_step步,也就是从“极\n祖大寿\n倪哑巴\n胡桂南\n胡老三崔秋山\n”,对就的输出是“崔”。
但我们不能直接使用文字 ,而是输出下标,我们会构建一个char_idx,也就是
输出:{'真': 649, '赫': 854, '笔': 691, '翰': 724, '侍': 72, '丝': 18, '纪': 705, '身': 860, '修': 80...}这样的格式。X=(5387, 20, 1017),Y=(5387,1017), 这就构建了(X,Y)的对应关系,就可以进行训练了。
import os
import requests
import tflearn
from tflearn.data_utils import *
path = "jy2.txt"
maxlen = 20
string_utf8 = open(path, "r",encoding='utf-8').read()
#char_idx是得到文本序列里,每个char(字)的坐标,英文序列就是每个字母。
#如果是英文,就是26个字母,中文字比较多
#这里步长为3,取序列长度=20,比如[0-19]个字做input,第20个字做output
X, Y, char_idx = \
string_to_semi_redundant_sequences(string_utf8, seq_maxlen=maxlen, redun_step=1)
这里使用双层的LSTM,SequenceGenerator,仍然是一个DNN的model,只不过把predict封装成了可以预测产生序列。
g = tflearn.input_data(shape=[None, maxlen, len(char_idx)])
g = tflearn.lstm(g, 512, return_seq=True)#这里有一个return_seq
g = tflearn.dropout(g, 0.5)
g = tflearn.lstm(g, 512)
g = tflearn.dropout(g, 0.5)
g = tflearn.fully_connected(g, len(char_idx), activation='softmax')#1022类
g = tflearn.regression(g, optimizer='adam', loss='categorical_crossentropy',
learning_rate=0.001)
m = tflearn.SequenceGenerator(g, dictionary=char_idx,
seq_maxlen=maxlen,
clip_gradients=5.0,
checkpoint_path='model_us_cities')
epoch = 40
for i in range(epoch):
seed = random_sequence_from_string(string_utf8, maxlen)
m.fit(X, Y, validation_set=0.1, batch_size=128,
n_epoch=1, run_id='us_cities')
print("-- TESTING...")
print("-- Test with temperature of 1.2 --")
out1 = m.generate(30, temperature=1.2, seq_seed=seed)
print(type(out1),out1)
print("-- Test with temperature of 1.0 --")
print(m.generate(30, temperature=1.0, seq_seed=seed))
print("-- Test with temperature of 0.5 --")
print(m.generate(30, temperature=0.5, seq_seed=seed))
第一个epoch之后的输出还比较乱:
第8个epoch之后,好一些了:
第28个epoch,基本上能识别出常用的姓了。
第35个epoch:
lstm的训练计算量比较大,双层lstm就更慢了,但效果还是不错的。统计到了文本里很多信息。这里可以扩展比如整本射雕英雄传,四大名著都可以。然后计算机就可以”创作“了。
关于作者:魏佳斌,互联网产品/技术总监,北京大学光华管理学院(MBA),特许金融分析师(CFA),资深产品经理/码农。偏爱python,深度关注互联网趋势,人工智能,AI金融量化。致力于使用最前沿的认知技术去理解这个复杂的世界。
联系客服