自己动手实现卷积操作(Pytorch)

本文详细介绍了如何在PyTorch中手动实现卷积操作,通过使用Unfold函数将输入数据展开,然后调整卷积核和展开数据的维度,最后利用einsum进行矩阵乘法和求和,完成卷积过程。实例展示了输入张量和卷积核的构造,以及卷积后的结果。对于理解卷积操作的内部工作原理非常有帮助。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考文章:https://blog.youkuaiyun.com/yutingzhaomeng/article/details/108883152
其中也有自己的一些理解。


某些时候可能需要用到类似卷积操作滑动窗的思想,实现一些操作。具体实现如下,首先导入必要的包

import torch
import numpy as np
import torch.nn as nn

方便起见(同时为了验证方法正确性),构建简单的卷积输入

input = torch.from_numpy(np.array([1,2,3,4,5,6,7,8,9])).view((1,1,3,3)).float()

查看输入内容

In [5]: input.shape                                                                                                                                                                                                                        
Out[5]: torch.Size([1, 1, 3, 3])
 
In [6]: input                                                                                                                                                                                                                              
Out[6]: 
tensor([[[[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]]])

其中,输入张量存储方式按照pytorch正常卷积操作,即B × \times ×C × \times ×K × \times ×K

手动构造卷积核

In [7]: kernel = torch.ones((1,2,2,1))                                                                                                                                                                                                     
 
In [8]: kernel                                                                                                                                                                                                                             
Out[8]: 
tensor([[[[1.],
          [1.]],
         [[1.],
          [1.]]]])

卷积核尺寸为Cin × \times ×K × \times ×K × \times ×Cout。

接下来是手动实现卷积的核心,利用Unfold函数,Unfold可以将输入数据按照卷积时候的滑动窗cube方式展开

unfold = nn.Unfold(kernel_size=2) 

对输入进行操作

unin = unfold(input) 

查看Unfold之后的尺寸

In [14]: unin.shape                                                                                                                                                                                                                        
Out[14]: torch.Size([1, 4, 4])

其各个轴分别为B × \times ×(K × \times ×K) × \times ×N,其中N是滑动窗的数量。这里可以这样理解:unfold的结果是(K × \times ×K) × \times ×N的输出,其中K × \times ×K就是我们所设定的卷积核的尺寸,N可以理解为最终卷积结果的长和宽的乘积,这个很容易相通,滑动几次相应的就会输出几个值,一个 10 × 10 10 \times 10 10×10大小的输出,必然是经过100次滑动卷积的结果。
如果还是不够明白的话,可以看这篇文章,挺清楚的

为了实现卷积,需要对Unfold之后的数据重新调整维度,如下

In [21]: unin = unin.view((1,1,-1,2,2))                                                                                                                                                                                                    
 
In [22]: unin.shape                                                                                                                                                                                                                        
Out[22]: torch.Size([1, 1, 4, 2, 2])
 

其中,unin的尺寸为B × \times ×C × \times ×(K × \times ×K) × \times ×H’ × \times ×W’

对卷积核重新调整维度

In [24]: kernel = kernel.view((1,-1,1))                                                                                                                                                                                                    
 
In [25]: kernel.shape                                                                                                                                                                                                                      
Out[25]: torch.Size([1, 4, 1])

其中kernel的维度为Cin × \times × (K × \times ×K) × \times × Cout

维度调整好后,实现卷积的乘积求和操作,采用einsum求和方式,具体的原理可以参考这篇文章

In [26]: out = torch.einsum('ijkmn,jkl->ilmn',unin,kernel)                                                                                                                                                                                 
 
In [27]: out.shape                                                                                                                                                                                                                         
Out[27]: torch.Size([1, 1, 2, 2])

查看输入数据及卷积后的结果

In [29]: input                                                                                                                                                                                                                             
Out[29]: 
tensor([[[[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]]])
 
In [28]: out                                                                                                                                                                                                                               
Out[28]: 
tensor([[[[12., 16.],
          [24., 28.]]]])
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值