sanatio / bootstrap_dataset.py
kfokesfojefoef's picture
Upload 17 files
247e300 verified
Raw
History Blame Contribute Delete
3.28 kB
"""
Bootstrap training data when CIFAKE download is slow/unavailable.
REAL = CIFAR-10 photos (same source as CIFAKE real class)
FAKE = stylized variants (placeholder until full CIFAKE download completes)
"""
from __future__ import annotations
import argparse
import pickle
import tarfile
import urllib.request
from io import BytesIO
from pathlib import Path
import numpy as np
from PIL import Image, ImageFilter, ImageOps
CIFAR_URL = "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz"
def _unpickle_file(path: Path) -> dict:
with path.open("rb") as handle:
return pickle.load(handle, encoding="bytes")
def download_cifar10(cache_dir: Path) -> Path:
cache_dir.mkdir(parents=True, exist_ok=True)
tar_path = cache_dir / "cifar-10-python.tar.gz"
extract_dir = cache_dir / "cifar-10-batches-py"
if not extract_dir.exists():
if not tar_path.exists():
print("Downloading CIFAR-10 (~170 MB)…")
urllib.request.urlretrieve(CIFAR_URL, tar_path)
print("Extracting CIFAR-10…")
with tarfile.open(tar_path, "r:gz") as tar:
tar.extractall(cache_dir)
return extract_dir
def load_cifar_images(extract_dir: Path, limit: int) -> list[Image.Image]:
images: list[Image.Image] = []
for batch_idx in range(1, 6):
batch_path = extract_dir / f"data_batch_{batch_idx}"
batch = _unpickle_file(batch_path)
data = batch[b"data"]
for row in data:
arr = np.array(row, dtype=np.uint8).reshape(3, 32, 32).transpose(1, 2, 0)
images.append(Image.fromarray(arr, mode="RGB"))
if len(images) >= limit:
return images
return images
def make_fake_variant(img: Image.Image, seed: int) -> Image.Image:
rng = np.random.default_rng(seed)
out = img.convert("RGB").resize((128, 128), Image.Resampling.BILINEAR)
out = out.filter(ImageFilter.GaussianBlur(radius=0.6 + float(rng.random())))
out = ImageOps.posterize(out, bits=5)
arr = np.asarray(out, dtype=np.float32)
arr += rng.normal(0, 6, arr.shape)
arr = np.clip(arr, 0, 255).astype(np.uint8)
return Image.fromarray(arr, mode="RGB")
def build_bootstrap(output_dir: Path, per_class: int) -> tuple[int, int]:
cache = output_dir.parent / "_cache"
extract_dir = download_cifar10(cache)
real_dir = output_dir / "REAL"
fake_dir = output_dir / "FAKE"
real_dir.mkdir(parents=True, exist_ok=True)
fake_dir.mkdir(parents=True, exist_ok=True)
print(f"Building bootstrap set ({per_class} per class)…")
cifar = load_cifar_images(extract_dir, per_class)
for i, img in enumerate(cifar):
img.resize((128, 128), Image.Resampling.LANCZOS).save(real_dir / f"real_{i:05d}.jpg", quality=92)
make_fake_variant(img, seed=i).save(fake_dir / f"fake_{i:05d}.jpg", quality=92)
print(f"Bootstrap ready REAL={len(cifar)} FAKE={len(cifar)}")
return len(cifar), len(cifar)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--output", default="ml/data/cifake_sample")
parser.add_argument("--per-class", type=int, default=2500)
args = parser.parse_args()
build_bootstrap(Path(args.output), args.per_class)
if __name__ == "__main__":
main()