上文我们介绍了卷积神经网络极其变形 LSTMLSTMLSTMGRUGRUGRU 的原理,我们来讲讲用法。循环神经网络主要使用在自然语言处理方面,自然语言处理主要使用的是语言信息,由字和词组成,所以我们一般需要将这些字或者词转为向量,这就不得不提到一个概念:词嵌入,即词向量。

词嵌入

  在最初做自然语言处理时,采用 one−hotone-hotonehot 编码来表示一个词,例如一个语料:我喜欢刘德华的歌,分词之后可表示为:我/喜欢/刘德华/的/歌。这里我们有 5 个词,那么使用 one−hotone-hotonehot 编码表示每个词:
    我: [1,0,0,0,0][1, 0, 0, 0, 0][1,0,0,0,0]
    喜欢:[0,1,0,0,0][0, 1, 0, 0, 0][0,1,0,0,0]
    刘德华:[0,0,1,0,0][0, 0, 1, 0, 0][0,0,1,0,0]
    的:[0,0,0,1,0][0, 0, 0, 1, 0][0,0,0,1,0]
    歌:[0,0,0,0,1][0, 0, 0, 0, 1][0,0,0,0,1]

  这种表示方法简单易懂,但是缺点也很明显,无法表示词与词之间的关系,而且如果语料足够大的话,那么维度就会非常大,给服务器带来很大的负载,同时这么多维度中,却只有一维是可用信息,就会造成很大的维度浪费情况。
  因为 one−hotone-hotonehot 的这种缺点,深度学习一般采用词嵌入的方式,词嵌入就是将一个全部词语数量为维度的高维空间嵌入到一个低维的连续空间中,词嵌入的具体解释可以看看 自然语言处理与词嵌入,我自信我不能比这位博主写的更加通俗易懂,所以这里大家就只能看看这位博主的大作了。
  在 pytorchpytorchpytorch 中,词嵌入是通过函数 nn.Embedding(m,n)nn.Embedding(m, n)nn.Embedding(m,n) 来实现的,其中 mmm 表示所有的单词数目,nnn 表示词嵌入的维度,对应为一个 [m,n][m, n][m,n] 的矩阵,例如果有两个词 hello,worldhello, worldhello,world,都为五维。对应的矩阵就为 [2,5][2, 5][2,5]EmbeddingEmbeddingEmbedding 的输入为 [batch_size,m][batch\_size, m][batch_size,m],输出为 [batch_size,m,n][batch\_size, m, n][batch_size,m,n]

   embedding = nn.Embedding(10, 5)  #  10个词,每个词为5维inputs = torch.arange(0, 6).view(3, 2).long()  # 输入三行两列,即三个句子,每个句子有两个词inputs = Variable(inputs)print("输入大小: ", inputs.shape)outputs = embedding(inputs)print("输出大小: ", outputs.shape)   # 输出大小

  得到的输出如下:

   输入大小:  torch.Size([3, 2])输出大小:  torch.Size([3, 2, 5])

AI起名

  网上做 AIAIAI 写诗的有很多,基本都是参考陈云老师的《深度学习框架 pytorch入门与实践》,我也根据内容,利用爬取的 922519225192251 首诗,完成了此 demodemodemo,但是网上同类型太多,我就不写了,这里我们换种方式,爬取一批姓名来完成 AIAIAI 起名的功能,本次利用爬虫获取 985010985010985010 组男孩子的名字,基本囊扩了所有的姓氏。

数据处理

  在前面了解到,深度学习的数据需要使用相同维度,而名字无法进行分词,为了方便,直接将每个名字当做一个词看待,然后进行处理而考虑到复姓的关系,名字最长可能为 444,但是为了方便或者出错,在名字后面加上一个终止符 <END><END><END>,最终组成一个 555 维向量。

   import numpy as npwith open(u"./data/boys.txt", "r", encoding="utf-8") as f:    # 获取所有名字names = []for line in f:names.append(line.strip())data = []for name in names:people = list(name) + ["<END>"]      # 在名字后面加上终止符并转为列表if len(people) < 5:                 # 如果长度小于5,补齐5位for i in range(5-len(people)):people.insert(i, "</s>")else:                              # 如果长度大于5,截取五位people = people[: 5]data.append(np.array(people))

  可以看看截取之后,出现的信息:

 data[0]

  每一个名字为 555 维,每维为一个汉字,但是代码是无法识别汉字的,所以我们需要想方法将其转为代码能够处理的数字。

   words += [word for poetry in data for word in poetry]   # 获取所有汉字words = set(words )                                       # 去重word2ix = dict((c, i) for i, c in enumerate(words))      # 字-indexix2word = dict((i, c) for i, c in enumerate(words))      # index-字

  将数字与汉字进行映射之后,我们需要将所有词即名字转为词嵌入的模式:

   name_data = []  # 姓名对应的下标向量化for name in data:name_txt = [word2ix[ii] for ii in name]  name_data.append(name_txt)name_data = np.array(name_data)name_txt = [ix2word[ii] for ii in name_data[0]]  # 查看第一个名字print("".join(name_txt))

  输出结果如下所示:

  数据处理完成后,将其封装为 tensortensortensor

   name_data = torch.from_numpy(name_data)dataloader = data.DataLoader(name_data, batch_size=64, shuffle=True, num_workers=1)
模型构建
   class NameModel(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim):  # (所有汉字数,词向量维度,隐藏层维度)super(NameModel, self).__init__()self.hidden_dim = hidden_dim  # 隐藏层self.embeddings = nn.Embedding(vocab_size, embedding_dim)   # 词表大小/词维度self.lstm = nn.LSTM(embedding_dim, self.hidden_dim, num_layers=2, batch_first=True)   # [输入维度,输出维度,网络层数]/LSTMself.linear = nn.Linear(self.hidden_dim, vocab_size)  # 全连接层def forward(self, input_, hidden=None):   # input_形状  (seq_len, batch_size)batch_size, seq_len = input_.size() if hidden is None:h_0, c_0 = Variable(torch.zeros(2, batch_size, self.hidden_dim)), Variable(torch.zeros(2, batch_size, self.hidden_dim))else:h_0, c_0 = hiddenembeds = self.embeddings(input_)output, hidden = self.lstm(embeds, (h_0, c_0))output = self.linear(output.view(seq_len * batch_size, -1))return output, hidden

  输入的字和词通过 nn.Embeddingnn.Embeddingnn.Embedding 得到相应的词向量,然后利用两层 lstmlstmlstm 提取到词的隐藏信息,再利用隐藏信息将词分类,得到下一个可能出现的词。同时使用相同方法定义损失函数与优化函数:

   model = NameModel(len(word2ix), 6, 32)   # 字库长度,词维度,隐藏层大小optimizer = torch.optim.Adam(model.parameters(), 1e-3)  # 优化器criterion = nn.CrossEntropyLoss()  # 损失函数

  同样可以使用 model.parametersmodel.parametersmodel.parameters 看看模型的参数:

模型训练

  训练方法与前面也是相同,不多讲,直接上代码。

   for epoch in range(20): epoch_loss = 0 for i, data in enumerate(dataloader): data = data.long()optimizer.zero_grad() input_, target = Variable(data[:-1, :]), Variable(data[1:, :])  # 将输入和目标错开output, _ = model(input_) loss = criterion(output, target.view(-1)) loss.backward() optimizer.step() epoch_loss += loss.dataprint('epoch: {}, name_loss: {:.6f}'.format(epoch, epoch_loss/len(dataloader)))torch.save(model.state_dict(), '%s_%s.pth' % ("./data/name/name", epoch))

  上面将输入和目标错开的原因是,正常情况下,比如第一个名字:“钱煜睿“,我们输入姓:“钱”,下一个正确的字为:“煜”,而“煜”就为姓“钱”的目标值,所以我们直接将同一个名字错开一维即可。因为电脑性能的原因,我这里只是将隐藏层大小设置为 323232,使用了 222 层网络,训练 202020 次,依然跑了一天一夜,各位童鞋如果自己也想练习此 demodemodemo,可根据具体情况设置这些参数与 GPUGPUGPU 加速,我这里模型的损失还是有点大,跟训练次数有一定关系,我这里没有计算准确率,后面补上:

生成姓名
   def create_name(model, start_words, ix2word, word2ix):results = list(start_words)   # 姓start_word_len = len(start_words)  # 起始长度inputs = Variable(torch.Tensor([word2ix[results[0]]]).view(1, 1).long())   # 获取第一个词即姓氏hidden = Nonefor i in range(200):output, hidden = model(inputs, hidden) if i < start_word_len:w = start_words[i]  inputs = Variable(inputs.data.new([word2ix[w]])).view(1, 1)  # 根据输入的姓预测下一个字else:top_index = output.data[0].topk(1)[1][0].item()  # 取出预测中最可能输出的字w = ix2word[top_index]results.append(w)inputs = Variable(inputs.data.new([top_index])).view(1, 1)  # 将输出作为下一次的输入if w == "<END>":breakreturn results[: -1]first_name = "李"result = create_name(model, first_name, ix2word, word2ix)print(''.join(result))

  可以看看我们通过模型生成的名字:

  多生成几次,看看效果:

总结

  其实神经网络的模型创建和训练都是大同小异,不同的是在自己数据处理与参数的调节,而 AIAIAI 起名还有很多可以补充的,比如说根据性别、生肖、姓名长度来就生成姓名,后续我会慢慢补充。
  

