使用OSS中的数据构建适用于流式顺序读取的Iterable型Dataset

OssIterableDataset类型的Dataset适用于内存有限或数据量巨大的场景,主要适用于顺序处理且对随机访问和并行处理要求不高的场景。本文为您介绍如何通过OssIterableDataset构建Dataset。

前提条件

已安装并配置OSS Connector for AI/ML。具体操作,请参见安装OSS Connector for AI/ML配置OSS Connector for AI/ML

构建Dataset

构建方式

在使用OssIterableDataset构建Dataset时,有三种构建方式:

  • OSS_URI前缀:适用于OSS存储路径具有统一规律的场景。

  • OSS_URI的列表:适用于OSS存储路径位置明确但分散的场景。

  • 清单文件:可以减少OSS list object开销,适用于数据集文件数量大(如千万级)且有重复加载数据集需求,以及已开通数据索引OSS功能的Bucket。

通过OSS_URI前缀构建Dataset

以下示例用于使用OssIterableDataset的from_prefix方法从OSS中指定的前缀(OSS_URI)构建Dataset。

from osstorchconnector import OssIterableDataset

ENDPOINT = "http://oss-cn-beijing-internal.aliyuncs.com"
CONFIG_PATH = "/etc/oss-connector/config.json"
CRED_PATH = "/root/.alibabacloud/credentials"
OSS_URI = "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/"

# 使用OssIterableDataset的from_frefix方法构建Dataset
map_dataset = OssIterableDataset.from_prefix(OSS_URI, endpoint=ENDPOINT, cred_path=CRED_PATH, config_path=CONFIG_PATH)

# 遍历Dataset中对象
for item in map_dataset:
    print(item.key)
    print(item.size)
    content = item.read()
    print(len(content))

通过OSS_URI列表构建Dataset

以下示例用于使用OssIterableDataset的from_objects方法从指定的OSS_URI列表构建Dataset。示例中的uris是一个包含多个OSS_URI的字符串迭代器。

from osstorchconnector import OssIterableDataset

ENDPOINT = "http://oss-cn-beijing-internal.aliyuncs.com"
CONFIG_PATH = "/etc/oss-connector/config.json"
CRED_PATH = "/root/.alibabacloud/credentials"

uris = [
    "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/img001-00001.png",
    "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/img001-00002.png",
    "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/img001-00003.png"
]

# 使用OssIterableDataset的from_objects方法构建Dataset
map_dataset = OssIterableDataset.from_objects(uris, endpoint=ENDPOINT, cred_path=CRED_PATH, config_path=CONFIG_PATH)

# 遍历Dataset中对象
for item in map_dataset:
    print(item.key)
    print(item.size)
    content = item.read()
    print(len(content))

通过清单文件构建Dataset

使用manifest file构建Dataset前,您需要创建manifest file,然后通过manifest file构建Dataset。

  1. 创建清单文件:

    在任意位置执行touch manifest _file命令创建manifest file,然后根据示例填写manifest file。

    带有OSS对象名称的manifest file示例:

    Img/BadImag/Bmp/Sample001/img001-00001.png
    Img/BadImag/Bmp/Sample001/img001-00002.png
    Img/BadImag/Bmp/Sample001/img001-00003.png

    带有OSS对象名称和label的manifest file示例:

    Img/BadImag/Bmp/Sample001/img001-00001.png label1
    Img/BadImag/Bmp/Sample001/img001-00002.png label2
    Img/BadImag/Bmp/Sample001/img001-00003.png label3
  2. 通过清单文件构建Dataset:

    以下示例用于使用OssIterableDataset的from_manifest_file方法从指定的manifest file文件构建Dataset。

    import io
    from typing import Iterable,Tuple,Union
    from osstorchconnector import OssIterableDataset
    from osstorchconnector import imagenet_manifest_parser
    
    ENDPOINT = "http://oss-cn-beijing-internal.aliyuncs.com"
    CONFIG_PATH = "/etc/oss-connector/config.json"
    CRED_PATH = "/root/.alibabacloud/credentials"
    OSS_BASE_URI = "oss://ai-testset/EnglistImg/"
    MANIFEST_FILE_URI = "oss://manifest_fileai-testset/EnglistImg/manifest_file"
    
    # 使用 OssMapDataset 的 from_manifest_file 方法通过本地的文件构建 Dataset
    # manifest_file_path 参数指定了清单文件本地路径
    # manifest_parser 参数为解析清单文件的方法,示例中使用了内置的解析方法 imagenet_manifest_parser
    # oss_base_uri 参数指定了BASE_OSS_URI,用于与从 manifest中解析的URI拼接成 FULL_OSS_URI,FULL_OSS_URI = BASE_OSS_URI + URI
    MANIFEST_FILE_LOCAL = "/path/to/manifest_file.txt"         
    iterable_dataset = OssIterableDataset.from_manifest_file(manifest_file_path=MANIFEST_FILE_LOCAL, manifest_parser=imagenet_manifest_parser, oss_base_uri=OSS_BASE_URI, endpoint=ENDPOINT, cred_path=CRED_PATH, config_path=CONFIG_PATH)
    for item in iterable_dataset:
        print(item.key)
        print(item.size)
        print(item.label)
        content = item.read()
        print(len(content))
    
    # 使用OssIterableDataset的from_manifest_file方法通过OSS Bucket内的manifest_file文件构建Dataset
    iterable_dataset = OssIterableDataset.from_manifest_file(manifest_file_path=MANIFEST_FILE_URI, manifest_parser=imagenet_manifest_parser, oss_base_uri=OSS_BASE_URI, endpoint=ENDPOINT, cred_path=CRED_PATH, config_path=CONFIG_PATH)

