Python深度学习实战!全头条会的不超过一只手吧!不吹不黑!
pridict('Hinton') (-0.47) Scottish (-1.52) English (-3.57) Irish pridict('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> 的Tensor def letter_to_tensor(letter): tensor = torch.zeros(1,n_letters) letter_index = all_letters.find(letter) tensor[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.]]]) 构建神经网络注意看图中各个参数解读:
大家仔细看看琢磨琢磨这个图构造。现在我们先看看 combined 这个操作 a = t.Tensor(3,1) b = t.Tensor(3,2) print(a) #a print(b) #b print(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,各个参数解读:
import torch.nn as nn class 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 = 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中的含有数据,想办法从中提取出预测的 语言类别信息 。 具体思路:
该索引值就是 所属语言类别的索引值,具体我们可以看下面的例子更好的理解tensor的操作方法。 output.data output.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 。 该函数输入:
该函数输出:
def category_from_output(output): _,top_i = output.data.topk(1) category_i = top_i[0][0] return all_categories[category_i],category_i category_from_output(output) 显示category_from_output(output)运行结果 ('Polish',tensor(17)) 类比机器学习中需要将数据打乱,这里我们也要增入随机性(打乱)。 但不是将训练数据打乱,而是每次训练时随机的从数据集中抽取一种语言中的一个姓名。 这里我们定义了 random_training_pair 函数, 函数返回的是一个元组 (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 random def 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) #学习率 每轮训练将:
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 time import math n_epochs = 100000 # 训练100000次(可重复的从数据集中抽取100000姓名) print_every = 5000 #每训练5000次,打印一次 plot_every = 1000 #每训练1000次,计算一次训练平均误差 current_loss = 0 #初始误差为0 all_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 inline plt.figure() plt.plot(all_losses) 从误差图中可以看出,随着训练轮数的增加,模型的每1000次训练的平均误差越来越小。 手动检验训练的模型为了方便,我们定义了 predict(rnn,input_name,n_predictions=3)函数
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比照本文,我们还可做很多类似的训练,比如
为了得到更准确的神经网络(更准确):
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |