前言

有好几个月没搞神经网络代码了,期间也就是回顾了两边之前的文字。

不料,对nn,cnn的理解反而更深入了-_-!。

修改

《零基础学习人工智能—Python—Pytorch学习(四)》,关于Linear的理解是错误的,已修改。

RNN

RNN是Recurrent Neural Network的缩写。中文叫循环神经网络。

RNN是在NN的基础上的扩展。

我们知道在训练NN的时候,要传递一个待训练的tensor。RNN简单来说就是在传递tensor的同时,再传递一个hidden。

这个hidden是哪来的?它是上一轮训练时,返回y_predict的同时,返回的(我们之前写NN只会返回y_predict,现在要多返回一个hidden)。

如果没有上一轮,那hidden就等于空的tensor。

代码实现

定义RNN

class RNN(nn.Module):
# implement RNN from scratch rather than using nn.RNN
def __init__(self, input_size, hidden_size, output_size):
super(RNN, self).__init__() self.hidden_size = hidden_size
self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
self.i2o = nn.Linear(input_size + hidden_size, output_size)
self.softmax = nn.LogSoftmax(dim=1) def forward(self, input_tensor, hidden_tensor):
combined = torch.cat((input_tensor, hidden_tensor), 1) hidden = self.i2h(combined) #input to hidden=i2h
output = self.i2o(combined) #input to output=i2o
output = self.softmax(output)
return output, hidden def init_hidden(self):
return torch.zeros(1, self.hidden_size)

代码分析

init

init函数增加了一个参数hidden_size。我们知道init函数是接受x的列和y_predict的列的,x的列是input,y_predict的列是输出。

现在我们增加了hidden_size,他是hidden层的tensor的列。

我们在使用linear的时候,会把input_size和hidden_size相加,因为,我们后面再前向传播的时候,也会把x的tensor和hidden的tensor组合成一个向量。

forward

forward函数,我们先看return。

return多返回了一个对象——hidden,hidden是一个tensor,是执行linear(i2h)时的output,他也是根据x进行线性变换后的tensor,因为不是最后输出的tensor,所以他叫做hidden,而最后输出的output的tensor叫做y_predict。

我们在看forward的第一行,combined = torch.cat((input_tensor, hidden_tensor), 1)。

这是把tensor变量input_tensor和hidden_tensor给合并成了一个tensor,使用的是torch.cat函数。参数1是指按列的方向合并。

即input_tensor如果是(3,5),hidden_tensor是(3,2),我们将得到一个(3,7),相当与把hidden的每一行的值取出来,添加进相同行的input_tensor里。

所以我们上面的init里,初始化linear的第一个参数(x的列)是input_size + hidden_size。

定义工具函数

