前言


  前段时间因为一些事情没有时间或者心情学习,现在两个多月过去了,事情结束了,心态也调整好了,所以又来接着学习Pytorch。这篇笔记主要是关于数据预处理过程、数据集标准化与数据集均值标准差计算的,前两者都是使用torchvision中的transforms里的方法来实现。torchvision是一个库,最常用到的主要是其中的datasets、models和transforms。datasets包含了许多数据集如MNIST、COCO、ImageNet、CIFAR、VOC等。models包含了许多模型如AlexNet、VGG、ResNet、DenseNet、GoogLeNet等,其中有些模型还是预训练好的。本笔记的知识框架主要来源于深度之眼,并作了一些相关的拓展,拓展内容主要源自对torch文档的翻译理解。

  数据切分参考:深度之眼Pytorch打卡(六):将数据集切分成训练集、验证集和测试集的方法
  数据读取参考:深度之眼Pytorch打卡(七):Pytorch数据读取机制,DataLoader()和Dataset


预处理过程


  读入的数据都是需要进行预处理的,在数据读取机制这篇笔记中虽然只是记录如何读取数据,但是也用了一种数据预处理方式,即在一次读取完成后,使用transforms.ToTensor()将PIL图像转换成数据范围为[0,1]的张量。实际的数据预处理,会用到很多方法,他们往往不是在要使用单独调用,而是会以组合形式出现。transforms.Compose()中以list的形式存放若干transforms方法,就可以实现这些方法的组合,定义一个全局的变量,以后就可以在任何地方使用用该变量,进而实现这些方法的整体调用。

#  预处理,标准化与图像增强normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 依通道标准化train_transformer = transforms.Compose([transforms.Resize(256),transforms.RandomResizedCrop((224), scale=(0.5, 1.0)),transforms.RandomHorizontalFlip(),transforms.ToTensor(),normalize
])val_transformer = transforms.Compose([transforms.Resize(224),transforms.CenterCrop(224),transforms.ToTensor(),normalize
])

  数据预处理的过程渗透在整个训练迭代过程中,每读入一张图片就会给它用一次预处理组合。通过数据读取机制这篇笔记可以知道,数据读取真正的实现是在我们定义的DataSet类的__getitem__方法中,如果要进行数据预处理就是在这里实现的,读取一张图片,调用一次预处理组合,进行一次预处理,如下所示。

class DataSet(Dataset):def __init__(self, , , ,transform=None):...self.transform = transform...def __getitem__(self, idx):...if self.transform:image = self.transform(image)...

数据标准化


  • Normalize()方法
torchvision.transforms.Normalize(mean, std, inplace=False)
output[channel] = (input[channel] - mean[channel]) / std[channel]

  数据标准化的目的,是为了将数据分布的均值化成0,标准差化成1。模型一般被初始化成0均值,所以这样有利于加快训练过程中模型的收敛。原本需要自己计算自己数据集的均值和标准差来进行标准化,但是许多项目直接采用了imagenet的均值和标准差来进行标准化,所以经常见到这样的一组数字:mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225],下表是一些数据集的均值与标准差。

表1.一些数据集均值标准差

数据集 均值 方差
cifar10 [0.491, 0.482, 0.446] [0.247, 0.243, 0.261]
coco [0.471, 0.448, 0.408] [0.234, 0.239, 0.242]
imagenet [0.485, 0.456, 0.406] [0.229, 0.224, 0.225]
MNIST [0.1307] [ 0.3081]
  • 数据集标准差与均值计算

  1.cifar10数据集

  cifar10是Alex Krizhevsky, 和Geoffrey Hinton等做的数据集,10类共6万张图,每类6千张,每张图尺寸为(3,32,32),训练集5万张,测试集1万张。pytorch直接提供了cifar10的接口,调用一个函数就可以直接获得该数据集,而且该数据集比较小,也有人算过它的均值标准差,适合用来做实验。

torchvision.datasets.CIFAR10(root, train=True, transform=None, target_transform=None, download=False)

  CIFAR10是一个继承于抽象类Dataset的一个类,里面不仅复写了__getitem__()__len__()方法,还写有数据集下载,解压和验证数据集完整性等的方法。数据集下载完成后形成的的CIFAR10,就相当于实例化后的Dataset,可以被DataLoader直接使用。
  root:数据集存放的位置。
  train:为True时表示是训练集的Dataset实例化,反之是测试集。
  transform:前面提到数据预处理是在__getitem__()中实现的,所以这里需要有此参数,不过此间目的是算均值标准差,故只需用ToTensor()归一化一下数据便可。
  download:为True,且root目录下没有解压后完整的数据集,则从该处下载数据集并解压到root目录下。

  对于较小的数据集,可以计算整个数据集的均值标准差,但是对于很大的数据集,则采用随机抽取若干样本的均值和标准差来代替整体的标准差。用numpystdmean方法来求标准差与均值,通过axis选择求取均值的维度。对于(50000,3,32,32)的数据,axis=(0, 2, 3)可以理解为先计算维度0的均值与方差,即压缩0维,完成后将得到一幅彩色图像(1,3,32,32)->(3,32,32),然后计算维度2的均值与方差,完成后将得到三个向量,即(1,3,1,32)->(3,32),最后计算维度3的均值与方差,完成后为一向量(3,1)即为所求。

np.mean(data_selected.numpy(), axis=(0, 2, 3))
std = np.std(data_selected.numpy(), axis=(0, 2, 3))

  如下笔者提供的方法。用随机打乱索引的方式来随机选取样本。由于数据集很小,所以ratio设的1,代表用全部数据来计算。注意到这里的dataset里是带有数据的,如果没有数据则不能用。
  代码:

import torch
import random
import time
from torchvision import datasets
from torchvision import transforms
import numpy as npdef get_std_mean(dataset, ratio=1):data_x = dataset.datadata_x = torch.transpose(torch.from_numpy(data_x), dim0=1, dim1=3) #(50000,32,32)->(50000,3,32,32)data_num = len(data_x)idx = list(range(data_num))random.shuffle(idx)                                                #产生随机索引data_selected = data_x[idx[0:int(ratio * data_num)]]mean = np.mean(data_selected.numpy(), axis=(0, 2, 3)) / 255std = np.std(data_selected.numpy(), axis=(0, 2, 3)) / 255return mean, stdif __name__ == '__main__':train_dataset = datasets.CIFAR10('./data',train=True, download=False,transform=transforms.ToTensor())test_dataset = datasets.CIFAR10('./data',train=False, download=False,transform=transforms.ToTensor()time0 = time.time()train_mean, train_std = get_std_mean(train_dataset)test_mean, test_std = get_std_mean(test_dataset)time1 = time.time()time = time1 - time0print(time)print(train_mean, train_std)print(test_mean, test_std)

  结果:符合上表数据。

1.7163739204406738
[0.49139968 0.48215841 0.44653091] [0.24703223 0.24348513 0.26158784]
[0.49421428 0.48513139 0.45040909] [0.24665252 0.24289226 0.26159238]

  改自这篇博客提供的方法。其巧妙的运用了DataLoader来随机选择一个batch的数据,而使得代码非常简洁,但是耗时却长了很多。由下图可知,DataLoader也是通过打乱的索引来随机获取数据的,但是由于其此处用循环来得到一个batch索引,加上还要进行如transform的其他许多操作,故而慢了不少。该方法无论dataset是否带数据都可以使用。

  代码:

import torch
import random
import time
from torchvision import datasets
from torchvision import transforms
import numpy as npdef get_mean_std(dataset, ratio=1):dataloader = torch.utils.data.DataLoader(dataset, batch_size=int(len(dataset)*ratio),shuffle=True, num_workers=0)data = iter(dataloader).next()[0]   # 一个batch的数据mean = np.mean(data.numpy(), axis=(0,2,3))std = np.std(data.numpy(), axis=(0,2,3))return mean, stdif __name__ == '__main__':train_dataset = datasets.CIFAR10('./data',train=True, download=False,transform=transforms.ToTensor())test_dataset = datasets.CIFAR10('./data',train=False, download=False,transform=transforms.ToTensor())time0 = time.time()train_mean, train_std = get_mean_std(train_dataset)test_mean, test_std = get_mean_std(test_dataset)time1 = time.time()time = time1 - time0print(time)print(train_mean, train_std)print(test_mean, test_std)

  结果:符合上表数据,时间要长4-5倍。

7.437113046646118
[0.49140078 0.48215902 0.44653085] [0.24703279 0.24348494 0.26158768]
[0.49421415 0.48513135 0.4504101 ] [0.24665275 0.24289201 0.26159224]

  2.自定义的数据集

  自定义的数据集,在数据读取机制这篇笔记中所述的方法获得的实例化的Dataset中没有数据,只有数据的地址信息。在使用时,需要一个batch一个batch的从数据地址读取数据,所以用上述第二种方法更方便一些。
  main.py

