Pytorch的CNN,RNNLSTM

CNN

拿二维卷积举例,我们先来看参数
在这里插入图片描述
卷积的基本原理,默认你已经知道了,然后我们来解释pytorch的各个参数,以及其背后的计算过程。
首先我们先来看卷积过后图片的形状的计算:
参数:

kernel_size :卷积核的大小,可以是一个元组,也就是(行大小,列大小)
stride : 移动步长,同样的可以是一个元组
padding:填充,同样的可以是一个元组。注意,填充是两边都填,如果原本宽是x,填充1后,宽会变成x+2,因为左右都填充了1
dilation : 空洞卷积大小

空洞卷积:

这里解释一下dilation,你可以认为他就是把卷积核之间加了一些洞,在不改变参数量的情况下增加了感受野。
下面两张图片引用自下面的链接,想详细了解空洞卷积的,可以看这篇文章。
https://zhuanlan.zhihu.com/p/50369448
dilation=1,此时卷积核的每个参数都是相邻的
在这里插入图片描述
dilation=2,此时卷积核的每个参数和上下左右都有一个空隙,这个空隙是一种间隔并不是一种参数,所以从形式上来看,卷积核变大变稀疏了,能够捕获更大的范围,但参数量没有变化。
![在这里插入图片描述](https://img-blog.csdnimg.cn/3dd7a254c03c4c89afe7e6257164aa78.png
所以,假设原卷积核形状是(a, b)那么dilation=k时,行增加了(k - 1)(a - 1),列增加了(k - 1)(b - 1)。
于是卷积核变成了(a + (k - 1)(a - 1), b + (k - 1)(b - 1))

输出行的计算:

我们来推导行的计算,列的计算同理。
我们可以把行分成两个部分第一个部分是卷积核做的第一次卷积,第二个部分是卷积核向右移动做的卷积。
此时行的大小应该是1 + 向右移动的次数。向右移动的次数应该等于(行大小 - 卷积核宽度) / 步长 再向下取整
行大小 = 图片宽度 + pandding[0] * 2
卷积核宽度 = kernel_size[0] + (dilation[0] - 1)(kernel_size[0] - 1)
我们把卷积核宽度计算展开得到:
卷积核宽度 = dilation[0](kernel_size[0] - 1) + 1
于是把上述公式整合就得到pytorch里的计算式
在这里插入图片描述

分组卷积:

我们可以看到Pytorch的CNN里有一个参数叫groups,是为分组卷积做准备的参数。
分组卷积的思路是吧in_channel和out_channel都进行分组,每个组内分别进行卷积运算,最后再把结果进行concat。下面举个例子:
输入in_channel = 4, out_channel = 6, groups = 2。
此时in_channel分成了两组,每组的channel数都是in_channel/groups = 2,同理out_channel 也分成了两组每组的channel数都是out_channel/groups=3
此时输入通道变成了in_channel_groups = (sub_in_channel1=2, sub_in_channel1=2)
输出通道变成了out_channel_groups = (sub_out_channel1=3, sub_out_channel1=3)
我们让sub_in_channel1和sub_out_channel1做卷积,sub_in_channel2和sub_out_channel2做卷积。
最后我们再把两个组的卷积结果concat一下,得到最终结果,第一个组的输出channel数是3,第二个组的数也是3,所以concat之后,输出的通道数还是6.

那么,分组卷积的意义何在呢?我们看参数数量就知道了。由于输出通道要除以groups,所以输入通道的数目会减少,此时每一个卷积核要负责的输入通道也就减少了,也就是说,卷积核的参数数目会减少groups倍,这就是分组卷积的意义。

参数量的计算

weight的大小为(out_channel, i n _ c h a n n e l g r o u p s \frac{in\_channel}{groups} groupsin_channel, kernel_size[0], kernel_size[1]),从这里也可以看出groups减少了参数量。
bias的大小就是out_channel的大小了。

示例代码:

conv = torch.nn.Conv2d(in_channels=3, out_channels=3, kernel_size=(3, 3),\
                       stride=(2, 2), padding=(0, 0), groups=3)
"""
上述代码创建了一个处理3通道图片的卷积层
其中输出通道为3,卷积核形状为(3, 3)没有padding,横向和垂直的步长都是2
输出通道和输入通道都会被平均的分为3组
"""

RNN

同理,这里也默认了你知道了RNN的基础知识,我们来看Pytorch中RNN的官方文档。
在这里插入图片描述
这里我们先忽略num_layers, bias, 等参数,先专注于hidden_size和input_size。
先创建一个RNN然后查看参数

rnn = torch.nn.RNN(input_size = 3, hidden_size=5, bias=False)
print(rnn.all_weights)
"""
[[Parameter containing:
tensor([[-0.2646, -0.4045, -0.1925],
        [-0.3035, -0.4026, -0.2005],
        [ 0.0181,  0.0157, -0.0804],
        [ 0.4191,  0.0750,  0.1659],
        [ 0.1848,  0.1085,  0.4351]], requires_grad=True), Parameter containing:
tensor([[ 0.4092,  0.1956, -0.1648,  0.0278, -0.3483],
        [ 0.3865,  0.3441,  0.1004, -0.4226, -0.2988],
        [ 0.2640,  0.3169, -0.2568, -0.3115,  0.3268],
        [-0.3311, -0.1856,  0.3827, -0.1265, -0.4149],
        [ 0.0930, -0.1986,  0.1813,  0.3944,  0.1576]], requires_grad=True)]]
"""

可以看到有两个参数,一个是wi=(5, 3)一个是wh=(5, 5),第一个参数wi用于乘以输入的数据,而第二个参数wh用于和隐藏层的向量相乘,在结合官方给出的RNN计算,我们就可以手动模拟以下RNN的推理过程了,RNN有两个输出,一个是out_put,一个是h_0
手动模拟:

data = torch.randn(size=(2, 4, 3), dtype=torch.float32) # 输入的数据
rnn = torch.nn.RNN(input_size = 3, hidden_size=5, bias=False)
wh = rnn.all_weights[0][0]
wi = rnn.all_weights[0][1]
h0 = torch.zeros(size=(1, 4, 5))

up_out = [] # out_put的数据
right_out = None # 隐藏层最终输出
acfun = torch.nn.Tanh()

for i in range(2): # 2代表时序
	tmp1 = data[i].matmul(wh.T) # 计算输入
    tmp2 = h0.matmul(wi.T) # 计算隐藏层
    res = acfun(tmp1 + tmp2) # 计算新的h_0
    up_out.append(res) # 本时刻的输出
    h0 = res # 更新隐藏层
print(torch.cat(up_out, dim=0), h0) # 把每一个时刻的输出都concat一下
print(rnn(data))

其余参数:

其余的参数就好理解了,num_layer是控制层数的,这会使得隐藏层增加。Bidirectional是控制是否开双向的最后输出会被叠加在out_put上,batch_first是为了方便输入数据的batch位于第一个维度。

LSTM

LSTM比RNN要复杂很多,同样的,通过模拟LSTM计算的过程,搞清楚pytorch的LSTM是怎么输出的。
首先先回忆一下LSTM的计算过程:
在这里插入图片描述
LSTM有三个门,分别是:输入门,输出门,遗忘门。每个门都需要对应一个权重。
除此之外对于输入也还需要做一个做一个变换,所以也需要一个参数。
对于Pytorch的LSTM来说,他还考虑上一次的输出,也就是说,Pytorch的LSTM计算时是这样的
在这里插入图片描述也可以看到,上一次的输出 h t h_t ht被接到了下一次输入中。那么我们针对于新增的 h t h_t ht也需要对应的参数。
那么Pytorch的LSTM一共有八个参数(除去bias)

观察参数:

首先,对于input_size = a, hidden_size=b的LSTM,针对输入数据的矩阵的形状应该是bxa的。针对上一次输出数据的形状应该是bxb的。
我们来看Pytorch的LSTM的参数

rnn = nn.LSTM(input_size = 3, hidden_size=5, bias=False)
print(rnn.all_weights[0][0].shape, rnn.all_weights[0][1].shape)
"""
torch.Size([20, 3]) torch.Size([20, 5])
"""

我们发现只有两组,其实这是八组。因为针对于输入数据,一共有4个5x3的数据。对于 h t h_t ht一共有4个5x5的数据。为了加快运算,Pytorch把这些数据concat到一起了。于是出现了两个20列的数据。

模拟LSTM运算

根据Pytorch官方给的计算公式和,LSTM的计算图解。我们来进行模拟
在这里插入图片描述
在这里插入图片描述
首先我们先拆分出来参数

wii = rnn.all_weights[0][0][:5, :]
wif = rnn.all_weights[0][0][5:10, :]
wig = rnn.all_weights[0][0][10:15, :]
wio = rnn.all_weights[0][0][15:20, :]

whi = rnn.all_weights[0][1][:5, :]
whf = rnn.all_weights[0][1][5:10, :]
whg = rnn.all_weights[0][1][10:15, :]
who = rnn.all_weights[0][1][15:20, :]

然后我们把LSTM的三个输入给构造出来

data = torch.randn(size=(2, 4, 3), dtype=torch.float32)
h = torch.zeros(size=(1, 4, 5)) # 隐藏层,也就是上一次的输出
c = torch.zeros(size=(1, 4, 5)) # 记忆单元

然后我们按照上面的公式进行计算,就会得到最终的结果

import torch
from torch import nn

data = torch.randn(size=(2, 4, 3), dtype=torch.float32)
rnn = nn.LSTM(input_size = 3, hidden_size=5, bias=False)

wii = rnn.all_weights[0][0][:5, :]
wif = rnn.all_weights[0][0][5:10, :]
wig = rnn.all_weights[0][0][10:15, :]
wio = rnn.all_weights[0][0][15:20, :]

whi = rnn.all_weights[0][1][:5, :]
whf = rnn.all_weights[0][1][5:10, :]
whg = rnn.all_weights[0][1][10:15, :]
who = rnn.all_weights[0][1][15:20, :]

h = torch.zeros(size=(1, 4, 5))
c = torch.zeros(size=(1, 4, 5))
up_out = []

tanh = nn.Tanh()
sigmoid = nn.Sigmoid()

for k in range(2):
    i = sigmoid(data[k].matmul(wii.T) + h.matmul(whi.T))
    f = sigmoid(data[k].matmul(wif.T) + h.matmul(whf.T))
    g = tanh(data[k].matmul(wig.T) + h.matmul(whg.T))
    o = sigmoid(data[k].matmul(wio.T) + h.matmul(who.T))
    
    c = c * f + i * g
    o = tanh(c) * o
    up_out.append(o) # 本次的输出加到output中
    h = o # 把本次的输出替换h
print(torch.cat(up_out, dim=0), (h, c))
print(rnn(data))

模拟完之后我们就搞懂了Pytorch的LSTM的输入和输出都是啥了:
输入:三个参数,data,隐藏层初始值,记忆单元初始值
输出:两个值,第二个值是一个元组。每一个时刻的输出,隐藏层输出(就是最后一个时刻的输出),记忆单元的值
其余的参数和RNN一致就不再说了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Linkage Mapper工进行物种分布建模的步骤详解(含实际案例分析)

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Linkage Mapper解密数字世界链接 文章目录 引言:一、介绍二、数据准备2.1 物种分布数据获取2.2 环境变量数据获取2.3 数据预处理

车道线检测

前言 目前,车道线检测技术已经相当成熟,主要应用在自动驾驶、智能交通等领域。下面列举一些当下最流行的车道线检测方法: 基于图像处理的车道线检测方法。该方法是通过图像处理技术从摄像头传回的图像中提取车道线信息的一种方法&#xff0c…

FreeRTOS(6)----软件定时器

一,软件定时器概述 软件定时器允许设置一段时间,当设定的时间到达之后就会执行指定的功能函数,被定时器调用的这个函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期。 二,回调函数的注意事项 回调函数是…

Django框架之模板过滤器

过滤器可以用来修改变量的显示样式。 使用方式 格式:{{变量|过滤器方法}}。可以连续使用,形式如:{{变量|过滤器方法1|过滤器方法2}}。 过滤器如下 Lower 转化为小写字母 格式:变量|lower Upper 转化为大写字母 格式&#xf…

chatgpt赋能python:Python的BeautifulSoup库和find_all()方法

Python的Beautiful Soup库和find_all()方法 在Web爬虫中,我们需要从网页中找到特定的HTML标记或属性,以便提取我们需要的数据。对于Python开发人员而言,Beautiful Soup是最流行的解析HTML和XML的库之一。该库可以让我们轻松地从HTML解析器中…

【Tcp通信服务器流程】

TCP通信流程 1、服务器端(被动接收连接的角色) (1)创建一个用于监听的套接字 - 监听:监听有客户端的连接 - 套接字:这个套接字其实就是一个文件描述符 (2)将这个监听文件描述符和…

26 KVM热迁移虚拟机

文章目录 26 KVM热迁移虚拟机26.1 总体介绍26.1.1 概述26.1.2 应用场景26.1.3 注意事项和约束限制 26.2 热迁移操作26.2.1 前提条件26.2.2 热迁移脏页率预测(可选)26.2.3 设置热迁移参数(可选)26.2.4 热迁移操作(共享存…

微服务之事务处理

Informal Essay By English Hi guys、happy labor day. Everyone should have a good time to relax during the Labor Day holiday. But don’t forget to improve yourself during the holiday period 参考书籍: “凤凰架构” “微服务架构设计模式” 引言 …

golang 服务中 context 超时处理的思考

文章目录 前言起因:日志告警引发的思考什么是contextcontext的作用context超时之后继续执行 or 中断 最后 前言 公司运行的服务代码中,随处可见各种各样的日志信息,其中大多数是用来记录各种异常的日志,一方面,当出现…

Linux终端环境下的浏览器Lynx和Carbonyl 的基本使用方法

一、Carbonyl 是基于Chromium开发的运行于终端下的现代版浏览器,比Lynx的功能更好,目前尚在滚动开发过程中,但也基本可以用了。 1. 2安装非常简单,下载Binaries,Docker,nmp install, 都可以。 注意&#…

FPGA远程更新/远程调试的一种简单方法

之前介绍过一种远程(无线)更新的方式,详见《起飞!通过无线WIFI下载调试FPGA》,这种方式缺点有两个:一是速度较慢;二是我们的设备中需要增加一个无线设备,增加成本的同时增加了暴露的…

SpringCloud(23):Sentinel对Spring Cloud Gateway的支持

代码地址:https://download.csdn.net/download/u013938578/87767363 从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流: route 维度:即在 Spring 配置文件中配置的路…

setContentHuggingPriority和setContentCompressionResistancePriority的使用

需求&#xff1a; 两个label并排显示&#xff0c;文字内容由服务器返回&#xff0c;label宽度以文字内容自适应&#xff0c;label之间间距大于等于10. 需要考虑以下情况&#xff1a; 当两个label的宽度和 < 屏幕宽度时&#xff0c;各自设置约束&#xff0c;无需处理&#…

GPT-4版Windows炸场,整个系统就是一个对话机器人,微软开建AI全宇宙

原创 智东西编辑部 智东西 Windows的GPT时刻到来&#xff0c;变革PC行业。 作者 | 智东西编辑部 今日凌晨&#xff0c;Windows迎来了GPT-4时刻&#xff01; 在2023微软Build大会上&#xff0c;微软总裁萨蒂亚纳德拉&#xff08;Satya Nadella&#xff09;宣布推出Windows Co…

【模型预测】A-4D战斗机姿态控制的模型预测控制方法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

力扣 695. 岛屿的最大面积

一、题目描述 给你一个大小为 m x n 的二进制矩阵 grid。 岛屿是由一些相邻的 1&#xff08;代表土地&#xff09;构成的组合&#xff0c;这里的相邻要求两个 1 必须在水平或者竖直的四个方向上相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&#xff09;包围着。…

[Nacos] Nacos Client获取所有服务和定时更新Client端的注册表 (三)

文章目录 1.Nacos Client获取所有服务1.1 Client如何获取所有服务1.2 Client获取服务方法getServices()详解 2.Nacos定时更新Client端的注册表2.1 Nacos和Eureka定时更新Client端的注册表的区别2.2 Client定时更新本地服务过程2.3 updateServiceNow方法解析2.4 定时更新本地注册…

40亿个QQ号,限制1G内存,如何去重?

40亿个QQ号&#xff0c;限制1G内存&#xff0c;如何去重&#xff1f; 40亿个unsigned int&#xff0c;如果直接用内存存储的话&#xff0c;需要&#xff1a; 4*4000000000 /1024/1024/1024 14.9G &#xff0c;考虑到其中有一些重复的话&#xff0c;那1G的空间也基本上是不够…

OPPO哲库事件 “ 始末 ” ! 集体打哑谜?

1►OPPO哲库解散 2019 年&#xff0c;美国商务部以“科技网络安全”为由&#xff0c;将华为公司及其70家附属公司列入出口管制“实体名单”。与此同时&#xff0c;OPPO 创始人兼 CEO陈明永对外宣布&#xff0c;公司将为未来三年内投入 500 亿元用于前沿技术和深水区技术的探索…

安装编译PostgreSql15.3.0

一、下载源码 方式一 官网手动下载 https://www.postgresql.org/download/. 解压 tar -zxvf postgresql-14.2.tar.gz方式二 git clone git clone https://github.com/postgres/postgres.git解压或下载后计入postgres目录 cd postgres-15.3二、创建目录 用root账户创建 创建…