计算机视觉知识点之COCO数据集和pytorch

COCO数据集方面:

COCO数据集现在有3种标注类型:

1, object instances(目标实例),

2, object keypoints(目标上的关键点),

3, image captions(看图说话)

使用JSON文件存储。每种类型又包含了训练验证,所以共6个JSON文件。

 

Object Instance 类型的标注格式

1,整体JSON文件格式

数据集中的instances_train2017.json、instances_val2017.json这两个文件就是这种格式

从头至尾按照顺序分为以下段落:

    "info": info,

    "licenses": [license],

    "images": [image],

    "annotations": [annotation],

    "categories": [category]

其中,info、licenses、images这三个结构体/类型,在不同的JSON文件中这三个类型是一样的,定义是共享的。

不共享的是annotation和category这两种结构体,他们在不同类型的JSON文件中是不一样的。

images数组、annotations数组、categories数组的元素数量是相等的,等于图片的数量。

  1. annotations字段

annotations字段是包含多个annotation实例的一个数组,annotation类型本身又包含了一系列的字段。

segmentation格式取决于这个实例是一个单个的对象(即iscrowd=0,将使用polygons格式)还是一组对象(即iscrowd=1,将使用RLE格式)。如下所示:

annotation{

    "id": int,

    "image_id": int,

    "category_id": int,

    "segmentation": RLE or [polygon],

    "area": float,

    "bbox": [x,y,width,height],

    "iscrowd": 0 or 1,

}

  1. categories字段

categories是一个包含多个category实例的数组,而category结构体描述如下:

{

    "id": int,

    "name": str,

    "supercategory": str,

}

 

 

Object Keypoint 类型的标注格式

1,整体JSON文件格式

数据集中的person_keypoints_train2017.json、person_keypoints_val2017.json这两个文件就是这种格式。

Object Keypoint这种格式的文件从头至尾按照顺序分为以下段落,看起来和Object Instance一样啊:

{

    "info": info,

    "licenses": [license],

    "images": [image],

    "annotations": [annotation],

    "categories": [category]

}

其中,info、licenses、images这三个结构体/类型 在第一节中已经说了,在不同的JSON文件中这三个类型是一样的,定义是共享的。

不共享的是annotation和category这两种结构体,他们在不同类型的JSON文件中是不一样的。

images数组和annotations数组的元素数量是相等的,等于图片的数量。

 

 

2,annotations字段

这个类型中的annotation结构体包含了Object Instance中annotation结构体的所有字段,再加上2个额外的字段。

新增的keypoints是一个长度为3*k的数组,其中k是category中keypoints的总数量。每一个keypoint是一个长度为3的数组,第一和第二个元素分别是x和y坐标值,第三个元素是个标志位v,v为0时表示这个关键点没有标注(这种情况下x=y=v=0),v为1时表示这个关键点标注了但是不可见(被遮挡了),v为2时表示这个关键点标注了同时也可见。

num_keypoints表示这个目标上被标注的关键点的数量(v>0),比较小的目标上可能就无法标注关键点。

annotation{

    "keypoints": [x1,y1,v1,...],

    "num_keypoints": int,

    "id": int,

    "image_id": int,

    "category_id": int,

    "segmentation": RLE or [polygon],

    "area": float,

    "bbox": [x,y,width,height],

    "iscrowd": 0 or 1,

}

3,categories字段

最后,对于每一个category结构体,相比Object Instance中的category新增了2个额外的字段,

keypoints是一个长度为k的数组,包含了每个关键点的名字;

skeleton定义了各个关键点之间的连接性(比如人的左手腕和左肘就是连接的,但是左手腕和右手腕就不是)。目前,COCO的keypoints只标注了person category (分类为人)

{

    "id": int,

    "name": str,

    "supercategory": str,

    "keypoints": [str],

    "skeleton": [edge]

}

pytorch方面:

基础知识:

1:PyTorch是什么?

这是一个基于Python的科学计算包,其旨在服务两类场合:

替代numpy发挥GPU潜能

