基于Pytorch的YoLoV4模型代码及作品欣赏

简介: 基于Pytorch的YoLoV4模型代码及作品欣赏
一、前言

在正式文章开始前,先写几句废话把。。。

距前面写完YoLoV4架构已经两个月过去,在这两个月中断断续续写代码,再debug。终于完成了YoLoV4的模型构建及运行,还得到了一些挺有意思的结果。

先说下学习感受:

第一,YoLo其实并不难:它有点像大学时候学的工程制图,其中,每个子构件,每条线,每个注释都比较简单易懂,但是合成一个整体,却是一个非常复杂的有机体。

第二,Debug要比Coding消耗更多的时间:所有的代码,基本上半个月就写完了。但是Debug用了一个半月。Debug过程确实对于YoLo还有Python的学习都是很有好处的,理解更深入一个层次。

二、YoLoV4的作品欣赏

我把源码部分放在最后,因为它实在是有点长。而且本着学以致用的精神,不妨可以先看下YoLo可以实现什么功能。

①第一张图:实拍路景

可以看到YoLo很好地识别到了Truck和Person,但是对于最左边的Truck,可能因为不完整,没有识别出来。

②第二章图:实拍路景

比较简单的一个构图,识别起来毫无压力。

③第三张图:实拍路景

对于这种车辆比较密集的情况,不能每台车都框出来,但是总的区域还是比较准确的。

上面说的“不能都框出来”的问题实际上是YoLo的缺点之一,叫label rewriting。可以搜索下Poly-YoLo

接下来,再搞点不一样的

④二次元图像

动漫bleach中的乌尔奇奥拉,被识别成了盆栽。(不过确实有点像)

⑤游戏壁纸

影魔被识别成Cake(难道学习样本中有影魔形状的Cake?)

⑥抖音艺术图(侵删)

这是有点意外的,居然还能识别成person。

⑦抖音艺术图(侵删)

这张图我觉得很好地诠释了YoLo的强大,因为它输出的结果,比我人脑乍一看识别出的内容更加丰富!而且框选的也很准确!

三、YoLo模型的源代码

按照YoLo的架构,我将把YoLo模型的代码分为Backbone,Neck,Head三个部分。

关于代码的理解写在源码注释中。

在放上代码之前,先声明一点:这里的源代码,只包含YoLo的模型部分,要想完整地运行出上面的结果,还需要:

读取图像,画出Bounding box,生成新图像的python代码辅助部分;

训练神经源网络,得到预训练后的权值,并导入到模型中。

(这两部分我是在别人的帮助下完成的,在这里就不附上了)

这里在多说一句,关于②导入预训练的权值,如果试下不导入,输出的结果就是下面这种混乱的状态。

这也很好理解,因为神经元模型并没有学习过很多样本,它也不知道什么样的结果应该输出Person,什么样的结果应该输出Cake。可见预训练对于神经元模型的重要性。

Backbone:
import torch
import torch.nn.functional as F
import torch.nn as nn
import math
import numpy as np
class Mish(nn.Module):  #定义激活函数Mish
    def __init__(self):
        super(Mish,self).__init__()
    def forward(self,x):
        return x*torch.tanh(F.softplus(x))
