昇思25天学习打卡营第5天|数据变换Transforms
前言
非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型!从今天起,笔者将以打卡的方式,将原文搬运和个人思考结合,分享25天的学习内容与成果。为了提升文章质量和阅读体验,笔者会将思考部分放在最后,供大家探索讨论。同时也欢迎各位领取算力,免费体验昇思大模型!
数据变换 Transforms
通常情况下,直接加载的原始数据并不能直接送入神经网络进行训练,此时我们需要对其进行数据预处理。MindSpore提供不同种类的数据变换(Transforms),配合数据处理Pipeline来实现数据预处理。所有的Transforms均可通过map
方法传入,实现对指定数据列的处理。
mindspore.dataset
提供了面向图像、文本、音频等不同数据类型的Transforms,同时也支持使用Lambda函数。下面分别对其进行介绍。
%%capture captured_output
# 实验环境已经预装了mindspore==2.3.0rc1,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.3.0rc1
import numpy as np
from PIL import Image
from download import download
from mindspore.dataset import transforms, vision, text
from mindspore.dataset import GeneratorDataset, MnistDataset
Common Transforms
mindspore.dataset.transforms
模块支持一系列通用Transforms。这里我们以Compose
为例,介绍其使用方式。
Compose
Compose
接收一个数据增强操作序列,然后将其组合成单个数据增强操作。我们仍基于Mnist数据集呈现Transforms的应用效果。
# Download data from open datasets
url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/" \
"notebook/datasets/MNIST_Data.zip"
path = download(url, "./", kind="zip", replace=True)#使用URL的方式下载MNIST数据集并解压缩
train_dataset = MnistDataset('MNIST_Data/train')#读取MNIST数据集的训练集部分train_dataset
image, label = next(train_dataset.create_tuple_iterator())#从训练集获取第一个批次的数据
print(image.shape) #输出图像形状,确定维度(H, W, C)为(28, 28, 1)
composed = transforms.Compose(
[
vision.Rescale(1.0 / 255.0, 0),#将图像像素值从0-255的范围缩放到0-1之间
vision.Normalize(mean=(0.1307,), std=(0.3081,)),#将图像数据标准化和归一化
vision.HWC2CHW()#改变维度顺序
]
)
train_dataset = train_dataset.map(composed, 'image')#将composed变换应用到训练数据集
image, label = next(train_dataset.create_tuple_iterator())
print(image.shape)#从训练数据集中获取第一个批次的图像数据的具体形状
更多通用Transforms详见mindspore.dataset.transforms。
Vision Transforms
mindspore.dataset.vision
模块提供一系列针对图像数据的Transforms。在Mnist数据处理过程中,使用了Rescale
、Normalize
和HWC2CHW
变换。下面对其进行详述。
Rescale
Rescale
变换用于调整图像像素值的大小,包括两个参数:
- rescale:缩放因子。
- shift:平移因子。
图像的每个像素将根据这两个参数进行调整,输出的像素值为 o u t p u t i = i n p u t i ∗ r e s c a l e + s h i f t output_{i} = input_{i} * rescale + shift outputi=inputi∗rescale+shift。
这里我们先使用numpy随机生成一个像素值在[0, 255]的图像,将其像素值进行缩放。
random_np = np.random.randint(0, 255, (48, 48), np.uint8)
random_image = Image.fromarray(random_np) #随机生成48*48尺寸的,值在0-255之间的图像
print(random_np) #输出图像
为了更直观地呈现Transform前后的数据对比,我们使用Transforms的Eager模式进行演示。首先实例化Transform对象,然后调用对象进行数据处理。
rescale = vision.Rescale(1.0 / 255.0, 0)
rescaled_image = rescale(random_image) #将图像像素值从0-255的范围缩放到0-1之间
print(rescaled_image)
可以看到,使用Rescale
后的每个像素值都进行了缩放。
Normalize
Normalize变换用于对输入图像的归一化,包括三个参数:
- mean:图像每个通道的均值。
- std:图像每个通道的标准差。
- is_hwc:bool值,输入图像的格式。True为(height, width, channel),False为(channel, height, width)。
图像的每个通道将根据mean
和std
进行调整,计算公式为
o
u
t
p
u
t
c
=
i
n
p
u
t
c
−
m
e
a
n
c
s
t
d
c
output_{c} = \frac{input_{c} - mean_{c}}{std_{c}}
outputc=stdcinputc−meanc,其中
c
c
c代表通道索引。
normalize = vision.Normalize(mean=(0.1307,), std=(0.3081,)) #通过图像的均值和标准差将输入图像归一化
normalized_image = normalize(rescaled_image)
print(normalized_image)
HWC2CHW
HWC2CHW
变换用于转换图像格式。在不同的硬件设备中可能会对(height, width, channel)或(channel, height, width)两种不同格式有针对性优化。MindSpore设置HWC为默认图像格式,在有CHW格式需求时,可使用该变换进行处理。
这里我们先将前文中normalized_image
处理为HWC格式,然后进行转换。可以看到转换前后的shape发生了变化。
hwc_image = np.expand_dims(normalized_image, -1)
hwc2chw = vision.HWC2CHW()
chw_image = hwc2chw(hwc_image) #调整图像从(H, W, C)变成(C, H, W)
print(hwc_image.shape, chw_image.shape)
更多Vision Transforms详见mindspore.dataset.vision。
Text Transforms
mindspore.dataset.text
模块提供一系列针对文本数据的Transforms。与图像数据不同,文本数据需要有分词(Tokenize)、构建词表、Token转Index等操作。这里简单介绍其使用方法。
首先我们定义三段文本,作为待处理的数据,并使用GeneratorDataset
进行加载。
texts = ['Welcome to Beijing']
test_dataset = GeneratorDataset(texts, 'text')
PythonTokenizer
分词(Tokenize)操作是文本数据的基础处理方法,MindSpore提供多种不同的Tokenizer。这里我们选择基础的PythonTokenizer
举例,此Tokenizer允许用户自由实现分词策略。随后我们利用map
操作将此分词器应用到输入的文本中,对其进行分词。
def my_tokenizer(content):
return content.split()
test_dataset = test_dataset.map(text.PythonTokenizer(my_tokenizer))
print(next(test_dataset.create_tuple_iterator())) #将句子分隔成单词,输出句子Tensor的类型
Lookup
Lookup
为词表映射变换,用来将Token转换为Index。在使用Lookup
前,需要构造词表,一般可以加载已有的词表,或使用Vocab
生成词表。这里我们选择使用Vocab.from_dataset
方法从数据集中生成词表。
vocab = text.Vocab.from_dataset(test_dataset) #从数据集生成词表
获得词表后我们可以使用vocab
方法查看词表。
print(vocab.vocab())
生成词表后,可以配合map
方法进行词表映射变换,将Token转为Index。
test_dataset = test_dataset.map(text.Lookup(vocab)) #使用map完成词表的映射,将Token转换成Index
print(next(test_dataset.create_tuple_iterator()))
更多Text Transforms详见mindspore.dataset.text。
Lambda Transforms
Lambda函数是一种不需要名字、由一个单独表达式组成的匿名函数,表达式会在调用时被求值。Lambda Transforms可以加载任意定义的Lambda函数,提供足够的灵活度。在这里,我们首先使用一个简单的Lambda函数,对输入数据乘2:
test_dataset = GeneratorDataset([1, 2, 3], 'data', shuffle=False)#非混洗方式生成数据集名为data,内容为[1, 2, 3]
test_dataset = test_dataset.map(lambda x: x * 2) #将数据集中的每个数据*2
print(list(test_dataset.create_tuple_iterator()))
可以看到map
传入Lambda函数后,迭代获得数据进行了乘2操作。
我们也可以定义较复杂的函数,配合Lambda函数实现复杂数据处理:
def func(x):
return x * x + 2
test_dataset = test_dataset.map(lambda x: func(x))#将数据集中的每个数据求平方再加2
print(list(test_dataset.create_tuple_iterator()))
个人任务打卡(读者请忽略)
个人理解与总结
本章节展示了昇思大模型对于数据变换Transforms的用法以及实际代码。具体而言,昇思大模型的数据变换操作包括普通变换(Common Transforms)、视觉变换(Vision Transforms)、文本变换(Text Transforms)和Lambda变换(Lambda Transforms)。笔者个人的研究方向为CV,所以常见在深度学习代码中经常使用到视觉变换中完成的功能,包括Rescale调整图像像素值的大小、Normalize使图像归一化和HWC2CHW转换图像格式(其中还可能引入BHWC转为BCHW)。这对即将在昇思大模型研究CV方向提供了良好的代码基础。