接上一篇,PaddleSeg 自定义数据类 https://blog.csdn.net/HaoZiHuang/article/details/125566058 这里再说一下 Normalize 操作
咱们自己写 Transform 时,总会担心一些细节,比如:
- np.uint8 转了没,要不要转为 np.float32
- 归一化做了没(/255做了没)
- 用不用减去0.5,然后除以0.5,将其移至 -1 到 1
- 送入数据之前,有没有 transpose 之类的
- 何时将 numpy.ndarray 初始化为 paddle.Tensor
上一篇PaddleSeg说到,在Compose结尾,会做输入通道数的转换(Transpose),而看源代码:
batch_sampler = paddle.io.DistributedBatchSampler(
eval_dataset, batch_size=1, shuffle=False, drop_last=False)
loader = paddle.io.DataLoader(
eval_dataset,
batch_sampler=batch_sampler,
num_workers=num_workers,
return_list=True, )
这个是实例化,Dataset 和 DataLoader 的部分,尽管 eval_dataset 返回的每个数据都是 np.ndarray,但是 paddle.io.DataLoader 这个类,会直接返回 Paddle.Tensor 类的数据,也就是无需再做 paddle.to_tensor操作
OK, 接下里的这三项:
- np.uint8 转了没,要不要转为 np.float32
- 归一化做了没
- 用不用减去0.5,然后除以0.5,将其移至 -1 到 1
就是 Normalize 部分的操作了,来看看它实现的源码
paddlesegtransformstransforms.py 中 Normalize 类
@manager.TRANSFORMS.add_component
class Normalize:
"""
Normalize an image.
Args:
mean (list, optional): The mean value of a data set. Default: [0.5, 0.5, 0.5].
std (list, optional): The standard deviation of a data set. Default: [0.5, 0.5, 0.5].
Raises:
ValueError: When mean/std is not list or any value in std is 0.
"""
def __init__(self, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)):
self.mean = mean
self.std = std
if not (isinstance(self.mean,
(list, tuple)) and isinstance(self.std,
(list, tuple))):
raise ValueError(
"{}: input type is invalid. It should be list or tuple".format(
self))
from functools import reduce
if reduce(lambda x, y: x * y, self.std) == 0:
raise ValueError('{}: std is invalid!'.format(self))
def __call__(self, im, label=None):
"""
Args:
im (np.ndarray): The Image data.
label (np.ndarray, optional): The label data. Default: None.
Returns:
(tuple). When label is None, it returns (im, ), otherwise it returns (im, label).
"""
mean = np.array(self.mean)[np.newaxis, np.newaxis, :]
std = np.array(self.std)[np.newaxis, np.newaxis, :]
im = functional.normalize(im, mean, std)
if label is None:
return (im, )
else:
return (im, label)
paddlesegtransformsfunctional.py 中 normalize 函数
def normalize(im, mean, std):
im = im.astype(np.float32, copy=False) / 255.0
im -= mean
im /= std
return im
可以看到 在 normalize 函数中,做了转 np.float32, 归一化
然后 -0.5 之后 /0.5
如果你对这两行感兴趣:
mean = np.array(self.mean)[np.newaxis, np.newaxis, :] std = np.array(self.std )[np.newaxis, np.newaxis, :]
自己打印看看吧,就是个原来的array维度前面加了两个1
shape 从 (3,) 变成了 (1, 1, 3)
而 np.newaxis 其实就是 None
(np.newaxis == None) == True
如果对 Normalize __init__函数中的 reduce 感兴趣:
可以看看这个:
functools下的reduce函数


![[PaddleSeg 源码阅读] PaddleSeg Transform 的 Normalize操作 [PaddleSeg 源码阅读] PaddleSeg Transform 的 Normalize操作](http://www.mshxw.com/aiimages/31/1005497.png)
