精华内容
下载资源
问答
  •   本文介绍最简单的pytorch分布式训练方法:使用torch.nn.DataParallel这个API来实现分布式训练。环境为单机多gpu,不妨假设有4个可用的gpu。 一、构建方法 使用这个API实现分布式训练步骤非常简单,总共分为3...

      本文介绍最简单的pytorch分布式训练方法:使用torch.nn.DataParallel这个API来实现分布式训练。环境为单机多gpu,不妨假设有4个可用的gpu。

    一、构建方法

    使用这个API实现分布式训练的步骤非常简单,总共分为3步骤:
    1、创建一个model,并将该model推到某个gpu上(这个gpu也将作为output_device,后面具体解释含义),不妨假设推到第0号gpu上,

    device = torch.device("cuda:0")
    model.to(device)
    

    2、将数据推到output_device对应的gpu上,

    data = data.to(device)
    

    3、使用torch.nn.DataParallel这个API来在0,1,2,3四个gpu上构建分布式模型,

    model = torch.nn.DataParallel(model, device_ids=[0,1,2,3], output_device=0)
    

    然后这个model就可以像普通的单gpu上的模型一样开始训练了。

    二、原理详解

    2.1 原理图

      首先通过图来看一下这个最简单的分布式训练API的工作原理,然后结合代码详细阐述。
    1
    将模型和数据推入output_device(也就是0号)gpu上。
    在这里插入图片描述
    0号gpu将当前模型在其他几个gpu上进行复制,同步模型的parameter、buffer和modules等;将当前batch尽可能平均的分为len(device)=4份,分别推给每一个设备,并开启多线程分别在每个设备上进行前向传播,得到各自的结果,最后将各自的结果全部汇总在一起,拷贝回0号gpu。
    在这里插入图片描述
    在0号gpu进行反向传播和模型的参数更新,并将结果同步给其他几个gpu,即完成了一个batch的训练。

    2.2 代码原理

      通过分析torch.nn.DataParallel的代码,可以看到具体的过程,这里重点看一下几个关键的地方。

    # 继承自nn.Module,只要实现__init__和forward函数即可
    class DataParallel(Module):
        # 构造函数里没有什么关键内容,主要是根据传进来的model、device_ids和output_device进行一些变量生成
        def __init__(self, module, device_ids=None, output_device=None, dim=0):
            super(DataParallel, self).__init__()
    
            device_type = _get_available_device_type()
            if device_type is None:
                self.module = module
                self.device_ids = []
                return
    
            if device_ids is None:
                device_ids = _get_all_device_indices()
    
            if output_device is None:
                output_device = device_ids[0]
    
            self.dim = dim
            self.module = module
            self.device_ids = list(map(lambda x: _get_device_index(x, True), device_ids))
            self.output_device = _get_device_index(output_device, True)
            self.src_device_obj = torch.device(device_type, self.device_ids[0])
    
            _check_balance(self.device_ids)
    
            if len(self.device_ids) == 1:
                self.module.to(self.src_device_obj)
        def forward(self, *inputs, **kwargs):
            if not self.device_ids:
                return self.module(*inputs, **kwargs)
    
            for t in chain(self.module.parameters(), self.module.buffers()):
                if t.device != self.src_device_obj:
                    raise RuntimeError("module must have its parameters and buffers "
                                       "on device {} (device_ids[0]) but found one of "
                                       "them on device: {}".format(self.src_device_obj, t.device))
    
            inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids)
            if len(self.device_ids) == 1:
                return self.module(*inputs[0], **kwargs[0])
            # 在每个gpu上都复制一个model
            replicas = self.replicate(self.module, self.device_ids[:len(inputs)])
            # 开启多线程进行前向传播,得到结果
            outputs = self.parallel_apply(replicas, inputs, kwargs)
            # 将每个gpu上得到的结果都gather到0号gpu上
            return self.gather(outputs, self.output_device)
    
        def replicate(self, module, device_ids):
            return replicate(module, device_ids, not torch.is_grad_enabled())
    
        def scatter(self, inputs, kwargs, device_ids):
            return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim)
    
        def parallel_apply(self, replicas, inputs, kwargs):
            return parallel_apply(replicas, inputs, kwargs, self.device_ids[:len(replicas)])
    
        def gather(self, outputs, output_device):
            return gather(outputs, output_device, dim=self.dim)
    

    再看一下parallel_apply这个关键的函数,

    def parallel_apply(modules, inputs, kwargs_tup=None, devices=None):
        assert len(modules) == len(inputs)
        if kwargs_tup is not None:
            assert len(modules) == len(kwargs_tup)
        else:
            kwargs_tup = ({},) * len(modules)
        if devices is not None:
            assert len(modules) == len(devices)
        else:
            devices = [None] * len(modules)
        devices = list(map(lambda x: _get_device_index(x, True), devices))
        # 创建一个互斥锁,防止前后两个batch的数据覆盖
        lock = threading.Lock()
        results = {}
        grad_enabled, autocast_enabled = torch.is_grad_enabled(), torch.is_autocast_enabled()
        # 线程的target函数,实现每个gpu上进行推理,其中i为gpu编号
        def _worker(i, module, input, kwargs, device=None):
            torch.set_grad_enabled(grad_enabled)
            if device is None:
                device = get_a_var(input).get_device()
            try:
                # 根据当前gpu编号确定推理硬件环境
                with torch.cuda.device(device), autocast(enabled=autocast_enabled):
                    # this also avoids accidental slicing of `input` if it is a Tensor
                    if not isinstance(input, (list, tuple)):
                        input = (input,)
                    output = module(*input, **kwargs)
                # 锁住赋值,防止后一个batch的数据将前一个batch的结果覆盖
                with lock:
                    results[i] = output
            except Exception:
                with lock:
                    results[i] = ExceptionWrapper(
                        where="in replica {} on device {}".format(i, device))
    
        if len(modules) > 1:
            # 创建多个线程,进行不同gpu的前向推理
            threads = [threading.Thread(target=_worker,
                                        args=(i, module, input, kwargs, device))
                       for i, (module, input, kwargs, device) in
                       enumerate(zip(modules, inputs, kwargs_tup, devices))]
    
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
        else:
            _worker(0, modules[0], inputs[0], kwargs_tup[0], devices[0])
        # 将不同gpu上推理的结果打包起来,后面会gather到output_device上
        outputs = []
        for i in range(len(inputs)):
            output = results[i]
            if isinstance(output, ExceptionWrapper):
                output.reraise()
            outputs.append(output)
        return outputs
    

    结论

      至此我们看到了torch.nn.DataParallel模块进行分布式训练的原理,数据和模型首先推入output_device对应的gpu,然后将分成多个子batch的数据和模型分别推给其他gpu,每个gpu单独处理各自的子batch,结果再打包回原output_device对应的gpu算梯度和更新参数,如此循环往复,其本质是一个单进程多线程的并发程序。
      由此我们也很容易得到torch.nn.DataParallel模块进行分布式的缺点,
    1、每个batch的数据先分发到各gpu上,结果再打包回output_device上,在output_device一个gpu上进行梯度计算和参数更新,再把更新同步给其他gpu上的model。其中涉及数据的来回拷贝,网络通信耗时严重,GPU使用率低。
    2、这种模式只支持单机多gpu的硬件拓扑结构,不支持Apex的混合精度训练等。
    3、torch.nn.DataParallel也没有很完整的考虑到多个gpu做数据并行的一些问题,比如batchnorm,在训练时各个gpu上的batchnorm的mean和variance是子batch的计算结果,而不是原来整个batch的值,可能会导致训练不稳定影响收敛等问题。

    展开全文
  • Pytorch修改预训练模型   torchvision模块带有很多预训练模型,具体支持的模型列表可以参看官方文档。   在语义分割中,预训练模型一般是3通道的,但是在实际情况中经常会有输入通道数量不止3个通道,要修改预...

    Pytorch修改预训练模型

      torchvision模块带有很多预训练模型,具体支持的模型列表可以参看官方文档
      在语义分割中,预训练模型一般是3通道的,但是在实际情况中经常会有输入通道数量不止3个通道,要修改预训练模型的通道数,要么重写模型,要么就复用预训练模型,这里推荐用官方的预训练模型,代码简洁且不容易出错。
      步入正题,要调整预训练模型需要两个步骤,首先如下加载预训练模型,并打印模型第一层,然后修改第一层结构的输入通道数即可。

    import torchvision.models as models
    backbone = models.resnet101(pretrained=False)
    print(backbone.conv1)
    

      这里打印得到第一层的结构。

    Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    

      于是这里可以看到输入模型的通道数为3,只要修改这个3就可以了,若期望的输入是4通道,则如下操作即可:

    backbone.conv1= nn.Conv2d(4, 64, kernel_size=7, stride=2, padding=3,bias=False)
    

      至此已经修改完毕,下面是deeplabv3+的backbone的调整实例。
      这里有个小技巧,在模型调整完毕后需要先做单元测试,通过随机生成一个tensor,输入模型看能不能跑出结果(代码最后的测试模块)。

    import torchvision.models as models
    import torch.nn as nn
    import torch
    
    class ResNet_101(nn.Module):
    	"""加载预训练模型resnet101"""
    	 def __init__(self, in_channels = 13, conv1_out = 64):
    	   super(ResNet_101,self).__init__()
    	   backbone = models.resnet101(pretrained=False)
    	   print("load pretrained ResNet101 model")
    	   # self.conv1 = backbone.conv1
    	   self.conv1 = nn.Conv2d(in_channels, 64, kernel_size=7, stride=2, padding=3,bias=False)
    	   self.bn1 = backbone.bn1
    	   self.relu = nn.ReLU(inplace=True)
    	   self.maxpool = backbone.maxpool
    	   self.layer1 = backbone.layer1
    	   self.layer2 = backbone.layer2
    	   self.layer3 = backbone.layer3
    	 
    	 def forward(self,x):
    	   x = self.relu(self.bn1(self.conv1(x)))
    	   x = self.maxpool(x)
    	   x = self.layer1(x)
    	   x = self.layer2(x)
    	   x = self.layer3(x)
    	   
    	   return x
        
    class Deeplabv3Resnet101(nn.Module):
    	"""语义分割中以resnet101为backbone的deeplabv3+模型"""
        def __init__(self,nc=2,input_channel=3):
            super(deeplabv3plus_resnet101,self).__init__()
            self.nc = nc
            self.backbone = ResNet_101(input_channel)
            self.assp = ASSP(in_channels=1024)
            self.out1 = nn.Sequential(nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1),nn.ReLU())
            self.dropout1 = nn.Dropout(0.5)
            self.up4 = nn.Upsample(scale_factor=4)
            self.up2 = nn.Upsample(scale_factor=2)
    
            self.conv1x1 = nn.Sequential(nn.Conv2d(1024,256,1,bias=False),nn.ReLU())
            self.conv3x3 = nn.Sequential(nn.Conv2d(512,self.nc,1),nn.ReLU())
            self.dec_conv = nn.Sequential(nn.Conv2d(256,256,3,padding=1),nn.ReLU())
            
        def forward(self,x):
            x = self.backbone(x)
            out1 = self.assp(x)
            out1 = self.out1(out1)
            out1 = self.dropout1(out1)
            out1 = self.up4(out1)
            # print(out1.shape)
    
            dec = self.conv1x1(x)
            dec = self.dec_conv(dec)
            dec = self.up4(dec)
            concat = torch.cat((out1,dec),dim=1)
            out = self.conv3x3(concat)
            out = self.up4(out)
            return out
    
    class ASSP(nn.Module):
        def __init__(self,in_channels,out_channels = 256):
            super(ASSP,self).__init__()
            self.relu = nn.ReLU(inplace=True)
            self.conv1 = nn.Conv2d(in_channels,out_channels,1,padding = 0,dilation=1,bias=False)
            self.bn1 = nn.BatchNorm2d(out_channels)
            self.conv2 = nn.Conv2d(in_channels = in_channels,out_channels = out_channels,kernel_size = 3,stride=1,padding = 6,dilation = 6,bias=False)
            self.bn2 = nn.BatchNorm2d(out_channels)
            self.conv3 = nn.Conv2d(in_channels = in_channels,out_channels = out_channels,kernel_size = 3,stride=1,padding = 12,dilation = 12,bias=False)
            self.bn3 = nn.BatchNorm2d(out_channels)
            self.conv4 = nn.Conv2d(in_channels = in_channels,out_channels = out_channels,kernel_size = 3,stride=1,padding = 18,dilation = 18,bias=False)
            self.bn4 = nn.BatchNorm2d(out_channels)
            self.conv5 = nn.Conv2d(in_channels = in_channels,out_channels = out_channels,kernel_size = 1,stride=1,padding = 0,dilation=1,bias=False)
            self.bn5 = nn.BatchNorm2d(out_channels)
            self.convf = nn.Conv2d(in_channels = out_channels * 5,out_channels = out_channels,kernel_size = 1,stride=1,padding = 0,dilation=1,bias=False)
            self.bnf = nn.BatchNorm2d(out_channels)
            self.adapool = nn.AdaptiveAvgPool2d(1)
        def forward(self,x):
            x1 = self.conv1(x)
            x1 = self.bn1(x1)
            x1 = self.relu(x1)
            x2 = self.conv2(x)
            x2 = self.bn2(x2)
            x2 = self.relu(x2)
            x3 = self.conv3(x)
            x3 = self.bn3(x3)
            x3 = self.relu(x3)
            x4 = self.conv4(x)
            x4 = self.bn4(x4)
            x4 = self.relu(x4)
            x5 = self.adapool(x)
            x5 = self.conv5(x5)
            x5 = self.bn5(x5)
            x5 = self.relu(x5)
            x5 = F.interpolate(x5, size = tuple(x4.shape[-2:]), mode='bilinear',align_corners=True)
        
            x = torch.cat((x1,x2,x3,x4,x5), dim = 1) #channels first
            x = self.convf(x)
            x = self.bnf(x)
            x = self.relu(x)
            return x
            
    if __name__ == "__main__":
    	input_tensor = torch.rand(4, 4, 128, 128)  # batch_size,input_channel,input_h,input_w
    	model = Deeplabv3Resnet101()
    	out = model(input_tensor)
    	print(out)
    
    展开全文
  • Pytorch Mask RCNN训练自定义数据集

    千次阅读 2020-05-13 17:51:49
    前言(必读) 最近做目标检测,然后记录一下 Faster RCNN、Mask RCNN来做目标检测踩得那些坑。 首先,本文并不是利用Pytorch从头去...上面都是利用pytorch从原理到具体实现的步骤。 不过本文主要还是利用Pytorch中的Tor

    前言(必读)

    最近做目标检测,然后记录一下 Faster RCNN、Mask RCNN来做目标检测踩得那些坑。

    首先,本文并不是利用Pytorch从头去实现Faster RCNN、Mask RCNN这两个结构的文章。如果有意向去从头实现并了解每一步细节可以看看下面这些视频和博客:

    来自B站的两位大佬讲解

    1. 大佬一:视频 博客 GitHub
    2. 大佬二:视频 博客 GitHub

    上面都是利用pytorch从原理到具体实现的步骤。

    不过本文主要还是利用Pytorch中的Torchvision.model中的Faster RCNN、Mask RCNN来实现迁移学习

    关于如何利用迁移学习来训练自己的数据集,这里也给出两个超赞的教程:

    1. 教程一:TORCHVISION 目标检测网络微调
    2. 教程二:手把手教你训练自己的Mask R-CNN图像实例分割模型(PyTorch官方教程)
    3. 教程三:TorchVision之MaskRCNN训练(推荐)

    看完以上三个教程,基本上利用Pytorch中的Torchvision.model中的Faster RCNN、Mask RCNN来实现迁移学习也基本上没问题了。

    下面介绍采坑:

    1. 训练自己的数据集

    这里讲一下如何制作自己的数据集训练这两个网络:

    1.1 准备图片

    首先你得准备图片数据,这个数据可能是别人给你提供的,也可能是你自己下载的,反正你得先准备好你的图片并放在一个指定的文件夹里。
    这里推荐一个批量下载网上图片的工具:IMAGE CYBORG

    1.2 数据标注工具(labelme)

    现在一般用于目标检测、实力分割的数据集制作的有两个工具:labelmelabeling。至于这两个有什么区别和联系呢,有如下解释:labelimg用于做目标检测,占内存小,labelme用于图像语义/实例分割,占内存大。

    Labelme LabelImg
    打开文件 Open Open
    打开文件夹 OpenDir OpenDir
    前后帧变换 Next & Prev Image Next & Prev Image
    标注方式 聚点分割&矩形框&圆&线 矩形框
    保存方式 JSON VOC&YOLO格式
    标注大小 内存占比大 忽略不计
    优点 标注类型多(分割和检测)标注文件另存了原始图像 存储简单,RCNN、SSD、YOLO指定标注格式,对象,明确,模式灵活
    适应场景 大部分2D分割任务,少数据量2D检测任务 单目标的2D检测任务,适用于VOC格式的数据

    1.3 如何安装labelme

    windows安装

    conda install pyqt  #conda现在已经自带pyqt5了,所以会提示你已安装
    pip install labelme
    

    使用
    在终端中执行以下命令:labelme就可以使用了,具体如何使用百度吧。

    1.4 制作数据集

    1. new_json_to_dataset.pydraw.py两个文件复制到下面labelme的路径下C:\Users\lee\Anaconda3\Lib\site-packages\labelme\cli

    2. 修改new_json_to_dataset.py中的你自己的类别名(一定得修改,不然会报错):

    NAME_LABEL_MAP = {
        '_background_': 0,
        "che": 1,
        "biao": 2
    
    }
    
    LABEL_NAME_MAP = ['0: _background_',
                      '1: che',
                      '2: biao']
    
    1. 在当前路径下打开命令行窗口,输入:python ./new_json_to_dataset.py C:\TorchVision_Maskrcnn\Maskrcnn_LPR\labelme
      其中C:\TorchVision_Maskrcnn\Maskrcnn_LPR\labelme是你存放图片的路径

    2. copy.py复制到刚刚的C:\TorchVision_Maskrcnn\Maskrcnn_LPR\labelme存放图片的路径,运行 python ./copy.py将生成gts(mask)和png(原始图片)两个文件夹

    3. 将gts(mask)里面的所有文件复制到PedMasks文件夹,png(原始图片)里面的所有文件复制到PNGImages文件夹

    1.6 安装 pycocotools

    在整个过程中你要安装 pycocotools,主要用到其中的IOU计算的库来评价模型的性能。但是这个安装并不简单,看了很多文章相对来说只有这篇文章最符合。(Windows下安装 pycocotools

    2. 定义 Faster RCNN、Mask RCNN 模型

    前言

    为什么要说这个呢?因为如果你不是很有钱,或者公司有点抠买不起一张8G以上的显卡,不改动就训练这两个网络你基本上不可能成功。懂?财大气粗可以忽略……

    因为本人就用的普通显卡(GTX1660,6G内存),训练Faster RCNN、Mask RCNN 这两个网络不要想着使用多GPU运行,我看了GitHub说了在windows上Faster RCNN、Mask RCNN暂时不支持多GPU运行。

    幸运的是,在改动一些参数之后就可以完美运行。

    Mask R-CNN是基于Faster R-CNN改造而来的。Faster R-CNN用于预测图像中潜在的目标框和分类得分.

    而Mask R-CNN在此基础上加了一个额外的分支,用于预测每个实例的分割mask。

    有两种方式来修改torchvision modelzoo中的模型,以达到预期的目的。第一种,采用预训练的模型,在修改网络最后一层后finetune。第二种,根据需要替换掉模型中的骨干网络,如将ResNet替换成MobileNet等。

    2.1 微调一个预训练好的Faster RCNN模型

    假设你想从一个在COCO上预先训练过的模型开始,并想针对你的特定类对它进行微调。下面有一种可行的方法:

    import torchvision
    from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
     
    # 在COCO上加载经过预训练的预训练模型
    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    #这个操作你是真的要有固定参数
    for param in model.parameters():
        param.requires_grad = False
        
    # 将分类器替换为具有用户定义的 num_classes的新分类器
    num_classes = 2  # 1 class (person) + background
    
    # 获取分类器的输入参数的数量
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    # 用新的头部替换预先训练好的头部
    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
    

    2.2 替换 Faster RCNN 模型的骨干网络

    场景:替换掉模型的骨干网络。举例来说,默认的骨干网络(ResNet-50)对于某些应用来说可能参数过多不易部署,可以考虑将其替换成更轻量的网络(如MobileNet)。

    import torchvision
    from torchvision.models.detection import FasterRCNN
    from torchvision.models.detection.rpn import AnchorGenerator
     
    # 加载用于分类的预先训练的模型并仅返回features
    backbone = torchvision.models.mobilenet_v2(pretrained=True).features
    # FasterRCNN需要知道骨干网中的输出通道数量。对于mobilenet_v2,它是1280,所以我们需要在这里添加它
    backbone.out_channels = 1280
     
    # 我们让RPN在每个空间位置生成5 x 3个Anchors(具有5种不同的大小和3种不同的宽高比)
    # 我们有一个元组[元组[int]],因为每个特征映射可能具有不同的大小和宽高比
    anchor_generator = AnchorGenerator(sizes=((32, 64, 128, 256, 512),),
                                       aspect_ratios=((0.5, 1.0, 2.0),))
     
    # 定义一下我们将用于执行感兴趣区域裁剪的特征映射,以及重新缩放后裁剪的大小。
    # 如果您的主干返回Tensor,则featmap_names应为[0]。
    # 更一般地,主干应该返回OrderedDict [Tensor]
    # 并且在featmap_names中,您可以选择要使用的功能映射。
    roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=[0],#featmap_names=['0']
                                                    output_size=7,
                                                    sampling_ratio=2)
    # 将这些pieces放在FasterRCNN模型中
    model = FasterRCNN(backbone,
                       num_classes=2,
                       rpn_anchor_generator=anchor_generator,
                       box_roi_pool=roi_pooler)
    

    2.3 微调一个预训练好的Mask RCNN模型(本文使用)

    import torchvision
    from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
    from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor
     
    # load an instance segmentation model pre-trained on COCO
    model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)
    for param in model.parameters():
        param.requires_grad = False
    
    num_classes = 3
    # get the number of input features for the classifier
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    
    # replace the pre-trained head with a new one
    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
    
    # now get the number of input features for the mask classifier
    in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels
    hidden_layer = 256
    
    # and replace the mask predictor with a new one
    model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask,
                                                       hidden_layer,
                                                       num_classes)
    

    2.4 替换 Mask RCNN 模型的骨干网络

    import torchvision
    from torchvision.models.detection import FasterRCNN
    from torchvision.models.detection.rpn import AnchorGenerator
     
    # 加载用于分类的预先训练的模型并仅返回features
    backbone = torchvision.models.mobilenet_v2(pretrained=True).features
    # FasterRCNN需要知道骨干网中的输出通道数量。对于mobilenet_v2,它是1280,所以我们需要在这里添加它
    backbone.out_channels = 1280
     
    # 我们让RPN在每个空间位置生成5 x 3个Anchors(具有5种不同的大小和3种不同的宽高比)
    # 我们有一个元组[元组[int]],因为每个特征映射可能具有不同的大小和宽高比
    anchor_generator = AnchorGenerator(sizes=((32, 64, 128, 256, 512),),
                                       aspect_ratios=((0.5, 1.0, 2.0),))
     
    # 定义一下我们将用于执行感兴趣区域裁剪的特征映射,以及重新缩放后裁剪的大小。
    # 如果您的主干返回Tensor,则featmap_names应为[0]。
    # 更一般地,主干应该返回OrderedDict [Tensor]
    # 并且在featmap_names中,您可以选择要使用的功能映射。
    roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=[0],
                                                    output_size=7,
                                                    sampling_ratio=2)
    mask_roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=[0],
                                                         output_size=14,
                                                         sampling_ratio=2)
    
    model = MaskRCNN(backbone,
                     num_classes=2,
                     rpn_anchor_generator=anchor_generator,
                     box_roi_pool=roi_pooler,
                     mask_roi_pool=mask_roi_pooler)
    

    3. 训练过程

    具体代码看我GitHub

    训练过程总的来说没什么,平平无奇,但还是总结一下几个我遇到的坑。

    1. batch_size不宜过大,过大GPU吃不消
    2. num_workers设置为0,我也不知道我设置成其他数会报错
    3. 学习率lr不宜设置太小,可以循序渐进
    4. 不一定要使用lr_scheduler,可以一直保持一个固定的学习率(我的0.01)由于我内存不够我给他禁了,不过相应engine.py的地方也得修改
    5. Mask RCNN 好像暂时不支持多GPU运行,(会的小伙伴下方请留言)

    此外补充一个我在训练时发生的一个BUG:

    TypeError: object of type <class 'numpy.float64'> cannot be safely interpreted as an integer.
    

    解决办法:

    找到cocoeval.py文件,大概507行。 修改self.iouThrs = np.linspace(.5, 0.95, np.round((0.95 - .5) / .05) + 1, endpoint=True)self.iouThrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05) + 1), endpoint=True)修改self.recThrs = np.linspace(.0, 1.00, np.round((1.00 - .0) / .01) + 1, endpoint=True)self.recThrs = np.linspace(.0, 1.00, int(np.round((1.00 - .0) / .01) + 1), endpoint=True)

    4. 测试

    import os
    import numpy as np
    import torch
    from PIL import Image
    
    import torchvision
    from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
    from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor
    
    import sys
    sys.path.append("./detection")
    from engine import train_one_epoch, evaluate
    import utils
    import transforms as T
    import cv2
    import cv2_util
    
    import random
    import time
    import datetime
    
    def random_color():
        b = random.randint(0,255)
        g = random.randint(0,255)
        r = random.randint(0,255)
     
        return (b,g,r)
    
    
    def toTensor(img):
        assert type(img) == np.ndarray,'the img type is {}, but ndarry expected'.format(type(img))
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = torch.from_numpy(img.transpose((2, 0, 1)))
        return img.float().div(255)  # 255也可以改为256
    
    def PredictImg( image, model,device):
        #img, _ = dataset_test[0] 
        img = cv2.imread(image)
        result = img.copy()
        dst=img.copy()
        img=toTensor(img)
    
        names = {'0': 'background', '1': 'che', '2': 'biao'}
        # put the model in evaluati
        # on mode
    
        prediction = model([img.to(device)])
    
        boxes = prediction[0]['boxes']
        labels = prediction[0]['labels']
        scores = prediction[0]['scores']
        masks=prediction[0]['masks']
    
        m_bOK=False;
        for idx in range(boxes.shape[0]):
            if scores[idx] >= 0.8:
                m_bOK=True
                color=random_color()
                mask=masks[idx, 0].mul(255).byte().cpu().numpy()
                thresh = mask
                contours, hierarchy = cv2_util.findContours(
                    thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE
                )
                cv2.drawContours(dst, contours, -1, color, -1)
    
                x1, y1, x2, y2 = boxes[idx][0], boxes[idx][1], boxes[idx][2], boxes[idx][3]
                name = names.get(str(labels[idx].item()))
                cv2.rectangle(result,(x1,y1),(x2,y2),color,thickness=2)
                cv2.putText(result, text=name, org=(x1, y1+10), fontFace=cv2.FONT_HERSHEY_SIMPLEX, 
                    fontScale=0.5, thickness=1, lineType=cv2.LINE_AA, color=color)
    
                dst1=cv2.addWeighted(result,0.7,dst,0.5,0)
    
                
        if m_bOK:
            cv2.imshow('result',dst1)
            cv2.waitKey()
            cv2.destroyAllWindows()
    
    if __name__ == "__main__":
    
        device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
        num_classes = 3
        model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=False,num_classes=num_classes)
        model.to(device)
        model.eval()
        save = torch.load('model.pth')
        model.load_state_dict(save['model'])
        start_time = time.time()
        PredictImg('test/11.jpg',model,device)
        total_time = time.time() - start_time
        total_time_str = str(datetime.timedelta(seconds=int(total_time)))
        print('Training time {}'.format(total_time_str))
        print(total_time)
    
    展开全文
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12+COCO yolo4_voc_weights.pth VOC-Test07 416x416 - ...
  • 实战人工智能框架PyTorch的模型训练

    千次阅读 2019-03-12 11:13:13
    具体步骤如下: 第一步:图像封装为向量后,将输入input向前传播,进行运算后得到输出output 第二步:将output再输入loss函数,计算loss值(是个标量)-损失函数用来得到新权重 第三步:将梯度反向传播到每个参数...

    我们关心网络结构和数据,定义损失函数,定义优化函数等。

    具体步骤如下:

    第一步:图像封装为向量后,将输入input向前传播,进行运算后得到输出output

    第二步:将output再输入loss函数,计算loss值(是个标量)-损失函数用来得到新权重

    第三步:将梯度反向传播到每个参数(优化函数):主要指标是 学习速率?  x 梯度向量g

    第四步:利用下面公式进行权重更新

    新权重w =  旧权重w  +  学习速率?  x 梯度向量g

    封装好了数据后,就可以作为模型的输入了。所以要先导入你的模型。在PyTorch中已经默认为大家准备了一些常用的网络结构,比如分类中的VGG,ResNet,DenseNet等等,可以用torchvision.models模块来导入。比如用torchvision.models.resnet18(pretrained=True)来导入ResNet18网络,同时指明导入的是已经预训练过的网络。因为预训练网络一般是在1000类的ImageNet数据集上进行的,所以要迁移到你自己数据集的2分类,需要替换最后的全连接层为你所需要的输出。因此下面这三行代码进行的就是用models模块导入resnet18网络,然后获取全连接层的输入channel个数,用这个channel个数和你要做的分类类别数(这里是2)替换原来模型中的全连接层。这样网络结果也准备好。

    model = models.resnet18(pretrained=True)
    num_ftrs = model.fc.in_features
    model.fc = nn.Linear(num_ftrs, 2)

    但是只有网络结构和数据还不足以让代码运行起来,还需要定义损失函数。在PyTorch中采用torch.nn模块来定义网络的所有层,比如卷积、降采样、损失层等等,这里采用交叉熵函数,因此可以这样定义:

    criterion = nn.CrossEntropyLoss()
    然后你还需要定义优化函数,比如最常见的随机梯度下降,在PyTorch中是通过torch.optim模块来实现的。另外这里虽然写的是SGD,但是因为有momentum,所以是Adam的优化方式。这个类的输入包括需要优化的参数:model.parameters(),学习率,还有Adam相关的momentum参数。现在很多优化方式的默认定义形式就是这样的。

    optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

    然后一般还会定义学习率的变化策略,这里采用的是torch.optim.lr_scheduler模块的StepLR类,表示每隔step_size个epoch就将学习率降为原来的gamma倍。

    代码实现如下:

    from __future__ import print_function, division

    1.导入算法的包

    import torch

    import torch.nn as nn

    import torch.optim as optim

    from torch.optim import lr_scheduler

    from torch.autograd import Variable

    import torchvision

    from torchvision import datasets, models, transforms

    import time

    import os

    2.训练模型

    def train_model(model, criterion, optimizer, scheduler, num_epochs=25):

        since = time.time()

     

        best_model_wts = model.state_dict()

        best_acc = 0.0

     

        for epoch in range(num_epochs):

            print('Epoch {}/{}'.format(epoch, num_epochs - 1))

            print('-' * 10)

     

            # Each epoch has a training and validation phase

            for phase in ['train', 'val']:

                if phase == 'train':

                    scheduler.step()

                    model.train(True# Set model to training mode

                else:

                    model.train(False# Set model to evaluate mode

     

                running_loss = 0.0

                running_corrects = 0.0

     

                # Iterate over data.

                for data in dataloders[phase]:

                    # get the inputs

                    inputs, labels = data

     

                    # wrap them in Variable

                    if use_gpu:

                        inputs = Variable(inputs.cuda())

                        labels = Variable(labels.cuda())

                    else:

                        inputs, labels = Variable(inputs), Variable(labels)

     

                    # zero the parameter gradients

                    optimizer.zero_grad()

     

                    # forward

                    outputs = model(inputs)

                    _, preds = torch.max(outputs.data, 1)

                    loss = criterion(outputs, labels)

     

                    # backward + optimize only if in training phase

                    if phase == 'train':

                        loss.backward()

                        optimizer.step()

     

                    # statistics

                    running_loss += loss.data[0]

                    running_corrects += torch.sum(preds == labels.data).to(torch.float32)

     

                epoch_loss = running_loss / dataset_sizes[phase]

                epoch_acc = running_corrects / dataset_sizes[phase]

     

                print('{} Loss: {:.4f} Acc: {:.4f}'.format(

                    phase, epoch_loss, epoch_acc))

     

                # deep copy the model

                if phase == 'val' and epoch_acc > best_acc:

                    best_acc = epoch_acc

                    best_model_wts = model.state_dict()

     

        time_elapsed = time.time() - since

        print('Training complete in {:.0f}m {:.0f}s'.format(

            time_elapsed // 60, time_elapsed % 60))

        print('Best val Acc: {:4f}'.format(best_acc))

     

        # load best model weights

        model.load_state_dict(best_model_wts)

        return model

     

    if __name__ == '__main__':

     

        # data_transform, pay attention that the input of Normalize() is Tensor and the input of RandomResizedCrop() or RandomHorizontalFlip() is PIL Image

        data_transforms = {

            'train': transforms.Compose([

                transforms.RandomSizedCrop(224),

                transforms.RandomHorizontalFlip(),

                transforms.ToTensor(),

                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

            ]),

            'val': transforms.Compose([

                transforms.Scale(256),

                transforms.CenterCrop(224),

                transforms.ToTensor(),

                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

            ]),

        }

    转换为元组image_datasets

        # your image data file

        data_dir = '/data'

        image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),

                                                  data_transforms[x]) for x in ['train', 'val']}

        # wrap your data and label into Tensor

    image_datasets元组转换为Tensor

        dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],

                                                     batch_size=4,

                                                     shuffle=True,

                                                     num_workers=4) for x in ['train', 'val']}

     

        dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}

     

        # use gpu or not

        use_gpu = torch.cuda.is_available()

     

        # get model and replace the original fc layer with your fc layer

        model_ft = models.resnet18(pretrained=True)

        num_ftrs = model_ft.fc.in_features

        model_ft.fc = nn.Linear(num_ftrs, 2)

     

        if use_gpu:

            model_ft = model_ft.cuda()

     

        # define loss function

        criterion = nn.CrossEntropyLoss()

     

        # Observe that all parameters are being optimized

        optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)

     

        # Decay LR by a factor of 0.1 every 7 epochs

        exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

     

        model_ft = train_model(model=model_ft,

                               criterion=criterion,

                               optimizer=optimizer_ft,

                               scheduler=exp_lr_scheduler,

                               num_epochs=25)

    展开全文
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 COCO-Train2017 yolo_weights.pth COCO-Val2017 416x416 38.0...
  • 全中文备注,详细说明每一步步骤. 欢迎 特点 相较于其他SSD项目,本项目在模型实现上更为合理.多GPU调用方面更加简单灵活. 将[基础网络,额外层]合并,利于替换基础网络,也便于改变网络连接情况,将[Conf分类网络和...
  • #这个参数主要是用来设置是否从断点处继续训练 if args.resume: #if isfile(args.resume): “ isfile(args.resume):里面的()放入自己的最好模型的具体位置 print("=&gt; loading checkpoint '{}'...
  • 说到模型模块的构建步骤,再来回顾一下Pytorch五大模块的流程《Pytorch:机器学习深度学习整个模型训练的总体步骤思路》 模型模块的具体框架如下: 模型创建 具体通过代码表述 ...
  • Pytorch学习(三)定义训练卷积神经网络训练图像分类器构建一个简单的神经网络定义损失函数和优化器训练网络 训练图像分类器 官方教程 我们将按顺序执行以下步骤: 1.使用使用 torchvision 2.定义卷积神经网络 3....
  • 具体包括以下几个步骤; 1.首先我们需要下载anaconda的安装包,由于在终端使用命令行进行操作,使用wget指令,在Linux终端输入 wget https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh 进行...
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12 retinanet_resnet50.pth VOC-Test07 600x600 - 81....
  • Pytorch 中文语言模型(Bert/Roberta)进一步预训练(further pretrain)1.Motivation2.相关链接3. 具体步骤3.1 依赖项3.2 数据格式3.3 代码运行4. 结果4.1 完整的目录结构4.2 训练过程4.3 训练结果5 .附录 1....
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12 voc_weights_resnet.pth VOC-Test07 - - 77.87 ...
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12 ssd_weights.pth VOC-Test07 300x300 - 79.39 VOC...
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 COCO-Train2017 efficientdet-d0.pth COCO-Val2017 512x512 33.1 ...
  • pytorch使用概括

    2019-12-20 00:10:15
    具体步骤主要包含:1. 定义torch.utils.data.Dataset数据接口 2. 使用torch.utils.data.DataLoader将数据接口封装成数据迭代器。 数据读取部分包含如何将你的数据转换成PyTorch框架的Tensor数据类型。当使用PyTorch...
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12+COCO yolov4_tiny_weights_voc.pth VOC-Test07 416x...
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12 centernet_resnet50_voc.pth VOC-Test07 512x512 - ...
  • pytorch中使用tensorboard踩坑记录 在pytorch代码中想通过tensorboard查看训练过程中的loss、acc、图片等等,需要先激活tensorflow环境,在tensorflow中使用命令,具体步骤如下:
  • 尽管pytorch代码看起来简单而具体,但是发生的许多细微变化是不可见的,因此在使用pytorch代码时,它有助于彻底理解运行时模型。 例如,考虑以下代码: torch.nn.cross_entropy(model(images.cuda()), labels
  • 训练(可能包含训练过程可视化) —> 测试 所以我们在自己写代码的时候也基本上就按照这四个大模块四步走就ok了 官方给的这个例子呢,是先进行的第二步数据处理和加载,然后定义网络,这其实没什么关系。 此例...
  • 我先说下我的具体的check步骤。 检查代码是否上传失败, 重新上传代码检查数据集上传是否正确检查代码数据集导入路径是否正确检查dataloader returen的data和label 最后发现os.listdir() 在ubuntu中是乱序读入数据的...
  • pytorch: 准备、训练和测试自己的图片数据 - denny402 - 博客园 ...pytorch: 准备、训练和测试自己的图片数据 - ...pytorch重新加载参数的代码,具体步骤_邹小驴-CSDN博客_args.resume https://blog.csdn.net/zouxiaolv
  • 神经网络 Pytorch中使用torch.nn...具体训练过程在后续章节记录。 1.定义神经网络 import torch import torch.nn as nn import torch.nn.functional as F # 定义网络 class Net(nn.Module): def __init__(self): sup
  • 训练步骤 How2train 评估步骤 How2eval 参考资料 Reference 性能情况 训练数据集 权值文件名称 测试数据集 输入图片大小 mAP 0.5:0.95 mAP 0.5 VOC07+12 yolov4_mobilenet_v1_voc.pth VOC-Test07 416x416 -...
  • 转换的具体步骤请参考我之前的文章<使用NCNN在移动端部署深度学习模型> 需要特别说明的地方在于关于onnx支持的操作算子问题,目前onnx的最新版本已经基本支持绝大部分的pytorch操作符,但是由于最终是要在...
  • 机器学习的模型训练步骤一般来讲都要经过读取数据、建立模型、选择损失函数、选择优化器、迭代训练最后得出模型。具体流程如下图: 在模型模块部分,分为两个部分,模型创建和权值初始化,而模型创建又分为构建网络...
  • 参考资料:...图片分类模型的具体步骤: 1.加载数据,对数据进行归一化处理(使用torchvision) 2.定义卷积神经网络 3.定义损失函数 4.在训练集上训练神经网络 5.在测...
  • 具体安装及训练、测试步骤: https://github.com/xinyu-ch/faster-rcnn.pytorch 参考了博客https://blog.csdn.net/Xinyu_cheng/article/details/89683832

空空如也

空空如也

1 2 3 4
收藏数 67
精华内容 26
关键字:

pytorch具体训练步骤