昇思MindSpore进阶教程-格式转换

大家好,我是刘明,明志科技创始人,华为昇思MindSpore布道师。
技术上主攻前端开发、鸿蒙开发和AI算法研究。
努力为大家带来持续的技术分享,如果你也喜欢我的文章,就点个关注吧

MindSpore中可以把用于训练网络模型的数据集,转换为MindSpore特定的格式数据(MindSpore Record格式),从而更加方便地保存和加载数据。其目标是归一化用户的数据集,并进一步通过MindDataset接口实现数据的读取,并用于训练过程。在这里插入图片描述
此外,MindSpore还针对部分数据场景进行了性能优化,使用MindSpore Record数据格式可以减少磁盘IO、网络IO开销,从而获得更好的使用体验。

MindSpore Record数据格式具备的特征如下:

  1. 实现数据统一存储、访问,使得训练时数据读取更加简便。

  2. 数据聚合存储、高效读取,使得训练时数据方便管理和移动。

  3. 高效的数据编解码操作,使得用户可以对数据操作无感知。

  4. 可以灵活控制数据切分的分区大小,实现分布式数据处理。

Record文件结构

如下图所示,MindSpore Record文件由数据文件和索引文件组成。
在这里插入图片描述

其中数据文件包含文件头、标量数据页、块数据页,用于存储用户归一化后的训练数据,且单个MindSpore Record文件建议小于20G,用户可将大数据集进行分片存储为多个MindSpore Record文件。

而索引文件则包含基于标量数据(如图像Label、图像文件名等)生成的索引信息,用于方便地检索、统计数据集信息。

数据文件中的文件头、标量数据页、块数据页的具体用途如下所示:

  • 文件头:是MindSpore Record文件的元信息,主要用来存储文件头大小、标量数据页大小、块数据页大小、Schema信息、索引字段、统计信息、文件分区信息、标量数据与块数据对应关系等。

  • 标量数据页:主要用来存储整型、字符串、浮点型数据,如图像的Label、图像的文件名、图像的长宽等信息,即适合用标量来存储的信息会保存在这里。

  • 块数据页:主要用来存储二进制串、NumPy数组等数据,如二进制图像文件本身、文本转换成的字典等。

转换成Record格式

下面主要介绍如何将CV类数据和NLP类数据转换为MindSpore Record文件格式,并通过MindDataset接口,实现MindSpore Record文件的读取。

转换CV类数据集

本示例主要以包含100条记录的CV数据集并将其转换为MindSpore Record格式为例子,介绍如何将CV类数据集转换成MindSpore Record文件格式,并使用MindDataset接口读取。

首先,需要创建100张图片的数据集并对齐进行保存,其样本包含file_name(字符串)、label(整型)、 data(二进制)三个字段,然后使用MindDataset接口读取该MindSpore Record文件。

  1. 生成100张图像,并转换成MindSpore Record文件格式。
from PIL import Image
from io import BytesIO
from mindspore.mindrecord import FileWriter

file_name = "test_vision.mindrecord"
# 定义包含的字段
cv_schema = {"file_name": {"type": "string"},
             "label": {"type": "int32"},
             "data": {"type": "bytes"}}

# 声明MindSpore Record文件格式
writer = FileWriter(file_name, shard_num=1, overwrite=True)
writer.add_schema(cv_schema, "it is a cv dataset")
writer.add_index(["file_name", "label"])

# 创建数据集
data = []
for i in range(100):
    sample = {}
    white_io = BytesIO()
    Image.new('RGB', ((i+1)*10, (i+1)*10), (255, 255, 255)).save(white_io, 'JPEG')
    image_bytes = white_io.getvalue()
    sample['file_name'] = str(i+1) + ".jpg"
    sample['label'] = i+1
    sample['data'] = white_io.getvalue()

    data.append(sample)
    if i % 10 == 0:
        writer.write_raw_data(data)
        data = []

if data:
    writer.write_raw_data(data)

writer.commit()

上面示例运行无报错说明数据集转换成功。

  1. 通过MindDataset接口读取MindSpore Record文件格式。
from mindspore.dataset import MindDataset
from mindspore.dataset.vision import Decode

# 读取MindSpore Record文件格式
data_set = MindDataset(dataset_files=file_name)
decode_op = Decode()
data_set = data_set.map(operations=decode_op, input_columns=["data"], num_parallel_workers=2)

# 样本计数
print("Got {} samples".format(data_set.get_dataset_size()))

转换NLP类数据集

本示例首先创建一个包含100条记录的MindSpore Record文件格式,其样本包含八个字段,均为整型数组,然后使用MindDataset接口读取该MindSpore Record文件。

  1. 生成100条文本数据,并转换成MindSpore Record文件格式。
import numpy as np
from mindspore.mindrecord import FileWriter

# 输出的MindSpore Record文件完整路径
file_name = "test_text.mindrecord"

# 定义样本数据包含的字段
nlp_schema = {"source_sos_ids": {"type": "int64", "shape": [-1]},
              "source_sos_mask": {"type": "int64", "shape": [-1]},
              "source_eos_ids": {"type": "int64", "shape": [-1]},
              "source_eos_mask": {"type": "int64", "shape": [-1]},
              "target_sos_ids": {"type": "int64", "shape": [-1]},
              "target_sos_mask": {"type": "int64", "shape": [-1]},
              "target_eos_ids": {"type": "int64", "shape": [-1]},
              "target_eos_mask": {"type": "int64", "shape": [-1]}}

# 声明MindSpore Record文件格式
writer = FileWriter(file_name, shard_num=1, overwrite=True)
writer.add_schema(nlp_schema, "Preprocessed nlp dataset.")

# 创建虚拟数据集
data = []
for i in range(100):
    sample = {"source_sos_ids": np.array([i, i + 1, i + 2, i + 3, i + 4], dtype=np.int64),
              "source_sos_mask": np.array([i * 1, i * 2, i * 3, i * 4, i * 5, i * 6, i * 7], dtype=np.int64),
              "source_eos_ids": np.array([i + 5, i + 6, i + 7, i + 8, i + 9, i + 10], dtype=np.int64),
              "source_eos_mask": np.array([19, 20, 21, 22, 23, 24, 25, 26, 27], dtype=np.int64),
              "target_sos_ids": np.array([28, 29, 30, 31, 32], dtype=np.int64),
              "target_sos_mask": np.array([33, 34, 35, 36, 37, 38], dtype=np.int64),
              "target_eos_ids": np.array([39, 40, 41, 42, 43, 44, 45, 46, 47], dtype=np.int64),
              "target_eos_mask": np.array([48, 49, 50, 51], dtype=np.int64)}
    data.append(sample)

    if i % 10 == 0:
        writer.write_raw_data(data)
        data = []

if data:
    writer.write_raw_data(data)

writer.commit()

  1. 通过MindDataset接口读取MindSpore Record格式文件。
from mindspore.dataset import MindDataset

# 读取MindSpore Record文件格式
data_set = MindDataset(dataset_files=file_name, shuffle=False)

# 样本计数
print("Got {} samples".format(data_set.get_dataset_size()))

# 打印部分数据
count = 0
for item in data_set.create_dict_iterator(output_numpy=True):
    print("source_sos_ids:", item["source_sos_ids"])
    count += 1
    if count == 10:
        break

Dataset转存MindRecord

MindSpore提供转换常用数据集的工具类,能够将常用的数据集转换为MindSpore Record文件格式。

转存CIFAR-10数据集

用户可以通过Dataset.save类,将CIFAR-10原始数据转换为MindSpore Record,并使用MindDataset接口读取。

  1. 下载CIFAR-10数据集,并使用Cifar10Dataset加载。
from download import download
from mindspore.dataset import Cifar10Dataset

url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz"

path = download(url, "./", kind="tar.gz", replace=True)
dataset = Cifar10Dataset("./cifar-10-batches-bin/")  # 加载数据

  1. 调用Dataset.save接口,将CIFAR-10数据集转存为MindSpore Record文件格式。
dataset.save("cifar10.mindrecord")

  1. 通过MindDataset接口读取MindSpore Record文件格式。
import os
from mindspore.dataset import MindDataset

# 读取MindSpore Record文件格式
data_set = MindDataset(dataset_files="cifar10.mindrecord")

# 样本计数
print("Got {} samples".format(data_set.get_dataset_size()))

if os.path.exists("cifar10.mindrecord") and os.path.exists("cifar10.mindrecord.db"):
    os.remove("cifar10.mindrecord")
    os.remove("cifar10.mindrecord.db")

好的,下面是使用MindSpore实现ResNet-34的步骤: 1. 导入必要的库 ```python import mindspore.nn as nn from mindspore import Tensor from mindspore.ops import operations as P ``` 2. 定义基本的卷积块 ```python class ConvBlock(nn.Cell): def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0): super(ConvBlock, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, has_bias=False) self.bn = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU() def construct(self, x): x = self.conv(x) x = self.bn(x) x = self.relu(x) return x ``` 3. 定义ResNet-34的基本块 ```python class BasicBlock(nn.Cell): expansion = 1 def __init__(self, in_channels, out_channels, stride=1, downsample=None): super(BasicBlock, self).__init__() self.conv1 = ConvBlock(in_channels, out_channels, kernel_size=3, stride=stride, padding=1) self.conv2 = ConvBlock(out_channels, out_channels, kernel_size=3, stride=1, padding=1) self.downsample = downsample self.stride = stride def construct(self, x): identity = x out = self.conv1(x) out = self.conv2(out) if self.downsample is not None: identity = self.downsample(x) out += identity out = nn.ReLU()(out) return out ``` 4. 定义ResNet-34的主体部分 ```python class ResNet34(nn.Cell): def __init__(self, num_classes=1000): super(ResNet34, self).__init__() self.in_channels = 64 self.conv1 = ConvBlock(3, 64, kernel_size=7, stride=2, padding=3) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(BasicBlock, 64, 3, stride=1) self.layer2 = self._make_layer(BasicBlock, 128, 4, stride=2) self.layer3 = self._make_layer(BasicBlock, 256, 6, stride=2) self.layer4 = self._make_layer(BasicBlock, 512, 3, stride=2) self.avgpool = nn.AvgPool2d(kernel_size=7, stride=1) self.fc = nn.Dense(512 * BasicBlock.expansion, num_classes) def _make_layer(self, block, out_channels, num_blocks, stride): downsample = None if stride != 1 or self.in_channels != out_channels * block.expansion: downsample = nn.SequentialCell([ nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size=1, stride=stride, has_bias=False), nn.BatchNorm2d(out_channels * block.expansion) ]) layers = [] layers.append(block(self.in_channels, out_channels, stride, downsample)) self.in_channels = out_channels * block.expansion for i in range(1, num_blocks): layers.append(block(self.in_channels, out_channels)) return nn.SequentialCell(layers) def construct(self, x): x = self.conv1(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = P.Reshape()(x, (x.shape[0], -1)) x = self.fc(x) return x ``` 5. 加载数据和训练模型 这里的数据加载和训练模型的部分可以根据具体的数据集和训练需求进行编写。 以上就是使用MindSpore实现ResNet-34的基本步骤,你可以根据自己的需要进行修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明志刘明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值