Compare commits

...

23 Commits

Author SHA1 Message Date
Michael Pilosov, PhD 2e7a2e995b copy script 9 months ago
Michael Pilosov, PhD 09a2333297 plotting updates, poster 9 months ago
Michael Pilosov, PhD cbb8218984 bit of cleanup 9 months ago
Michael Pilosov, PhD 32205b2cce update font 9 months ago
Michael Pilosov, PhD 9430e0fcd3 save sorts for color chart 9 months ago
Michael Pilosov, PhD 036ea839ea rename 9 months ago
Michael Pilosov, PhD 2777c0d7ab some tweaks, ready to run at scale 9 months ago
Michael Pilosov, PhD 42a973e12f go longer 9 months ago
Michael Pilosov, PhD 822400191e real run 9 months ago
Michael Pilosov, PhD bc51e6b195 need blockage on train end 9 months ago
Michael Pilosov, PhD 97f51ef8b4 job looks good to go 9 months ago
Michael Pilosov, PhD fc66438f28 test run 9 months ago
Michael Pilosov, PhD e9afd8ae19 really prepare for jobs 9 months ago
Michael Pilosov, PhD 8ffdd67a51 prep for job 9 months ago
Michael Pilosov, PhD 2582bdbbec much faster animations 9 months ago
Michael Pilosov, PhD d9fa9895db delete hsv.png 9 months ago
Michael Pilosov, PhD f83a2bc21a accept nondeterminism, use loading 9 months ago
Michael Pilosov, PhD 5948ab477e load umap 9 months ago
Michael Pilosov, PhD ba9d6c034e update contract 9 months ago
Michael Pilosov, PhD 3575d3259d transparent background for plotting 9 months ago
Michael Pilosov, PhD bd579913d9 update baseline. note nondeterminism 9 months ago
Michael Pilosov, PhD 8522aa0386 isinstance 9 months ago
Michael Pilosov, PhD 6321157df1 align plotting code with defaults 9 months ago
  1. 2
      .gitignore
  2. 0
      archive/hsv1.txt
  3. 0
      archive/hsv2.txt
  4. 0
      archive/hsv3.txt
  5. 0
      archive/index.html
  6. 6
      archive/scrape.py
  7. 170
      baseline.py
  8. 54
      callbacks.py
  9. 111
      check.py
  10. 14
      datamodule.py
  11. BIN
      hsv.png
  12. 11
      makefile
  13. 44
      newsearch.py
  14. 16
      scripts/color_poster.py
  15. 23
      scripts/grab.sh
  16. 44
      scripts/install_ptmono.sh
  17. 40
      scripts/sortcolor.py

2
.gitignore

@ -1,3 +1,5 @@
lightning_logs*/
lightning_logs_dev/
lightning_logs/ lightning_logs/
__pycache__/ __pycache__/
out/ out/

0
hsv1.txt → archive/hsv1.txt

0
hsv2.txt → archive/hsv2.txt

0
hsv3.txt → archive/hsv3.txt

0
index.html → archive/index.html

6
scrape.py → archive/scrape.py

@ -2,7 +2,7 @@ import glob
import shutil import shutil
from pathlib import Path from pathlib import Path
from check import make_image from check import create_rectangle
def get_exps(pattern: str, splitter: str = "_", dry_run: bool = True): def get_exps(pattern: str, splitter: str = "_", dry_run: bool = True):
@ -33,8 +33,8 @@ def get_exps(pattern: str, splitter: str = "_", dry_run: bool = True):
print(latest_checkpoint) print(latest_checkpoint)
if not dry_run: if not dry_run:
shutil.copy(source_path, dir_path) shutil.copy(source_path, dir_path)
make_image(latest_checkpoint, f"out/version_{i}") create_rectangle(latest_checkpoint, f"out/version_{i}")
# make_image(latest_checkpoint, f"out/version_{i}b", color=False) # create_rectangle(latest_checkpoint, f"out/version_{i}b", color=False)
else: else:
print("Would copy", source_path, dir_path) print("Would copy", source_path, dir_path)
return H return H

170
baseline.py

