Python深度学习实战!全头条会的不超过一只手吧!不吹不黑!

Python深度学习实战!全头条会的不超过一只手吧!不吹不黑!,第1张

概述 pridict(\'Hinton\')(-0.47)Scottish(-1.52)English(-3.57)Irishpridict(\'Schmidhuber\')(-0.19)German(-2.48)Czech

prIDict('Hinton')(-0.47) Scottish(-1.52) English(-3.57) IrishprIDict('SchmIDhuber')(-0.19) German(-2.48) Czech(-2.68) Dutch

all_filenames结果

 ['data/Czech.txt','data/German.txt','data/arabic.txt','data/Japanese.txt','data/Chinese.txt','data/VIEtnamese.txt','data/Russian.txt','data/french.txt','data/Irish.txt','data/English.txt','data/Spanish.txt','data/Greek.txt','data/Italian.txt','data/Portuguese.txt','data/Scottish.txt','data/Dutch.txt','data/Korean.txt','data/Polish.txt']

进群:548377875  即可获取不同的pdf哦!都是非常实用的呢!

打印结果

57'Slusarski'

构建 语言类别-姓名映射字典 ,形如 {language1: [name1,name2,...],language2: [name_x1,name_x2,...]}

将姓名转化为Tensors

跟机器学习类似,在这里我们也需要将文本转化为具体的计算机能理解的数据形式。

为了表征单个的字符, 我们使用 独热编码向量one-hot vector , 该向量的尺寸为 1 x n_letters (每个字符是2维向量)

例如

定义letter_to_tensor函数

import torch# 将字符转化为 <1 x n_letters> 的Tensordef letter_to_tensor(letter): tensor = torch.zeros(1,n_letters) letter_index = all_letters.find(letter) tensor[0][letter_index] = 1 return tensor# 将姓名转化成尺寸为的数据# 使用的是one-hot编码方式转化def name_to_tensor(name): tensor = torch.zeros(len(name),1,n_letters) for ni,letter in enumerate(name): letter_index = all_letters.find(letter) tensor[ni][0][letter_index] = 1 return tensor

现在我们运行letter_to_tensor('J')

print(letter_to_tensor('J'))

显示上面代码运行结果

 tensor([[0.,0.,1.,0.]])name_to_tensor('Jones').size()print(name_to_tensor('Jones'))

显示上面代码运行结果

 torch.Size([5,57]) tensor([[[0.,0.]],[[0.,0.]]])
构建神经网络

注意看图中各个参数解读:

input : 输入的数据 hIDden : 神经网络现有的参数矩阵 combined : input矩阵与hIDden矩阵合并,两个矩阵的行数一致,input和hIDden分布位于新矩阵的 左侧和右侧 i2o :对输入的数据转化为output的计算过程 12h :将输入的数据转化为hIDden参数的计算过程 output :当前网络的输出 hIDden :当前网络传递给下层网络的参数

大家仔细看看琢磨琢磨这个图构造。现在我们先看看 combined 这个 *** 作

a = t.Tensor(3,1)b = t.Tensor(3,2)print(a) #aprint(b) #bprint(t.cat((a,b),1)) #a、b合并后的样子

打印结果

 tensor([[0.0000],[0.0000],[0.0000]]) tensor([[ 0.0000,0.0000],[ 0.0000,-0.0000],0.0000]]) tensor([[ 0.0000,0.0000,0.0000]])

开始DIY我们第一个循环神经网络RNN,各个参数解读:

input_size : 表征字母的向量的特征数量(向量长度) hIDden_size : 隐藏层特征数量(列数) output_size : 语言数目,18 i2h : 隐藏网络参数的计算过程。输入的数据尺寸为 input_size + hIDden_size,输出的尺寸为 hIDden_size i2o : 输出网络参数的计算过程。输入的数据尺寸为 input_size + hIDden_size,输出的尺寸为 output_size
import torch.nn as nnclass RNN(nn.Module): def __init__(self,input_size,hIDden_size,output_size): super(RNN,self).__init__() self.input_size = input_size self.hIDden_size = hIDden_size self.output_size = output_size self.i2h = nn.linear(input_size + hIDden_size,hIDden_size) self.i2o = nn.linear(input_size + hIDden_size,output_size) def forward(self,input,hIDden): #将input和之前的网络中的隐藏层参数合并。 combined = torch.cat((input,hIDden),1) hIDden = self.i2h(combined) #计算隐藏层参数 output = self.i2o(combined) #计算网络输出的结果 return output,hIDden  def init_hIDden(self): #初始化隐藏层参数hIDden return torch.zeros(1,self.hIDden_size)
检验我们构建的RNN网络