一个提供了高度灵活性和效率的深度学习实验性平台

2:Numpy桥

将Torch的Tensor和numpy的array相互转换简直就是洒洒水啦。注意Torch的Tensor和numpy的array会共享他们的存储空间,修改一个会导致另外的一个也被修改。

 

第一题:Tensor的五种基本数据类型:

32位浮点型:torch.FloatTensor。 (默认)

64位浮点型:torch.DoubleTensor。

16位整型:torch.ShortTensor。
32位整型:torch.IntTensor。

64位整型:torch.LongTensor。
除以上数字类型外,还有 byte和chart型

第二题:基本操作

1:生成标量 a = torch.tensor()   tensor转化为Python数据 a.item()

2:tensor转化为numpy array   a.numpy()   反之 torch.from_numpy(a)

3:torch.view 改变张量的维度和大小 和Numpy的reshape类似

a = torch.rand(2,2)

a.view(1,4)

4:沿着行取最大值

X = torch.randn(2,2)

max_value, max_idx = torch.max(x, dim=1)

Print(max_value, max_idx)

5:每行x求和

Sum_x = torch.sum(x, dim=1)

Print(sum_x)

 

第三题:设备之间的转换

1: .cuda的方法将tensor移动到gpu

gpu_a = cpu_a.cuda()

2:  .cpu的方法将tensor移动到cpu

cpu_b = gpu_a.cpu()

3:多GPU的情况下  .to方法确定使用哪个设备

device = torch.device(cudaif torch.cuda.is_available() else cpu)

Print(device)

gpu_b = cpu_b.to(device) # 将tensor传送到设备

第四题:autograd 自动求导

PyTorch中的神经网络都来自于autograd包

1:autograd.Variable 这是这个包中最核心的类。 它包装了一个Tensor,并且几乎支持所有的定义在其上的操作。一旦完成了你的运算,你可以调用 .backward()来自动计算出所有的梯度。

通过属性 .data 来访问原始的tensor,而关于这一Variable的梯度则集中于 .grad 属性中。

2:Variable 和 Function 二者相互联系并且构建了一个描述整个运算过程的无环图。每个Variable拥有一个 .creator 属性,其引用了一个创建Variable的 Function。(除了用户创建的Variable其 creator 部分是 None)。

如果你想要进行求导计算,你可以在Variable上调用.backward()。 如果Variable是一个标量(例如它包含一个单元素数据),你无需对backward()指定任何参数,然而如果它有更多的元素,你需要指定一个和tensor的形状想匹配的grad_output参数。

第五题:神经网络

使用 torch.nn 包可以进行神经网络的构建。

现在你对autograd有了初步的了解,而nn建立在autograd的基础上来进行模型的定义和微分。

nn.Module中包含着神经网络的层,同时forward(input)方法能够将output进行返回。

 

神经网络训练过程:

  1. 定义一个可学习参数的神经网络
  2. 对一个输入数据集进行迭代
  1. 神经网络预处理数据
  2. 计算loss
  3. 反向传播
  4. 更新权重   weight = weight + learning_rate * gradient

注意: torch.nn 只接受小批量的数据
整个torch.nn包只接受那种小批量样本的数据,而非单个样本。 例如,nn.Conv2d能够结构一个四维的TensornSamples x nChannels x Height x Width。
如果你拿的是单个样本,使用input.unsqueeze(0)来加一个假维度就可以了。

第六题:数据处理

通常来讲,当你处理图像,声音,文本,视频时需要使用python中其他独立的包来将他们转换为numpy中的数组,之后再转换为torch.*Tensor。

  1. 图像的话,可以用Pillow, OpenCV。
  2. 声音处理可以用scipy和librosa。
  3. 文本的处理使用原生Python或者Cython以及NLTK和SpaCy都可以。

 

 

Pytorch图像数据的读取