@ -0,0 +1,170 @@
import argparse
from pathlib import Path
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
import numpy as np
from hilbertcurve.hilbertcurve import HilbertCurve
from check import plot_preds
# Extract XKCD colors
colors = list(mcolors.XKCD_COLORS.keys())
rgb_values = [mcolors.to_rgb(mcolors.XKCD_COLORS[color]) for color in colors]
# Parse command-line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--sort-by", type=str, default="hsv", help="kind of sorting")
parser.add_argument("--seed", type=int, default=21, help="seed for UMAP")
parser.add_argument("--dpi", type=int, default=300, help="dpi for saving")
parser.add_argument("--size", type=float, default=6.0, help="size of figure")
parser.add_argument(
"--fontsize",
type=float,
default=0,
help="fontsize of annotation (default: 0 = None)",
)
parser.add_argument(
"--radius", type=float, default=1 / 2, help="inner radius of circle"
)
args = parser.parse_args()
KIND = args.sort_by
SEED = args.seed
DPI = args.dpi
SIZE = args.size
FONTSIZE = args.fontsize
INNER_RADIUS = args.radius
DIR = "/teamspace/studios/this_studio/colors/colors-umap"
prefix = ""
if KIND == "umap":
prefix = f"{SEED:04d}"
FDIR = DIR
else:
FDIR = f"{DIR}/{KIND}"
Path(FDIR).mkdir(exist_ok=True, parents=True)
fname = f"{FDIR}/v{prefix}.png"
if KIND in ("lex", "alpha", "abc"):
preds = np.array(colors)
elif KIND == "umap":
# from umap import UMAP
from cuml import UMAP
# Use UMAP to create a 1D representation
reducer = UMAP(
n_components=1,
n_neighbors=250,
min_dist=1e-2,
metric="euclidean",
random_state=SEED,
negative_sample_rate=2,
)
embedding = reducer.fit_transform(np.array(rgb_values))
# Sort colors by the 1D representation
preds = embedding[:, 0]
del reducer, embedding
elif KIND in ("cielab", "lab", "ciede2000"):
from skimage.color import deltaE_ciede2000, rgb2lab
# CIELAB
# Convert RGB values to CIELAB
lab_values = rgb2lab([rgb_values])
# Reference color for sorting (can be the first color or any other reference point)
reference_color = lab_values[0]
# Compute CIEDE2000 distances of all colors to the reference color
distances = [deltaE_ciede2000(reference_color, color) for color in lab_values]
# Sort colors by their CIEDE2000 distance to the reference color
# preds = distances).flatten() # awful
lab_values_flat = lab_values.reshape(-1, 3)
# Sort colors based on the L* value in the CIELAB space
# 0 corresponds to the L* channel
preds = lab_values_flat[:, 0]
elif KIND == "hsv":
from matplotlib.colors import rgb_to_hsv
# Convert RGB values to HSV
hsv_values = np.array([rgb_to_hsv(np.array(rgb)) for rgb in rgb_values])
# Sort colors based on the hue value
# 0 corresponds to the hue component
preds = hsv_values[:, 0]
else:
raise ValueError(f"Unknown kind: {KIND}")
sorted_indices = np.argsort(preds)
# Save the sorted indices to disk
# if (KIND == "umap") or (KIND != "umap"):
PDIR = f"scripts/{KIND}"
Path(PDIR).mkdir(parents=True, exist_ok=True)
file_path = f"{PDIR}/{SEED:06d}.npy"
np.save(file_path, preds.ravel())
print(f"Predictions saved to {file_path}")
# Sort colors by the 1D representation
sorted_colors = [colors[i] for i in sorted_indices]
plot_preds(
preds,
np.array(rgb_values),
fname,
roll=False,
dpi=DPI,
radius=INNER_RADIUS,
figsize=(SIZE, SIZE),
fsize=FONTSIZE,
label=f"{KIND.upper()}",
)
print(f"saved {fname}")
HILBERT = False
if HILBERT:
# Create Hilbert curve
# We'll set the order such that the number of positions is greater than or equal to the number of colors
hilbert_order = int(np.ceil(0.5 * np.log2(len(sorted_colors))))
hilbert_curve = HilbertCurve(hilbert_order, 2)
# Create an image for visualization
image_size = 2**hilbert_order
image = np.ones((image_size, image_size, 3))
for i, color in enumerate(sorted_colors):
# Convert linear index to Hilbert coordinates
coords = hilbert_curve.point_from_distance(i)
image[coords[1], coords[0]] = mcolors.to_rgb(color)
# annotation in upper right
# Display the image
fig, ax = plt.subplots(1, 1, figsize=(SIZE, SIZE))
ax.imshow(image)
ax.annotate(
f"{KIND.upper()}",
(1.0, 1.0),
ha="right",
va="top",
size=FONTSIZE,
xycoords="axes fraction",
)
ax.axis("off")
ax.set_aspect("equal")
fig.tight_layout()
fname = f"{DIR}/{prefix}{KIND}_sorted_colors_hilbert.png"
fig.savefig(
fname,
dpi=DPI,
transparent=True,
# bbox_inches="tight",
# pad_inches=0
)
print(f"Saved {fname}")

54
callbacks.py