import io
import os
import unicodedata
import string
import glob import torch
import random # alphabet small + capital letters + " .,;'"
ALL_LETTERS = string.ascii_letters + " .,;'"
N_LETTERS = len(ALL_LETTERS) # Turn a Unicode string to plain ASCII, thanks to https://stackoverflow.com/a/518232/2809427
def unicode_to_ascii(s):
return ''.join(
c for c in unicodedata.normalize('NFD', s)
if unicodedata.category(c) != 'Mn'
and c in ALL_LETTERS
) def load_data():
# Build the category_lines dictionary, a list of names per language
category_lines = {}
all_categories = [] def find_files(path):
return glob.glob(path) # Read a file and split into lines
def read_lines(filename):
lines = io.open(filename, encoding='utf-8').read().strip().split('\n')
return [unicode_to_ascii(line) for line in lines] for filename in find_files('data/names/*.txt'):
category = os.path.splitext(os.path.basename(filename))[0]
all_categories.append(category) lines = read_lines(filename)
category_lines[category] = lines return category_lines, all_categories """
To represent a single letter, we use a “one-hot vector” of
size <1 x n_letters>. A one-hot vector is filled with 0s
except for a 1 at index of the current letter, e.g. "b" = <0 1 0 0 0 ...>. To make a word we join a bunch of those into a
2D matrix <line_length x 1 x n_letters>. That extra 1 dimension is because PyTorch assumes
everything is in batches - we’re just using a batch size of 1 here.
""" # Find letter index from all_letters, e.g. "a" = 0
def letter_to_index(letter):
return ALL_LETTERS.find(letter) # Just for demonstration, turn a letter into a <1 x n_letters> Tensor
def letter_to_tensor(letter):
tensor = torch.zeros(1, N_LETTERS)
tensor[0][letter_to_index(letter)] = 1
return tensor # Turn a line into a <line_length x 1 x n_letters>,
# or an array of one-hot letter vectors
def line_to_tensor(line):
tensor = torch.zeros(len(line), 1, N_LETTERS)
for i, letter in enumerate(line):
tensor[i][0][letter_to_index(letter)] = 1
return tensor def random_training_example(category_lines, all_categories): def random_choice(a):
random_idx = random.randint(0, len(a) - 1)
return a[random_idx] category = random_choice(all_categories)
line = random_choice(category_lines[category])
category_tensor = torch.tensor([all_categories.index(category)], dtype=torch.long)
line_tensor = line_to_tensor(line)
return category, line, category_tensor, line_tensor if __name__ == '__main__':
print(ALL_LETTERS)
print(unicode_to_ascii('Ślusàrski')) category_lines, all_categories = load_data()
print(category_lines['Italian'][:5]) print(letter_to_tensor('J')) # [1, 57]
print(line_to_tensor('Jones').size()) # [5, 1, 57]

代码分析

string.ascii_letters 是一个字符串常量,它包含了所有 ASCII 字母,即小写字母 'abcdefghijklmnopqrstuvwxyz' 和大写字母 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 的组合

letter_to_tensor函数:是把入参的字母转成tensor,tensor的shape是(1,57),后面我们使用该向量做神经网络的输入。

one-hot 向量

letter_to_tensor函数输出是tensor被称为one-hot向量,直译就是一个热点向量,即向量里就一个值是有意义的值。

【one-hot向量】就是一行N列的向量,列的值为1时,该列的位置,就是字母在字符串的位置。

如果我们有以下字母表,共27个字符(26个字母 + 空格):

ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz "

转成one-hot 向量,就会如下图模式分配。

load_data函数:查询一个文件夹下的全部文件,然后把文件名全部取出来,组成集合,然后把文件的内容取出来,结合文件的名字,组成字典。

glob.glob:系统函数,查询指定目录下的指定文件。

data.names文件夹如下:

RNN前向传播

category_lines, all_categories = load_data()
n_categories = len(all_categories) n_hidden = 128
print("N_LETTERS",N_LETTERS)
rnn = RNN(N_LETTERS, n_hidden, n_categories) # RNN(57,128,18) 18是18个国家即18个类别 input_tensor = letter_to_tensor('A') # 把A转成tensor(1,57)
hidden_tensor = rnn.init_hidden() output, next_hidden = rnn(input_tensor, hidden_tensor) input_tensor = line_to_tensor('Albert')
hidden_tensor = rnn.init_hidden() output, next_hidden = rnn(input_tensor[0], hidden_tensor) def category_from_output(output):
category_idx = torch.argmax(output).item()
return all_categories[category_idx] print(category_from_output(output))

代码分析

torch.argmax(output).item()是取出tensor里的最大值,其最大值的索引。

这里,我们通过整个RNN的前向传播,得到了一个output,即通过线性转换,我们得到y_predict,然后我们找到y_predict里最大的值的索引,我们认为,我们这个索引对应国家集合里对应索引的国家名,就是我们预测的我们输入的名字(实际输入的是字母)的所属国家。

完整代码:
import threading

