1. Paddle数据读取包(basic_dataloader.py)
import os
import random
import numpy as np
import paddle.fluid as fluid
from paddle.reader.decorator import shuffle
import cv2
'''
实现paddle数据读取的包,针对分割来说
目的: 把图都读到程序当中,让paddle模型能够每次都调用,也就是数据在框架当中都是tensor,并希望更高效
的运行,因此需要找一个dataloader
paddle虽然提供API,但是我们还得实现自己的 basic_dataLoader(决定我们要怎么样读数据,怎么样处理数据),
因为paddle不知道我们自己的数据要怎么处理,以什么格式输入,paddle只负责当我们输入数据后将数据转换成我们
需要的格式。
'''
class Transform(object):
def __init__(self, size = 256):
self.size = size
def __call__(self, input, label):
input = cv2.resize(input, (self.size, self.size), interpolation=cv2.INTER_LINEAR)
# 用NEAREST,label不会越界
label = cv2.resize(label, (self.size, self.size), interpolation=cv2.INTER_NEAREST)
return input, label
class BasicDataLoader(object):
def __init__(self,
image_folder,
image_list_file,
transform=None,
shuffle=True):
self.image_floder = image_folder
self.image_list_file = image_list_file
self.transform = transform
self.shuffle = shuffle
self.data_list = self.read_list()
def read_list(self):
data_list = []
with open(self.image_list_file) as infile:
for line in infile:
# os.path.join 自动填/ 或者是 \
data_path = os.path.join(self.image_floder,line.split()[0])
label_path = os.path.join(self.image_floder,line.split()[1])
# 思考:为什么加tuple而不用list?
# Python中内置了list集合与tuple集合,在list集合中可以实现元素的添加、修改、插入、以及删除。tuple集合看似与list类似,但两者还是有很大的区别。
# 在tuple集合中,一旦元素被存储,以后就不能修改,删除了,这比list集合安全许多,所以能用tuple就用tuple
data_list.append((data_path, label_path))
random.shuffle(data_list)
return data_list
def preprocess(self, data, label):
h, w, c = data.shape
h_gt, w_gt = label.shape
assert h==h_gt, "Error"
assert w==w_gt, "Error"
if self.transform:
data, label = self.transform(data, label)
# 加了新轴,变成256*256*1
label = label[:, :, np.newaxis]
return data, label
def __len__(self):
return len(self.data_list)
def __call__(self):
# Class A
# a = A()
# a()就会调用__call__()方法
for data_path, label_path in self.data_list:
# type:numpy.array
# data:H * W * 3 、 label:H * W
# 读图、读label
data = cv2.imread(data_path, cv2.IMREAD_COLOR)
data = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
label = cv2.imread(label_path, cv2.IMREAD_GRAYSCALE)
print(data.shape, label.shape)
# 做基本的处理
data, label = self.preprocess(data, label)
# yield 相当于 return
yield data, label
def main():
batch_size = 5
place = fluid.CPUPlace()
with fluid.dygraph.guard(place):
transform = Transform(256)
# create BasicDataloader instance, class:python的generator
basic_dataloader = BasicDataLoader(
image_folder = r'./work/dummy_data',
image_list_file= r'./work/dummy_data/list.txt',
transform = transform,
shuffle=True # 打乱数据
)
# creat fluid.io.DataLoader instance
# 在paddle中训练,不断的调取数据
# 创建instance调用from_generator,basic_dataloader就是generator形式
dataloader = fluid.io.DataLoader.from_generator(capacity=1, use_multiprocess=False)
# set sample generator for fluid dataloader
dataloader.set_sample_generator(basic_dataloader,
batch_size=batch_size,
places=place)
num_epoch = 2
for epoch in range(1, num_epoch + 1):
print(f'Epoch [{epoch}/{num_epoch}]')
for idx, (data, label) in enumerate(dataloader):
print(f'Iter {idx}, Data shape:{data.shape}, Label shape:{label.shape}')
if __name__ == '__main__':
main()
2. basic_transforms.py
import cv2
import numpy as np
class Compose(object):
def __init__(self, transforms):
self.transforms = transforms
def __call__(self, image, label=None):
for t in self.transforms:
image, label = t(image, label)
return image, label
class Normalize(object):
def __init__(self, mean_val, std_val, val_scale=1):
# set val_scale = 1 if mean and std are in range (0,1)
# set val_scale to other value, if mean and std are in range (0,255)
self.mean = np.array(mean_val, dtype=np.float32)
self.std = np.array(std_val, dtype=np.float32)
self.val_scale = 1/255.0 if val_scale==1 else 1
def __call__(self, image, label=None):
image = image.astype(np.float32)
image = image * self.val_scale
image = image - self.mean
image = image * (1 / self.std)
return image, label
class ConvertDataType(object):
def __call__(self, image, label=None):
if label is not None:
label = label.astype(np.int64)
return image.astype(np.float32), label
class Pad(object):
def __init__(self, size, ignore_label=255, mean_val=0, val_scale=1):
# set val_scale to 1 if mean_val is in range (0, 1)
# set val_scale to 255 if mean_val is in range (0, 255)
factor = 255 if val_scale == 1 else 1
self.size = size
self.ignore_label = ignore_label
self.mean_val=mean_val
# from 0-1 to 0-255
if isinstance(self.mean_val, (tuple,list)):
self.mean_val = [int(x* factor) for x in self.mean_val]
else:
self.mean_val = int(self.mean_val * factor)
def __call__(self, image, label=None):
h, w, c = image.shape
pad_h = max(self.size - h, 0)
pad_w = max(self.size - w, 0)
pad_h_half = int(pad_h / 2)
pad_w_half = int(pad_w / 2)
if pad_h > 0 or pad_w > 0:
image = cv2.copyMakeBorder(image,
top=pad_h_half,
left=pad_w_half,
bottom=pad_h - pad_h_half,
right=pad_w - pad_w_half,
borderType=cv2.BORDER_CONSTANT,
value=self.mean_val)
if label is not None:
label = cv2.copyMakeBorder(label,
top=pad_h_half,
left=pad_w_half,
bottom=pad_h - pad_h_half,
right=pad_w - pad_w_half,
borderType=cv2.BORDER_CONSTANT,
value=self.ignore_label)
return image, label
# TODO
class CenterCrop(object):
def __init__(self, crop_size):
self.crop_h = crop_size
self.crop_w = crop_size
def __call__(self, image, label = None):
h, w, c = image.shape
top = (h - self.crop_h) // 2
left = (w - self.crop_w) // 2
image = image[top:top+self.crop_h, left:left+self.crop_w,:]
if label is not None:
label = label[top:top+self.crop_h, left:left+self.crop_w,:]
return image, label
# TODO
class Resize(object):
def __init__(self, size):
self.size = size
def __call__(self, image, label=None):
image = cv2.resize(image, (self.size, self.size), interpolation=cv2.INTER_LINEAR)
if label is not None:
label = cv2.resize(label, (self.size, self.size), interpolation=cv2.INTER_NEAREST)
return image,label
# TODO
class RandomFlip(object):
def __call__(self, image, label = None):
prob_of_filp = np.random.rand()
if prob_of_filp > 0.5:
image = cv2.flip(image, 1)
if label is not None:
label = cv2.flip(label,1)
return image, label
# TODO
class RandomCrop(object):
def __init__(self, crop_size):
self.crop_size = crop_size
def __call__(self, image, label = None):
h, w, c = image.shape
top = np.random.uniform(h-self.crop_size)
left = np.random.uniform(w-self.crop_size)
assert top >= 0, "Error: crop_size > image height!"
assert left >= 0, "Error: crop_size > image width!"
rect = np.array([int(left),
int(top),
int(left + self.crop_size),
int(top + self.crop_size)])
image = image[rect[1]:rect[3], rect[0]:rect[2], :]
if label is not None:
label = label[rect[1]:rect[3], rect[0]:rect[2], :]
return image,label
# # TODO
class Scale(object):
def __call__(self, image, label=None, scale=1.0):
if not isinstance(scale,(list,tuple)):
scale = [scale, scale]
h, w, c = image.shape
image = cv2.resize(image,
(int(w*scale[0]),int(h*scale[1])),
interpolation=cv2.INTER_LINEAR)
if label is not None:
label = cv2.resize(label,
(int(w*scale[0]),int(h*scale[1])),
interpolation=cv2.INTER_NEAREST)
return image,label
# TODO
class RandomScale(object):
def __init__(self, min_scale=0.5, max_scale=2.0, step=0.25):
self.min_scale = min_scale
self.max_scale = max_scale
self.step = step
self.scale = Scale()
def __call__(self, image, label=None, scale=1.0):
if self.step == 0:
self.random_scale = np.random.rand.uniform(self.min_scale,
self.max_scale,
1)[0]
else:
num_steps = int((self.max_scale - self.min_scale) / self.step + 1)
scale_factors = np.linspace(self.min_scale,
self.max_scale,
num_steps)
np.random.shuffle(scale_factors)
self.random_scale = scale_factors[0]
image, label = self.scale(image, label, self.random_scale)
return image,label
def main():
image = cv2.imread('./work/dummy_data/JPEGImages/2008_000064.jpg')
label = cv2.imread('./work/dummy_data/GroundTruth_trainval_png/2008_000064.png')
# TODO: crop_size
# TODO: Transform: RandomSacle, RandomFlip, Pad, RandomCrop
crop_size = 200
augment = Compose([
RandomScale(),
RandomFlip(),
Pad(crop_size, mean_val=[0.485, 0.456, 0.406]),
RandomCrop(crop_size),
ConvertDataType(),
# Normalize(0, 1)
])
# for i in range(10):
# TODO: call transform
# TODO: save image
new_img, new_label = augment(image,label)
cv2.imwrite('img_new.png', new_img)
cv2.imwrite('label_new.png', new_label)
if __name__ == "__main__":
main()
3. basic_model.py
'''
Author: cheng
Date: 2021-10-20 01:12:29
LastEditTime: 2021-10-20 10:58:54
FilePath: /paddlepaddle/code1.py
'''
# paddle动态图
import paddle
import numpy as np
import paddle.fluid as fluid
from paddle.fluid.dygraph.base import to_variable
from paddle.fluid.dygraph import Pool2D
from paddle.fluid.dygraph import Conv2D
# BasicModel继承动态图的层
class BasicModel(fluid.dygraph.Layer):
# 初始化,简单给一个类别参数,59类
def __init__(self, num_classes=59):
# 父类初始化
super(BasicModel, self).__init__()
self.pool = Pool2D(pool_size=2, pool_stride=2)
# num_chanels:input的channel数,
# num_filters:output维度,或者有多少个卷积核,
# filter_size卷积尺寸大小
self.conv = Conv2D(num_channels=3, num_filters=num_classes,filter_size=1)
def forward(self, inputs):
x = self.pool(inputs)
# 上采样,插值,输出和输入尺寸一样
x = fluid.layers.interpolate(x, out_shape=inputs.shape[2::])
x = self.conv(x)
return x
def main():
# cpu
place = fluid.CPUPlace()
# place = fluid.CUDAPlace(0) #GPU
with fluid.dygraph.guard(place):
model = BasicModel(num_classes=59)
model.eval() # model.train()
# random一个数据,类型NCHW,astype转换数据类型
input_data = np.random.rand(1, 3, 8, 8).astype(np.float32)
print('Input data shape:', input_data.shape)
# numpy.array 转换成 tensor
input_data = to_variable(input_data)
output_data = model(input_data)
output_data = output_data.numpy()
print('Output data shape:',output_data.shape)
if __name__ =='__main__':
main()
输出:
Input data shape: (1, 3, 8, 8)
Output data shape: (1, 59, 8, 8)