@ -1,14 +1,27 @@
# import subprocess
import os
from pathlib import Path from pathlib import Path
from lightning import Callback from lightning import Callback
from check import create_circle from check import create_circle_nonblocking as create_circle
class SaveImageCallback(Callback): class SaveImageCallback(Callback):
def __init__(self, save_interval=1, final_dir: str = None): def __init__(
self,
save_interval=1,
final_dir: str = None,
radius: float = 0.5,
dpi: int = 300,
figsize=(15, 15), # 4k is at 14.4
):
self.save_interval = save_interval self.save_interval = save_interval
self.final_dir = final_dir self.final_dir = final_dir
self.radius = radius
self.dpi = dpi
self.figsize = figsize
self.processes = []
def on_train_epoch_end(self, trainer, pl_module): def on_train_epoch_end(self, trainer, pl_module):
epoch = trainer.current_epoch epoch = trainer.current_epoch
@ -20,12 +33,15 @@ class SaveImageCallback(Callback):
pl_module.eval() pl_module.eval()
# Save the image # Save the image
# if pl_module.trainer.logger:
#
# else:
# version = 0
fname = Path(pl_module.trainer.logger.log_dir) / Path(f"e{epoch:04d}") fname = Path(pl_module.trainer.logger.log_dir) / Path(f"e{epoch:04d}")
create_circle(pl_module, fname=fname, dpi=300, figsize=(6, 6)) p = create_circle(
pl_module,
fname=fname,
dpi=self.dpi,
figsize=self.figsize,
radius=self.radius,
)
self.processes.append(p)
# Make sure to set it back to train mode # Make sure to set it back to train mode
pl_module.train() pl_module.train()
@ -35,14 +51,24 @@ class SaveImageCallback(Callback):
version = pl_module.trainer.logger.version version = pl_module.trainer.logger.version
fname = Path(f"{self.final_dir}") / Path(f"v{version}") fname = Path(f"{self.final_dir}") / Path(f"v{version}")
pl_module.eval() pl_module.eval()
create_circle(pl_module, fname=fname, dpi=300, figsize=(6, 6)) p = create_circle(
if self.save_interval > 0: pl_module,
import os fname=fname,
dpi=self.dpi,
figsize=self.figsize,
radius=self.radius,
)
self.processes.append(p)
# Wait for all subprocesses to finish
for p in self.processes:
p.join()
if self.save_interval > 0:
log_dir = str(Path(pl_module.trainer.logger.log_dir)) log_dir = str(Path(pl_module.trainer.logger.log_dir))
fps = 12 fps = 12
_cmd = f'ffmpeg -r {fps} -f image2 -i {log_dir}/e%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=white" {log_dir}/a{version}.mp4' # w, h = self.figsize[0] * self.dpi, self.figsize[1] * self.dpi
w, h = 7680, 4320
_cmd = f'ffmpeg -r {fps} -f image2 -i {log_dir}/e%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p -vf "scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:(ow-iw)/2:(oh-ih)/2:color=white" {log_dir}/a{version}.mp4'
# _ = subprocess.Popen(_cmd, shell=True)
os.system(_cmd) os.system(_cmd)
# os.system(
# f'ffmpeg -i {log_dir}/e%04d.png -c:v libx264 -vf "fps={fps},format=yuv420p,pad=ceil(iw/2)*2:ceil(ih/2)*2" {log_dir}/a{version}.mp4'
# )

111
check.py

