224 lines
6.8 KiB
Python
224 lines
6.8 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
# All rights reserved.
|
|
#
|
|
# This source code is licensed under the license found in the
|
|
# LICENSE file in the root directory of this source tree.
|
|
#
|
|
|
|
import os
|
|
import subprocess
|
|
import time
|
|
|
|
import numpy as np
|
|
|
|
from logging import getLogger
|
|
|
|
import torch
|
|
import torchvision
|
|
|
|
_GLOBAL_SEED = 0
|
|
logger = getLogger()
|
|
|
|
|
|
def make_imagenet1k(
|
|
transform,
|
|
batch_size,
|
|
collator=None,
|
|
pin_mem=True,
|
|
num_workers=8,
|
|
world_size=1,
|
|
rank=0,
|
|
root_path=None,
|
|
image_folder=None,
|
|
training=True,
|
|
copy_data=False,
|
|
drop_last=True,
|
|
subset_file=None
|
|
):
|
|
dataset = ImageNet(
|
|
root=root_path,
|
|
image_folder=image_folder,
|
|
transform=transform,
|
|
train=training,
|
|
copy_data=copy_data,
|
|
index_targets=False)
|
|
if subset_file is not None:
|
|
dataset = ImageNetSubset(dataset, subset_file)
|
|
logger.info('ImageNet dataset created')
|
|
dist_sampler = torch.utils.data.distributed.DistributedSampler(
|
|
dataset=dataset,
|
|
num_replicas=world_size,
|
|
rank=rank)
|
|
data_loader = torch.utils.data.DataLoader(
|
|
dataset,
|
|
collate_fn=collator,
|
|
sampler=dist_sampler,
|
|
batch_size=batch_size,
|
|
drop_last=drop_last,
|
|
pin_memory=pin_mem,
|
|
num_workers=num_workers,
|
|
persistent_workers=False)
|
|
logger.info('ImageNet unsupervised data loader created')
|
|
|
|
return dataset, data_loader, dist_sampler
|
|
|
|
|
|
class ImageNet(torchvision.datasets.ImageFolder):
|
|
|
|
def __init__(
|
|
self,
|
|
root,
|
|
image_folder='imagenet_full_size/061417/',
|
|
tar_file='imagenet_full_size-061417.tar.gz',
|
|
transform=None,
|
|
train=True,
|
|
job_id=None,
|
|
local_rank=None,
|
|
copy_data=True,
|
|
index_targets=False
|
|
):
|
|
"""
|
|
ImageNet
|
|
|
|
Dataset wrapper (can copy data locally to machine)
|
|
|
|
:param root: root network directory for ImageNet data
|
|
:param image_folder: path to images inside root network directory
|
|
:param tar_file: zipped image_folder inside root network directory
|
|
:param train: whether to load train data (or validation)
|
|
:param job_id: scheduler job-id used to create dir on local machine
|
|
:param copy_data: whether to copy data from network file locally
|
|
:param index_targets: whether to index the id of each labeled image
|
|
"""
|
|
|
|
suffix = 'train/' if train else 'val/'
|
|
data_path = None
|
|
if copy_data:
|
|
logger.info('copying data locally')
|
|
data_path = copy_imgnt_locally(
|
|
root=root,
|
|
suffix=suffix,
|
|
image_folder=image_folder,
|
|
tar_file=tar_file,
|
|
job_id=job_id,
|
|
local_rank=local_rank)
|
|
if (not copy_data) or (data_path is None):
|
|
data_path = os.path.join(root, image_folder, suffix)
|
|
logger.info(f'data-path {data_path}')
|
|
|
|
super(ImageNet, self).__init__(root=data_path, transform=transform)
|
|
logger.info('Initialized ImageNet')
|
|
|
|
if index_targets:
|
|
self.targets = []
|
|
for sample in self.samples:
|
|
self.targets.append(sample[1])
|
|
self.targets = np.array(self.targets)
|
|
self.samples = np.array(self.samples)
|
|
|
|
mint = None
|
|
self.target_indices = []
|
|
for t in range(len(self.classes)):
|
|
indices = np.squeeze(np.argwhere(
|
|
self.targets == t)).tolist()
|
|
self.target_indices.append(indices)
|
|
mint = len(indices) if mint is None else min(mint, len(indices))
|
|
logger.debug(f'num-labeled target {t} {len(indices)}')
|
|
logger.info(f'min. labeled indices {mint}')
|
|
|
|
|
|
class ImageNetSubset(object):
|
|
|
|
def __init__(self, dataset, subset_file):
|
|
"""
|
|
ImageNetSubset
|
|
|
|
:param dataset: ImageNet dataset object
|
|
:param subset_file: '.txt' file containing IDs of IN1K images to keep
|
|
"""
|
|
self.dataset = dataset
|
|
self.subset_file = subset_file
|
|
self.filter_dataset_(subset_file)
|
|
|
|
def filter_dataset_(self, subset_file):
|
|
""" Filter self.dataset to a subset """
|
|
root = self.dataset.root
|
|
class_to_idx = self.dataset.class_to_idx
|
|
# -- update samples to subset of IN1k targets/samples
|
|
new_samples = []
|
|
logger.info(f'Using {subset_file}')
|
|
with open(subset_file, 'r') as rfile:
|
|
for line in rfile:
|
|
class_name = line.split('_')[0]
|
|
target = class_to_idx[class_name]
|
|
img = line.split('\n')[0]
|
|
new_samples.append(
|
|
(os.path.join(root, class_name, img), target)
|
|
)
|
|
self.samples = new_samples
|
|
|
|
@property
|
|
def classes(self):
|
|
return self.dataset.classes
|
|
|
|
def __len__(self):
|
|
return len(self.samples)
|
|
|
|
def __getitem__(self, index):
|
|
path, target = self.samples[index]
|
|
img = self.dataset.loader(path)
|
|
if self.dataset.transform is not None:
|
|
img = self.dataset.transform(img)
|
|
if self.dataset.target_transform is not None:
|
|
target = self.dataset.target_transform(target)
|
|
return img, target
|
|
|
|
|
|
def copy_imgnt_locally(
|
|
root,
|
|
suffix,
|
|
image_folder='imagenet_full_size/061417/',
|
|
tar_file='imagenet_full_size-061417.tar.gz',
|
|
job_id=None,
|
|
local_rank=None
|
|
):
|
|
if job_id is None:
|
|
try:
|
|
job_id = os.environ['SLURM_JOBID']
|
|
except Exception:
|
|
logger.info('No job-id, will load directly from network file')
|
|
return None
|
|
|
|
if local_rank is None:
|
|
try:
|
|
local_rank = int(os.environ['SLURM_LOCALID'])
|
|
except Exception:
|
|
logger.info('No job-id, will load directly from network file')
|
|
return None
|
|
|
|
source_file = os.path.join(root, tar_file)
|
|
target = f'/scratch/slurm_tmpdir/{job_id}/'
|
|
target_file = os.path.join(target, tar_file)
|
|
data_path = os.path.join(target, image_folder, suffix)
|
|
logger.info(f'{source_file}\n{target}\n{target_file}\n{data_path}')
|
|
|
|
tmp_sgnl_file = os.path.join(target, 'copy_signal.txt')
|
|
|
|
if not os.path.exists(data_path):
|
|
if local_rank == 0:
|
|
commands = [
|
|
['tar', '-xf', source_file, '-C', target]]
|
|
for cmnd in commands:
|
|
start_time = time.time()
|
|
logger.info(f'Executing {cmnd}')
|
|
subprocess.run(cmnd)
|
|
logger.info(f'Cmnd took {(time.time()-start_time)/60.} min.')
|
|
with open(tmp_sgnl_file, '+w') as f:
|
|
print('Done copying locally.', file=f)
|
|
else:
|
|
while not os.path.exists(tmp_sgnl_file):
|
|
time.sleep(60)
|
|
logger.info(f'{local_rank}: Checking {tmp_sgnl_file}')
|
|
|
|
return data_path
|