适用于不是分类问题,或者标签不是简单的文件名的映射
首先:定义一个Dataset的派生类,并且对数据的处理、数据增强之类的都需要自己定义,这些定义的时候利用__call_()就可以了
第一步:定义一个Dataset的派生类,这个派生类目标是重载两个魔法方法 __ len __ (),__ getitem__()

  1. __ len __ () 函数是在调用 len(对象)的时候会被调用并返回,重载的目的是,在调用的时候返回数据集的大小
  2. __getitem __() 函数可让对象编程可迭代的,定义了它之后就可以使得对像被for语句迭代,重载它的目的是能够使得它每次都迭代返回数据集的一个样本

 

加载包

import os

import glob

import cv2

import numpy as np

from torchvision import transforms as T

from torch.utils.data import Dataset, DataLoader

所以无论是自定义的dataset,或是 ImageFolder得到的dataset,因其都继承自utils.data.Dataset, 故以上方法两种方法都有。

 

#数据读取方式

transform = T.Compose([

    T.Resize(224),

    T.CenterCrop(224),

    T.RandomHorizontalFlip(),

    T.RandomSizedCrop(224),

    T.ToTensor(),#将图片从0-255变为0-1

    T.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])#标准化到[-1,1]

])

 

# 相当于一个派生类

class Test_Data(Dataset):

    def __init__(self,data_root,mask_root,transforms=None):

 

        data_image = glob.glob(data_root+'/*.jpg')

        self.data_image = data_image

 

        mask_image = glob.glob(mask_root+'/*.jpg')

        self.mask_image = mask_image

 

        self.transforms = transforms

 

# getitem则是定义了迭代返回一个数据集样本,返回值可以是包含训练样本和标签的list,也可以是字典输入索引,返回对应的图片与标签根据这个不同后面的用法也回不太一样(无非就是索引是数字还是key的区别)

    def __getitem__(self, index):

 

        data_image_path = self.data_image[index]

        mask_image_path = self.mask_image[index]

 

        image_data = cv2.imread(data_image_path,-1)

        mask_data = cv2.imread(mask_image_path,-1)

        if self.transforms:

            image_data = self.transforms(image_data)

            mask_data = self.transforms(mask_data)

 

        return image_data,mask_data

 

# 读取出保存整个数据集的表格,然后len就是返回了数据集的数目

    def __len__(self):

        return len(self.data_image)

 

 

 

 

Dataset一般还会要求输入对数据集的操作,

  1. 要是不想数据增强,就加个ToTensor就可以(因为要转换成tensor才能训练)
  2. 要是想数据增强就自己加一些新的类(没错,ToTensor、各种数据增强的函数其实都是一个类,然后定义的一个对象),接着用transforms.Compose把他们连在一起就可以了。上面的transform写的是None,就是不进行数据处理,直接输出

 

Dataset=Test_Data(data_root='../../test_image/37_simple/0001/data',mask_root='../../test_image/37_simple/0001/mask')

 

#第一种调用,不常用

for data,mask in dataset:

     print(data.shape,mask.shape)

 

下面两种应该在训练过程中更加好:

test_data_loader = DataLoader(dataset=dataset, num_workers=1, batch_size=1, pin_memory=True, shuffle=True,drop_last=True)

 

  1. ampler: 样本抽样。定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数。

#第1

# for i,data in enumerate(test_data_loader,0):

#     print(data[0].shape,'..')

#     print(data[1].shape,'...')

#第2种

for data_batch,mask_batch in test_data_loader:

print(data_batch.size(),mask_batch.size)

注意事项

  1. 使用GPU训练的时候,要把模型、tensor都放在GPU上,就是后面加个.cuda(),
  2. 定义模型对象的时候,cnn.cuda()
  3. 输入进模型、计算loss的时候,b_x.cuda() b_y.cuda()
  4. tensor a 转numpy a.data.numpy()
  5. 如果是在GPU上,要先a.cpu().data.numpy()

nn.CrossEntropyLoss()这个损失函数是个大坑,它是softmax + 归一化,所以使用这个损失函数的时候模型最后就不要再加softmax了,不然会发现自己的损失就那几个值,也降不下去
输入模型的 input图像,格式为(batch_size,Nc,H,W)的四维矩阵

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页