如何使用PyTorch实现循环神经网络(RNNs)

人工智能64

如何使用PyTorch实现循环神经网络(RNNs)


你好,这篇文章咱们讨论一下关于「如何使用PyTorch实现循环神经网络(RNNs)」的事情...

PyTorch 实现循环神经网络

本文介绍如何使用 PyTorch 实现循环神经网络(Recurrent Neural Networks, RNNs),涵盖基本的 RNN、LSTM 和 GRU 模型,并以样例代码进行展示。

循环神经网络简介

循环神经网络是一种具有记忆功能的神经网络,常用于处理序列数据(例如文本、音频等)。在传统的神经网络中,每个输入都是独立的,无法利用之前的输入的信息。而在循环神经网络中,每个输入与之前的输入相关联,通过向后传递隐藏状态实现对之前输入的记忆。这种机制使得循环神经网络能够处理可变长度的序列数据,并在理解语言、生成文本等领域取得了应用。

RNN 模型中,我们通常使用一个向量 $h_t$ 表示时刻 $t$ 的隐藏状态,将其作为网络的短期记忆,并在之后的时刻使用到。在标准的 RNN 模型中,隐藏状态 $h_t$ 的计算方式为:

$$
h_t = \sigma(W_h h_{t-1} + W_x x_t + b_h)
$$

其中,$x_t$ 是时刻 $t$ 的输入,$W_x$ 是输入到隐藏状态的权重矩阵,$W_h$ 是上一个时刻的隐藏状态到当前时刻隐藏状态的权重矩阵,$b_h$ 是偏置向量。$\sigma$ 是非线性激活函数(例如 tanh 或 ReLU)。

在 PyTorch 中,我们可以通过 nn.RNN 模块实现标准的 RNN 模型。

实现标准的 RNN 模型

数据预处理

为了方便起见,我们首先生成一个假的序列数据。

import torch
import torch.nn as nn

# 生成一个假的序列数据,长度为 10,每个元素的维度为 3
seq_data = torch.randn(10, 1, 3)

注意到 PyTorch 中的 RNN 模型的输入是一个三维张量,维度分别对应:序列长度、batch 大小、每个元素的维度。

定义 RNN 模型

接下来,我们定义一个标准的 RNN 模型。

class RNN(nn.Module):
 def __init__(self, input_size, hidden_size):
 super(RNN, self).__init__()
 self.input_size = input_size
 self.hidden_size = hidden_size
 self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)

 def forward(self, x):
 output, hidden = self.rnn(x)
 return output, hidden

RNN 构造函数中的参数 input_sizehidden_size 分别表示输入向量的维度和隐藏状态向量的维度。注意到此处我们将 batch_first 参数设置为 True,以指定输入张量中 batch 大小的维度在第一维。

在 forward 函数中,我们输入张量 x,得到输出张量 output 和隐藏状态张量 hidden。值得注意的是,RNN 模型的输出包含的是每个时刻的隐藏状态。如果我们想要获取最后一个时刻的输出,可以使用 output[:, -1, :]

计算模型输出

接下来,我们计算上述模型对于指定的序列数据输出的结果。

input_size = 3
hidden_size = 4

rnn = RNN(input_size, hidden_size)

output, hidden = rnn(seq_data)
last_output = output[:, -1, :]

print("Output shape:", output.shape)
print("Last output shape:", last_output.shape)

以上代码会输出如下信息:

Output shape: torch.Size([10, 1, 4])
Last output shape: torch.Size([1, 4])

LSTM 模型

接下来,我们介绍如何使用 PyTorch 实现 LSTM 模型。

LSTM(Long Short-Term Memory)是一种循环神经网络的变体,通过使用称为“单元状态”(cell state)的额外线路,存储长期记忆信息。相比于标准的 RNN,LSTM 模型的结构更加复杂,能够更好地处理长期依赖信息。

LSTM 中,我们通常使用两个向量来表示每个时刻的状态:

  • 隐藏状态 $h_t$
  • 单元状态 $c_t$

其中,单元状态是长期记忆信息,而隐藏状态是短期记忆信息。

在 PyTorch 中,可以使用 nn.LSTM 模块实现 LSTM 模型。其使用方法和 nn.RNN 类似。

class LSTM(nn.Module):
 def __init__(self, input_size, hidden_size):
 super(LSTM, self).__init__()
 self.input_size = input_size
 self.hidden_size = hidden_size
 self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)

 def forward(self, x):
 output, (hidden, cell) = self.lstm(x)
 return output, hidden, cell

