以前在语音合成项目第一次接触PyTorch中的Conv1d函数时,作为一个初学者,我对它的参数和工作机制感到很困惑。
原本以为既然是1维卷积,那输入输出应该都是简单的1维张量。然而实际上,输入必须是一个3维张量,这让我颇感意外。
后来因为工作缘故,我有一段时间没接触深度学习了。后来再次遇到Conv1d函数时,我又陷入了同样的困惑。
因此,我决定写下自己的理解过程,帮助可能遇到类似情况的读者(包括未来的我自己)。
本文使用的工具版本是Python 3.13.3,PyTorch 2.7.1。
Python的版本号可用python -V命令确认。PyTorch的版本号可用pip show torch命令确认。- > pip show torch
- Name: torch
- Version: 2.7.1
- ...
复制代码 或者也可以像下面这样进入Python交互式控制台确认。- > python
- Python 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)] on win32
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import torch
- >>> torch.__version__
- '2.7.1+cpu'
复制代码 理解Conv1d输入输出形状的关键在于,我们必须考虑深度学习中的批次(batch)和通道(channel)概念。
下面通过在Python交互式控制台里一步步执行代码来理解这一点。
第一步:创建Conv1d实例
使用Conv1d首先需要创建一个实例。实例化时需要指定三个主要参数:
- in_channels:输入通道数。例如,1表示单声道音频,2表示立体声音频。
- out_channels:卷积后的输出通道数,代表卷积滤波器的数量。
- kernel_size:卷积滤波器的大小。
创建一个具有2个输入通道、3个输出通道和滤波器大小为5的Conv1d实例:- >>> from torch import nn
- >>> conv1d = nn.Conv1d(2, 3, 5)
复制代码 第二步:查看权重和偏置
创建实例时,卷积操作使用的权重(weight)和偏置(bias)会自动初始化。
在机器学习过程中,这些值会在训练过程中被逐步优化。- >>> conv1d.weight.shape
- torch.Size([3, 2, 5])
- >>> conv1d.weight
- Parameter containing:
- tensor([[[ 0.2076, 0.1669, -0.0984, 0.0040, -0.0094],
- [-0.0277, -0.0257, -0.3107, 0.2883, 0.2560]],
- [[ 0.0501, -0.2257, 0.0464, -0.0605, 0.1463],
- [-0.1195, 0.1820, 0.0764, 0.2922, -0.2718]],
- [[ 0.2699, -0.2734, 0.1698, 0.2720, -0.2554],
- [-0.0706, -0.2028, -0.2554, -0.1495, 0.2460]]], requires_grad=True)
- >>> conv1d.bias
- Parameter containing:
- tensor([-0.1664, -0.0393, 0.2074], requires_grad=True)
复制代码
- conv1d.weight表示每个滤波器的权重,形状为(输出通道数, 输入通道数, 滤波器大小)
- conv1d.bias表示每个滤波器的偏置,形状为(输出通道数)
第三步:准备输入数据
Conv1d的输入数据必须是3维张量:
- 第1维:批次大小(batch_size),表示一次处理的数据样本数量
- 第2维:输入通道数,必须与创建Conv1d实例时指定的in_channels一致
- 第3维:单个数据样本的长度。对于音频数据,通常是帧数
- >>> x = torch.rand(4, 2, 6) # 随机数据:批次大小4,2个输入通道,长度6
- >>> x
- tensor([[[0.5487, 0.5584, 0.7142, 0.6534, 0.2741, 0.9281],
- [0.8480, 0.2020, 0.3171, 0.4146, 0.8032, 0.4344]],
- [[0.6481, 0.6134, 0.9704, 0.5787, 0.1803, 0.1568],
- [0.6690, 0.8022, 0.2466, 0.2352, 0.2962, 0.2569]],
- [[0.7968, 0.8019, 0.4341, 0.4369, 0.5804, 0.2109],
- [0.8624, 0.1870, 0.9518, 0.7393, 0.3436, 0.4962]],
- [[0.5005, 0.9210, 0.0010, 0.9487, 0.0381, 0.5954],
- [0.5601, 0.9394, 0.3438, 0.5394, 0.6369, 0.4937]]])
复制代码 第四步:执行卷积操作
将输入数据x传递给conv1d并查看结果:- >>> y = conv1d(x)
- >>> y.shape
- torch.Size([4, 3, 2])
- >>> y
- tensor([[[ 0.1683, 0.1969],
- [-0.2416, 0.1589],
- [ 0.3856, -0.0863]],
- [[ 0.0034, 0.1147],
- [-0.0358, -0.2050],
- [ 0.2556, 0.0671]],
- [[ 0.0630, -0.0035],
- [ 0.0246, 0.0918],
- [-0.1203, 0.1590]],
- [[ 0.2665, 0.0337],
- [-0.1590, 0.1789],
- [ 0.0974, 0.2275]]], grad_fn=<ConvolutionBackward0>)
复制代码 输出y是一个3维张量,形状为(批次大小, 输出通道数, 输出长度)。
第五步:理解计算过程
卷积操作遵循以下原则:
- 滤波器在输入数据上滑动
- 计算元素乘积的和
- 加上偏置
每个输出元素的计算公式为:- y[批次索引, 输出通道索引, 数据位置] =
- sum(x[批次索引, 输入通道0, (数据位置):(数据位置+滤波器大小)] @ conv1d.weight[输出通道索引, 输入通道0]) +
- sum(x[批次索引, 输入通道1, (数据位置):(数据位置+滤波器大小)] @ conv1d.weight[输出通道索引, 输入通道1]) +
- ... +
- conv1d.bias[输出通道索引]
复制代码 其中@表示点积操作,A @ B等同于A.dot(B)。
输出长度可以通过以下公式计算:- 输出长度 = (输入长度 - 滤波器大小 + 1)
复制代码 例如,我们可以验证y[0,0,0]的计算:- >>> y[0,0,0] # 第0个数据样本,第0个输出通道,第0个输出数据位置
- tensor(0.1683, grad_fn=<SelectBackward0>)
- >>> x[0,0,0:5] @ conv1d.weight[0,0] + x[0,1,0:5] @ conv1d.weight[0,1] + conv1d.bias[0]
- tensor(0.1683, grad_fn=)
复制代码 同样,我们可以计算y[0, 0, 1]:- >>> y[0,0,1] # 第0个数据样本,第0个输出通道,第1个输出数据位置
- tensor(0.1969, grad_fn=<SelectBackward0>)
- >>> x[0,0,1:6] @ conv1d.weight[0,0] + x[0,1,1:6] @ conv1d.weight[0,1] + conv1d.bias[0]
- tensor(0.1969, grad_fn=)
复制代码 如上所示,Conv1d通过对输入数据x进行卷积操作生成新的特征量y。
特征量y可用于音频识别、自然语言处理等各种1维(单通道或多通道)数据的处理任务。
总结
- 输入必须是3维张量:(批次大小, 输入通道数, 数据长度)
- 输出也是3维张量:(批次大小, 输出通道数, 输出长度)
- 输出长度由公式输入长度 - 滤波器大小 + 1决定
- 每个输出元素是输入数据与滤波器权重的点积加上偏置
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |