开发者分享利⽤Python和PyTorch处理⾯向对象的数据集:1.原始数据和数据集机器学习中⼀个常见问题是判定与数据交互的最佳⽅式。
在本⽂中,我们将提供⼀种⾼效⽅法,⽤于完成数据的交互、组织以及最终变换(预处理)。随后,我们将讲解如何在训练过程中正确地把数据输⼊给模型。
PyTorch 框架将帮助我们实现此⽬标,我们还将从头开始编写⼏个类。PyTorch 可提供更完整的原⽣类,但创建我们⾃⼰的类可帮助我们加速学习。
第 1 部分:原始数据和数据集
⾸先我们把尚未经过组织的所有样本称为“原始数据”。
把“数据集”定义为现成可⽤的数据,即含标签以及基本函数接⼝(以便于使⽤原始数据信息)的原始数据。
此处我们使⽤⼀种简单的原始数据形式:1 个包含图像和标签的⽂件夹。
但此⽅法可扩展⾄任意性质的样本(可以是图⽚、录⾳、视频等)以及包含标签的⽂件。
标签⽂件中的每⼀⾏都⽤于描述 1 个样本和相关标签,格式如下:
file_sample_1 label1
file_sample_2 label2
file_sample_3 label3
(...)
当能够完成⼀些基本信息查询(已有样本数量、返回特定编号的样本、预处理每个样本等)时,说明我们已从原始数据集创建了 1 个数据集。
此⽅法基于⾯向对象编程以及创建⽤于数据处理的 “类”。
对于⼀组简单的图像和标签⽽⾔,此⽅法可能看上去略显杀鸡⽤⽜⼑(实际上,此⽤例通常是通过创建分别⽤于训练、验证和测试的独⽴⽂件夹来进⾏处理的)。但如果要选择标准交互⽅法,则此⽅法将来可复⽤于多种不同⽤例,以节省时间。
在 Python 中处理数据
在 Python 中所有⼀切都是对象:整数、列表、字典都是如此。
构建含标准属性和⽅法的“数据集”对象的原因多种多样。我认为,代码的精致要求就⾜以合理化这⼀选择,但我理解这是品味的问题。可移植性、速度和代码模块化可能是最重要的原因。
在许多⽰例以及编码书籍中,我发现了⾯向对象的编码(尤以类为甚)的其它有趣的功能和优势,总结如下:
• 类可提供继承
• 继承可提供复⽤
• 继承可提供数据类型扩展
• 继承⽀持多态现象
• 继承⽀持多态现象
• 继承是⾯向对象的编码的特有功能
■输⼊ [1]:
import torch
from torchvision import transforms
to_tensor = transforms.ToTensor
from collections import namedtuple
import functools
import copy
import csv
from PIL import Image
from matplotlib import pyplot as plt
import numpy as np
import os
import datetime
import torch.optim as optim
在我们的⽰例中,所有原始样本都存储在⽂件夹中。此⽂件夹的地址在 raw_data_path 变量中声明。
■输⼊ [2]:
raw_data_path = './raw_data/data_images'
构建模块
数据集接⼝需要⼀些函数和类。数据集本⾝就是⼀个对象,因此我们将创建 MyDatat 类来包含所有重要函数和变量。⾸先,我们需要读取标签⽂件,然后可对样本在其原始格式(此处为 PIL 图像)以及最终的张量格式应⽤某些变换。
我们需要使⽤以下函数来读取 1 次标签⽂件,然后创建包含所有样本名称和标签的元组。
内存中缓存可提升性能,但如果标签⽂件发⽣更改,请务必更新缓存内容。
■输⼊ [113]:
DataInfoTuple = namedtuple('Sample','SampleName, SampleLabel')
def myFunc(e):
return e.SampleLabel
@functools.lru_cache(1)
def getSampleInfoList(raw_data_path):
sample_list = []
with open(str(raw_data_path) + '/', mode = 'r') as f:
reader = ader(f, delimiter = ' ')
for i, row in enumerate(reader):
刘邦手下
imgname = row[0]
label = int(row[1])
sample_list.append(DataInfoTuple(imgname, label))
sample_list.sort(rever=Fal, key=myFunc)
# print("DataInfoTouple: samples list length = {}".format(len(sample_list)))
return sample_list
如需直接变换 PIL 图像,那么以下类很实⽤。
该类仅含 1 种⽅法:resize。resize ⽅法能够改变 PIL 图像的原始⼤⼩,并对其进⾏重新采样。如需其它预处理(翻转、剪切、旋转等),需在此类种添加⽅法。
当 PIL 图像完成预处理后,即可将其转换为张量。此外还可对张量执⾏进⼀步的处理步骤。
在以下⽰例种,可以看到这两种变换:
砂锅白菜炖豆腐■输⼊ [4]:
class PilTransform:
"""generic transformation of a pil image"""
def resize(lf, img, **kwargs):
img = size(( ('width'), ('height')), resample=Image.NEAREST)
return img
# creation of the object pil_transform, having all powers inherited by the class PilTransform
pil_transform = PilTransform
以下是类 PilTransform 的实操⽰例:
■输⼊ [5]:
永恒的爱英文■输⼊ [5]:
path = raw_data_path + "/img_00000600.JPEG"
print(path)
im1 = Image.open(path, mode='r')
plt.imshow(im1)
.
/raw_data/data_images/img_00000600.JPEG
■输出 [5]:
■输⼊ [6]:
im2 = size(im1, width=128, height=128)
# im2.show
plt.imshow(im2)
■输出 [6]:
<matplotlib.image.AxesImage at 0x12104b36358>
最后,我们定义⼀个类,⽤于实现与原始数据的交互。
类 MyDatat 主要提供了 2 个⽅法:
__len__ 可提供原始样本的数量。
__getitem__ 可使对象变为可迭代类型,并按张量格式返回请求的样本(已完成预处理)。__getitem__ 步骤:
__getitem__ 步骤:
1) 打开来⾃⽂件的样本。
2) 按样本的原始格式对其进⾏预处理。
吃什么能养胃3) 将样本变换为张量。
4) 以张量格式对样本进⾏预处理。
此处添加的预处理仅作为⽰例。
此类可对张量进⾏归⼀化(求平均值和标准差),这有助于加速训练过程。
请注意,PIL 图像由范围 0-255 内的整数值组成,⽽张量则为范围 0-1 内的浮点数矩阵。
该类会返回包含两个元素的列表:在位置 [0] 返回张量,在位置 [1] 返回包含 SampleName 和 SampleLabel 的命名元组。
■输⼊ [109]:
class MyDatat:
"""Interface class to raw data, providing the total number of samples in the datat and a preprocesd item"""
def __init__(lf,
购房委托书isValSet_bool = None,
raw_data_path = './',
SampleInfoList = DataInfoTuple,norm = Fal,
resize = Fal,
newsize = (32, 32)
):
lf.raw_data_path = raw_data_path
lf.SampleInfoList = py(getSampleInfoList(lf.raw_data_path))
lf.isValSet_bool = isValSet_bool
四季养生
< = norm
def __str__(lf):
大学生主题班会return 'Path of raw data is ' + lf.raw_data_path + '/' + '<raw samples>'女人和女孩的区别