Pytorch中torch.nn.Conv3D、torch.nn.Conv2D函数详解


原文链接: Pytorch中torch.nn.Conv3D、torch.nn.Conv2D函数详解

PyTorch中的nn.Conv1d与nn.Conv2d - 简书
pytorch1.0中nn.Conv1d详解 - 简书

import torch
import torch.nn as nn
import numpy as np
from torch.autograd import Variable
 
x = torch.Tensor([1,10,100,1000,10000,100000]).view(1,2,-1,1,1)
# view()函数用来reshape,-1参数 意为自动设置,此处计算得6
# Conv2d的规定输入数据格式为(batch, channel, Height, Width)
# Conv3d的规定输入数据格式为(batch, channel, Depth, Height, Width)
x = Variable(x)
 
conv = nn.Conv3d(in_channels=2,
                 out_channels=6,
                 kernel_size=(2,1,1),
                 stride=1,
                 padding=0,
                 dilation=1,
                 groups=1,
                 bias=False)
 
# 参数group的作用为:将输入数据按通道顺序分组, 每组有in_channel/group个通道.(例:group为2时,输入数据前一半通道为一组)
# 	同时, 每组对应的kernel个数, 从原来的out_channel变为outchannel/group.
			# 此处的kernel为三维及以上结构,而filter特指二维层状的过滤器。
# 	原来的情况中, 每个生成的特征图都有所有通道的贡献.
# 	而现在, 特征图仅由其所在group对应的通道卷积构成. 
# 简而言之, group参数的目的就是将原本的大卷积分成多个并联(side by side)的小卷积
# 另: 在in_channel不变的情况下, 当group>1时, kernel总数不变, 而filter总数缩小group倍.
		# 而在filter、kernel总数不变的情况下, group增大, 需要的in_channel按同样比例增大.
 
# 参数dilation的作用为: 控制卷积核元素的间隔大小.具体可搜索“空洞卷积”
 
 
print(conv.weight.data.size())
## 	conv.weight.data.size()的返回值:
#		# (num_kernels, num_filters_perkernel, (Depth,) Height, Width)
# 		#	i.e.:(out_channels, in_channels/group, kernel_size)
 
# 影响权重数目的因素有:
	# 欲输出featurecube的个数,直接影响卷积核的个数(相等) 
	# 输入的通道数与设定的该层group数, 多通道卷积会导致与某输出值相关的卷积核成倍增加
	# 每个卷积核的尺寸
 
# ————————————————————————
conv.weight.data=torch.from_numpy(np.ones(24,dtype=np.float32).reshape(6,2,2,1,1))
	# 替换权重值便于观察输出
print(conv.weight.data)
 
 
output=conv(x)
print('output=',output.data)
print('outputsize=',output.data.size())
# output.data.size()的返回值:
# 	(batch, out_channels/ or num_of_featurecube, size_of_featurecube)

————————————————
版权声明:本文为CSDN博主「rotk2015」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/rotk2015/article/details/87820036

原文地址 https://www.jianshu.com/p/23977c24a71c

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

Conv1d 一维卷积

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

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

textcnn

图中输入的词向量维度为 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。

`