Transformer和Conv2d卷积运算随手记

11.Transformer原理

11.1概述

基础神经网络:CNN、RNN、

seq2seq模型(encoder+attention+decoder)的基础模块,可以用CNN、RNN、Transformer等进行做

CNN权重共享体现在滑动窗口上,正着计算和反着计算是相同的

多层卷积进行长程建模,对相对位置敏感,对绝对位置不敏感

RNN循环神经网络,当前时刻的输出依赖于上一时刻的运算,对位置和顺序非常的敏感,运算也非常的耗时。

对于相对位置敏感,对于绝对位置也敏感

transformer没有序假设,序列建模问题相当于是这样。

任意两字符之间都可以建模,需要依靠自注意力机制,计算复杂度非常大

encoder是由n层构成的

input word embedding 由稀疏的one_hot进入一个不带bias的FFN得到一个稠密的连续向量

position encoding每个位置上面的都是确定的,通过残差链接将位置信息流入深层

mult-head self-attention多头自注意力机制,是模型捕捉到更多的位置与位置之间的联系。

feed-forward network

enbedding每一个维度的融合。

Decoder

class Transformer(MOdule):
    transformer_model = nn.Transformer(nhead=16,num_encoder_layers=12)
    src = torch.rand((10,32,512))
    tgt = torch.rand((20,32,512))
    out = transformer_model(src,tgt)
    def __init__():
        

TransformerDecoder 实现encoder,把解码层给串起来,

TransformerEncoderLayer 编码层

TransformerEencoder 把编码层给串起来

TransformerDecoderLayer

softmax出来每一个位置上的概率。

11.2Encoder

import torch
import numpy
import torch.nn as nn
import torch.nn.functional as F
​
##关于word emdding 以序列建模为例
##考虑source sentence 和 target sentence
##构建序列、序列字符以索引形式
​
batch_size=2
#单词表大小
max_num_src_words=8
max_num_tgt_words=8
​
​
model_dim=8
​
max_src_seq_len_words=5
max_src_tgt_len_words=5
#src_len=torch.randint(2,5,(batch_size,))
#tgt_len=torch.randint(2,5,(batch_size,))
##最大序列长度
src_len=torch.Tensor([2,4]).to(torch.int32)
tgt_len=torch.Tensor([4,3]).to(torch.int32)
​
##单词索引构成源句子和目标句子,并且做了padding,默认值为0
src_seq=torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max_src_seq_len_words-L)),0) for L in src_len ])
tgt_seq=torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max_tgt_seq_len_words-L)),0) for L in tgt_len ])
​
##构造embedding
src_embedding_table=nn.Embedding(max_num_src_words+1,model_dim)  ##model_dim 模型特征大小
tgt_embedding_table=nn.Embedding(max_num_tgt_words+1,model_dim)
​
​

11.3Decoder

12.Pytorch nn.Conv2d卷积网络

Conv2d可以自己创建参数

torch.nn.functional.conv2d,手动传入weight,api

通常将一个向量作为全连接网络的输入。

更复杂的如卷积更复杂。

卷积的滑动窗口原理,stride=1滑动步长为1

如果是channel=2则有两个kernel 将输出的两个结果点对点相乘

如果有多个输出通道,将不同的kernel得到的输出分别多通道输出

二维卷积演示:

