K折交叉验证:每轮都将训练集分为训练集+验证集两部分,K-1折作为训练集而1折作为测试集。

它是一种用于评估模型的方法,一般数据集小,选择的测试集样本不足可能会导致评估结果不稳定,而使用这种方法可以使测试集样本较多,使结果稳定。并且将数据都使用了一遍作为训练和测试,就具有说服力。

下面是10折交叉验证的原理图:将数据集分为十折,每轮取其中九折作为训练集,剩下一折作为验证集。每轮的验证集需要记录结果最后返回平均值作为精度,从而对模型进行评估。

交叉验证

它的代码实现方法是在每一个Epoch中使用交叉验证,并且将这一轮的十折交叉后的eva的平均值作为返回的Acc

# shuffle是代表每一折的数据被随机打乱,如果为False,就是顺序性的每一轮选不一样的数据作为验证集。
kf = kFold(n_splits=5, shuffle=True, random_state=42)
epoch in range(1, EPOCHS+1):
for fold, (train_indexes, val_indexes) in enumerate(kf.split(dataset)):
train_dataset = torch.utils.data.Subset(dataset, train_indexes)
val_dataset = torch.utils.data.Subset(dataset, val_indexes)
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, drop_last=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)

核心部分代码如上所示:需要解释的是kFold实质只是每轮将dataset的图像顺序编号找到并且提取出来。

在一份train代码中,对于数据需要做预处理以及增强操作。

常用的数据增强方法为角度变化、明暗度变化,当然明暗度变化也可以作为预处理中的部分看待,看用于什么地方。

torchvision.transfoms可以使用Compose对数据进行一系列的变换和处理。方法是transforms.Compose(list)

对于图像的输入处理可以使用**transforms.Resize()*函数。如果是缩放短边,并保持长宽比不变的话就用Resize(224);如果需要把长短边都变成224224就需要写Resize([224,224])。

用于对输入的数据进行数据增强和预处理的方法有:

  • transforms中的中心裁剪使用CenterCrop(224)就会裁切成(224,224)的格式,而如果使用CenterCrop([h,w])就会切成(h,w)的格式;
  • transforms中的RandomHorizontalFlip()是水平翻转图像,默认的概率是p=0.5,这样可以对图片进行概率的翻转。这里我们需要知道:tran
  • transforms中的ToTensor作用是将PIL image或ndarray数据转化为tensor数据,并且使用将所有像素点除以255以归一化到[0,1]。注意:tensor数据维度为[C,H,W],而图像的np.array数据是[H,W,C],所以ToTensor还有作用就是reshape的作用。
  • Normalize操作是将tensor图片归一化,不支持PIL image格式,所以对于PIL格式的图片,Normalize操作必须要在Totensor之后。有了上面的ToTensor再进行transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])就相当于把每张图像的每个像素点的值都缩小到[-1,1]之间了。
  • torchtoolbox.transform中的Cutout随机将图像中的某些部分遮挡掉,以减少模型对局部的依赖性。它的内部是随机选择一个趋于并将该区域内的像素值设置为0。它与torchvision.transforms中的RandomErasing是一样的效果。

此外我们需要了解的是:

  1. 将PIL图像转化为Numpy数组的方法为:

    img = Image.open(img_path)
    imgArray = np.array(img)
    # 得到的维度为(H,W,C)
  2. 将Numpy转换为PIL的方法为:

    img = Image.fromarray(imgArray)
    img.show()
  3. Numpy转tensor也可以:

    img_tensor = torch.tensor(imgArray)
  4. tensor转Numpy:

    imgArray = img_tensor.numpy()
    #或者
    imgArray = np.array(img_tensor)
  5. tensor转Image:

    to_pil = transforms.ToPILImage()
    img = to_pil(img_tensor)
    img.show()
  6. list转numpy

    array=numpy.array(list)
  7. list转tensor

    tensor=torch.Tensor(list)
  8. array转为list

    list=numpy.tolist()
  9. tensor转list

    list=tensor.numpy().tolist()

list,array,tensor,numpy的辨别

array和tensor用法一致,只能存储单一数据类型的元素。

  • list(列表)可以存储不同类型的数据,但是整体不够高效。
  • array(数组)较为高效,python本身没有数组这个概念,但是可以通过numpy.array来实现
  • tensor(张量),与numpy的ndarray相互转换,唯一不同的是tensor可以在GPU上运行,支持自动求导,而numpy的ndarray只能在cpu上运行。

torchvision.datasets.ImageFolder的作用是将一个文件夹下已经分好的每一个子文件夹分配一个label,子文件夹中的图像数据作为data,data对应了label。使用方法是dataset = datasets.ImageFolder(root,transforms)。

或者我们可以自己打标签:

DataLoader中的shuffle参数=True是指在每一个epoch里数据集会被打乱再按Batch_Size的数量来取数据,这样每个epoch里Batch_Size就不一样了。能够避免模型学习到类似排序等习惯性偏差,提高模型的泛化能力。