@ -1,6 +1,8 @@
# import matplotlib.patches as patches # import matplotlib.patches as patches
import pickle
from multiprocessing import Process
from pathlib import Path from pathlib import Path
from typing import Union from typing import Tuple, Union
import matplotlib.patches as patches import matplotlib.patches as patches
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -13,21 +15,21 @@ from model import ColorTransformerModel
# import matplotlib.colors as mcolors # import matplotlib.colors as mcolors
def make_image(ckpt: str, fname: str, color=True, **kwargs): def create_rectangle(ckpt: str, fname: str, color: bool = True, **kwargs):
M = ColorTransformerModel.load_from_checkpoint(ckpt) M = ColorTransformerModel.load_from_checkpoint(ckpt)
# preds = M(rgb_tensor) # preds = M(rgb_tensor)
if not color: if color is False: # black and white ordering...
N = 949 N = 949
linear_space = torch.linspace(0, 1, N) linear_space = torch.linspace(0, 1, N)
rgb_tensor = linear_space.unsqueeze(1).repeat(1, 3) rgb_tensor = linear_space.unsqueeze(1).repeat(1, 3)
else: else:
rgb_tensor, names = extract_colors() rgb_tensor, names = extract_colors()
rgb_values = rgb_tensor.detach().numpy() rgb_tensor = preprocess_data(rgb_tensor).to(M.device)
rgb_tensor = preprocess_data(rgb_tensor) preds = M(rgb_tensor).detach().cpu().numpy()
preds = M(rgb_tensor) rgb_values = rgb_tensor.detach().cpu().numpy()
sorted_inds = np.argsort(preds.detach().numpy().ravel()) sorted_inds = np.argsort(preds.ravel())
fig, ax = plt.subplots() fig, ax = plt.subplots()
for i in range(len(sorted_inds)): for i in range(len(sorted_inds)):
@ -42,11 +44,9 @@ def make_image(ckpt: str, fname: str, color=True, **kwargs):
plt.savefig(f"{fname}.png", **kwargs) plt.savefig(f"{fname}.png", **kwargs)
def create_circle( def do_inference(ckpt: Union[str, ColorTransformerModel]):
ckpt: Union[str, ColorTransformerModel], fname: str, skip: bool = True, **kwargs
):
if isinstance(ckpt, str):
if isinstance(ckpt, str):
M = ColorTransformerModel.load_from_checkpoint( M = ColorTransformerModel.load_from_checkpoint(
ckpt, map_location=lambda storage, loc: storage ckpt, map_location=lambda storage, loc: storage
) )
@ -55,16 +55,49 @@ def create_circle(
xkcd_colors, _ = extract_colors() xkcd_colors, _ = extract_colors()
xkcd_colors = preprocess_data(xkcd_colors).to(M.device) xkcd_colors = preprocess_data(xkcd_colors).to(M.device)
preds = M(xkcd_colors) preds = M(xkcd_colors).detach().cpu().numpy()
rgb_array = xkcd_colors.detach().cpu().numpy() rgb_array = xkcd_colors.detach().cpu().numpy()
return preds, rgb_array
def create_circle(ckpt: Union[str, ColorTransformerModel], fname: str, **kwargs):
preds, rgb_array = do_inference(ckpt)
plot_preds(preds, rgb_array, fname=fname, **kwargs) plot_preds(preds, rgb_array, fname=fname, **kwargs)
def _plot_preds_serialized(serialized_data, fname, **kwargs):
# Deserialize the data
preds, rgb_array = pickle.loads(serialized_data)
plot_preds(preds, rgb_array, fname=fname, **kwargs)
def create_circle_nonblocking(
ckpt: Union[str, ColorTransformerModel], fname: str, **kwargs
):
preds, rgb_array = do_inference(ckpt)
# Serialize the data
serialized_data = pickle.dumps((preds, rgb_array))
# Run _plot_preds_serialized function in a separate process
p = Process(
target=_plot_preds_serialized, args=(serialized_data, fname), kwargs=kwargs
)
p.start()
return p
def plot_preds( def plot_preds(
preds, rgb_values, fname: str, roll: bool = False, dpi: int = 300, figsize=(6, 6) preds: np.ndarray,
rgb_values: np.ndarray,
fname: str,
roll: bool = False,
radius: float = 1 / 2,
dpi: int = 300,
figsize: Tuple[float] = (6, 6),
fsize: int = 0,
label: str = "",
): ):
if isinstance(preds, torch.Tensor):
preds = preds.detach().cpu().numpy()
sorted_inds = np.argsort(preds.ravel()) sorted_inds = np.argsort(preds.ravel())
colors = rgb_values[sorted_inds, :3] colors = rgb_values[sorted_inds, :3]
if roll: if roll:
@ -107,55 +140,67 @@ def plot_preds(
ax.set_yticks([]) ax.set_yticks([])
ax.set_aspect("equal") ax.set_aspect("equal")
ax.axis("off") ax.axis("off")
radius = 1 ax.set_ylim(0, 1) # implicit outer radius of 1
ax.set_ylim(-radius, radius)
# Overlay white circle # Overlay white circle
inner_radius = 1 / 3
circle = patches.Circle( circle = patches.Circle(
(0, 0), inner_radius, transform=ax.transData._b, color="white", zorder=2 (0, 0), radius, transform=ax.transData._b, color="white", zorder=2
) )
ax.add_patch(circle) ax.add_patch(circle)
if fsize > 0.0:
center = (0, 0)
ax.annotate(
label,
center,
ha="center",
va="center",
size=fsize,
color="black",
)
fig.tight_layout(pad=0) fig.tight_layout(pad=0)
plt.savefig( plt.savefig(fname, dpi=dpi, transparent=True, pad_inches=0, bbox_inches="tight")
f"{fname}.png", dpi=dpi, transparent=False, pad_inches=0, bbox_inches="tight"
)
plt.close() plt.close()
if __name__ == "__main__": if __name__ == "__main__":
# name = "color_128_0.3_1.00e-06"
import argparse import argparse
import glob import glob
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
# make the following accept a list of arguments
parser.add_argument("-v", "--version", type=int, nargs="+", default=[0]) parser.add_argument("-v", "--version", type=int, nargs="+", default=[0])
parser.add_argument( parser.add_argument(
"--dpi", type=int, default=300, help="Resolution for saved image." "--dpi", type=int, default=300, help="Resolution for saved image."
) )
parser.add_argument(
"--studio",
type=str,
default=["this_studio"],
nargs="+",
help="Checkpoint studio name.",
)
parser.add_argument("--figsize", type=int, default=6, help="Figure size") parser.add_argument("--figsize", type=int, default=6, help="Figure size")
args = parser.parse_args() args = parser.parse_args()
versions = args.version versions = args.version
for v in versions: for studio in args.studio:
# name = f"out/v{v}"
studio = "colors-refactor-supervised"
# studio = "colors-refactor-unsupervised"
# studio = "colors-refactor-unsupervised-anchors"
# studio = "this_studio"
Path(studio).mkdir(exist_ok=True, parents=True) Path(studio).mkdir(exist_ok=True, parents=True)
for v in versions:
name = f"{studio}/v{v}" name = f"{studio}/v{v}"
# ckpt = f"/teamspace/jobs/{name}/work/colors/lightning_logs/version_2/checkpoints/epoch=999-step=8000.ckpt" # ckpt = f"/teamspace/jobs/{name}/work/colors/lightning_logs/version_2/checkpoints/epoch=999-step=8000.ckpt"
# ckpt_path = f"/teamspace/studios/this_studio/colors/lightning_logs/version_{v}/checkpoints/*.ckpt" # ckpt_path = f"/teamspace/studios/this_studio/colors/lightning_logs/version_{v}/checkpoints/*.ckpt"
ckpt_path = f"/teamspace/studios/{studio}/colors/lightning_logs/version_{v}/checkpoints/*.ckpt" ckpt_path = f"/teamspace/studios/{studio}/colors/lightning_logs/version_{v}/checkpoints/*.ckpt"
ckpt = glob.glob(ckpt_path) ckpt = glob.glob(ckpt_path)
if len(ckpt) > 0: if len(ckpt) > 0: # get latest checkpoint
ckpt = ckpt[-1] ckpt = ckpt[-1] # TODO: allow specification via CLI
print(f"Generating image for checkpoint: {ckpt}") print(f"Generating image for checkpoint: {ckpt}")
create_circle( create_circle(
ckpt, fname=name, dpi=args.dpi, figsize=[args.figsize] * 2, roll=False ckpt,
fname=name,
dpi=args.dpi,
figsize=[args.figsize] * 2,
roll=False,
) )
else: else:
print(f"No checkpoint found for version {v}") print(f"No checkpoint found for version {v}")

14
datamodule.py

@ -35,14 +35,18 @@ class ColorDataModule(L.LightningDataModule):
return [(c, cls.get_hue(c)) for c in train_rgb] return [(c, cls.get_hue(c)) for c in train_rgb]
@classmethod @classmethod
def get_xkcd_colors(cls): def get_xkcd_colors(cls, label="hues"):
rgb_tensor, xkcd_color_names = extract_colors() rgb_tensor, xkcd_color_names = extract_colors()
rgb_tensor = preprocess_data(rgb_tensor, skip=True) rgb_tensor = preprocess_data(rgb_tensor, skip=True)
# return [ if label == "names":
# (rgb_tensor[i], xkcd_color_names[i].replace("xkcd:", "")) return [
# for i in range(len(rgb_tensor)) (rgb_tensor[i], xkcd_color_names[i].replace("xkcd:", ""))
# ] for i in range(len(rgb_tensor))
]
if label == "hues":
return [(c, cls.get_hue(c)) for c in rgb_tensor] return [(c, cls.get_hue(c)) for c in rgb_tensor]
else:
raise ValueError("Please specify `label` as one of ['hues', 'names'].")
def setup(self, stage: str): def setup(self, stage: str):
# Assign train/val datasets for use in dataloaders # Assign train/val datasets for use in dataloaders

BIN
hsv.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

11
makefile

@ -56,13 +56,15 @@ umap:
done done
sort_umap: sort_umap:
python scripts/sortcolor.py -s umap --dpi 300 --seed 21 python baseline.py -s umap --dpi 300 --seed 21
parallel_umap: parallel_umap:
parallel -j 4 python scripts/sortcolor.py -s umap --dpi 300 --seed ::: $$(seq 1 100) parallel -j 4 python baseline.py -s umap --dpi 300 --seed ::: $$(seq 1 100)
parallel_check: parallel_check:
parallel -j 4 python check.py -v ::: $$(seq 0 99) parallel -j 3 python check.py \
--studio colors-refactor-unsupervised colors-refactor-supervised colors-refactor-unsupervised-anchors \
-v ::: $$(seq 0 99)
sort_lex: sort_lex:
python scripts/sortcolor.py -s lex --dpi 300 python scripts/sortcolor.py -s lex --dpi 300
@ -70,6 +72,9 @@ sort_lex:
sort_hsv: sort_hsv:
python scripts/sortcolor.py -s hsv --dpi 300 python scripts/sortcolor.py -s hsv --dpi 300
poster: sort_lex sort_hsv
python scripts/color_poster.py -k hsv lex --rows 119
clean: clean:
rm -rf lightning_logs rm -rf lightning_logs
rm -rf .lr_find_*.ckpt rm -rf .lr_find_*.ckpt

44
newsearch.py

@ -1,4 +1,4 @@
import subprocess import subprocess # noqa: F401
import sys import sys
from random import sample, seed from random import sample, seed
@ -8,17 +8,7 @@ from lightning_sdk import Machine, Studio # noqa: F401
# consistency of randomly sampled experiments. # consistency of randomly sampled experiments.
seed(19920921) seed(19920921)
NUM_JOBS = 50 NUM_JOBS = 20
# reference to the current studio
# if you run outside of Lightning, you can pass the Studio name
# studio = Studio()
# use the jobs plugin
# studio.install_plugin("jobs")
# job_plugin = studio.installed_plugins["jobs"]
# do a sweep over learning rates
# Define the ranges or sets of values for each hyperparameter # Define the ranges or sets of values for each hyperparameter
# alpha_values = list(np.round(np.linspace(2, 4, 21), 4)) # alpha_values = list(np.round(np.linspace(2, 4, 21), 4))
@ -29,16 +19,17 @@ learning_rate_values = [1e-3]
# alpha_values = [0, .25, 0.5, 0.75, 1] # alpha = 0 is unsupervised. alpha = 1 is supervised. # alpha_values = [0, .25, 0.5, 0.75, 1] # alpha = 0 is unsupervised. alpha = 1 is supervised.
alpha_values = [0, 0.1] alpha_values = [0, 0.1]
widths = [2**k for k in range(4, 13)] widths = [2**k for k in range(4, 13)]
depths = [1, 2, 4, 8, 16] depths = [1, 2, 4, 8]
dropouts = [0, 0.5]
# widths, depths = [512], [4] # widths, depths = [512], [4]
batch_size_values = [256] batch_size_values = [64, 256]
max_epochs_values = [420] # at 12 fps, around 35s max_epochs_values = [720 * 3] # at 12fps 720 frames = 60s
seeds = list(range(21, 1992)) seeds = list(range(21, 1992))
optimizers = [ optimizers = [
# "Adagrad", # "Adagrad",
"Adam", "Adam",
# "SGD", "SGD",
# "AdamW", # "AdamW",
# "LBFGS", # "LBFGS",
# "RAdam", # "RAdam",
@ -48,7 +39,7 @@ optimizers = [
# Generate all possible combinations of hyperparameters # Generate all possible combinations of hyperparameters
all_params = [ all_params = [
(alpha, lr, bs, me, s, w, d, opt) (alpha, lr, bs, me, s, w, d, opt, dr)
for alpha in alpha_values for alpha in alpha_values
for lr in learning_rate_values for lr in learning_rate_values
for bs in batch_size_values for bs in batch_size_values
@ -57,6 +48,7 @@ all_params = [
for w in widths for w in widths
for d in depths for d in depths
for opt in optimizers for opt in optimizers
for dr in dropouts
] ]
@ -67,10 +59,10 @@ search_params = sample(all_params, min(NUM_JOBS, len(all_params)))
# --trainer.callbacks.init_args.monitor hp_metric \ # --trainer.callbacks.init_args.monitor hp_metric \
for idx, params in enumerate(search_params): for idx, params in enumerate(search_params):
a, lr, bs, me, s, w, d, opt = params a, lr, bs, me, s, w, d, opt, dr = params
# cmd = f"cd ~/colors && python main.py --alpha {a} --lr {lr} --bs {bs} --max_epochs {me} --seed {s} --width {w}" # cmd = f"cd ~/colors && python main.py --alpha {a} --lr {lr} --bs {bs} --max_epochs {me} --seed {s} --width {w}"
cmd = f""" cmd = f"""
python newmain.py fit \ cd ~/colors && python newmain.py fit \
--seed_everything {s} \ --seed_everything {s} \
--data.batch_size {bs} \ --data.batch_size {bs} \
--data.train_size 0 \ --data.train_size 0 \
@ -81,6 +73,7 @@ python newmain.py fit \
--model.bias true \ --model.bias true \
--model.loop true \ --model.loop true \
--model.transform tanh \ --model.transform tanh \
--model.dropout {dr} \
--trainer.min_epochs 10 \ --trainer.min_epochs 10 \
--trainer.max_epochs {me} \ --trainer.max_epochs {me} \
--trainer.log_every_n_steps 3 \ --trainer.log_every_n_steps 3 \
@ -92,20 +85,23 @@ python newmain.py fit \
--optimizer torch.optim.{opt} \ --optimizer torch.optim.{opt} \
--optimizer.init_args.lr {lr} \ --optimizer.init_args.lr {lr} \
--trainer.callbacks+ lightning.pytorch.callbacks.LearningRateFinder --trainer.callbacks+ lightning.pytorch.callbacks.LearningRateFinder
"""
# --lr_scheduler lightning.pytorch.cli.ReduceLROnPlateau \ # --lr_scheduler lightning.pytorch.cli.ReduceLROnPlateau \
# --lr_scheduler.init_args.monitor hp_metric \ # --lr_scheduler.init_args.monitor hp_metric \
# --lr_scheduler.init_args.factor 0.05 \ # --lr_scheduler.init_args.factor 0.05 \
# --lr_scheduler.init_args.patience 5 \ # --lr_scheduler.init_args.patience 5 \
# --lr_scheduler.init_args.cooldown 10 \ # --lr_scheduler.init_args.cooldown 10 \
# --lr_scheduler.init_args.verbose true # --lr_scheduler.init_args.verbose true
"""
# job_name = f"color2_{bs}_{a}_{lr:2.2e}"
# job_plugin.run(cmd, machine=Machine.T4, name=job_name)
print(f"Running {params}: {cmd}") print(f"Running {params}: {cmd}")
try: try:
studio = Studio("colors-animate-jobs")
studio.install_plugin("jobs")
job_plugin = studio.installed_plugins["jobs"]
job_name = f"hour-colors-20240303-{idx+1}"
job_plugin.run(cmd, machine=Machine.T4, name=job_name)
# Run the command and wait for it to complete # Run the command and wait for it to complete
# subprocess.run(test_cmd, shell=True, check=True) # subprocess.run(cmd, shell=True, check=True)
subprocess.run(cmd, shell=True, check=True)
except KeyboardInterrupt: except KeyboardInterrupt:
print("Interrupted by user") print("Interrupted by user")
sys.exit(1) sys.exit(1)

16
color_poster.py → scripts/color_poster.py

@ -3,9 +3,14 @@ from typing import List
import matplotlib.colors as mcolors import matplotlib.colors as mcolors
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from matplotlib.font_manager import FontProperties
pt_mono_font = FontProperties(
fname="/usr/share/fonts/truetype/PT_Mono/PTMono-Regular.ttf"
)
# set font by default to courier new # set font by default to courier new
plt.rcParams["font.family"] = "PT Mono" # plt.rcParams["font.family"] = "PT Mono"
# # sort by the proximity to the colors in viridis # # sort by the proximity to the colors in viridis
# # Importing necessary functions # # Importing necessary functions
@ -63,6 +68,7 @@ def create_color_calibration_image(
color.replace("xkcd:", ""), color.replace("xkcd:", ""),
va="center", va="center",
fontsize=fontsize, fontsize=fontsize,
fontproperties=pt_mono_font,
# bbox=dict(facecolor='gray', alpha=0.21), # bbox=dict(facecolor='gray', alpha=0.21),
) )
ax.text( ax.text(
@ -71,6 +77,7 @@ def create_color_calibration_image(
f"{hex_code}\n({rgb_triple})", f"{hex_code}\n({rgb_triple})",
va="center", va="center",
fontsize=6, fontsize=6,
fontproperties=pt_mono_font,
# bbox=dict(facecolor='gray', alpha=0.33), # bbox=dict(facecolor='gray', alpha=0.33),
) )
# ax.text( # ax.text(
@ -79,6 +86,7 @@ def create_color_calibration_image(
# f"{hex_code}", # f"{hex_code}",
# va="center", # va="center",
# fontsize=fontsize * 0.6, # fontsize=fontsize * 0.6,
# fontproperties=pt_mono_font,
# ) # )
# Draw color square # Draw color square
@ -160,14 +168,14 @@ if __name__ == "__main__":
"--rows", type=int, default=73, help="Number of entries per column" "--rows", type=int, default=73, help="Number of entries per column"
) )
parser.add_argument( parser.add_argument(
"--dir", type=str, default="/Volumes/TMP/tests", help="Directory to save images" "--dir", type=str, default="~/out_sortcolors", help="Directory to save images"
) )
parser.add_argument( parser.add_argument(
"-k", "-k",
"--kind", "--kind",
type=str, type=str,
nargs="+", nargs="+",
default=["hsv", "lex", "lab", "umap"], default=["hsv", "lex"],
help="Kinds of sorting", help="Kinds of sorting",
) )
parser.add_argument( parser.add_argument(
@ -201,7 +209,7 @@ if __name__ == "__main__":
# KIND = "hsv" # choose from umap, hsv # KIND = "hsv" # choose from umap, hsv
for KIND in KINDS: for KIND in KINDS:
colors = list(mcolors.XKCD_COLORS.keys()) colors = list(mcolors.XKCD_COLORS.keys())
sorted_indices = np.load(f"scripts/{KIND}_sorted_indices.npy") sorted_indices = np.load(f"/teamspace/studios/this_studio/out_sortcolors/{KIND}/sorted_indices.npy")
sorted_colors = [colors[idx] for idx in sorted_indices] sorted_colors = [colors[idx] for idx in sorted_indices]
colors = sorted_colors colors = sorted_colors

23
scripts/grab.sh

@ -0,0 +1,23 @@
#!/bin/bash
# Define the function to run the scp command for a specific value of j
run_scp() {
# studio id
id=$1
# version number
j=$2
# job prefix
job=hour-colors-20240303-${j}
# name of file (locally)
out=hour-a${j}.mp4
# name of file (remotely)
input=colors/lightning_logs/version_0/a0.mp4
scp ${id}@ssh.lightning.ai:/teamspace/jobs/${job}/work/${input} ${out}
}
# Export the function so that it can be used by parallel
export -f run_scp
# Run scp command in parallel with 2 threads for j in 1 and 2
parallel -j 2 run_scp ::: {1..3}

44
scripts/install_ptmono.sh

@ -0,0 +1,44 @@
#!/bin/bash
# Source: https://blog.programster.org/ubuntu-install-pt-mono-font
# Installs PT Mono font onto Ubuntu 12.04 or 14.04 Systems
# Check to make sure the user has the unzip package installed
export NO_UNZIP=$(apt-cache policy unzip | grep "Installed: (none)" | wc -l)
# Result will be 1 if it is NOT installed
if [ "$NO_UNZIP" = "0" ]; then
export TEMP_DIR='temp-technostu-script'
cd ~
mkdir $TEMP_DIR
cd $TEMP_DIR
# Download PT mono from google fonts
export FONT_URL="http://www.google.com/fonts/download"
export FONT_URL="$FONT_URL?kit=7qsh9BNBJbZ6khIbS3ZpfKCWcynf_cDxXwCLxiixG1c"
wget --content-disposition "$FONT_URL"
# Create a PT_Mono directory which we will copy across into the fonts directory.
mkdir PT_Mono
mv PT_Mono.zip PT_Mono/.
cd PT_Mono
unzip PT_Mono.zip
rm PT_Mono.zip
cd ..
sudo mv PT_Mono /usr/share/fonts/truetype/.
# Re-cache the fonts
echo 'Re-caching fonts...'
sudo fc-cache -fv
# cleanup
cd ~
sudo rm -rf $TEMP_DIR
echo 'done!'
else
# User doesnt have unzip installed, tell them how to install it
echo 'You need to install unzip for this to work: try '
echo '"sudo apt-get install unzip"'
fi

40
scripts/sortcolor.py

@ -82,11 +82,20 @@ def peano_curve(n):
if KIND in ("lex", "alpha", "abc"): if KIND in ("lex", "alpha", "abc"):
KIND = "lex"
preds = np.array(colors) preds = np.array(colors)
elif KIND == "umap": elif KIND == "umap":
PDIR = f"/teamspace/studios/this_studio/out_sortcolors/{KIND}"
Path(PDIR).mkdir(parents=True, exist_ok=True)
file_path = f"{PDIR}/{SEED:06d}.npy"
if Path(file_path).exists():
print(f"Loading {file_path}")
preds = np.load(file_path)
else:
# from umap import UMAP # from umap import UMAP
from cuml import UMAP from cuml import UMAP # not fully deterministic.
# Use UMAP to create a 1D representation # Use UMAP to create a 1D representation
reducer = UMAP( reducer = UMAP(
@ -102,6 +111,9 @@ elif KIND == "umap":
# Sort colors by the 1D representation # Sort colors by the 1D representation
preds = embedding[:, 0] preds = embedding[:, 0]
del reducer, embedding del reducer, embedding
# Save the preds to disk
print(f"Saving {file_path}")
np.save(file_path, preds.ravel())
elif KIND in ("cielab", "lab", "ciede2000"): elif KIND in ("cielab", "lab", "ciede2000"):
from skimage.color import deltaE_ciede2000, rgb2lab from skimage.color import deltaE_ciede2000, rgb2lab
@ -135,18 +147,15 @@ elif KIND == "hsv":
else: else:
raise ValueError(f"Unknown kind: {KIND}") raise ValueError(f"Unknown kind: {KIND}")
sorted_indices = np.argsort(preds)
# Save the sorted indices to disk PDIR = f"/teamspace/studios/this_studio/out_sortcolors/{KIND}"
# if (KIND == "umap") or (KIND != "umap"):
PDIR = f"scripts/{KIND}"
Path(PDIR).mkdir(parents=True, exist_ok=True) Path(PDIR).mkdir(parents=True, exist_ok=True)
file_path = f"{PDIR}/{SEED:06d}.npy" file_path = f"{PDIR}/sorted_indices.npy"
np.save(file_path, preds.ravel())
print(f"Predictions saved to {file_path}")
# Sort colors by the 1D representation # Sort colors by the 1D representation
sorted_indices = np.argsort(preds)
sorted_colors = [colors[i] for i in sorted_indices] sorted_colors = [colors[i] for i in sorted_indices]
print(f"Saving {file_path}")
np.save(file_path, sorted_indices.ravel())
# # Display the sorted colors around the ring of a circle # # Display the sorted colors around the ring of a circle
# # Create a new figure for the circle visualization # # Create a new figure for the circle visualization
@ -215,9 +224,9 @@ def plot_preds(
rgb_values, rgb_values,
fname: str, fname: str,
roll: bool = False, roll: bool = False,
dpi: int = 150, radius: float = 1 / 3,
inner_radius: float = 1 / 3, dpi: int = 300,
figsize=(3, 3), figsize=(6, 6),
): ):
sorted_inds = np.argsort(preds.ravel()) sorted_inds = np.argsort(preds.ravel())
colors = rgb_values[sorted_inds, :3] colors = rgb_values[sorted_inds, :3]
@ -261,12 +270,11 @@ def plot_preds(
ax.set_yticks([]) ax.set_yticks([])
ax.set_aspect("equal") ax.set_aspect("equal")
ax.axis("off") ax.axis("off")
radius = 1 ax.set_ylim(0, 1)
ax.set_ylim(0, radius)
# Overlay white circle # Overlay white circle
circle = patches.Circle( circle = patches.Circle(
(0, 0), inner_radius, transform=ax.transData._b, color="white", zorder=2 (0, 0), radius, transform=ax.transData._b, color="white", zorder=2
) )
ax.add_patch(circle) ax.add_patch(circle)
@ -294,7 +302,7 @@ plot_preds(
fname, fname,
roll=False, roll=False,
dpi=DPI, dpi=DPI,
inner_radius=INNER_RADIUS, radius=INNER_RADIUS,
figsize=(SIZE, SIZE), figsize=(SIZE, SIZE),
) )
print(f"saved {fname}") print(f"saved {fname}")

Loading…
Cancel
Save