import torch
import torch.nn as nn
import torch.nn.functional as F
​
in_channels =1
out_channels = 1
kernerl_size =3
batch_size=1  ##样本数量
bias=False
​
input_size=[batch_size,in_channels,4,4]   ##通道数、长度、宽度
conv_layer = torch.nn.Conv2d(in_channels,out_channels ,kernerl_size,bias=bias)
input_feature_map = torch.randn(input_size)    ##产生input
output_feature_map=conv_layer(input_feature_map)  ##
​
print(input_feature_map)
print(conv_layer.weight)  ##相当于权重,kernel    1*1*1*3=out_channels*in_channels*height*width
print(output_feature_map)
​
##函数形式的卷积
output_feature_map1=F.conv2d(input_feature_map,conv_layer.weight)
​
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
​
in_channels =1
out_channels = 1
kernerl_size =3
batch_size=1  ##样本数量
bias=torch.randn(1)  ##默认通道数1
​
input_size=[batch_size,in_channels,4,4]   ##通道数、长度、宽度
conv_layer = torch.nn.Conv2d(in_channels,out_channels ,kernerl_size,bias=bias)
input_feature_map = torch.randn(input_size)    ##产生input
output_feature_map=conv_layer(input_feature_map)  ##
​
print(input_feature_map)
print(conv_layer.weight)  ##相当于权重,kernel    1*1*1*3=out_channels*in_channels*height*width
print(output_feature_map)
​
##函数形式的卷积
output_feature_map1=F.conv2d(input_feature_map,conv_layer.weight)
​
input = torch.radn(5,5)
kernel=torch.randn(3,3)
input=input_feature_map     ##卷积输入特征图
kernel = conv_layer.weight.data  ##卷积核
##1.原始矩阵运算实现二维卷积
def matix_multiplation_for_conv2d(input,kernel,bias=0,stride=1,padding=0):
    if padding>0:
        input=F.pad(input,(padding,padding,padding,padding))
    input_h,input_w=input.shape
    kernel_h,kernel_w=kernel.shape
    
    ##卷积输出的宽度和高度
    output_h=(math.floor(input_h-kernel_h)/stride+1)
    output_w=(math.floor(input_w-kernel_w)/stride+1)
​
    output = torch.zeros(output_h,output_w)
    for i in range(0,input_h-kernel+1,stride):  ##对高度维度便利
        for j in range(0,input_w-kernel_w+1,stride):  ##对宽度维度便利
            region=input(i:i+kernel_h,j:j+kernel_w)   ##取出被核滑动到的区域
            output[int(i/stride),int(j/stride)]torch.sum(region*kernel)+bias
    return ouptput
​
mat_mul_conv_output=matix_multiplation_for_conv2d(input,kernel,padding=1)
print(mat_mul_conv_output)
​
pytorch_mul_conv_output=F.conv2d(input.reshape((1,1,input.shape[0])),kernel.reshape((1,1,kernel.shape[0],kernel.shape[1])))

import torch
import torch.nn as nn
import torch.nn.functional as F
import math
​
in_channels =1
out_channels = 1
kernerl_size =3
batch_size=1  ##样本数量
bias=torch.randn(1)  ##默认通道数1
​
input_size=[batch_size,in_channels,4,4]   ##通道数、长度、宽度
conv_layer = torch.nn.Conv2d(in_channels,out_channels ,kernerl_size,bias=bias)
input_feature_map = torch.randn(input_size)    ##产生input
output_feature_map=conv_layer(input_feature_map)  ##
​
print(input_feature_map)
print(conv_layer.weight)  ##相当于权重,kernel    1*1*1*3=out_channels*in_channels*height*width
print(output_feature_map)
​
##函数形式的卷积
output_feature_map1=F.conv2d(input_feature_map,conv_layer.weight)
​
input = torch.radn(5,5)
kernel=torch.randn(3,3)
input=input_feature_map     ##卷积输入特征图
kernel = conv_layer.weight.data  ##卷积核
##1.原始矩阵运算实现二维卷积
def matix_multiplation_for_conv2d(input,kernel,bias=0,stride=1,padding=0):
    if padding>0:
        input=F.pad(input,(padding,padding,padding,padding))
    input_h,input_w=input.shape
    kernel_h,kernel_w=kernel.shape
    
    ##卷积输出的宽度和高度
    output_h=(math.floor(input_h-kernel_h)/stride+1)
    output_w=(math.floor(input_w-kernel_w)/stride+1)
​
    output = torch.zeros(output_h,output_w)
    for i in range(0,input_h-kernel+1,stride):  ##对高度维度便利
        for j in range(0,input_w-kernel_w+1,stride):  ##对宽度维度便利
            region=input(i:i+kernel_h,j:j+kernel_w)   ##取出被核滑动到的区域
            output[int(i/stride),int(j/stride)]torch.sum(region*kernel)+bias
    return ouptput