Dataset中的数据类型

Dataset中对象的数据类型实现了常用的IO接口。更多信息,请参见OSS Connector for AI/ML中的数据类型

构建参数说明

使用OssMapDataset或OssIterableDataset构建Dataset时需要进行相应配置,具体配置项说明请参见下表。

参数名

参数类型

是否必选

说明

endpoint

string

公共参数:

OSS对外服务的访问域名。更多信息,请参见访问域名和数据中心

transform

object

公共参数:

转换函数,用于将DataObject(oss object)转换成任意类型。可以根据需求自定义其方法,具体请参见transform

重要

请勿在transform中直接返回DataObject对象,可能导致迭代器无法工作。如果要返回对象,需要调用copy方法。

cred_path

string

公共参数:

鉴权文件默认路径为/root/.alibabacloud/credentials。更多信息,请参见配置访问凭证

config_path

string

公共参数:

OSS Connector配置文件默认路径为/etc/oss-connector/config.json。更多信息,请参见配置OSS Connector

oss_uri

string

from_prefix方法参数:

OSS资源路径,用于通过OSS_URI前缀构建Dataset。仅支持以oss:// 开头的OSS_URI。

object_uris

string

from_objects方法参数:

OSS资源路径列表,通过列表中的路径构建Dataset。仅支持以oss:// 开头的OSS_URI。

manifest_file_path

string

from_manifest_file方法参数:

清单文件的路径,支持本地文件路径或以oss://开头的OSS_URI。

manifest_parser

Callable Object

from_manifest_file方法参数:

解析清单文件的内置方法,接收已打开的清单文件作为输入,返回一个迭代器,每个元素为(oss_uri,label)的元组。具体请参见manifest_parser。您也可以根据不同数据集的manifest file格式自定义manifest_parser方法。

oss_base_uri

string

from_manifest_file方法参数:

OSS基础URI,用于拼接清单文件中可能不完整的OSS_URI,形成完整的OS_URI。如果没有oss_base_uri,需要填写为""

内置方法

transform

构建Dataset时,Dataset会返回transform(DataObject) 的迭代器。其中DataObject是OSS Connector for AI/ML中的数据类型

transform支持自定义其方法,在构建dataset时如果不指定transform,则会使用默认的transform方法。

默认transform方法

以下示例为默认transfrom方法,在构建Dataset时无需指定。

#默认transform函数
def identity(obj: DataObject) -> DataObject:
    if obj is not None:
        return obj.copy()
    else:
        return None

自定义transform方法

以下示例用于构建Dataset时使用自定义transform方法。

import sys
import io
import torchvision.transforms as transforms
from PIL import Image
from osstorchconnector import OssIterableDataset

ENDPOINT = "http://oss-cn-beijing-internal.aliyuncs.com"
CONFIG_PATH = "/etc/oss-connector/config.json"
CRED_PATH = "/root/.alibabacloud/credentials"
OSS_URI = "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/"

# 定义图像数据的转换操作
trans = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 创建transform方法对输入的对象进行处理
def transform(object):
    try:
        img = Image.open(io.BytesIO(object.read())).convert('RGB')
        val = trans(img)
    except Exception as e:
        raise e
    return val, object.label

# 在构建dataset时使用transform=transform参数
iterable_dataset = OssIterableDataset.from_prefix(OSS_URI, endpoint=ENDPOINT, transform=transform, cred_path=CRED_PATH, config_path=CONFIG_PATH)
 

manifest_parser

默认manifest_parser方法,在构建Dataset时需导入示例如下。

from osstorchconnector import imagenet_manifest_parser

以下示例为默认manifest_parser方法。

def imagenet_manifest_parser(reader: io.IOBase) -> Iterable[Tuple[str, str]]:
    lines = reader.read().decode("utf-8").strip().split("\n")
    for i, line in enumerate(lines):
        try:
            items = line.strip().split('\t')
            if len(items) >= 2:
                key = items[0]
                label = items[1]
                yield (key, label)
            elif len(items) == 1:
                key = items[0]
                yield (key, '')
            else:
                raise ValueError("format error")
        except ValueError as e:
            logging.error(f"Error: {e} for line {i}: {line}")

使用PyTorch通过Dataset创建数据加载器

以下示例展示了如何根据OssIterableDataset构建的Dataset作为数据源来创建PyTorch数据加载器。

import torch
from osstorchconnector import OssIterableDataset

ENDPOINT = "http://oss-cn-beijing-internal.aliyuncs.com"
CONFIG_PATH = "/etc/oss-connector/config.json"
CRED_PATH = "/root/.alibabacloud/credentials"
OSS_URI = "oss://ai-testset/EnglistImg/Img/BadImag/Bmp/Sample001/"

def transform(object):
 data = object.read()
 return object.key, object.label

# 使用OssIterableDataset的from_frefix方法构建Dataset
map_dataset = OssIterableDataset.from_prefix(OSS_URI, endpoint=ENDPOINT,transform=transform, cred_path=CRED_PATH, config_path=CONFIG_PATH)

# 基于map_dataset创建PyTorch数据加载器
loader = torch.utils.data.DataLoader(map_dataset, batch_size=256, num_workers=32, prefetch_factor=2)
# 在训练循环中使用数据
# for batch in loader:
     # 进行训练操作
   ...

相关文档

如果您是在容器化环境中进行数据训练任务,那么OSS Connector for AI/ML同样适用于容器化环境。具体操作,请参见构建含有OSS Connector for AI/ML环境的Docker镜像