|
| 1 | +import os |
| 2 | +import argparse |
| 3 | +import torch |
| 4 | +import torch.nn as nn |
| 5 | +from PIL import Image |
| 6 | +import open_clip |
| 7 | +from os.path import expanduser |
| 8 | +from urllib.request import urlretrieve |
| 9 | +import pandas as pd |
| 10 | +from tqdm import tqdm |
| 11 | +from concurrent.futures import ThreadPoolExecutor |
| 12 | +from queue import Queue |
| 13 | + |
| 14 | + |
| 15 | +def get_aesthetic_model(clip_model="vit_l_14"): |
| 16 | + """load the aethetic model""" |
| 17 | + home = expanduser("~") |
| 18 | + cache_folder = home + "/.cache/emb_reader" |
| 19 | + path_to_model = cache_folder + "/sa_0_4_"+clip_model+"_linear.pth" |
| 20 | + if not os.path.exists(path_to_model): |
| 21 | + os.makedirs(cache_folder, exist_ok=True) |
| 22 | + url_model = ( |
| 23 | + "https://github.com/LAION-AI/aesthetic-predictor/blob/main/sa_0_4_"+clip_model+"_linear.pth?raw=true" |
| 24 | + ) |
| 25 | + urlretrieve(url_model, path_to_model) |
| 26 | + if clip_model == "vit_l_14": |
| 27 | + m = nn.Linear(768, 1) |
| 28 | + elif clip_model == "vit_b_32": |
| 29 | + m = nn.Linear(512, 1) |
| 30 | + else: |
| 31 | + raise ValueError() |
| 32 | + s = torch.load(path_to_model) |
| 33 | + m.load_state_dict(s) |
| 34 | + m.eval() |
| 35 | + return m |
| 36 | + |
| 37 | + |
| 38 | +if __name__ == "__main__": |
| 39 | + parser = argparse.ArgumentParser() |
| 40 | + parser.add_argument("--clip_model", type=str, default="vit_l_14") |
| 41 | + parser.add_argument("--output_dir", type=str, required=True) |
| 42 | + parser.add_argument("--rank", type=int, default=0) |
| 43 | + parser.add_argument("--world_size", type=int, default=1) |
| 44 | + opt = parser.parse_args() |
| 45 | + |
| 46 | + amodel = get_aesthetic_model(clip_model="vit_l_14") |
| 47 | + amodel.eval() |
| 48 | + model, _, preprocess = open_clip.create_model_and_transforms('ViT-L-14', pretrained='openai') |
| 49 | + model = model.cuda() |
| 50 | + amodel = amodel.cuda() |
| 51 | + |
| 52 | + metadata = pd.read_csv(os.path.join(opt.output_dir, 'metadata.csv')) |
| 53 | + metadata = metadata[metadata['snapshotted'] == 1] |
| 54 | + sha256s = metadata['sha256'].values |
| 55 | + |
| 56 | + # filter out objects that are already calculated |
| 57 | + if os.path.exists(os.path.join(opt.output_dir, 'aesthetic_scores.csv')): |
| 58 | + with open(os.path.join(opt.output_dir, 'aesthetic_scores.csv'), 'r') as f: |
| 59 | + old_metadata = pd.read_csv(f) |
| 60 | + sha256s = list(set(sha256s) - set(old_metadata['sha256'].values)) |
| 61 | + |
| 62 | + sha256s = sorted(sha256s) |
| 63 | + sha256s = sha256s[len(sha256s) * opt.rank // opt.world_size: len(sha256s) * (opt.rank + 1) // opt.world_size] |
| 64 | + |
| 65 | + rows = [] |
| 66 | + |
| 67 | + with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor: |
| 68 | + finished = Queue(maxsize=128) |
| 69 | + |
| 70 | + def load_image(sha256): |
| 71 | + try: |
| 72 | + files = os.listdir(os.path.join(opt.output_dir, 'snapshots', sha256)) |
| 73 | + files = [f for f in files if f.endswith('.png')] |
| 74 | + processed = [] |
| 75 | + for file in files: |
| 76 | + image = Image.open(os.path.join(opt.output_dir, 'snapshots', sha256, file)) |
| 77 | + processed.append(preprocess(image)) |
| 78 | + processed = torch.stack(processed, dim=0) |
| 79 | + except Exception as e: |
| 80 | + print(e) |
| 81 | + processed = None |
| 82 | + finished.put((sha256, processed)) |
| 83 | + |
| 84 | + executor.map(load_image, sha256s) |
| 85 | + for _ in tqdm(range(len(sha256s)), desc='Calculating aesthetic scores'): |
| 86 | + sha256, processed = finished.get() |
| 87 | + if processed is not None: |
| 88 | + with torch.no_grad(): |
| 89 | + image_features = model.encode_image(processed.cuda()) |
| 90 | + image_features /= image_features.norm(dim=-1, keepdim=True) |
| 91 | + aesthetic_score = amodel(image_features).cpu() |
| 92 | + rows.append(pd.DataFrame({ |
| 93 | + 'sha256': [sha256], |
| 94 | + 'mean': [aesthetic_score.mean().item()], |
| 95 | + 'std': [aesthetic_score.std().item()], |
| 96 | + 'min': [aesthetic_score.min().item()], |
| 97 | + 'max': [aesthetic_score.max().item()], |
| 98 | + 'median': [aesthetic_score.median().item()] |
| 99 | + })) |
| 100 | + |
| 101 | + with open(os.path.join(opt.output_dir, f'aesthetic_scores_{opt.rank}.csv'), 'w') as f: |
| 102 | + pd.concat(rows).to_csv(f, index=False) |
0 commit comments