机器学习周报(9.30-10.6)

文章目录

  • [1 RNN](#1 RNN)
    • [1.1 使用pytorch RNN](#1.1 使用pytorch RNN)
    • [1.2 单向、单层RNN](#1.2 单向、单层RNN)
    • [1.3 双向、单层RNN](#1.3 双向、单层RNN)
    • [1.4 手写一个rnn_forward函数 实现单向RNN的计算原理](#1.4 手写一个rnn_forward函数 实现单向RNN的计算原理)
  • [2 pytorch中tensor相关函数学习使用](#2 pytorch中tensor相关函数学习使用)

摘要

进一步学习了循环神经网络(RNN)原理、种类、优缺点,使用Pytorch中所提供的RNN模型,并根据公式进行了手写实现RNN的计算原理。继续补充学习pytorch中其他函数的使用

Abstract

I further learn the principle, types, advantages and disadvantages of recurrent neural network (RNN), use the RNN model provided in Pytorch, and implement the calculation principle of RNN by hand according to the formula. Continue to supplement the use of other functions in pytorch

1 RNN

优点:

  • 可以处理变长序列
  • 模型大小与序列长度无关
  • 计算量与序列长度呈线性增长
  • 考虑历史信息
  • 便于流氏输出
  • 权重在每一时刻都不改变

缺点:

  • 串行计算比较慢
  • 无法获取太长的历史信息

1. one to n

还有一种结构是把输入信息X作为每个阶段的输入:

这种 one-to-n 的结构可以处理的问题有:

  • 从图像生成文字(image caption),此时输入的X就是图像的特征,而输出的y序列就是一段句子,就像看图说话等
  • AI诗歌(歌词)生成

2. n to one

要处理的问题输入是一个序列,输出是一个单独的值而不是序列,

这种结构通常用来处理序列分类问题,如:文本情感分类;输入一段文字判别它所属的类别,输入一个句子判断其情感倾向,输入一段视频并判断它的类别等

3. n to n

最经典的RNN结构,输入、输出都是等长的序列数据。

该结构可用于词法识别等问题领域

4. n to m

输入、输出为不等长的序列。

这种结构是Encoder-Decoder模型,也叫Seq2Seq模型,是RNN的一个重要变种

机器翻译

该结构可应用于:

  • 机器翻译:Encoder-Decoder的最经典应用,事实上这结构就是在机器翻译领域最先提出的。
  • 文本摘要:输入是一段文本序列,输出是这段文本序列的摘要序列。
  • 阅读理解:将输入的文章和问题分别编码,再对其进行解码得到问题的答案。
  • 语音识别:输入是语音信号序列,输出是文字序列。

1.1 使用pytorch RNN

隐含状态计算函数:

x t x_t xt当前时刻的输入
w i h w_{ih} wih对当前时刻输入 x t x_t xt的权重
b i h b_{ih} bih对当前舒克输入 x t x_t xt的偏置值
h t − 1 h_{t-1} ht−1上一时刻的输出(隐含状态)
w h h w_{hh} whh对上一时刻输出的权重
b h h b_{hh} bhh对上一时刻输出的偏置值

每一时刻的输出(隐含状态) h t h_t ht,不仅和当前的输入 x t x_t xt有关,还跟上一时刻的隐含状态 h t − 1 h_{t-1} ht−1有关; h 0 h_0 h0表示初始的隐含状态

实例化RNN类,需要传递的参数:

input_size:输入数据的特征维度

hidden_size:隐含状态 h t h_t ht的大小

num_layers:默认值为1,大于1,表示多个RNN堆叠起来

nonlinearity:默认是tanh,使用'tanh'还是'relu'非线性激活函数

batch_first:默认是False;若为True,输入输出格式为:(batch, seq, feature) ;若为False:输入输出格式为: (seq, batch, feature);

bidirectional:默认为False;若为True,则是双向RNN,同时输出长度为2*hidden_size

输入值:

  1. input:当batch_first=True 输入格式为(N,L, H i n H_{in} Hin);当batch_first=False 输入格式为(L,N, H i n H_{in} Hin);
  2. h 0 h_0 h0:默认输入值为0;输入格式为:(D*num_layers,N, H o u t H_{out} Hout)

其中:

N = batch size

L = sequence length

D = 2 if bidirectional=True otherwise 1
H i n H_{in} Hin = input_size
H o u t H_{out} Hout = hidden_size

输出值:

  1. output:当batch_first=True 输出格式为(N,L,D* H o u t H_{out} Hout);当batch_first=False 输出格式为(L,N,D* H o u t H_{out} Hout);
  2. h_n:输出格式为:(D*num_layers,N, H o u t H_{out} Hout)

1.2 单向、单层RNN

python 复制代码
import torch
import torch.nn as nn

# 单层、单向RNN
single_RNN = nn.RNN(input_size=4, hidden_size=3, num_layers=1, batch_first=True)
input = torch.randn(1, 2, 4)    # batch_size, seq, feature

# 输入:input,h_0,  h_0默认为0
output, h_n = single_RNN(input)
print(output)
print(output.shape) # torch.Size([1, 2, 3])
#   (1, 2, 3) batch_size, sequence_length(输入的序列长度), 1*hidden_size
'''
tensor([[[ 0.0776, -0.1944,  0.2900],
         [ 0.5634,  0.4408, -0.1425]]], grad_fn=<TransposeBackward1>)
'''

# 最后一个时刻的隐含状态,在简单的RNN中最后时刻的隐含状态等于最后时刻的输出的
print(h_n)  # tensor([[[ 0.5634,  0.4408, -0.1425]]], grad_fn=<StackBackward0>)
print(h_n.shape)    # torch.Size([1, 1, 3])	

1.3 双向、单层RNN

python 复制代码
# 双向、单层 RNN
bidirectional_rnn = nn.RNN(input_size=4, hidden_size=3, num_layers=1, batch_first=True, bidirectional=True)
input = torch.randn(1, 3, 4)    # 对应:batch_size, sequence_length,input_size
output, h_n = bidirectional_rnn(input)
print(output)
'''
tensor([[[ 0.2334,  0.4457, -0.7746, -0.8840, -0.4599,  0.3842],
         [ 0.2279,  0.7657, -0.6831, -0.4505, -0.8027,  0.7260],
         [ 0.8037, -0.2561,  0.4805, -0.9449, -0.1073, -0.3663]]],
       grad_fn=<TransposeBackward1>)
'''
print(output.shape) # torch.Size([1, 3, 6]) ,对应:batch_size, 输入的sequence_length,2*hidden_size
print(h_n)
'''
tensor([[[ 0.8037, -0.2561,  0.4805]],

        [[-0.8840, -0.4599,  0.3842]]], grad_fn=<StackBackward0>)
'''
print(h_n.shape)    # torch.Size([2, 1, 3])  对应:2*num_layers,batch_size,hidden_size

1.4 手写一个rnn_forward函数 实现单向RNN的计算原理

python 复制代码
# batch_size, sequence_length
bs, T = 2, 3 #批大小,输入序列长度
# input_size, hidden_size, num_layers
input_size, hidden_size = 2, 3  #输入特征大小,隐含层特征大小

input = torch.randn(bs, T, input_size)  # 随机初始化一个输入特征序列
h_prev = torch.zeros(bs, hidden_size)   # 初始隐含状态
  1. step1 调用pytorch RNN API
python 复制代码
# step1 调用一下pytorch RNN API
py_RNN = nn.RNN(input_size=input_size, hidden_size=hidden_size, batch_first=True)
rnn_output, rnn_h_n = py_RNN(input, h_prev.unsqueeze(0))
print(rnn_output)
print(rnn_h_n)
  1. step2 手写一个rnn_forward函数 实现单向RNN的计算原理
python 复制代码
# step2 手写一个rnn_forward函数 实现单向RNN的计算原理
def rnn_forward(input, weight_ih, weight_hh, h_prev, bias_ih, bias_hh):
        # 获取一下维度
        bs, T, input_size = input.shape
        h_dim = weight_ih.shape[0]

        # 初始化一个输出(状态)矩阵
        h_out = torch.zeros(bs, T, h_dim)

        #使用循环进行计算
        # RNN的计算复杂度跟序列程度呈线性关系 故对序列长度进行循环即可
        for t in range(T):
            x = input[:, t, :].unsqueeze(2)  # 获取当前时刻输入特征   bs*input_size *1
            weight_ih_batch = weight_ih.unsqueeze(0).tile(bs, 1, 1) #bs*h_dim*input_size
            weight_hh_batch = weight_hh.unsqueeze(0).tile(bs, 1, 1) #bs*h_dim*h_dim

            w_times_x = torch.bmm(weight_ih_batch, x).squeeze(-1)   # bs*h_dim
            w_times_h = torch.bmm(weight_hh_batch, h_prev.unsqueeze(2)).squeeze(-1) # bs*h_dim

            h_prev = torch.tanh(w_times_x + bias_hh + w_times_h + bias_ih)

            h_out[:, t, :] = h_prev

        return h_out, h_prev.unsqueeze(0)

获取 pytorch RNN内置参数

python 复制代码
for k, v in py_RNN.named_parameters():
    print(k, v)

输出为:

python 复制代码
weight_ih_l0 Parameter containing:
tensor([[-0.3953,  0.1414],
        [ 0.2219,  0.3725],
        [ 0.4715,  0.4406]], requires_grad=True)
weight_hh_l0 Parameter containing:
tensor([[ 0.2937, -0.1251, -0.0135],
        [-0.0135,  0.1731,  0.4419],
        [-0.4208, -0.2223,  0.3648]], requires_grad=True)
bias_ih_l0 Parameter containing:
tensor([-0.3374,  0.3580, -0.2634], requires_grad=True)
bias_hh_l0 Parameter containing:
tensor([-0.5208, -0.0641, -0.5621], requires_grad=True)
  1. step3 调用forward函数验证结果
python 复制代码
c_output, c_h_n = rnn_forward(input, py_RNN.weight_ih_l0, py_RNN.weight_hh_l0, h_prev, py_RNN.bias_ih_l0, py_RNN.bias_hh_l0)
print("rnn_forward function output:")
print(c_output)
print(c_h_n)

2 pytorch中tensor相关函数学习使用

  • squeeze unsqueeze 使用

squeeze: 删除输入张量中大小为1的指定维度

  1. 未指定参数dim,将张量中,维度为1的
python 复制代码
a = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

print(a.shape) # torch.Size([2, 3])
a = torch.reshape(a, [2, 1, 3, 1, 1])
print(a.shape)  # torch.Size([2, 1, 3, 1, 1])
b = torch.squeeze(a)
print(b.shape)  # torch.Size([2, 3])
  1. 参数dim取整型int,删除指定一个位置的维度1
python 复制代码
a = torch.reshape(a, [2, 1, 3, 1, 1])
b = torch.squeeze(a, dim=1)
print(b.shape)  # torch.Size([2, 3, 1, 1])
  1. 参数dim取list,删除指定多个位置的维度1
python 复制代码
a = torch.reshape(a, [2, 1, 3, 1, 1])
b = torch.squeeze(a, dim=[1, 3])
print(b.shape)  # torch.Size([2, 3, 1])

unsqueeze: 对输入张量中指定维度位置,增加大小为1的维度

注意:对于torch.unsqueeze的使用,必须声明dim的值且是整型int,不能是list型

python 复制代码
a = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])

print(a.shape) # torch.Size([2, 3])

# 参数dim的值必须是int,不能是list
b = torch.unsqueeze(a, dim=1)
print(b.shape)  # torch.Size([2, 1, 3])
  • torch.flip使用

沿着指定维度上,反转张量的顺序

python 复制代码
a = torch.arange(0, 12).view([2, 2, 3])
print(a)
a = torch.flip(a, [0, 1])
print(a)

翻转前:

python 复制代码
tensor([[[ 0,  1,  2],
         [ 3,  4,  5]],

        [[ 6,  7,  8],
         [ 9, 10, 11]]])

翻转后(第0维度上进行翻转,第一维度上进行翻转):

python 复制代码
tensor([[[ 9, 10, 11],
         [ 6,  7,  8]],

        [[ 3,  4,  5],
         [ 0,  1,  2]]])

总结

对于通过手写RNN的计算原理,有了更深刻的印象,下周将继续手写双向RNN的计算原理,并对LSTM更深入的学习

相关推荐
tech讯息3 分钟前
风冷、液冷、风液融合数据中心制冷方案品牌怎么挑?结合负载工况与项目场景筛选
人工智能
孙启超10 分钟前
【AI应用开发】ReAct 原理是什么?和普通直接提问 LLM 差别在哪?
前端·人工智能·llm·agent·react·rag·ai应用开发
RobinDevNotes12 分钟前
开源AI渗透测试智能体自动验证真实漏洞
人工智能·网络安全·ai·个人开发·开发工具
数据皮皮侠AI14 分钟前
上市公司数字供应链金融指数(2010-2024)
大数据·人工智能·算法
海兰27 分钟前
【思考】AI编码企业落地:从“通用生成”到“工程落地”的鸿沟与跨越
人工智能
白拾36 分钟前
【ICML 2026 (Oral)】RoboMME 论文解读:首个大规模具身记忆评测基准,系统评估 VLA 长程记忆
人工智能·机器人·具身智能·vla·icml·记忆·基准评测
word39 分钟前
用 AI 搭一条自动化热点监控流水线:RSS 聚合、智能筛选、定时推送一次跑通
人工智能
土星云SaturnCloud41 分钟前
智慧温室精准环控:土星云边缘计算设备实现温光水肥本地闭环调节
服务器·人工智能·ai·边缘计算
孙启超1 小时前
【AI应用开发】LangChain 中 Chain 和 Agent 核心区别?
java·人工智能·langchain·llm·rag·ai应用开发·agent loop
别动我齐刘海1 小时前
Day6 unitree_G1人形机器人GMR—— MotionInput
c语言·c++·人工智能·学习·机器学习·机器人·github