Files
wilds-ijepa/src/datasets/imagenet1k.py
T
2023-06-13 13:03:30 +00:00

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