mirror of
https://github.com/modelscope/modelscope.git
synced 2026-07-10 12:33:28 +02:00
1. Optimize downloading meta-csv files for large-scale dataset like mPLUG-youku (> 1GB for meta csv mapping) 2. Add head and overall progress bar for NativeIterableDataset 3. Modify the try-catch info for oss_utils Link: https://code.alibaba-inc.com/Ali-MaaS/MaaS-lib/codereview/12952842
186 lines
8.5 KiB
Python
186 lines
8.5 KiB
Python
# Copyright (c) Alibaba, Inc. and its affiliates.
|
|
|
|
import os
|
|
import shutil
|
|
from collections import defaultdict
|
|
|
|
import json
|
|
from datasets.utils.filelock import FileLock
|
|
|
|
from modelscope.hub.api import HubApi
|
|
from modelscope.msdatasets.context.dataset_context_config import \
|
|
DatasetContextConfig
|
|
from modelscope.msdatasets.meta.data_meta_config import DataMetaConfig
|
|
from modelscope.msdatasets.utils.dataset_utils import (
|
|
get_dataset_files, get_target_dataset_structure)
|
|
from modelscope.utils.constant import (DatasetFormations, DatasetPathName,
|
|
DownloadMode)
|
|
|
|
|
|
class DataMetaManager(object):
|
|
"""Data-meta manager."""
|
|
|
|
def __init__(self, dataset_context_config: DatasetContextConfig):
|
|
self.dataset_context_config = dataset_context_config
|
|
self.api = HubApi()
|
|
|
|
def fetch_meta_files(self) -> None:
|
|
|
|
# Init meta infos
|
|
dataset_name = self.dataset_context_config.dataset_name
|
|
namespace = self.dataset_context_config.namespace
|
|
download_mode = self.dataset_context_config.download_mode
|
|
version = self.dataset_context_config.version
|
|
cache_root_dir = self.dataset_context_config.cache_root_dir
|
|
subset_name = self.dataset_context_config.subset_name
|
|
split = self.dataset_context_config.split
|
|
|
|
dataset_version_cache_root_dir = os.path.join(cache_root_dir,
|
|
namespace, dataset_name,
|
|
version)
|
|
meta_cache_dir = os.path.join(dataset_version_cache_root_dir,
|
|
DatasetPathName.META_NAME)
|
|
data_meta_config = self.dataset_context_config.data_meta_config or DataMetaConfig(
|
|
)
|
|
|
|
# Get lock file path
|
|
if not subset_name:
|
|
lock_subset_name = DatasetPathName.LOCK_FILE_NAME_ANY
|
|
else:
|
|
lock_subset_name = subset_name
|
|
if not split:
|
|
lock_split = DatasetPathName.LOCK_FILE_NAME_ANY
|
|
else:
|
|
lock_split = split
|
|
lock_file_name = f'{DatasetPathName.META_NAME}{DatasetPathName.LOCK_FILE_NAME_DELIMITER}{dataset_name}' \
|
|
f'{DatasetPathName.LOCK_FILE_NAME_DELIMITER}{version}' \
|
|
f'{DatasetPathName.LOCK_FILE_NAME_DELIMITER}' \
|
|
f'{lock_subset_name}{DatasetPathName.LOCK_FILE_NAME_DELIMITER}{lock_split}.lock'
|
|
lock_file_path = os.path.join(dataset_version_cache_root_dir,
|
|
lock_file_name)
|
|
os.makedirs(dataset_version_cache_root_dir, exist_ok=True)
|
|
|
|
# Fetch meta from cache or hub if reuse dataset
|
|
if download_mode == DownloadMode.REUSE_DATASET_IF_EXISTS:
|
|
if os.path.exists(meta_cache_dir) and os.listdir(meta_cache_dir):
|
|
dataset_scripts, dataset_formation = self._fetch_meta_from_cache(
|
|
meta_cache_dir)
|
|
else:
|
|
# Fetch meta-files from modelscope-hub if cache does not exist
|
|
with FileLock(lock_file=lock_file_path):
|
|
os.makedirs(meta_cache_dir, exist_ok=True)
|
|
dataset_scripts, dataset_formation = self._fetch_meta_from_hub(
|
|
dataset_name, namespace, version, meta_cache_dir)
|
|
# Fetch meta from hub if force download
|
|
elif download_mode == DownloadMode.FORCE_REDOWNLOAD:
|
|
# Clean meta-files
|
|
if os.path.exists(meta_cache_dir) and os.listdir(meta_cache_dir):
|
|
shutil.rmtree(meta_cache_dir, ignore_errors=True)
|
|
# Re-download meta-files
|
|
with FileLock(lock_file=lock_file_path):
|
|
os.makedirs(meta_cache_dir, exist_ok=True)
|
|
dataset_scripts, dataset_formation = self._fetch_meta_from_hub(
|
|
dataset_name, namespace, version, meta_cache_dir)
|
|
else:
|
|
raise ValueError(
|
|
f'Expected values of download_mode: '
|
|
f'{DownloadMode.REUSE_DATASET_IF_EXISTS.value} or '
|
|
f'{DownloadMode.FORCE_REDOWNLOAD.value}, but got {download_mode} .'
|
|
)
|
|
|
|
# Set data_meta_config
|
|
data_meta_config.meta_cache_dir = meta_cache_dir
|
|
data_meta_config.dataset_scripts = dataset_scripts
|
|
data_meta_config.dataset_formation = dataset_formation
|
|
|
|
# Set dataset_context_config
|
|
self.dataset_context_config.data_meta_config = data_meta_config
|
|
self.dataset_context_config.dataset_version_cache_root_dir = dataset_version_cache_root_dir
|
|
self.dataset_context_config.global_meta_lock_file_path = lock_file_path
|
|
|
|
def parse_dataset_structure(self):
|
|
# Get dataset_name.json
|
|
dataset_name = self.dataset_context_config.dataset_name
|
|
subset_name = self.dataset_context_config.subset_name
|
|
split = self.dataset_context_config.split
|
|
namespace = self.dataset_context_config.namespace
|
|
version = self.dataset_context_config.version
|
|
data_meta_config = self.dataset_context_config.data_meta_config or DataMetaConfig(
|
|
)
|
|
|
|
dataset_json = None
|
|
dataset_py_script = None
|
|
dataset_scripts = data_meta_config.dataset_scripts
|
|
if not dataset_scripts or len(dataset_scripts) == 0:
|
|
raise 'Cannot find dataset meta-files, please fetch meta from modelscope hub.'
|
|
if '.py' in dataset_scripts:
|
|
dataset_py_script = dataset_scripts['.py'][0]
|
|
for json_path in dataset_scripts['.json']:
|
|
if json_path.endswith(f'{dataset_name}.json'):
|
|
with open(json_path, encoding='utf-8') as dataset_json_file:
|
|
dataset_json = json.load(dataset_json_file)
|
|
break
|
|
if not dataset_json and not dataset_py_script:
|
|
raise f'File {dataset_name}.json and {dataset_name}.py not found, please specify at least one meta-file.'
|
|
|
|
# Parse meta and get dataset structure
|
|
if dataset_py_script:
|
|
data_meta_config.dataset_py_script = dataset_py_script
|
|
else:
|
|
target_subset_name, target_dataset_structure = get_target_dataset_structure(
|
|
dataset_json, subset_name, split)
|
|
meta_map, file_map, args_map, type_map = get_dataset_files(
|
|
target_dataset_structure, dataset_name, namespace,
|
|
self.dataset_context_config, version)
|
|
|
|
data_meta_config.meta_data_files = meta_map
|
|
data_meta_config.zip_data_files = file_map
|
|
data_meta_config.meta_args_map = args_map
|
|
data_meta_config.meta_type_map = type_map
|
|
data_meta_config.target_dataset_structure = target_dataset_structure
|
|
|
|
self.dataset_context_config.data_meta_config = data_meta_config
|
|
|
|
def fetch_virgo_meta(self) -> None:
|
|
virgo_dataset_id = self.dataset_context_config.dataset_name
|
|
version = int(self.dataset_context_config.version)
|
|
|
|
meta_content = self.api.get_virgo_meta(
|
|
dataset_id=virgo_dataset_id, version=version)
|
|
self.dataset_context_config.config_kwargs.update(meta_content)
|
|
|
|
def _fetch_meta_from_cache(self, meta_cache_dir):
|
|
local_paths = defaultdict(list)
|
|
dataset_type = None
|
|
for meta_file_name in os.listdir(meta_cache_dir):
|
|
file_ext = os.path.splitext(meta_file_name)[-1]
|
|
if file_ext == DatasetFormations.formation_mark_ext.value:
|
|
dataset_type = int(os.path.splitext(meta_file_name)[0])
|
|
continue
|
|
local_paths[file_ext].append(
|
|
os.path.join(meta_cache_dir, meta_file_name))
|
|
if not dataset_type:
|
|
raise FileNotFoundError(
|
|
f'{DatasetFormations.formation_mark_ext.value} file does not exist, '
|
|
f'please use {DownloadMode.FORCE_REDOWNLOAD.value} .')
|
|
|
|
return local_paths, DatasetFormations(dataset_type)
|
|
|
|
def _fetch_meta_from_hub(self, dataset_name: str, namespace: str,
|
|
revision: str, meta_cache_dir: str):
|
|
|
|
# Fetch id and type of dataset
|
|
dataset_id, dataset_type = self.api.get_dataset_id_and_type(
|
|
dataset_name, namespace)
|
|
|
|
# Fetch meta file-list of dataset
|
|
file_list = self.api.get_dataset_meta_file_list(
|
|
dataset_name, namespace, dataset_id, revision)
|
|
|
|
# Fetch urls of meta-files
|
|
local_paths, dataset_formation = self.api.get_dataset_meta_files_local_paths(
|
|
dataset_name, namespace, revision, meta_cache_dir, dataset_type,
|
|
file_list)
|
|
|
|
return local_paths, dataset_formation
|