注意到在 forward 函数中,我们输入张量 x,得到的输出包含了输出张量 output、隐藏状态张量 hidden 和单元状态张量 cell

GRU 模型

最后,我们介绍如何使用 PyTorch 实现 GRU 模型。

GRU(Gated Recurrent Units)是一种介于 RNN 和 LSTM 之间的模型,比 LSTM 更加简单,但比标准的 RNN 更加强大。GRU 最大的特点是引入了两个门:重置门(reset gate)和更新门(update gate)。它们能够控制上一时刻的隐藏状态 $h_{t-1}$ 对当前的隐藏状态 $h_t$ 的影响,有效地解决了梯度消失问题。

在 PyTorch 中,可以使用 nn.GRU 模块实现 GRU 模型,其使用方法和 nn.LSTM 类似。

class GRU(nn.Module):
 def __init__(self, input_size, hidden_size):
 super(GRU, self).__init__()
 self.input_size = input_size
 self.hidden_size = hidden_size
 self.gru = nn.GRU(input_size, hidden_size, batch_first=True)

 def forward(self, x):
 output, hidden = self.gru(x)
 return output, hidden

注意到 forward 函数返回的结果仅包含输出张量 output 和隐藏状态张量 hidden

总结

本文介绍了如何使用 PyTorch 实现循环神经网络,包括标准的 RNN、LSTM 和 GRU 模型。我们对每个模型的结构和PyTorch实现进行了简要介绍,并提供了代码示例。希望本文能够对你学习和实践循环神经网络有所帮助。

大家都在看:

Hough 变换检测圆----Matlab实现(以虹膜检测为例)

一、hough变换的原理:

  1. 圆方程

如何使用PyTorch实现循环神经网络(RNNs)

(1)xy空间一个圆对应三维参数空间一个点(a,b,r)
(2)xy空间圆上一个点(x,y)对应参数空间一条曲线
(3)xy空间圆上n个点对应参数空间n条相交于一点的曲线
注:对于原图中每一点,在参数空间确定一条曲线,经过曲线最多的点为原图中圆的参数

  1. 算法步骤:

(1)假设原图像已经处理为二值边缘图像,扫描图中的每一个像素点:
①背景点,不作任何处理
② 目标点,确定曲线:参数空间上的对应曲线上所有点的值累加1
(2)循环扫描所有点
(3)参数空间上累计值为最大的点(a,b,r*)为所求圆参数
(4)按照该参数与原图像同等大小的空白图像上绘制圆

  1. 简化运算

三维参数空间,计算量大,可以采样其他形式,如极坐标式,进行进一步简化。如何使用PyTorch实现循环神经网络(RNNs)

二、主函数

I=rgb2gray(imread('renyan.png'));
BW = edge(I,'sobel'); %目的检测圆的轮廓,如果直接就是圆图像,不用这个
% 用sobel进行边缘检测
%设置参数:
%检测的圆半径步长为0.5
Step_r = 0.5;  %步长过短,运行时间会很长
%角度步长0.1,单位为弧度
Step_angle = 0.1;   %步长过短,运行时间会很长
%最小圆半径30(圆半径根据实际检测调整)
minr =30;
%最大圆半径50
maxr=50;
%以thresh*hough_space的最大值为阈值,thresh取0-1之间的数
thresh = 0.8;
circleParaXYR=[];
%---------------------------------------------------------------------------------
%开始检测
[Hough_space,Hough_circle_result,Para] = Hough_circle(BW,Step_r,Step_angle,minr,maxr,thresh);
circleParaXYR=Para;
axis equal
figure(1);
imshow(BW,[]),title('边缘');
axis equal
figure(2);
imshow(Hough_circle_result,[]),title('检测结果');
axis equal
figure(3),imshow(I,[]),title('检测出图中的圆')
hold on
%---------------------------------------------------------------------------------
%以红色线标记出的检测圆心与圆
plot(circleParaXYR(:,2), circleParaXYR(:,1), 'r+');
for k = 1 : size(circleParaXYR, 1)
    t=0:0.01*pi:2*pi;
    x=cos(t).*circleParaXYR(k,3)+circleParaXYR(k,2);
    y=sin(t).*circleParaXYR(k,3)+circleParaXYR(k,1);
    plot(x,y,'r-');
end

三、构造Hough变换检测圆函数(主函数调用即可)