class CBM(nn.Module):  #定义CBM模块
    def __init__(self,in_channels, out_channels, kernel_size, stride=1):
        super(CBM,self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, kernel_size//2, bias=False)  #定义卷积层
        self.bn = nn.BatchNorm2d(out_channels)
        self.activation = Mish()
    def forward(self,x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.activation(x)
        return x
class Res_Unit(nn.Module): #构建Res Unit,回忆下Res Unit的结构=CBM*2+残差相加
    def __init__(self,channels,hidden_channels = None):
        super(Res_Unit,self).__init__()
        if hidden_channels == None:
            hidden_channels = channels
        self.block = nn.Sequential(
            CBM(channels, hidden_channels, 1) , #第一个CBM的卷积核为1×1,作用是降维提高运算效率
            CBM(hidden_channels,channels, 3)
        )
    def forward(self,x):
        return x+self.block(x)   #计算残差
class CSPNet(nn.Module):
# -----------CSPNet原理图-----------------------------------------------------------------------------------
#
#    CSPX ==>  [downsample]--> [CBM(split_conv0)]--------------------->[concat]->[downsample]
#                          |                                                ↑
#                          |-> [CBM(split_conv1)]-->[Res Unit(block_conv)]--|
#
# -----------CSPNet原理图------------------------------------------------------------------------------------
    def __init__(self,in_channels, out_channels, num_Res_Unit, first):    #num_Res_Unit表示在CSPNet中,Res_Unit的个数
        super(CSPNet,self).__init__()
        self.downsample_conv = CBM(in_channels, out_channels, 3, stride=2)  #在CSP模块最开始,有一个下采样
        if first == True:     #第一个CSP和后面的CSP不同,后面的CSP输出会降维,所以需要区分是否是first CSP
            self.split_conv0 = CBM(out_channels, out_channels, 1) #对应结构图中CPSX模块中,上面的那个CBM。输入为下采样之后的输出。
            self.split_conv1 = CBM(out_channels, out_channels, 1) #对应结构图中CPSX模块中,下面第一个的那个CBM
            self.block_conv = nn.Sequential(
                Res_Unit(channels=out_channels, hidden_channels=out_channels//2),
                CBM(out_channels,out_channels,1)  #第一个CSPNet是CSP1,所以这里Res_Unit刚好只有一个
            ) #对应结构图中CPSX模块中,下面的那个Res_Unit 及后面的CBM
            self.concat_downsample = CBM(out_channels*2, out_channels,1)  #这是concat之后的下采样模块,因为concat,输入变成out_channels的2倍
        else:
            self.split_conv0 = CBM(out_channels, out_channels//2, 1)  # 对于非第一个CSP模块,输出会降维,所以增加//2
            self.split_conv1 = CBM(out_channels, out_channels//2, 1)
            self.block_conv = nn.Sequential(
                *[Res_Unit(channels=out_channels//2) for _ in range(num_Res_Unit)]
                ,CBM(out_channels//2, out_channels//2, 1)
            )  # 用*[]构建num_Res_Unit个输入参数()
            self.concat_downsample = CBM(out_channels, out_channels,1)  # 这是concat之后的下采样模块
    def forward(self,x):   #x为要处理的tensor
        x = self.downsample_conv(x)
        x0 = self.split_conv0(x)
        x1 = self.split_conv1(x)
        x1 = self.block_conv(x1)
        x = torch.cat([x1,x0],dim = 1)
        x = self.concat_downsample(x)
        return x
#======================backbone结构构建=============================================
class Yolo_backbone(nn.Module):
    def __init__(self):
        super(Yolo_backbone, self).__init__()
#---------构建Darknet 53的结构------------------------------------
        self.conv1 = CBM(3, 32, kernel_size=3, stride=1) #对应第一个CBM,输入原始图像通道为3,输出通道为32
        self.structure = nn.ModuleList([
            CSPNet(32, 64, num_Res_Unit = 1, first= True),
            CSPNet(64, 128, num_Res_Unit = 2, first=False),
            CSPNet(128, 256, num_Res_Unit = 8, first=False),
            CSPNet(256, 512, num_Res_Unit = 8, first=False),
            CSPNet(512, 1024, num_Res_Unit = 4, first=False),
        ]) #每经过一个CSP,输出通道数翻倍
#-----------------------------------------------------------------
#-------------下面进行网络初始化---------------------------------
        for m in self.modules():
            if isinstance(m,nn.Conv2d) :  #卷积核初始化,还有其他的卷积核初始化方法
                n = m.kernel_size[0]* m.kernel_size[1]* m.out_channels
                m.weight.data.normal_(0,math.sqrt(2./n))
            if isinstance(m,nn.BatchNorm2d):    #BN层初始化
                m.weight.data.fill_(1)
                m.bias.data.zero_()
    def forward(self, x):
        x = self.conv1(x)
        x = self.structure[0](x)
        x = self.structure[1](x)
        out1 = self.structure[2](x)   #参考YOLO的整体框架结构,从此开始有3个输出,输出顺序out1,out2,out3
        out2 = self.structure[3](out1)
        out3 = self.structure[4](out2)
        return out1,out2,out3
#==============以上,backbone构建完成 =============================
def load_model_path(model,pth):  #model是网络模型,pth是预训练权重的文件路径
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model_dict = model.state_dict() #所有权重weight的label和parameter将输入到字典model_dict中。
    # 在pytorch中,torch.nn.Module模块中的state_dict变量存放训练过程中需要学习的权重和偏置系数
    # model_dict是还未训练的权值文件
    pretrain_dict = torch.load(pth,map_location=device)  #导入已经训练好的权值文件
    matched_dict = {}
    for k,v in model_dict.items():
        if k.find('backbone') == -1:
            key = 'backbone.'+k.replace('structure','stages').replace('block_conv','blocks_conv').replace('concat_downsample','concat_conv')
            #上面这里是发现已经训练好的权值,和要替换的未训练的权值名称有些差异,所以要替换下这些名称
            if np.shape(pretrain_dict[key]) == np.shape(v):
                matched_dict[k] = v
    #上面这个for的作用:这里可以先打印下pretrain_dict中的变量名,可以看到几乎都是backbone开头,这些都是训练好的backbone的权值
    #model_dict是未训练的模型的权值文件,通过变量key找到在pretrain_dict中的对应变量,把训练好的变量赋值给matched_dict
    model_dict.update(matched_dict)  #更新我们自己YOLO的权值文件(也就是model_dict)
    model.load_state_dict(model_dict)
    return model
def YOLO_backbone_pretrain(pretrain):  #进行网络预训练
    model = Yolo_backbone()
    load_model_path(model, pretrain)
    return model
if __name__ == "__main__":
    backbone = YOLO_backbone_pretrain('pth/yolo4_weights_my.pth')  #这个路径放入预训练好的权值文件
Neck:

这部分我认为是YoLo中最复杂、最容易出错、需要耐心的一部分,必须要严格参照YoLo的构架图。

import torch
import torch.nn as nn
from collections import OrderedDict
from YOLO_backbone import *
def CBL(channel_in,channel_out,kernel_size,stride=1):  #编辑NECK中的CBL模块
    if kernel_size:
        pad = (kernel_size-1)//2
    else:
        pad = 0
    return nn.Sequential(OrderedDict([
                             ('conv',nn.Conv2d(channel_in,channel_out,kernel_size=kernel_size,stride=stride,padding=pad)),
                             ('bn',nn.BatchNorm2d(channel_out)),
                             ('leaky_relu',nn.LeakyReLU(0.1))
                         ]))
class SPP(nn.Module):   #定义SPP模块
    def __init__(self,pool_sizes=[13,9,5]):  #13,9,5怎是工程经验值
        super(SPP, self).__init__()
        self.maxpools = nn.ModuleList([nn.MaxPool2d(pool_size, 1, pool_size//2) for pool_size in pool_sizes])
    def forward(self,x):
        features = [maxpool(x) for maxpool in self.maxpools]
        features = torch.cat(features+[x],dim=1)   #注意:虽然经过maxpooling之后features的维度会比x小很多,但是因为concat的broadcast机制,仍然可以拼接得上
        return features
class upsample(nn.Module):  #定义卷积+上采样模块
    def __init__(self, in_channels, out_channels):
        super(upsample,self).__init__()
        self.up_sample = nn.Sequential(
            CBL(in_channels,out_channels,1),
            nn.Upsample(scale_factor=2,mode='nearest')
        )
    def forward(self,x):
        return self.up_sample(x)
def CBL_3(channel_list,channel_in): #定义CBL*3模块(通道数调用的时候需要输入)
    m = nn.Sequential(
        CBL(channel_in, channel_list[0],1),
        CBL(channel_list[0],channel_list[1],3),
        CBL(channel_list[1],channel_list[0],1)
    )
    return m
def CBL_5(channel_list,channel_in): #定义CBL*5模块
    m= nn.Sequential(
        CBL(channel_in, channel_list[0],1),   #降维,1*1卷积核降维?
        CBL(channel_list[0],channel_list[1],3),  #升维,3*3卷积核升维?
        CBL(channel_list[1],channel_list[0],1),#降维
        CBL(channel_list[0], channel_list[1], 3),#升维
        CBL(channel_list[1], channel_list[0], 1)#降维
    )
    return m
def YOLO_before_head(channel_list,channel_in):  #定义head前面的CBL+conv模块
    m = nn.Sequential(
        CBL(channel_in, channel_list[0],3),
        nn.Conv2d(channel_list[0],channel_list[1],1)
    )
    return m
#-------------------下面通过上面构造的各个子组件,构建整个neck的网络-------------------------------
class YOLO_neck_body(nn.Module):
     def __init__(self, num_anchors, num_classes):
         super(YOLO_neck_body, self).__init__()
         # self.backbone = YOLO_backbone_pretrain('pth/yolo4_weights_my.pth')  #!!!这里也会显示预训练数据名冲突,所以线注释掉!!!用下面的替换
         self.backbone = Yolo_backbone()
         # 以下内容需要参考Neck的架构图
         # 首先编写①
         self.CBL31_1 = CBL_3([512,1024],1024)  #通道数按照YOLO的规定
         self.SPP_1 = SPP()
         self.CBL32_1 = CBL_3([512,1024],2048)
         #继续写②
         self.upsample_2 = upsample(512,256)  #通道数同样是按YOLO的架构规定,不用纠结。注意:upsample内部已经包含前面的CBL了
         self.CBL_2 = CBL(512,256,1)
         self.CBL5_2 = CBL_5([256,512],512)
         #继续写③
         self.upsample_3 = upsample(256,128)
         self.CBL_3 = CBL(256,128,1)     #这里第一个256原来是512
         self.CBL5_3 = CBL_5([128,256],256)
         #写第一个head输出(76*76这个)
         final_out_channels = num_anchors*(5+num_classes)   #等于255
         self.yolo_head76 = YOLO_before_head([256,final_out_channels],128)
         #继续写④
         self.downsample_4 = CBL(128,256,3,stride=2)  #在④的CBL之前有个downsample,所以stride=2
         self.CBL5_4 = CBL_5([256,512],256)
         self.downsample2_4 = CBL(256,256,3,stride=2)  #R5从④出来后有一个downsample
         self.yolo_head38 = YOLO_before_head([512,final_out_channels],256) #这是第2个head,38*38
         #继续写⑤
         self.downsample_5 = CBL(256,512,3,stride=2)#同样,在⑤的CBL之前有个downsample,所以stride=2
         self.CBL5_5 = CBL_5([512,1024],512)
         self.CBL_5 = CBL(1024,512,3,stride=1)
         self.yolo_head19 = YOLO_before_head([1024,final_out_channels],512)  #这是第3个head,19*19
     def forward(self,x):
         #forward要严格按照YOLO的架构顺序,是个比较精细的工作
         x2,x1,x0 = self.backbone(x)   #x2,x1,x0对应backbone的三个输出,注意:对应backbone的结构,输出顺序为x2->x1->x0
         # 先写R1,R1为最上面的路径
         R1 = self.CBL31_1(x0)
         R1 = self.SPP_1(R1)
         R1_before_upsample = self.CBL32_1(R1)  #引出一条之路,给后面的R6用
         R1 = self.upsample_2(R1_before_upsample)
         print('开始neck部分debug')
         print('R1_before_upsample:',R1_before_upsample.shape)
         print('R1:',R1.shape)
         #写R2,上面第二条路径
         R2 = self.CBL_2(x1) #引入x1,仍然是按照yolo的架构
         print('R2:',R2.shape)
         R1_and_2 = torch.cat([R1,R2],axis=1)
         print('R1_and_2:',R1_and_2.shape)
         R1_and_2 = self.CBL5_2(R1_and_2)
         print('R1_and_2:',R1_and_2.shape)
         R1_and_2 = self.upsample_3(R1_and_2)   #upsample包括前面的CBL
         print('R1_and_2:',R1_and_2.shape)
         #写第三条路径,R3
         R3 = self.CBL_3(x2) #引入x2
         R1_and_2_and_3 = torch.cat([R3,R1_and_2],axis=1)
         R1_and_2_and_3 = self.CBL5_3(R1_and_2_and_3)
         print('R3:',R3.shape)
         print('R1_and_2_and_3:',R1_and_2_and_3.shape)
         #写第四条路径,R4
         R4 = R1_and_2_and_3
         print('R4:',R4.shape)
         #写第五条路径,R5
         R5 = torch.cat([R4,R1_and_2],axis=1)
         R5 = self.CBL5_4(R5)
         R5_beforehead = self.downsample2_4(R5) #创造一个断点给输出
         print('R5_beforehead:',R5_beforehead.shape)
         #写第六条路径,R6
         R5 = self.downsample_5(R5_beforehead)
         print('R5:',R5.shape)
         print('R1_before_upsample:',R1_before_upsample.shape)
         R6 = torch.cat([R5,R1_before_upsample],axis=1)
         R6 = self.CBL_5(R6)
         print('R6:',R6.shape)
         #写输出
         print('进入头部前再检查一遍neck的输入张量')
         print('76*76:',R1_and_2_and_3.shape)
         print('38*38:',R5_beforehead.shape)
         print('19*19:',R6.shape)
         out76 = self.yolo_head76(R1_and_2_and_3)
         out38 = self.yolo_head38(R5_beforehead)
         out19 = self.yolo_head19(R6)
         return out76,out38,out19
if __name__ == '__main__':
    model = YOLO_neck_body(3,80)
    # load_model_path(model,'pth/yolo4_weights_my.pth')
Head:
import torch.nn as nn
import torch.nn.functional as F
import torch
def yolo_decode(output,num_class, anchors, num_anchors, scale):
    #anchors释意见Yololayer;
    #output=[B,A*n_ch,H,W],这个是head输出的张量,这个张量中的数据顺序、结构是由neck的模型结构决定的
    device = None
    if output.is_cuda:
        device = output.get_device()
    n_ch = 4+1+num_class  #tx,ty,th,tw,obj
    A = num_anchors  #num_anchors = 3
    B = output.size(0) #output第一个B是batch,代表每次处理图片的批次数
    H = output.size(2) #output第三个是H,纵向网格数 = 19或38或76
    W = output.size(3) #output第四个是W,横向网格数 = 19或38或76
    output = output.view(B,A,n_ch,H,W).permute(0,1,3,4,2).contiguous() #重组output中数据的顺序,变成[B,A,H,W,n_ch],为了下一步方便取bx,by,bw,bh
    tx = output[...,0] #n_ch=85=[tx,ty,tw,th,obj,coco]
    ty = output[...,1]
    tw = output[...,2]
    th = output[...,3]
    obj = output[...,4]
    cls = output[...,5:]
    print('tw:',tw.shape)
    print('th:',th.shape)
     #bx,by,bw,bh是bounding box中心点位置及框的长宽的值;tx,ty,tw,th是网络学习得到的值(其实是list),需要用tx,ty,tw,th解码得出bx,by,bw,bh。
    #注意!!!这里的bx,by,bw,bh的单位是网格数(也就是按19*19,38*38,76*76分割的网格数),而不是实际的像素数
    obj = torch.sigmoid(obj)
    cls = torch.sigmoid(cls)
    grid_x = torch.arange(W,dtype=torch.float).repeat(1,3,W,1).to(device)
    # grid_y = torch.arange(H, dtype=torch.float).repeat(1, 3, 1, H).to(device)
    grid_y = torch.arange(H, dtype=torch.float).repeat(1, 3, H, 1).permute(0, 1, 3, 2).to(device)
    print('开始头部debug')
    print('tx:',tx.shape)
    print('ty:',ty.shape)
    print('grid_x:',grid_x.shape)
    print('grid_y:',grid_y.shape)
    bx = grid_x + torch.sigmoid(tx)
    by = grid_y + torch.sigmoid(ty)
    for i in range(num_anchors):
        tw[:,i,:,:] = (torch.exp(tw[:,i,:,:])*scale -0.5*(scale-1))*anchors[i*2]  #计算bw,因为Anchor在第二维(output中的A),i也对应要在第二维;因为anchor要跳一位去宽度值,所以要*2
        tw[:,i,:,:] = (torch.exp(th[:,i,:,:])*scale - 0.5*(scale-1))*anchors[i*2+1]  #与上面同理
    bx = (bx / W).unsqueeze(-1)  #进行归一化,为了方便模型训练
    by = (by / H).unsqueeze(-1)  #同上
    bw = (tw / W).unsqueeze(-1)  #同上
    bh = (th / H).unsqueeze(-1)  #同上
    print('bx:',bx.shape)
    print('by:',by.shape)
    print('bw:',bw.shape)
    print('bh:',bh.shape)
    box = torch.cat((bx,by,bw,bh),dim=-1).reshape(B,A*H*W,4)
    obj = obj.unsqueeze(-1).reshape(B,A*H*W,1) #索引的时候,损失了最后一个维度,要补回来
    cls = cls.reshape(B,A*H*W,num_class)
    head_output = torch.cat([box, obj, cls],dim = -1)
    return head_output
class YoloLayer(nn.Module):
    def __init__(self,img_size, anchor_mask=[],num_class =80, anchors = [],num_anchors=9, stride =32, scale = 1):
        super(YoloLayer,self).__init__()
        self.anchor_mask = anchor_mask  #anchor_mask,[[6,7,8],[3,4,5],[0,1,2]],是一个二维数组
        self.num_class = num_class  #coco类别有80类
        self.anchors = anchors  #每个head有3个anchor,共9个anchor,anchors = [12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192,243, 459, 401]
        # 共9组数据12,16  19,36  40,28;  36,75  76,55  72,146;  142,110  192,243  459,401
        self.num_anchors = num_anchors  #每个head有3个anchor,共9个anchor,num_anchors=9
        self.anchor_step = len(anchors) // num_anchors   #anchor_step = 18/9 = 2
        self.stride = stride  #stride是网格的像素数,stride*网格数=608
        self.scale = scale   #scale 一般取1
        self.feature_length = [img_size[0]//8,img_size[0]//16,img_size[0]//32]
        self.img_size = img_size
    def forward(self,output):
        if self.training:   #????
            return output
        masked_anchors = []
        for m in [0,1,2,3,4,5,6,7,8]:
            masked_anchors += self.anchors[m*self.anchor_step:(m+1)*self.anchor_step]  #取所有mask对应的所有的anchor
        masked_anchors = [anchor/self.stride for anchor in masked_anchors]  #这个操作我理解是进行单位转换,把像素数除以每个网格的像素数,得到网格数,传入上面yolo_decode
        data = yolo_decode(output, self.num_class, masked_anchors, len(self.anchor_mask),scale = self.scale)
        return data
四、写在最后

对于上面的图像输出结果,其实最开始我是很诧异的,因为YoLo神经元网络模型,其实数学本质上就是非线性运算(Leaky Relu),并不复杂。没想到经过一系列的组合、堆叠,居然能实现这么复杂的功能!

然而,刚好在最近看到的一本书里看到了一个理论说明了这个现象,送给大家:

如果让计算机反复地计算极其简单的运算法则,那么就可以使之发展成为异常复杂的模型,并可以解释自然界中的所有现象,支配宇宙的原理无非就是区区几行程序代码。
-Stephen Wolfram


相关文章
|
6天前
|
存储 物联网 PyTorch
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
**Torchtune**是由PyTorch团队开发的一个专门用于LLM微调的库。它旨在简化LLM的微调流程,提供了一系列高级API和预置的最佳实践
104 59
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
|
23天前
|
算法 PyTorch 算法框架/工具
Pytorch学习笔记(九):Pytorch模型的FLOPs、模型参数量等信息输出(torchstat、thop、ptflops、torchsummary)
本文介绍了如何使用torchstat、thop、ptflops和torchsummary等工具来计算Pytorch模型的FLOPs、模型参数量等信息。
105 2
|
2月前
|
机器学习/深度学习 PyTorch 算法框架/工具
CNN中的注意力机制综合指南:从理论到Pytorch代码实现
注意力机制已成为深度学习模型的关键组件,尤其在卷积神经网络(CNN)中发挥了重要作用。通过使模型关注输入数据中最相关的部分,注意力机制显著提升了CNN在图像分类、目标检测和语义分割等任务中的表现。本文将详细介绍CNN中的注意力机制,包括其基本概念、不同类型(如通道注意力、空间注意力和混合注意力)以及实际实现方法。此外,还将探讨注意力机制在多个计算机视觉任务中的应用效果及其面临的挑战。无论是图像分类还是医学图像分析,注意力机制都能显著提升模型性能,并在不断发展的深度学习领域中扮演重要角色。
81 10
|
25天前
|
机器学习/深度学习 自然语言处理 监控
利用 PyTorch Lightning 搭建一个文本分类模型
利用 PyTorch Lightning 搭建一个文本分类模型
45 8
利用 PyTorch Lightning 搭建一个文本分类模型
|
27天前
|
机器学习/深度学习 自然语言处理 数据建模
三种Transformer模型中的注意力机制介绍及Pytorch实现:从自注意力到因果自注意力
本文深入探讨了Transformer模型中的三种关键注意力机制:自注意力、交叉注意力和因果自注意力,这些机制是GPT-4、Llama等大型语言模型的核心。文章不仅讲解了理论概念,还通过Python和PyTorch从零开始实现这些机制,帮助读者深入理解其内部工作原理。自注意力机制通过整合上下文信息增强了输入嵌入,多头注意力则通过多个并行的注意力头捕捉不同类型的依赖关系。交叉注意力则允许模型在两个不同输入序列间传递信息,适用于机器翻译和图像描述等任务。因果自注意力确保模型在生成文本时仅考虑先前的上下文,适用于解码器风格的模型。通过本文的详细解析和代码实现,读者可以全面掌握这些机制的应用潜力。
43 3
三种Transformer模型中的注意力机制介绍及Pytorch实现:从自注意力到因果自注意力
|
2月前
|
机器学习/深度学习 PyTorch 调度
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
在深度学习中,学习率作为关键超参数对模型收敛速度和性能至关重要。传统方法采用统一学习率,但研究表明为不同层设置差异化学习率能显著提升性能。本文探讨了这一策略的理论基础及PyTorch实现方法,包括模型定义、参数分组、优化器配置及训练流程。通过示例展示了如何为ResNet18设置不同层的学习率,并介绍了渐进式解冻和层适应学习率等高级技巧,帮助研究者更好地优化模型训练。
117 4
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
|
22天前
|
机器学习/深度学习 PyTorch 算法框架/工具
聊一聊计算机视觉中常用的注意力机制以及Pytorch代码实现
本文介绍了几种常用的计算机视觉注意力机制及其PyTorch实现,包括SENet、CBAM、BAM、ECA-Net、SA-Net、Polarized Self-Attention、Spatial Group-wise Enhance和Coordinate Attention等,每种方法都附有详细的网络结构说明和实验结果分析。通过这些注意力机制的应用,可以有效提升模型在目标检测任务上的性能。此外,作者还提供了实验数据集的基本情况及baseline模型的选择与实验结果,方便读者理解和复现。
22 0
聊一聊计算机视觉中常用的注意力机制以及Pytorch代码实现
|
2月前
|
机器学习/深度学习 监控 PyTorch
PyTorch 模型调试与故障排除指南
在深度学习领域,PyTorch 成为开发和训练神经网络的主要框架之一。本文为 PyTorch 开发者提供全面的调试指南,涵盖从基础概念到高级技术的内容。目标读者包括初学者、中级开发者和高级工程师。本文探讨常见问题及解决方案,帮助读者理解 PyTorch 的核心概念、掌握调试策略、识别性能瓶颈,并通过实际案例获得实践经验。无论是在构建简单神经网络还是复杂模型,本文都将提供宝贵的洞察和实用技巧,帮助开发者更高效地开发和优化 PyTorch 模型。
39 3
PyTorch 模型调试与故障排除指南
|
30天前
|
存储 并行计算 PyTorch
探索PyTorch:模型的定义和保存方法
探索PyTorch:模型的定义和保存方法
|
3月前
|
机器学习/深度学习 PyTorch 编译器
PyTorch 与 TorchScript:模型的序列化与加速
【8月更文第27天】PyTorch 是一个非常流行的深度学习框架,它以其灵活性和易用性而著称。然而,当涉及到模型的部署和性能优化时,PyTorch 的动态计算图可能会带来一些挑战。为了解决这些问题,PyTorch 引入了 TorchScript,这是一个用于序列化和优化 PyTorch 模型的工具。本文将详细介绍如何使用 TorchScript 来序列化 PyTorch 模型以及如何加速模型的执行。
106 4