import torch
import torch.nn as nn
from utils import ALL_LETTERS, N_LETTERS
from utils import load_data, letter_to_tensor, line_to_tensor, random_training_example def category_from_output(output):
category_idx = torch.argmax(output).item()
return all_categories[category_idx]
class RNN(nn.Module):
# implement RNN from scratch rather than using nn.RNN
def __init__(self, input_size, hidden_size, output_size):
super(RNN, self).__init__() self.hidden_size = hidden_size
self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
self.i2o = nn.Linear(input_size + hidden_size, output_size)
self.softmax = nn.LogSoftmax(dim=1) def forward(self, input_tensor, hidden_tensor):
combined = torch.cat((input_tensor, hidden_tensor), 1) hidden = self.i2h(combined) #input to hidden=i2h
output = self.i2o(combined) #input to output=i2o
output = self.softmax(output)
return output, hidden def init_hidden(self):
return torch.zeros(1, self.hidden_size) category_lines, all_categories = load_data()
n_categories = len(all_categories) n_hidden = 128
print("N_LETTERS",N_LETTERS)
rnn = RNN(N_LETTERS, n_hidden, n_categories) # RNN(57,128,18) 18是18个国家即18个类别 input_tensor = letter_to_tensor('A') # 把A转成tensor(1,57)
hidden_tensor = rnn.init_hidden() output, next_hidden = rnn(input_tensor, hidden_tensor) print(category_from_output(output)) input_tensor = line_to_tensor('Albert')
hidden_tensor = rnn.init_hidden() output, next_hidden = rnn(input_tensor[0], hidden_tensor) print(category_from_output(output))

使用RNN训练及预测

定义训练函数

def train(line_tensor, category_tensor):
hidden = rnn.init_hidden() for i in range(line_tensor.size()[0]):
output, hidden = rnn(line_tensor[i], hidden) loss = criterion(output, category_tensor) optimizer.zero_grad()
loss.backward()
optimizer.step() return output, loss.item()

代码分析

入参line_tensor是一个tesnor,shape是(n,1,57),即,是一个字符串转成n个one-hot向量。他是一个名字的字符串。

入参category_tensor是真实的y值,这里他的shape是tensor(1),即,这个名字的真实国家的索引。

然后我们通过循环执行output, hidden = rnn(line_tensor[i], hidden),把每个字母都在rnn里进行线性变换,这里每次都会把hidden返回,然后下次调用rnn,会把hideen传递过去,形成循环网络。

最后输出的output是个1行18列的tensor,1行是因为我们输出的x是1行,18列是因为我们创建rnn时,指定了18列的输出。

然后我们执行损失函数,loss = criterion(output, category_tensor),计算损失值,损失函数有很多种。(我们可以简单这样理解损失函数的运行逻辑,上面通过线性计算把X转成了tensor(1,18),这个tensor是y_predict,现在我们计算y_predicd与真y的差,在把结果平方,在求平均数,反正就是计算出一个数,这个数如果是2,3,那就代表我们的模型错的很离谱)

损失值求完,我们就可以使用损失值进行逆向传播了loss.backward()。这里loss是触发逆向传播的,也就是计算梯度,也就是求偏导数,之所以是loss触发,是因为loss本身是通过函数计算出来的,而我们求梯度,是对这个求loss的函数偏导,但是loss值,并不参与求偏导,所以loss是触发逆向传播的启点。

完整代码
import threading