参考

  1. 陈云:《深度学习框架 pytorch入门与实践》
  2. 廖星宇:《深度学习之pytorch》

深度学习(十)-AI起名相关推荐

  1. Hinton等谈深度学习十年;PyTorch落地Linux基金会的影响;机器学习界的“GitHub”|AI系统前沿动态

    1. 重磅!PyTorch落地Linux基金会 扎克伯格亲自宣布,PyTorch基金会已新鲜成立,并归入Linux基金会旗下,管理委员会成员,包括Meta.AMD.AWS.谷歌云.微软和英伟达.Met ...

  2. 甲小姐对话稚晖君:深度学习并非AI的终点

    "人类不应该只存在在地球上,对于这么浩瀚的宇宙来说太浪费了." 作者 | 甲小姐 助理 | 沁云 近日,华为"天才少年".B站UP主稚晖君的新作自动驾驶自行车在 ...

  3. NLP:LSTM之父眼中的深度学习十年简史《The 2010s: Our Decade of Deep Learning / Outlook on the 2020s》的参考文献

    NLP:LSTM之父眼中的深度学习十年简史<The 2010s: Our Decade of Deep Learning / Outlook on the 2020s>的参考文献 目录 T ...

  4. LSTM 之父发文:2010-2020,我眼中的深度学习十年简史

    作者 | Jürgen Schmidhuber 译者 | 刘畅.若名 出品 | AI科技大本营(ID:rgznai100) 作为LSTM发明人.深度学习元老,Jürgen Schmidhuber于2月 ...

  5. LSTM之父发文:2010-2020,我眼中的深度学习十年简史

    2020-02-23 15:04:22 作者 | Jürgen Schmidhuber 编译 | 刘畅.若名 出品 | AI科技大本营(ID:rgznai100) 作为LSTM发明人.深度学习元老,J ...

  6. LSTM之父发文:我眼中的深度学习十年简史!

    点击上方"开发者技术前线",选择"星标" 13:21 在看 真爱 作者 | Jürgen Schmidhuber 编译 | 刘畅.若名  出品 | AI科技大本 ...

  7. 图说2016深度学习十大指数级增长

    转自:https://www.52ml.net/21402.html http://mp.weixin.qq.com/s?__biz=MzI3MTA0MTk1MA==&mid=26519906 ...

  8. 深度学习、AI构图、智能裁图、显著性检测、美感质量评价

    深度学习.AI构图.智能裁图.显著性检测.美感质量评价 基于美感数据集和改进的Alexnet-SPP的AI构图智能裁图 基于美感数据集和改进的Alexnet-SPP的显著性检测 部分代码下载地址:下载 ...

  9. 2017年深度学习十大趋势预测

    2017年深度学习十大趋势预测 本文作者曾经多次预测了技术发展的趋势,最近的一次预测是"2011年软件发展的趋势与预测".10项预言中,准确地命中了6项,比如JavaScript ...

最新文章

  1. [P1363] 幻想迷宫
  2. JFreeChart的简单图表的制作------柱形图
  3. perl 序列化_对Perl的热爱团结了多元化的社区
  4. jmeter学习指南之源码导入 IntelliJ IDEA
  5. Pycharm返回上一次编辑处的快捷键
  6. 联想笔记本电脑(LENOVO)关闭触摸板
  7. Firefox定位网页元素工具
  8. OOAD 3 迭代、进化和敏捷(Iterative,Evolutionary,and Agile)
  9. 【开源方案】PPT/PPTX转image图片
  10. 学计算机做纸质笔记,详细图文教你康奈尔大学推荐的超级笔记法,只要一张A4纸张,你也可以做学霸...
  11. matlab电机系统建模与仿真软件下载,基于MATLAB直流无刷电动机系统建模与仿真
  12. 易图通: 路口三维实景导航面面观
  13. Linux删除文件,df查看磁盘空间未减少
  14. 在火狐上安装chrome 的crx扩展
  15. 视频会议系统gk服务器,详解华为视频会议系统中信令之间如何实现跨GK呼叫
  16. 软连接ln -s 创建以及删除
  17. Microsoft Dynamics 365 (on-premises) Update 2.12
  18. 准备1500 RMB Go云南!!
  19. FinClip小程序+Rust(二):环境搭建
  20. Android国际化,阿语RTL适配总结

热门文章

  1. cocos creator全局变量与常住节点
  2. [Unity3D]人物模型的换装
  3. wmv是什么格式?如何录制wmv格式的视频?图文教学
  4. @container 规则
  5. python 绘制对数坐标散点图
  6. 分布式系统消息中间件-RabbitMQ介绍及其应用
  7. 电子测量技术知识点(实录)
  8. Fil币怎么挖?收益怎么来,会不会被割?
  9. 一步一步学习Vim 全图解释
  10. 《教父》二代教父之迈克·柯里昂