Skip to content

Commit 0c01f6b

Browse files
committed
Add aesthetic score processing to dataset toolkits
1 parent 6b0d647 commit 0c01f6b

4 files changed

Lines changed: 127 additions & 2 deletions

File tree

DATASET.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ After downloading, update the metadata file with:
8585
python dataset_toolkits/build_metadata.py ObjaverseXL --output_dir datasets/ObjaverseXL_sketchfab
8686
```
8787

88-
### Step 4: Render Multiview Images
88+
### Step 4: Render Multiview Images (& Calculate Aesthetic Scores)
8989

9090
Multiview images can be rendered with:
9191

@@ -104,6 +104,14 @@ For example, to render the ObjaverseXL (sketchfab) subset and save it to `datase
104104
python dataset_toolkits/render.py ObjaverseXL --output_dir datasets/ObjaverseXL_sketchfab
105105
```
106106

107+
(Optional) If you want to calculate the aesthetic scores of your own rendered datasets, you can use the following command:
108+
109+
```
110+
python dataset_toolkits/calculate_aesthetic_scores.py --output_dir <OUTPUT_DIR> [--rank <RANK> --world_size <WORLD_SIZE>]
111+
```
112+
- `OUTPUT_DIR`: The directory to save the data.
113+
- `RANK` and `WORLD_SIZE`: Multi-node configuration.
114+
107115
Don't forget to update the metadata file with:
108116

109117
```

dataset_toolkits/build_metadata.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,21 @@ def need_process(key):
116116
for f in df_files:
117117
shutil.move(os.path.join(opt.output_dir, f), os.path.join(opt.output_dir, 'merged_records', f'{timestamp}_{f}'))
118118

119+
# merge aesthetic scores
120+
df_files = [f for f in os.listdir(opt.output_dir) if f.startswith('aesthetic_scores_') and f.endswith('.csv')]
121+
df_parts = []
122+
for f in df_files:
123+
try:
124+
df_parts.append(pd.read_csv(os.path.join(opt.output_dir, f)))
125+
except:
126+
pass
127+
if len(df_parts) > 0:
128+
df = pd.concat(df_parts)
129+
df.set_index('sha256', inplace=True)
130+
metadata.update(df, overwrite=True)
131+
for f in df_files:
132+
shutil.move(os.path.join(opt.output_dir, f), os.path.join(opt.output_dir, 'merged_records', f'{timestamp}_{f}'))
133+
119134
# merge voxelized
120135
df_files = [f for f in os.listdir(opt.output_dir) if f.startswith('voxelized_') and f.endswith('.csv')]
121136
df_parts = []
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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)

dataset_toolkits/setup.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pip install pillow imageio imageio-ffmpeg tqdm easydict opencv-python-headless pandas open3d objaverse huggingface_hub
1+
pip install pillow imageio imageio-ffmpeg tqdm easydict opencv-python-headless pandas open3d objaverse huggingface_hub open_clip_torch

0 commit comments

Comments
 (0)