from tools.dataload import DataSet
from tools.get_mean_std import get_mean_std
import oslabel_name = {'unmasking': 0, 'masking': 1}if __name__ == '__main__':train_set_path = os.path.join('data', 'train_set')val_set_path = os.path.join('data', 'val_set')test_set_path = os.path.join('data', 'test_set')train_set = DataSet(data_path=train_set_path, label_name=label_name)val_set = DataSet(data_path=val_set_path, label_name=label_name)test_set = DataSet(data_path=test_set_path, label_name=label_name)train_mean, train_std = get_mean_std(train_set)val_mean, val_std = get_mean_std(val_set)print('train_set:', train_mean, train_std)print('val_set:', val_mean, val_std)

  get_mean_std.py

import torch
import random
import time
from torchvision import datasets
from torchvision import transforms
import numpy as npdef get_mean_std(dataset, ratio=1):dataloader = torch.utils.data.DataLoader(dataset, batch_size=int(len(dataset) * ratio),shuffle=True, num_workers=0)data = iter(dataloader).next()[0]  # 一个batch的数据mean = np.mean(data.numpy(), axis=(0, 2, 3))std = np.std(data.numpy(), axis=(0, 2, 3))return mean, stddef get_std_mean(dataset, ratio=1):data_x = dataset.datadata_x = torch.transpose(torch.from_numpy(data_x), dim0=1, dim1=3)  # (50000,32,32)->(50000,3,32,32)data_num = len(data_x)idx = list(range(data_num))random.shuffle(idx)  # 产生随机索引data_selected = data_x[idx[0:int(ratio * data_num)]]mean = np.mean(data_selected.numpy(), axis=(0, 2, 3)) / 255std = np.std(data_selected.numpy(), axis=(0, 2, 3)) / 255return mean, std

  dataload.py

import os
from PIL import Image
from torch.utils.data import DataLoader
from torchvision import transforms
from torch.utils.data import Datasetlabel_name = {}class DataSet(Dataset):def __init__(self, data_path, label_name):  # 除了这两个参数之外,还可以设置其它参数self.label_name = label_name#self.data_info = get_info_list(data_path)self.data_info = get_info(data_path, label_name)def __getitem__(self, index):label, img_path = self.data_info[index]pil_img = Image.open(img_path).convert('RGB')  # 读数据re_img = transforms.Resize((32, 32))(pil_img)img = transforms.ToTensor()(re_img)  # PIL转张量return img, labeldef __len__(self):return len(self.data_info)def get_info(data_path, label_name):data_info = list()for root_dir, sub_dirs, _ in os.walk(data_path):for sub_dir in sub_dirs:file_names = os.listdir(os.path.join(root_dir, sub_dir))img_names = list(filter(lambda x: x.endswith('.jpg'), file_names))for i in range(len(img_names)):img_path = os.path.join(root_dir, sub_dir, img_names[i])img_label = label_name[sub_dir]data_info.append((img_label, img_path))return data_infodef get_info_list(list_path):data_info = list()with open(list_path, mode='r') as f:lines = f.readlines()for j in range(len(lines)):img_label = int(lines[j].split(',')[0])img_path = lines[j].split(',')[1].replace('\n', '')data_info.append((img_label, img_path))return data_info

  结果:

train_set: [0.58094215 0.53512526 0.5137592 ] [0.29900312 0.2990571  0.30414605]
val_set: [0.57392234 0.5163339  0.49625048] [0.2890443  0.2879651  0.29451588]

参考


  https://blog.csdn.net/weixin_38533896/article/details/85951903
  https://blog.csdn.net/cvsvsvsvsvs/article/details/94149896