定义好 RNN 类之后,我们可以创建RNN的实例

rnn = RNN(input_size=57,#输入每个字母向量的长度(57个字符) hIDden_size=128,#隐藏层向量的长度,神经元个数。这里可自行调整参数大小 output_size=18) #语言的种类数目

要运行此网络,我们需要给网络传入:

input(在我们的例子中,是当前字母的Tensor) hIDden(我们首先将隐藏层参数初始化为零)

经过网络内部的运算,我们将得到:

output(每种语言的可能性的大小) next_hIDden(传递给下一个网络的隐藏状态hIDden)
input = letter_to_tensor('A')hIDden = rnn.init_hIDden()output,next_hIDden = rnn(input,hIDden)print('output.size =',output.size())

显示上面代码运行结果

 output.size = torch.Size([1,18])

现在我们使用 line_to_tensor 替换 letter_to_tensor 来构件输入的数据。注意在本例子中,给RNN网络一次输入一个姓名数据,但对该网络而言,是将姓名数据拆分成字母数组数据,逐次输入训练网络,直到这个姓名最后一个字母数组输入完成,才输出真正的预测结果(姓名所属的语言类别)。

输入 RNN神经网络 的数据的粒度变细,不再是 姓名数组数据(三维) ,而是 组成姓名的字母的数组或矩阵(二维) 。

input = name_to_tensor('Albert')hIDden = torch.zeros(1,128) #这里的128是hIDden_size#给rnn传入的初始化hIDden参数是尺寸为(1, 128)的zeros矩阵#input[0]是传入姓名的第一个字符数组,注意这个数组是batch_size=1的矩阵。因为在pytorch中所有输入的数据都是batch方式输入的output,next_hIDden = rnn(input[0],hIDden)print(output.shape)print(output)

显示上述结果

 torch.Size([1,18]) tensor([[-0.0785,0.0147,0.0940,-0.0518,-0.0286,0.0175,-0.0641,-0.0449,-0.0013,0.0421,0.0153,0.0269,-0.0556,0.0304,-0.0133,-0.0572,0.0217,0.1066]],grad_fn=)

现在我们看看output这个tensor中的含有数据,想办法从中提取出预测的 语言类别信息 。

具体思路:

因为output是tensor,我们可以先获取这个tensor中的data 再使用基于data的topk方法,提取tensor中似然值最大的索引值。

该索引值就是 所属语言类别的索引值,具体我们可以看下面的例子更好的理解tensor的 *** 作方法。

output.dataoutput.data.topk(1)

显示上面两行代码运行结果

 tensor([[-0.0785,0.1066]]) (tensor([[0.1066]]),tensor([[17]]))

上面的两行代码,

其中第一行代码得到tensor中的data

第二行代码得到某姓姓名(这里我们实际上只输入了一个字母,姑且当成只有一个字母的姓名)的 所属语言的似然值 及 所属语言类别的索引值

top_n,top_i = output.data.topk(1)top_n #所属语言的似然值,我们可以将其想象成概率top_i #所属语言类别信息

显示上面tpo_n和 top_i

 tensor([[0.1066]]) tensor([[17]])

接下来我们继续看

top_n,top_i = output.data.topk(1)top_i[0][0] #所属语言类别的索引值

显示top_i[0][0]

 tensor(17)
准备训练RNN

在训练前,我们把上面刚刚测试的求 所属语言类别的索引值 方法封装成函数 category_from_output 。

该函数输入:

output : RNN网络输出的output

该函数输出:

语言类别 语言类别索引值
def category_from_output(output): _,top_i = output.data.topk(1)  category_i = top_i[0][0] return all_categorIEs[category_i],category_icategory_from_output(output)

显示category_from_output(output)运行结果

 ('Polish',tensor(17))

类比机器学习中需要将数据打乱,这里我们也要增入随机性(打乱)。

但不是将训练数据打乱,而是每次训练时随机的从数据集中抽取一种语言中的一个姓名。

这里我们定义了 random_training_pair 函数, 函数返回的是一个元组 (category,name,category_tensor,name_tensor) :

category: 语言名 name: 姓名 category_tensor name_tensor

在定义函数前先看下面几个例子,更好的理解函数内部的运算过程。

category = random.choice(all_categorIEs)category

显示category

 'Polish'

上面的随机抽取了 一种语言 , 接下来我们在 该语言 中抽取一个 姓名

name = random.choice(category_names[category])name

显示name

 'Krol'

训练过程中我们要有标签数据,在本文中 所属语言的索引值 作为 标签 。

由于pytorch中训练过程中使用的都是tensor结构数据,其中的元素都是浮点型数值,所以这里我们使用LongTensor, 可以保证标签是整数。

另外要注意的是,pytorch中运算的数据都是batch。所以我们要将 所属语言的索引值 放入一个List中,再将该List传入torch.LongTensor()中

category_tensor = torch.LongTensor([all_categorIEs.index(category)])category_tensor

显示category_tensor

 tensor([17])

同理,name也要转化为tensor,这里我们调用name_to_tensor函数即可。

name_tensor = name_to_tensor(name)name_tensor

显示name_tensor

 tensor([[[0.,0.]]])

刚刚几个例子,相信大家已经明白了函数内部的实现方法,现在将其封装成 random_training_pair函数

import randomdef random_training_pair():  category = random.choice(all_categorIEs) name = random.choice(category_names[category]) category_tensor = torch.LongTensor([all_categorIEs.index(category)]) name_tensor = name_to_tensor(name) return category,name_tensor#我们从数据集中抽取十次for i in range(10): category,name_tensor = random_training_pair() print('category =',category,'/ name =',name)

上述代码块运行结果

 category = VIEtnamese / name = Truong category = arabic / name = Malouf category = German / name = Messner category = arabic / name = Boulos category = English / name = Batchelor category = Spanish / name = Guerrero category = Italian / name = Monti category = Scottish / name = Thomson category = Irish / name = Connell category = Korean / name = Youn
训练RNN网络

我们使用 nn.CrossEntropyLoss 作为评判标准,来检验 姓名真实所属的语言truth 与 预测该姓名得到预测所属语言类别predict 比对,计算RNN网络训练的误差。

criterion = nn.CrossEntropyLoss()

我们也创建了 优化器optimizer , 常用的优化器是 SGD算法 。当 每次训练网络,我们比对结果,好则改之,无则加勉, 让该网络改善的学习率learning rate(改进的速度)设置为0.005 。

注意学习率learning rate不能设置的太大或者太小:

所谓欲速则不达,太大导致训练效果不佳。容易大条 太小了会导致训练速度太慢,遥遥无期。
learning_rate = 0.005 optimizer = torch.optim.SGD(rnn.parameters(),#给优化器传入rnn网络参数 lr=learning_rate) #学习率

每轮训练将:

创建input(name_tensor)和 input对应的语言类别标签(category_tensor) 当输入姓名第一个字母时,需要初始化隐藏层参数。 读取姓名中的 每个字母的数组信息 ,传入rnn,并将网络输出的hIDden_state和下一个字母数组信息传入之后的RNN网络中 使用criterion比对 最终输出结果 与 姓名真实所属的语言标签 作比较 更新网络参数,改进网络。 循环往复以上几步
def train(category_tensor,name_tensor): rnn.zero_grad() #将rnn网络梯度清零 hIDden = rnn.init_hIDden() #只对姓名的第一字母构建起hIDden参数 #对姓名的每一个字母逐次学习规律。每次循环的得到的hIDden参数传入下次rnn网络中 for i in range(name_tensor.size()[0]): output,hIDden = rnn(name_tensor[i],hIDden) #比较最终输出结果与 该姓名真实所属语言,计算训练误差 loss = criterion(output,category_tensor) #将比较后的结果反向传播给整个网络 loss.backward() #调整网络参数。有则改之无则加勉 optimizer.step() #返回预测结果 和 训练误差 return output,loss.data[0]

现在我们可以使用一大堆姓名和语言数据来训练RNN网络,因为 train函数 会同时返回 预测结果 和 训练误差 , 我们可以打印并可视化这些信息。

为了方便,我们每训练5000次(5000个姓名),就打印 一个姓名的预测结果 ,并 查看该姓名是否预测正确 。

我们对每1000次的训练累计误差,最终将误差 可视化出来。

import timeimport mathn_epochs = 100000 # 训练100000次(可重复的从数据集中抽取100000姓名)print_every = 5000 #每训练5000次,打印一次plot_every = 1000 #每训练1000次,计算一次训练平均误差current_loss = 0 #初始误差为0all_losses = [] #记录平均误差def time_since(since): #计算训练使用的时间 Now = time.time() s = Now - since m = math.floor(s / 60) s -= m * 60 return '%dm %ds' % (m,s)#训练开始时间点start = time.time()for epoch in range(1,n_epochs + 1): # 随机的获取训练数据name和对应的language category,name_tensor = random_training_pair() output,loss = train(category_tensor,name_tensor) current_loss += loss #每训练5000次,预测一个姓名,并打印预测情况 if epoch % print_every == 0: guess,guess_i = category_from_output(output) correct = '✓' if guess == category else '✗ (%s)' % category print('%d %d%% (%s) %.4f %s / %s %s' % (epoch,epoch / n_epochs * 100,time_since(start),loss,guess,correct)) # 每训练5000次,计算一个训练平均误差,方便后面可视化误差曲线图 if epoch % plot_every == 0: all_losses.append(current_loss / plot_every) current_loss = 0

上面代码块运行结果

 5000 5% (0m 8s) 1.6642 San / Chinese ✗ (Korean) 10000 10% (0m 15s) 3.1045 Sobol / arabic ✗ (Polish) 15000 15% (0m 23s) 2.9460 Hill / VIEtnamese ✗ (Scottish) 20000 20% (0m 30s) 1.3255 Uemura / Japanese ✓ 25000 25% (0m 37s) 0.0889 Antonopoulos / Greek ✓ 30000 30% (0m 45s) 2.0578 Keighley / Russian ✗ (English) 35000 35% (0m 53s) 3.4646 Gaspar / arabic ✗ (Spanish) 40000 40% (1m 1s) 2.6537 soto / Japanese ✗ (Spanish) 45000 45% (1m 8s) 0.7883 Lykoshin / Russian ✓ 50000 50% (1m 17s) 3.1190 Blau / VIEtnamese ✗ (German) 55000 55% (1m 26s) 1.4374 Sacco / Portuguese ✗ (Italian) 60000 60% (1m 33s) 0.0793 O'Boyle / Irish ✓ 65000 65% (1m 41s) 1.0468 Kong / Chinese ✓ 70000 70% (1m 47s) 0.6785 DavIDson / Scottish ✓ 75000 75% (1m 55s) 3.3509 Serafin / Irish ✗ (Polish) 80000 80% (2m 2s) 0.1848 Portelli / Italian ✓ 85000 85% (2m 8s) 1.0430 Gabrisova / Czech ✓ 90000 90% (2m 15s) 1.3065 Loyola / Czech ✗ (Spanish) 95000 95% (2m 22s) 0.2379 Coelho / Portuguese ✓ 100000 100% (2m 29s) 0.3560 Teng / Chinese ✓
绘制训练误差
import matplotlib.pyplot as plt%matplotlib inlineplt.figure()plt.plot(all_losses)

从误差图中可以看出,随着训练轮数的增加,模型的每1000次训练的平均误差越来越小。

手动检验训练的模型

为了方便,我们定义了 predict(rnn,input_name,n_predictions=3)函数

rnn: 训练得到的rnn网络 input_name: 姓名字符串 n_predictions:该姓名预测结果的前n_predictions个预测结果
def predict(rnn,n_predictions=3): hIDden = rnn.init_hIDden() #name_tensor.size()[0] 名字的长度(字母的数目) for i in range(name_tensor.size()[0]): output,hIDden) print('> %s' % input_name) # 得到该姓名预测结果中似然值中前n_predictions大的 似然值和所属语言 topv,topi = output.data.topk(n_predictions,True) predictions = [] for i in range(n_predictions): value = topv[0][i] category_index = topi[0][i] print('(%.2f) %s' % (value,all_categorIEs[category_index])) predictions.append([value,all_categorIEs[category_index]])predict(rnn,'Dovesky')predict(rnn,'Jackson')predict(rnn,'Satoshi')

上述代码块运行结果

思考Exercises

比照本文,我们还可做很多类似的训练,比如

根据任意词汇 -> 所属语言 根据名字 -> 名字的性别 文章标题 -> 文章所属话题

为了得到更准确的神经网络(更准确):

添加更多层Add more linear layers 尝试使用 nn.LSTM 或者 nn.GRU 聚合多种(如rnn、lstm、gru)为更高级的网络 总结

以上是内存溢出为你收集整理的Python深度学习实战!全头条会的不超过一只手吧!不吹不黑!全部内容,希望文章能够帮你解决Python深度学习实战!全头条会的不超过一只手吧!不吹不黑!所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1208761.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存