pytorch之nn.Conv1d详解

之前学习pytorch用于文本分类的时候,用到了一维卷积,花了点时间了解其中的原理,看网上也没有详细解释的博客,所以就记录一下。

Conv1d
class torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

in_channels(int) – 输入信号的通道。在文本分类中,即为词向量的维度
out_channels(int) – 卷积产生的通道。有多少个out_channels,就需要多少个1维卷积
kerner_size(int or tuple) - 卷积核的尺寸,卷积核的大小为(k,),第二个维度是由in_channels来决定的,所以实际上卷积大小为kerner_size*in_channels
stride(int or tuple, optional) - 卷积步长
padding (int or tuple, optional)- 输入的每一条边补充0的层数
dilation(int or tuple, `optional``) – 卷积核元素之间的间距
groups(int, optional) – 从输入通道到输出通道的阻塞连接数
bias(bool, optional) - 如果bias=True,添加偏置
举个例子:

conv1 = nn.Conv1d(in_channels=256,out_channels=100,kernel_size=2)
input = torch.randn(32,35,256)
# batch_size x text_len x embedding_size -> batch_size x embedding_size x text_len
input = input.permute(0,2,1)
out = conv1(input)
print(out.size())

  

这里32为batch_size,35为句子最大长度,256为词向量

再输入一维卷积的时候,需要将32*25*256变换为32*256*35,因为一维卷积是在最后维度上扫的,最后out的大小即为:32*100*(35-2+1)=32*100*34

附上一张图,可以很直观的理解一维卷积是如何用的:

图中输入的词向量维度为5,输入大小为7*5,一维卷积和的大小为2、3、4,每个都有两个,总共6个特征。

对于k=4,见图中红色的大矩阵,卷积核大小为4*5,步长为1。这里是针对输入从上到下扫一遍,输出的向量大小为((7-4)/1+1)*1=4*1,最后经过一个卷积核大小为4的max_pooling,变成1个值。最后获得6个值,进行拼接,在经过一个全连接层,输出2个类别的概率。

附上一个代码来详解:

其中,embedding_size=256, feature_size=100, window_sizes=[3,4,5,6], max_text_len=35

class TextCNN(nn.Module):
def __init__(self, config):
super(TextCNN, self).__init__()
self.is_training = True
self.dropout_rate = config.dropout_rate
self.num_class = config.num_class
self.use_element = config.use_element
self.config = config self.embedding = nn.Embedding(num_embeddings=config.vocab_size,
embedding_dim=config.embedding_size)
self.convs = nn.ModuleList([
nn.Sequential(nn.Conv1d(in_channels=config.embedding_size,
out_channels=config.feature_size,
kernel_size=h),
# nn.BatchNorm1d(num_features=config.feature_size),
nn.ReLU(),
nn.MaxPool1d(kernel_size=config.max_text_len-h+1))
for h in config.window_sizes
])
self.fc = nn.Linear(in_features=config.feature_size*len(config.window_sizes),
out_features=config.num_class)
if os.path.exists(config.embedding_path) and config.is_training and config.is_pretrain:
print("Loading pretrain embedding...")
self.embedding.weight.data.copy_(torch.from_numpy(np.load(config.embedding_path))) def forward(self, x):
embed_x = self.embedding(x) #print('embed size 1',embed_x.size()) # 32*35*256
# batch_size x text_len x embedding_size -> batch_size x embedding_size x text_len
embed_x = embed_x.permute(0, 2, 1)
#print('embed size 2',embed_x.size()) # 32*256*35
out = [conv(embed_x) for conv in self.convs] #out[i]:batch_size x feature_size*1
#for o in out:
# print('o',o.size()) # 32*100*1
out = torch.cat(out, dim=1) # 对应第二个维度(行)拼接起来,比如说5*2*1,5*3*1的拼接变成5*5*1
#print(out.size(1)) # 32*400*1
out = out.view(-1, out.size(1))
#print(out.size()) # 32*400
if not self.use_element:
out = F.dropout(input=out, p=self.dropout_rate)
out = self.fc(out)
return out

  

embed_x一开始大小为32*35*256,32为batch_size。经过permute,变为32*256*35,输入到自定义的网络后,out中的每一个元素,大小为32*100*1,共有4个元素。在dim=1维度上进行拼接后,变为32*400*1,在经过view,变为32*400,最后通过400*num_class大小的全连接矩阵,变为32*2。

===================================================================================================================================

Pytorch中计算卷积方法的区别(conv2d的区别)

在二维矩阵间的运算:

class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

  

对由多个特征平面组成的输入信号进行2D的卷积操作。

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)

  

在由多个输入平面组成的输入图像上应用2D卷积,这个操作其实和上面的操作是一样的,只不过这个操作多用于计算一组卷积核对于输入的卷积结果,而上面的那条代码更多的则是用在定义网络中去。

======================================================================================================================

先来看二维卷积conv2d

conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", dilations=[1, 1, 1, 1], name=None)
"""Computes a 2-D convolution given 4-D `input` and `filter` tensors."""
给定4维的输入张量和滤波器张量来进行2维的卷积计算。

input:4维张量,形状:[batch, in_height, in_width, in_channels]

filter:滤波器(卷积核),4维张量,形状:[filter_height, filter_width, in_channels, out_channels]

strides:滤波器滑动窗口在input的每一维度上,每次要滑动的步长,是一个长度为4的一维张量。

padding:边界填充算法参数,有两个值:‘SAME’、‘VALID’。具体差别体现在卷积池化后,特征图的大小变化上面。卷积池化后特征矩阵的大小计算参见https://blog.csdn.net/qq_26552071/article/details/81171161

return:该函数返回一个张量,其类型与input输入张量相同。

再看一维卷积conv1d,python中的一维卷积最终还是通过二维卷积实现的,先将输入张量和滤波器的维度扩展,再调用二维卷积conv2d来实现。

def conv1d(value,filters, stride, padding, use_cudnn_on_gpu=None, data_format=None, name=None)
"""Computes a 1-D convolution given 3-D input and filter tensors."""
给定三维的输入张量和滤波器来进行1维卷积计算。

input:3维张量,形状shape和data_format有关:

(1)data_format = "NWC", shape = [batch, in_width, in_channels]

(2)data_format = "NCW", shape = [batch, in_channels, in_width]

filters:3维张量,shape = [filter_width, in_channels, out_channels],

stride:滤波器窗口移动的步长,为一个整数。

padding:与上文一致。

由conv1d源码可以看出,一维卷积的实现,是先对输入张量和filter扩展了一维,然后调用二维卷积进行运算的:

    value = array_ops.expand_dims(value, spatial_start_dim)  # 输入张量
filters = array_ops.expand_dims(filters, 0) # 滤波器
result = gen_nn_ops.conv2d(
value,
filters,
strides,
padding,
use_cudnn_on_gpu=use_cudnn_on_gpu,
data_format=data_format)
return array_ops.squeeze(result, [spatial_start_dim])

  

下面为conv1d完整源码:

def conv1d(value,
filters,
stride,
padding,
use_cudnn_on_gpu=None,
data_format=None,
name=None):
with ops.name_scope(name, "conv1d", [value, filters]) as name:
# Reshape the input tensor to [batch, 1, in_width, in_channels]
if data_format is None or data_format == "NHWC" or data_format == "NWC":
data_format = "NHWC"
spatial_start_dim = 1
strides = [1, 1, stride, 1]
elif data_format == "NCHW" or data_format == "NCW":
data_format = "NCHW"
spatial_start_dim = 2
strides = [1, 1, 1, stride]
else:
raise ValueError("data_format must be \"NWC\" or \"NCW\".")
value = array_ops.expand_dims(value, spatial_start_dim)
filters = array_ops.expand_dims(filters, 0)
result = gen_nn_ops.conv2d(
value,
filters,
strides,
padding,
use_cudnn_on_gpu=use_cudnn_on_gpu,
data_format=data_format)
return array_ops.squeeze(result, [spatial_start_dim])

  

==============================================

备忘

input     w*h

output   wo*ho

filter   F

Padding  P

stride    S

wo = (w - F + 2*P)/S +1

pytorch种, 一维Conv1d, 二维Conv2d的更多相关文章

  1. Java基本语法-----java数组(一维数组二维数组)

    嘿嘿!你们懂的,又是图片,委屈大家了. java数组(一维数组二维数组) [正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!下面有个"顶"字,你就 ...

  2. C语言malloc函数为一维,二维,三维数组分配空间

    c语言允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放,这些数据存储在堆区.可以根据需要,向系统申请 ...

  3. Java一维与二维数组的拷贝与排序

    Java一维与二维数组的拷贝与排序 目录 Java一维与二维数组的拷贝与排序 Arrays.sort() 一维数组升序排序 二维数组按行升序排序 二维数组按列升序排序 Java中的数组 Java中数组 ...

  4. 10-20C#基础---一维、二维数组&&冒泡排序

    一.一维数组 1.定义:是某一种数据类型的数据的组合,数组用来分组基本类型或相同类型的对象.数组中的实体叫做数组的元素或成员. 2. 格式:int[ ] shuzu=new int[ 6];存放int ...

  5. Java一维数组二维数组详解API

    所谓数组,是有序的元素序列. 若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量.用于区分数组的各个元素的数字编号称为下标 ...

  6. php获取一维,二维数组长度的方法(有实例)

    在php中获取数组长度方法很简单,php为我们提供了两个函数可以计算一维数组长度,如count,sizeof都可以直接统计数组长度哦,下面我们来看几个实例吧.php如何获取数组的长度,使用php函数c ...

  7. Java 一维数组 二维数组 三维数组

    二维数组包含一位数组  三维数组就是在二维数组的基础上,再加一层.把二维数组看做是一维数组就可以了,按照上述理解类推.   下面是 一维 二维 三维数组例子   一维数组: int[] array1 ...

  8. 两种PHP生成二维码的方法

    PHP生成二维码,个人认为最常用的有两种,1.使用google的api生成,2.使用PHP QR Code生成,两种方法生成的二维码都是很清淅的,效果不错.下面来分别说明这两种方法如何实现. 一.PH ...

  9. 4种方法生成二维码 (js 控制canvas 画出 二维码)

    随着网络的迅速发展 发展 发展,二维码的应用将会越来越多.同时很多只是很平凡的二维码,请拿起你的手 把这个二维码 设计起来吧.下面分享了几个非常好的二维码设计.  二维码原理: 二维条码/二维码可以分 ...

随机推荐

  1. python 内置方法expandtabs 把字符串格式化成列表输出

    #!/usr/bin/python3 # -*- coding: utf-8 -*- test = "username\tmail\tage\nzhangsen\tzhangsen@qq.c ...

  2. cocos环境配置 -cocos2dx 入门

    cocos最好的是安装官方exe,官方会把cocos 3.10和cocos studio都安装好. Cocos2d-x v3.10:点击http://www.cocos.com/,进入cocos官网, ...

  3. 从零开始一起学习SLAM | 不推公式,如何真正理解对极约束?

    自从小白向师兄学习了李群李代数和相机成像模型的基本原理后,感觉书上的内容没那么难了,公式推导也能推得动了,感觉进步神速,不过最近小白在学习对极几何,貌似又遇到了麻烦... 小白:师兄,对极几何这块你觉 ...

  4. 关于double精确度的简单问题

    (1)测试TestDouble.java结果 结果:如图,使用double类型的数据进行运算时结果是不准确的. 原因:double类型的数值占用64bit,即64个二进制数,除去最高位表示正负符号的位 ...

  5. PHP json_encode/json_decode与serialize/unserializ性能测

    PHP里面,有时候出于实际需求考虑,需要将某些信息以数组的方式进行存储,甚至有时候介于数组.字符串两者之间,很难确定是数组还是字符串,如果最终还需要将这些信息存储到文件系统中,而且要保证正确无误的存储 ...

  6. HTML-CSS线性渐变

    实现背景的渐变可以通过为背景添加颜色渐变的图片,也可以使用浏览器的功能来为背景添加渐变的颜色 在IE6或IE7浏览器下可以使用一下示例的CSS语句,设置filter属性来实现颜色 filter:pro ...

  7. 深入解析Java反射(1) - 基础

    深入解析Java反射(1) - 基础 最近正筹备Samsara框架的开发,而其中的IOC部分非常依靠反射,因此趁这个机会来总结一下关于Java反射的一些知识.本篇为基本篇,基于JDK 1.8. 一.回 ...

  8. Rpgmakermv(34) Mog_Event Sensor

    原文: =============================================================================+++ MOG - Event Sen ...

  9. Mysql常规优化

    一.SQL语句优化 (1)使用limit对查询结果的记录进行限定(2)避免select *,将需要查找的字段列出来(3)使用连接(join)来代替子查询(4)拆分大的delete或insert语句 二 ...

  10. Windows10上安装Keras 和 TensorFlow-GPU

    安装环境: Windows 10 64bit GPU: GeForce gt 720 Python: 3.5.3 CUDA: 8 首先下载Anaconda3的Win10 64bit版,安装Python ...