​
mat_mul_conv_output=matix_multiplation_for_conv2d(input,kernel,padding=1)
print(mat_mul_conv_output)
​
pytorch_mul_conv_output=F.conv2d(input.reshape((1,1,input.shape[0])),kernel.reshape((1,1,kernel.shape[0],kernel.shape[1])))
当我们将Transformer与3D卷积神经网络(CNN)联合使用时,特别是在视频分析领域,我们可以充分利用二者各自的优势。下面是一份更详细的代码示例及其解释,展示如何在一个完整的管道中集成这两者来进行视频分类。 ### 环境准备 确保安装了必要的库: ```bash pip install torch torchvision torchaudio transformers ``` ### 导入库并定义模型组件 首先导入所需的Python包,并初始化一些常量配置项: ```python import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset from torchvision.transforms import Compose, Resize, ToTensor, Normalize from transformers import BertConfig, BertModel ``` 接下来分别编写两个关键组成部分——**3D 卷积模块** **基于BERT架构的Transformer 编码器** #### 1. 定义3D CNN提取空间时间特征 这部分负责从输入的视频片段(即连续几帧图像)中抽取局部及时空信息: ```python class SpatialTemporalCNN(nn.Module): def __init__(self, in_channels=3, base_channel=64): super(SpatialTemporalCNN, self).__init__() self.conv_3d = nn.Sequential( nn.Conv3d(in_channels, base_channel, kernel_size=(3, 7, 7), stride=1, padding=(1, 3, 3)), nn.BatchNorm3d(base_channel), nn.ReLU(inplace=True), nn.MaxPool3d(kernel_size=(1, 2, 2), stride=(1, 2, 2)), # 更深层次可以按需添加更多的Conv3D+BN+ReLU组合... nn.AdaptiveAvgPool3d((None, 1, 1)), # 自适应平均池化层保持时间维度不变 ) def forward(self, x): """ 输入形状 (B,C,T,H,W),其中 B=batch size; C=color channels; T=temporal length of video clip; H/W=image height and width""" return self.conv_3d(x).squeeze(-1).squeeze(-1) ``` #### 2. 引入预训练好的Transformer作为编码器 这里直接借用Hugging Face提供的`transformers` 库里的实现,并做一定修改使之适用于我们的任务需求: ```python class VideoTransformerEncoder(nn.Module): def __init__(self, embed_dim=512, n_head=8, num_layers=6): super().__init__() config = BertConfig(hidden_size=embed_dim, num_hidden_layers=num_layers, num_attention_heads=n_head) self.transformer = BertModel(config) def forward(self, inputs_embeds): outputs = self.transformer(inputs_embeds=inputs_embeds)[0] # 只保留最后一层hidden states cls_output = outputs[:, 0, :] # 提取每个序列的第一个token对应的输出 return cls_output ``` ### 整合两部分构建完整模型 现在我们需要一个类来整合上面提到的所有组件并将它们连接起来工作: ```python class ConvTransVideoClassifier(nn.Module): def __init__(self, cnn_out_features, num_classes): super(ConvTransVideoClassifier, self).__init__() self.spatial_temporal_cnn = SpatialTemporalCNN() self.cls_token = nn.Parameter(torch.randn(1, 1, cnn_out_features)) self.positional_embedding = nn.Parameter(torch.zeros(1, max_video_length + 1, cnn_out_features)) self.video_transformer_encoder = VideoTransformerEncoder(embed_dim=cnn_out_features) self.classifier = nn.Linear(cnn_out_features, num_classes) def forward(self, frames_tensor): batch_size, seq_len, c, h, w = frames_tensor.shape spatial_temporal_feats = [] for t in range(seq_len): # 遍历每一段短片中的每一帧图片 frame_slice = frames_tensor[:,t,...].unsqueeze(dim=1) # shape [batch_size, 1, C, H, W] conv_feat = self.spatial_temporal_cnn(frame_slice) # 进行三维卷积运算 if len(spatial_temporal_feats)==0: spatial_temporal_feats.append(self.cls_token.expand(batch_size,-1,-1)) spatial_temporal_feats.append(conv_feat.unsqueeze(dim=1)) all_frame_features = torch.cat(spatial_temporal_feats,dim=1) # concat along temporal dimension pos_emb_added = all_frame_features + self.positional_embedding[:,:all_frame_features.size()[1]] trans_encoded = self.video_transformer_encoder(pos_emb_added) logits = self.classifier(trans_encoded) return logits ``` 此段代码实现了将视频切分为小片段的形式传入至由3D-CNN初步处理后再交予Transformer进一步深入挖掘潜在关联的过程,最终通过全连接层映射得到各个类别的概率分布情况供下游任务决策参考之用。 --- ### 使用建议 为了提高效果还可以考虑增加数据增广、早停法等措施防止过拟合并加速收敛过程。此外,根据实际应用场景的不同可能还需要调整具体的参数设置,例如学习率调度策略的选择、权重衰减系数等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值