2026/7/21 19:10:52

pytorch的基础函数和常用CNN

pytorch的基础函数和常用CNN 1.PyTorch 提供的 “基本积木”PyTorch 的 torch.nn 和 torch.nn.functional 里提供的基本模块大体分几类层Layers线性层nn.Linear全连接 也称为dense是最简单的神经网络神经节点就是说的全连接层的输出单元在卷积层神经节点不是一个术语。nn.Linear(128, 10) 有十个神经元每个神经元有128个weight一个bias有10个输出。在tourch中Linear( in_features: int, out_features)因为在nn.Flatten()后需要全连接层因此需要计算目前总共有多少个特征图。在tourch中nn.MaxPool2d()和nn.Conv2d()他们默认都不填充paddingConv2d的stride默认为(1,1)MaxPool2d的stride默认为池化核的尺寸大小(tensorflow的stride和padding默认也都是如此)。卷积层nn.Conv1dnn.Conv2dnn.Conv3d 卷积层不是每个时间步都能跟新响应以及 nn.ConvTranspose*反卷积/上采样conv1 nn.Conv1d(in_channels1, out_channels16, kernel_size5, stride2)in_channels4输入 4 个特征RTT、丢包率、缓存大小、拥塞窗口。out_channels32有 32 个卷积核每个核生成一个特征图。kernel_size3每个核覆盖 3 个时间步。stride感受野每次滑动两个时间步。stride默认是1。卷积是滑动窗口机制。每次输入的时间步个数需要等于感受野然后向前stride步伐滑动。这一层神经网络的感受野 (kernel_size - 1) * dilation 1。感受野代表着能捕获多少个时间步内的变化。conv nn.Conv2d(in_channels3, out_channels5, kernel_size4)输入3个通道比如RGB5个卷积核输出5个通道每个卷积核是(3 , 4 , 4)的三维张量其中3是因为有三个通道每个卷积核同时看到三个通道同时在RGB上滚动每次卷积都会有一个输出这相当于神经元的一次操作输出卷积核滑动一遍做了N次卷积就相当于运行完一层神经网络这层神经网络中weight和bias。因此5个卷积核相当于5层神经网络。每个卷积核如何处理RGB他在RGB三个相同的位置做卷积把三个和加在一起放入输出的特征图对应的位置这样三个输入做完卷积就输出一个特征图。有多少个卷积核代表多少个特征图输出。(以上是简化的说法三个RGB通道其实对应的是一个三维卷积核然后分别对RGB卷积后相加因此一个卷积层的参数量为输入通道数x输出通道数x卷积核心宽x高)卷积和池化的输出尺寸计算公式output_size(W−K2P)/S1W输入尺寸K卷积核大小kernel_sizePpaddingSstride循环层nn.RNN, nn.LSTM, nn.GRU循环层的核心思想是当前时刻的输出不仅取决于当前输入还依赖于之前时刻的隐藏状态。因此它可以用于NLP这类语言模型因为词前后有关也可以用于股票/rtt有时间前后关系。循环层是用来处理序列的循环神经网络层模块。RNN(100–200ms 粒度) LSTM观察过去 2–5s。GRU 100ms-1s算力消耗也在它俩之间。 天生逐点更新每个时间步都能立刻响应。正则化/归一化nn.BatchNorm1d/2d/3dnn.LayerNormnn.GroupNormnn.InstanceNorm*池化作用减少特征图大小降低计算连防止过拟合。平均值池化卷积核内的平均值作为输出。最大值池化卷积核内最大值作为输出。池化一般在卷积后紧接着使用因此它和卷积可以看作一个步骤吃化之后改变输入的特征图尺寸不会改变个数。nn.MaxPool*, nn.AvgPool*, nn.AdaptiveAvgPool*, nn.AdaptiveMaxPool*Dropoutnn.Dropout, nn.Dropout2d激活函数nn.ReLU, nn.Sigmoid, nn.Tanh, nn.Softmax, nn.LeakyReLU, nn.ELU …对于负值很容易使得梯度爆炸训练慢等原因因此ReLU是简单粗暴又好用方法因此它目前是主力。但负值的信息也是有点价值的虽然不多。因此才有了LeakyReLU和PReLU。LeakyReLU给负区间一个小斜率。PReLU在负区间的斜率可学习。nn.Softmax的范围为[0, 1]且要求各个元素之间之和为1,它适合分类任务。nn.Tanh输出范围为[-1, 1]它不要求各个元素之间的和为1。还有 functional 版本F.relu(x)F.softmax(x, dim1)。sofrmax用于分类的最后输出它把数据压缩到01且相加为1。当其中一个数接近1时那么在损失函数中梯度接近0, 说明梯度消失也说明已经训练到位了。F.softmax(output_t / args.T, dim1)其中dim为1代表所有概率相加为1。log_softmax(x) log(softmax(x))Sigmoid预处理函数ToTensortransforms.ToTensor() 会自动把像素除以 255Normalize()它让数据均值为1,方差为0。这是神经网络喜欢的数据范围。开源数据集合一般都有自己的范围比如ImageNetT.Normalize(mean[0.485, 0.456, 0.406],std[0.229, 0.224, 0.225])工具类/容器nn.Sequential按顺序堆积层nn.ModuleListnn.ModuleDict管理一组子模块nn.Parameter定义可训练参数这些就是“乐高积木”你可以随便拼。例如blocknn.Sequential(nn.Conv2d(3,64,3,padding1),#卷积层nn.BatchNorm2d(64),#批归一化nn.ReLU(inplaceTrue)#激活函数)这就是一个最常见的“小 CNN 块”。数据集ImageNet李飞飞团队用于图像分类Pascal VOCMarkus团队发起用于目标识别COCO微软发起目标识别比VOC大的多。2.损失函数与优化器nn.MSELoss() //交叉熵损失函数用来预测回归任务比如房价温度速度等连续数值。因为如果对错误的预测非常自信那么loss最大也为1。nn.CrossEntropyLoss() //均方差损失函数预测分类任务因为如果对错误的预测非常自信那么loss会大到爆炸极大惩罚。criterion(output, label.long())它要求label必须为tensor的long类型。F.cross_entropy() nn.CrossEntropyLoss().forward()两者完全一样。你能互换使用。区别只是nn.CrossEntropyLoss() 是一个类F.cross_entropy 是 functional APISGD一般和momentum一起使用增加惯性。收敛满但泛化好。Adam自带惯性收敛快泛化不如SGD。AdamW兼容了SDG和Adam是目前主流的方案几乎所有新模型Transformer、ResNet50、YOLOv8都在用它。Adam 是“聪明但心浮气躁”的学生学得快但容易粗心SGD 是“笨但稳”的学生学得慢但最后考试成绩好AdamW 是“聪明又自律”的学生既学得快也学得稳。optimizer_ft optim.SGD(model.parameters(), lr0.1, momentum0.9)这个是学习率调度器对Adam / AdamW / SDG等所有优化器都适用。scheduler lr_scheduler.StepLR(optimizer, step_size100, gamma0.1)常见调度器StepLR每隔一定步数让学习率 × γExponentialLR指数衰减CosineAnnealingLR余弦退火更平滑ReduceLROnPlateauloss 不再下降时自动降学习率也可以自定义损失因为在一个网络中分为很多卷积和全连接层每个单独的部分都可以使用单独的学习率比如我们迁移学习预训练的ResNet然后加上全连接层实现自己的业务ResNet部分以小的学习率微调全连接成以大的学习率学习。classSimpleNet(nn.Module):def__init__(self):super().__init__()self.backbonenn.Sequential(nn.Linear(100,50),nn.ReLU(),)self.headnn.Linear(50,10)defforward(self,x):xself.backbone(x)xself.head(x)returnx #第一种方式 optimizeroptim.SGD([{params:model.backbone.parameters(),lr:1e-4,name:backbone},{params:model.head.parameters(),lr:1e-2,name:head},],momentum0.9)#第二种方式ifepoch in[int(epochs*0.5),int(epochs*0.75)]:print(f\n Epoch {epoch}: 手动学习率衰减)forgroup in optimizer.param_groups:namegroup[name]ifnamebackbone:#这里的名字是第一种方法定义的 group[lr]*0.1# backbone 衰减10%elif namehead:group[lr]*0.2# head 衰减20%ifepoch in[args.epochs*0.5,args.epochs*0.75]:##学习率变更50%75%的2次epoch学习率乘以0.1param_groups包括[{params,lr,momentum,dampening,weight_decay,nesterov},{……}]forparam_group in optimizer.param_groups:param_group[lr]*0.1特别函数nn.Flatten()view(-1 , 48 * 5 * 5) #(batch_size, 总的通道数 X 特征图W X H) -1代表自动推导 这个等同于Flatten()一般用Flatten()创建张量函数labeltorch.ones(b_size,devicedevice)*real_label #之所以是 它等价于#PyTorch 的张量 shape 必须是 tuple 类型所以是(b_size,)(b_size)是个int类型的b_size(b_size,)是tuple其中包含一个元素b_sizelabeltorch.full((b_size,),real_label,devicedevice)#这种写法更推荐 内部是 C 实现效率高 #创建一个两维度张量3x4都用0.9填充 labeltorch.full((3,4),0.9)torch.randn(4,3,1,1,devicedevice)#生成一个[4,3,1,1]的张量shape的类型是 torch.Size而 torch.Size是tuple的子类x.view()与nn.Flatten()x.view(a, b, c, …) 的参数就是 新的张量形状它是在做reshape操作比如x.view(A, B)就是把x变成[A, B]两个维度。x.view(A)就是把参数变为一个维度其中有A个元素。不过怎么变总的元素数不变因此其中可以有一个维度的位置写-1让它自己来推导这个位置的参数是多少。如x.view(A, -1)。nn.Flatten(start_dim1, end_dim-1) 它是从start_dim维度开始到end_dim都展平。-1是最后一个维度。例如[B, C, H, W]B是第0维度因此Flatten默认保留Batch_size展平后面所有的因此它一般是在分类中使用。CxHxW就是每个特征图进行像素级展平了。其中C只是通道数C和H W一起才叫一个特征图比如一张有宽高的RGB图像特征图的概念就是就是特别的图片而以。val_images是一个list里面的元素是[C, H, W]有6个。val_images torch.stack(val_images) 执行完后得到的val_images是一个tensor它是[6, C, H, W]。val_images torch.chunk(val_images, val_images.size(0) // 2) 它是把[6, C, H, W]分成2个batch块得到的val_images是一个tuple每个元素是tensor为[6/2, H, W]utils.make_grid(image, nrow3, padding5) 其中image是张量为[N, C, H, W]把N张图片分为3列放在一个画不上。torch.save(netG.state_dict(), ‘epochs/netG_epoch_%d_%d.pth’ % (UPSCALE_FACTOR, epoch)) 保存3.torchvision.models提供常用CNN它提供封装好的CNN块常见常见网络的现成实现“现成的玩具”包括LeNet由杨立昆编写用于手写字识别较简单。平均值池化使用MNIST。LeNet是2个卷积3个全连接层。ALexNet辛顿和它的学生ALex。首次使用以下技术数据增强Dropout最大值池化使用ImageNet数据集使用多GPU并行训练。5个卷积3个全连接层。VGG牛津大学VGG团队比ALeNet更多的卷积层使用连续多个3x3卷积代替ALexNet中的大卷积核并有与大卷积相同的感受野同时参数大幅减少。ResNet18, 34, 50, 101, 152何恺明它最大的作用是解决了深层网络的梯度消失与爆炸问题它的这种残差方法可以使得神经网路达上百层千层。VGGDenseNetMobileNetEfficientNetViT 等等示例from torchvision.modelsimportresnet18modelresnet18(pretrainedTrue)# 直接拿来用一个标准的CNN一般是每次处理完卷积后进行池化多次这样操作后最后进行全连接。因此也把卷积和池化看作一个步骤。差别在于torch.nn 提供的是 最小算子基础积木torchvision.models 提供的是 常用组合成品积木块/整车所以ResNet 的 BasicBlock 确实是 CNN 块但它不是 PyTorch 核心必须的一部分而是放在 torchvision 里方便用户快速复现。里nn.PixelShuffle(up_scale) 将图片的宽高都 将通道维度的信息重新排列到空间维度上从而实现上采样。3.自注意力机制自注意力机制与注意力机制最大的区别就是自注意力机制还关注每个token与其他token的关系。它的用途一般来说CNN用于计算机视觉FC(全连接)用于分类transformer用于自然语言翻译等。它解决了LSTM/RNN的两大问题难以长记忆无法并行计算。它的结构中有多个Encoder和多个DecoderEncoder之间串行处理最后一个Encoder把输出发送个每个decoder同时decoder也串行处理。这样每个decoder就有两个输入一个是上个decoder的输出一个是最后一个Encoder的输出。其中Encoder中分为Feed Forward和Multi-Head Attention。Decoder只有Feed Forward模块。自注意力机制为什么需要位置编码像RNN是串行处理每个token因此输出的结果也是串行的。但transformer是并行处理每个token但我们需要把结果顺序串起来因此需要有位置编码才能把结果按顺序连起来。Query告诉注意力机制我对哪项感兴趣Key指名有哪些项位置编码后。Value这些项对应的值。一个注意力也称一个注意力头一个注意力头中包含WqWkWq把输入与每个多注意力头相乘得到一个个Z把每个Z连起来成为向量再与Wo相乘得到最终的Z。Z这就是输出。其中Wo和每个注意力头中的Wq, Wk, Wv都是训练时需要调整的参数也就是改动他们就是学习的目的。transform的残差网络与CNN的相同 自注意力机制输出的与输入自注意力机制的源相加再输入下去。解码器使用掩码自注意力交叉注意力(也称基本注意力)编码器使用自注意力。这三种注意力都可以同时多次使用叫做多头。多个头就多个角度比如有的头关注语法有的头关注单词等等。交叉注意力每个token输入的时候i会关注输出。自注意力每个token会关注其他token。掩码自注意力因为自注意力能关注前后加上掩码后使得它只能关注前面的后面的无法关注因为我们要做的就是预测后一个值所以不能让它看到。补充超分原理用清晰的图片降低采样然后输入把原图作为标签。训练好了后它就会学会如何补偿图片。风格迁移原理用分类的监督问题来训练CNN得到比如VGG19他们已经习得如何抓去图片的笔触颜色纹理。然后输入一张图片处理结果与待使用的风格对比如果内容损失和纹理就继续减少梯度训练输入的图片直到得到合适的图片它训练的是图片hh。这两个的CNN块也在torch.nn里因为它们通用性太强就放入核心库里了。nn.Transformer完整的 Encoder-Decoder 架构nn.TransformerEncoder, nn.TransformerDecoder子结构transformer用小型 Transformer 或 局部注意力 (local attention)只看最近 0.5–1s 的 RTT/丢包变化。优点Transformer 的自注意力机制能捕捉 RTT 增加与丢包率上升的联合模式优于 CNN 的局部感受野。TCN 是什么它是用来替代RNN的序列CNN是时间卷积网络基于 Conv1d 和扩张卷积专为时间序列设计。它和transformer一样是通用的但是pytorch没有它的成品实现它是一个思维需要自己搭建。在时间上TCN观察几十到几百毫秒时间趋势