import torch
import torch.nn as nn
import matplotlib.pyplot as plt from utils import ALL_LETTERS, N_LETTERS
from utils import load_data, letter_to_tensor, line_to_tensor, random_training_example def category_from_output(output):
category_idx = torch.argmax(output).item()
return all_categories[category_idx]
class RNN(nn.Module):
# implement RNN from scratch rather than using nn.RNN
def __init__(self, input_size, hidden_size, output_size):
super(RNN, self).__init__() self.hidden_size = hidden_size
self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
self.i2o = nn.Linear(input_size + hidden_size, output_size)
self.softmax = nn.LogSoftmax(dim=1) def forward(self, input_tensor, hidden_tensor):
combined = torch.cat((input_tensor, hidden_tensor), 1) hidden = self.i2h(combined) #input to hidden=i2h
output = self.i2o(combined) #input to output=i2o
output = self.softmax(output)
return output, hidden def init_hidden(self):
return torch.zeros(1, self.hidden_size) category_lines, all_categories = load_data()
# print("category_lines",category_lines)
# print("all_categories",all_categories)
n_categories = len(all_categories) n_hidden = 128
rnn = RNN(N_LETTERS, n_hidden, n_categories) criterion = nn.NLLLoss()
learning_rate = 0.005
optimizer = torch.optim.SGD(rnn.parameters(), lr=learning_rate) def train(line_tensor, category_tensor):
hidden = rnn.init_hidden() for i in range(line_tensor.size()[0]):
output, hidden = rnn(line_tensor[i], hidden) loss = criterion(output, category_tensor) optimizer.zero_grad()
loss.backward()
optimizer.step() return output, loss.item() current_loss = 0
all_losses = []
plot_steps, print_steps = 1000, 5000
n_iters = 100000
for i in range(n_iters):
category, line, category_tensor, line_tensor = random_training_example(category_lines, all_categories) # category=国家名 line=这个国家下的随机一个名字 category_tensor=国家名索引值转换成的tensor(1) line_tensor=名字转换成的tensor(n,1,57) output, loss = train(line_tensor, category_tensor)
current_loss += loss if (i+1) % plot_steps == 0:
all_losses.append(current_loss / plot_steps)
current_loss = 0 if (i+1) % print_steps == 0:
guess = category_from_output(output)
correct = "CORRECT" if guess == category else f"WRONG ({category})"
print(f"{i+1} {(i+1)/n_iters*100} {loss:.4f} {line} / {guess} {correct}") def show():
plt.figure()
plt.plot(all_losses)
plt.show()
show() def predict(input_line):
print(f"\n> {input_line}")
with torch.no_grad():
line_tensor = line_to_tensor(input_line) hidden = rnn.init_hidden() for i in range(line_tensor.size()[0]):
output, hidden = rnn(line_tensor[i], hidden) guess = category_from_output(output)
print("guess:",guess) while True:
sentence = input("Input:")
if sentence == "quit":
break predict(sentence)

到此,Python—Pytorch学习-RNN(一)就介绍完了。


参考网站:https://github.com/patrickloeber/pytorch-examples/tree/master/rnn-name-classification


注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!



若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/18844861

Python—Pytorch学习-RNN(一)的更多相关文章

  1. 7大python 深度学习框架的描述及优缺点绍

    Theano https://github.com/Theano/Theano 描述: Theano 是一个python库, 允许你定义, 优化并且有效地评估涉及到多维数组的数学表达式. 它与GPUs ...

  2. 新手必备 | 史上最全的PyTorch学习资源汇总

    目录: PyTorch学习教程.手册 PyTorch视频教程 PyTorch项目资源      - NLP&PyTorch实战      - CV&PyTorch实战 PyTorch论 ...

  3. Day1 Python基础学习

    一.编程语言分类 1.简介 机器语言:站在计算机的角度,说计算机能听懂的语言,那就是直接用二进制编程,直接操作硬件 汇编语言:站在计算机的角度,简写的英文标识符取代二进制去编写程序,本质仍然是直接操作 ...

  4. Day1 Python基础学习——概述、基本数据类型、流程控制

    一.Python基础学习 一.编程语言分类 1.简介 机器语言:站在计算机的角度,说计算机能听懂的语言,那就是直接用二进制编程,直接操作硬件 汇编语言:站在计算机的角度,简写的英文标识符取代二进制去编 ...

  5. 【深度学习】Pytorch学习基础

    目录 pytorch学习 numpy & Torch Variable 激励函数 回归 区分类型 快速搭建法 模型的保存与提取 批训练 加速神经网络训练 Optimizer优化器 CNN MN ...

  6. Pytorch学习记录-torchtext和Pytorch的实例( 使用神经网络训练Seq2Seq代码)

    Pytorch学习记录-torchtext和Pytorch的实例1 0. PyTorch Seq2Seq项目介绍 1. 使用神经网络训练Seq2Seq 1.1 简介,对论文中公式的解读 1.2 数据预 ...

  7. Pytorch学习--编程实战:猫和狗二分类

    Pytorch学习系列(一)至(四)均摘自<深度学习框架PyTorch入门与实践>陈云 目录: 1.程序的主要功能 2.文件组织架构 3. 关于`__init__.py` 4.数据处理 5 ...

  8. Python基础学习之环境搭建

    Python如今成为零基础编程爱好者的首选学习语言,这和Python语言自身的强大功能和简单易学是分不开的.今天我们将带领Python零基础的初学者完成入门的第一步——环境搭建.本文会先来区分几个在P ...

  9. [深度学习] Pytorch学习(一)—— torch tensor

    [深度学习] Pytorch学习(一)-- torch tensor 学习笔记 . 记录 分享 . 学习的代码环境:python3.6 torch1.3 vscode+jupyter扩展 #%% im ...

  10. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

随机推荐

  1. 独立开发经验谈:我是如何借助 Docker 环境变量让客户 1 分钟上线客服系统的

    我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户,在这个过程中,我也积累了不少如何开发运营 ...

  2. 玩转云端|够轻松!天翼云边缘安全加速平台AccessOne助力企业解决远程办公难题!

    本文分享自天翼云开发者社区<玩转云端|够轻松!天翼云边缘安全加速平台AccessOne助力企业解决远程办公难题>,作者:天翼云社区官方账号 省去早起挤地铁的苦恼,享受居家办公的从容不迫-- ...

  3. Q:Linux查看进程启动服务的精确时间

    输入命令 获取进程号 #1#获取进程号ps -ef|grep java|grep 进程名#2#获取启动时间ps -p 进程号 -o lstart  展示启动时间:星期 月 日 小时:分钟:秒 年 一键 ...

  4. 在python中通过模型api

    前言 首先我选择的siliconflow(硅基流动)平台来调用它的api,无为啥,就是因为我点击了别人的邀请链接它送了我14块余额,那个人同样也获得14块余额 这时候,就不得不说一下我的邀请链接了ht ...

  5. JS用 URL 构造函数来解析 URL

    const url = new URL('http://username:password@hostname:9090/path?arg=value#anchor'); console.log(url ...

  6. 使用Express对mysql进行增改查操作(完全代码版本)

    使用Express对mysql进行增改查操作(完全代码版本) 今天发的是Express对mysql进行增删改操作的所有代码,这个代码还没有完善好,都是一些基础的增删改查操作,有一些地方也写上了注释方便 ...

  7. Assignment to property of function parameter 'XXX' no-param-reassign 记录

    在react项目中写了一个工具方法将两个数组数据进行整合,用了双重for循环,但是在提交代码时报了eslint的no-param-reassign 结果效果是有了,但是报lint错误,图片中已是解决后 ...

  8. 自动旋转ROS小车(rviz+urdf+xacro)(附加python操作键盘控制小车运动)

    博客地址:https://www.cnblogs.com/zylyehuo/ 成果图 STEP1 创建工作空间 mkdir -p car_ws/src cd car_ws catkin_make ST ...

  9. Destination host unreachable 一般解决办法

    症状: 上网各类应用基本正常,但是在命令行下使用ping命令,无论任何地址,均反馈Destination host unreachable. 分析: 输入命令arp -a可以看到网关的MAC地址正常解 ...

  10. 查询Oracle正在执行的sql语句及执行该语句的用户

    SELECT b.sid oracleID, b.username 登录Oracle用户名, b.serial#, spid 操作系统ID, paddr, sql_text 正在执行的SQL, b.m ...