Vansh Chugh commited on
Commit ·
550f5fe
1
Parent(s): 05f1e67
cleanup: remove dead code (training/, audio modality, chunk_inference, unused imports)
Browse files- app.py +11 -21
- models/CLAP/training/__init__.py +0 -0
- models/CLAP/training/audioset_textmap.npy +0 -3
- models/CLAP/training/data.py +0 -966
- models/CLAP/training/distributed.py +0 -150
- models/CLAP/training/imagenet_zeroshot_data.py +0 -1088
- models/CLAP/training/infer_demo.py +0 -109
- models/CLAP/training/logger.py +0 -30
- models/CLAP/training/lp_main.py +0 -670
- models/CLAP/training/lp_train.py +0 -301
- models/CLAP/training/main.py +0 -596
- models/CLAP/training/params.py +0 -563
- models/CLAP/training/scheduler.py +0 -24
- models/CLAP/training/train.py +0 -838
- models/CLAP/training/zero_shot.py +0 -95
- models/clap_encoder.py +5 -46
- models/resunet.py +1 -60
app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import sys
|
| 2 |
-
sys.stdout.reconfigure(line_buffering=True)
|
| 3 |
|
| 4 |
import os
|
| 5 |
import tempfile
|
|
@@ -8,7 +8,6 @@ import traceback
|
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
import librosa
|
| 11 |
-
import numpy as np
|
| 12 |
import torch
|
| 13 |
import soundfile as sf
|
| 14 |
from huggingface_hub import hf_hub_download
|
|
@@ -17,12 +16,8 @@ from pyharp import ModelCard, build_endpoint
|
|
| 17 |
from models.resunet import ResUNet30
|
| 18 |
from models.clap_encoder import CLAP_Encoder
|
| 19 |
|
| 20 |
-
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 21 |
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 22 |
|
| 23 |
-
REPO_ID = "Audio-AGI/AudioSep"
|
| 24 |
-
REPO_TYPE = "space"
|
| 25 |
-
|
| 26 |
# Model loading state — populated by the background thread.
|
| 27 |
ss_model = None
|
| 28 |
query_encoder = None
|
|
@@ -33,24 +28,19 @@ model_error = None
|
|
| 33 |
def load_model():
|
| 34 |
global ss_model, query_encoder, model_loading, model_error
|
| 35 |
try:
|
| 36 |
-
print(
|
| 37 |
main_ckpt_path = hf_hub_download(
|
| 38 |
-
repo_id=
|
| 39 |
-
repo_type=
|
| 40 |
filename="checkpoint/audiosep_base_4M_steps.ckpt",
|
| 41 |
)
|
| 42 |
-
|
| 43 |
-
print(f"Downloading CLAP checkpoint from {REPO_ID}...", flush=True)
|
| 44 |
clap_ckpt_path = hf_hub_download(
|
| 45 |
-
repo_id=
|
| 46 |
-
repo_type=
|
| 47 |
filename="checkpoint/music_speech_audioset_epoch_15_esc_89.98.pt",
|
| 48 |
)
|
| 49 |
|
| 50 |
-
print("Loading CLAP encoder...", flush=True)
|
| 51 |
query_encoder = CLAP_Encoder(pretrained_path=clap_ckpt_path).eval()
|
| 52 |
-
|
| 53 |
-
print("Loading ResUNet30 separation model...", flush=True)
|
| 54 |
_ss_model = ResUNet30(input_channels=1, output_channels=1, condition_size=512)
|
| 55 |
|
| 56 |
# Load weights from the Lightning checkpoint — keys are prefixed with "ss_model."
|
|
@@ -64,10 +54,10 @@ def load_model():
|
|
| 64 |
_ss_model.eval().to(DEVICE)
|
| 65 |
|
| 66 |
ss_model = _ss_model
|
| 67 |
-
print("Model loaded successfully."
|
| 68 |
except Exception as e:
|
| 69 |
model_error = str(e)
|
| 70 |
-
print(f"Error loading model: {traceback.format_exc()}"
|
| 71 |
finally:
|
| 72 |
model_loading = False
|
| 73 |
|
|
@@ -84,15 +74,15 @@ model_card = ModelCard(
|
|
| 84 |
|
| 85 |
|
| 86 |
@torch.inference_mode()
|
| 87 |
-
def process_fn(audio_path: str, text_query: str)
|
| 88 |
if model_loading:
|
| 89 |
raise gr.Error("Model is still loading, please wait a moment and try again.")
|
| 90 |
if ss_model is None:
|
| 91 |
raise gr.Error(f"Model failed to load: {model_error}")
|
| 92 |
|
| 93 |
-
print(f"Separating [{audio_path}] with query [{text_query}]"
|
| 94 |
|
| 95 |
-
mixture, _ = librosa.load(audio_path, sr=32000, mono=True)
|
| 96 |
|
| 97 |
conditions = query_encoder.get_query_embed(
|
| 98 |
modality="text",
|
|
|
|
| 1 |
import sys
|
| 2 |
+
sys.stdout.reconfigure(line_buffering=True) # flush print() calls immediately so HF Space logs are live
|
| 3 |
|
| 4 |
import os
|
| 5 |
import tempfile
|
|
|
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
import librosa
|
|
|
|
| 11 |
import torch
|
| 12 |
import soundfile as sf
|
| 13 |
from huggingface_hub import hf_hub_download
|
|
|
|
| 16 |
from models.resunet import ResUNet30
|
| 17 |
from models.clap_encoder import CLAP_Encoder
|
| 18 |
|
|
|
|
| 19 |
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 20 |
|
|
|
|
|
|
|
|
|
|
| 21 |
# Model loading state — populated by the background thread.
|
| 22 |
ss_model = None
|
| 23 |
query_encoder = None
|
|
|
|
| 28 |
def load_model():
|
| 29 |
global ss_model, query_encoder, model_loading, model_error
|
| 30 |
try:
|
| 31 |
+
print("Downloading checkpoints...")
|
| 32 |
main_ckpt_path = hf_hub_download(
|
| 33 |
+
repo_id="Audio-AGI/AudioSep",
|
| 34 |
+
repo_type="space",
|
| 35 |
filename="checkpoint/audiosep_base_4M_steps.ckpt",
|
| 36 |
)
|
|
|
|
|
|
|
| 37 |
clap_ckpt_path = hf_hub_download(
|
| 38 |
+
repo_id="Audio-AGI/AudioSep",
|
| 39 |
+
repo_type="space",
|
| 40 |
filename="checkpoint/music_speech_audioset_epoch_15_esc_89.98.pt",
|
| 41 |
)
|
| 42 |
|
|
|
|
| 43 |
query_encoder = CLAP_Encoder(pretrained_path=clap_ckpt_path).eval()
|
|
|
|
|
|
|
| 44 |
_ss_model = ResUNet30(input_channels=1, output_channels=1, condition_size=512)
|
| 45 |
|
| 46 |
# Load weights from the Lightning checkpoint — keys are prefixed with "ss_model."
|
|
|
|
| 54 |
_ss_model.eval().to(DEVICE)
|
| 55 |
|
| 56 |
ss_model = _ss_model
|
| 57 |
+
print("Model loaded successfully.")
|
| 58 |
except Exception as e:
|
| 59 |
model_error = str(e)
|
| 60 |
+
print(f"Error loading model: {traceback.format_exc()}")
|
| 61 |
finally:
|
| 62 |
model_loading = False
|
| 63 |
|
|
|
|
| 74 |
|
| 75 |
|
| 76 |
@torch.inference_mode()
|
| 77 |
+
def process_fn(audio_path: str, text_query: str):
|
| 78 |
if model_loading:
|
| 79 |
raise gr.Error("Model is still loading, please wait a moment and try again.")
|
| 80 |
if ss_model is None:
|
| 81 |
raise gr.Error(f"Model failed to load: {model_error}")
|
| 82 |
|
| 83 |
+
print(f"Separating [{audio_path}] with query [{text_query}]")
|
| 84 |
|
| 85 |
+
mixture, _ = librosa.load(audio_path, sr=32000, mono=True) # model expects 32k audio
|
| 86 |
|
| 87 |
conditions = query_encoder.get_query_embed(
|
| 88 |
modality="text",
|
models/CLAP/training/__init__.py
DELETED
|
File without changes
|
models/CLAP/training/audioset_textmap.npy
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:bada103070d92f9eadd33e1b4f45ec8583f59080ef218c966b43294bd4c86d5b
|
| 3 |
-
size 84448
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/data.py
DELETED
|
@@ -1,966 +0,0 @@
|
|
| 1 |
-
import ast
|
| 2 |
-
import json
|
| 3 |
-
import logging
|
| 4 |
-
import math
|
| 5 |
-
import os
|
| 6 |
-
import random
|
| 7 |
-
import io
|
| 8 |
-
import copy
|
| 9 |
-
import tempfile
|
| 10 |
-
from dataclasses import dataclass
|
| 11 |
-
from functools import partial
|
| 12 |
-
from pathlib import Path
|
| 13 |
-
import numpy as np
|
| 14 |
-
import torch
|
| 15 |
-
import torch.nn as nn
|
| 16 |
-
import torch.nn.functional as F
|
| 17 |
-
import torchvision.transforms
|
| 18 |
-
import braceexpand
|
| 19 |
-
import soundfile as sf
|
| 20 |
-
from PIL import Image
|
| 21 |
-
from torch.utils.data import Dataset, DataLoader, SubsetRandomSampler
|
| 22 |
-
from torch.utils.data.distributed import DistributedSampler
|
| 23 |
-
|
| 24 |
-
try:
|
| 25 |
-
import horovod.torch as hvd
|
| 26 |
-
except ImportError:
|
| 27 |
-
hvd = None
|
| 28 |
-
|
| 29 |
-
try:
|
| 30 |
-
import torchaudio
|
| 31 |
-
except ImportError:
|
| 32 |
-
torchaudio = None
|
| 33 |
-
|
| 34 |
-
from models.CLAP.open_clip import tokenize
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def tokenizer(text):
|
| 38 |
-
return tokenize(text).squeeze(0)
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
from transformers import RobertaTokenizer
|
| 42 |
-
|
| 43 |
-
tokenize = RobertaTokenizer.from_pretrained("roberta-base")
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def tokenizer(text):
|
| 47 |
-
result = tokenize(
|
| 48 |
-
text,
|
| 49 |
-
padding="max_length",
|
| 50 |
-
truncation=True,
|
| 51 |
-
max_length=77,
|
| 52 |
-
return_tensors="pt",
|
| 53 |
-
)
|
| 54 |
-
return {k: v.squeeze(0) for k, v in result.items()}
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
# initizlied the audioset map
|
| 58 |
-
_AUDIOSET_MAP_PATH = os.path.join(Path(__file__).parent, "audioset_textmap.npy")
|
| 59 |
-
_AUDIOSET_MAP = np.load(_AUDIOSET_MAP_PATH, allow_pickle=True)
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
def int16_to_float32(x):
|
| 63 |
-
return (x / 32767.0).astype(np.float32)
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
def float32_to_int16(x):
|
| 67 |
-
x = np.clip(x, a_min=-1.0, a_max=1.0)
|
| 68 |
-
return (x * 32767.0).astype(np.int16)
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
# For Toy Dataset
|
| 72 |
-
class ToyDataset(Dataset):
|
| 73 |
-
def __init__(self, index_path, ipc, config, eval_mode=False):
|
| 74 |
-
"""Toy Dataset for testing the audioset input with text labels
|
| 75 |
-
Parameters
|
| 76 |
-
----------
|
| 77 |
-
index_path: str
|
| 78 |
-
the link to the h5 file of each audio
|
| 79 |
-
idc: str
|
| 80 |
-
the link to the npy file, the number of samples in each class
|
| 81 |
-
config: dict
|
| 82 |
-
the audio cfg file
|
| 83 |
-
eval_model (bool): to indicate if the dataset is a testing dataset
|
| 84 |
-
"""
|
| 85 |
-
self.audio_cfg = config["audio_cfg"]
|
| 86 |
-
self.text_cfg = config["text_cfg"]
|
| 87 |
-
self.fp = h5py.File(index_path, "r")
|
| 88 |
-
self.ipc = np.load(ipc, allow_pickle=True)
|
| 89 |
-
self.total_size = len(self.fp["audio_name"])
|
| 90 |
-
self.classes_num = self.audio_cfg["class_num"]
|
| 91 |
-
self.eval_mode = eval_mode
|
| 92 |
-
|
| 93 |
-
if not eval_mode:
|
| 94 |
-
self.generate_queue()
|
| 95 |
-
else:
|
| 96 |
-
self.queue = []
|
| 97 |
-
for i in range(self.total_size):
|
| 98 |
-
target = self.fp["target"][i]
|
| 99 |
-
if np.sum(target) > 0:
|
| 100 |
-
self.queue.append(i)
|
| 101 |
-
self.total_size = len(self.queue)
|
| 102 |
-
logging.info("total dataset size: %d" % (self.total_size))
|
| 103 |
-
logging.info("class num: %d" % (self.classes_num))
|
| 104 |
-
|
| 105 |
-
def time_shifting(self, x):
|
| 106 |
-
frame_num = len(x)
|
| 107 |
-
shift_len = random.randint(0, frame_num - 1)
|
| 108 |
-
new_sample = np.concatenate([x[shift_len:], x[:shift_len]], axis=0)
|
| 109 |
-
return new_sample
|
| 110 |
-
|
| 111 |
-
def generate_queue(self):
|
| 112 |
-
self.queue = []
|
| 113 |
-
while len(self.queue) < self.total_size:
|
| 114 |
-
class_set = [*range(self.classes_num)]
|
| 115 |
-
random.shuffle(class_set)
|
| 116 |
-
self.queue += [
|
| 117 |
-
self.ipc[d][random.randint(0, len(self.ipc[d]) - 1)] for d in class_set
|
| 118 |
-
]
|
| 119 |
-
self.queue = self.queue[: self.total_size]
|
| 120 |
-
|
| 121 |
-
logging.info("queue regenerated:%s" % (self.queue[-5:]))
|
| 122 |
-
|
| 123 |
-
def crop_wav(self, x):
|
| 124 |
-
crop_size = self.audio_cfg["crop_size"]
|
| 125 |
-
crop_pos = random.randint(0, len(x) - crop_size - 1)
|
| 126 |
-
return x[crop_pos : crop_pos + crop_size]
|
| 127 |
-
|
| 128 |
-
def prompt_text(self, target):
|
| 129 |
-
events = _AUDIOSET_MAP[np.where(target > 0)]
|
| 130 |
-
event_text = "The sounds of " + ", ".join(events[:-1]) + " and " + events[-1]
|
| 131 |
-
text = tokenize(event_text)[0]
|
| 132 |
-
return text
|
| 133 |
-
|
| 134 |
-
def __getitem__(self, index):
|
| 135 |
-
"""Load waveform, text, and target of an audio clip
|
| 136 |
-
|
| 137 |
-
Parameters
|
| 138 |
-
----------
|
| 139 |
-
index: int
|
| 140 |
-
the index number
|
| 141 |
-
Return
|
| 142 |
-
------
|
| 143 |
-
output: dict {
|
| 144 |
-
"hdf5_path": str,
|
| 145 |
-
"index_in_hdf5": int,
|
| 146 |
-
"audio_name": str,
|
| 147 |
-
"waveform": list (audio_length,),
|
| 148 |
-
"target": list (class_num, ),
|
| 149 |
-
"text": torch.tensor (context_length,)
|
| 150 |
-
}
|
| 151 |
-
the output dictionary
|
| 152 |
-
"""
|
| 153 |
-
s_index = self.queue[index]
|
| 154 |
-
|
| 155 |
-
audio_name = self.fp["audio_name"][s_index].decode()
|
| 156 |
-
# Hardcode here CHANGE
|
| 157 |
-
hdf5_path = (
|
| 158 |
-
self.fp["hdf5_path"][s_index]
|
| 159 |
-
.decode()
|
| 160 |
-
.replace(
|
| 161 |
-
"../workspace",
|
| 162 |
-
"/home/la/kechen/Research/ke_zsasp/workspace",
|
| 163 |
-
)
|
| 164 |
-
)
|
| 165 |
-
r_idx = self.fp["index_in_hdf5"][s_index]
|
| 166 |
-
target = self.fp["target"][s_index].astype(np.float32)
|
| 167 |
-
text = self.prompt_text(target)
|
| 168 |
-
with h5py.File(hdf5_path, "r") as f:
|
| 169 |
-
waveform = int16_to_float32(f["waveform"][r_idx])[
|
| 170 |
-
: self.audio_cfg["clip_samples"]
|
| 171 |
-
]
|
| 172 |
-
assert (
|
| 173 |
-
len(waveform) == self.audio_cfg["clip_samples"]
|
| 174 |
-
), "The sample length is not match"
|
| 175 |
-
# Time shift
|
| 176 |
-
# if (self.config.enable_time_shift) and (not self.eval_mode):
|
| 177 |
-
# waveform = self.time_shifting(waveform)
|
| 178 |
-
# # Label Enhance
|
| 179 |
-
# if (self.config.crop_size is not None) and (not self.eval_mode):
|
| 180 |
-
# waveform = self.crop_wav(waveform)
|
| 181 |
-
# # the label enhance rate is fixed 0.5
|
| 182 |
-
# if (self.config.enable_label_enhance) and (not self.eval_mode) and random.random() < 0.5:
|
| 183 |
-
# kidx = np.where(target)[0]
|
| 184 |
-
# for k in kidx:
|
| 185 |
-
# for add_key in self.class_map[k][1]:
|
| 186 |
-
# target[add_key] = 1.0
|
| 187 |
-
# if len(self.class_map[k][2]) > 0:
|
| 188 |
-
# add_key = random.choice(self.class_map[k][2])
|
| 189 |
-
# target[add_key] = 1.0
|
| 190 |
-
|
| 191 |
-
# missing the text input
|
| 192 |
-
mel_spec = get_mel(torch.from_numpy(waveform), self.audio_cfg)[None, :, :]
|
| 193 |
-
mel_spec = (
|
| 194 |
-
torch.cat(
|
| 195 |
-
[mel_spec, mel_spec.clone(), mel_spec.clone(), mel_spec.clone()], dim=0
|
| 196 |
-
)
|
| 197 |
-
.cpu()
|
| 198 |
-
.numpy()
|
| 199 |
-
)
|
| 200 |
-
longer = random.choice([True, False])
|
| 201 |
-
if longer == False:
|
| 202 |
-
mel_spec[1:, :, :] = 0.0
|
| 203 |
-
data_dict = {
|
| 204 |
-
"hdf5_path": hdf5_path,
|
| 205 |
-
"index_in_hdf5": r_idx,
|
| 206 |
-
"audio_name": audio_name,
|
| 207 |
-
"waveform": waveform,
|
| 208 |
-
"class_label": target,
|
| 209 |
-
"text": text,
|
| 210 |
-
"longer": longer,
|
| 211 |
-
"mel_fusion": mel_spec,
|
| 212 |
-
}
|
| 213 |
-
return data_dict
|
| 214 |
-
|
| 215 |
-
def __len__(self):
|
| 216 |
-
return self.total_size
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
class CsvDataset(Dataset):
|
| 220 |
-
def __init__(self, input_filename, transforms, img_key, caption_key, sep="\t"):
|
| 221 |
-
logging.debug(f"Loading csv data from {input_filename}.")
|
| 222 |
-
df = pd.read_csv(input_filename, sep=sep)
|
| 223 |
-
|
| 224 |
-
self.images = df[img_key].tolist()
|
| 225 |
-
self.captions = df[caption_key].tolist()
|
| 226 |
-
self.transforms = transforms
|
| 227 |
-
logging.debug("Done loading data.")
|
| 228 |
-
|
| 229 |
-
def __len__(self):
|
| 230 |
-
return len(self.captions)
|
| 231 |
-
|
| 232 |
-
def __getitem__(self, idx):
|
| 233 |
-
images = self.transforms(Image.open(str(self.images[idx])))
|
| 234 |
-
texts = tokenize([str(self.captions[idx])])[0]
|
| 235 |
-
return images, texts
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
@dataclass
|
| 239 |
-
class DataInfo:
|
| 240 |
-
dataloader: DataLoader
|
| 241 |
-
sampler: DistributedSampler
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
def preprocess_txt(text):
|
| 245 |
-
return tokenize([str(text)])[0]
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
def get_dataset_size(shards, sizefilepath_=None, is_local=True):
|
| 249 |
-
if isinstance(shards, list):
|
| 250 |
-
size_list = []
|
| 251 |
-
for s in shards:
|
| 252 |
-
size_list.append(
|
| 253 |
-
get_dataset_size(s, sizefilepath_=sizefilepath_, is_local=is_local)[0]
|
| 254 |
-
)
|
| 255 |
-
else:
|
| 256 |
-
if not is_local:
|
| 257 |
-
for n in dataset_split.keys():
|
| 258 |
-
if n in shards.split("/"):
|
| 259 |
-
break
|
| 260 |
-
for s in dataset_split[n]:
|
| 261 |
-
if s in shards.split("/"):
|
| 262 |
-
break
|
| 263 |
-
sizefilepath_ = f"./json_files/{n}/{s}/sizes.json"
|
| 264 |
-
shards_list = list(braceexpand.braceexpand(shards))
|
| 265 |
-
dir_path = os.path.dirname(shards)
|
| 266 |
-
if sizefilepath_ is not None:
|
| 267 |
-
sizes = json.load(open(sizefilepath_, "r"))
|
| 268 |
-
total_size = sum(
|
| 269 |
-
[
|
| 270 |
-
int(sizes[os.path.basename(shard.replace(".tar -", ".tar"))])
|
| 271 |
-
for shard in shards_list
|
| 272 |
-
]
|
| 273 |
-
)
|
| 274 |
-
else:
|
| 275 |
-
sizes_filename = os.path.join(dir_path, "sizes.json")
|
| 276 |
-
len_filename = os.path.join(dir_path, "__len__")
|
| 277 |
-
if os.path.exists(sizes_filename):
|
| 278 |
-
sizes = json.load(open(sizes_filename, "r"))
|
| 279 |
-
total_size = sum(
|
| 280 |
-
[int(sizes[os.path.basename(shard)]) for shard in shards_list]
|
| 281 |
-
)
|
| 282 |
-
elif os.path.exists(len_filename):
|
| 283 |
-
# FIXME this used to be eval(open(...)) but that seemed rather unsafe
|
| 284 |
-
total_size = ast.literal_eval(open(len_filename, "r").read())
|
| 285 |
-
else:
|
| 286 |
-
raise Exception(
|
| 287 |
-
"Cannot find sizes file for dataset. Please specify the path to the file."
|
| 288 |
-
)
|
| 289 |
-
# total_size = None # num samples undefined
|
| 290 |
-
# some common dataset sizes (at time of authors last download)
|
| 291 |
-
# cc3m-train: 2905954
|
| 292 |
-
# cc12m: 10968539
|
| 293 |
-
# LAION-400m: 407332084
|
| 294 |
-
num_shards = len(shards_list)
|
| 295 |
-
if isinstance(shards, list):
|
| 296 |
-
return sum(size_list), len(shards)
|
| 297 |
-
else:
|
| 298 |
-
return total_size, num_shards
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
def get_imagenet(args, preprocess_fns, split):
|
| 302 |
-
assert split in ["train", "val", "v2"]
|
| 303 |
-
is_train = split == "train"
|
| 304 |
-
preprocess_train, preprocess_val = preprocess_fns
|
| 305 |
-
|
| 306 |
-
if split == "v2":
|
| 307 |
-
from imagenetv2_pytorch import ImageNetV2Dataset
|
| 308 |
-
|
| 309 |
-
dataset = ImageNetV2Dataset(location=args.imagenet_v2, transform=preprocess_val)
|
| 310 |
-
else:
|
| 311 |
-
if is_train:
|
| 312 |
-
data_path = args.imagenet_train
|
| 313 |
-
preprocess_fn = preprocess_train
|
| 314 |
-
else:
|
| 315 |
-
data_path = args.imagenet_val
|
| 316 |
-
preprocess_fn = preprocess_val
|
| 317 |
-
assert data_path
|
| 318 |
-
|
| 319 |
-
dataset = datasets.ImageFolder(data_path, transform=preprocess_fn)
|
| 320 |
-
|
| 321 |
-
if is_train:
|
| 322 |
-
idxs = np.zeros(len(dataset.targets))
|
| 323 |
-
target_array = np.array(dataset.targets)
|
| 324 |
-
k = 50
|
| 325 |
-
for c in range(1000):
|
| 326 |
-
m = target_array == c
|
| 327 |
-
n = len(idxs[m])
|
| 328 |
-
arr = np.zeros(n)
|
| 329 |
-
arr[:k] = 1
|
| 330 |
-
np.random.shuffle(arr)
|
| 331 |
-
idxs[m] = arr
|
| 332 |
-
|
| 333 |
-
idxs = idxs.astype("int")
|
| 334 |
-
sampler = SubsetRandomSampler(np.where(idxs)[0])
|
| 335 |
-
else:
|
| 336 |
-
sampler = None
|
| 337 |
-
|
| 338 |
-
dataloader = torch.utils.data.DataLoader(
|
| 339 |
-
dataset,
|
| 340 |
-
batch_size=args.batch_size,
|
| 341 |
-
num_workers=args.workers,
|
| 342 |
-
sampler=sampler,
|
| 343 |
-
)
|
| 344 |
-
|
| 345 |
-
return DataInfo(dataloader, sampler)
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
def count_samples(dataloader):
|
| 349 |
-
os.environ["WDS_EPOCH"] = "0"
|
| 350 |
-
n_elements, n_batches = 0, 0
|
| 351 |
-
for images, texts in dataloader:
|
| 352 |
-
n_batches += 1
|
| 353 |
-
n_elements += len(images)
|
| 354 |
-
assert len(images) == len(texts)
|
| 355 |
-
return n_elements, n_batches
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
def filter_no_caption(sample):
|
| 359 |
-
return "txt" in sample
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
def log_and_continue(exn):
|
| 363 |
-
"""Call in an exception handler to ignore any exception, isssue a warning, and continue."""
|
| 364 |
-
logging.warning(f"Handling webdataset error ({repr(exn)}). Ignoring.")
|
| 365 |
-
return True
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
_SHARD_SHUFFLE_SIZE = 2000
|
| 369 |
-
_SHARD_SHUFFLE_INITIAL = 500
|
| 370 |
-
_SAMPLE_SHUFFLE_SIZE = 5000
|
| 371 |
-
_SAMPLE_SHUFFLE_INITIAL = 1000
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
def sample_prop(sizefile, inputs, proportion, is_local=True):
|
| 375 |
-
"""
|
| 376 |
-
Sample a proportion of the data.
|
| 377 |
-
"""
|
| 378 |
-
file_path_dict = {
|
| 379 |
-
os.path.split(inputs[i])[1]: os.path.split(inputs[i])[0]
|
| 380 |
-
for i in range(len(inputs))
|
| 381 |
-
}
|
| 382 |
-
sampled_filepath_dict = {}
|
| 383 |
-
sampled_size_dict = {}
|
| 384 |
-
if not is_local:
|
| 385 |
-
if os.path.exists("sizes.json"):
|
| 386 |
-
os.remove("sizes.json")
|
| 387 |
-
wget.download(sizefile, "sizes.json")
|
| 388 |
-
sizefile = "sizes.json"
|
| 389 |
-
with open(sizefile, "r", encoding="UTF-8") as f:
|
| 390 |
-
load_dict = json.load(f)
|
| 391 |
-
L = int(len(file_path_dict) * proportion)
|
| 392 |
-
subkeys = random.sample(file_path_dict.keys(), L)
|
| 393 |
-
for k in subkeys:
|
| 394 |
-
sampled_size_dict[k] = load_dict[k]
|
| 395 |
-
sampled_filepath_dict[k] = file_path_dict[k]
|
| 396 |
-
return (
|
| 397 |
-
sum(sampled_size_dict.values()),
|
| 398 |
-
L,
|
| 399 |
-
[os.path.join(v, k) for k, v in sampled_filepath_dict.items()],
|
| 400 |
-
sampled_size_dict,
|
| 401 |
-
)
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
def get_mel(audio_data, audio_cfg):
|
| 405 |
-
# mel shape: (n_mels, T)
|
| 406 |
-
mel = torchaudio.transforms.MelSpectrogram(
|
| 407 |
-
sample_rate=audio_cfg["sample_rate"],
|
| 408 |
-
n_fft=audio_cfg["window_size"],
|
| 409 |
-
win_length=audio_cfg["window_size"],
|
| 410 |
-
hop_length=audio_cfg["hop_size"],
|
| 411 |
-
center=True,
|
| 412 |
-
pad_mode="reflect",
|
| 413 |
-
power=2.0,
|
| 414 |
-
norm=None,
|
| 415 |
-
onesided=True,
|
| 416 |
-
n_mels=64,
|
| 417 |
-
f_min=audio_cfg["fmin"],
|
| 418 |
-
f_max=audio_cfg["fmax"],
|
| 419 |
-
).to(audio_data.device)
|
| 420 |
-
mel = mel(audio_data)
|
| 421 |
-
# Align to librosa:
|
| 422 |
-
# librosa_melspec = librosa.feature.melspectrogram(
|
| 423 |
-
# waveform,
|
| 424 |
-
# sr=audio_cfg['sample_rate'],
|
| 425 |
-
# n_fft=audio_cfg['window_size'],
|
| 426 |
-
# hop_length=audio_cfg['hop_size'],
|
| 427 |
-
# win_length=audio_cfg['window_size'],
|
| 428 |
-
# center=True,
|
| 429 |
-
# pad_mode="reflect",
|
| 430 |
-
# power=2.0,
|
| 431 |
-
# n_mels=64,
|
| 432 |
-
# norm=None,
|
| 433 |
-
# htk=True,
|
| 434 |
-
# f_min=audio_cfg['fmin'],
|
| 435 |
-
# f_max=audio_cfg['fmax']
|
| 436 |
-
# )
|
| 437 |
-
# we use log mel spectrogram as input
|
| 438 |
-
mel = torchaudio.transforms.AmplitudeToDB(top_db=None)(mel)
|
| 439 |
-
return mel.T # (T, n_mels)
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
def get_audio_features(
|
| 443 |
-
sample, audio_data, max_len, data_truncating, data_filling, audio_cfg
|
| 444 |
-
):
|
| 445 |
-
"""
|
| 446 |
-
Calculate and add audio features to sample.
|
| 447 |
-
Sample: a dict containing all the data of current sample.
|
| 448 |
-
audio_data: a tensor of shape (T) containing audio data.
|
| 449 |
-
max_len: the maximum length of audio data.
|
| 450 |
-
data_truncating: the method of truncating data.
|
| 451 |
-
data_filling: the method of filling data.
|
| 452 |
-
audio_cfg: a dict containing audio configuration. Comes from model_cfg['audio_cfg'].
|
| 453 |
-
"""
|
| 454 |
-
with torch.no_grad():
|
| 455 |
-
if len(audio_data) > max_len:
|
| 456 |
-
if data_truncating == "rand_trunc":
|
| 457 |
-
longer = torch.tensor([True])
|
| 458 |
-
elif data_truncating == "fusion":
|
| 459 |
-
# fusion
|
| 460 |
-
mel = get_mel(audio_data, audio_cfg)
|
| 461 |
-
# split to three parts
|
| 462 |
-
chunk_frames = (
|
| 463 |
-
max_len // audio_cfg["hop_size"] + 1
|
| 464 |
-
) # the +1 related to how the spectrogram is computed
|
| 465 |
-
total_frames = mel.shape[0]
|
| 466 |
-
if chunk_frames == total_frames:
|
| 467 |
-
# there is a corner case where the audio length is
|
| 468 |
-
# larger than max_len but smaller than max_len+hop_size.
|
| 469 |
-
# In this case, we just use the whole audio.
|
| 470 |
-
mel_fusion = torch.stack([mel, mel, mel, mel], dim=0)
|
| 471 |
-
sample["mel_fusion"] = mel_fusion
|
| 472 |
-
longer = torch.tensor([False])
|
| 473 |
-
else:
|
| 474 |
-
ranges = np.array_split(
|
| 475 |
-
list(range(0, total_frames - chunk_frames + 1)), 3
|
| 476 |
-
)
|
| 477 |
-
# print('total_frames-chunk_frames:', total_frames-chunk_frames,
|
| 478 |
-
# 'len(audio_data):', len(audio_data),
|
| 479 |
-
# 'chunk_frames:', chunk_frames,
|
| 480 |
-
# 'total_frames:', total_frames)
|
| 481 |
-
if len(ranges[1]) == 0:
|
| 482 |
-
# if the audio is too short, we just use the first chunk
|
| 483 |
-
ranges[1] = [0]
|
| 484 |
-
if len(ranges[2]) == 0:
|
| 485 |
-
# if the audio is too short, we just use the first chunk
|
| 486 |
-
ranges[2] = [0]
|
| 487 |
-
# randomly choose index for each part
|
| 488 |
-
idx_front = np.random.choice(ranges[0])
|
| 489 |
-
idx_middle = np.random.choice(ranges[1])
|
| 490 |
-
idx_back = np.random.choice(ranges[2])
|
| 491 |
-
# select mel
|
| 492 |
-
mel_chunk_front = mel[idx_front : idx_front + chunk_frames, :]
|
| 493 |
-
mel_chunk_middle = mel[idx_middle : idx_middle + chunk_frames, :]
|
| 494 |
-
mel_chunk_back = mel[idx_back : idx_back + chunk_frames, :]
|
| 495 |
-
|
| 496 |
-
# shrink the mel
|
| 497 |
-
mel_shrink = torchvision.transforms.Resize(size=[chunk_frames, 64])(
|
| 498 |
-
mel[None]
|
| 499 |
-
)[0]
|
| 500 |
-
# logging.info(f"mel_shrink.shape: {mel_shrink.shape}")
|
| 501 |
-
|
| 502 |
-
# stack
|
| 503 |
-
mel_fusion = torch.stack(
|
| 504 |
-
[mel_chunk_front, mel_chunk_middle, mel_chunk_back, mel_shrink],
|
| 505 |
-
dim=0,
|
| 506 |
-
)
|
| 507 |
-
sample["mel_fusion"] = mel_fusion
|
| 508 |
-
longer = torch.tensor([True])
|
| 509 |
-
else:
|
| 510 |
-
raise NotImplementedError(
|
| 511 |
-
f"data_truncating {data_truncating} not implemented"
|
| 512 |
-
)
|
| 513 |
-
# random crop to max_len (for compatibility)
|
| 514 |
-
overflow = len(audio_data) - max_len
|
| 515 |
-
idx = np.random.randint(0, overflow + 1)
|
| 516 |
-
audio_data = audio_data[idx : idx + max_len]
|
| 517 |
-
|
| 518 |
-
else: # padding if too short
|
| 519 |
-
if len(audio_data) < max_len: # do nothing if equal
|
| 520 |
-
if data_filling == "repeatpad":
|
| 521 |
-
n_repeat = int(max_len / len(audio_data))
|
| 522 |
-
audio_data = audio_data.repeat(n_repeat)
|
| 523 |
-
# audio_data = audio_data.unsqueeze(0).unsqueeze(0).unsqueeze(0)
|
| 524 |
-
# audio_data = F.interpolate(audio_data,size=max_len,mode="bicubic")[0,0,0]
|
| 525 |
-
audio_data = F.pad(
|
| 526 |
-
audio_data,
|
| 527 |
-
(0, max_len - len(audio_data)),
|
| 528 |
-
mode="constant",
|
| 529 |
-
value=0,
|
| 530 |
-
)
|
| 531 |
-
elif data_filling == "pad":
|
| 532 |
-
audio_data = F.pad(
|
| 533 |
-
audio_data,
|
| 534 |
-
(0, max_len - len(audio_data)),
|
| 535 |
-
mode="constant",
|
| 536 |
-
value=0,
|
| 537 |
-
)
|
| 538 |
-
elif data_filling == "repeat":
|
| 539 |
-
n_repeat = int(max_len / len(audio_data))
|
| 540 |
-
audio_data = audio_data.repeat(n_repeat + 1)[:max_len]
|
| 541 |
-
else:
|
| 542 |
-
raise NotImplementedError(
|
| 543 |
-
f"data_filling {data_filling} not implemented"
|
| 544 |
-
)
|
| 545 |
-
if data_truncating == "fusion":
|
| 546 |
-
mel = get_mel(audio_data, audio_cfg)
|
| 547 |
-
mel_fusion = torch.stack([mel, mel, mel, mel], dim=0)
|
| 548 |
-
sample["mel_fusion"] = mel_fusion
|
| 549 |
-
longer = torch.tensor([False])
|
| 550 |
-
|
| 551 |
-
sample["longer"] = longer
|
| 552 |
-
sample["waveform"] = audio_data
|
| 553 |
-
|
| 554 |
-
return sample
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
def preprocess(
|
| 558 |
-
sample,
|
| 559 |
-
audio_ext,
|
| 560 |
-
text_ext,
|
| 561 |
-
max_len,
|
| 562 |
-
audio_cfg,
|
| 563 |
-
class_index_dict=None,
|
| 564 |
-
data_filling="pad",
|
| 565 |
-
data_truncating="rand_trunc",
|
| 566 |
-
text_augment_selection=None,
|
| 567 |
-
):
|
| 568 |
-
"""
|
| 569 |
-
Preprocess a single sample for wdsdataloader.
|
| 570 |
-
"""
|
| 571 |
-
audio_data, orig_sr = sf.read(io.BytesIO(sample[audio_ext]))
|
| 572 |
-
audio_data = int16_to_float32(float32_to_int16(audio_data))
|
| 573 |
-
audio_data = torch.tensor(audio_data).float()
|
| 574 |
-
|
| 575 |
-
# TODO: (yusong) to be include in the future
|
| 576 |
-
# # if torchaudio not installed, use soundfile to load audio
|
| 577 |
-
# if torchaudio is None:
|
| 578 |
-
# audio_data, orig_sr = sf.read(io.BytesIO(sample[audio_ext]))
|
| 579 |
-
# audio_data = torch.tensor(audio_data).float()
|
| 580 |
-
# else:
|
| 581 |
-
# # https://github.com/webdataset/webdataset/blob/main/webdataset/autodecode.py
|
| 582 |
-
# with tempfile.TemporaryDirectory() as dirname:
|
| 583 |
-
# os.makedirs(dirname, exist_ok=True)
|
| 584 |
-
# fname = os.path.join(dirname, f"file.flac")
|
| 585 |
-
# with open(fname, "wb") as stream:
|
| 586 |
-
# stream.write(sample[audio_ext])
|
| 587 |
-
# audio_data, orig_sr = torchaudio.load(fname)
|
| 588 |
-
# audio_data = audio_data[0, :].float()
|
| 589 |
-
|
| 590 |
-
sample = get_audio_features(
|
| 591 |
-
sample, audio_data, max_len, data_truncating, data_filling, audio_cfg
|
| 592 |
-
)
|
| 593 |
-
del sample[audio_ext]
|
| 594 |
-
|
| 595 |
-
try:
|
| 596 |
-
json_dict_raw = json.loads(sample[text_ext].decode("utf-8"))
|
| 597 |
-
except:
|
| 598 |
-
print("sample[__url__]:", sample["__url__"])
|
| 599 |
-
|
| 600 |
-
# For selecting augmented text from dataset
|
| 601 |
-
if text_augment_selection is None or text_augment_selection == "none":
|
| 602 |
-
texts = json_dict_raw["text"]
|
| 603 |
-
elif text_augment_selection == "all":
|
| 604 |
-
if "text_augment_all" in json_dict_raw.keys():
|
| 605 |
-
texts = json_dict_raw["text_augment_all"]
|
| 606 |
-
else:
|
| 607 |
-
texts = json_dict_raw["text"]
|
| 608 |
-
elif text_augment_selection == "augment_only":
|
| 609 |
-
if "text_augment_all" in json_dict_raw.keys():
|
| 610 |
-
if json_dict_raw["text_augment_t5"] is None:
|
| 611 |
-
texts = json_dict_raw["text"]
|
| 612 |
-
else:
|
| 613 |
-
texts = json_dict_raw["text_augment_t5"]
|
| 614 |
-
else:
|
| 615 |
-
texts = json_dict_raw["text"]
|
| 616 |
-
else:
|
| 617 |
-
raise NotImplementedError(
|
| 618 |
-
f"text_augment_selection {text_augment_selection} not implemented"
|
| 619 |
-
)
|
| 620 |
-
sample["full_text"] = texts
|
| 621 |
-
|
| 622 |
-
if isinstance(texts, list) and isinstance(texts[0], str) and len(texts) > 1:
|
| 623 |
-
texts = random.choice(texts)
|
| 624 |
-
sample["raw_text"] = texts
|
| 625 |
-
sample["text"] = tokenizer(texts) # text shape: [num_token]
|
| 626 |
-
if class_index_dict is not None:
|
| 627 |
-
# https://stackoverflow.com/questions/48004243/how-to-share-large-read-only-dictionary-list-across-processes-in-multiprocessing
|
| 628 |
-
# https://stackoverflow.com/questions/45693949/storing-strings-in-a-multiprocessing-sharedctypes-array
|
| 629 |
-
# key, val = class_index_dict
|
| 630 |
-
# key = key[:].split('\n')
|
| 631 |
-
# _dict = {k: v for k, v in zip(key, val)}
|
| 632 |
-
sample["class_label"] = np.zeros(len(class_index_dict.keys()))
|
| 633 |
-
for x in json_dict_raw["tag"]:
|
| 634 |
-
sample["class_label"][class_index_dict[x]] = 1
|
| 635 |
-
sample["class_label"] = torch.tensor(sample["class_label"]).float()
|
| 636 |
-
del sample[text_ext]
|
| 637 |
-
sample["audio_name"] = sample["__key__"].split("/")[-1] + "." + audio_ext
|
| 638 |
-
sample["text_name"] = sample["__key__"].split("/")[-1] + "." + text_ext
|
| 639 |
-
sample["audio_orig_sr"] = orig_sr
|
| 640 |
-
return sample
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
def collate_fn(batch):
|
| 644 |
-
"""
|
| 645 |
-
Collate function for wdsdataloader.
|
| 646 |
-
batch: a list of dict, each dict is a sample
|
| 647 |
-
"""
|
| 648 |
-
# concatenate values in each dictionary. if it is a tensor, concatenate. if it is a list, extend.
|
| 649 |
-
batch_dict = {}
|
| 650 |
-
for k in batch[0].keys():
|
| 651 |
-
if isinstance(batch[0][k], dict): # dealwith bert tokenizer output
|
| 652 |
-
batch_dict[k] = {}
|
| 653 |
-
for kk in batch[0][k].keys():
|
| 654 |
-
tmp = []
|
| 655 |
-
for i in range(len(batch)):
|
| 656 |
-
tmp.append(batch[i][k][kk])
|
| 657 |
-
batch_dict[k][kk] = torch.vstack(tmp)
|
| 658 |
-
elif isinstance(batch[0][k], torch.Tensor):
|
| 659 |
-
batch_dict[k] = torch.stack([sample[k] for sample in batch])
|
| 660 |
-
elif isinstance(batch[0][k], np.ndarray):
|
| 661 |
-
batch_dict[k] = torch.tensor(np.stack([sample[k] for sample in batch]))
|
| 662 |
-
else:
|
| 663 |
-
batch_dict[k] = [sample[k] for sample in batch]
|
| 664 |
-
return batch_dict
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
def get_wds_dataset(
|
| 668 |
-
args,
|
| 669 |
-
model_cfg,
|
| 670 |
-
is_train,
|
| 671 |
-
audio_ext="flac",
|
| 672 |
-
text_ext="json",
|
| 673 |
-
max_len=480000,
|
| 674 |
-
proportion=1.0,
|
| 675 |
-
sizefilepath_=None,
|
| 676 |
-
is_local=None,
|
| 677 |
-
):
|
| 678 |
-
"""
|
| 679 |
-
Get a dataset for wdsdataloader.
|
| 680 |
-
"""
|
| 681 |
-
if is_local is None and (not args.remotedata is None):
|
| 682 |
-
is_local = not args.remotedata
|
| 683 |
-
|
| 684 |
-
input_shards = args.train_data if is_train else args.val_data
|
| 685 |
-
assert input_shards is not None
|
| 686 |
-
|
| 687 |
-
if not sizefilepath_ is None:
|
| 688 |
-
sizefilepath = sizefilepath_
|
| 689 |
-
else:
|
| 690 |
-
sizefilepath = os.path.join(os.path.dirname(input_shards[0]), "sizes.json")
|
| 691 |
-
|
| 692 |
-
if proportion != 1.0:
|
| 693 |
-
num_samples, num_shards, input_shards, _ = sample_prop(
|
| 694 |
-
sizefilepath, input_shards, proportion, is_local=is_local
|
| 695 |
-
)
|
| 696 |
-
else:
|
| 697 |
-
num_samples, num_shards = get_dataset_size(
|
| 698 |
-
input_shards, sizefilepath_=sizefilepath_, is_local=is_local
|
| 699 |
-
)
|
| 700 |
-
|
| 701 |
-
if not num_samples:
|
| 702 |
-
if is_train:
|
| 703 |
-
num_samples = args.train_num_samples
|
| 704 |
-
if not num_samples:
|
| 705 |
-
raise RuntimeError(
|
| 706 |
-
"Currently, number of dataset samples must be specified for training dataset. "
|
| 707 |
-
"Please specify via `--train-num-samples` if no dataset length info present."
|
| 708 |
-
)
|
| 709 |
-
else:
|
| 710 |
-
num_samples = (
|
| 711 |
-
args.val_num_samples or 0
|
| 712 |
-
) # eval will just exhaust the iterator if not specified
|
| 713 |
-
|
| 714 |
-
pipeline = [wds.SimpleShardList(input_shards)]
|
| 715 |
-
# at this point we have an iterator over all the shards
|
| 716 |
-
# TODO: (yusong): add a if statement of distributed. If not, we don't need to split_by_node
|
| 717 |
-
if is_train or args.parallel_eval:
|
| 718 |
-
pipeline.extend(
|
| 719 |
-
[
|
| 720 |
-
wds.detshuffle(
|
| 721 |
-
bufsize=_SHARD_SHUFFLE_SIZE,
|
| 722 |
-
initial=_SHARD_SHUFFLE_INITIAL,
|
| 723 |
-
seed=args.seed,
|
| 724 |
-
),
|
| 725 |
-
wds.split_by_node,
|
| 726 |
-
wds.split_by_worker,
|
| 727 |
-
# at this point, we have an iterator over the shards assigned to each worker at each node
|
| 728 |
-
wds.tarfile_to_samples(handler=log_and_continue),
|
| 729 |
-
wds.shuffle(
|
| 730 |
-
bufsize=_SAMPLE_SHUFFLE_SIZE,
|
| 731 |
-
initial=_SAMPLE_SHUFFLE_INITIAL,
|
| 732 |
-
rng=random.Random(args.seed),
|
| 733 |
-
),
|
| 734 |
-
# wds.repeatedly, # FIXME determine if this is beneficial
|
| 735 |
-
]
|
| 736 |
-
)
|
| 737 |
-
else:
|
| 738 |
-
pipeline.extend(
|
| 739 |
-
[
|
| 740 |
-
wds.split_by_worker,
|
| 741 |
-
# at this point, we have an iterator over the shards assigned to each worker
|
| 742 |
-
wds.tarfile_to_samples(handler=log_and_continue),
|
| 743 |
-
]
|
| 744 |
-
)
|
| 745 |
-
pipeline.append(
|
| 746 |
-
wds.map(
|
| 747 |
-
partial(
|
| 748 |
-
preprocess,
|
| 749 |
-
audio_ext=audio_ext,
|
| 750 |
-
text_ext=text_ext,
|
| 751 |
-
max_len=max_len,
|
| 752 |
-
audio_cfg=model_cfg["audio_cfg"],
|
| 753 |
-
class_index_dict=copy.deepcopy(args.class_index_dict),
|
| 754 |
-
data_filling=args.data_filling,
|
| 755 |
-
data_truncating=args.data_truncating,
|
| 756 |
-
text_augment_selection=args.text_augment_selection,
|
| 757 |
-
)
|
| 758 |
-
),
|
| 759 |
-
)
|
| 760 |
-
|
| 761 |
-
pipeline.append(
|
| 762 |
-
wds.batched(
|
| 763 |
-
args.batch_size,
|
| 764 |
-
partial=not (is_train or args.parallel_eval),
|
| 765 |
-
collation_fn=collate_fn,
|
| 766 |
-
)
|
| 767 |
-
)
|
| 768 |
-
|
| 769 |
-
dataset = wds.DataPipeline(*pipeline)
|
| 770 |
-
if is_train or args.parallel_eval:
|
| 771 |
-
# (yusong): Currently parallel evaluation will be not precise as we are repeat the last few samples.
|
| 772 |
-
# (yusong): See comments below.
|
| 773 |
-
# roll over and repeat a few samples to get same number of full batches on each node
|
| 774 |
-
global_batch_size = args.batch_size * args.world_size
|
| 775 |
-
num_batches = math.ceil(num_samples / global_batch_size)
|
| 776 |
-
num_workers = max(1, args.workers)
|
| 777 |
-
num_worker_batches = math.ceil(
|
| 778 |
-
num_batches / num_workers
|
| 779 |
-
) # per dataloader worker
|
| 780 |
-
num_batches = num_worker_batches * num_workers
|
| 781 |
-
num_samples = num_batches * global_batch_size
|
| 782 |
-
dataset = dataset.with_epoch(
|
| 783 |
-
num_worker_batches
|
| 784 |
-
) # each worker is iterating over this
|
| 785 |
-
else:
|
| 786 |
-
# last batches are partial, eval is done on single (master) node
|
| 787 |
-
num_batches = math.ceil(num_samples / args.batch_size)
|
| 788 |
-
|
| 789 |
-
kwargs = {}
|
| 790 |
-
if args.horovod: # multi-node training on summit
|
| 791 |
-
kwargs["multiprocessing_context"] = "forkserver"
|
| 792 |
-
|
| 793 |
-
dataloader = wds.WebLoader(
|
| 794 |
-
dataset, batch_size=None, shuffle=False, num_workers=args.workers, **kwargs
|
| 795 |
-
)
|
| 796 |
-
|
| 797 |
-
# FIXME not clear which approach is better, with_epoch before vs after dataloader?
|
| 798 |
-
# hoping to resolve via https://github.com/webdataset/webdataset/issues/169
|
| 799 |
-
# if is_train:
|
| 800 |
-
# # roll over and repeat a few samples to get same number of full batches on each node
|
| 801 |
-
# global_batch_size = args.batch_size * args.world_size
|
| 802 |
-
# num_batches = math.ceil(num_samples / global_batch_size)
|
| 803 |
-
# num_workers = max(1, args.workers)
|
| 804 |
-
# num_batches = math.ceil(num_batches / num_workers) * num_workers
|
| 805 |
-
# num_samples = num_batches * global_batch_size
|
| 806 |
-
# dataloader = dataloader.with_epoch(num_batches)
|
| 807 |
-
# else:
|
| 808 |
-
# # last batches are partial, eval is done on single (master) node
|
| 809 |
-
# num_batches = math.ceil(num_samples / args.batch_size)
|
| 810 |
-
|
| 811 |
-
# add meta-data to dataloader instance for convenience
|
| 812 |
-
dataloader.num_batches = num_batches
|
| 813 |
-
dataloader.num_samples = num_samples
|
| 814 |
-
|
| 815 |
-
return DataInfo(dataloader, None)
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
def wds_batch_list2dict(
|
| 819 |
-
batch,
|
| 820 |
-
keys=[
|
| 821 |
-
"__url__",
|
| 822 |
-
"__key__",
|
| 823 |
-
"waveform",
|
| 824 |
-
"text",
|
| 825 |
-
"raw_text",
|
| 826 |
-
"audio_name",
|
| 827 |
-
"text_name",
|
| 828 |
-
"audio_orig_sr",
|
| 829 |
-
],
|
| 830 |
-
):
|
| 831 |
-
"""
|
| 832 |
-
Return a dictionary of the batch, with keys as the names of the fields.
|
| 833 |
-
"""
|
| 834 |
-
assert len(keys) == len(
|
| 835 |
-
batch
|
| 836 |
-
), "batch must have same number of keys as keys argument"
|
| 837 |
-
return {keys[i]: batch[i] for i in range(len(batch))}
|
| 838 |
-
|
| 839 |
-
|
| 840 |
-
def get_csv_dataset(args, preprocess_fn, is_train):
|
| 841 |
-
input_filename = args.train_data if is_train else args.val_data
|
| 842 |
-
assert input_filename
|
| 843 |
-
dataset = CsvDataset(
|
| 844 |
-
input_filename,
|
| 845 |
-
preprocess_fn,
|
| 846 |
-
img_key=args.csv_img_key,
|
| 847 |
-
caption_key=args.csv_caption_key,
|
| 848 |
-
sep=args.csv_separator,
|
| 849 |
-
)
|
| 850 |
-
num_samples = len(dataset)
|
| 851 |
-
sampler = DistributedSampler(dataset) if args.distributed and is_train else None
|
| 852 |
-
shuffle = is_train and sampler is None
|
| 853 |
-
|
| 854 |
-
dataloader = DataLoader(
|
| 855 |
-
dataset,
|
| 856 |
-
batch_size=args.batch_size,
|
| 857 |
-
shuffle=shuffle,
|
| 858 |
-
num_workers=args.workers,
|
| 859 |
-
pin_memory=True,
|
| 860 |
-
sampler=sampler,
|
| 861 |
-
drop_last=is_train,
|
| 862 |
-
)
|
| 863 |
-
dataloader.num_samples = num_samples
|
| 864 |
-
dataloader.num_batches = len(dataloader)
|
| 865 |
-
|
| 866 |
-
return DataInfo(dataloader, sampler)
|
| 867 |
-
|
| 868 |
-
|
| 869 |
-
def get_toy_dataset(args, model_cfg, is_train):
|
| 870 |
-
index_path = args.train_data if is_train else args.val_data
|
| 871 |
-
ipc_path = args.train_ipc if is_train else args.val_ipc
|
| 872 |
-
assert index_path and ipc_path
|
| 873 |
-
eval_mode = not is_train
|
| 874 |
-
dataset = ToyDataset(index_path, ipc_path, model_cfg, eval_mode=eval_mode)
|
| 875 |
-
|
| 876 |
-
num_samples = len(dataset)
|
| 877 |
-
sampler = (
|
| 878 |
-
DistributedSampler(dataset, shuffle=False)
|
| 879 |
-
if args.distributed and is_train
|
| 880 |
-
else None
|
| 881 |
-
)
|
| 882 |
-
|
| 883 |
-
dataloader = DataLoader(
|
| 884 |
-
dataset,
|
| 885 |
-
batch_size=args.batch_size,
|
| 886 |
-
shuffle=False,
|
| 887 |
-
num_workers=args.workers,
|
| 888 |
-
sampler=sampler,
|
| 889 |
-
drop_last=is_train,
|
| 890 |
-
)
|
| 891 |
-
dataloader.num_samples = num_samples
|
| 892 |
-
dataloader.num_batches = len(dataloader)
|
| 893 |
-
|
| 894 |
-
return DataInfo(dataloader, sampler)
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
def get_dataset_fn(data_path, dataset_type):
|
| 898 |
-
if dataset_type == "webdataset":
|
| 899 |
-
return get_wds_dataset
|
| 900 |
-
elif dataset_type == "csv":
|
| 901 |
-
return get_csv_dataset
|
| 902 |
-
elif dataset_type == "auto":
|
| 903 |
-
ext = data_path.split(".")[-1]
|
| 904 |
-
if ext in ["csv", "tsv"]:
|
| 905 |
-
return get_csv_dataset
|
| 906 |
-
elif ext in ["tar"]:
|
| 907 |
-
return get_wds_dataset
|
| 908 |
-
else:
|
| 909 |
-
raise ValueError(
|
| 910 |
-
f"Tried to figure out dataset type, but failed for extention {ext}."
|
| 911 |
-
)
|
| 912 |
-
elif dataset_type == "toy":
|
| 913 |
-
return get_toy_dataset
|
| 914 |
-
else:
|
| 915 |
-
raise ValueError(f"Unsupported dataset type: {dataset_type}")
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
def get_data(args, model_cfg):
|
| 919 |
-
data = {}
|
| 920 |
-
|
| 921 |
-
args.class_index_dict = load_class_label(args.class_label_path)
|
| 922 |
-
|
| 923 |
-
if args.datasetinfos is None:
|
| 924 |
-
args.datasetinfos = ["train", "unbalanced_train", "balanced_train"]
|
| 925 |
-
if args.dataset_type == "webdataset":
|
| 926 |
-
args.train_data = get_tar_path_from_dataset_name(
|
| 927 |
-
args.datasetnames,
|
| 928 |
-
args.datasetinfos,
|
| 929 |
-
islocal=not args.remotedata,
|
| 930 |
-
proportion=args.dataset_proportion,
|
| 931 |
-
dataset_path=args.datasetpath,
|
| 932 |
-
full_dataset=args.full_train_dataset,
|
| 933 |
-
)
|
| 934 |
-
|
| 935 |
-
if args.full_train_dataset is None:
|
| 936 |
-
args.full_train_dataset = []
|
| 937 |
-
if args.exclude_eval_dataset is None:
|
| 938 |
-
args.exclude_eval_dataset = []
|
| 939 |
-
excluded_eval_datasets = args.full_train_dataset + args.exclude_eval_dataset
|
| 940 |
-
|
| 941 |
-
val_dataset_names = (
|
| 942 |
-
[n for n in args.datasetnames if n not in excluded_eval_datasets]
|
| 943 |
-
if excluded_eval_datasets
|
| 944 |
-
else args.datasetnames
|
| 945 |
-
)
|
| 946 |
-
args.val_dataset_names = val_dataset_names
|
| 947 |
-
args.val_data = get_tar_path_from_dataset_name(
|
| 948 |
-
val_dataset_names,
|
| 949 |
-
["valid", "test", "eval"],
|
| 950 |
-
islocal=not args.remotedata,
|
| 951 |
-
proportion=1,
|
| 952 |
-
dataset_path=args.datasetpath,
|
| 953 |
-
full_dataset=None,
|
| 954 |
-
)
|
| 955 |
-
|
| 956 |
-
if args.train_data:
|
| 957 |
-
data["train"] = get_dataset_fn(args.train_data, args.dataset_type)(
|
| 958 |
-
args, model_cfg, is_train=True
|
| 959 |
-
)
|
| 960 |
-
|
| 961 |
-
if args.val_data:
|
| 962 |
-
data["val"] = get_dataset_fn(args.val_data, args.dataset_type)(
|
| 963 |
-
args, model_cfg, is_train=False
|
| 964 |
-
)
|
| 965 |
-
|
| 966 |
-
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/distributed.py
DELETED
|
@@ -1,150 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
|
| 3 |
-
import torch
|
| 4 |
-
import socket
|
| 5 |
-
|
| 6 |
-
try:
|
| 7 |
-
import horovod.torch as hvd
|
| 8 |
-
except ImportError:
|
| 9 |
-
hvd = None
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def is_global_master(args):
|
| 13 |
-
return args.rank == 0
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
def is_local_master(args):
|
| 17 |
-
return args.local_rank == 0
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def is_master(args, local=False):
|
| 21 |
-
return is_local_master(args) if local else is_global_master(args)
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def is_using_horovod():
|
| 25 |
-
# NOTE w/ horovod run, OMPI vars should be set, but w/ SLURM PMI vars will be set
|
| 26 |
-
# Differentiating between horovod and DDP use via SLURM may not be possible, so horovod arg still required...
|
| 27 |
-
ompi_vars = ["OMPI_COMM_WORLD_RANK", "OMPI_COMM_WORLD_SIZE"]
|
| 28 |
-
pmi_vars = ["PMI_RANK", "PMI_SIZE"]
|
| 29 |
-
if all([var in os.environ for var in ompi_vars]) or all(
|
| 30 |
-
[var in os.environ for var in pmi_vars]
|
| 31 |
-
):
|
| 32 |
-
return True
|
| 33 |
-
else:
|
| 34 |
-
return False
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def is_using_distributed():
|
| 38 |
-
if "WORLD_SIZE" in os.environ:
|
| 39 |
-
return int(os.environ["WORLD_SIZE"]) > 1
|
| 40 |
-
if "SLURM_NTASKS" in os.environ:
|
| 41 |
-
return int(os.environ["SLURM_NTASKS"]) > 1
|
| 42 |
-
return False
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
def world_info_from_env():
|
| 46 |
-
local_rank = 0
|
| 47 |
-
for v in (
|
| 48 |
-
"SLURM_LOCALID",
|
| 49 |
-
"MPI_LOCALRANKID",
|
| 50 |
-
"OMPI_COMM_WORLD_LOCAL_RANK",
|
| 51 |
-
"LOCAL_RANK",
|
| 52 |
-
):
|
| 53 |
-
if v in os.environ:
|
| 54 |
-
local_rank = int(os.environ[v])
|
| 55 |
-
break
|
| 56 |
-
global_rank = 0
|
| 57 |
-
for v in ("SLURM_PROCID", "PMI_RANK", "OMPI_COMM_WORLD_RANK", "RANK"):
|
| 58 |
-
if v in os.environ:
|
| 59 |
-
global_rank = int(os.environ[v])
|
| 60 |
-
break
|
| 61 |
-
world_size = 1
|
| 62 |
-
for v in ("SLURM_NTASKS", "PMI_SIZE", "OMPI_COMM_WORLD_SIZE", "WORLD_SIZE"):
|
| 63 |
-
if v in os.environ:
|
| 64 |
-
world_size = int(os.environ[v])
|
| 65 |
-
break
|
| 66 |
-
|
| 67 |
-
return local_rank, global_rank, world_size
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
def init_distributed_device(args):
|
| 71 |
-
# Distributed training = training on more than one GPU.
|
| 72 |
-
# Works in both single and multi-node scenarios.
|
| 73 |
-
args.distributed = False
|
| 74 |
-
args.world_size = 1
|
| 75 |
-
args.rank = 0 # global rank
|
| 76 |
-
args.local_rank = 0
|
| 77 |
-
if args.horovod:
|
| 78 |
-
assert hvd is not None, "Horovod is not installed"
|
| 79 |
-
hvd.init()
|
| 80 |
-
world_size = int(os.environ["OMPI_COMM_WORLD_SIZE"])
|
| 81 |
-
world_rank = int(os.environ["OMPI_COMM_WORLD_RANK"])
|
| 82 |
-
local_rank = int(os.environ["OMPI_COMM_WORLD_LOCAL_RANK"])
|
| 83 |
-
args.local_rank = local_rank
|
| 84 |
-
args.rank = world_rank
|
| 85 |
-
args.world_size = world_size
|
| 86 |
-
# args.local_rank = int(hvd.local_rank())
|
| 87 |
-
# args.rank = hvd.rank()
|
| 88 |
-
# args.world_size = hvd.size()
|
| 89 |
-
args.distributed = True
|
| 90 |
-
os.environ["LOCAL_RANK"] = str(args.local_rank)
|
| 91 |
-
os.environ["RANK"] = str(args.rank)
|
| 92 |
-
os.environ["WORLD_SIZE"] = str(args.world_size)
|
| 93 |
-
print(
|
| 94 |
-
f"Distributed training: local_rank={args.local_rank}, "
|
| 95 |
-
f"rank={args.rank}, world_size={args.world_size}, "
|
| 96 |
-
f"hostname={socket.gethostname()}, pid={os.getpid()}"
|
| 97 |
-
)
|
| 98 |
-
elif is_using_distributed():
|
| 99 |
-
if "SLURM_PROCID" in os.environ:
|
| 100 |
-
# DDP via SLURM
|
| 101 |
-
args.local_rank, args.rank, args.world_size = world_info_from_env()
|
| 102 |
-
# SLURM var -> torch.distributed vars in case needed
|
| 103 |
-
os.environ["LOCAL_RANK"] = str(args.local_rank)
|
| 104 |
-
os.environ["RANK"] = str(args.rank)
|
| 105 |
-
os.environ["WORLD_SIZE"] = str(args.world_size)
|
| 106 |
-
torch.distributed.init_process_group(
|
| 107 |
-
backend=args.dist_backend,
|
| 108 |
-
init_method=args.dist_url,
|
| 109 |
-
world_size=args.world_size,
|
| 110 |
-
rank=args.rank,
|
| 111 |
-
)
|
| 112 |
-
elif "OMPI_COMM_WORLD_SIZE" in os.environ: # using Summit cluster
|
| 113 |
-
world_size = int(os.environ["OMPI_COMM_WORLD_SIZE"])
|
| 114 |
-
world_rank = int(os.environ["OMPI_COMM_WORLD_RANK"])
|
| 115 |
-
local_rank = int(os.environ["OMPI_COMM_WORLD_LOCAL_RANK"])
|
| 116 |
-
args.local_rank = local_rank
|
| 117 |
-
args.rank = world_rank
|
| 118 |
-
args.world_size = world_size
|
| 119 |
-
torch.distributed.init_process_group(
|
| 120 |
-
backend=args.dist_backend,
|
| 121 |
-
init_method=args.dist_url,
|
| 122 |
-
world_size=args.world_size,
|
| 123 |
-
rank=args.rank,
|
| 124 |
-
)
|
| 125 |
-
else:
|
| 126 |
-
# DDP via torchrun, torch.distributed.launch
|
| 127 |
-
args.local_rank, _, _ = world_info_from_env()
|
| 128 |
-
torch.distributed.init_process_group(
|
| 129 |
-
backend=args.dist_backend, init_method=args.dist_url
|
| 130 |
-
)
|
| 131 |
-
args.world_size = torch.distributed.get_world_size()
|
| 132 |
-
args.rank = torch.distributed.get_rank()
|
| 133 |
-
args.distributed = True
|
| 134 |
-
print(
|
| 135 |
-
f"Distributed training: local_rank={args.local_rank}, "
|
| 136 |
-
f"rank={args.rank}, world_size={args.world_size}, "
|
| 137 |
-
f"hostname={socket.gethostname()}, pid={os.getpid()}"
|
| 138 |
-
)
|
| 139 |
-
|
| 140 |
-
if torch.cuda.is_available():
|
| 141 |
-
if args.distributed and not args.no_set_device_rank:
|
| 142 |
-
device = "cuda:%d" % args.local_rank
|
| 143 |
-
else:
|
| 144 |
-
device = "cuda:0"
|
| 145 |
-
torch.cuda.set_device(device)
|
| 146 |
-
else:
|
| 147 |
-
device = "cpu"
|
| 148 |
-
args.device = device
|
| 149 |
-
device = torch.device(device)
|
| 150 |
-
return device
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/imagenet_zeroshot_data.py
DELETED
|
@@ -1,1088 +0,0 @@
|
|
| 1 |
-
# NOTE: This script is currently not supported for CLAP.
|
| 2 |
-
|
| 3 |
-
imagenet_classnames = [
|
| 4 |
-
"tench",
|
| 5 |
-
"goldfish",
|
| 6 |
-
"great white shark",
|
| 7 |
-
"tiger shark",
|
| 8 |
-
"hammerhead shark",
|
| 9 |
-
"electric ray",
|
| 10 |
-
"stingray",
|
| 11 |
-
"rooster",
|
| 12 |
-
"hen",
|
| 13 |
-
"ostrich",
|
| 14 |
-
"brambling",
|
| 15 |
-
"goldfinch",
|
| 16 |
-
"house finch",
|
| 17 |
-
"junco",
|
| 18 |
-
"indigo bunting",
|
| 19 |
-
"American robin",
|
| 20 |
-
"bulbul",
|
| 21 |
-
"jay",
|
| 22 |
-
"magpie",
|
| 23 |
-
"chickadee",
|
| 24 |
-
"American dipper",
|
| 25 |
-
"kite (bird of prey)",
|
| 26 |
-
"bald eagle",
|
| 27 |
-
"vulture",
|
| 28 |
-
"great grey owl",
|
| 29 |
-
"fire salamander",
|
| 30 |
-
"smooth newt",
|
| 31 |
-
"newt",
|
| 32 |
-
"spotted salamander",
|
| 33 |
-
"axolotl",
|
| 34 |
-
"American bullfrog",
|
| 35 |
-
"tree frog",
|
| 36 |
-
"tailed frog",
|
| 37 |
-
"loggerhead sea turtle",
|
| 38 |
-
"leatherback sea turtle",
|
| 39 |
-
"mud turtle",
|
| 40 |
-
"terrapin",
|
| 41 |
-
"box turtle",
|
| 42 |
-
"banded gecko",
|
| 43 |
-
"green iguana",
|
| 44 |
-
"Carolina anole",
|
| 45 |
-
"desert grassland whiptail lizard",
|
| 46 |
-
"agama",
|
| 47 |
-
"frilled-necked lizard",
|
| 48 |
-
"alligator lizard",
|
| 49 |
-
"Gila monster",
|
| 50 |
-
"European green lizard",
|
| 51 |
-
"chameleon",
|
| 52 |
-
"Komodo dragon",
|
| 53 |
-
"Nile crocodile",
|
| 54 |
-
"American alligator",
|
| 55 |
-
"triceratops",
|
| 56 |
-
"worm snake",
|
| 57 |
-
"ring-necked snake",
|
| 58 |
-
"eastern hog-nosed snake",
|
| 59 |
-
"smooth green snake",
|
| 60 |
-
"kingsnake",
|
| 61 |
-
"garter snake",
|
| 62 |
-
"water snake",
|
| 63 |
-
"vine snake",
|
| 64 |
-
"night snake",
|
| 65 |
-
"boa constrictor",
|
| 66 |
-
"African rock python",
|
| 67 |
-
"Indian cobra",
|
| 68 |
-
"green mamba",
|
| 69 |
-
"sea snake",
|
| 70 |
-
"Saharan horned viper",
|
| 71 |
-
"eastern diamondback rattlesnake",
|
| 72 |
-
"sidewinder rattlesnake",
|
| 73 |
-
"trilobite",
|
| 74 |
-
"harvestman",
|
| 75 |
-
"scorpion",
|
| 76 |
-
"yellow garden spider",
|
| 77 |
-
"barn spider",
|
| 78 |
-
"European garden spider",
|
| 79 |
-
"southern black widow",
|
| 80 |
-
"tarantula",
|
| 81 |
-
"wolf spider",
|
| 82 |
-
"tick",
|
| 83 |
-
"centipede",
|
| 84 |
-
"black grouse",
|
| 85 |
-
"ptarmigan",
|
| 86 |
-
"ruffed grouse",
|
| 87 |
-
"prairie grouse",
|
| 88 |
-
"peafowl",
|
| 89 |
-
"quail",
|
| 90 |
-
"partridge",
|
| 91 |
-
"african grey parrot",
|
| 92 |
-
"macaw",
|
| 93 |
-
"sulphur-crested cockatoo",
|
| 94 |
-
"lorikeet",
|
| 95 |
-
"coucal",
|
| 96 |
-
"bee eater",
|
| 97 |
-
"hornbill",
|
| 98 |
-
"hummingbird",
|
| 99 |
-
"jacamar",
|
| 100 |
-
"toucan",
|
| 101 |
-
"duck",
|
| 102 |
-
"red-breasted merganser",
|
| 103 |
-
"goose",
|
| 104 |
-
"black swan",
|
| 105 |
-
"tusker",
|
| 106 |
-
"echidna",
|
| 107 |
-
"platypus",
|
| 108 |
-
"wallaby",
|
| 109 |
-
"koala",
|
| 110 |
-
"wombat",
|
| 111 |
-
"jellyfish",
|
| 112 |
-
"sea anemone",
|
| 113 |
-
"brain coral",
|
| 114 |
-
"flatworm",
|
| 115 |
-
"nematode",
|
| 116 |
-
"conch",
|
| 117 |
-
"snail",
|
| 118 |
-
"slug",
|
| 119 |
-
"sea slug",
|
| 120 |
-
"chiton",
|
| 121 |
-
"chambered nautilus",
|
| 122 |
-
"Dungeness crab",
|
| 123 |
-
"rock crab",
|
| 124 |
-
"fiddler crab",
|
| 125 |
-
"red king crab",
|
| 126 |
-
"American lobster",
|
| 127 |
-
"spiny lobster",
|
| 128 |
-
"crayfish",
|
| 129 |
-
"hermit crab",
|
| 130 |
-
"isopod",
|
| 131 |
-
"white stork",
|
| 132 |
-
"black stork",
|
| 133 |
-
"spoonbill",
|
| 134 |
-
"flamingo",
|
| 135 |
-
"little blue heron",
|
| 136 |
-
"great egret",
|
| 137 |
-
"bittern bird",
|
| 138 |
-
"crane bird",
|
| 139 |
-
"limpkin",
|
| 140 |
-
"common gallinule",
|
| 141 |
-
"American coot",
|
| 142 |
-
"bustard",
|
| 143 |
-
"ruddy turnstone",
|
| 144 |
-
"dunlin",
|
| 145 |
-
"common redshank",
|
| 146 |
-
"dowitcher",
|
| 147 |
-
"oystercatcher",
|
| 148 |
-
"pelican",
|
| 149 |
-
"king penguin",
|
| 150 |
-
"albatross",
|
| 151 |
-
"grey whale",
|
| 152 |
-
"killer whale",
|
| 153 |
-
"dugong",
|
| 154 |
-
"sea lion",
|
| 155 |
-
"Chihuahua",
|
| 156 |
-
"Japanese Chin",
|
| 157 |
-
"Maltese",
|
| 158 |
-
"Pekingese",
|
| 159 |
-
"Shih Tzu",
|
| 160 |
-
"King Charles Spaniel",
|
| 161 |
-
"Papillon",
|
| 162 |
-
"toy terrier",
|
| 163 |
-
"Rhodesian Ridgeback",
|
| 164 |
-
"Afghan Hound",
|
| 165 |
-
"Basset Hound",
|
| 166 |
-
"Beagle",
|
| 167 |
-
"Bloodhound",
|
| 168 |
-
"Bluetick Coonhound",
|
| 169 |
-
"Black and Tan Coonhound",
|
| 170 |
-
"Treeing Walker Coonhound",
|
| 171 |
-
"English foxhound",
|
| 172 |
-
"Redbone Coonhound",
|
| 173 |
-
"borzoi",
|
| 174 |
-
"Irish Wolfhound",
|
| 175 |
-
"Italian Greyhound",
|
| 176 |
-
"Whippet",
|
| 177 |
-
"Ibizan Hound",
|
| 178 |
-
"Norwegian Elkhound",
|
| 179 |
-
"Otterhound",
|
| 180 |
-
"Saluki",
|
| 181 |
-
"Scottish Deerhound",
|
| 182 |
-
"Weimaraner",
|
| 183 |
-
"Staffordshire Bull Terrier",
|
| 184 |
-
"American Staffordshire Terrier",
|
| 185 |
-
"Bedlington Terrier",
|
| 186 |
-
"Border Terrier",
|
| 187 |
-
"Kerry Blue Terrier",
|
| 188 |
-
"Irish Terrier",
|
| 189 |
-
"Norfolk Terrier",
|
| 190 |
-
"Norwich Terrier",
|
| 191 |
-
"Yorkshire Terrier",
|
| 192 |
-
"Wire Fox Terrier",
|
| 193 |
-
"Lakeland Terrier",
|
| 194 |
-
"Sealyham Terrier",
|
| 195 |
-
"Airedale Terrier",
|
| 196 |
-
"Cairn Terrier",
|
| 197 |
-
"Australian Terrier",
|
| 198 |
-
"Dandie Dinmont Terrier",
|
| 199 |
-
"Boston Terrier",
|
| 200 |
-
"Miniature Schnauzer",
|
| 201 |
-
"Giant Schnauzer",
|
| 202 |
-
"Standard Schnauzer",
|
| 203 |
-
"Scottish Terrier",
|
| 204 |
-
"Tibetan Terrier",
|
| 205 |
-
"Australian Silky Terrier",
|
| 206 |
-
"Soft-coated Wheaten Terrier",
|
| 207 |
-
"West Highland White Terrier",
|
| 208 |
-
"Lhasa Apso",
|
| 209 |
-
"Flat-Coated Retriever",
|
| 210 |
-
"Curly-coated Retriever",
|
| 211 |
-
"Golden Retriever",
|
| 212 |
-
"Labrador Retriever",
|
| 213 |
-
"Chesapeake Bay Retriever",
|
| 214 |
-
"German Shorthaired Pointer",
|
| 215 |
-
"Vizsla",
|
| 216 |
-
"English Setter",
|
| 217 |
-
"Irish Setter",
|
| 218 |
-
"Gordon Setter",
|
| 219 |
-
"Brittany dog",
|
| 220 |
-
"Clumber Spaniel",
|
| 221 |
-
"English Springer Spaniel",
|
| 222 |
-
"Welsh Springer Spaniel",
|
| 223 |
-
"Cocker Spaniel",
|
| 224 |
-
"Sussex Spaniel",
|
| 225 |
-
"Irish Water Spaniel",
|
| 226 |
-
"Kuvasz",
|
| 227 |
-
"Schipperke",
|
| 228 |
-
"Groenendael dog",
|
| 229 |
-
"Malinois",
|
| 230 |
-
"Briard",
|
| 231 |
-
"Australian Kelpie",
|
| 232 |
-
"Komondor",
|
| 233 |
-
"Old English Sheepdog",
|
| 234 |
-
"Shetland Sheepdog",
|
| 235 |
-
"collie",
|
| 236 |
-
"Border Collie",
|
| 237 |
-
"Bouvier des Flandres dog",
|
| 238 |
-
"Rottweiler",
|
| 239 |
-
"German Shepherd Dog",
|
| 240 |
-
"Dobermann",
|
| 241 |
-
"Miniature Pinscher",
|
| 242 |
-
"Greater Swiss Mountain Dog",
|
| 243 |
-
"Bernese Mountain Dog",
|
| 244 |
-
"Appenzeller Sennenhund",
|
| 245 |
-
"Entlebucher Sennenhund",
|
| 246 |
-
"Boxer",
|
| 247 |
-
"Bullmastiff",
|
| 248 |
-
"Tibetan Mastiff",
|
| 249 |
-
"French Bulldog",
|
| 250 |
-
"Great Dane",
|
| 251 |
-
"St. Bernard",
|
| 252 |
-
"husky",
|
| 253 |
-
"Alaskan Malamute",
|
| 254 |
-
"Siberian Husky",
|
| 255 |
-
"Dalmatian",
|
| 256 |
-
"Affenpinscher",
|
| 257 |
-
"Basenji",
|
| 258 |
-
"pug",
|
| 259 |
-
"Leonberger",
|
| 260 |
-
"Newfoundland dog",
|
| 261 |
-
"Great Pyrenees dog",
|
| 262 |
-
"Samoyed",
|
| 263 |
-
"Pomeranian",
|
| 264 |
-
"Chow Chow",
|
| 265 |
-
"Keeshond",
|
| 266 |
-
"brussels griffon",
|
| 267 |
-
"Pembroke Welsh Corgi",
|
| 268 |
-
"Cardigan Welsh Corgi",
|
| 269 |
-
"Toy Poodle",
|
| 270 |
-
"Miniature Poodle",
|
| 271 |
-
"Standard Poodle",
|
| 272 |
-
"Mexican hairless dog (xoloitzcuintli)",
|
| 273 |
-
"grey wolf",
|
| 274 |
-
"Alaskan tundra wolf",
|
| 275 |
-
"red wolf or maned wolf",
|
| 276 |
-
"coyote",
|
| 277 |
-
"dingo",
|
| 278 |
-
"dhole",
|
| 279 |
-
"African wild dog",
|
| 280 |
-
"hyena",
|
| 281 |
-
"red fox",
|
| 282 |
-
"kit fox",
|
| 283 |
-
"Arctic fox",
|
| 284 |
-
"grey fox",
|
| 285 |
-
"tabby cat",
|
| 286 |
-
"tiger cat",
|
| 287 |
-
"Persian cat",
|
| 288 |
-
"Siamese cat",
|
| 289 |
-
"Egyptian Mau",
|
| 290 |
-
"cougar",
|
| 291 |
-
"lynx",
|
| 292 |
-
"leopard",
|
| 293 |
-
"snow leopard",
|
| 294 |
-
"jaguar",
|
| 295 |
-
"lion",
|
| 296 |
-
"tiger",
|
| 297 |
-
"cheetah",
|
| 298 |
-
"brown bear",
|
| 299 |
-
"American black bear",
|
| 300 |
-
"polar bear",
|
| 301 |
-
"sloth bear",
|
| 302 |
-
"mongoose",
|
| 303 |
-
"meerkat",
|
| 304 |
-
"tiger beetle",
|
| 305 |
-
"ladybug",
|
| 306 |
-
"ground beetle",
|
| 307 |
-
"longhorn beetle",
|
| 308 |
-
"leaf beetle",
|
| 309 |
-
"dung beetle",
|
| 310 |
-
"rhinoceros beetle",
|
| 311 |
-
"weevil",
|
| 312 |
-
"fly",
|
| 313 |
-
"bee",
|
| 314 |
-
"ant",
|
| 315 |
-
"grasshopper",
|
| 316 |
-
"cricket insect",
|
| 317 |
-
"stick insect",
|
| 318 |
-
"cockroach",
|
| 319 |
-
"praying mantis",
|
| 320 |
-
"cicada",
|
| 321 |
-
"leafhopper",
|
| 322 |
-
"lacewing",
|
| 323 |
-
"dragonfly",
|
| 324 |
-
"damselfly",
|
| 325 |
-
"red admiral butterfly",
|
| 326 |
-
"ringlet butterfly",
|
| 327 |
-
"monarch butterfly",
|
| 328 |
-
"small white butterfly",
|
| 329 |
-
"sulphur butterfly",
|
| 330 |
-
"gossamer-winged butterfly",
|
| 331 |
-
"starfish",
|
| 332 |
-
"sea urchin",
|
| 333 |
-
"sea cucumber",
|
| 334 |
-
"cottontail rabbit",
|
| 335 |
-
"hare",
|
| 336 |
-
"Angora rabbit",
|
| 337 |
-
"hamster",
|
| 338 |
-
"porcupine",
|
| 339 |
-
"fox squirrel",
|
| 340 |
-
"marmot",
|
| 341 |
-
"beaver",
|
| 342 |
-
"guinea pig",
|
| 343 |
-
"common sorrel horse",
|
| 344 |
-
"zebra",
|
| 345 |
-
"pig",
|
| 346 |
-
"wild boar",
|
| 347 |
-
"warthog",
|
| 348 |
-
"hippopotamus",
|
| 349 |
-
"ox",
|
| 350 |
-
"water buffalo",
|
| 351 |
-
"bison",
|
| 352 |
-
"ram (adult male sheep)",
|
| 353 |
-
"bighorn sheep",
|
| 354 |
-
"Alpine ibex",
|
| 355 |
-
"hartebeest",
|
| 356 |
-
"impala (antelope)",
|
| 357 |
-
"gazelle",
|
| 358 |
-
"arabian camel",
|
| 359 |
-
"llama",
|
| 360 |
-
"weasel",
|
| 361 |
-
"mink",
|
| 362 |
-
"European polecat",
|
| 363 |
-
"black-footed ferret",
|
| 364 |
-
"otter",
|
| 365 |
-
"skunk",
|
| 366 |
-
"badger",
|
| 367 |
-
"armadillo",
|
| 368 |
-
"three-toed sloth",
|
| 369 |
-
"orangutan",
|
| 370 |
-
"gorilla",
|
| 371 |
-
"chimpanzee",
|
| 372 |
-
"gibbon",
|
| 373 |
-
"siamang",
|
| 374 |
-
"guenon",
|
| 375 |
-
"patas monkey",
|
| 376 |
-
"baboon",
|
| 377 |
-
"macaque",
|
| 378 |
-
"langur",
|
| 379 |
-
"black-and-white colobus",
|
| 380 |
-
"proboscis monkey",
|
| 381 |
-
"marmoset",
|
| 382 |
-
"white-headed capuchin",
|
| 383 |
-
"howler monkey",
|
| 384 |
-
"titi monkey",
|
| 385 |
-
"Geoffroy's spider monkey",
|
| 386 |
-
"common squirrel monkey",
|
| 387 |
-
"ring-tailed lemur",
|
| 388 |
-
"indri",
|
| 389 |
-
"Asian elephant",
|
| 390 |
-
"African bush elephant",
|
| 391 |
-
"red panda",
|
| 392 |
-
"giant panda",
|
| 393 |
-
"snoek fish",
|
| 394 |
-
"eel",
|
| 395 |
-
"silver salmon",
|
| 396 |
-
"rock beauty fish",
|
| 397 |
-
"clownfish",
|
| 398 |
-
"sturgeon",
|
| 399 |
-
"gar fish",
|
| 400 |
-
"lionfish",
|
| 401 |
-
"pufferfish",
|
| 402 |
-
"abacus",
|
| 403 |
-
"abaya",
|
| 404 |
-
"academic gown",
|
| 405 |
-
"accordion",
|
| 406 |
-
"acoustic guitar",
|
| 407 |
-
"aircraft carrier",
|
| 408 |
-
"airliner",
|
| 409 |
-
"airship",
|
| 410 |
-
"altar",
|
| 411 |
-
"ambulance",
|
| 412 |
-
"amphibious vehicle",
|
| 413 |
-
"analog clock",
|
| 414 |
-
"apiary",
|
| 415 |
-
"apron",
|
| 416 |
-
"trash can",
|
| 417 |
-
"assault rifle",
|
| 418 |
-
"backpack",
|
| 419 |
-
"bakery",
|
| 420 |
-
"balance beam",
|
| 421 |
-
"balloon",
|
| 422 |
-
"ballpoint pen",
|
| 423 |
-
"Band-Aid",
|
| 424 |
-
"banjo",
|
| 425 |
-
"baluster / handrail",
|
| 426 |
-
"barbell",
|
| 427 |
-
"barber chair",
|
| 428 |
-
"barbershop",
|
| 429 |
-
"barn",
|
| 430 |
-
"barometer",
|
| 431 |
-
"barrel",
|
| 432 |
-
"wheelbarrow",
|
| 433 |
-
"baseball",
|
| 434 |
-
"basketball",
|
| 435 |
-
"bassinet",
|
| 436 |
-
"bassoon",
|
| 437 |
-
"swimming cap",
|
| 438 |
-
"bath towel",
|
| 439 |
-
"bathtub",
|
| 440 |
-
"station wagon",
|
| 441 |
-
"lighthouse",
|
| 442 |
-
"beaker",
|
| 443 |
-
"military hat (bearskin or shako)",
|
| 444 |
-
"beer bottle",
|
| 445 |
-
"beer glass",
|
| 446 |
-
"bell tower",
|
| 447 |
-
"baby bib",
|
| 448 |
-
"tandem bicycle",
|
| 449 |
-
"bikini",
|
| 450 |
-
"ring binder",
|
| 451 |
-
"binoculars",
|
| 452 |
-
"birdhouse",
|
| 453 |
-
"boathouse",
|
| 454 |
-
"bobsleigh",
|
| 455 |
-
"bolo tie",
|
| 456 |
-
"poke bonnet",
|
| 457 |
-
"bookcase",
|
| 458 |
-
"bookstore",
|
| 459 |
-
"bottle cap",
|
| 460 |
-
"hunting bow",
|
| 461 |
-
"bow tie",
|
| 462 |
-
"brass memorial plaque",
|
| 463 |
-
"bra",
|
| 464 |
-
"breakwater",
|
| 465 |
-
"breastplate",
|
| 466 |
-
"broom",
|
| 467 |
-
"bucket",
|
| 468 |
-
"buckle",
|
| 469 |
-
"bulletproof vest",
|
| 470 |
-
"high-speed train",
|
| 471 |
-
"butcher shop",
|
| 472 |
-
"taxicab",
|
| 473 |
-
"cauldron",
|
| 474 |
-
"candle",
|
| 475 |
-
"cannon",
|
| 476 |
-
"canoe",
|
| 477 |
-
"can opener",
|
| 478 |
-
"cardigan",
|
| 479 |
-
"car mirror",
|
| 480 |
-
"carousel",
|
| 481 |
-
"tool kit",
|
| 482 |
-
"cardboard box / carton",
|
| 483 |
-
"car wheel",
|
| 484 |
-
"automated teller machine",
|
| 485 |
-
"cassette",
|
| 486 |
-
"cassette player",
|
| 487 |
-
"castle",
|
| 488 |
-
"catamaran",
|
| 489 |
-
"CD player",
|
| 490 |
-
"cello",
|
| 491 |
-
"mobile phone",
|
| 492 |
-
"chain",
|
| 493 |
-
"chain-link fence",
|
| 494 |
-
"chain mail",
|
| 495 |
-
"chainsaw",
|
| 496 |
-
"storage chest",
|
| 497 |
-
"chiffonier",
|
| 498 |
-
"bell or wind chime",
|
| 499 |
-
"china cabinet",
|
| 500 |
-
"Christmas stocking",
|
| 501 |
-
"church",
|
| 502 |
-
"movie theater",
|
| 503 |
-
"cleaver",
|
| 504 |
-
"cliff dwelling",
|
| 505 |
-
"cloak",
|
| 506 |
-
"clogs",
|
| 507 |
-
"cocktail shaker",
|
| 508 |
-
"coffee mug",
|
| 509 |
-
"coffeemaker",
|
| 510 |
-
"spiral or coil",
|
| 511 |
-
"combination lock",
|
| 512 |
-
"computer keyboard",
|
| 513 |
-
"candy store",
|
| 514 |
-
"container ship",
|
| 515 |
-
"convertible",
|
| 516 |
-
"corkscrew",
|
| 517 |
-
"cornet",
|
| 518 |
-
"cowboy boot",
|
| 519 |
-
"cowboy hat",
|
| 520 |
-
"cradle",
|
| 521 |
-
"construction crane",
|
| 522 |
-
"crash helmet",
|
| 523 |
-
"crate",
|
| 524 |
-
"infant bed",
|
| 525 |
-
"Crock Pot",
|
| 526 |
-
"croquet ball",
|
| 527 |
-
"crutch",
|
| 528 |
-
"cuirass",
|
| 529 |
-
"dam",
|
| 530 |
-
"desk",
|
| 531 |
-
"desktop computer",
|
| 532 |
-
"rotary dial telephone",
|
| 533 |
-
"diaper",
|
| 534 |
-
"digital clock",
|
| 535 |
-
"digital watch",
|
| 536 |
-
"dining table",
|
| 537 |
-
"dishcloth",
|
| 538 |
-
"dishwasher",
|
| 539 |
-
"disc brake",
|
| 540 |
-
"dock",
|
| 541 |
-
"dog sled",
|
| 542 |
-
"dome",
|
| 543 |
-
"doormat",
|
| 544 |
-
"drilling rig",
|
| 545 |
-
"drum",
|
| 546 |
-
"drumstick",
|
| 547 |
-
"dumbbell",
|
| 548 |
-
"Dutch oven",
|
| 549 |
-
"electric fan",
|
| 550 |
-
"electric guitar",
|
| 551 |
-
"electric locomotive",
|
| 552 |
-
"entertainment center",
|
| 553 |
-
"envelope",
|
| 554 |
-
"espresso machine",
|
| 555 |
-
"face powder",
|
| 556 |
-
"feather boa",
|
| 557 |
-
"filing cabinet",
|
| 558 |
-
"fireboat",
|
| 559 |
-
"fire truck",
|
| 560 |
-
"fire screen",
|
| 561 |
-
"flagpole",
|
| 562 |
-
"flute",
|
| 563 |
-
"folding chair",
|
| 564 |
-
"football helmet",
|
| 565 |
-
"forklift",
|
| 566 |
-
"fountain",
|
| 567 |
-
"fountain pen",
|
| 568 |
-
"four-poster bed",
|
| 569 |
-
"freight car",
|
| 570 |
-
"French horn",
|
| 571 |
-
"frying pan",
|
| 572 |
-
"fur coat",
|
| 573 |
-
"garbage truck",
|
| 574 |
-
"gas mask or respirator",
|
| 575 |
-
"gas pump",
|
| 576 |
-
"goblet",
|
| 577 |
-
"go-kart",
|
| 578 |
-
"golf ball",
|
| 579 |
-
"golf cart",
|
| 580 |
-
"gondola",
|
| 581 |
-
"gong",
|
| 582 |
-
"gown",
|
| 583 |
-
"grand piano",
|
| 584 |
-
"greenhouse",
|
| 585 |
-
"radiator grille",
|
| 586 |
-
"grocery store",
|
| 587 |
-
"guillotine",
|
| 588 |
-
"hair clip",
|
| 589 |
-
"hair spray",
|
| 590 |
-
"half-track",
|
| 591 |
-
"hammer",
|
| 592 |
-
"hamper",
|
| 593 |
-
"hair dryer",
|
| 594 |
-
"hand-held computer",
|
| 595 |
-
"handkerchief",
|
| 596 |
-
"hard disk drive",
|
| 597 |
-
"harmonica",
|
| 598 |
-
"harp",
|
| 599 |
-
"combine harvester",
|
| 600 |
-
"hatchet",
|
| 601 |
-
"holster",
|
| 602 |
-
"home theater",
|
| 603 |
-
"honeycomb",
|
| 604 |
-
"hook",
|
| 605 |
-
"hoop skirt",
|
| 606 |
-
"gymnastic horizontal bar",
|
| 607 |
-
"horse-drawn vehicle",
|
| 608 |
-
"hourglass",
|
| 609 |
-
"iPod",
|
| 610 |
-
"clothes iron",
|
| 611 |
-
"carved pumpkin",
|
| 612 |
-
"jeans",
|
| 613 |
-
"jeep",
|
| 614 |
-
"T-shirt",
|
| 615 |
-
"jigsaw puzzle",
|
| 616 |
-
"rickshaw",
|
| 617 |
-
"joystick",
|
| 618 |
-
"kimono",
|
| 619 |
-
"knee pad",
|
| 620 |
-
"knot",
|
| 621 |
-
"lab coat",
|
| 622 |
-
"ladle",
|
| 623 |
-
"lampshade",
|
| 624 |
-
"laptop computer",
|
| 625 |
-
"lawn mower",
|
| 626 |
-
"lens cap",
|
| 627 |
-
"letter opener",
|
| 628 |
-
"library",
|
| 629 |
-
"lifeboat",
|
| 630 |
-
"lighter",
|
| 631 |
-
"limousine",
|
| 632 |
-
"ocean liner",
|
| 633 |
-
"lipstick",
|
| 634 |
-
"slip-on shoe",
|
| 635 |
-
"lotion",
|
| 636 |
-
"music speaker",
|
| 637 |
-
"loupe magnifying glass",
|
| 638 |
-
"sawmill",
|
| 639 |
-
"magnetic compass",
|
| 640 |
-
"messenger bag",
|
| 641 |
-
"mailbox",
|
| 642 |
-
"tights",
|
| 643 |
-
"one-piece bathing suit",
|
| 644 |
-
"manhole cover",
|
| 645 |
-
"maraca",
|
| 646 |
-
"marimba",
|
| 647 |
-
"mask",
|
| 648 |
-
"matchstick",
|
| 649 |
-
"maypole",
|
| 650 |
-
"maze",
|
| 651 |
-
"measuring cup",
|
| 652 |
-
"medicine cabinet",
|
| 653 |
-
"megalith",
|
| 654 |
-
"microphone",
|
| 655 |
-
"microwave oven",
|
| 656 |
-
"military uniform",
|
| 657 |
-
"milk can",
|
| 658 |
-
"minibus",
|
| 659 |
-
"miniskirt",
|
| 660 |
-
"minivan",
|
| 661 |
-
"missile",
|
| 662 |
-
"mitten",
|
| 663 |
-
"mixing bowl",
|
| 664 |
-
"mobile home",
|
| 665 |
-
"ford model t",
|
| 666 |
-
"modem",
|
| 667 |
-
"monastery",
|
| 668 |
-
"monitor",
|
| 669 |
-
"moped",
|
| 670 |
-
"mortar and pestle",
|
| 671 |
-
"graduation cap",
|
| 672 |
-
"mosque",
|
| 673 |
-
"mosquito net",
|
| 674 |
-
"vespa",
|
| 675 |
-
"mountain bike",
|
| 676 |
-
"tent",
|
| 677 |
-
"computer mouse",
|
| 678 |
-
"mousetrap",
|
| 679 |
-
"moving van",
|
| 680 |
-
"muzzle",
|
| 681 |
-
"metal nail",
|
| 682 |
-
"neck brace",
|
| 683 |
-
"necklace",
|
| 684 |
-
"baby pacifier",
|
| 685 |
-
"notebook computer",
|
| 686 |
-
"obelisk",
|
| 687 |
-
"oboe",
|
| 688 |
-
"ocarina",
|
| 689 |
-
"odometer",
|
| 690 |
-
"oil filter",
|
| 691 |
-
"pipe organ",
|
| 692 |
-
"oscilloscope",
|
| 693 |
-
"overskirt",
|
| 694 |
-
"bullock cart",
|
| 695 |
-
"oxygen mask",
|
| 696 |
-
"product packet / packaging",
|
| 697 |
-
"paddle",
|
| 698 |
-
"paddle wheel",
|
| 699 |
-
"padlock",
|
| 700 |
-
"paintbrush",
|
| 701 |
-
"pajamas",
|
| 702 |
-
"palace",
|
| 703 |
-
"pan flute",
|
| 704 |
-
"paper towel",
|
| 705 |
-
"parachute",
|
| 706 |
-
"parallel bars",
|
| 707 |
-
"park bench",
|
| 708 |
-
"parking meter",
|
| 709 |
-
"railroad car",
|
| 710 |
-
"patio",
|
| 711 |
-
"payphone",
|
| 712 |
-
"pedestal",
|
| 713 |
-
"pencil case",
|
| 714 |
-
"pencil sharpener",
|
| 715 |
-
"perfume",
|
| 716 |
-
"Petri dish",
|
| 717 |
-
"photocopier",
|
| 718 |
-
"plectrum",
|
| 719 |
-
"Pickelhaube",
|
| 720 |
-
"picket fence",
|
| 721 |
-
"pickup truck",
|
| 722 |
-
"pier",
|
| 723 |
-
"piggy bank",
|
| 724 |
-
"pill bottle",
|
| 725 |
-
"pillow",
|
| 726 |
-
"ping-pong ball",
|
| 727 |
-
"pinwheel",
|
| 728 |
-
"pirate ship",
|
| 729 |
-
"drink pitcher",
|
| 730 |
-
"block plane",
|
| 731 |
-
"planetarium",
|
| 732 |
-
"plastic bag",
|
| 733 |
-
"plate rack",
|
| 734 |
-
"farm plow",
|
| 735 |
-
"plunger",
|
| 736 |
-
"Polaroid camera",
|
| 737 |
-
"pole",
|
| 738 |
-
"police van",
|
| 739 |
-
"poncho",
|
| 740 |
-
"pool table",
|
| 741 |
-
"soda bottle",
|
| 742 |
-
"plant pot",
|
| 743 |
-
"potter's wheel",
|
| 744 |
-
"power drill",
|
| 745 |
-
"prayer rug",
|
| 746 |
-
"printer",
|
| 747 |
-
"prison",
|
| 748 |
-
"missile",
|
| 749 |
-
"projector",
|
| 750 |
-
"hockey puck",
|
| 751 |
-
"punching bag",
|
| 752 |
-
"purse",
|
| 753 |
-
"quill",
|
| 754 |
-
"quilt",
|
| 755 |
-
"race car",
|
| 756 |
-
"racket",
|
| 757 |
-
"radiator",
|
| 758 |
-
"radio",
|
| 759 |
-
"radio telescope",
|
| 760 |
-
"rain barrel",
|
| 761 |
-
"recreational vehicle",
|
| 762 |
-
"fishing casting reel",
|
| 763 |
-
"reflex camera",
|
| 764 |
-
"refrigerator",
|
| 765 |
-
"remote control",
|
| 766 |
-
"restaurant",
|
| 767 |
-
"revolver",
|
| 768 |
-
"rifle",
|
| 769 |
-
"rocking chair",
|
| 770 |
-
"rotisserie",
|
| 771 |
-
"eraser",
|
| 772 |
-
"rugby ball",
|
| 773 |
-
"ruler measuring stick",
|
| 774 |
-
"sneaker",
|
| 775 |
-
"safe",
|
| 776 |
-
"safety pin",
|
| 777 |
-
"salt shaker",
|
| 778 |
-
"sandal",
|
| 779 |
-
"sarong",
|
| 780 |
-
"saxophone",
|
| 781 |
-
"scabbard",
|
| 782 |
-
"weighing scale",
|
| 783 |
-
"school bus",
|
| 784 |
-
"schooner",
|
| 785 |
-
"scoreboard",
|
| 786 |
-
"CRT monitor",
|
| 787 |
-
"screw",
|
| 788 |
-
"screwdriver",
|
| 789 |
-
"seat belt",
|
| 790 |
-
"sewing machine",
|
| 791 |
-
"shield",
|
| 792 |
-
"shoe store",
|
| 793 |
-
"shoji screen / room divider",
|
| 794 |
-
"shopping basket",
|
| 795 |
-
"shopping cart",
|
| 796 |
-
"shovel",
|
| 797 |
-
"shower cap",
|
| 798 |
-
"shower curtain",
|
| 799 |
-
"ski",
|
| 800 |
-
"balaclava ski mask",
|
| 801 |
-
"sleeping bag",
|
| 802 |
-
"slide rule",
|
| 803 |
-
"sliding door",
|
| 804 |
-
"slot machine",
|
| 805 |
-
"snorkel",
|
| 806 |
-
"snowmobile",
|
| 807 |
-
"snowplow",
|
| 808 |
-
"soap dispenser",
|
| 809 |
-
"soccer ball",
|
| 810 |
-
"sock",
|
| 811 |
-
"solar thermal collector",
|
| 812 |
-
"sombrero",
|
| 813 |
-
"soup bowl",
|
| 814 |
-
"keyboard space bar",
|
| 815 |
-
"space heater",
|
| 816 |
-
"space shuttle",
|
| 817 |
-
"spatula",
|
| 818 |
-
"motorboat",
|
| 819 |
-
"spider web",
|
| 820 |
-
"spindle",
|
| 821 |
-
"sports car",
|
| 822 |
-
"spotlight",
|
| 823 |
-
"stage",
|
| 824 |
-
"steam locomotive",
|
| 825 |
-
"through arch bridge",
|
| 826 |
-
"steel drum",
|
| 827 |
-
"stethoscope",
|
| 828 |
-
"scarf",
|
| 829 |
-
"stone wall",
|
| 830 |
-
"stopwatch",
|
| 831 |
-
"stove",
|
| 832 |
-
"strainer",
|
| 833 |
-
"tram",
|
| 834 |
-
"stretcher",
|
| 835 |
-
"couch",
|
| 836 |
-
"stupa",
|
| 837 |
-
"submarine",
|
| 838 |
-
"suit",
|
| 839 |
-
"sundial",
|
| 840 |
-
"sunglasses",
|
| 841 |
-
"sunglasses",
|
| 842 |
-
"sunscreen",
|
| 843 |
-
"suspension bridge",
|
| 844 |
-
"mop",
|
| 845 |
-
"sweatshirt",
|
| 846 |
-
"swim trunks / shorts",
|
| 847 |
-
"swing",
|
| 848 |
-
"electrical switch",
|
| 849 |
-
"syringe",
|
| 850 |
-
"table lamp",
|
| 851 |
-
"tank",
|
| 852 |
-
"tape player",
|
| 853 |
-
"teapot",
|
| 854 |
-
"teddy bear",
|
| 855 |
-
"television",
|
| 856 |
-
"tennis ball",
|
| 857 |
-
"thatched roof",
|
| 858 |
-
"front curtain",
|
| 859 |
-
"thimble",
|
| 860 |
-
"threshing machine",
|
| 861 |
-
"throne",
|
| 862 |
-
"tile roof",
|
| 863 |
-
"toaster",
|
| 864 |
-
"tobacco shop",
|
| 865 |
-
"toilet seat",
|
| 866 |
-
"torch",
|
| 867 |
-
"totem pole",
|
| 868 |
-
"tow truck",
|
| 869 |
-
"toy store",
|
| 870 |
-
"tractor",
|
| 871 |
-
"semi-trailer truck",
|
| 872 |
-
"tray",
|
| 873 |
-
"trench coat",
|
| 874 |
-
"tricycle",
|
| 875 |
-
"trimaran",
|
| 876 |
-
"tripod",
|
| 877 |
-
"triumphal arch",
|
| 878 |
-
"trolleybus",
|
| 879 |
-
"trombone",
|
| 880 |
-
"hot tub",
|
| 881 |
-
"turnstile",
|
| 882 |
-
"typewriter keyboard",
|
| 883 |
-
"umbrella",
|
| 884 |
-
"unicycle",
|
| 885 |
-
"upright piano",
|
| 886 |
-
"vacuum cleaner",
|
| 887 |
-
"vase",
|
| 888 |
-
"vaulted or arched ceiling",
|
| 889 |
-
"velvet fabric",
|
| 890 |
-
"vending machine",
|
| 891 |
-
"vestment",
|
| 892 |
-
"viaduct",
|
| 893 |
-
"violin",
|
| 894 |
-
"volleyball",
|
| 895 |
-
"waffle iron",
|
| 896 |
-
"wall clock",
|
| 897 |
-
"wallet",
|
| 898 |
-
"wardrobe",
|
| 899 |
-
"military aircraft",
|
| 900 |
-
"sink",
|
| 901 |
-
"washing machine",
|
| 902 |
-
"water bottle",
|
| 903 |
-
"water jug",
|
| 904 |
-
"water tower",
|
| 905 |
-
"whiskey jug",
|
| 906 |
-
"whistle",
|
| 907 |
-
"hair wig",
|
| 908 |
-
"window screen",
|
| 909 |
-
"window shade",
|
| 910 |
-
"Windsor tie",
|
| 911 |
-
"wine bottle",
|
| 912 |
-
"airplane wing",
|
| 913 |
-
"wok",
|
| 914 |
-
"wooden spoon",
|
| 915 |
-
"wool",
|
| 916 |
-
"split-rail fence",
|
| 917 |
-
"shipwreck",
|
| 918 |
-
"sailboat",
|
| 919 |
-
"yurt",
|
| 920 |
-
"website",
|
| 921 |
-
"comic book",
|
| 922 |
-
"crossword",
|
| 923 |
-
"traffic or street sign",
|
| 924 |
-
"traffic light",
|
| 925 |
-
"dust jacket",
|
| 926 |
-
"menu",
|
| 927 |
-
"plate",
|
| 928 |
-
"guacamole",
|
| 929 |
-
"consomme",
|
| 930 |
-
"hot pot",
|
| 931 |
-
"trifle",
|
| 932 |
-
"ice cream",
|
| 933 |
-
"popsicle",
|
| 934 |
-
"baguette",
|
| 935 |
-
"bagel",
|
| 936 |
-
"pretzel",
|
| 937 |
-
"cheeseburger",
|
| 938 |
-
"hot dog",
|
| 939 |
-
"mashed potatoes",
|
| 940 |
-
"cabbage",
|
| 941 |
-
"broccoli",
|
| 942 |
-
"cauliflower",
|
| 943 |
-
"zucchini",
|
| 944 |
-
"spaghetti squash",
|
| 945 |
-
"acorn squash",
|
| 946 |
-
"butternut squash",
|
| 947 |
-
"cucumber",
|
| 948 |
-
"artichoke",
|
| 949 |
-
"bell pepper",
|
| 950 |
-
"cardoon",
|
| 951 |
-
"mushroom",
|
| 952 |
-
"Granny Smith apple",
|
| 953 |
-
"strawberry",
|
| 954 |
-
"orange",
|
| 955 |
-
"lemon",
|
| 956 |
-
"fig",
|
| 957 |
-
"pineapple",
|
| 958 |
-
"banana",
|
| 959 |
-
"jackfruit",
|
| 960 |
-
"cherimoya (custard apple)",
|
| 961 |
-
"pomegranate",
|
| 962 |
-
"hay",
|
| 963 |
-
"carbonara",
|
| 964 |
-
"chocolate syrup",
|
| 965 |
-
"dough",
|
| 966 |
-
"meatloaf",
|
| 967 |
-
"pizza",
|
| 968 |
-
"pot pie",
|
| 969 |
-
"burrito",
|
| 970 |
-
"red wine",
|
| 971 |
-
"espresso",
|
| 972 |
-
"tea cup",
|
| 973 |
-
"eggnog",
|
| 974 |
-
"mountain",
|
| 975 |
-
"bubble",
|
| 976 |
-
"cliff",
|
| 977 |
-
"coral reef",
|
| 978 |
-
"geyser",
|
| 979 |
-
"lakeshore",
|
| 980 |
-
"promontory",
|
| 981 |
-
"sandbar",
|
| 982 |
-
"beach",
|
| 983 |
-
"valley",
|
| 984 |
-
"volcano",
|
| 985 |
-
"baseball player",
|
| 986 |
-
"bridegroom",
|
| 987 |
-
"scuba diver",
|
| 988 |
-
"rapeseed",
|
| 989 |
-
"daisy",
|
| 990 |
-
"yellow lady's slipper",
|
| 991 |
-
"corn",
|
| 992 |
-
"acorn",
|
| 993 |
-
"rose hip",
|
| 994 |
-
"horse chestnut seed",
|
| 995 |
-
"coral fungus",
|
| 996 |
-
"agaric",
|
| 997 |
-
"gyromitra",
|
| 998 |
-
"stinkhorn mushroom",
|
| 999 |
-
"earth star fungus",
|
| 1000 |
-
"hen of the woods mushroom",
|
| 1001 |
-
"bolete",
|
| 1002 |
-
"corn cob",
|
| 1003 |
-
"toilet paper",
|
| 1004 |
-
]
|
| 1005 |
-
|
| 1006 |
-
|
| 1007 |
-
openai_imagenet_template = [
|
| 1008 |
-
lambda c: f"a bad photo of a {c}.",
|
| 1009 |
-
lambda c: f"a photo of many {c}.",
|
| 1010 |
-
lambda c: f"a sculpture of a {c}.",
|
| 1011 |
-
lambda c: f"a photo of the hard to see {c}.",
|
| 1012 |
-
lambda c: f"a low resolution photo of the {c}.",
|
| 1013 |
-
lambda c: f"a rendering of a {c}.",
|
| 1014 |
-
lambda c: f"graffiti of a {c}.",
|
| 1015 |
-
lambda c: f"a bad photo of the {c}.",
|
| 1016 |
-
lambda c: f"a cropped photo of the {c}.",
|
| 1017 |
-
lambda c: f"a tattoo of a {c}.",
|
| 1018 |
-
lambda c: f"the embroidered {c}.",
|
| 1019 |
-
lambda c: f"a photo of a hard to see {c}.",
|
| 1020 |
-
lambda c: f"a bright photo of a {c}.",
|
| 1021 |
-
lambda c: f"a photo of a clean {c}.",
|
| 1022 |
-
lambda c: f"a photo of a dirty {c}.",
|
| 1023 |
-
lambda c: f"a dark photo of the {c}.",
|
| 1024 |
-
lambda c: f"a drawing of a {c}.",
|
| 1025 |
-
lambda c: f"a photo of my {c}.",
|
| 1026 |
-
lambda c: f"the plastic {c}.",
|
| 1027 |
-
lambda c: f"a photo of the cool {c}.",
|
| 1028 |
-
lambda c: f"a close-up photo of a {c}.",
|
| 1029 |
-
lambda c: f"a black and white photo of the {c}.",
|
| 1030 |
-
lambda c: f"a painting of the {c}.",
|
| 1031 |
-
lambda c: f"a painting of a {c}.",
|
| 1032 |
-
lambda c: f"a pixelated photo of the {c}.",
|
| 1033 |
-
lambda c: f"a sculpture of the {c}.",
|
| 1034 |
-
lambda c: f"a bright photo of the {c}.",
|
| 1035 |
-
lambda c: f"a cropped photo of a {c}.",
|
| 1036 |
-
lambda c: f"a plastic {c}.",
|
| 1037 |
-
lambda c: f"a photo of the dirty {c}.",
|
| 1038 |
-
lambda c: f"a jpeg corrupted photo of a {c}.",
|
| 1039 |
-
lambda c: f"a blurry photo of the {c}.",
|
| 1040 |
-
lambda c: f"a photo of the {c}.",
|
| 1041 |
-
lambda c: f"a good photo of the {c}.",
|
| 1042 |
-
lambda c: f"a rendering of the {c}.",
|
| 1043 |
-
lambda c: f"a {c} in a video game.",
|
| 1044 |
-
lambda c: f"a photo of one {c}.",
|
| 1045 |
-
lambda c: f"a doodle of a {c}.",
|
| 1046 |
-
lambda c: f"a close-up photo of the {c}.",
|
| 1047 |
-
lambda c: f"a photo of a {c}.",
|
| 1048 |
-
lambda c: f"the origami {c}.",
|
| 1049 |
-
lambda c: f"the {c} in a video game.",
|
| 1050 |
-
lambda c: f"a sketch of a {c}.",
|
| 1051 |
-
lambda c: f"a doodle of the {c}.",
|
| 1052 |
-
lambda c: f"a origami {c}.",
|
| 1053 |
-
lambda c: f"a low resolution photo of a {c}.",
|
| 1054 |
-
lambda c: f"the toy {c}.",
|
| 1055 |
-
lambda c: f"a rendition of the {c}.",
|
| 1056 |
-
lambda c: f"a photo of the clean {c}.",
|
| 1057 |
-
lambda c: f"a photo of a large {c}.",
|
| 1058 |
-
lambda c: f"a rendition of a {c}.",
|
| 1059 |
-
lambda c: f"a photo of a nice {c}.",
|
| 1060 |
-
lambda c: f"a photo of a weird {c}.",
|
| 1061 |
-
lambda c: f"a blurry photo of a {c}.",
|
| 1062 |
-
lambda c: f"a cartoon {c}.",
|
| 1063 |
-
lambda c: f"art of a {c}.",
|
| 1064 |
-
lambda c: f"a sketch of the {c}.",
|
| 1065 |
-
lambda c: f"a embroidered {c}.",
|
| 1066 |
-
lambda c: f"a pixelated photo of a {c}.",
|
| 1067 |
-
lambda c: f"itap of the {c}.",
|
| 1068 |
-
lambda c: f"a jpeg corrupted photo of the {c}.",
|
| 1069 |
-
lambda c: f"a good photo of a {c}.",
|
| 1070 |
-
lambda c: f"a plushie {c}.",
|
| 1071 |
-
lambda c: f"a photo of the nice {c}.",
|
| 1072 |
-
lambda c: f"a photo of the small {c}.",
|
| 1073 |
-
lambda c: f"a photo of the weird {c}.",
|
| 1074 |
-
lambda c: f"the cartoon {c}.",
|
| 1075 |
-
lambda c: f"art of the {c}.",
|
| 1076 |
-
lambda c: f"a drawing of the {c}.",
|
| 1077 |
-
lambda c: f"a photo of the large {c}.",
|
| 1078 |
-
lambda c: f"a black and white photo of a {c}.",
|
| 1079 |
-
lambda c: f"the plushie {c}.",
|
| 1080 |
-
lambda c: f"a dark photo of a {c}.",
|
| 1081 |
-
lambda c: f"itap of a {c}.",
|
| 1082 |
-
lambda c: f"graffiti of the {c}.",
|
| 1083 |
-
lambda c: f"a toy {c}.",
|
| 1084 |
-
lambda c: f"itap of my {c}.",
|
| 1085 |
-
lambda c: f"a photo of a cool {c}.",
|
| 1086 |
-
lambda c: f"a photo of a small {c}.",
|
| 1087 |
-
lambda c: f"a tattoo of the {c}.",
|
| 1088 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/infer_demo.py
DELETED
|
@@ -1,109 +0,0 @@
|
|
| 1 |
-
import sys
|
| 2 |
-
|
| 3 |
-
sys.path.append(
|
| 4 |
-
"/mnt/fast/nobackup/users/hl01486/projects/contrastive_pretraining/CLAP/src"
|
| 5 |
-
)
|
| 6 |
-
|
| 7 |
-
import os
|
| 8 |
-
import torch
|
| 9 |
-
import librosa
|
| 10 |
-
from open_clip import create_model
|
| 11 |
-
from training.data import get_audio_features
|
| 12 |
-
from training.data import int16_to_float32, float32_to_int16
|
| 13 |
-
from transformers import RobertaTokenizer
|
| 14 |
-
|
| 15 |
-
tokenize = RobertaTokenizer.from_pretrained("roberta-base")
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
def tokenizer(text):
|
| 19 |
-
result = tokenize(
|
| 20 |
-
text,
|
| 21 |
-
padding="max_length",
|
| 22 |
-
truncation=True,
|
| 23 |
-
max_length=77,
|
| 24 |
-
return_tensors="pt",
|
| 25 |
-
)
|
| 26 |
-
return {k: v.squeeze(0) for k, v in result.items()}
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
PRETRAINED_PATH = "/mnt/fast/nobackup/users/hl01486/projects/contrastive_pretraining/CLAP/assets/checkpoints/epoch_top_0_audioset_no_fusion.pt"
|
| 30 |
-
WAVE_48k_PATH = "/mnt/fast/nobackup/users/hl01486/projects/contrastive_pretraining/CLAP/assets/audio/machine.wav"
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
def infer_text():
|
| 34 |
-
device = "cuda:0" if torch.cuda.is_available() else "cpu"
|
| 35 |
-
precision = "fp32"
|
| 36 |
-
amodel = "HTSAT-tiny" # or 'PANN-14'
|
| 37 |
-
tmodel = "roberta" # the best text encoder in our training
|
| 38 |
-
enable_fusion = False # False if you do not want to use the fusion model
|
| 39 |
-
fusion_type = "aff_2d"
|
| 40 |
-
pretrained = PRETRAINED_PATH
|
| 41 |
-
|
| 42 |
-
model, model_cfg = create_model(
|
| 43 |
-
amodel,
|
| 44 |
-
tmodel,
|
| 45 |
-
pretrained,
|
| 46 |
-
precision=precision,
|
| 47 |
-
device=device,
|
| 48 |
-
enable_fusion=enable_fusion,
|
| 49 |
-
fusion_type=fusion_type,
|
| 50 |
-
)
|
| 51 |
-
# load the text, can be a list (i.e. batch size)
|
| 52 |
-
text_data = ["I love the contrastive learning", "I love the pretrain model"]
|
| 53 |
-
# tokenize for roberta, if you want to tokenize for another text encoder, please refer to data.py#L43-90
|
| 54 |
-
text_data = tokenizer(text_data)
|
| 55 |
-
|
| 56 |
-
text_embed = model.get_text_embedding(text_data)
|
| 57 |
-
print(text_embed.size())
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
def infer_audio():
|
| 61 |
-
|
| 62 |
-
device = "cuda:0" if torch.cuda.is_available() else "cpu"
|
| 63 |
-
precision = "fp32"
|
| 64 |
-
amodel = "HTSAT-tiny" # or 'PANN-14'
|
| 65 |
-
tmodel = "roberta" # the best text encoder in our training
|
| 66 |
-
enable_fusion = False # False if you do not want to use the fusion model
|
| 67 |
-
fusion_type = "aff_2d"
|
| 68 |
-
pretrained = PRETRAINED_PATH
|
| 69 |
-
|
| 70 |
-
model, model_cfg = create_model(
|
| 71 |
-
amodel,
|
| 72 |
-
tmodel,
|
| 73 |
-
pretrained,
|
| 74 |
-
precision=precision,
|
| 75 |
-
device=device,
|
| 76 |
-
enable_fusion=enable_fusion,
|
| 77 |
-
fusion_type=fusion_type,
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
# load the waveform of the shape (T,), should resample to 48000
|
| 81 |
-
audio_waveform, sr = librosa.load(WAVE_48k_PATH, sr=48000)
|
| 82 |
-
# quantize
|
| 83 |
-
audio_waveform = int16_to_float32(float32_to_int16(audio_waveform))
|
| 84 |
-
audio_waveform = torch.from_numpy(audio_waveform).float()
|
| 85 |
-
audio_dict = {}
|
| 86 |
-
|
| 87 |
-
# the 'fusion' truncate mode can be changed to 'rand_trunc' if run in unfusion mode
|
| 88 |
-
import ipdb
|
| 89 |
-
|
| 90 |
-
ipdb.set_trace()
|
| 91 |
-
audio_dict = get_audio_features(
|
| 92 |
-
audio_dict,
|
| 93 |
-
audio_waveform,
|
| 94 |
-
480000,
|
| 95 |
-
data_truncating="fusion",
|
| 96 |
-
data_filling="repeatpad",
|
| 97 |
-
audio_cfg=model_cfg["audio_cfg"],
|
| 98 |
-
)
|
| 99 |
-
# can send a list to the model, to process many audio tracks in one time (i.e. batch size)
|
| 100 |
-
audio_embed = model.get_audio_embedding([audio_dict])
|
| 101 |
-
print(audio_embed.size())
|
| 102 |
-
import ipdb
|
| 103 |
-
|
| 104 |
-
ipdb.set_trace()
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
if __name__ == "__main__":
|
| 108 |
-
infer_text()
|
| 109 |
-
infer_audio()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/logger.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
| 1 |
-
import logging
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
def setup_logging(log_file, level, include_host=False):
|
| 5 |
-
if include_host:
|
| 6 |
-
import socket
|
| 7 |
-
|
| 8 |
-
hostname = socket.gethostname()
|
| 9 |
-
formatter = logging.Formatter(
|
| 10 |
-
f"%(asctime)s | {hostname} | %(levelname)s | %(message)s",
|
| 11 |
-
datefmt="%Y-%m-%d,%H:%M:%S",
|
| 12 |
-
)
|
| 13 |
-
else:
|
| 14 |
-
formatter = logging.Formatter(
|
| 15 |
-
"%(asctime)s | %(levelname)s | %(message)s", datefmt="%Y-%m-%d,%H:%M:%S"
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
logging.root.setLevel(level)
|
| 19 |
-
loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict]
|
| 20 |
-
for logger in loggers:
|
| 21 |
-
logger.setLevel(level)
|
| 22 |
-
|
| 23 |
-
stream_handler = logging.StreamHandler()
|
| 24 |
-
stream_handler.setFormatter(formatter)
|
| 25 |
-
logging.root.addHandler(stream_handler)
|
| 26 |
-
|
| 27 |
-
if log_file:
|
| 28 |
-
file_handler = logging.FileHandler(filename=log_file)
|
| 29 |
-
file_handler.setFormatter(formatter)
|
| 30 |
-
logging.root.addHandler(file_handler)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/lp_main.py
DELETED
|
@@ -1,670 +0,0 @@
|
|
| 1 |
-
from cmath import cos
|
| 2 |
-
from inspect import getargs
|
| 3 |
-
import logging
|
| 4 |
-
import os
|
| 5 |
-
import random
|
| 6 |
-
from datetime import datetime
|
| 7 |
-
import bisect
|
| 8 |
-
import copy
|
| 9 |
-
from sched import scheduler
|
| 10 |
-
import numpy as np
|
| 11 |
-
import torch
|
| 12 |
-
import torch.backends.cudnn as cudnn
|
| 13 |
-
from torch import optim
|
| 14 |
-
from torch.cuda.amp import GradScaler
|
| 15 |
-
import faulthandler
|
| 16 |
-
import pathlib
|
| 17 |
-
import argparse
|
| 18 |
-
import time
|
| 19 |
-
|
| 20 |
-
try:
|
| 21 |
-
import wandb
|
| 22 |
-
except ImportError:
|
| 23 |
-
wandb = None
|
| 24 |
-
|
| 25 |
-
try:
|
| 26 |
-
import torch.utils.tensorboard as tensorboard
|
| 27 |
-
except ImportError:
|
| 28 |
-
tensorboard = None
|
| 29 |
-
|
| 30 |
-
try:
|
| 31 |
-
import horovod.torch as hvd
|
| 32 |
-
except ImportError:
|
| 33 |
-
hvd = None
|
| 34 |
-
|
| 35 |
-
from open_clip import create_model_and_transforms, trace_model, create_model
|
| 36 |
-
from training.data import get_data
|
| 37 |
-
from training.params import parse_args
|
| 38 |
-
from training.distributed import is_master, init_distributed_device, world_info_from_env
|
| 39 |
-
from training.logger import setup_logging
|
| 40 |
-
from training.scheduler import cosine_lr
|
| 41 |
-
from training.lp_train import train_one_epoch, evaluate
|
| 42 |
-
from open_clip.utils import get_tar_path_from_dataset_name, dataset_split, get_optimizer
|
| 43 |
-
from open_clip.utils import load_p, load_class_label
|
| 44 |
-
from open_clip.linear_probe import LinearProbe
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
def maintain_ckpts(args, startidx, all_idx_len):
|
| 48 |
-
for i in reversed(range(startidx, all_idx_len)):
|
| 49 |
-
if os.path.exists(os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt")):
|
| 50 |
-
os.rename(
|
| 51 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt"),
|
| 52 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i+1}.pt"),
|
| 53 |
-
)
|
| 54 |
-
if os.path.exists(
|
| 55 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{all_idx_len}.pt")
|
| 56 |
-
):
|
| 57 |
-
os.remove(os.path.join(args.checkpoint_path, f"epoch_top_{all_idx_len}.pt"))
|
| 58 |
-
return
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
def update_top_k_performance(
|
| 62 |
-
new_metrics_inputs, current_top_k_ckpt_metrics, args, ckpt, bignumbetter=True
|
| 63 |
-
):
|
| 64 |
-
"""
|
| 65 |
-
Record the top-k performance of the current epoch.
|
| 66 |
-
current_top_k_metrics is a dictionary of the form: {1: top_1_ckpt_measure, 2: top_2_ckpt_measure, ...}
|
| 67 |
-
"""
|
| 68 |
-
if isinstance(new_metrics_inputs, (list, tuple)):
|
| 69 |
-
new_metrics_inputs = np.mean(new_metrics_inputs)
|
| 70 |
-
return update_top_k_performance(
|
| 71 |
-
new_metrics_inputs,
|
| 72 |
-
current_top_k_ckpt_metrics,
|
| 73 |
-
args=args,
|
| 74 |
-
ckpt=ckpt,
|
| 75 |
-
bignumbetter=bignumbetter,
|
| 76 |
-
)
|
| 77 |
-
elif isinstance(new_metrics_inputs, dict):
|
| 78 |
-
new_metrics_inputs = np.mean(list(new_metrics_inputs.values()))
|
| 79 |
-
return update_top_k_performance(
|
| 80 |
-
new_metrics_inputs,
|
| 81 |
-
current_top_k_ckpt_metrics,
|
| 82 |
-
args=args,
|
| 83 |
-
ckpt=ckpt,
|
| 84 |
-
bignumbetter=bignumbetter,
|
| 85 |
-
)
|
| 86 |
-
elif isinstance(new_metrics_inputs, (float, int)):
|
| 87 |
-
update_flag = {k: False for k in current_top_k_ckpt_metrics.keys()}
|
| 88 |
-
sorted_keys = sorted(current_top_k_ckpt_metrics.keys())
|
| 89 |
-
sorted_values = sorted(
|
| 90 |
-
current_top_k_ckpt_metrics.values(), reverse=bignumbetter
|
| 91 |
-
)
|
| 92 |
-
sorted_values_ = copy.deepcopy(sorted_values)
|
| 93 |
-
sorted_values.append(new_metrics_inputs)
|
| 94 |
-
sorted_values = sorted(sorted_values, reverse=bignumbetter)
|
| 95 |
-
sorted_values = sorted_values[:-1]
|
| 96 |
-
|
| 97 |
-
if sorted_values == sorted_values_:
|
| 98 |
-
return current_top_k_ckpt_metrics, new_metrics_inputs
|
| 99 |
-
else:
|
| 100 |
-
for i in range(len(sorted_keys)):
|
| 101 |
-
if current_top_k_ckpt_metrics[sorted_keys[i]] != sorted_values[i]:
|
| 102 |
-
current_top_k_ckpt_metrics[sorted_keys[i]] = sorted_values[i]
|
| 103 |
-
update_flag[sorted_keys[i]] = True
|
| 104 |
-
for i in range(len(update_flag)):
|
| 105 |
-
if update_flag[i]:
|
| 106 |
-
maintain_ckpts(args, i, len(sorted_keys))
|
| 107 |
-
torch.save(
|
| 108 |
-
ckpt,
|
| 109 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt"),
|
| 110 |
-
)
|
| 111 |
-
break
|
| 112 |
-
return current_top_k_ckpt_metrics, new_metrics_inputs
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
# def updateifNone(a, b):
|
| 116 |
-
# a = b if None else a
|
| 117 |
-
# return a
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
def is_pretrained_params(n):
|
| 121 |
-
return (
|
| 122 |
-
n.startswith("clap_model.transformer")
|
| 123 |
-
or n in ["clap_model.positional_embedding", "clap_model.text_projection"]
|
| 124 |
-
or n.startswith("clap_model.token_embedding")
|
| 125 |
-
or n.startswith("clap_model.ln_final")
|
| 126 |
-
or n.startswith("clap_model.logit_scale_t")
|
| 127 |
-
)
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
def random_seed(seed=42, rank=0):
|
| 131 |
-
torch.manual_seed(seed + rank)
|
| 132 |
-
np.random.seed(seed + rank)
|
| 133 |
-
random.seed(seed + rank)
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
def config_lp_optimizer(model, data, args):
|
| 137 |
-
# set wd-related params to 0 if use adam optimizer
|
| 138 |
-
if args.optimizer == "adam":
|
| 139 |
-
args.wd = 0
|
| 140 |
-
args.wd_pretrained = 0
|
| 141 |
-
args.wd_new = 0
|
| 142 |
-
|
| 143 |
-
in_clap = lambda n, p: n.startswith("clap_model")
|
| 144 |
-
|
| 145 |
-
named_parameters = list(model.named_parameters())
|
| 146 |
-
|
| 147 |
-
optimizer = {}
|
| 148 |
-
scheduler = {}
|
| 149 |
-
|
| 150 |
-
# freeze text encoder
|
| 151 |
-
text_freeze_parameters = [
|
| 152 |
-
p
|
| 153 |
-
for n, p in named_parameters
|
| 154 |
-
if n.startswith("clap_model.transformer")
|
| 155 |
-
or n in ["clap_model.positional_embedding", "clap_model.text_projection"]
|
| 156 |
-
or n.startswith("clap_model.token_embedding")
|
| 157 |
-
or n.startswith("clap_model.ln_final")
|
| 158 |
-
]
|
| 159 |
-
|
| 160 |
-
if args.freeze_text:
|
| 161 |
-
logging.info("Freeze Text!!!!")
|
| 162 |
-
for k in text_freeze_parameters:
|
| 163 |
-
k.requires_grad = False
|
| 164 |
-
|
| 165 |
-
if not args.lp_freeze:
|
| 166 |
-
exclude = (
|
| 167 |
-
lambda n, p: p.ndim < 2
|
| 168 |
-
or "bn" in n
|
| 169 |
-
or "ln" in n
|
| 170 |
-
or "bias" in n
|
| 171 |
-
or "logit_scale" in n
|
| 172 |
-
)
|
| 173 |
-
include = lambda n, p: not exclude(n, p)
|
| 174 |
-
|
| 175 |
-
# (yusong): we do not split the learning rate anymore
|
| 176 |
-
# p for n, p in named_parameters if in_clap(n,p) and exclude(n, p) and p.requires_grad
|
| 177 |
-
gain_or_bias_params = [
|
| 178 |
-
p for n, p in named_parameters if exclude(n, p) and p.requires_grad
|
| 179 |
-
]
|
| 180 |
-
# rest_params = [p for n, p in named_parameters if in_clap(n,p) and include(n, p) and p.requires_grad]
|
| 181 |
-
rest_params = [
|
| 182 |
-
p for n, p in named_parameters if include(n, p) and p.requires_grad
|
| 183 |
-
]
|
| 184 |
-
|
| 185 |
-
if args.train_data is None:
|
| 186 |
-
optimizer = None
|
| 187 |
-
scheduler = None
|
| 188 |
-
else:
|
| 189 |
-
total_steps = data["train"].dataloader.num_batches * args.epochs
|
| 190 |
-
|
| 191 |
-
if args.split_opt:
|
| 192 |
-
for x in ["lr", "beta1", "beta2", "eps", "wd"]:
|
| 193 |
-
for y in ["_new", "_pretrained"]:
|
| 194 |
-
if getattr(args, x + y) is None:
|
| 195 |
-
setattr(args, x + y, getattr(args, x))
|
| 196 |
-
|
| 197 |
-
gain_or_bias_pretrained_params = [
|
| 198 |
-
p
|
| 199 |
-
for n, p in named_parameters
|
| 200 |
-
if (exclude(n, p) and p.requires_grad) and is_pretrained_params(n)
|
| 201 |
-
]
|
| 202 |
-
rest_pretrained_params = [
|
| 203 |
-
p
|
| 204 |
-
for n, p in named_parameters
|
| 205 |
-
if (include(n, p) and p.requires_grad) and is_pretrained_params(n)
|
| 206 |
-
]
|
| 207 |
-
gain_or_bias_new_params = [
|
| 208 |
-
p
|
| 209 |
-
for n, p in named_parameters
|
| 210 |
-
if (exclude(n, p) and p.requires_grad)
|
| 211 |
-
and (not is_pretrained_params(n))
|
| 212 |
-
]
|
| 213 |
-
rest_new_params = [
|
| 214 |
-
p
|
| 215 |
-
for n, p in named_parameters
|
| 216 |
-
if (include(n, p) and p.requires_grad)
|
| 217 |
-
and (not is_pretrained_params(n))
|
| 218 |
-
]
|
| 219 |
-
|
| 220 |
-
pretrained_params_optimizer = get_optimizer(
|
| 221 |
-
[
|
| 222 |
-
{"params": gain_or_bias_pretrained_params, "weight_decay": 0.0},
|
| 223 |
-
{
|
| 224 |
-
"params": rest_pretrained_params,
|
| 225 |
-
"weight_decay": args.wd_pretrained,
|
| 226 |
-
},
|
| 227 |
-
],
|
| 228 |
-
lr=args.lr_pretrained,
|
| 229 |
-
betas=(args.beta1_pretrained, args.beta2_pretrained),
|
| 230 |
-
eps=args.eps_pretrained,
|
| 231 |
-
momentum=args.momentum_pretrained,
|
| 232 |
-
optimizer_name=args.optimizer,
|
| 233 |
-
)
|
| 234 |
-
pretrained_params_scheduler = cosine_lr(
|
| 235 |
-
pretrained_params_optimizer,
|
| 236 |
-
args.lr_pretrained,
|
| 237 |
-
args.warmup,
|
| 238 |
-
total_steps,
|
| 239 |
-
)
|
| 240 |
-
|
| 241 |
-
new_params_optimizer = get_optimizer(
|
| 242 |
-
[
|
| 243 |
-
{"params": gain_or_bias_new_params, "weight_decay": 0.0},
|
| 244 |
-
{"params": rest_new_params, "weight_decay": args.wd_new},
|
| 245 |
-
],
|
| 246 |
-
lr=args.lr_new,
|
| 247 |
-
betas=(args.beta1_new, args.beta2_new),
|
| 248 |
-
eps=args.eps_new,
|
| 249 |
-
momentum=args.momentum_new,
|
| 250 |
-
optimizer_name=args.optimizer,
|
| 251 |
-
)
|
| 252 |
-
new_params_scheduler = cosine_lr(
|
| 253 |
-
new_params_optimizer, args.lr_new, args.warmup, total_steps
|
| 254 |
-
)
|
| 255 |
-
|
| 256 |
-
optimizer["text"] = pretrained_params_optimizer
|
| 257 |
-
optimizer["audio"] = new_params_optimizer
|
| 258 |
-
scheduler["text"] = pretrained_params_scheduler
|
| 259 |
-
scheduler["audio"] = new_params_scheduler
|
| 260 |
-
|
| 261 |
-
if args.horovod:
|
| 262 |
-
pretrained_params_optimizer = hvd.DistributedOptimizer(
|
| 263 |
-
pretrained_params_optimizer,
|
| 264 |
-
named_parameters=model.named_parameters(),
|
| 265 |
-
)
|
| 266 |
-
new_params_optimizer = hvd.DistributedOptimizer(
|
| 267 |
-
new_params_optimizer, named_parameters=model.named_parameters()
|
| 268 |
-
)
|
| 269 |
-
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
|
| 270 |
-
hvd.broadcast_optimizer_state(
|
| 271 |
-
pretrained_params_optimizer, root_rank=0
|
| 272 |
-
)
|
| 273 |
-
hvd.broadcast_optimizer_state(new_params_optimizer, root_rank=0)
|
| 274 |
-
else:
|
| 275 |
-
|
| 276 |
-
optimizer["clap"] = get_optimizer(
|
| 277 |
-
[
|
| 278 |
-
{"params": gain_or_bias_params, "weight_decay": 0.0},
|
| 279 |
-
{"params": rest_params, "weight_decay": args.wd},
|
| 280 |
-
],
|
| 281 |
-
lr=args.lr,
|
| 282 |
-
betas=(args.beta1, args.beta2),
|
| 283 |
-
eps=args.eps,
|
| 284 |
-
momentum=args.momentum,
|
| 285 |
-
optimizer_name=args.optimizer,
|
| 286 |
-
)
|
| 287 |
-
scheduler["clap"] = cosine_lr(
|
| 288 |
-
optimizer["clap"], args.lr, args.warmup, total_steps
|
| 289 |
-
)
|
| 290 |
-
|
| 291 |
-
if args.horovod:
|
| 292 |
-
optimizer["clap"] = hvd.DistributedOptimizer(
|
| 293 |
-
optimizer["clap"], named_parameters=model.named_parameters()
|
| 294 |
-
)
|
| 295 |
-
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
|
| 296 |
-
hvd.broadcast_optimizer_state(optimizer["clap"], root_rank=0)
|
| 297 |
-
|
| 298 |
-
# linear probe optimizer
|
| 299 |
-
else:
|
| 300 |
-
lp_params = [
|
| 301 |
-
p for n, p in named_parameters if (not in_clap(n, p)) and p.requires_grad
|
| 302 |
-
]
|
| 303 |
-
lp_optim = get_optimizer(
|
| 304 |
-
lp_params,
|
| 305 |
-
lr=args.lp_lr,
|
| 306 |
-
betas=(args.beta1, args.beta2),
|
| 307 |
-
eps=args.eps,
|
| 308 |
-
momentum=0.9,
|
| 309 |
-
optimizer_name=args.optimizer,
|
| 310 |
-
)
|
| 311 |
-
optimizer["lp"] = lp_optim
|
| 312 |
-
|
| 313 |
-
return optimizer, scheduler, text_freeze_parameters
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
def main():
|
| 317 |
-
args = parse_args()
|
| 318 |
-
|
| 319 |
-
time.sleep(args.sleep)
|
| 320 |
-
|
| 321 |
-
# sanitize model name for filesystem / uri use, easier if we don't use / in name as a rule?
|
| 322 |
-
args.amodel = args.amodel.replace("/", "-")
|
| 323 |
-
# download sizes.json file
|
| 324 |
-
|
| 325 |
-
# (yusong): the below two lines are for debug
|
| 326 |
-
# print("setting up faulthandler")
|
| 327 |
-
# faulthandler.register(10)
|
| 328 |
-
|
| 329 |
-
random.seed(args.seed)
|
| 330 |
-
torch.manual_seed(args.seed)
|
| 331 |
-
torch.cuda.manual_seed(args.seed)
|
| 332 |
-
torch.cuda.manual_seed_all(args.seed)
|
| 333 |
-
np.random.seed(args.seed)
|
| 334 |
-
args.class_index_dict = load_class_label(args.class_label_path)
|
| 335 |
-
|
| 336 |
-
# get the name of the experiments
|
| 337 |
-
if args.name is None:
|
| 338 |
-
args.name = "-".join(
|
| 339 |
-
[
|
| 340 |
-
datetime.now().strftime("%Y_%m_%d-%H_%M_%S"),
|
| 341 |
-
f"linear_probe" f"model_{args.amodel}",
|
| 342 |
-
f"lr_{args.lr}",
|
| 343 |
-
f"b_{args.batch_size}",
|
| 344 |
-
f"j_{args.workers}",
|
| 345 |
-
f"p_{args.precision}",
|
| 346 |
-
]
|
| 347 |
-
)
|
| 348 |
-
|
| 349 |
-
# discover initial world args early so we can log properly
|
| 350 |
-
args.distributed = False
|
| 351 |
-
args.local_rank, args.rank, args.world_size = world_info_from_env()
|
| 352 |
-
|
| 353 |
-
if args.remotedata and is_master(args):
|
| 354 |
-
for dataset_name in args.datasetnames:
|
| 355 |
-
for split in dataset_split[dataset_name]:
|
| 356 |
-
if not os.path.exists(f"./json_files/{dataset_name}/{split}"):
|
| 357 |
-
os.makedirs(f"./json_files/{dataset_name}/{split}")
|
| 358 |
-
os.system(
|
| 359 |
-
f"aws s3 cp s3://s-laion-audio/webdataset_tar/{dataset_name}/{split}/sizes.json ./json_files/{dataset_name}/{split}/sizes.json"
|
| 360 |
-
)
|
| 361 |
-
|
| 362 |
-
args.log_path = None
|
| 363 |
-
if is_master(args, local=args.log_local):
|
| 364 |
-
log_base_path = os.path.join(args.logs, args.name)
|
| 365 |
-
os.makedirs(log_base_path, exist_ok=True)
|
| 366 |
-
log_filename = f"out-{args.rank}" if args.log_local else "out.log"
|
| 367 |
-
args.log_path = os.path.join(log_base_path, log_filename)
|
| 368 |
-
|
| 369 |
-
# avoid log dir in same name:
|
| 370 |
-
postfix = 0
|
| 371 |
-
while os.path.exists(args.log_path):
|
| 372 |
-
postfix += 1
|
| 373 |
-
log_base_path_new = log_base_path + "-" + str(postfix)
|
| 374 |
-
os.makedirs(log_base_path_new, exist_ok=True)
|
| 375 |
-
log_filename = f"out-{args.rank}" if args.log_local else "out.log"
|
| 376 |
-
args.log_path = os.path.join(log_base_path_new, log_filename)
|
| 377 |
-
# print(
|
| 378 |
-
# "Error. Experiment already exists. Use --name {} to specify a new experiment."
|
| 379 |
-
# )
|
| 380 |
-
# return -1
|
| 381 |
-
|
| 382 |
-
# Set logger
|
| 383 |
-
args.log_level = logging.DEBUG if args.debug else logging.INFO
|
| 384 |
-
setup_logging(args.log_path, args.log_level)
|
| 385 |
-
|
| 386 |
-
# fully initialize distributed device environment
|
| 387 |
-
device = init_distributed_device(args)
|
| 388 |
-
|
| 389 |
-
args.wandb = "wandb" in args.report_to or "all" in args.report_to
|
| 390 |
-
args.tensorboard = "tensorboard" in args.report_to or "all" in args.report_to
|
| 391 |
-
if is_master(args):
|
| 392 |
-
args.tensorboard_path = (
|
| 393 |
-
os.path.join(args.logs, args.name, "tensorboard")
|
| 394 |
-
if args.tensorboard
|
| 395 |
-
else ""
|
| 396 |
-
)
|
| 397 |
-
args.checkpoint_path = os.path.join(args.logs, args.name, "checkpoints")
|
| 398 |
-
for dirname in [args.tensorboard_path, args.checkpoint_path]:
|
| 399 |
-
if dirname:
|
| 400 |
-
os.makedirs(dirname, exist_ok=True)
|
| 401 |
-
else:
|
| 402 |
-
args.tensorboard_path = ""
|
| 403 |
-
args.checkpoint_path = ""
|
| 404 |
-
|
| 405 |
-
if args.copy_codebase:
|
| 406 |
-
copy_codebase(args)
|
| 407 |
-
|
| 408 |
-
assert args.precision in ["amp", "fp16", "fp32"]
|
| 409 |
-
if args.precision == "fp16":
|
| 410 |
-
logging.warning(
|
| 411 |
-
"It is recommended to use AMP mixed-precision instead of FP16. "
|
| 412 |
-
"FP16 support needs further verification and tuning, especially for train."
|
| 413 |
-
)
|
| 414 |
-
|
| 415 |
-
if args.horovod:
|
| 416 |
-
logging.info(
|
| 417 |
-
f"Running in horovod mode with multiple processes / nodes. Device: {args.device}."
|
| 418 |
-
f"Process (global: {args.rank}, local {args.local_rank}), total {args.world_size}."
|
| 419 |
-
)
|
| 420 |
-
elif args.distributed:
|
| 421 |
-
logging.info(
|
| 422 |
-
f"Running in distributed mode with multiple processes. Device: {args.device}."
|
| 423 |
-
f"Process (global: {args.rank}, local {args.local_rank}), total {args.world_size}."
|
| 424 |
-
)
|
| 425 |
-
else:
|
| 426 |
-
logging.info(f"Running with a single process. Device {args.device}.")
|
| 427 |
-
|
| 428 |
-
logging.info(f"openai cache dir: {os.path.expanduser(args.openai_model_cache_dir)}")
|
| 429 |
-
|
| 430 |
-
# Create CLAP model
|
| 431 |
-
clap_model, clap_model_cfg = create_model(
|
| 432 |
-
args.amodel,
|
| 433 |
-
args.tmodel,
|
| 434 |
-
args.pretrained,
|
| 435 |
-
precision=args.precision,
|
| 436 |
-
device=device,
|
| 437 |
-
jit=args.torchscript,
|
| 438 |
-
force_quick_gelu=args.force_quick_gelu,
|
| 439 |
-
openai_model_cache_dir=os.path.expanduser(args.openai_model_cache_dir),
|
| 440 |
-
skip_params=False,
|
| 441 |
-
pretrained_audio=args.pretrained_audio,
|
| 442 |
-
pretrained_text=args.pretrained_text,
|
| 443 |
-
enable_fusion=args.enable_fusion,
|
| 444 |
-
fusion_type=args.fusion_type,
|
| 445 |
-
)
|
| 446 |
-
|
| 447 |
-
args.lp_out_ch = len(list(args.class_index_dict.keys()))
|
| 448 |
-
# Linear Probe
|
| 449 |
-
logging.info(f"linear probe using mlp: {args.lp_mlp}")
|
| 450 |
-
logging.info(f"linear probe using freeze: {args.lp_freeze}")
|
| 451 |
-
logging.info(f"linear probe act layer: {args.lp_act}")
|
| 452 |
-
logging.info(f"linear probe out ch: {args.lp_out_ch}")
|
| 453 |
-
logging.info(f"linear probe learning rate (if applicable): {args.lp_lr}")
|
| 454 |
-
logging.info(f"linear probe loss func: {args.lp_loss}")
|
| 455 |
-
logging.info(f"linear probe lp_metrics: {args.lp_metrics}")
|
| 456 |
-
|
| 457 |
-
model = LinearProbe(
|
| 458 |
-
clap_model,
|
| 459 |
-
mlp=args.lp_mlp,
|
| 460 |
-
freeze=args.lp_freeze,
|
| 461 |
-
in_ch=512,
|
| 462 |
-
out_ch=args.lp_out_ch,
|
| 463 |
-
act=args.lp_act,
|
| 464 |
-
) # in_ch is fixed (i.e., 512)
|
| 465 |
-
model = model.to(device)
|
| 466 |
-
|
| 467 |
-
if args.horovod:
|
| 468 |
-
with torch.no_grad():
|
| 469 |
-
for param in model.parameters():
|
| 470 |
-
param.set_(param.contiguous())
|
| 471 |
-
|
| 472 |
-
if args.trace:
|
| 473 |
-
model = trace_model(model, batch_size=args.batch_size, device=device)
|
| 474 |
-
|
| 475 |
-
if is_master(args):
|
| 476 |
-
logging.info("Linear Probe CLAP Model:")
|
| 477 |
-
logging.info(f"{str(clap_model)}")
|
| 478 |
-
logging.info("Params:")
|
| 479 |
-
params_file = os.path.join(args.logs, args.name, "params.txt")
|
| 480 |
-
with open(params_file, "w") as f:
|
| 481 |
-
for name in sorted(vars(args)):
|
| 482 |
-
val = getattr(args, name)
|
| 483 |
-
logging.info(f" {name}: {val}")
|
| 484 |
-
f.write(f"{name}: {val}\n")
|
| 485 |
-
|
| 486 |
-
if args.distributed and not args.horovod:
|
| 487 |
-
if args.use_bn_sync:
|
| 488 |
-
model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
|
| 489 |
-
ddp_args = {}
|
| 490 |
-
if args.ddp_static_graph:
|
| 491 |
-
# this doesn't exist in older PyTorch, arg only added if enabled
|
| 492 |
-
ddp_args["static_graph"] = True
|
| 493 |
-
model = torch.nn.parallel.DistributedDataParallel(
|
| 494 |
-
model, device_ids=[device], find_unused_parameters=True, **ddp_args
|
| 495 |
-
)
|
| 496 |
-
|
| 497 |
-
data = get_data(args, clap_model_cfg)
|
| 498 |
-
assert len(data), "At least one train or eval dataset must be specified."
|
| 499 |
-
if args.trace:
|
| 500 |
-
assert "train" not in data, "Cannot train with traced model"
|
| 501 |
-
|
| 502 |
-
optimizer, scheduler, text_freeze_parameters = config_lp_optimizer(
|
| 503 |
-
model, data, args
|
| 504 |
-
)
|
| 505 |
-
|
| 506 |
-
scaler = GradScaler() if args.precision == "amp" else None
|
| 507 |
-
|
| 508 |
-
# optionally resume from a checkpoint
|
| 509 |
-
start_epoch = 0
|
| 510 |
-
if args.resume is not None:
|
| 511 |
-
if os.path.isfile(args.resume):
|
| 512 |
-
checkpoint = torch.load(args.resume, map_location=device)
|
| 513 |
-
if "epoch" in checkpoint:
|
| 514 |
-
# resuming a train checkpoint w/ epoch and optimizer state
|
| 515 |
-
start_epoch = checkpoint["epoch"]
|
| 516 |
-
sd = checkpoint["state_dict"]
|
| 517 |
-
if not args.distributed and next(iter(sd.items()))[0].startswith(
|
| 518 |
-
"module"
|
| 519 |
-
):
|
| 520 |
-
sd = {k[len("module.") :]: v for k, v in sd.items()}
|
| 521 |
-
model.load_state_dict(sd)
|
| 522 |
-
if args.split_opt:
|
| 523 |
-
if optimizer is not None:
|
| 524 |
-
for k, o_ in optimizer.items():
|
| 525 |
-
o_.load_state_dict(checkpoint[k + "_" + "optimizer"])
|
| 526 |
-
if optimizer is not None:
|
| 527 |
-
optimizer.load_state_dict(checkpoint["optimizer"])
|
| 528 |
-
if scaler is not None and "scaler" in checkpoint:
|
| 529 |
-
scaler.load_state_dict(checkpoint["scaler"])
|
| 530 |
-
logging.info(
|
| 531 |
-
f"=> resuming checkpoint '{args.resume}' (epoch {start_epoch})"
|
| 532 |
-
)
|
| 533 |
-
else:
|
| 534 |
-
# loading a bare (model only) checkpoint for fine-tune or evaluation
|
| 535 |
-
model.load_state_dict(checkpoint)
|
| 536 |
-
logging.info(
|
| 537 |
-
f"=> loaded checkpoint '{args.resume}' (epoch {start_epoch})"
|
| 538 |
-
)
|
| 539 |
-
if args.freeze_text:
|
| 540 |
-
print("Freeze Text!!!!")
|
| 541 |
-
for k in text_freeze_parameters:
|
| 542 |
-
k.requires_grad = False
|
| 543 |
-
else:
|
| 544 |
-
logging.info("=> no checkpoint found at '{}'".format(args.resume))
|
| 545 |
-
|
| 546 |
-
cudnn.benchmark = True
|
| 547 |
-
cudnn.deterministic = False
|
| 548 |
-
|
| 549 |
-
# determine if this worker should save logs and checkpoints. only do so if it is rank == 0
|
| 550 |
-
args.save_logs = args.logs and args.logs.lower() != "none" and is_master(args)
|
| 551 |
-
writer = None
|
| 552 |
-
if args.save_logs and args.tensorboard:
|
| 553 |
-
assert tensorboard is not None, "Please install tensorboard."
|
| 554 |
-
writer = tensorboard.SummaryWriter(args.tensorboard_path)
|
| 555 |
-
|
| 556 |
-
if args.wandb and is_master(args):
|
| 557 |
-
assert wandb is not None, "Please install wandb."
|
| 558 |
-
logging.debug("Starting wandb.")
|
| 559 |
-
args.train_sz = data["train"].dataloader.num_samples
|
| 560 |
-
if args.val_data is not None:
|
| 561 |
-
args.val_sz = data["val"].dataloader.num_samples
|
| 562 |
-
# you will have to configure this for your project!
|
| 563 |
-
wandb.init(
|
| 564 |
-
project="clap",
|
| 565 |
-
notes=args.wandb_notes,
|
| 566 |
-
name=args.wandb_notes,
|
| 567 |
-
tags=[],
|
| 568 |
-
config=vars(args),
|
| 569 |
-
)
|
| 570 |
-
if args.debug:
|
| 571 |
-
wandb.watch(model, log="all")
|
| 572 |
-
wandb.save(params_file)
|
| 573 |
-
logging.debug("Finished loading wandb.")
|
| 574 |
-
|
| 575 |
-
if "train" not in data:
|
| 576 |
-
evaluate(model, data, start_epoch, args, writer)
|
| 577 |
-
return
|
| 578 |
-
elif start_epoch == 0 and "val" in data and not args.no_eval:
|
| 579 |
-
evaluate(model, data, 0, args, writer)
|
| 580 |
-
if args.save_top_performance:
|
| 581 |
-
current_top_k_ckpt_metrics = {
|
| 582 |
-
i: 0 for i in range(args.save_top_performance)
|
| 583 |
-
} # initialize the top-k metric for ckpts to 0
|
| 584 |
-
|
| 585 |
-
for epoch in range(start_epoch, args.epochs):
|
| 586 |
-
# freeze the text param after (include) args.freeze_text_after, this is -1 by default
|
| 587 |
-
if epoch == args.freeze_text_after:
|
| 588 |
-
print("Text pretrained parameters are freezed since this epoch.")
|
| 589 |
-
for k in text_freeze_parameters:
|
| 590 |
-
k.requires_grad = False
|
| 591 |
-
if is_master(args):
|
| 592 |
-
logging.info(f"Start epoch {epoch}")
|
| 593 |
-
|
| 594 |
-
train_one_epoch(model, data, epoch, optimizer, scaler, scheduler, args, writer)
|
| 595 |
-
completed_epoch = epoch + 1
|
| 596 |
-
|
| 597 |
-
if (
|
| 598 |
-
any(v in data for v in ("val", "imagenet-val", "imagenet-v2"))
|
| 599 |
-
and not args.no_eval
|
| 600 |
-
):
|
| 601 |
-
metrics = evaluate(model, data, completed_epoch, args, writer)
|
| 602 |
-
if args.save_top_performance:
|
| 603 |
-
top_k_dataset = args.top_k_checkpoint_select_dataset
|
| 604 |
-
top_k_metric = args.top_k_checkpoint_select_metric
|
| 605 |
-
filtered_metrics = [
|
| 606 |
-
v
|
| 607 |
-
for k, v in metrics.items()
|
| 608 |
-
if top_k_metric in k and top_k_dataset in k
|
| 609 |
-
] # check all R@10 metrics (all dataset) and use it to update the ckpt
|
| 610 |
-
# Saving checkpoints.
|
| 611 |
-
if args.save_logs:
|
| 612 |
-
opt_dict = {
|
| 613 |
-
k + "_" + "optimizer": v.state_dict() for k, v in optimizer.items()
|
| 614 |
-
}
|
| 615 |
-
checkpoint_dict = {
|
| 616 |
-
"epoch": completed_epoch,
|
| 617 |
-
"name": args.name,
|
| 618 |
-
"state_dict": model.state_dict(),
|
| 619 |
-
}
|
| 620 |
-
checkpoint_dict.update(opt_dict)
|
| 621 |
-
if scaler is not None:
|
| 622 |
-
checkpoint_dict["scaler"] = scaler.state_dict()
|
| 623 |
-
|
| 624 |
-
if completed_epoch == args.epochs or (
|
| 625 |
-
args.save_frequency > 0 and (completed_epoch % args.save_frequency) == 0
|
| 626 |
-
):
|
| 627 |
-
torch.save(
|
| 628 |
-
checkpoint_dict,
|
| 629 |
-
os.path.join(args.checkpoint_path, f"epoch_{completed_epoch}.pt"),
|
| 630 |
-
)
|
| 631 |
-
if args.save_most_recent:
|
| 632 |
-
torch.save(
|
| 633 |
-
checkpoint_dict,
|
| 634 |
-
os.path.join(args.checkpoint_path, f"epoch_latest.pt"),
|
| 635 |
-
)
|
| 636 |
-
if args.save_top_performance and not args.no_eval:
|
| 637 |
-
update_top_k_performance(
|
| 638 |
-
filtered_metrics,
|
| 639 |
-
current_top_k_ckpt_metrics,
|
| 640 |
-
args,
|
| 641 |
-
checkpoint_dict,
|
| 642 |
-
bignumbetter=True,
|
| 643 |
-
)
|
| 644 |
-
|
| 645 |
-
if args.wandb and is_master(args):
|
| 646 |
-
wandb.finish()
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
def copy_codebase(args):
|
| 650 |
-
from shutil import copytree, ignore_patterns
|
| 651 |
-
|
| 652 |
-
new_code_path = os.path.join(args.logs, args.name, "code")
|
| 653 |
-
if os.path.exists(new_code_path):
|
| 654 |
-
print(
|
| 655 |
-
f"Error. Experiment already exists at {new_code_path}. Use --name to specify a new experiment."
|
| 656 |
-
)
|
| 657 |
-
return -1
|
| 658 |
-
print(f"Copying codebase to {new_code_path}")
|
| 659 |
-
current_code_path = os.path.realpath(__file__)
|
| 660 |
-
for _ in range(3):
|
| 661 |
-
current_code_path = os.path.dirname(current_code_path)
|
| 662 |
-
copytree(
|
| 663 |
-
current_code_path, new_code_path, ignore=ignore_patterns("log", "logs", "wandb")
|
| 664 |
-
)
|
| 665 |
-
print("Done copying code.")
|
| 666 |
-
return 1
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
if __name__ == "__main__":
|
| 670 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/lp_train.py
DELETED
|
@@ -1,301 +0,0 @@
|
|
| 1 |
-
import json
|
| 2 |
-
import logging
|
| 3 |
-
import math
|
| 4 |
-
import os
|
| 5 |
-
import time
|
| 6 |
-
from contextlib import suppress
|
| 7 |
-
|
| 8 |
-
import numpy as np
|
| 9 |
-
import torch
|
| 10 |
-
import torch.nn.functional as F
|
| 11 |
-
|
| 12 |
-
try:
|
| 13 |
-
import wandb
|
| 14 |
-
except ImportError:
|
| 15 |
-
wandb = None
|
| 16 |
-
|
| 17 |
-
from open_clip import LPLoss, LPMetrics, lp_gather_features
|
| 18 |
-
from open_clip.utils import do_mixup, get_mix_lambda
|
| 19 |
-
from .distributed import is_master
|
| 20 |
-
from .zero_shot import zero_shot_eval
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
class AverageMeter(object):
|
| 24 |
-
"""Computes and stores the average and current value"""
|
| 25 |
-
|
| 26 |
-
def __init__(self):
|
| 27 |
-
self.reset()
|
| 28 |
-
|
| 29 |
-
def reset(self):
|
| 30 |
-
self.val = 0
|
| 31 |
-
self.avg = 0
|
| 32 |
-
self.sum = 0
|
| 33 |
-
self.count = 0
|
| 34 |
-
|
| 35 |
-
def update(self, val, n=1):
|
| 36 |
-
self.val = val
|
| 37 |
-
self.sum += val * n
|
| 38 |
-
self.count += n
|
| 39 |
-
self.avg = self.sum / self.count
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def unwrap_model(model):
|
| 43 |
-
if hasattr(model, "module"):
|
| 44 |
-
return model.module
|
| 45 |
-
else:
|
| 46 |
-
return model
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
def train_one_epoch(
|
| 50 |
-
model,
|
| 51 |
-
data,
|
| 52 |
-
epoch,
|
| 53 |
-
optimizer,
|
| 54 |
-
scaler,
|
| 55 |
-
scheduler,
|
| 56 |
-
args,
|
| 57 |
-
tb_writer=None,
|
| 58 |
-
extra_suffix="",
|
| 59 |
-
):
|
| 60 |
-
device = torch.device(args.device)
|
| 61 |
-
autocast = torch.cuda.amp.autocast if args.precision == "amp" else suppress
|
| 62 |
-
model.train()
|
| 63 |
-
loss = LPLoss(args.lp_loss)
|
| 64 |
-
|
| 65 |
-
dataloader, sampler = data["train"].dataloader, data["train"].sampler
|
| 66 |
-
if args.distributed and sampler is not None:
|
| 67 |
-
sampler.set_epoch(epoch)
|
| 68 |
-
num_batches_per_epoch = dataloader.num_batches
|
| 69 |
-
sample_digits = math.ceil(math.log(dataloader.num_samples + 1, 10))
|
| 70 |
-
|
| 71 |
-
# for toy dataset
|
| 72 |
-
if args.dataset_type == "toy":
|
| 73 |
-
dataloader.dataset.generate_queue()
|
| 74 |
-
|
| 75 |
-
loss_m = AverageMeter()
|
| 76 |
-
batch_time_m = AverageMeter()
|
| 77 |
-
data_time_m = AverageMeter()
|
| 78 |
-
end = time.time()
|
| 79 |
-
|
| 80 |
-
for i, batch in enumerate(dataloader):
|
| 81 |
-
step = num_batches_per_epoch * epoch + i
|
| 82 |
-
|
| 83 |
-
if isinstance(scheduler, dict):
|
| 84 |
-
for s in scheduler.values():
|
| 85 |
-
s(step)
|
| 86 |
-
else:
|
| 87 |
-
scheduler(step)
|
| 88 |
-
|
| 89 |
-
audio = batch # contains mel_spec, wavform, and longer list
|
| 90 |
-
class_label = batch["class_label"]
|
| 91 |
-
# audio = audio.to(device=device, non_blocking=True)
|
| 92 |
-
class_label = class_label.to(device=device, non_blocking=True)
|
| 93 |
-
|
| 94 |
-
if args.mixup:
|
| 95 |
-
# https://github.com/RetroCirce/HTS-Audio-Transformer/blob/main/utils.py#L146
|
| 96 |
-
mix_lambda = torch.from_numpy(
|
| 97 |
-
get_mix_lambda(0.5, len(audio["waveform"]))
|
| 98 |
-
).to(device)
|
| 99 |
-
class_label = do_mixup(class_label, mix_lambda)
|
| 100 |
-
else:
|
| 101 |
-
mix_lambda = None
|
| 102 |
-
|
| 103 |
-
data_time_m.update(time.time() - end)
|
| 104 |
-
if isinstance(optimizer, dict):
|
| 105 |
-
for o_ in optimizer.values():
|
| 106 |
-
o_.zero_grad()
|
| 107 |
-
else:
|
| 108 |
-
optimizer.zero_grad()
|
| 109 |
-
|
| 110 |
-
with autocast():
|
| 111 |
-
pred = model(audio, mix_lambda=mix_lambda, device=device)
|
| 112 |
-
total_loss = loss(pred, class_label)
|
| 113 |
-
|
| 114 |
-
if isinstance(optimizer, dict):
|
| 115 |
-
if scaler is not None:
|
| 116 |
-
scaler.scale(total_loss).backward()
|
| 117 |
-
for o_ in optimizer.values():
|
| 118 |
-
if args.horovod:
|
| 119 |
-
o_.synchronize()
|
| 120 |
-
scaler.unscale_(o_)
|
| 121 |
-
with o_.skip_synchronize():
|
| 122 |
-
scaler.step(o_)
|
| 123 |
-
else:
|
| 124 |
-
scaler.step(o_)
|
| 125 |
-
scaler.update()
|
| 126 |
-
else:
|
| 127 |
-
total_loss.backward()
|
| 128 |
-
for o_ in optimizer.values():
|
| 129 |
-
o_.step()
|
| 130 |
-
else:
|
| 131 |
-
if scaler is not None:
|
| 132 |
-
scaler.scale(total_loss).backward()
|
| 133 |
-
if args.horovod:
|
| 134 |
-
optimizer.synchronize()
|
| 135 |
-
scaler.unscale_(optimizer)
|
| 136 |
-
with optimizer.skip_synchronize():
|
| 137 |
-
scaler.step(optimizer)
|
| 138 |
-
else:
|
| 139 |
-
scaler.step(optimizer)
|
| 140 |
-
scaler.update()
|
| 141 |
-
else:
|
| 142 |
-
total_loss.backward()
|
| 143 |
-
optimizer.step()
|
| 144 |
-
|
| 145 |
-
# Note: we clamp to 4.6052 = ln(100), as in the original paper.
|
| 146 |
-
with torch.no_grad():
|
| 147 |
-
unwrap_model(model).clap_model.logit_scale_a.clamp_(0, math.log(100))
|
| 148 |
-
unwrap_model(model).clap_model.logit_scale_t.clamp_(0, math.log(100))
|
| 149 |
-
|
| 150 |
-
batch_time_m.update(time.time() - end)
|
| 151 |
-
end = time.time()
|
| 152 |
-
batch_count = i + 1
|
| 153 |
-
|
| 154 |
-
if is_master(args) and (i % 100 == 0 or batch_count == num_batches_per_epoch):
|
| 155 |
-
if isinstance(audio, dict):
|
| 156 |
-
batch_size = len(audio["waveform"])
|
| 157 |
-
else:
|
| 158 |
-
batch_size = len(audio)
|
| 159 |
-
num_samples = batch_count * batch_size * args.world_size
|
| 160 |
-
samples_per_epoch = dataloader.num_samples
|
| 161 |
-
percent_complete = 100.0 * batch_count / num_batches_per_epoch
|
| 162 |
-
|
| 163 |
-
# NOTE loss is coarsely sampled, just master node and per log update
|
| 164 |
-
loss_m.update(total_loss.item(), batch_size)
|
| 165 |
-
if isinstance(optimizer, dict):
|
| 166 |
-
logging.info(
|
| 167 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 168 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 169 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 170 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 171 |
-
f"LR: {[o_.param_groups[0]['lr'] for o_ in optimizer.values()]}"
|
| 172 |
-
)
|
| 173 |
-
log_data = {
|
| 174 |
-
"loss": loss_m.val,
|
| 175 |
-
"data_time": data_time_m.val,
|
| 176 |
-
"batch_time": batch_time_m.val,
|
| 177 |
-
"lr": [o_.param_groups[0]["lr"] for o_ in optimizer.values()],
|
| 178 |
-
}
|
| 179 |
-
else:
|
| 180 |
-
logging.info(
|
| 181 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 182 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 183 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 184 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 185 |
-
f"LR: {optimizer.param_groups[0]['lr']:5f} "
|
| 186 |
-
)
|
| 187 |
-
|
| 188 |
-
# Save train loss / etc. Using non avg meter values as loggers have their own smoothing
|
| 189 |
-
log_data = {
|
| 190 |
-
"loss": loss_m.val,
|
| 191 |
-
"data_time": data_time_m.val,
|
| 192 |
-
"batch_time": batch_time_m.val,
|
| 193 |
-
"lr": optimizer.param_groups[0]["lr"],
|
| 194 |
-
}
|
| 195 |
-
for name, val in log_data.items():
|
| 196 |
-
name = f"train{extra_suffix}/{name}"
|
| 197 |
-
if tb_writer is not None:
|
| 198 |
-
tb_writer.add_scalar(name, val, step)
|
| 199 |
-
if args.wandb:
|
| 200 |
-
assert wandb is not None, "Please install wandb."
|
| 201 |
-
wandb.log({name: val, "step": step})
|
| 202 |
-
|
| 203 |
-
# resetting batch / data time meters per log window
|
| 204 |
-
batch_time_m.reset()
|
| 205 |
-
data_time_m.reset()
|
| 206 |
-
# end for
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
def evaluate(model, data, epoch, args, tb_writer=None, extra_suffix=""):
|
| 210 |
-
metrics = {}
|
| 211 |
-
if not args.parallel_eval:
|
| 212 |
-
if not is_master(args):
|
| 213 |
-
return metrics
|
| 214 |
-
device = torch.device(args.device)
|
| 215 |
-
model.eval()
|
| 216 |
-
|
| 217 |
-
# CHANGE
|
| 218 |
-
# zero_shot_metrics = zero_shot_eval(model, data, epoch, args)
|
| 219 |
-
# metrics.update(zero_shot_metrics)
|
| 220 |
-
if is_master(args):
|
| 221 |
-
print("Evaluating...")
|
| 222 |
-
metric_names = args.lp_metrics.split(",")
|
| 223 |
-
eval_tool = LPMetrics(metric_names=metric_names)
|
| 224 |
-
|
| 225 |
-
autocast = torch.cuda.amp.autocast if args.precision == "amp" else suppress
|
| 226 |
-
if "val" in data and (
|
| 227 |
-
args.val_frequency
|
| 228 |
-
and ((epoch % args.val_frequency) == 0 or epoch == args.epochs)
|
| 229 |
-
):
|
| 230 |
-
if args.parallel_eval:
|
| 231 |
-
dataloader, sampler = data["val"].dataloader, data["val"].sampler
|
| 232 |
-
if args.distributed and sampler is not None:
|
| 233 |
-
sampler.set_epoch(epoch)
|
| 234 |
-
samples_per_val = dataloader.num_samples
|
| 235 |
-
else:
|
| 236 |
-
dataloader = data["val"].dataloader
|
| 237 |
-
num_samples = 0
|
| 238 |
-
samples_per_val = dataloader.num_samples
|
| 239 |
-
|
| 240 |
-
eval_info = {"pred": [], "target": []}
|
| 241 |
-
with torch.no_grad():
|
| 242 |
-
for i, batch in enumerate(dataloader):
|
| 243 |
-
audio = batch # contains mel_spec, wavform, and longer list
|
| 244 |
-
class_label = batch["class_label"]
|
| 245 |
-
|
| 246 |
-
# audio = audio.to(device=device, non_blocking=True)
|
| 247 |
-
class_label = class_label.to(device=device, non_blocking=True)
|
| 248 |
-
|
| 249 |
-
with autocast():
|
| 250 |
-
pred = model(audio, device=device)
|
| 251 |
-
if args.parallel_eval:
|
| 252 |
-
pred, class_label = lp_gather_features(
|
| 253 |
-
pred, class_label, args.world_size, args.horovod
|
| 254 |
-
)
|
| 255 |
-
eval_info["pred"].append(pred)
|
| 256 |
-
eval_info["target"].append(class_label)
|
| 257 |
-
|
| 258 |
-
num_samples += class_label.shape[0]
|
| 259 |
-
|
| 260 |
-
if (i % 100) == 0: # and i != 0:
|
| 261 |
-
logging.info(
|
| 262 |
-
f"Eval Epoch: {epoch} [{num_samples} / {samples_per_val}]"
|
| 263 |
-
)
|
| 264 |
-
|
| 265 |
-
if is_master(args):
|
| 266 |
-
eval_info["pred"] = torch.cat(eval_info["pred"], 0).cpu()
|
| 267 |
-
eval_info["target"] = torch.cat(eval_info["target"], 0).cpu()
|
| 268 |
-
metric_dict = eval_tool.evaluate_mertics(
|
| 269 |
-
eval_info["pred"], eval_info["target"]
|
| 270 |
-
)
|
| 271 |
-
metrics.update(metric_dict)
|
| 272 |
-
if "epoch" not in metrics.keys():
|
| 273 |
-
metrics.update({"epoch": epoch})
|
| 274 |
-
|
| 275 |
-
if is_master(args):
|
| 276 |
-
if not metrics:
|
| 277 |
-
return metrics
|
| 278 |
-
|
| 279 |
-
logging.info(
|
| 280 |
-
f"Eval Epoch: {epoch} "
|
| 281 |
-
+ "\n".join(
|
| 282 |
-
["\t".join([f"{m}: {round(metrics[m], 4):.4f}"]) for m in metrics]
|
| 283 |
-
)
|
| 284 |
-
)
|
| 285 |
-
if args.save_logs:
|
| 286 |
-
for name, val in metrics.items():
|
| 287 |
-
if tb_writer is not None:
|
| 288 |
-
tb_writer.add_scalar(f"val{extra_suffix}/{name}", val, epoch)
|
| 289 |
-
|
| 290 |
-
with open(os.path.join(args.checkpoint_path, "results.jsonl"), "a+") as f:
|
| 291 |
-
f.write(json.dumps(metrics))
|
| 292 |
-
f.write("\n")
|
| 293 |
-
|
| 294 |
-
if args.wandb:
|
| 295 |
-
assert wandb is not None, "Please install wandb."
|
| 296 |
-
for name, val in metrics.items():
|
| 297 |
-
wandb.log({f"val{extra_suffix}/{name}": val, "epoch": epoch})
|
| 298 |
-
|
| 299 |
-
return metrics
|
| 300 |
-
else:
|
| 301 |
-
return metrics
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/main.py
DELETED
|
@@ -1,596 +0,0 @@
|
|
| 1 |
-
from inspect import getargs
|
| 2 |
-
import logging
|
| 3 |
-
import os
|
| 4 |
-
import random
|
| 5 |
-
from datetime import datetime
|
| 6 |
-
import bisect
|
| 7 |
-
import copy
|
| 8 |
-
import numpy as np
|
| 9 |
-
import torch
|
| 10 |
-
import torch.backends.cudnn as cudnn
|
| 11 |
-
from torch import optim
|
| 12 |
-
from torch.cuda.amp import GradScaler
|
| 13 |
-
import faulthandler
|
| 14 |
-
import pathlib
|
| 15 |
-
|
| 16 |
-
try:
|
| 17 |
-
import wandb
|
| 18 |
-
except ImportError:
|
| 19 |
-
wandb = None
|
| 20 |
-
|
| 21 |
-
try:
|
| 22 |
-
import torch.utils.tensorboard as tensorboard
|
| 23 |
-
except ImportError:
|
| 24 |
-
tensorboard = None
|
| 25 |
-
|
| 26 |
-
try:
|
| 27 |
-
import horovod.torch as hvd
|
| 28 |
-
except ImportError:
|
| 29 |
-
hvd = None
|
| 30 |
-
|
| 31 |
-
from open_clip import create_model_and_transforms, trace_model, create_model
|
| 32 |
-
from training.data import get_data
|
| 33 |
-
from training.distributed import is_master, init_distributed_device, world_info_from_env
|
| 34 |
-
from training.logger import setup_logging
|
| 35 |
-
from training.params import parse_args
|
| 36 |
-
from training.scheduler import cosine_lr
|
| 37 |
-
from training.train import train_one_epoch, evaluate
|
| 38 |
-
from open_clip.utils import dataset_split, get_optimizer
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
def maintain_ckpts(args, startidx, all_idx_len):
|
| 42 |
-
for i in reversed(range(startidx, all_idx_len)):
|
| 43 |
-
if os.path.exists(os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt")):
|
| 44 |
-
os.rename(
|
| 45 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt"),
|
| 46 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i+1}.pt"),
|
| 47 |
-
)
|
| 48 |
-
if os.path.exists(
|
| 49 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{all_idx_len}.pt")
|
| 50 |
-
):
|
| 51 |
-
os.remove(os.path.join(args.checkpoint_path, f"epoch_top_{all_idx_len}.pt"))
|
| 52 |
-
return
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
def update_top_k_performance(
|
| 56 |
-
new_metrics_inputs, current_top_k_ckpt_metrics, args, ckpt, bignumbetter=True
|
| 57 |
-
):
|
| 58 |
-
"""
|
| 59 |
-
Record the top-k performance of the current epoch.
|
| 60 |
-
current_top_k_metrics is a dictionary of the form: {1: top_1_ckpt_measure, 2: top_2_ckpt_measure, ...}
|
| 61 |
-
"""
|
| 62 |
-
if isinstance(new_metrics_inputs, (list, tuple)):
|
| 63 |
-
new_metrics_inputs = np.mean(new_metrics_inputs)
|
| 64 |
-
return update_top_k_performance(
|
| 65 |
-
new_metrics_inputs,
|
| 66 |
-
current_top_k_ckpt_metrics,
|
| 67 |
-
args=args,
|
| 68 |
-
ckpt=ckpt,
|
| 69 |
-
bignumbetter=bignumbetter,
|
| 70 |
-
)
|
| 71 |
-
elif isinstance(new_metrics_inputs, dict):
|
| 72 |
-
new_metrics_inputs = np.mean(list(new_metrics_inputs.values()))
|
| 73 |
-
return update_top_k_performance(
|
| 74 |
-
new_metrics_inputs,
|
| 75 |
-
current_top_k_ckpt_metrics,
|
| 76 |
-
args=args,
|
| 77 |
-
ckpt=ckpt,
|
| 78 |
-
bignumbetter=bignumbetter,
|
| 79 |
-
)
|
| 80 |
-
elif isinstance(new_metrics_inputs, (float, int)):
|
| 81 |
-
update_flag = {k: False for k in current_top_k_ckpt_metrics.keys()}
|
| 82 |
-
sorted_keys = sorted(current_top_k_ckpt_metrics.keys())
|
| 83 |
-
sorted_values = sorted(
|
| 84 |
-
current_top_k_ckpt_metrics.values(), reverse=bignumbetter
|
| 85 |
-
)
|
| 86 |
-
sorted_values_ = copy.deepcopy(sorted_values)
|
| 87 |
-
sorted_values.append(new_metrics_inputs)
|
| 88 |
-
sorted_values = sorted(sorted_values, reverse=bignumbetter)
|
| 89 |
-
sorted_values = sorted_values[:-1]
|
| 90 |
-
|
| 91 |
-
if sorted_values == sorted_values_:
|
| 92 |
-
return current_top_k_ckpt_metrics, new_metrics_inputs
|
| 93 |
-
else:
|
| 94 |
-
for i in range(len(sorted_keys)):
|
| 95 |
-
if current_top_k_ckpt_metrics[sorted_keys[i]] != sorted_values[i]:
|
| 96 |
-
current_top_k_ckpt_metrics[sorted_keys[i]] = sorted_values[i]
|
| 97 |
-
update_flag[sorted_keys[i]] = True
|
| 98 |
-
for i in range(len(update_flag)):
|
| 99 |
-
if update_flag[i]:
|
| 100 |
-
maintain_ckpts(args, i, len(sorted_keys))
|
| 101 |
-
torch.save(
|
| 102 |
-
ckpt,
|
| 103 |
-
os.path.join(args.checkpoint_path, f"epoch_top_{i}.pt"),
|
| 104 |
-
)
|
| 105 |
-
break
|
| 106 |
-
return current_top_k_ckpt_metrics, new_metrics_inputs
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
# def updateifNone(a, b):
|
| 110 |
-
# a = b if None else a
|
| 111 |
-
# return a
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
def is_pretrained_params(n):
|
| 115 |
-
return (
|
| 116 |
-
n.startswith("transformer")
|
| 117 |
-
or n in ["positional_embedding", "text_projection"]
|
| 118 |
-
or n.startswith("token_embedding")
|
| 119 |
-
or n.startswith("ln_final")
|
| 120 |
-
or n.startswith("logit_scale_t")
|
| 121 |
-
)
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
def random_seed(seed=42, rank=0):
|
| 125 |
-
torch.manual_seed(seed + rank)
|
| 126 |
-
np.random.seed(seed + rank)
|
| 127 |
-
random.seed(seed + rank)
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
def main():
|
| 131 |
-
args = parse_args()
|
| 132 |
-
# sanitize model name for filesystem / uri use, easier if we don't use / in name as a rule?
|
| 133 |
-
args.amodel = args.amodel.replace("/", "-")
|
| 134 |
-
# download sizes.json file
|
| 135 |
-
|
| 136 |
-
# (yusong): the below two lines are for debug
|
| 137 |
-
# print("setting up faulthandler")
|
| 138 |
-
# faulthandler.register(10)
|
| 139 |
-
|
| 140 |
-
random.seed(args.seed)
|
| 141 |
-
torch.manual_seed(args.seed)
|
| 142 |
-
torch.cuda.manual_seed(args.seed)
|
| 143 |
-
torch.cuda.manual_seed_all(args.seed)
|
| 144 |
-
np.random.seed(args.seed)
|
| 145 |
-
if args.tmodel == "bert" or args.tmodel == "roberta" or args.tmodel == "bart":
|
| 146 |
-
assert (
|
| 147 |
-
args.pretrained == "" or args.pretrained is None
|
| 148 |
-
), "bert/roberta/bart text encoder does not support pretrained models."
|
| 149 |
-
|
| 150 |
-
# get the name of the experiments
|
| 151 |
-
if args.name is None:
|
| 152 |
-
args.name = "-".join(
|
| 153 |
-
[
|
| 154 |
-
datetime.now().strftime("%Y_%m_%d-%H_%M_%S"),
|
| 155 |
-
f"model_{args.amodel}",
|
| 156 |
-
f"lr_{args.lr}",
|
| 157 |
-
f"b_{args.batch_size}",
|
| 158 |
-
f"j_{args.workers}",
|
| 159 |
-
f"p_{args.precision}",
|
| 160 |
-
]
|
| 161 |
-
)
|
| 162 |
-
|
| 163 |
-
# discover initial world args early so we can log properly
|
| 164 |
-
args.distributed = False
|
| 165 |
-
args.local_rank, args.rank, args.world_size = world_info_from_env()
|
| 166 |
-
|
| 167 |
-
if args.remotedata and is_master(args):
|
| 168 |
-
for dataset_name in args.datasetnames:
|
| 169 |
-
for split in dataset_split[dataset_name]:
|
| 170 |
-
if not os.path.exists(f"./json_files/{dataset_name}/{split}"):
|
| 171 |
-
os.makedirs(f"./json_files/{dataset_name}/{split}")
|
| 172 |
-
os.system(
|
| 173 |
-
f"aws s3 cp s3://s-laion-audio/webdataset_tar/{dataset_name}/{split}/sizes.json ./json_files/{dataset_name}/{split}/sizes.json"
|
| 174 |
-
)
|
| 175 |
-
|
| 176 |
-
args.log_path = None
|
| 177 |
-
if is_master(args, local=args.log_local):
|
| 178 |
-
log_base_path = os.path.join(args.logs, args.name)
|
| 179 |
-
os.makedirs(log_base_path, exist_ok=True)
|
| 180 |
-
log_filename = f"out-{args.rank}" if args.log_local else "out.log"
|
| 181 |
-
args.log_path = os.path.join(log_base_path, log_filename)
|
| 182 |
-
if os.path.exists(args.log_path):
|
| 183 |
-
print(
|
| 184 |
-
"Error. Experiment already exists. Use --name {} to specify a new experiment."
|
| 185 |
-
)
|
| 186 |
-
return -1
|
| 187 |
-
|
| 188 |
-
# Set logger
|
| 189 |
-
args.log_level = logging.DEBUG if args.debug else logging.INFO
|
| 190 |
-
setup_logging(args.log_path, args.log_level)
|
| 191 |
-
|
| 192 |
-
# fully initialize distributed device environment
|
| 193 |
-
device = init_distributed_device(args)
|
| 194 |
-
|
| 195 |
-
args.wandb = "wandb" in args.report_to or "all" in args.report_to
|
| 196 |
-
args.tensorboard = "tensorboard" in args.report_to or "all" in args.report_to
|
| 197 |
-
if is_master(args):
|
| 198 |
-
args.tensorboard_path = (
|
| 199 |
-
os.path.join(args.logs, args.name, "tensorboard")
|
| 200 |
-
if args.tensorboard
|
| 201 |
-
else ""
|
| 202 |
-
)
|
| 203 |
-
args.checkpoint_path = os.path.join(args.logs, args.name, "checkpoints")
|
| 204 |
-
for dirname in [args.tensorboard_path, args.checkpoint_path]:
|
| 205 |
-
if dirname:
|
| 206 |
-
os.makedirs(dirname, exist_ok=True)
|
| 207 |
-
else:
|
| 208 |
-
args.tensorboard_path = ""
|
| 209 |
-
args.checkpoint_path = ""
|
| 210 |
-
|
| 211 |
-
if args.copy_codebase:
|
| 212 |
-
copy_codebase(args)
|
| 213 |
-
|
| 214 |
-
assert args.precision in ["amp", "fp16", "fp32"]
|
| 215 |
-
if args.precision == "fp16":
|
| 216 |
-
logging.warning(
|
| 217 |
-
"It is recommended to use AMP mixed-precision instead of FP16. "
|
| 218 |
-
"FP16 support needs further verification and tuning, especially for train."
|
| 219 |
-
)
|
| 220 |
-
|
| 221 |
-
if args.horovod:
|
| 222 |
-
logging.info(
|
| 223 |
-
f"Running in horovod mode with multiple processes / nodes. Device: {args.device}."
|
| 224 |
-
f"Process (global: {args.rank}, local {args.local_rank}), total {args.world_size}."
|
| 225 |
-
)
|
| 226 |
-
elif args.distributed:
|
| 227 |
-
logging.info(
|
| 228 |
-
f"Running in distributed mode with multiple processes. Device: {args.device}."
|
| 229 |
-
f"Process (global: {args.rank}, local {args.local_rank}), total {args.world_size}."
|
| 230 |
-
)
|
| 231 |
-
else:
|
| 232 |
-
logging.info(f"Running with a single process. Device {args.device}.")
|
| 233 |
-
|
| 234 |
-
logging.info(f"openai cache dir: {os.path.expanduser(args.openai_model_cache_dir)}")
|
| 235 |
-
|
| 236 |
-
model, model_cfg = create_model(
|
| 237 |
-
args.amodel,
|
| 238 |
-
args.tmodel,
|
| 239 |
-
args.pretrained,
|
| 240 |
-
precision=args.precision,
|
| 241 |
-
device=device,
|
| 242 |
-
jit=args.torchscript,
|
| 243 |
-
force_quick_gelu=args.force_quick_gelu,
|
| 244 |
-
openai_model_cache_dir=os.path.expanduser(args.openai_model_cache_dir),
|
| 245 |
-
skip_params=True,
|
| 246 |
-
pretrained_audio=args.pretrained_audio,
|
| 247 |
-
pretrained_text=args.pretrained_text,
|
| 248 |
-
enable_fusion=args.enable_fusion,
|
| 249 |
-
fusion_type=args.fusion_type,
|
| 250 |
-
)
|
| 251 |
-
|
| 252 |
-
if args.horovod:
|
| 253 |
-
with torch.no_grad():
|
| 254 |
-
for param in model.parameters():
|
| 255 |
-
param.set_(param.contiguous())
|
| 256 |
-
|
| 257 |
-
if args.trace:
|
| 258 |
-
model = trace_model(model, batch_size=args.batch_size, device=device)
|
| 259 |
-
|
| 260 |
-
if is_master(args):
|
| 261 |
-
logging.info("Model:")
|
| 262 |
-
logging.info(f"{str(model)}")
|
| 263 |
-
logging.info("Params:")
|
| 264 |
-
params_file = os.path.join(args.logs, args.name, "params.txt")
|
| 265 |
-
with open(params_file, "w") as f:
|
| 266 |
-
for name in sorted(vars(args)):
|
| 267 |
-
val = getattr(args, name)
|
| 268 |
-
logging.info(f" {name}: {val}")
|
| 269 |
-
f.write(f"{name}: {val}\n")
|
| 270 |
-
|
| 271 |
-
if args.distributed and not args.horovod:
|
| 272 |
-
if args.use_bn_sync:
|
| 273 |
-
model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
|
| 274 |
-
ddp_args = {}
|
| 275 |
-
if args.ddp_static_graph:
|
| 276 |
-
# this doesn't exist in older PyTorch, arg only added if enabled
|
| 277 |
-
ddp_args["static_graph"] = True
|
| 278 |
-
model = torch.nn.parallel.DistributedDataParallel(
|
| 279 |
-
model, device_ids=[device], find_unused_parameters=True, **ddp_args
|
| 280 |
-
)
|
| 281 |
-
|
| 282 |
-
data = get_data(args, model_cfg)
|
| 283 |
-
assert len(data), "At least one train or eval dataset must be specified."
|
| 284 |
-
if args.trace:
|
| 285 |
-
assert "train" not in data, "Cannot train with traced model"
|
| 286 |
-
|
| 287 |
-
exclude = (
|
| 288 |
-
lambda n, p: p.ndim < 2
|
| 289 |
-
or "bn" in n
|
| 290 |
-
or "ln" in n
|
| 291 |
-
or "bias" in n
|
| 292 |
-
or "logit_scale" in n
|
| 293 |
-
)
|
| 294 |
-
include = lambda n, p: not exclude(n, p)
|
| 295 |
-
|
| 296 |
-
named_parameters = list(model.named_parameters())
|
| 297 |
-
|
| 298 |
-
# freeze text encoder
|
| 299 |
-
text_freeze_parameters = [p for n, p in named_parameters if "text_branch" in n]
|
| 300 |
-
|
| 301 |
-
if args.freeze_text:
|
| 302 |
-
print("Freeze Text!!!!")
|
| 303 |
-
for k in text_freeze_parameters:
|
| 304 |
-
k.requires_grad = False
|
| 305 |
-
|
| 306 |
-
gain_or_bias_params = [
|
| 307 |
-
p for n, p in named_parameters if exclude(n, p) and p.requires_grad
|
| 308 |
-
]
|
| 309 |
-
rest_params = [p for n, p in named_parameters if include(n, p) and p.requires_grad]
|
| 310 |
-
|
| 311 |
-
# set wd-related params to 0 if use adam optimizer
|
| 312 |
-
if args.optimizer == "adam":
|
| 313 |
-
args.wd = 0
|
| 314 |
-
args.wd_pretrained = 0
|
| 315 |
-
args.wd_new = 0
|
| 316 |
-
|
| 317 |
-
if args.train_data is None:
|
| 318 |
-
optimizer = None
|
| 319 |
-
scheduler = None
|
| 320 |
-
else:
|
| 321 |
-
total_steps = data["train"].dataloader.num_batches * args.epochs
|
| 322 |
-
|
| 323 |
-
if args.split_opt:
|
| 324 |
-
for x in ["lr", "beta1", "beta2", "eps", "wd"]:
|
| 325 |
-
for y in ["_new", "_pretrained"]:
|
| 326 |
-
if getattr(args, x + y) is None:
|
| 327 |
-
setattr(args, x + y, getattr(args, x))
|
| 328 |
-
|
| 329 |
-
gain_or_bias_pretrained_params = [
|
| 330 |
-
p
|
| 331 |
-
for n, p in named_parameters
|
| 332 |
-
if (exclude(n, p) and p.requires_grad) and is_pretrained_params(n)
|
| 333 |
-
]
|
| 334 |
-
rest_pretrained_params = [
|
| 335 |
-
p
|
| 336 |
-
for n, p in named_parameters
|
| 337 |
-
if (include(n, p) and p.requires_grad) and is_pretrained_params(n)
|
| 338 |
-
]
|
| 339 |
-
gain_or_bias_new_params = [
|
| 340 |
-
p
|
| 341 |
-
for n, p in named_parameters
|
| 342 |
-
if (exclude(n, p) and p.requires_grad) and (not is_pretrained_params(n))
|
| 343 |
-
]
|
| 344 |
-
rest_new_params = [
|
| 345 |
-
p
|
| 346 |
-
for n, p in named_parameters
|
| 347 |
-
if (include(n, p) and p.requires_grad) and (not is_pretrained_params(n))
|
| 348 |
-
]
|
| 349 |
-
pretrained_params_optimizer = get_optimizer(
|
| 350 |
-
[
|
| 351 |
-
{"params": gain_or_bias_pretrained_params, "weight_decay": 0.0},
|
| 352 |
-
{
|
| 353 |
-
"params": rest_pretrained_params,
|
| 354 |
-
"weight_decay": args.wd_pretrained,
|
| 355 |
-
},
|
| 356 |
-
],
|
| 357 |
-
lr=args.lr_pretrained,
|
| 358 |
-
betas=(args.beta1_pretrained, args.beta2_pretrained),
|
| 359 |
-
eps=args.eps_pretrained,
|
| 360 |
-
momentum=args.momentum_pretrained,
|
| 361 |
-
optimizer_name=args.optimizer,
|
| 362 |
-
)
|
| 363 |
-
pretrained_params_scheduler = cosine_lr(
|
| 364 |
-
pretrained_params_optimizer,
|
| 365 |
-
args.lr_pretrained,
|
| 366 |
-
args.warmup,
|
| 367 |
-
total_steps,
|
| 368 |
-
)
|
| 369 |
-
new_params_optimizer = get_optimizer(
|
| 370 |
-
[
|
| 371 |
-
{"params": gain_or_bias_new_params, "weight_decay": 0.0},
|
| 372 |
-
{"params": rest_new_params, "weight_decay": args.wd_new},
|
| 373 |
-
],
|
| 374 |
-
lr=args.lr_new,
|
| 375 |
-
betas=(args.beta1_new, args.beta2_new),
|
| 376 |
-
eps=args.eps_new,
|
| 377 |
-
momentum=args.momentum_new,
|
| 378 |
-
optimizer_name=args.optimizer,
|
| 379 |
-
)
|
| 380 |
-
|
| 381 |
-
new_params_scheduler = cosine_lr(
|
| 382 |
-
new_params_optimizer, args.lr_new, args.warmup, total_steps
|
| 383 |
-
)
|
| 384 |
-
|
| 385 |
-
optimizer = {
|
| 386 |
-
"pretrained": pretrained_params_optimizer,
|
| 387 |
-
"new": new_params_optimizer,
|
| 388 |
-
}
|
| 389 |
-
scheduler = {
|
| 390 |
-
"pretrained": pretrained_params_scheduler,
|
| 391 |
-
"new": new_params_scheduler,
|
| 392 |
-
}
|
| 393 |
-
|
| 394 |
-
if args.horovod:
|
| 395 |
-
pretrained_params_optimizer = hvd.DistributedOptimizer(
|
| 396 |
-
pretrained_params_optimizer,
|
| 397 |
-
named_parameters=model.named_parameters(),
|
| 398 |
-
)
|
| 399 |
-
new_params_optimizer = hvd.DistributedOptimizer(
|
| 400 |
-
new_params_optimizer, named_parameters=model.named_parameters()
|
| 401 |
-
)
|
| 402 |
-
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
|
| 403 |
-
hvd.broadcast_optimizer_state(pretrained_params_optimizer, root_rank=0)
|
| 404 |
-
hvd.broadcast_optimizer_state(new_params_optimizer, root_rank=0)
|
| 405 |
-
else:
|
| 406 |
-
optimizer = get_optimizer(
|
| 407 |
-
[
|
| 408 |
-
{"params": gain_or_bias_params, "weight_decay": 0.0},
|
| 409 |
-
{"params": rest_params, "weight_decay": args.wd},
|
| 410 |
-
],
|
| 411 |
-
lr=args.lr,
|
| 412 |
-
betas=(args.beta1, args.beta2),
|
| 413 |
-
eps=args.eps,
|
| 414 |
-
momentum=args.momentum,
|
| 415 |
-
optimizer_name=args.optimizer,
|
| 416 |
-
)
|
| 417 |
-
|
| 418 |
-
scheduler = cosine_lr(optimizer, args.lr, args.warmup, total_steps)
|
| 419 |
-
|
| 420 |
-
if args.horovod:
|
| 421 |
-
optimizer = hvd.DistributedOptimizer(
|
| 422 |
-
optimizer, named_parameters=model.named_parameters()
|
| 423 |
-
)
|
| 424 |
-
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
|
| 425 |
-
hvd.broadcast_optimizer_state(optimizer, root_rank=0)
|
| 426 |
-
|
| 427 |
-
scaler = GradScaler() if args.precision == "amp" else None
|
| 428 |
-
|
| 429 |
-
# optionally resume from a checkpoint
|
| 430 |
-
start_epoch = 0
|
| 431 |
-
if args.resume is not None:
|
| 432 |
-
if os.path.isfile(args.resume):
|
| 433 |
-
checkpoint = torch.load(args.resume, map_location=device)
|
| 434 |
-
if "epoch" in checkpoint:
|
| 435 |
-
# resuming a train checkpoint w/ epoch and optimizer state
|
| 436 |
-
start_epoch = checkpoint["epoch"]
|
| 437 |
-
sd = checkpoint["state_dict"]
|
| 438 |
-
if not args.distributed and next(iter(sd.items()))[0].startswith(
|
| 439 |
-
"module"
|
| 440 |
-
):
|
| 441 |
-
sd = {k[len("module.") :]: v for k, v in sd.items()}
|
| 442 |
-
model.load_state_dict(sd)
|
| 443 |
-
if args.split_opt:
|
| 444 |
-
if optimizer is not None:
|
| 445 |
-
for k, o_ in optimizer.items():
|
| 446 |
-
o_.load_state_dict(checkpoint[k + "_" + "optimizer"])
|
| 447 |
-
if optimizer is not None:
|
| 448 |
-
optimizer.load_state_dict(checkpoint["optimizer"])
|
| 449 |
-
if scaler is not None and "scaler" in checkpoint:
|
| 450 |
-
scaler.load_state_dict(checkpoint["scaler"])
|
| 451 |
-
logging.info(
|
| 452 |
-
f"=> resuming checkpoint '{args.resume}' (epoch {start_epoch})"
|
| 453 |
-
)
|
| 454 |
-
else:
|
| 455 |
-
# loading a bare (model only) checkpoint for fine-tune or evaluation
|
| 456 |
-
model.load_state_dict(checkpoint)
|
| 457 |
-
logging.info(
|
| 458 |
-
f"=> loaded checkpoint '{args.resume}' (epoch {start_epoch})"
|
| 459 |
-
)
|
| 460 |
-
if args.freeze_text:
|
| 461 |
-
print("Freeze Text!!!!")
|
| 462 |
-
for k in text_freeze_parameters:
|
| 463 |
-
k.requires_grad = False
|
| 464 |
-
else:
|
| 465 |
-
logging.info("=> no checkpoint found at '{}'".format(args.resume))
|
| 466 |
-
|
| 467 |
-
cudnn.benchmark = True
|
| 468 |
-
cudnn.deterministic = False
|
| 469 |
-
|
| 470 |
-
# determine if this worker should save logs and checkpoints. only do so if it is rank == 0
|
| 471 |
-
args.save_logs = args.logs and args.logs.lower() != "none" and is_master(args)
|
| 472 |
-
writer = None
|
| 473 |
-
if args.save_logs and args.tensorboard:
|
| 474 |
-
assert tensorboard is not None, "Please install tensorboard."
|
| 475 |
-
writer = tensorboard.SummaryWriter(args.tensorboard_path)
|
| 476 |
-
|
| 477 |
-
if args.wandb and is_master(args):
|
| 478 |
-
assert wandb is not None, "Please install wandb."
|
| 479 |
-
logging.debug("Starting wandb.")
|
| 480 |
-
args.train_sz = data["train"].dataloader.num_samples
|
| 481 |
-
if args.val_data is not None:
|
| 482 |
-
args.val_sz = data["val"].dataloader.num_samples
|
| 483 |
-
# you will have to configure this for your project!
|
| 484 |
-
wandb.init(
|
| 485 |
-
project="clap",
|
| 486 |
-
notes=args.wandb_notes,
|
| 487 |
-
name=args.wandb_notes,
|
| 488 |
-
tags=[],
|
| 489 |
-
config=vars(args),
|
| 490 |
-
)
|
| 491 |
-
if args.debug:
|
| 492 |
-
wandb.watch(model, log="all")
|
| 493 |
-
wandb.save(params_file)
|
| 494 |
-
logging.debug("Finished loading wandb.")
|
| 495 |
-
|
| 496 |
-
if "train" not in data:
|
| 497 |
-
evaluate(model, data, start_epoch, args, writer)
|
| 498 |
-
return
|
| 499 |
-
elif start_epoch == 0 and "val" in data and not args.no_eval:
|
| 500 |
-
evaluate(model, data, 0, args, writer)
|
| 501 |
-
# print(f'rank {args.rank}, Start First Evaluation')# (yusong): for debug
|
| 502 |
-
if args.save_top_performance:
|
| 503 |
-
current_top_k_ckpt_metrics = {
|
| 504 |
-
i: 0 for i in range(args.save_top_performance)
|
| 505 |
-
} # initialize the top-k metric for ckpts to 0
|
| 506 |
-
|
| 507 |
-
# print(f'rank {args.rank}, Start Training') # (yusong): for debug
|
| 508 |
-
for epoch in range(start_epoch, args.epochs):
|
| 509 |
-
# freeze the text param after (include) args.freeze_text_after, this is -1 by default
|
| 510 |
-
if epoch == args.freeze_text_after:
|
| 511 |
-
print("Text pretrained parameters are freezed since this epoch.")
|
| 512 |
-
for k in text_freeze_parameters:
|
| 513 |
-
k.requires_grad = False
|
| 514 |
-
if is_master(args):
|
| 515 |
-
logging.info(f"Start epoch {epoch}")
|
| 516 |
-
|
| 517 |
-
train_one_epoch(model, data, epoch, optimizer, scaler, scheduler, args, writer)
|
| 518 |
-
completed_epoch = epoch + 1
|
| 519 |
-
|
| 520 |
-
if (
|
| 521 |
-
any(v in data for v in ("val", "imagenet-val", "imagenet-v2"))
|
| 522 |
-
and not args.no_eval
|
| 523 |
-
):
|
| 524 |
-
metrics = evaluate(model, data, completed_epoch, args, writer)
|
| 525 |
-
if args.save_top_performance:
|
| 526 |
-
top_k_dataset = args.top_k_checkpoint_select_dataset
|
| 527 |
-
top_k_metric = args.top_k_checkpoint_select_metric
|
| 528 |
-
filtered_metrics = [
|
| 529 |
-
v
|
| 530 |
-
for k, v in metrics.items()
|
| 531 |
-
if top_k_metric in k and top_k_dataset in k
|
| 532 |
-
] # check all R@10 metrics (all dataset) and use it to update the ckpt
|
| 533 |
-
# Saving checkpoints.
|
| 534 |
-
if args.save_logs:
|
| 535 |
-
if args.split_opt:
|
| 536 |
-
opt_dict = {
|
| 537 |
-
k + "_" + "optimizer": v.state_dict() for k, v in optimizer.items()
|
| 538 |
-
}
|
| 539 |
-
else:
|
| 540 |
-
opt_dict = {"optimizer": optimizer.state_dict()}
|
| 541 |
-
checkpoint_dict = {
|
| 542 |
-
"epoch": completed_epoch,
|
| 543 |
-
"name": args.name,
|
| 544 |
-
"state_dict": model.state_dict(),
|
| 545 |
-
}
|
| 546 |
-
checkpoint_dict.update(opt_dict)
|
| 547 |
-
if scaler is not None:
|
| 548 |
-
checkpoint_dict["scaler"] = scaler.state_dict()
|
| 549 |
-
|
| 550 |
-
if completed_epoch == args.epochs or (
|
| 551 |
-
args.save_frequency > 0 and (completed_epoch % args.save_frequency) == 0
|
| 552 |
-
):
|
| 553 |
-
torch.save(
|
| 554 |
-
checkpoint_dict,
|
| 555 |
-
os.path.join(args.checkpoint_path, f"epoch_{completed_epoch}.pt"),
|
| 556 |
-
)
|
| 557 |
-
if args.save_most_recent:
|
| 558 |
-
torch.save(
|
| 559 |
-
checkpoint_dict,
|
| 560 |
-
os.path.join(args.checkpoint_path, f"epoch_latest.pt"),
|
| 561 |
-
)
|
| 562 |
-
if args.save_top_performance and not args.no_eval:
|
| 563 |
-
update_top_k_performance(
|
| 564 |
-
filtered_metrics,
|
| 565 |
-
current_top_k_ckpt_metrics,
|
| 566 |
-
args,
|
| 567 |
-
checkpoint_dict,
|
| 568 |
-
bignumbetter=True,
|
| 569 |
-
)
|
| 570 |
-
|
| 571 |
-
if args.wandb and is_master(args):
|
| 572 |
-
wandb.finish()
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
def copy_codebase(args):
|
| 576 |
-
from shutil import copytree, ignore_patterns
|
| 577 |
-
|
| 578 |
-
new_code_path = os.path.join(args.logs, args.name, "code")
|
| 579 |
-
if os.path.exists(new_code_path):
|
| 580 |
-
print(
|
| 581 |
-
f"Error. Experiment already exists at {new_code_path}. Use --name to specify a new experiment."
|
| 582 |
-
)
|
| 583 |
-
return -1
|
| 584 |
-
print(f"Copying codebase to {new_code_path}")
|
| 585 |
-
current_code_path = os.path.realpath(__file__)
|
| 586 |
-
for _ in range(3):
|
| 587 |
-
current_code_path = os.path.dirname(current_code_path)
|
| 588 |
-
copytree(
|
| 589 |
-
current_code_path, new_code_path, ignore=ignore_patterns("log", "logs", "wandb")
|
| 590 |
-
)
|
| 591 |
-
print("Done copying code.")
|
| 592 |
-
return 1
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
if __name__ == "__main__":
|
| 596 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/params.py
DELETED
|
@@ -1,563 +0,0 @@
|
|
| 1 |
-
import argparse
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
def get_default_params(model_name):
|
| 5 |
-
# Params from paper (https://arxiv.org/pdf/2103.00020.pdf)
|
| 6 |
-
model_name = model_name.lower()
|
| 7 |
-
if "vit" in model_name:
|
| 8 |
-
return {"lr": 5.0e-4, "beta1": 0.9, "beta2": 0.98, "eps": 1.0e-6}
|
| 9 |
-
else:
|
| 10 |
-
return {"lr": 5.0e-4, "beta1": 0.9, "beta2": 0.999, "eps": 1.0e-8}
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def parse_args():
|
| 14 |
-
parser = argparse.ArgumentParser()
|
| 15 |
-
parser.add_argument(
|
| 16 |
-
"--train-data",
|
| 17 |
-
type=str,
|
| 18 |
-
default=None,
|
| 19 |
-
help="Path to h5 filewith training data",
|
| 20 |
-
)
|
| 21 |
-
parser.add_argument(
|
| 22 |
-
"--val-data",
|
| 23 |
-
type=str,
|
| 24 |
-
default=None,
|
| 25 |
-
help="Path to h5 file with validation data",
|
| 26 |
-
)
|
| 27 |
-
parser.add_argument(
|
| 28 |
-
"--freeze-text",
|
| 29 |
-
default=False,
|
| 30 |
-
action="store_true",
|
| 31 |
-
help="if you need to freeze the text encoder, make this True",
|
| 32 |
-
)
|
| 33 |
-
parser.add_argument(
|
| 34 |
-
"--freeze-text-after",
|
| 35 |
-
type=int,
|
| 36 |
-
default=-1,
|
| 37 |
-
help="if you need to freeze the text encoder after (include) epoch x, set this param to x. Set -1 to disable it",
|
| 38 |
-
)
|
| 39 |
-
parser.add_argument(
|
| 40 |
-
"--train-ipc",
|
| 41 |
-
type=str,
|
| 42 |
-
default=None,
|
| 43 |
-
help="Path to npy file of the number of instance per class in training data",
|
| 44 |
-
)
|
| 45 |
-
parser.add_argument(
|
| 46 |
-
"--val-ipc",
|
| 47 |
-
type=str,
|
| 48 |
-
default=None,
|
| 49 |
-
help="Path to npy file of the number of instance per class in validation data",
|
| 50 |
-
)
|
| 51 |
-
parser.add_argument(
|
| 52 |
-
"--train-num-samples",
|
| 53 |
-
type=int,
|
| 54 |
-
default=None,
|
| 55 |
-
help="Number of samples in dataset. Required for webdataset if not available in info file.",
|
| 56 |
-
)
|
| 57 |
-
parser.add_argument(
|
| 58 |
-
"--val-num-samples",
|
| 59 |
-
type=int,
|
| 60 |
-
default=None,
|
| 61 |
-
help="Number of samples in dataset. Useful for webdataset if not available in info file.",
|
| 62 |
-
)
|
| 63 |
-
parser.add_argument(
|
| 64 |
-
"--dataset-type",
|
| 65 |
-
choices=["webdataset", "csv", "auto", "toy"],
|
| 66 |
-
default="auto",
|
| 67 |
-
help="Which type of dataset to process.",
|
| 68 |
-
)
|
| 69 |
-
parser.add_argument(
|
| 70 |
-
"--csv-separator",
|
| 71 |
-
type=str,
|
| 72 |
-
default="\t",
|
| 73 |
-
help="For csv-like datasets, which separator to use.",
|
| 74 |
-
)
|
| 75 |
-
parser.add_argument(
|
| 76 |
-
"--csv-img-key",
|
| 77 |
-
type=str,
|
| 78 |
-
default="filepath",
|
| 79 |
-
help="For csv-like datasets, the name of the key for the image paths.",
|
| 80 |
-
)
|
| 81 |
-
parser.add_argument(
|
| 82 |
-
"--csv-caption-key",
|
| 83 |
-
type=str,
|
| 84 |
-
default="title",
|
| 85 |
-
help="For csv-like datasets, the name of the key for the captions.",
|
| 86 |
-
)
|
| 87 |
-
parser.add_argument(
|
| 88 |
-
"--imagenet-val",
|
| 89 |
-
type=str,
|
| 90 |
-
default=None,
|
| 91 |
-
help="Path to imagenet val set for conducting zero shot evaluation.",
|
| 92 |
-
)
|
| 93 |
-
parser.add_argument(
|
| 94 |
-
"--imagenet-v2",
|
| 95 |
-
type=str,
|
| 96 |
-
default=None,
|
| 97 |
-
help="Path to imagenet v2 for conducting zero shot evaluation.",
|
| 98 |
-
)
|
| 99 |
-
parser.add_argument(
|
| 100 |
-
"--datasetnames",
|
| 101 |
-
nargs="+",
|
| 102 |
-
default=None,
|
| 103 |
-
help="If loading webdataset, spedify the dataset names to load. Can be some of these: Clotho, audioset, audiocaps, BBCSoundEffects",
|
| 104 |
-
)
|
| 105 |
-
parser.add_argument(
|
| 106 |
-
"--full-train-dataset",
|
| 107 |
-
nargs="+",
|
| 108 |
-
default=None,
|
| 109 |
-
help="Which dataset will be trained with all the subsets. (train+test)",
|
| 110 |
-
)
|
| 111 |
-
parser.add_argument(
|
| 112 |
-
"--exclude-eval-dataset",
|
| 113 |
-
nargs="+",
|
| 114 |
-
default=None,
|
| 115 |
-
help="Which dataset will be excluded with evaluation",
|
| 116 |
-
)
|
| 117 |
-
parser.add_argument(
|
| 118 |
-
"--datasetinfos",
|
| 119 |
-
nargs="+",
|
| 120 |
-
default=None,
|
| 121 |
-
help="If loading webdataset, spedify the dataset types to load. Can be some of these: train, test, valid, unbalanced_train, balanced_train, eval",
|
| 122 |
-
)
|
| 123 |
-
parser.add_argument(
|
| 124 |
-
"--dataset-proportion",
|
| 125 |
-
type=float,
|
| 126 |
-
default=1.0,
|
| 127 |
-
help="How much proportion of dataset we want to train.",
|
| 128 |
-
)
|
| 129 |
-
parser.add_argument(
|
| 130 |
-
"--remotedata",
|
| 131 |
-
default=False,
|
| 132 |
-
action="store_true",
|
| 133 |
-
help="if the dataset is remote, set this flag",
|
| 134 |
-
)
|
| 135 |
-
parser.add_argument(
|
| 136 |
-
"--class-label-path",
|
| 137 |
-
type=str,
|
| 138 |
-
default=None,
|
| 139 |
-
help="The path of the class label pickle or csv.",
|
| 140 |
-
)
|
| 141 |
-
parser.add_argument(
|
| 142 |
-
"--datasetpath",
|
| 143 |
-
type=str,
|
| 144 |
-
default="/mnt/audio_clip/webdataset_tar",
|
| 145 |
-
help="The path to the dataset",
|
| 146 |
-
)
|
| 147 |
-
parser.add_argument(
|
| 148 |
-
"--logs",
|
| 149 |
-
type=str,
|
| 150 |
-
default="./logs/",
|
| 151 |
-
help="Where to store tensorboard logs. Use None to avoid storing logs.",
|
| 152 |
-
)
|
| 153 |
-
parser.add_argument(
|
| 154 |
-
"--log-local",
|
| 155 |
-
action="store_true",
|
| 156 |
-
default=False,
|
| 157 |
-
help="log files on local master, otherwise global master only.",
|
| 158 |
-
)
|
| 159 |
-
parser.add_argument(
|
| 160 |
-
"--name",
|
| 161 |
-
type=str,
|
| 162 |
-
default=None,
|
| 163 |
-
help="Optional identifier for the experiment when storing logs. Otherwise use current time.",
|
| 164 |
-
)
|
| 165 |
-
parser.add_argument(
|
| 166 |
-
"--workers", type=int, default=1, help="Number of workers per GPU."
|
| 167 |
-
)
|
| 168 |
-
parser.add_argument(
|
| 169 |
-
"--batch-size", type=int, default=64, help="Batch size per GPU."
|
| 170 |
-
)
|
| 171 |
-
parser.add_argument(
|
| 172 |
-
"--epochs", type=int, default=32, help="Number of epochs to train for."
|
| 173 |
-
)
|
| 174 |
-
parser.add_argument("--lr", type=float, default=None, help="Learning rate.")
|
| 175 |
-
parser.add_argument("--beta1", type=float, default=None, help="Adam beta 1.")
|
| 176 |
-
parser.add_argument("--beta2", type=float, default=None, help="Adam beta 2.")
|
| 177 |
-
parser.add_argument("--eps", type=float, default=None, help="Adam epsilon.")
|
| 178 |
-
parser.add_argument("--momentum", type=float, default=None, help="SGD epsilon.")
|
| 179 |
-
parser.add_argument("--wd", type=float, default=0.2, help="Weight decay.")
|
| 180 |
-
|
| 181 |
-
parser.add_argument(
|
| 182 |
-
"--split-opt",
|
| 183 |
-
action="store_true",
|
| 184 |
-
default=False,
|
| 185 |
-
help="Use this flag to skip the learning rate decay.",
|
| 186 |
-
)
|
| 187 |
-
parser.add_argument(
|
| 188 |
-
"--lr-pretrained", type=float, default=None, help="Learning rate for text."
|
| 189 |
-
)
|
| 190 |
-
parser.add_argument(
|
| 191 |
-
"--beta1-pretrained", type=float, default=None, help="Adam beta 1 for text."
|
| 192 |
-
)
|
| 193 |
-
parser.add_argument(
|
| 194 |
-
"--beta2-pretrained", type=float, default=None, help="Adam beta 2 for text."
|
| 195 |
-
)
|
| 196 |
-
parser.add_argument(
|
| 197 |
-
"--eps-pretrained", type=float, default=None, help="Adam epsilon for text."
|
| 198 |
-
)
|
| 199 |
-
parser.add_argument(
|
| 200 |
-
"--wd-pretrained", type=float, default=0.2, help="Weight decay for text."
|
| 201 |
-
)
|
| 202 |
-
parser.add_argument(
|
| 203 |
-
"--momentum-pretrained", type=float, default=0.9, help="Momentum for text."
|
| 204 |
-
)
|
| 205 |
-
parser.add_argument(
|
| 206 |
-
"--lr-new", type=float, default=None, help="Learning rate for audio."
|
| 207 |
-
)
|
| 208 |
-
parser.add_argument(
|
| 209 |
-
"--beta1-new", type=float, default=None, help="Adam beta 1 for audio."
|
| 210 |
-
)
|
| 211 |
-
parser.add_argument(
|
| 212 |
-
"--beta2-new", type=float, default=None, help="Adam beta 2 for audio."
|
| 213 |
-
)
|
| 214 |
-
parser.add_argument(
|
| 215 |
-
"--eps-new", type=float, default=None, help="Adam epsilon for audio."
|
| 216 |
-
)
|
| 217 |
-
parser.add_argument(
|
| 218 |
-
"--wd-new", type=float, default=0.2, help="Weight decay for audio."
|
| 219 |
-
)
|
| 220 |
-
parser.add_argument(
|
| 221 |
-
"--momentum-new", type=float, default=0.9, help="Momentum for audio."
|
| 222 |
-
)
|
| 223 |
-
parser.add_argument(
|
| 224 |
-
"--warmup", type=int, default=10000, help="Number of steps to warmup for."
|
| 225 |
-
)
|
| 226 |
-
parser.add_argument(
|
| 227 |
-
"--use-bn-sync",
|
| 228 |
-
default=False,
|
| 229 |
-
action="store_true",
|
| 230 |
-
help="Whether to use batch norm sync.",
|
| 231 |
-
)
|
| 232 |
-
parser.add_argument(
|
| 233 |
-
"--skip-scheduler",
|
| 234 |
-
action="store_true",
|
| 235 |
-
default=False,
|
| 236 |
-
help="Use this flag to skip the learning rate decay.",
|
| 237 |
-
)
|
| 238 |
-
parser.add_argument(
|
| 239 |
-
"--save-frequency", type=int, default=1, help="How often to save checkpoints."
|
| 240 |
-
)
|
| 241 |
-
parser.add_argument(
|
| 242 |
-
"--save-top-performance",
|
| 243 |
-
type=int,
|
| 244 |
-
default=0,
|
| 245 |
-
help="Save the top x performance weights if the value >0",
|
| 246 |
-
)
|
| 247 |
-
parser.add_argument(
|
| 248 |
-
"--save-most-recent",
|
| 249 |
-
action="store_true",
|
| 250 |
-
default=False,
|
| 251 |
-
help="Always save the most recent model trained to epoch_latest.pt.",
|
| 252 |
-
)
|
| 253 |
-
parser.add_argument(
|
| 254 |
-
"--zeroshot-frequency", type=int, default=2, help="How often to run zero shot."
|
| 255 |
-
)
|
| 256 |
-
parser.add_argument(
|
| 257 |
-
"--val-frequency",
|
| 258 |
-
type=int,
|
| 259 |
-
default=1,
|
| 260 |
-
help="How often to run evaluation with val data.",
|
| 261 |
-
)
|
| 262 |
-
parser.add_argument(
|
| 263 |
-
"--resume",
|
| 264 |
-
default=None,
|
| 265 |
-
type=str,
|
| 266 |
-
help="path to latest checkpoint (default: none)",
|
| 267 |
-
)
|
| 268 |
-
parser.add_argument(
|
| 269 |
-
"--precision",
|
| 270 |
-
choices=["amp", "fp16", "fp32"],
|
| 271 |
-
default="amp",
|
| 272 |
-
help="Floating point precision.",
|
| 273 |
-
)
|
| 274 |
-
parser.add_argument(
|
| 275 |
-
"--amodel",
|
| 276 |
-
type=str,
|
| 277 |
-
default="RN50",
|
| 278 |
-
help="Name of the audio backbone to use.",
|
| 279 |
-
)
|
| 280 |
-
parser.add_argument(
|
| 281 |
-
"--tmodel",
|
| 282 |
-
type=str,
|
| 283 |
-
default="transformer",
|
| 284 |
-
help="Name of the text backbone to use. Can be [transformer, bert, roberta, bart]",
|
| 285 |
-
)
|
| 286 |
-
parser.add_argument(
|
| 287 |
-
"--pretrained-audio",
|
| 288 |
-
default="",
|
| 289 |
-
type=str,
|
| 290 |
-
help="Use a pretrained audio model weights for the audio encoder of CLAP",
|
| 291 |
-
)
|
| 292 |
-
parser.add_argument(
|
| 293 |
-
"--pretrained-text",
|
| 294 |
-
default="",
|
| 295 |
-
type=str,
|
| 296 |
-
help="Use a pretrained text model weights for the text encoder of CLAP",
|
| 297 |
-
)
|
| 298 |
-
parser.add_argument(
|
| 299 |
-
"--pretrained",
|
| 300 |
-
default="",
|
| 301 |
-
type=str,
|
| 302 |
-
help="Use a pretrained CLIP model weights with the specified tag or file path.",
|
| 303 |
-
)
|
| 304 |
-
parser.add_argument(
|
| 305 |
-
"--pretrained-image",
|
| 306 |
-
default=False,
|
| 307 |
-
action="store_true",
|
| 308 |
-
help="Load imagenet pretrained weights for image tower backbone if available.",
|
| 309 |
-
)
|
| 310 |
-
parser.add_argument(
|
| 311 |
-
"--lock-image",
|
| 312 |
-
default=False,
|
| 313 |
-
action="store_true",
|
| 314 |
-
help="Lock full image tower by disabling gradients.",
|
| 315 |
-
)
|
| 316 |
-
parser.add_argument(
|
| 317 |
-
"--lock-image-unlocked-groups",
|
| 318 |
-
type=int,
|
| 319 |
-
default=0,
|
| 320 |
-
help="Leave last n image tower layer groups unlocked.",
|
| 321 |
-
)
|
| 322 |
-
parser.add_argument(
|
| 323 |
-
"--lock-image-freeze-bn-stats",
|
| 324 |
-
default=False,
|
| 325 |
-
action="store_true",
|
| 326 |
-
help="Freeze BatchNorm running stats in image tower for any locked layers.",
|
| 327 |
-
)
|
| 328 |
-
parser.add_argument(
|
| 329 |
-
"--local-loss",
|
| 330 |
-
default=False,
|
| 331 |
-
action="store_true",
|
| 332 |
-
help="calculate loss w/ local features @ global (instead of realizing full global @ global matrix)",
|
| 333 |
-
)
|
| 334 |
-
parser.add_argument(
|
| 335 |
-
"--gather-with-grad",
|
| 336 |
-
default=False,
|
| 337 |
-
action="store_true",
|
| 338 |
-
help="enable full distributed gradient for feature gather",
|
| 339 |
-
)
|
| 340 |
-
parser.add_argument(
|
| 341 |
-
"--force-quick-gelu",
|
| 342 |
-
default=False,
|
| 343 |
-
action="store_true",
|
| 344 |
-
help="Force use of QuickGELU activation for non-OpenAI transformer models.",
|
| 345 |
-
)
|
| 346 |
-
parser.add_argument(
|
| 347 |
-
"--torchscript",
|
| 348 |
-
default=False,
|
| 349 |
-
action="store_true",
|
| 350 |
-
help="torch.jit.script the model, also uses jit version of OpenAI models if pretrained=='openai'",
|
| 351 |
-
)
|
| 352 |
-
parser.add_argument(
|
| 353 |
-
"--trace",
|
| 354 |
-
default=False,
|
| 355 |
-
action="store_true",
|
| 356 |
-
help="torch.jit.trace the model for inference / eval only",
|
| 357 |
-
)
|
| 358 |
-
# arguments for distributed training
|
| 359 |
-
parser.add_argument(
|
| 360 |
-
"--dist-url",
|
| 361 |
-
default="env://",
|
| 362 |
-
type=str,
|
| 363 |
-
help="url used to set up distributed training",
|
| 364 |
-
)
|
| 365 |
-
parser.add_argument(
|
| 366 |
-
"--dist-backend", default="nccl", type=str, help="distributed backend"
|
| 367 |
-
)
|
| 368 |
-
parser.add_argument(
|
| 369 |
-
"--report-to",
|
| 370 |
-
default="",
|
| 371 |
-
type=str,
|
| 372 |
-
help="Options are ['wandb', 'tensorboard', 'wandb,tensorboard']",
|
| 373 |
-
)
|
| 374 |
-
parser.add_argument(
|
| 375 |
-
"--wandb-notes", default="", type=str, help="Notes if logging with wandb"
|
| 376 |
-
)
|
| 377 |
-
parser.add_argument(
|
| 378 |
-
"--C", type=float, default=3.16, help="inverse regularizer for logistic reg."
|
| 379 |
-
)
|
| 380 |
-
parser.add_argument(
|
| 381 |
-
"--debug",
|
| 382 |
-
default=False,
|
| 383 |
-
action="store_true",
|
| 384 |
-
help="If true, more information is logged.",
|
| 385 |
-
)
|
| 386 |
-
parser.add_argument(
|
| 387 |
-
"--copy-codebase",
|
| 388 |
-
default=False,
|
| 389 |
-
action="store_true",
|
| 390 |
-
help="If true, we copy the entire base on the log diretory, and execute from there.",
|
| 391 |
-
)
|
| 392 |
-
parser.add_argument(
|
| 393 |
-
"--horovod",
|
| 394 |
-
default=False,
|
| 395 |
-
action="store_true",
|
| 396 |
-
help="Use horovod for distributed training.",
|
| 397 |
-
)
|
| 398 |
-
parser.add_argument(
|
| 399 |
-
"--ddp-static-graph",
|
| 400 |
-
default=False,
|
| 401 |
-
action="store_true",
|
| 402 |
-
help="Enable static graph optimization for DDP in PyTorch >= 1.11.",
|
| 403 |
-
)
|
| 404 |
-
parser.add_argument(
|
| 405 |
-
"--no-set-device-rank",
|
| 406 |
-
default=False,
|
| 407 |
-
action="store_true",
|
| 408 |
-
help="Don't set device index from local rank (when CUDA_VISIBLE_DEVICES restricted to one per proc).",
|
| 409 |
-
)
|
| 410 |
-
parser.add_argument("--seed", type=int, default=4242, help="Default random seed.")
|
| 411 |
-
|
| 412 |
-
parser.add_argument(
|
| 413 |
-
"--top-k-checkpoint-select-dataset",
|
| 414 |
-
type=str,
|
| 415 |
-
default="all",
|
| 416 |
-
help="The dataset of selecting top-k checkpoint.",
|
| 417 |
-
)
|
| 418 |
-
|
| 419 |
-
# @R10, @R@5, @R1, mAP@10
|
| 420 |
-
parser.add_argument(
|
| 421 |
-
"--top-k-checkpoint-select-metric",
|
| 422 |
-
type=str,
|
| 423 |
-
default="_R@10",
|
| 424 |
-
help="The metric for selecting top-k checkpoint.",
|
| 425 |
-
)
|
| 426 |
-
parser.add_argument(
|
| 427 |
-
"--openai-model-cache-dir",
|
| 428 |
-
type=str,
|
| 429 |
-
default="~/.cache/clip",
|
| 430 |
-
help="Directory to download OpenAI models.",
|
| 431 |
-
)
|
| 432 |
-
parser.add_argument(
|
| 433 |
-
"--optimizer",
|
| 434 |
-
type=str,
|
| 435 |
-
default="adamw",
|
| 436 |
-
help="can be AdamW or SGD",
|
| 437 |
-
)
|
| 438 |
-
parser.add_argument(
|
| 439 |
-
"--parallel-eval",
|
| 440 |
-
default=False,
|
| 441 |
-
action="store_true",
|
| 442 |
-
help="Eval in parallel (multi-GPU, multi-node).",
|
| 443 |
-
)
|
| 444 |
-
|
| 445 |
-
parser.add_argument(
|
| 446 |
-
"--no-eval",
|
| 447 |
-
default=False,
|
| 448 |
-
action="store_true",
|
| 449 |
-
help="Training without evaluation.",
|
| 450 |
-
)
|
| 451 |
-
|
| 452 |
-
parser.add_argument(
|
| 453 |
-
"--lp-mlp",
|
| 454 |
-
default=False,
|
| 455 |
-
action="store_true",
|
| 456 |
-
help="Linear Probe using MLP layer or not.",
|
| 457 |
-
)
|
| 458 |
-
|
| 459 |
-
parser.add_argument(
|
| 460 |
-
"--lp-freeze",
|
| 461 |
-
default=False,
|
| 462 |
-
action="store_true",
|
| 463 |
-
help="Linear Probe using Freeze CLAP or not",
|
| 464 |
-
)
|
| 465 |
-
|
| 466 |
-
parser.add_argument(
|
| 467 |
-
"--lp-act",
|
| 468 |
-
default="None",
|
| 469 |
-
type=str,
|
| 470 |
-
help="Options are ['relu','elu','prelu','softmax','sigmoid']",
|
| 471 |
-
)
|
| 472 |
-
|
| 473 |
-
parser.add_argument(
|
| 474 |
-
"--lp-loss", type=str, default="bce", help="Loss func of Linear Probe."
|
| 475 |
-
)
|
| 476 |
-
|
| 477 |
-
parser.add_argument(
|
| 478 |
-
"--lp-metrics",
|
| 479 |
-
type=str,
|
| 480 |
-
default="map,mauc,acc",
|
| 481 |
-
help="Metrics of Linear Probe.",
|
| 482 |
-
)
|
| 483 |
-
|
| 484 |
-
parser.add_argument(
|
| 485 |
-
"--lp-lr", type=float, default=1e-4, help="learning rate of linear probe"
|
| 486 |
-
)
|
| 487 |
-
parser.add_argument(
|
| 488 |
-
"--kappa",
|
| 489 |
-
type=float,
|
| 490 |
-
default=0,
|
| 491 |
-
help="the kappa in the weighted contrastive loss, default is to turn off the weighted contrastive loss",
|
| 492 |
-
)
|
| 493 |
-
|
| 494 |
-
parser.add_argument(
|
| 495 |
-
"--data-filling",
|
| 496 |
-
type=str,
|
| 497 |
-
default="pad",
|
| 498 |
-
help="type of data filling when the audio length is shorter than the max length."
|
| 499 |
-
"Can be one of the following: repeat, repeatpad, pad",
|
| 500 |
-
)
|
| 501 |
-
parser.add_argument(
|
| 502 |
-
"--data-truncating",
|
| 503 |
-
type=str,
|
| 504 |
-
default="rand_trunc",
|
| 505 |
-
help="type of data truncation when the audio length is longer than the max length."
|
| 506 |
-
"Can be one of the following: rand_trunc, fusion",
|
| 507 |
-
)
|
| 508 |
-
|
| 509 |
-
parser.add_argument(
|
| 510 |
-
"--clap-mlploss",
|
| 511 |
-
default=False,
|
| 512 |
-
action="store_true",
|
| 513 |
-
help="Using MLP loss for CLAP model or not",
|
| 514 |
-
)
|
| 515 |
-
|
| 516 |
-
parser.add_argument(
|
| 517 |
-
"--wandb-id",
|
| 518 |
-
type=str,
|
| 519 |
-
default=None,
|
| 520 |
-
help="the id of wandb experiment to restore.",
|
| 521 |
-
)
|
| 522 |
-
|
| 523 |
-
parser.add_argument(
|
| 524 |
-
"--sleep", type=float, default=0, help="sleep n seconds before start training"
|
| 525 |
-
)
|
| 526 |
-
|
| 527 |
-
# variable length processing
|
| 528 |
-
parser.add_argument(
|
| 529 |
-
"--enable-fusion",
|
| 530 |
-
default=False,
|
| 531 |
-
action="store_true",
|
| 532 |
-
help="Enable feature funsion for variable-length data",
|
| 533 |
-
)
|
| 534 |
-
|
| 535 |
-
parser.add_argument(
|
| 536 |
-
"--fusion-type",
|
| 537 |
-
type=str,
|
| 538 |
-
default="None",
|
| 539 |
-
help="Type is among ['channel_map', 'daf_1d','aff_1d','iaff_1d','daf_2d','aff_2d','iaff_2d']",
|
| 540 |
-
)
|
| 541 |
-
|
| 542 |
-
parser.add_argument(
|
| 543 |
-
"--mixup",
|
| 544 |
-
default=False,
|
| 545 |
-
action="store_true",
|
| 546 |
-
help="Enable mixup in finetuning training.",
|
| 547 |
-
)
|
| 548 |
-
parser.add_argument(
|
| 549 |
-
"--text-augment-selection",
|
| 550 |
-
type=str,
|
| 551 |
-
default=None,
|
| 552 |
-
help="For selecting levels of augmented text. Type is among ['all', 'augment_only', 'none']",
|
| 553 |
-
)
|
| 554 |
-
|
| 555 |
-
args = parser.parse_args()
|
| 556 |
-
|
| 557 |
-
# If some params are not passed, we use the default values based on model name.
|
| 558 |
-
default_params = get_default_params(args.amodel)
|
| 559 |
-
for name, val in default_params.items():
|
| 560 |
-
if getattr(args, name) is None:
|
| 561 |
-
setattr(args, name, val)
|
| 562 |
-
|
| 563 |
-
return args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/scheduler.py
DELETED
|
@@ -1,24 +0,0 @@
|
|
| 1 |
-
import numpy as np
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
def assign_learning_rate(optimizer, new_lr):
|
| 5 |
-
for param_group in optimizer.param_groups:
|
| 6 |
-
param_group["lr"] = new_lr
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
def _warmup_lr(base_lr, warmup_length, step):
|
| 10 |
-
return base_lr * (step + 1) / warmup_length
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def cosine_lr(optimizer, base_lr, warmup_length, steps):
|
| 14 |
-
def _lr_adjuster(step):
|
| 15 |
-
if step < warmup_length:
|
| 16 |
-
lr = _warmup_lr(base_lr, warmup_length, step)
|
| 17 |
-
else:
|
| 18 |
-
e = step - warmup_length
|
| 19 |
-
es = steps - warmup_length
|
| 20 |
-
lr = 0.5 * (1 + np.cos(np.pi * e / es)) * base_lr
|
| 21 |
-
assign_learning_rate(optimizer, lr)
|
| 22 |
-
return lr
|
| 23 |
-
|
| 24 |
-
return _lr_adjuster
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/train.py
DELETED
|
@@ -1,838 +0,0 @@
|
|
| 1 |
-
import json
|
| 2 |
-
import logging
|
| 3 |
-
import math
|
| 4 |
-
import os
|
| 5 |
-
import time
|
| 6 |
-
from contextlib import suppress
|
| 7 |
-
|
| 8 |
-
import numpy as np
|
| 9 |
-
import torch
|
| 10 |
-
import torch.nn.functional as F
|
| 11 |
-
|
| 12 |
-
try:
|
| 13 |
-
import wandb
|
| 14 |
-
except ImportError:
|
| 15 |
-
wandb = None
|
| 16 |
-
|
| 17 |
-
from open_clip import ClipLoss, gather_features
|
| 18 |
-
from .distributed import is_master
|
| 19 |
-
from .zero_shot import zero_shot_eval
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
class AverageMeter(object):
|
| 23 |
-
"""Computes and stores the average and current value"""
|
| 24 |
-
|
| 25 |
-
def __init__(self):
|
| 26 |
-
self.reset()
|
| 27 |
-
|
| 28 |
-
def reset(self):
|
| 29 |
-
self.val = 0
|
| 30 |
-
self.avg = 0
|
| 31 |
-
self.sum = 0
|
| 32 |
-
self.count = 0
|
| 33 |
-
|
| 34 |
-
def update(self, val, n=1):
|
| 35 |
-
self.val = val
|
| 36 |
-
self.sum += val * n
|
| 37 |
-
self.count += n
|
| 38 |
-
self.avg = self.sum / self.count
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
def unwrap_model(model):
|
| 42 |
-
if hasattr(model, "module"):
|
| 43 |
-
return model.module
|
| 44 |
-
else:
|
| 45 |
-
return model
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def train_one_epoch(
|
| 49 |
-
model, data, epoch, optimizer, scaler, scheduler, args, tb_writer=None
|
| 50 |
-
):
|
| 51 |
-
device = torch.device(args.device)
|
| 52 |
-
autocast = torch.cuda.amp.autocast if args.precision == "amp" else suppress
|
| 53 |
-
model.train()
|
| 54 |
-
loss = ClipLoss(
|
| 55 |
-
local_loss=args.local_loss,
|
| 56 |
-
gather_with_grad=args.gather_with_grad,
|
| 57 |
-
cache_labels=True,
|
| 58 |
-
rank=args.rank,
|
| 59 |
-
world_size=args.world_size,
|
| 60 |
-
use_horovod=args.horovod,
|
| 61 |
-
mlp_loss=args.clap_mlploss,
|
| 62 |
-
weight_loss_kappa=args.kappa,
|
| 63 |
-
)
|
| 64 |
-
|
| 65 |
-
dataloader, sampler = data["train"].dataloader, data["train"].sampler
|
| 66 |
-
if args.distributed and sampler is not None:
|
| 67 |
-
sampler.set_epoch(epoch)
|
| 68 |
-
num_batches_per_epoch = dataloader.num_batches
|
| 69 |
-
sample_digits = math.ceil(math.log(dataloader.num_samples + 1, 10))
|
| 70 |
-
|
| 71 |
-
# for toy dataset
|
| 72 |
-
if args.dataset_type == "toy":
|
| 73 |
-
dataloader.dataset.generate_queue()
|
| 74 |
-
|
| 75 |
-
loss_m = AverageMeter()
|
| 76 |
-
batch_time_m = AverageMeter()
|
| 77 |
-
data_time_m = AverageMeter()
|
| 78 |
-
end = time.time()
|
| 79 |
-
|
| 80 |
-
for i, batch in enumerate(dataloader):
|
| 81 |
-
# logging.info(f"batch {i} of {num_batches_per_epoch}")
|
| 82 |
-
step = num_batches_per_epoch * epoch + i
|
| 83 |
-
if isinstance(scheduler, dict):
|
| 84 |
-
for s in scheduler.values():
|
| 85 |
-
s(step)
|
| 86 |
-
else:
|
| 87 |
-
scheduler(step)
|
| 88 |
-
audios = batch # contains mel_spec, wavform, and longer list
|
| 89 |
-
texts = batch["text"]
|
| 90 |
-
# audios = audios.to(device=device, non_blocking=True)
|
| 91 |
-
# texts = texts.to(device=device, non_blocking=True)
|
| 92 |
-
|
| 93 |
-
data_time_m.update(time.time() - end)
|
| 94 |
-
if isinstance(optimizer, dict):
|
| 95 |
-
for o_ in optimizer.values():
|
| 96 |
-
o_.zero_grad()
|
| 97 |
-
else:
|
| 98 |
-
optimizer.zero_grad()
|
| 99 |
-
|
| 100 |
-
with autocast():
|
| 101 |
-
(
|
| 102 |
-
audio_features,
|
| 103 |
-
text_features,
|
| 104 |
-
audio_features_mlp,
|
| 105 |
-
text_features_mlp,
|
| 106 |
-
logit_scale_a,
|
| 107 |
-
logit_scale_t,
|
| 108 |
-
) = model(audios, texts, device)
|
| 109 |
-
|
| 110 |
-
if args.clap_mlploss:
|
| 111 |
-
total_loss = loss(
|
| 112 |
-
audio_features=audio_features,
|
| 113 |
-
text_features=text_features,
|
| 114 |
-
logit_scale_a=logit_scale_a,
|
| 115 |
-
logit_scale_t=logit_scale_t,
|
| 116 |
-
audio_features_mlp=audio_features_mlp,
|
| 117 |
-
text_features_mlp=text_features_mlp,
|
| 118 |
-
)
|
| 119 |
-
else:
|
| 120 |
-
total_loss = loss(
|
| 121 |
-
audio_features=audio_features,
|
| 122 |
-
text_features=text_features,
|
| 123 |
-
logit_scale_a=logit_scale_a,
|
| 124 |
-
)
|
| 125 |
-
if isinstance(optimizer, dict):
|
| 126 |
-
if scaler is not None:
|
| 127 |
-
scaler.scale(total_loss).backward()
|
| 128 |
-
for o_ in optimizer.values():
|
| 129 |
-
if args.horovod:
|
| 130 |
-
o_.synchronize()
|
| 131 |
-
scaler.unscale_(o_)
|
| 132 |
-
with o_.skip_synchronize():
|
| 133 |
-
scaler.step(o_)
|
| 134 |
-
else:
|
| 135 |
-
scaler.step(o_)
|
| 136 |
-
scaler.update()
|
| 137 |
-
else:
|
| 138 |
-
total_loss.backward()
|
| 139 |
-
for o_ in optimizer.values():
|
| 140 |
-
o_.step()
|
| 141 |
-
else:
|
| 142 |
-
if scaler is not None:
|
| 143 |
-
scaler.scale(total_loss).backward()
|
| 144 |
-
if args.horovod:
|
| 145 |
-
optimizer.synchronize()
|
| 146 |
-
scaler.unscale_(optimizer)
|
| 147 |
-
with optimizer.skip_synchronize():
|
| 148 |
-
scaler.step(optimizer)
|
| 149 |
-
else:
|
| 150 |
-
scaler.step(optimizer)
|
| 151 |
-
scaler.update()
|
| 152 |
-
else:
|
| 153 |
-
total_loss.backward()
|
| 154 |
-
optimizer.step()
|
| 155 |
-
|
| 156 |
-
# Note: we clamp to 4.6052 = ln(100), as in the original paper.
|
| 157 |
-
with torch.no_grad():
|
| 158 |
-
unwrap_model(model).logit_scale_a.clamp_(0, math.log(100))
|
| 159 |
-
if args.clap_mlploss:
|
| 160 |
-
unwrap_model(model).logit_scale_t.clamp_(0, math.log(100))
|
| 161 |
-
|
| 162 |
-
batch_time_m.update(time.time() - end)
|
| 163 |
-
end = time.time()
|
| 164 |
-
batch_count = i + 1
|
| 165 |
-
if is_master(args) and (i % 100 == 0 or batch_count == num_batches_per_epoch):
|
| 166 |
-
if isinstance(audios, dict):
|
| 167 |
-
batch_size = len(audios["waveform"])
|
| 168 |
-
else:
|
| 169 |
-
batch_size = len(audios)
|
| 170 |
-
num_samples = batch_count * batch_size * args.world_size
|
| 171 |
-
samples_per_epoch = dataloader.num_samples
|
| 172 |
-
percent_complete = 100.0 * batch_count / num_batches_per_epoch
|
| 173 |
-
|
| 174 |
-
# NOTE loss is coarsely sampled, just master node and per log update
|
| 175 |
-
loss_m.update(total_loss.item(), batch_size)
|
| 176 |
-
logit_scale_scalar_a = logit_scale_a.item()
|
| 177 |
-
logit_scale_scalar_t = logit_scale_t.item()
|
| 178 |
-
if isinstance(optimizer, dict):
|
| 179 |
-
if args.clap_mlploss:
|
| 180 |
-
logging.info(
|
| 181 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 182 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 183 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 184 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 185 |
-
f"LR: {[o_.param_groups[0]['lr'] for o_ in optimizer.values()]} "
|
| 186 |
-
f"Logit Scale Audio: {logit_scale_scalar_a:.3f}"
|
| 187 |
-
f"Logit Scale Text: {logit_scale_scalar_t:.3f}"
|
| 188 |
-
)
|
| 189 |
-
log_data = {
|
| 190 |
-
"loss": loss_m.val,
|
| 191 |
-
"data_time": data_time_m.val,
|
| 192 |
-
"batch_time": batch_time_m.val,
|
| 193 |
-
"scale_audio": logit_scale_scalar_a,
|
| 194 |
-
"scale_text": logit_scale_scalar_t,
|
| 195 |
-
"lr": [o_.param_groups[0]["lr"] for o_ in optimizer.values()],
|
| 196 |
-
}
|
| 197 |
-
else:
|
| 198 |
-
logging.info(
|
| 199 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 200 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 201 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 202 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 203 |
-
f"LR: {[o_.param_groups[0]['lr'] for o_ in optimizer.values()]} "
|
| 204 |
-
f"Logit Scale Audio: {logit_scale_scalar_a:.3f}"
|
| 205 |
-
)
|
| 206 |
-
log_data = {
|
| 207 |
-
"loss": loss_m.val,
|
| 208 |
-
"data_time": data_time_m.val,
|
| 209 |
-
"batch_time": batch_time_m.val,
|
| 210 |
-
"scale_audio": logit_scale_scalar_a,
|
| 211 |
-
"lr": [o_.param_groups[0]["lr"] for o_ in optimizer.values()],
|
| 212 |
-
}
|
| 213 |
-
|
| 214 |
-
else:
|
| 215 |
-
if args.clap_mlploss:
|
| 216 |
-
logging.info(
|
| 217 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 218 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 219 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 220 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 221 |
-
f"LR: {optimizer.param_groups[0]['lr']:5f} "
|
| 222 |
-
f"Logit Scale Audio: {logit_scale_scalar_a:.3f}"
|
| 223 |
-
f"Logit Scale Text: {logit_scale_scalar_t:.3f}"
|
| 224 |
-
)
|
| 225 |
-
|
| 226 |
-
# Save train loss / etc. Using non avg meter values as loggers have their own smoothing
|
| 227 |
-
log_data = {
|
| 228 |
-
"loss": loss_m.val,
|
| 229 |
-
"data_time": data_time_m.val,
|
| 230 |
-
"batch_time": batch_time_m.val,
|
| 231 |
-
"scale_audio": logit_scale_scalar_a,
|
| 232 |
-
"scale_text": logit_scale_scalar_t,
|
| 233 |
-
"lr": optimizer.param_groups[0]["lr"],
|
| 234 |
-
}
|
| 235 |
-
else:
|
| 236 |
-
logging.info(
|
| 237 |
-
f"Train Epoch: {epoch} [{num_samples:>{sample_digits}}/{samples_per_epoch} ({percent_complete:.0f}%)] "
|
| 238 |
-
f"Loss: {loss_m.val:#.5g} ({loss_m.avg:#.4g}) "
|
| 239 |
-
f"Data (t): {data_time_m.avg:.3f} "
|
| 240 |
-
f"Batch (t): {batch_time_m.avg:.3f} "
|
| 241 |
-
f"LR: {optimizer.param_groups[0]['lr']:5f} "
|
| 242 |
-
f"Logit Scale Audio: {logit_scale_scalar_a:.3f}"
|
| 243 |
-
)
|
| 244 |
-
|
| 245 |
-
# Save train loss / etc. Using non avg meter values as loggers have their own smoothing
|
| 246 |
-
log_data = {
|
| 247 |
-
"loss": loss_m.val,
|
| 248 |
-
"data_time": data_time_m.val,
|
| 249 |
-
"batch_time": batch_time_m.val,
|
| 250 |
-
"scale_audio": logit_scale_scalar_a,
|
| 251 |
-
"lr": optimizer.param_groups[0]["lr"],
|
| 252 |
-
}
|
| 253 |
-
for name, val in log_data.items():
|
| 254 |
-
name = "train/" + name
|
| 255 |
-
if tb_writer is not None:
|
| 256 |
-
tb_writer.add_scalar(name, val, step)
|
| 257 |
-
if args.wandb:
|
| 258 |
-
assert wandb is not None, "Please install wandb."
|
| 259 |
-
wandb.log({name: val, "step": step})
|
| 260 |
-
|
| 261 |
-
# resetting batch / data time meters per log window
|
| 262 |
-
batch_time_m.reset()
|
| 263 |
-
data_time_m.reset()
|
| 264 |
-
# end for
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
def evaluate(model, data, epoch, args, tb_writer=None):
|
| 268 |
-
metrics = {}
|
| 269 |
-
if not args.parallel_eval:
|
| 270 |
-
if not is_master(args):
|
| 271 |
-
return metrics
|
| 272 |
-
device = torch.device(args.device)
|
| 273 |
-
model.eval()
|
| 274 |
-
|
| 275 |
-
# CHANGE
|
| 276 |
-
# zero_shot_metrics = zero_shot_eval(model, data, epoch, args)
|
| 277 |
-
# metrics.update(zero_shot_metrics)
|
| 278 |
-
if is_master(args):
|
| 279 |
-
print("Evaluating...")
|
| 280 |
-
autocast = torch.cuda.amp.autocast if args.precision == "amp" else suppress
|
| 281 |
-
if args.val_dataset_names == ["Clotho", "audiocaps"]:
|
| 282 |
-
# if only clotho and audiocaps are used, then we will use a different evaluation function.
|
| 283 |
-
# This is because in the Clotho and audiocaps valid and test set, there are 5 text for 1 audio.
|
| 284 |
-
if args.parallel_eval:
|
| 285 |
-
# (yusong): just a hack here. Don't use parallel eval when evaluating only clotho and audiocaps.
|
| 286 |
-
raise NotImplementedError(
|
| 287 |
-
"Parallel evaluation not supported for eval only Clotho and audiocaps."
|
| 288 |
-
)
|
| 289 |
-
val_metrics_per_dataset = evaluate_clotho_audiocaps(
|
| 290 |
-
model, data, epoch, args, autocast, device, tb_writer
|
| 291 |
-
)
|
| 292 |
-
for m in val_metrics_per_dataset.values():
|
| 293 |
-
metrics.update(m)
|
| 294 |
-
if "epoch" not in metrics.keys():
|
| 295 |
-
metrics.update({"epoch": epoch})
|
| 296 |
-
metrics = select_top_metric_clotho_audiocaps(
|
| 297 |
-
metrics, val_metrics_per_dataset, args
|
| 298 |
-
)
|
| 299 |
-
elif "val" in data and (
|
| 300 |
-
args.val_frequency
|
| 301 |
-
and ((epoch % args.val_frequency) == 0 or epoch == args.epochs)
|
| 302 |
-
):
|
| 303 |
-
dataloader = data["val"].dataloader
|
| 304 |
-
num_samples = 0
|
| 305 |
-
samples_per_val = dataloader.num_samples
|
| 306 |
-
|
| 307 |
-
# FIXME this does not scale past small eval datasets
|
| 308 |
-
# all_audio_features @ all_text_features will blow up memory and compute very quickly
|
| 309 |
-
eval_info = {}
|
| 310 |
-
if args.clap_mlploss:
|
| 311 |
-
eval_info["all"] = {
|
| 312 |
-
"cumulative_loss": 0.0,
|
| 313 |
-
"num_samples": 0,
|
| 314 |
-
"all_audio_features": [],
|
| 315 |
-
"all_text_features": [],
|
| 316 |
-
"all_audio_features_mlp": [],
|
| 317 |
-
"all_text_features_mlp": [],
|
| 318 |
-
} # cumulative_loss = 0.0
|
| 319 |
-
else:
|
| 320 |
-
eval_info["all"] = {
|
| 321 |
-
"cumulative_loss": 0.0,
|
| 322 |
-
"num_samples": 0,
|
| 323 |
-
"all_audio_features": [],
|
| 324 |
-
"all_text_features": [],
|
| 325 |
-
} # cumu
|
| 326 |
-
# all_audio_features, all_text_features, all_audio_features_mlp, all_text_features_mlp = [], [], [], []
|
| 327 |
-
with torch.no_grad():
|
| 328 |
-
for i, batch in enumerate(dataloader):
|
| 329 |
-
audios = batch # contains mel_spec, wavform, and longer list
|
| 330 |
-
texts = batch["text"]
|
| 331 |
-
# audios = audios.to(device=device, non_blocking=True)
|
| 332 |
-
|
| 333 |
-
all_names = list(
|
| 334 |
-
set(["-".join(b.split("/")[-3:-1]) for b in batch["__url__"]])
|
| 335 |
-
)
|
| 336 |
-
for name in all_names:
|
| 337 |
-
if name not in eval_info.keys():
|
| 338 |
-
if args.clap_mlploss:
|
| 339 |
-
eval_info[name] = {
|
| 340 |
-
"cumulative_loss": 0.0,
|
| 341 |
-
"num_samples": 0,
|
| 342 |
-
"all_audio_features": [],
|
| 343 |
-
"all_text_features": [],
|
| 344 |
-
"all_audio_features_mlp": [],
|
| 345 |
-
"all_text_features_mlp": [],
|
| 346 |
-
}
|
| 347 |
-
else:
|
| 348 |
-
eval_info[name] = {
|
| 349 |
-
"cumulative_loss": 0.0,
|
| 350 |
-
"num_samples": 0,
|
| 351 |
-
"all_audio_features": [],
|
| 352 |
-
"all_text_features": [],
|
| 353 |
-
}
|
| 354 |
-
with autocast():
|
| 355 |
-
(
|
| 356 |
-
audio_features,
|
| 357 |
-
text_features,
|
| 358 |
-
audio_features_mlp,
|
| 359 |
-
text_features_mlp,
|
| 360 |
-
logit_scale_a,
|
| 361 |
-
logit_scale_t,
|
| 362 |
-
) = model(audios, texts, device)
|
| 363 |
-
|
| 364 |
-
if args.parallel_eval:
|
| 365 |
-
# multi-GPU eval
|
| 366 |
-
if args.clap_mlploss:
|
| 367 |
-
(
|
| 368 |
-
audio_features,
|
| 369 |
-
text_features,
|
| 370 |
-
audio_features_mlp,
|
| 371 |
-
text_features_mlp,
|
| 372 |
-
) = gather_features(
|
| 373 |
-
audio_features=audio_features,
|
| 374 |
-
text_features=text_features,
|
| 375 |
-
audio_features_mlp=audio_features_mlp,
|
| 376 |
-
text_features_mlp=text_features_mlp,
|
| 377 |
-
local_loss=False,
|
| 378 |
-
gather_with_grad=False,
|
| 379 |
-
rank=args.rank,
|
| 380 |
-
world_size=args.world_size,
|
| 381 |
-
use_horovod=args.horovod,
|
| 382 |
-
mlp_loss=args.clap_mlploss,
|
| 383 |
-
)
|
| 384 |
-
else:
|
| 385 |
-
(audio_features, text_features,) = gather_features(
|
| 386 |
-
audio_features=audio_features,
|
| 387 |
-
text_features=text_features,
|
| 388 |
-
local_loss=False,
|
| 389 |
-
gather_with_grad=False,
|
| 390 |
-
rank=args.rank,
|
| 391 |
-
world_size=args.world_size,
|
| 392 |
-
use_horovod=args.horovod,
|
| 393 |
-
mlp_loss=args.clap_mlploss,
|
| 394 |
-
)
|
| 395 |
-
|
| 396 |
-
if is_master(args):
|
| 397 |
-
num_samples += audio_features.shape[0]
|
| 398 |
-
for n in [*all_names, "all"]:
|
| 399 |
-
if n == "all":
|
| 400 |
-
eval_info[n]["all_audio_features"].append(
|
| 401 |
-
audio_features.cpu()
|
| 402 |
-
)
|
| 403 |
-
eval_info[n]["all_text_features"].append(
|
| 404 |
-
text_features.cpu()
|
| 405 |
-
)
|
| 406 |
-
if args.clap_mlploss:
|
| 407 |
-
eval_info[n]["all_audio_features_mlp"].append(
|
| 408 |
-
audio_features_mlp.cpu()
|
| 409 |
-
)
|
| 410 |
-
eval_info[n]["all_text_features_mlp"].append(
|
| 411 |
-
text_features_mlp.cpu()
|
| 412 |
-
)
|
| 413 |
-
else:
|
| 414 |
-
idx = np.where(
|
| 415 |
-
np.array(
|
| 416 |
-
[
|
| 417 |
-
"-".join(b.split("/")[-3:-1])
|
| 418 |
-
for b in batch["__url__"]
|
| 419 |
-
]
|
| 420 |
-
)
|
| 421 |
-
== n
|
| 422 |
-
)[0]
|
| 423 |
-
eval_info[n]["all_audio_features"].append(
|
| 424 |
-
audio_features.cpu().index_select(
|
| 425 |
-
0, torch.tensor(idx).long()
|
| 426 |
-
)
|
| 427 |
-
)
|
| 428 |
-
eval_info[n]["all_text_features"].append(
|
| 429 |
-
text_features.cpu().index_select(
|
| 430 |
-
0, torch.tensor(idx).long()
|
| 431 |
-
)
|
| 432 |
-
)
|
| 433 |
-
if args.clap_mlploss:
|
| 434 |
-
eval_info[n]["all_audio_features_mlp"].append(
|
| 435 |
-
audio_features_mlp.cpu().index_select(
|
| 436 |
-
0, torch.tensor(idx).long()
|
| 437 |
-
)
|
| 438 |
-
)
|
| 439 |
-
eval_info[n]["all_text_features_mlp"].append(
|
| 440 |
-
text_features_mlp.cpu().index_select(
|
| 441 |
-
0, torch.tensor(idx).long()
|
| 442 |
-
)
|
| 443 |
-
)
|
| 444 |
-
# print(f'eval step {i}') # (yusong): for debug
|
| 445 |
-
|
| 446 |
-
# cumulative_loss += total_loss * batch_size
|
| 447 |
-
# num_samples += batch_size
|
| 448 |
-
if is_master(args) and (i % 100) == 0: # and i != 0:
|
| 449 |
-
logging.info(
|
| 450 |
-
f"Eval Epoch: {epoch} [{num_samples} / {samples_per_val}]"
|
| 451 |
-
)
|
| 452 |
-
if is_master(args):
|
| 453 |
-
val_metrics_per_dataset = {}
|
| 454 |
-
for n in eval_info.keys():
|
| 455 |
-
if args.clap_mlploss:
|
| 456 |
-
metrics_single_dataset = get_metrics(
|
| 457 |
-
audio_features=torch.cat(
|
| 458 |
-
eval_info[n]["all_audio_features"]
|
| 459 |
-
),
|
| 460 |
-
text_features=torch.cat(eval_info[n]["all_text_features"]),
|
| 461 |
-
logit_scale_a=logit_scale_a.cpu(),
|
| 462 |
-
audio_features_mlp=torch.cat(
|
| 463 |
-
eval_info[n]["all_audio_features_mlp"]
|
| 464 |
-
),
|
| 465 |
-
text_features_mlp=torch.cat(
|
| 466 |
-
eval_info[n]["all_text_features_mlp"]
|
| 467 |
-
),
|
| 468 |
-
logit_scale_t=logit_scale_t.cpu(),
|
| 469 |
-
mlp_loss=args.clap_mlploss,
|
| 470 |
-
)
|
| 471 |
-
else:
|
| 472 |
-
metrics_single_dataset = get_metrics(
|
| 473 |
-
audio_features=torch.cat(
|
| 474 |
-
eval_info[n]["all_audio_features"]
|
| 475 |
-
),
|
| 476 |
-
text_features=torch.cat(eval_info[n]["all_text_features"]),
|
| 477 |
-
logit_scale_a=logit_scale_a.cpu(),
|
| 478 |
-
mlp_loss=args.clap_mlploss,
|
| 479 |
-
)
|
| 480 |
-
val_metrics_per_dataset[n] = {
|
| 481 |
-
n + "/" + k: v for k, v in metrics_single_dataset.items()
|
| 482 |
-
}
|
| 483 |
-
metrics.update(val_metrics_per_dataset[n])
|
| 484 |
-
if "epoch" not in metrics.keys():
|
| 485 |
-
metrics.update({"epoch": epoch})
|
| 486 |
-
if is_master(args):
|
| 487 |
-
if not metrics:
|
| 488 |
-
return metrics
|
| 489 |
-
|
| 490 |
-
logging.info(
|
| 491 |
-
f"Eval Epoch: {epoch} "
|
| 492 |
-
+ "\n".join(
|
| 493 |
-
[
|
| 494 |
-
"\t".join([f"{k}: {round(v, 4):.4f}" for k, v in m.items()])
|
| 495 |
-
for m in val_metrics_per_dataset.values()
|
| 496 |
-
]
|
| 497 |
-
)
|
| 498 |
-
)
|
| 499 |
-
|
| 500 |
-
if args.save_logs:
|
| 501 |
-
for name, val in metrics.items():
|
| 502 |
-
if tb_writer is not None:
|
| 503 |
-
tb_writer.add_scalar(f"val/{name}", val, epoch)
|
| 504 |
-
|
| 505 |
-
with open(os.path.join(args.checkpoint_path, "results.jsonl"), "a+") as f:
|
| 506 |
-
f.write(json.dumps(metrics))
|
| 507 |
-
f.write("\n")
|
| 508 |
-
|
| 509 |
-
if args.wandb:
|
| 510 |
-
assert wandb is not None, "Please install wandb."
|
| 511 |
-
for name, val in metrics.items():
|
| 512 |
-
wandb.log({f"val/{name}": val, "epoch": epoch})
|
| 513 |
-
|
| 514 |
-
return metrics
|
| 515 |
-
else:
|
| 516 |
-
return metrics
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
def get_metrics(
|
| 520 |
-
audio_features,
|
| 521 |
-
text_features,
|
| 522 |
-
logit_scale_a,
|
| 523 |
-
audio_features_mlp=None,
|
| 524 |
-
text_features_mlp=None,
|
| 525 |
-
logit_scale_t=None,
|
| 526 |
-
mlp_loss=False,
|
| 527 |
-
):
|
| 528 |
-
metrics = {}
|
| 529 |
-
if mlp_loss:
|
| 530 |
-
# Set up audio to text & text to audio similary matrice
|
| 531 |
-
a_logits_per_audio = (
|
| 532 |
-
(logit_scale_a * audio_features @ text_features_mlp.t()).detach().cpu()
|
| 533 |
-
)
|
| 534 |
-
a_logits_per_text = a_logits_per_audio.t().detach().cpu()
|
| 535 |
-
t_logits_per_audio = (
|
| 536 |
-
(logit_scale_t * audio_features_mlp @ text_features.t()).detach().cpu()
|
| 537 |
-
)
|
| 538 |
-
t_logits_per_text = t_logits_per_audio.t().detach().cpu()
|
| 539 |
-
|
| 540 |
-
labels = torch.arange(audio_features.shape[0]).long()
|
| 541 |
-
# Change the loss from two terms into four terms with 2x2 combined CE loss
|
| 542 |
-
total_loss = (
|
| 543 |
-
F.cross_entropy(a_logits_per_audio, labels)
|
| 544 |
-
+ F.cross_entropy(a_logits_per_text, labels)
|
| 545 |
-
+ F.cross_entropy(t_logits_per_audio, labels)
|
| 546 |
-
+ F.cross_entropy(t_logits_per_text, labels)
|
| 547 |
-
) / 4
|
| 548 |
-
|
| 549 |
-
metrics[f"cumulative_loss"] = total_loss.item()
|
| 550 |
-
metrics[f"num_samples"] = audio_features.shape[0]
|
| 551 |
-
|
| 552 |
-
logits = {
|
| 553 |
-
"audio_to_text": (a_logits_per_audio + t_logits_per_audio) / 2,
|
| 554 |
-
"text_to_audio": (a_logits_per_text + t_logits_per_text) / 2,
|
| 555 |
-
}
|
| 556 |
-
ground_truth = torch.arange(len(text_features)).view(-1, 1)
|
| 557 |
-
|
| 558 |
-
else:
|
| 559 |
-
# print("text_features", text_features)
|
| 560 |
-
# print("text_features.shape", text_features.shape)
|
| 561 |
-
logits_per_audio = (
|
| 562 |
-
(logit_scale_a * audio_features @ text_features.t()).detach().cpu()
|
| 563 |
-
)
|
| 564 |
-
logits_per_text = logits_per_audio.t().detach().cpu()
|
| 565 |
-
|
| 566 |
-
labels = torch.arange(audio_features.shape[0]).long()
|
| 567 |
-
# Change the loss from two terms into four terms with 2x2 combined CE loss
|
| 568 |
-
total_loss = (
|
| 569 |
-
F.cross_entropy(logits_per_audio, labels)
|
| 570 |
-
+ F.cross_entropy(logits_per_text, labels)
|
| 571 |
-
) / 2
|
| 572 |
-
|
| 573 |
-
metrics[f"cumulative_loss"] = total_loss.item()
|
| 574 |
-
metrics[f"num_samples"] = audio_features.shape[0]
|
| 575 |
-
|
| 576 |
-
logits = {"audio_to_text": logits_per_audio, "text_to_audio": logits_per_text}
|
| 577 |
-
|
| 578 |
-
ground_truth = torch.arange(len(text_features)).view(-1, 1)
|
| 579 |
-
|
| 580 |
-
for name, logit in logits.items():
|
| 581 |
-
ranking = torch.argsort(logit, descending=True)
|
| 582 |
-
preds = torch.where(ranking == ground_truth)[
|
| 583 |
-
1
|
| 584 |
-
] # (yusong) this line is slow because it uses single thread
|
| 585 |
-
preds = preds.detach().cpu().numpy()
|
| 586 |
-
metrics[f"{name}_mean_rank"] = preds.mean() + 1
|
| 587 |
-
metrics[f"{name}_median_rank"] = np.floor(np.median(preds)) + 1
|
| 588 |
-
for k in [1, 5, 10]:
|
| 589 |
-
metrics[f"{name}_R@{k}"] = np.mean(preds < k)
|
| 590 |
-
# map@10
|
| 591 |
-
metrics[f"{name}_mAP@10"] = np.mean(np.where(preds < 10, 1 / (preds + 1), 0.0))
|
| 592 |
-
|
| 593 |
-
return metrics
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
def evaluate_clotho_audiocaps(
|
| 597 |
-
model, data, epoch, args, autocast, device, tb_writer=None
|
| 598 |
-
):
|
| 599 |
-
"""
|
| 600 |
-
Adapted from https://github.com/XinhaoMei/audio-text_retrieval/blob/main/tools/utils.py.
|
| 601 |
-
1. for text-to-audio retrieval, do 5 times and average the results
|
| 602 |
-
2. for R@1, R@5, R@10 in audio-to-text retrieval, take the best rank among 5 text
|
| 603 |
-
3. for map@10 in audio-to-text retrieval:
|
| 604 |
-
3.1: sort the rank of 5 text
|
| 605 |
-
3.2: exclude the rank >=10 (0-index)
|
| 606 |
-
3.3: compute the map regarding the remaining ranks: np.mean(np.arange(1, len(ranks)+1) / ranks).
|
| 607 |
-
(3.3) That is, take the top ranks of 5 text that is < 10, and assign the descending number as ground truth.
|
| 608 |
-
(3.3) E.g.: the ground truth of first rank of the 5 text should be 1, the second rank should be 2, etc.
|
| 609 |
-
"""
|
| 610 |
-
# TODO: (yusong) only support single GPU evaluation and only support non-mlp case for now.
|
| 611 |
-
dataloader = data["val"].dataloader
|
| 612 |
-
with torch.no_grad():
|
| 613 |
-
eval_info = {}
|
| 614 |
-
for i, batch in enumerate(dataloader):
|
| 615 |
-
audios = batch # contains mel_spec, wavform, and longer list
|
| 616 |
-
|
| 617 |
-
# each item in the list has 5 texts
|
| 618 |
-
if args.tmodel == "transformer":
|
| 619 |
-
from open_clip import tokenize
|
| 620 |
-
|
| 621 |
-
texts = [tokenize(t) for t in batch["full_text"]]
|
| 622 |
-
texts = torch.cat(texts)
|
| 623 |
-
else:
|
| 624 |
-
from .data import tokenizer
|
| 625 |
-
|
| 626 |
-
texts = [
|
| 627 |
-
tokenizer(t) for t in batch["full_text"]
|
| 628 |
-
] # 5 texts for each audio
|
| 629 |
-
texts = {
|
| 630 |
-
k: torch.cat([t[k] for t in texts]) for k in texts[0].keys()
|
| 631 |
-
} # 5 x batch
|
| 632 |
-
|
| 633 |
-
# audios = audios.to(device=device, non_blocking=True)
|
| 634 |
-
|
| 635 |
-
all_names = list(
|
| 636 |
-
set(["-".join(b.split("/")[-3:-1]) for b in batch["__url__"]])
|
| 637 |
-
)
|
| 638 |
-
for name in all_names:
|
| 639 |
-
if name not in eval_info.keys():
|
| 640 |
-
# we will not use mlp outputs even if args.clap_mlploss=True
|
| 641 |
-
eval_info[name] = {
|
| 642 |
-
"cumulative_loss": 0.0,
|
| 643 |
-
"num_samples": 0,
|
| 644 |
-
"all_audio_features": [],
|
| 645 |
-
"all_text_features": [],
|
| 646 |
-
}
|
| 647 |
-
with autocast():
|
| 648 |
-
audio_features = model(audios, None, device)
|
| 649 |
-
text_features = model(None, texts, device)
|
| 650 |
-
audio_features = F.normalize(audio_features, dim=-1)
|
| 651 |
-
text_features = F.normalize(text_features, dim=-1)
|
| 652 |
-
|
| 653 |
-
all_names = list(
|
| 654 |
-
set(["-".join(b.split("/")[-3:-1]) for b in batch["__url__"]])
|
| 655 |
-
)
|
| 656 |
-
for n in all_names:
|
| 657 |
-
idx = np.where(
|
| 658 |
-
np.array(
|
| 659 |
-
["-".join(b.split("/")[-3:-1]) for b in batch["__url__"]]
|
| 660 |
-
)
|
| 661 |
-
== n
|
| 662 |
-
)[0]
|
| 663 |
-
eval_info[n]["all_audio_features"].append(
|
| 664 |
-
audio_features.cpu().index_select(0, torch.tensor(idx).long())
|
| 665 |
-
)
|
| 666 |
-
# (yusong) please double-check. This is for selecting 5 text features at once.
|
| 667 |
-
# because idx is a list of indices in size of num_samples,
|
| 668 |
-
# and text_features is a tensor of size (5*num_samples, dim)
|
| 669 |
-
# so we need to select 5 consecutive indices at once for a single index in idx.
|
| 670 |
-
eval_info[n]["all_text_features"].append(
|
| 671 |
-
text_features.cpu()
|
| 672 |
-
.reshape([-1, 5, text_features.shape[1]])
|
| 673 |
-
.index_select(0, torch.tensor(idx).long())
|
| 674 |
-
.reshape([-1, text_features.shape[1]])
|
| 675 |
-
)
|
| 676 |
-
|
| 677 |
-
val_metrics_all = {}
|
| 678 |
-
|
| 679 |
-
for n in eval_info.keys():
|
| 680 |
-
logit_scale_a, logit_scale_t = model(None, None, device)
|
| 681 |
-
logit_scale_a = logit_scale_a.cpu()
|
| 682 |
-
|
| 683 |
-
audio_features = torch.cat(eval_info[n]["all_audio_features"], dim=0)
|
| 684 |
-
text_features = torch.cat(eval_info[n]["all_text_features"], dim=0)
|
| 685 |
-
|
| 686 |
-
logits_per_audio = (
|
| 687 |
-
(logit_scale_a * audio_features @ text_features.t()).detach().cpu()
|
| 688 |
-
)
|
| 689 |
-
logits_per_text = logits_per_audio.t().detach().cpu()
|
| 690 |
-
|
| 691 |
-
# logits_per_audio shape: [num_samples, num_samples*5]
|
| 692 |
-
# logits_per_text shape: [num_samples*5, num_samples]
|
| 693 |
-
|
| 694 |
-
logging.info(
|
| 695 |
-
f"dataset {n}, logits_per_audio shape: {logits_per_audio.shape}, "
|
| 696 |
-
f"logits_per_text shape: {logits_per_text.shape}"
|
| 697 |
-
)
|
| 698 |
-
|
| 699 |
-
metrics = {}
|
| 700 |
-
num_samples = audio_features.shape[0]
|
| 701 |
-
metrics[f"num_samples"] = num_samples
|
| 702 |
-
|
| 703 |
-
# (yusong) the following code is very important, please double-check:
|
| 704 |
-
# logits_per_audio.reshape(num_samples, num_samples, 5)[:, :, d]
|
| 705 |
-
# logits_per_text.reshape(num_samples, 5, num_samples)[:, d, :]
|
| 706 |
-
# Those two are retrieving one of the 5 text for each audio.
|
| 707 |
-
labels = torch.arange(audio_features.shape[0]).long()
|
| 708 |
-
audio_to_text_loss = [
|
| 709 |
-
F.cross_entropy(
|
| 710 |
-
logits_per_audio.reshape(num_samples, num_samples, 5)[:, :, d],
|
| 711 |
-
labels,
|
| 712 |
-
)
|
| 713 |
-
for d in range(5)
|
| 714 |
-
]
|
| 715 |
-
text_to_audio_loss = [
|
| 716 |
-
F.cross_entropy(
|
| 717 |
-
logits_per_text.reshape(num_samples, 5, num_samples)[:, d, :],
|
| 718 |
-
labels,
|
| 719 |
-
)
|
| 720 |
-
for d in range(5)
|
| 721 |
-
]
|
| 722 |
-
total_loss = (np.mean(audio_to_text_loss) + np.mean(text_to_audio_loss)) / 2
|
| 723 |
-
|
| 724 |
-
metrics[f"cumulative_loss"] = total_loss.item()
|
| 725 |
-
|
| 726 |
-
# text to audio: do 5 times
|
| 727 |
-
pred_text = []
|
| 728 |
-
for d in range(5):
|
| 729 |
-
logit = logits_per_text.reshape(num_samples, 5, num_samples)[:, d, :]
|
| 730 |
-
ground_truth = torch.arange(len(logit)).view(-1, 1)
|
| 731 |
-
ranking = torch.argsort(
|
| 732 |
-
logit, descending=True
|
| 733 |
-
) # [num_samples, num_samples]
|
| 734 |
-
preds = torch.where(ranking == ground_truth)[1]
|
| 735 |
-
pred_text.append(preds.detach().cpu().numpy())
|
| 736 |
-
pred_text_concat = np.concatenate(pred_text, axis=0) # [5*num_samples]
|
| 737 |
-
metrics[f"text_to_audio_mean_rank"] = pred_text_concat.mean() + 1
|
| 738 |
-
metrics[f"text_to_audio_median_rank"] = (
|
| 739 |
-
np.floor(np.median(pred_text_concat)) + 1
|
| 740 |
-
)
|
| 741 |
-
for k in [1, 5, 10]:
|
| 742 |
-
metrics[f"text_to_audio_R@{k}"] = np.mean(pred_text_concat < k)
|
| 743 |
-
# map@10
|
| 744 |
-
metrics[f"text_to_audio_mAP@10"] = np.mean(
|
| 745 |
-
np.where(pred_text_concat < 10, 1 / (pred_text_concat + 1), 0.0)
|
| 746 |
-
)
|
| 747 |
-
|
| 748 |
-
# audio to text: take the best result
|
| 749 |
-
# for audio to text map 10, sort and assign descending ground truth.
|
| 750 |
-
# see https://github.com/XinhaoMei/audio-text_retrieval/blob/main/tools/utils.py#L103
|
| 751 |
-
# map@10
|
| 752 |
-
map_all = []
|
| 753 |
-
pred_audio_all = []
|
| 754 |
-
for d in range(num_samples):
|
| 755 |
-
# logits_per_audio: [num_samples, num_samples*5]
|
| 756 |
-
logit_single = logits_per_audio[d, :] # [5*num_samples]
|
| 757 |
-
# Ground-truth index: [d*5, d*5+1, d*5+2, d*5+3, d*5+4]
|
| 758 |
-
ranking = torch.argsort(
|
| 759 |
-
logit_single, descending=True
|
| 760 |
-
) # [5*num_samples]
|
| 761 |
-
# ranking: the index of first match, second match, ...
|
| 762 |
-
ground_truth = torch.arange(d * 5, d * 5 + 5)[None]
|
| 763 |
-
all_pred = torch.where(
|
| 764 |
-
torch.stack([ranking] * 5) == ground_truth.view(-1, 1)
|
| 765 |
-
)[1]
|
| 766 |
-
min_pred = torch.min(all_pred)
|
| 767 |
-
pred_audio_all.append(min_pred.detach().cpu().numpy())
|
| 768 |
-
all_pred_filter = all_pred[all_pred < 10].detach().cpu().numpy()
|
| 769 |
-
# /5 because we have 5 text, so it means for the text rank >=10 we count as 0.
|
| 770 |
-
map_single = (
|
| 771 |
-
np.sum(
|
| 772 |
-
(np.arange(1, len(all_pred_filter) + 1) / (all_pred_filter + 1))
|
| 773 |
-
)
|
| 774 |
-
/ 5
|
| 775 |
-
)
|
| 776 |
-
map_all.append(map_single)
|
| 777 |
-
metrics[f"audio_to_text_mAP@10"] = np.mean(map_all)
|
| 778 |
-
for k in [1, 5, 10]:
|
| 779 |
-
metrics[f"audio_to_text_R@{k}"] = np.mean(np.array(pred_audio_all) < k)
|
| 780 |
-
|
| 781 |
-
val_metrics_all[n] = {n + "/" + k: v for k, v in metrics.items()}
|
| 782 |
-
return val_metrics_all
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
def calculate_selection_performance_clotho_audiocaps(val_metrics_per_dataset):
|
| 786 |
-
"""
|
| 787 |
-
Calculate performance for Clotho+AudioCaps for model selection.
|
| 788 |
-
"""
|
| 789 |
-
selection_performance_all = []
|
| 790 |
-
for n in val_metrics_per_dataset.keys():
|
| 791 |
-
selection_performance = (
|
| 792 |
-
val_metrics_per_dataset[n][f"{n}/audio_to_text_mAP@10"]
|
| 793 |
-
+ val_metrics_per_dataset[n][f"{n}/text_to_audio_mAP@10"]
|
| 794 |
-
) / 2
|
| 795 |
-
selection_performance_all.append(selection_performance)
|
| 796 |
-
return np.mean(selection_performance_all)
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
def select_top_metric_clotho_audiocaps(metrics, val_metrics_per_dataset, args):
|
| 800 |
-
# val_metrics_per_dataset: dict, key: dataset name, value: dict, key: metric name, value: metric value
|
| 801 |
-
# metrics: dict, key: metric name, value: metric value
|
| 802 |
-
# Hack: use args to save the top performance
|
| 803 |
-
if not hasattr(args, "top_selection_performance"):
|
| 804 |
-
selection_performance = calculate_selection_performance_clotho_audiocaps(
|
| 805 |
-
val_metrics_per_dataset
|
| 806 |
-
)
|
| 807 |
-
# TODO: write the if and else together
|
| 808 |
-
metric_update = {}
|
| 809 |
-
for n in val_metrics_per_dataset.keys():
|
| 810 |
-
for k in val_metrics_per_dataset[n].keys():
|
| 811 |
-
metric_update[
|
| 812 |
-
k.split("/")[0] + "-top" + "/" + k.split("/")[1]
|
| 813 |
-
] = val_metrics_per_dataset[n][k]
|
| 814 |
-
metric_update["top_selection_performance"] = selection_performance
|
| 815 |
-
metric_update["top-selection-epoch"] = metrics["epoch"]
|
| 816 |
-
metrics.update(metric_update)
|
| 817 |
-
args.top_metric = metric_update
|
| 818 |
-
args.top_selection_performance = selection_performance
|
| 819 |
-
else:
|
| 820 |
-
selection_performance_new = calculate_selection_performance_clotho_audiocaps(
|
| 821 |
-
val_metrics_per_dataset
|
| 822 |
-
)
|
| 823 |
-
selection_performance_old = args.top_selection_performance
|
| 824 |
-
if selection_performance_new > selection_performance_old:
|
| 825 |
-
metric_update = {}
|
| 826 |
-
for n in val_metrics_per_dataset.keys():
|
| 827 |
-
for k in val_metrics_per_dataset[n].keys():
|
| 828 |
-
metric_update[
|
| 829 |
-
k.split("/")[0] + "-top" + "/" + k.split("/")[1]
|
| 830 |
-
] = val_metrics_per_dataset[n][k]
|
| 831 |
-
metric_update["top_selection_performance"] = selection_performance_new
|
| 832 |
-
metric_update["top-selection-epoch"] = metrics["epoch"]
|
| 833 |
-
metrics.update(metric_update)
|
| 834 |
-
args.top_metric = metric_update
|
| 835 |
-
args.top_selection_performance = selection_performance_new
|
| 836 |
-
else:
|
| 837 |
-
metrics.update(args.top_metric)
|
| 838 |
-
return metrics
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/CLAP/training/zero_shot.py
DELETED
|
@@ -1,95 +0,0 @@
|
|
| 1 |
-
# NOTE: This script is currently not supported for CLAP.
|
| 2 |
-
import logging
|
| 3 |
-
from contextlib import suppress
|
| 4 |
-
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn.functional as F
|
| 7 |
-
from tqdm import tqdm
|
| 8 |
-
|
| 9 |
-
from open_clip import tokenize
|
| 10 |
-
from .imagenet_zeroshot_data import imagenet_classnames, openai_imagenet_template
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def zero_shot_classifier(model, classnames, templates, args):
|
| 14 |
-
with torch.no_grad():
|
| 15 |
-
zeroshot_weights = []
|
| 16 |
-
for classname in tqdm(classnames):
|
| 17 |
-
texts = [template(classname) for template in templates] # format with class
|
| 18 |
-
texts = tokenize(texts).to(args.device) # tokenize
|
| 19 |
-
if args.distributed and not args.horovod:
|
| 20 |
-
class_embeddings = model.module.encode_text(texts)
|
| 21 |
-
else:
|
| 22 |
-
class_embeddings = model.encode_text(texts)
|
| 23 |
-
class_embedding = F.normalize(class_embeddings, dim=-1).mean(dim=0)
|
| 24 |
-
class_embedding /= class_embedding.norm()
|
| 25 |
-
zeroshot_weights.append(class_embedding)
|
| 26 |
-
zeroshot_weights = torch.stack(zeroshot_weights, dim=1).to(args.device)
|
| 27 |
-
return zeroshot_weights
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def accuracy(output, target, topk=(1,)):
|
| 31 |
-
pred = output.topk(max(topk), 1, True, True)[1].t()
|
| 32 |
-
correct = pred.eq(target.view(1, -1).expand_as(pred))
|
| 33 |
-
return [
|
| 34 |
-
float(correct[:k].reshape(-1).float().sum(0, keepdim=True).cpu().numpy())
|
| 35 |
-
for k in topk
|
| 36 |
-
]
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
def run(model, classifier, dataloader, args):
|
| 40 |
-
autocast = torch.cuda.amp.autocast if args.precision == "amp" else suppress
|
| 41 |
-
with torch.no_grad():
|
| 42 |
-
top1, top5, n = 0.0, 0.0, 0.0
|
| 43 |
-
for images, target in tqdm(dataloader, unit_scale=args.batch_size):
|
| 44 |
-
images = images.to(args.device)
|
| 45 |
-
target = target.to(args.device)
|
| 46 |
-
|
| 47 |
-
with autocast():
|
| 48 |
-
# predict
|
| 49 |
-
if args.distributed and not args.horovod:
|
| 50 |
-
image_features = model.module.encode_image(images)
|
| 51 |
-
else:
|
| 52 |
-
image_features = model.encode_image(images)
|
| 53 |
-
image_features = F.normalize(image_features, dim=-1)
|
| 54 |
-
logits = 100.0 * image_features @ classifier
|
| 55 |
-
|
| 56 |
-
# measure accuracy
|
| 57 |
-
acc1, acc5 = accuracy(logits, target, topk=(1, 5))
|
| 58 |
-
top1 += acc1
|
| 59 |
-
top5 += acc5
|
| 60 |
-
n += images.size(0)
|
| 61 |
-
|
| 62 |
-
top1 = top1 / n
|
| 63 |
-
top5 = top5 / n
|
| 64 |
-
return top1, top5
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
def zero_shot_eval(model, data, epoch, args):
|
| 68 |
-
if "imagenet-val" not in data and "imagenet-v2" not in data:
|
| 69 |
-
return {}
|
| 70 |
-
if args.zeroshot_frequency == 0:
|
| 71 |
-
return {}
|
| 72 |
-
if (epoch % args.zeroshot_frequency) != 0 and epoch != args.epochs:
|
| 73 |
-
return {}
|
| 74 |
-
|
| 75 |
-
logging.info("Starting zero-shot imagenet.")
|
| 76 |
-
|
| 77 |
-
logging.info("Building zero-shot classifier")
|
| 78 |
-
classifier = zero_shot_classifier(
|
| 79 |
-
model, imagenet_classnames, openai_imagenet_template, args
|
| 80 |
-
)
|
| 81 |
-
|
| 82 |
-
logging.info("Using classifier")
|
| 83 |
-
results = {}
|
| 84 |
-
if "imagenet-val" in data:
|
| 85 |
-
top1, top5 = run(model, classifier, data["imagenet-val"].dataloader, args)
|
| 86 |
-
results["imagenet-zeroshot-val-top1"] = top1
|
| 87 |
-
results["imagenet-zeroshot-val-top5"] = top5
|
| 88 |
-
if "imagenet-v2" in data:
|
| 89 |
-
top1, top5 = run(model, classifier, data["imagenet-v2"].dataloader, args)
|
| 90 |
-
results["imagenetv2-zeroshot-val-top1"] = top1
|
| 91 |
-
results["imagenetv2-zeroshot-val-top5"] = top5
|
| 92 |
-
|
| 93 |
-
logging.info("Finished zero-shot imagenet.")
|
| 94 |
-
|
| 95 |
-
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
models/clap_encoder.py
CHANGED
|
@@ -1,17 +1,14 @@
|
|
| 1 |
-
import random
|
| 2 |
import torch
|
| 3 |
import torch.nn as nn
|
| 4 |
-
import torchaudio
|
| 5 |
from models.CLAP.open_clip import create_model
|
| 6 |
-
from models.CLAP.training.data import get_audio_features
|
| 7 |
from transformers import RobertaTokenizer
|
|
|
|
| 8 |
|
| 9 |
|
| 10 |
class CLAP_Encoder(nn.Module):
|
| 11 |
def __init__(
|
| 12 |
self,
|
| 13 |
pretrained_path='checkpoint/music_speech_audioset_epoch_15_esc_89.98.pt',
|
| 14 |
-
sampling_rate=32000,
|
| 15 |
amodel = "HTSAT-base",
|
| 16 |
):
|
| 17 |
super().__init__()
|
|
@@ -22,7 +19,7 @@ class CLAP_Encoder(nn.Module):
|
|
| 22 |
self.enable_fusion = False # False if you do not want to use the fusion model
|
| 23 |
self.fusion_type = "aff_2d"
|
| 24 |
self.pretrained = pretrained_path
|
| 25 |
-
self.sampling_rate
|
| 26 |
self.tokenize = RobertaTokenizer.from_pretrained("roberta-base")
|
| 27 |
|
| 28 |
self.model, self.model_cfg = create_model(
|
|
@@ -41,39 +38,7 @@ class CLAP_Encoder(nn.Module):
|
|
| 41 |
self.model.eval()
|
| 42 |
self.encoder_type = 'CLAP'
|
| 43 |
|
| 44 |
-
|
| 45 |
-
ret = []
|
| 46 |
-
for i in range(batch.size(0)):
|
| 47 |
-
ret.append(batch[i])
|
| 48 |
-
return ret
|
| 49 |
-
|
| 50 |
-
def _get_audio_embed(self, batch):
|
| 51 |
-
# batch: [B, samples]
|
| 52 |
-
with torch.no_grad():
|
| 53 |
-
audio_dict_list = []
|
| 54 |
-
assert (
|
| 55 |
-
self.sampling_rate == 32000
|
| 56 |
-
), "We only support 32000 sampling rate"
|
| 57 |
-
|
| 58 |
-
# batch: [bs, 1, t-samples]
|
| 59 |
-
batch = torchaudio.functional.resample(
|
| 60 |
-
batch, orig_freq=self.sampling_rate, new_freq=48000
|
| 61 |
-
)
|
| 62 |
-
for waveform in self.batch_to_list(batch):
|
| 63 |
-
audio_dict = {}
|
| 64 |
-
audio_dict = get_audio_features(
|
| 65 |
-
audio_dict,
|
| 66 |
-
waveform,
|
| 67 |
-
480000,
|
| 68 |
-
data_truncating="fusion",
|
| 69 |
-
data_filling="repeatpad",
|
| 70 |
-
audio_cfg=self.model_cfg["audio_cfg"],
|
| 71 |
-
)
|
| 72 |
-
audio_dict_list.append(audio_dict)
|
| 73 |
-
# [bs, 512]
|
| 74 |
-
embed = self.model.get_audio_embedding(audio_dict_list)
|
| 75 |
-
|
| 76 |
-
return embed.detach()
|
| 77 |
|
| 78 |
def _get_text_embed(self, batch):
|
| 79 |
double_batch = False
|
|
@@ -91,15 +56,9 @@ class CLAP_Encoder(nn.Module):
|
|
| 91 |
|
| 92 |
|
| 93 |
def get_query_embed(self, modality, audio=None, text=None, use_text_ratio=0.5, device=None):
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
elif modality == 'text':
|
| 97 |
embed = self._get_text_embed(text)
|
| 98 |
-
elif modality == 'hybird':
|
| 99 |
-
if random.random() > use_text_ratio:
|
| 100 |
-
embed = self._get_audio_embed(audio)
|
| 101 |
-
else:
|
| 102 |
-
embed = self._get_text_embed(text)
|
| 103 |
else:
|
| 104 |
raise NotImplementedError("Please check flag 'training_modality'.")
|
| 105 |
|
|
|
|
|
|
|
| 1 |
import torch
|
| 2 |
import torch.nn as nn
|
|
|
|
| 3 |
from models.CLAP.open_clip import create_model
|
|
|
|
| 4 |
from transformers import RobertaTokenizer
|
| 5 |
+
# removed: import random, torchaudio, get_audio_features — only used by _get_audio_embed (audio modality), not needed for text inference
|
| 6 |
|
| 7 |
|
| 8 |
class CLAP_Encoder(nn.Module):
|
| 9 |
def __init__(
|
| 10 |
self,
|
| 11 |
pretrained_path='checkpoint/music_speech_audioset_epoch_15_esc_89.98.pt',
|
|
|
|
| 12 |
amodel = "HTSAT-base",
|
| 13 |
):
|
| 14 |
super().__init__()
|
|
|
|
| 19 |
self.enable_fusion = False # False if you do not want to use the fusion model
|
| 20 |
self.fusion_type = "aff_2d"
|
| 21 |
self.pretrained = pretrained_path
|
| 22 |
+
# removed: self.sampling_rate — only used by _get_audio_embed
|
| 23 |
self.tokenize = RobertaTokenizer.from_pretrained("roberta-base")
|
| 24 |
|
| 25 |
self.model, self.model_cfg = create_model(
|
|
|
|
| 38 |
self.model.eval()
|
| 39 |
self.encoder_type = 'CLAP'
|
| 40 |
|
| 41 |
+
# removed: batch_to_list, _get_audio_embed — audio modality not used in inference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
def _get_text_embed(self, batch):
|
| 44 |
double_batch = False
|
|
|
|
| 56 |
|
| 57 |
|
| 58 |
def get_query_embed(self, modality, audio=None, text=None, use_text_ratio=0.5, device=None):
|
| 59 |
+
# removed: audio and hybird modality branches — only text modality used in inference
|
| 60 |
+
if modality == 'text':
|
|
|
|
| 61 |
embed = self._get_text_embed(text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
else:
|
| 63 |
raise NotImplementedError("Please check flag 'training_modality'.")
|
| 64 |
|
models/resunet.py
CHANGED
|
@@ -652,65 +652,6 @@ class ResUNet30(nn.Module):
|
|
| 652 |
|
| 653 |
return output_dict
|
| 654 |
|
| 655 |
-
|
| 656 |
-
def chunk_inference(self, input_dict):
|
| 657 |
-
chunk_config = {
|
| 658 |
-
'NL': 1.0,
|
| 659 |
-
'NC': 3.0,
|
| 660 |
-
'NR': 1.0,
|
| 661 |
-
'RATE': 32000
|
| 662 |
-
}
|
| 663 |
-
|
| 664 |
-
mixtures = input_dict['mixture']
|
| 665 |
-
conditions = input_dict['condition']
|
| 666 |
-
|
| 667 |
-
film_dict = self.film(
|
| 668 |
-
conditions=conditions,
|
| 669 |
-
)
|
| 670 |
-
|
| 671 |
-
NL = int(chunk_config['NL'] * chunk_config['RATE'])
|
| 672 |
-
NC = int(chunk_config['NC'] * chunk_config['RATE'])
|
| 673 |
-
NR = int(chunk_config['NR'] * chunk_config['RATE'])
|
| 674 |
-
|
| 675 |
-
L = mixtures.shape[2]
|
| 676 |
-
|
| 677 |
-
out_np = np.zeros([1, L])
|
| 678 |
-
|
| 679 |
-
WINDOW = NL + NC + NR
|
| 680 |
-
current_idx = 0
|
| 681 |
-
|
| 682 |
-
while current_idx + WINDOW < L:
|
| 683 |
-
chunk_in = mixtures[:, :, current_idx:current_idx + WINDOW]
|
| 684 |
-
|
| 685 |
-
chunk_out = self.base(
|
| 686 |
-
mixtures=chunk_in,
|
| 687 |
-
film_dict=film_dict,
|
| 688 |
-
)['waveform']
|
| 689 |
-
|
| 690 |
-
chunk_out_np = chunk_out.squeeze(0).cpu().data.numpy()
|
| 691 |
-
|
| 692 |
-
if current_idx == 0:
|
| 693 |
-
out_np[:, current_idx:current_idx+WINDOW-NR] = \
|
| 694 |
-
chunk_out_np[:, :-NR] if NR != 0 else chunk_out_np
|
| 695 |
-
else:
|
| 696 |
-
out_np[:, current_idx+NL:current_idx+WINDOW-NR] = \
|
| 697 |
-
chunk_out_np[:, NL:-NR] if NR != 0 else chunk_out_np[:, NL:]
|
| 698 |
-
|
| 699 |
-
current_idx += NC
|
| 700 |
-
|
| 701 |
-
if current_idx < L:
|
| 702 |
-
chunk_in = mixtures[:, :, current_idx:current_idx + WINDOW]
|
| 703 |
-
chunk_out = self.base(
|
| 704 |
-
mixtures=chunk_in,
|
| 705 |
-
film_dict=film_dict,
|
| 706 |
-
)['waveform']
|
| 707 |
-
|
| 708 |
-
chunk_out_np = chunk_out.squeeze(0).cpu().data.numpy()
|
| 709 |
-
|
| 710 |
-
seg_len = chunk_out_np.shape[1]
|
| 711 |
-
out_np[:, current_idx + NL:current_idx + seg_len] = \
|
| 712 |
-
chunk_out_np[:, NL:]
|
| 713 |
-
|
| 714 |
-
return out_np
|
| 715 |
|
| 716 |
|
|
|
|
| 652 |
|
| 653 |
return output_dict
|
| 654 |
|
| 655 |
+
# removed: chunk_inference — not called during inference; also had a latent self.sampling_rate AttributeError in the original source
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 656 |
|
| 657 |
|