function [Hough_space,Hough_circle_result,Para] = Hough_circle(BW,Step_r,Step_angle,r_min,r_max,p)
circleParaXYR=[];
Para=[];
%得到二值图像大小
[m,n] = size(BW);
%计算检测半径和角度的步数、循环次数 并取整,四舍五入
size_r = round((r_max-r_min)/Step_r)+1;
size_angle = round(2*pi/Step_angle);
%建立参数空间
Hough_space = zeros(m,n,size_r);
%查找非零元素的行列坐标
[rows,cols] = find(BW);
%非零坐标的个数
ecount = size(rows);
% Hough变换
% 将图像空间(x,y)对应到参数空间(a,b,r)
% a = x-r*cos(angle)
% b = y-r*sin(angle)
for i=1:ecount
    for r=1:size_r %半径步长数按一定弧度把圆几等分
        for k=1:size_angle
            a = round(rows(i)-(r_min+(r-1)*Step_r)*cos(k*Step_angle));
            b = round(cols(i)-(r_min+(r-1)*Step_r)*sin(k*Step_angle));
            if (a>0&&am&&b>0&&bn)
                Hough_space(a,b,r)=Hough_space(a,b,r)+1;%h(a,b,r)的坐标,圆心和半径
            end
        end
    end
end
% 搜索超过阈值的聚集点,对于多个圆的检测,阈值要设的小一点!通过调此值,可以求出所有圆的圆心和半径返回值就是这个矩阵的最大值
max_para = max(max(max(Hough_space)));
%一个矩阵中,想找到其中大于max_para*p数的位置
index = find(Hough_space>=max_para*p);
length = size(index);%符合阈值的个数
Hough_circle_result=zeros(m,n);
%通过位置求半径和圆心。
for i=1:ecount
    for k=1:length
        par3 = floor(index(k)/(m*n))+1;
        par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;
        par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;
        if((rows(i)-par1)^2+(cols(i)-par2)^2<(r_min+(par3-1)*Step_r)^2+5&&...

          (rows(i)-par1)^2+(cols(i)-par2)^2>(r_min+(par3-1)*Step_r)^2-5)
            Hough_circle_result(rows(i),cols(i)) = 1;%检测的圆
        end
    end
end
% 从超过峰值阈值中得到
for k=1:length
    par3 = floor(index(k)/(m*n))+1;%取整
    par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;
    par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;
    circleParaXYR = [circleParaXYR;par1,par2,par3];
    Hough_circle_result(par1,par2)= 1; %这时得到好多圆心和半径,不同的圆的圆心处聚集好多点,这是因为所给的圆不是标准的圆
end
%集中在各个圆的圆心处的点取平均,得到针对每个圆的精确圆心和半径;
while size(circleParaXYR,1) >= 1
    num=1;
    XYR=[];
    temp1=circleParaXYR(1,1);
    temp2=circleParaXYR(1,2);
    temp3=circleParaXYR(1,3);
    c1=temp1;
    c2=temp2;
    c3=temp3;
    temp3= r_min+(temp3-1)*Step_r;
    if size(circleParaXYR,1)>1
        for k=2:size(circleParaXYR,1)
            if (circleParaXYR(k,1)-temp1)^2+(circleParaXYR(k,2)-temp2)^2 > temp3^2
                XYR=[XYR;circleParaXYR(k,1),circleParaXYR(k,2),circleParaXYR(k,3)];  %保存剩下圆的圆心和半径位置
            else
                c1=c1+circleParaXYR(k,1);
                c2=c2+circleParaXYR(k,2);
                c3=c3+circleParaXYR(k,3);
                num=num+1;
            end
        end
    end
    c1=round(c1/num);
    c2=round(c2/num);
    c3=round(c3/num);
    c3=r_min+(c3-1)*Step_r;
    Para=[Para;c1,c2,c3]; %保存各个圆的圆心和半径的值
    circleParaXYR=XYR;
end

四、结果
(1)眼睛的虹膜检测属于较难的检测,主函数加强预处理部分可提高效果;
(2)如果直接用Hough变换检测圆,调用该函数会得到较好效果;
(3)如果是彩色复杂图像,则采用预处理将圆大致提取出来,设置好Hough变换的参数,就可以完成识别。
如何使用PyTorch实现循环神经网络(RNNs)
支持可以关注我哦,持续分享编写的代码。

Original: https://blog.csdn.net/weixin_46548255/article/details/124371871
Author: 火球2号
Title: Hough 变换检测圆----Matlab实现(以虹膜检测为例)