文章目录
前言
pytorch
用了一段时间,后来又不用了,所以重新捡起pytorch
再学一遍。
本次的资料是来自官方教程pytorch自定义数据导入和处理教程,教程中使用的是skimage
处理,在我的实现中,我使用了PIL
处理图片。
Self-made dataset (使用Dataset
自定义数据集)
通过继承torch.utils.data.Dataset
,我们可以实现自定义的数据集。继承之后,必须覆盖以下两种方法:
__len__
: 获得数据集的大小__getitem__
: 支持下标索引访问,如dataset[i]
在_init__
构造函数里预加载文件,在__len__
中定义大小, 在__getitem__
中定义用idx
获得单个样本的方法。
以下是使用PIL和pandas加载数据集的例子,样例来自官网。
class LandmarkFacesDataset(Dataset):
def __init__(self, csv_file, root, transform=None):
"""
:params csv_file(string): Path to the csv file with annotations
:params root(string): Path to images
:params transform(callable, optional): Optional transform ot be applied
on a sample
"""
super(LandmarkFacesDataset, self).__init__()
self.root = root
self.data = pd.read_csv(csv_file)
self.transform = transform
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
assert idx >= 0 and idx < self.__len__(), "IndexError: idx must >= {} and < {}".format(0, self.__len__())
name = self.data.iloc[idx, 0]
pixels = self.data.iloc[idx, 1:].values.reshape(-1, 2)
# load image array
image_arr = np.array(Image.open(self.root + name))
sample = {
"images":image_arr, "landmarks":pixels}
if self.transform is not None:
sample = self.transform(sample)
return sample
注意:
- 单个sample是
dict
类型,包括一个样本包含的所有必须的信息。 __getitem__
函数只返回对应idx
的一个样本,在DataLoader
内部暂时我们不需要关心怎么调用的。
Self-made transform(自定义transform)
自定义的transform
其实是基于其他的图像处理库,比如说PIL.Image
,scikit-image(skimage)
,openCV
,一般它们将图片和numpy.ndarray
类型进行互转。
定义的transform
除了必要的时候需要改写构造函数外,重写__call__
方法,初始化后就可以直接像函数一样调用了。同时,这也使得它可以传入transforms.Compose()
作为参数,对图片进行连续处理。
如下是一个对图片进行放缩的函数,该函数必须 特别注意长宽,不要弄反了。
class Rescale1(object):
"""对图片进行放缩或者调整大小,
注意长宽在选择的时候是反的
"""
def __init__(self, output_size):
assert(isinstance(output_size, (int, tuple)))
self.output_size = output_size
def __call__(self, sample):
image, landmarks = sample["images"], sample["landmarks"]
h,w = image.shape[:2]
if isinstance(self.output_size, int):
if h > w:
new_h, new_w = self.output_size * h / w, self.output_size
else:
new_h, new_w = self.output_size, self.output_size * w / h
else:
new_h, new_w = self.output_size
new_h, new_w = int(new_h), int(new_w)
img = Image.fromarray(image)
img = img.resize((new_w, new_h))
img = np.array(img, dtype=image.dtype)
landmarks = landmarks * np.array([new_w / w, new_h / h])
return {
"images":img, "landmarks": landmarks}
以下是随机裁减和转化为tensor
的变换:
class RandomCrop(object):
"""对图片进行随机裁减
"""
def __init__(self, output_size):