mindspore/tests/ut/python/dataset/test_map.py

377 lines
17 KiB
Python
Raw Normal View History

2022-03-24 10:24:10 +08:00
# Copyright 2022 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
Test Map op in Dataset
"""
2022-08-30 04:21:55 +08:00
import random
2022-08-27 01:35:26 +08:00
import numpy as np
2022-03-24 10:24:10 +08:00
import pytest
2022-08-27 01:35:26 +08:00
2022-03-24 10:24:10 +08:00
import mindspore.dataset as ds
import mindspore.dataset.text as text
from mindspore.dataset.transforms import transforms
import mindspore.dataset.vision as vision
2022-09-10 02:02:15 +08:00
from util import config_get_set_seed, config_get_set_num_parallel_workers, config_get_set_enable_shared_mem
2022-03-24 10:24:10 +08:00
DATA_DIR = "../data/dataset/testPK/data"
def test_map_c_transform_exception():
"""
2022-05-27 20:53:41 +08:00
Feature: Test Cpp error op def
Description: Op defined like vision.HWC2CHW
Expectation: Success
2022-03-24 10:24:10 +08:00
"""
data_set = ds.ImageFolderDataset(DATA_DIR, num_parallel_workers=1, shuffle=True)
train_image_size = 224
mean = [0.485 * 255, 0.456 * 255, 0.406 * 255]
std = [0.229 * 255, 0.224 * 255, 0.225 * 255]
# define map operations
random_crop_decode_resize_op = vision.RandomCropDecodeResize(train_image_size,
scale=(0.08, 1.0),
ratio=(0.75, 1.333))
random_horizontal_flip_op = vision.RandomHorizontalFlip(prob=0.5)
normalize_op = vision.Normalize(mean=mean, std=std)
hwc2chw_op = vision.HWC2CHW # exception
2022-03-24 10:24:10 +08:00
data_set = data_set.map(operations=random_crop_decode_resize_op, input_columns="image", num_parallel_workers=1)
data_set = data_set.map(operations=random_horizontal_flip_op, input_columns="image", num_parallel_workers=1)
data_set = data_set.map(operations=normalize_op, input_columns="image", num_parallel_workers=1)
with pytest.raises(ValueError) as info:
data_set = data_set.map(operations=hwc2chw_op, input_columns="image", num_parallel_workers=1)
assert "Parameter operations's element of method map should be a " in str(info.value)
# compose exception
with pytest.raises(ValueError) as info:
transforms.Compose([
vision.RandomCropDecodeResize(train_image_size, scale=(0.08, 1.0), ratio=(0.75, 1.333)),
vision.RandomHorizontalFlip,
vision.Normalize(mean=mean, std=std),
vision.HWC2CHW()])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
# randomapply exception
with pytest.raises(ValueError) as info:
transforms.RandomApply([
vision.RandomCropDecodeResize,
vision.RandomHorizontalFlip(prob=0.5),
vision.Normalize(mean=mean, std=std),
vision.HWC2CHW()])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
# randomchoice exception
with pytest.raises(ValueError) as info:
transforms.RandomChoice([
vision.RandomCropDecodeResize(train_image_size, scale=(0.08, 1.0), ratio=(0.75, 1.333)),
vision.RandomHorizontalFlip(prob=0.5),
vision.Normalize,
vision.HWC2CHW()])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
def test_map_py_transform_exception():
"""
2022-05-27 20:53:41 +08:00
Feature: Test Python error op def
Description: Op defined like vision.RandomHorizontalFlip
Expectation: Success
2022-03-24 10:24:10 +08:00
"""
data_set = ds.ImageFolderDataset(DATA_DIR, num_parallel_workers=1, shuffle=True)
# define map operations
decode_op = vision.Decode(to_pil=True)
random_horizontal_flip_op = vision.RandomHorizontalFlip # exception
to_tensor_op = vision.ToTensor()
2022-03-24 10:24:10 +08:00
trans = [decode_op, random_horizontal_flip_op, to_tensor_op]
with pytest.raises(ValueError) as info:
data_set = data_set.map(operations=trans, input_columns="image", num_parallel_workers=1)
assert "Parameter operations's element of method map should be a " in str(info.value)
# compose exception
with pytest.raises(ValueError) as info:
transforms.Compose([
vision.Decode,
vision.RandomHorizontalFlip(),
vision.ToTensor()])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
# randomapply exception
with pytest.raises(ValueError) as info:
transforms.RandomApply([
vision.Decode(to_pil=True),
vision.RandomHorizontalFlip,
vision.ToTensor()])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
# randomchoice exception
with pytest.raises(ValueError) as info:
transforms.RandomChoice([
vision.Decode(to_pil=True),
vision.RandomHorizontalFlip(),
vision.ToTensor])
2022-03-24 10:24:10 +08:00
assert " should be a " in str(info.value)
def test_map_text_and_data_transforms():
"""
Feature: Map op
Description: Test Map op with both Text Transforms and Data Transforms
Expectation: Dataset pipeline runs successfully and results are verified
"""
data = ds.TextFileDataset("../data/dataset/testVocab/words.txt", shuffle=False)
vocab = text.Vocab.from_dataset(data, "text", freq_range=None, top_k=None,
special_tokens=["<pad>", "<unk>"],
special_first=True)
padend_op = transforms.PadEnd([100], pad_value=vocab.tokens_to_ids('<pad>'))
lookup_op = text.Lookup(vocab, "<unk>")
# Use both Text Lookup op and Data Transforms PadEnd op in operations list for Map
data = data.map(operations=[lookup_op, padend_op], input_columns=["text"])
res = []
for d in data.create_dict_iterator(num_epochs=1, output_numpy=True):
res.append(d["text"].item())
assert res == [4, 5, 3, 6, 7, 2], res
def test_map_operations1():
"""
Feature: Map op
Description: Test Map op with operations in multiple formats
Expectation: Dataset pipeline runs successfully and results are verified
"""
class RandomHorizontal(vision.RandomHorizontalFlip):
def __init__(self, p):
self.p = p
super().__init__(p)
data1 = ds.ImageFolderDataset(DATA_DIR, num_samples=5)
# Use 2 different formats to list ops for map operations
data1 = data1.map(operations=[vision.Decode(to_pil=True),
vision.RandomCrop(512),
RandomHorizontal(0.5)], input_columns=["image"])
num_iter = 0
for _ in data1.create_dict_iterator(num_epochs=1): # each data is a dictionary
num_iter += 1
assert num_iter == 5
2022-08-30 04:21:55 +08:00
def test_c_map_randomness_repeatability(set_seed_to=1111, set_num_parallel_workers_to=3, num_repeat=5):
2022-08-27 01:35:26 +08:00
"""
Feature: Map op
Description: Test repeatability of Map op with C implemented random ops with num_parallel_workers > 1
Expectation: The dataset would be the same each iteration
"""
data_dir_tf = ["../data/dataset/test_tf_file_3_images/train-0000-of-0001.data"]
schema_dir_tf = "../data/dataset/test_tf_file_3_images/datasetSchema.json"
original_seed = config_get_set_seed(set_seed_to)
original_num_parallel_workers = config_get_set_num_parallel_workers(set_num_parallel_workers_to)
# First dataset
data1 = ds.TFRecordDataset(data_dir_tf, schema_dir_tf, columns_list=["image"], shuffle=False)
transforms_list1 = [vision.Decode(),
vision.RandomResizedCrop((256, 512), (2, 2), (1, 3)),
vision.RandomColorAdjust(
brightness=(0.5, 0.5), contrast=(0.5, 0.5), saturation=(0.5, 0.5), hue=(0, 0))]
data1 = data1.map(operations=transforms_list1, input_columns=["image"])
for _ in range(num_repeat):
# Next datasets
data2 = ds.TFRecordDataset(data_dir_tf, schema_dir_tf, columns_list=["image"], shuffle=False)
transforms_list2 = [vision.Decode(),
vision.RandomResizedCrop((256, 512), (2, 2), (1, 3)),
vision.RandomColorAdjust(
brightness=(0.5, 0.5), contrast=(0.5, 0.5), saturation=(0.5, 0.5), hue=(0, 0))]
data2 = data2.map(operations=transforms_list2, input_columns=["image"])
# Expect to have the same image every time
for img1, img2 in zip(data1.create_tuple_iterator(num_epochs=1, output_numpy=True),
data2.create_tuple_iterator(num_epochs=1, output_numpy=True)):
np.testing.assert_equal(img1, img2)
# Restore config setting
ds.config.set_seed(original_seed)
ds.config.set_num_parallel_workers(original_num_parallel_workers)
2022-08-30 04:21:55 +08:00
def test_c_map_randomness_repeatability_with_shards(set_seed_to=312, set_num_parallel_workers_to=5, num_repeat=5):
2022-08-27 01:35:26 +08:00
"""
Feature: Map op
Description: Test repeatability of Map op with C implemented random ops with num_parallel_workers > 1 and sharding
Expectation: The dataset would be the same each iteration
"""
image_folder_dir = "../data/dataset/testPK/data"
num_samples = 55
num_shards = 2
shard_id = 0
shuffle = False
class_index = dict()
original_seed = config_get_set_seed(set_seed_to)
original_num_parallel_workers = config_get_set_num_parallel_workers(set_num_parallel_workers_to)
# First dataset
data1 = ds.ImageFolderDataset(image_folder_dir, num_samples=num_samples, num_shards=num_shards,
shard_id=shard_id,
shuffle=shuffle, class_indexing=class_index)
transforms_list1 = [vision.Decode(),
vision.RandomResizedCrop((256, 512), (2, 2), (1, 3)),
vision.RandomColorAdjust(
brightness=(0.5, 0.5), contrast=(0.5, 0.5), saturation=(0.5, 0.5), hue=(0, 0))]
data1 = data1.map(operations=transforms_list1, input_columns=["image"])
for _ in range(num_repeat):
# Next datasets
data2 = ds.ImageFolderDataset(image_folder_dir, num_samples=num_samples, num_shards=num_shards,
shard_id=shard_id,
shuffle=shuffle, class_indexing=class_index)
transforms_list2 = [vision.Decode(),
vision.RandomResizedCrop((256, 512), (2, 2), (1, 3)),
vision.RandomColorAdjust(
brightness=(0.5, 0.5), contrast=(0.5, 0.5), saturation=(0.5, 0.5), hue=(0, 0))]
data2 = data2.map(operations=transforms_list2, input_columns=["image"])
# Expect to have the same image every time
for img1, img2 in zip(data1.create_tuple_iterator(num_epochs=1, output_numpy=True),
data2.create_tuple_iterator(num_epochs=1, output_numpy=True)):
np.testing.assert_equal(img1, img2)
# Restore config setting
ds.config.set_seed(original_seed)
ds.config.set_num_parallel_workers(original_num_parallel_workers)
@pytest.mark.parametrize("num_parallel_workers", (2, 4, 6))
@pytest.mark.parametrize("num_samples", (1, 2, 5, 6))
def test_python_map_mp_repeatability(num_parallel_workers, num_samples, set_seed_to=1605):
2022-08-27 01:35:26 +08:00
"""
Feature: Map op
Description: Test repeatability of Map op with Python multiprocessing with Python implemented
random ops and num_parallel_workers > 1
Expectation: The dataset would be the same each iteration
"""
data_dir = "../data/dataset/testImageNetData2/train/"
2022-08-27 01:35:26 +08:00
original_seed = config_get_set_seed(set_seed_to)
original_num_parallel_workers = config_get_set_num_parallel_workers(num_parallel_workers)
2022-09-10 02:02:15 +08:00
# Reduce memory required by disabling the shared memory optimization
original_enable_shared_mem = config_get_set_enable_shared_mem(False)
2022-08-27 01:35:26 +08:00
# dataset
data1 = ds.ImageFolderDataset(dataset_dir=data_dir, shuffle=False, num_samples=num_samples)
2022-08-27 01:35:26 +08:00
transforms_list1 = [vision.Decode(to_pil=True),
vision.RandomPerspective(0.4, 1.0),
vision.RandomLighting(0.01)]
data1 = data1.map(transforms_list1, num_parallel_workers=num_parallel_workers, python_multiprocessing=True)
2022-08-27 01:35:26 +08:00
# Expect to have the same augmentations
for img1, img2 in zip(data1.create_tuple_iterator(num_epochs=1, output_numpy=True),
data1.create_tuple_iterator(num_epochs=1, output_numpy=True)):
np.testing.assert_equal(img1, img2)
2022-08-27 01:35:26 +08:00
# Restore config setting
ds.config.set_seed(original_seed)
ds.config.set_num_parallel_workers(original_num_parallel_workers)
2022-09-10 02:02:15 +08:00
ds.config.set_enable_shared_mem(original_enable_shared_mem)
2022-08-27 01:35:26 +08:00
2022-08-30 04:21:55 +08:00
def test_python_map_mp_seed_repeatability(set_seed_to=1337, set_num_parallel_workers_to=4, num_repeat=5):
2022-08-27 01:35:26 +08:00
"""
Feature: Map op
Description: Test repeatability of Map op with Python multiprocessing with num_parallel_workers > 1
Expectation: The set of seeds of each process would be the same as expected
"""
# Generate md int numpy array from [[0, 1], [2, 3]] to [[63, 64], [65, 66]]
def generator_md():
for i in range(64):
yield (np.array([[i, i + 1], [i + 2, i + 3]]),)
original_seed = config_get_set_seed(set_seed_to)
original_num_parallel_workers = config_get_set_num_parallel_workers(set_num_parallel_workers_to)
2022-09-10 02:02:15 +08:00
# Reduce memory required by disabling the shared memory optimization
original_enable_shared_mem = config_get_set_enable_shared_mem(False)
2022-08-30 04:21:55 +08:00
expected_result_np_array = {i: [] for i in range(set_seed_to, set_seed_to + set_num_parallel_workers_to)}
data1 = ds.GeneratorDataset(generator_md, ["data"])
data1 = data1.map([lambda x: [ds.config.get_seed()] + [random.randrange(1, 1000) for i in range(100)]],
num_parallel_workers=set_num_parallel_workers_to, python_multiprocessing=True)
for item1 in data1.create_dict_iterator(num_epochs=1, output_numpy=True): # each data is a dictionary
seed_used1 = int(list(item1.values())[0][0])
result_np_array1 = list(item1.values())[0]
try:
expected_result_np_array[seed_used1].append(result_np_array1)
except KeyError:
raise AssertionError("Not all expected seeds were used")
2022-08-27 01:35:26 +08:00
for _ in range(num_repeat):
expected_seed = {i: 0 for i in range(set_seed_to, set_seed_to + set_num_parallel_workers_to)}
2022-08-30 04:21:55 +08:00
data2 = ds.GeneratorDataset(generator_md, ["data"])
data2 = data2.map([lambda x: [ds.config.get_seed()] + [random.randrange(1, 1000) for i in range(100)]],
2022-08-27 01:35:26 +08:00
num_parallel_workers=set_num_parallel_workers_to, python_multiprocessing=True)
2022-08-30 04:21:55 +08:00
for item2 in data2.create_dict_iterator(num_epochs=1, output_numpy=True): # each data is a dictionary
seed_used2 = int(list(item2.values())[0][0])
result_np_array2 = list(item2.values())[0]
if seed_used2 in expected_seed:
cur_iter = expected_seed[seed_used2]
np.testing.assert_array_equal(result_np_array2, expected_result_np_array[seed_used2][cur_iter])
expected_seed[seed_used2] += 1
2022-08-27 01:35:26 +08:00
else:
2022-08-30 04:21:55 +08:00
raise AssertionError("Seed not found")
2022-08-27 01:35:26 +08:00
if 0 in expected_seed.values():
2022-08-30 04:21:55 +08:00
raise AssertionError("Not all expected seeds were used")
2022-08-27 01:35:26 +08:00
# Restore config setting
ds.config.set_seed(original_seed)
ds.config.set_num_parallel_workers(original_num_parallel_workers)
2022-09-10 02:02:15 +08:00
ds.config.set_enable_shared_mem(original_enable_shared_mem)
2022-08-27 01:35:26 +08:00
2022-09-26 14:44:58 +08:00
def test_map_with_deprecated_parameter():
"""
Feature: Map op
Description: map with deprecated parameter
Expectation: ValueError
"""
data1 = np.array(np.random.sample(size=(300, 300, 3)) * 255, dtype=np.uint8)
data2 = np.array(np.random.sample(size=(300, 300, 3)) * 255, dtype=np.uint8)
data3 = np.array(np.random.sample(size=(300, 300, 3)) * 255, dtype=np.uint8)
data4 = np.array(np.random.sample(size=(300, 300, 3)) * 255, dtype=np.uint8)
label = [1, 2, 3, 4]
dataset = ds.NumpySlicesDataset(([data1, data2, data3, data4], label), ["data", "label"])
with pytest.raises(ValueError) as info:
dataset = dataset.map(operations=[(lambda x: (x + 1, x / 255))],
input_columns=["data"],
output_columns=["data2", "data3"],
column_order=["data2", "data3"])
assert "The parameter 'column_order' had been deleted in map operation." in str(info.value)
2022-03-24 10:24:10 +08:00
if __name__ == '__main__':
test_map_c_transform_exception()
test_map_py_transform_exception()
test_map_text_and_data_transforms()
test_map_operations1()
2022-08-27 01:35:26 +08:00
test_c_map_randomness_repeatability()
test_c_map_randomness_repeatability_with_shards()
test_python_map_mp_repeatability(num_parallel_workers=4, num_samples=4)
2022-08-27 01:35:26 +08:00
test_python_map_mp_seed_repeatability()
2022-09-26 14:44:58 +08:00
test_map_with_deprecated_parameter()