深度之眼Pytorch打卡(九):Pytorch数据预处理——预处理过程与数据标准化(transforms过程、Normalize原理、常用数据集均值标准差与数据集均值标准差计算)相关推荐

  1. 深度之眼课程打卡-python入门05

    目录 文章目录 目录 前言 内容 一.数据结构介绍 1.Series的创建 2.DataFrame的创建 二.数据索引index 1.通过索引值或索引标签获取数据 2.自动化对齐 三.利用pandas ...

  2. 深度之眼课程打卡-统计学习方法01

    目录 文章目录 目录 前言 绪论 作业打卡 L1和L2范式 ROC曲线 一 roc曲线 二 如何画roc曲线 三 为什么使用Roc和Auc评价分类器 补充 混淆矩阵 参考 前言 为了增加实战经验,选择 ...

  3. 深度之眼Pytorch打卡(十三):Pytorch全连接神经网络部件——线性层、非线性激活层与Dropout层(即全连接层、常用激活函数与失活 )

    前言   无论是做分类还是做回归,都主要包括数据.模型.损失函数和优化器四个部分.数据部分在上一篇笔记中已经基本完结,从这篇笔记开始,将学习深度学习模型.全连接网络MLP是最简单.最好理解的神经网络, ...

  4. 【深度之眼PyTorch框架班第五期】作业打卡01:PyTorch简介及环境配置;PyTorch基础数据结构——张量

    文章目录 任务名称 任务简介 详细说明 作业 1. 安装anaconda,pycharm, CUDA+CuDNN(可选),虚拟环境,pytorch,并实现hello pytorch查看pytorch的 ...

  5. pytorch 指定卡1_[原创][深度][PyTorch] DDP系列第一篇:入门教程

    引言 DistributedDataParallel(DDP)是一个支持多机多卡.分布式训练的深度学习工程方法.PyTorch现已原生支持DDP,可以直接通过torch.distributed使用,超 ...

  6. 【完结】12大深度学习开源框架(caffe,tf,pytorch,mxnet等)快速入门项目

    这是一篇总结文,给大家来捋清楚12大深度学习开源框架的快速入门,这是有三AI的GitHub项目,欢迎大家star/fork. https://github.com/longpeng2008/yousa ...

  7. PyTorch框架学习八——PyTorch数据读取机制(简述)

    PyTorch框架学习八--PyTorch数据读取机制(简述) 一.数据 二.DataLoader与Dataset 1.torch.utils.data.DataLoader 2.torch.util ...

  8. 深度学习入门笔记(十五):深度学习框架(TensorFlow和Pytorch之争)

    欢迎关注WX公众号:[程序员管小亮] 专栏--深度学习入门笔记 声明 1)该文章整理自网上的大牛和机器学习专家无私奉献的资料,具体引用的资料请看参考文献. 2)本文仅供学术交流,非商用.所以每一部分具 ...

  9. 常用深度学习框——Caffe/TensorFlow / Keras/ PyTorch/MXNet

    常用深度学习框--Caffe/TensorFlow / Keras/ PyTorch/MXNet 一.概述 近几年来,深度学习的研究和应用的热潮持续高涨,各种开源深度学习框架层出不穷,包括Tensor ...

最新文章

  1. mysql的odbc连接字符串_MySQL :: linux ODBC连接mysql
  2. python代码大全o-python文件编码及执行
  3. 基于Linux的socket编程模板
  4. Linux开发环境搭建三 使用mount -t cifs 挂载windows共享目录方法与问题解决
  5. SpringCloud-使用熔断器仪表盘监控熔断
  6. trigger 触发器(mysql)
  7. 测试题的答案(技术博客)
  8. 怎么清空topic数据_20.Roscpp/Rospy:Topic_demo
  9. service程序改为windows窗体展示
  10. 原型设计中展示数据的“行模式”与“列模式”的选择
  11. 制作一个企业网站——html华为官网购物商城项目的设计与实现
  12. [面试] 步步为营:吉大学士的PG宝洁面经
  13. php app用户验证失败,无法验证app需要互联网连接以认证 建议更换登陆的AppleID
  14. 校学 离散数学主析取合取范式 做题心得
  15. select函数到底该怎么用?
  16. 什么是抖音SEO? 抖音SEO优化怎么做?如果做好抖音推广优化呢?
  17. 为何Excel表格部分选项是灰色的,无法选择?
  18. 【阅读】Leaf——美团点评分布式ID生成系统
  19. 吉大c 语言程序设计奥鹏作业,吉大19年9月《C语言程序设计》作业考核试题
  20. mysql 想在某个时间上再加上一段时间

热门文章

  1. 推荐一款功能强大的js 在线编辑器
  2. 了解如何在Google Colaboratory中构建深度学习系统
  3. Excel VBA中判断word文件是否打开,未打开则打开该文件
  4. COM 组件设计与应用
  5. 使用Java、Servlet 生成二维码
  6. C/C++财务报销审批
  7. LAN端口和WAN端口的区别
  8. MB、MiB、GB、GiB的定义
  9. oraclerman清理归档
  10. Dijit、ExtJS、jQuery UI 异同浅析