def download(args): """Downloads one or more image files to local computer. If a range of run ids is provided then files are saved to a folder named according to the range. Args: args: A single run id or a range of run ids in the form [start]-[end] Raises: RuntimeError: If arguments are missing or illegal """ if len(args) is not 1: raise RuntimeError( "The download command requires a single parameter specifying a run number or a range" ) run_numbers = [] arg = args[0] range_requested = "-" in arg if range_requested: start, end = arg.split("-") if not utils.isinteger(start) or not utils.isinteger(end): raise ValueError("Run number must be an integer") for run_num in range(int(start), int(end) + 1): if run_num not in run_numbers: run_numbers.append(run_num) else: if not utils.isinteger(arg): raise ValueError("Run number must be an integer") run_number = int(arg) if run_number not in run_numbers: run_numbers.append(run_number) create_folder = len(run_numbers) > 1 if create_folder: output_dir = localfs.filepath(paths["resultsDirLocal"], "result-{}".format(arg)) if localfs.exists(output_dir): localfs.rm(output_dir) localfs.mkdir(output_dir) else: output_dir = paths["resultsDirLocal"] log("Fetching remote files...") if not localfs.exists(paths["resultsDirLocal"]): localfs.mkdir(paths["resultsDirLocal"]) for run_number in run_numbers: spell.download( "runs/{}/image_output/result/result.png".format(run_number)) target_path = localfs.filepath(output_dir, "result-{}.png".format(run_number)) localfs.mv("result.png", target_path) log("Saved result file [{}]".format(target_path))
def _transfer(img_group_name, neural_args): imgs_base_dir = "{}/{}".format(paths["imagesBaseRemote"], img_group_name) style_imgs_dir = "{}/{}".format(imgs_base_dir, "styles") style_imgs = spell.ls(style_imgs_dir) content_img_dir = "{}/{}".format(imgs_base_dir, "content") content_img = spell.ls(content_img_dir)[0] neural_style_cmd = _neural_style_cmd(neural_args, style_imgs, content_img) run = spell.client.runs.new( command=neural_style_cmd, machine_type="K80", github_url="https://github.com/ebranda/neural-style-tf", attached_resources=_mounts(img_group_name)) spell.wait_until_running(run) run_id = spell.get_id(run) spell.label_run(run, "Style Transfer single") logFilePath = localfs.filepath(paths["resultsDirLocal"], "log-run-{}.txt".format(run_id)) with open(logFilePath, "w") as f: f.write("{} = {}\n".format("Run ID", run_id)) f.write("{} = {}\n".format("Command", "python {}".format(" ".join(sys.argv)))) f.write("{} = {}\n".format("Parameters", neural_args)) f.write("{} = {}\n".format("Image group", img_group_name)) f.write("{} = {}\n".format("Style images", " ".join(style_imgs))) f.write("{} = {}\n".format("Content image", content_img)) log(spell.get_run_started_message(run)) return run_id
def create_pair(output_dir_path, img_a_path, img_b_path, img_a_name, img_b_name): img_a = Image.open(img_a_path) img_b = Image.open(img_b_path) widths, heights = zip(*(i.size for i in [img_a, img_b])) img_pair = Image.new('RGB', (sum(widths), max(heights))) img_pair.paste(img_a, (0, 0)) img_pair.paste(img_b, (img_a.size[0], 0)) img_pair.save(fs.filepath(output_dir_path, img_a_name))
def export(args, machine_type="CPU"): """Runs a pix2pix model export job on Spell. Automatically downloads the finished model to the local "models" directory. Args: args: The command arguments. Should contain only the run id from the training run. If no run id is provided then the last run id is retrieved from the local cache. machine_type: The machine type to use. Defaults to "CPU". Raises: ValueError: If run id argument is not an integer. RuntimeError: If no run id argument is provided or found in cache. """ run_id = _fetch_run_id(args, 0, "pix2pixTrainingRunId") spell.validate_machine_type(machine_type) # Build and run the commands. Bundle the two required # commands into one Spell run to simplify management. pix2pix_export_cmd = "python pix2pix.py \ --mode export \ --output_dir output/ \ --checkpoint input_model/ \ --which_direction BtoA" pix2pix_convert_cmd = "python server/tools/export-checkpoint.py \ --checkpoint output \ --output_file output/model.pict" log("Converting model. Please wait...") run = spell.client.runs.new( command=pix2pix_export_cmd + ";" + pix2pix_convert_cmd, machine_type=machine_type, github_url="https://github.com/affinelayer/pix2pix-tensorflow.git", attached_resources={"runs/{}/output".format(run_id): "input_model"}) spell.label_run(run, "Pix2Pix export") spell.wait_until_complete(run) # Download the model file now that the run is complete. log("Export complete. Downloading model pict file...") run.cp("output/model.pict", localfs.filepath("models", "pix2pix")) msg = "Download complete. The model.pict file in the models directory " msg += "{} is ready for use in tensorflowjs." log(msg.format(localfs.filepath("models", "pix2pix")))
def hyperparam_search(args): log("Building hyperparameter grid. Please wait...") img_group_name = getstr(args, 0) imgs_base_dir = localfs.filepath(paths["imagesBaseLocal"], img_group_name) style_imgs_dir = localfs.filepath(imgs_base_dir, "styles") style_imgs = localfs.ls(style_imgs_dir) content_img_dir = localfs.filepath(imgs_base_dir, "content") content_img = localfs.ls(content_img_dir)[0] neural_args = params.neural_style_hypergrid neural_style_cmd = _neural_style_cmd(neural_args, style_imgs, content_img) neural_style_cmd += " --style_weight :STYLE_WEIGHT:" neural_style_cmd += " --temporal_weight :TEMPORAL_WEIGHT:" search = spell.client.hyper.new_grid_search( { #"STYLE_WEIGHT": spell.get_value_spec(["1e4","1e1","1e7"]), #"TEMPORAL_WEIGHT": spell.get_value_spec(["2e2","2e6","2e-2"]) "STYLE_WEIGHT": spell.get_value_spec(neural_args.style_weights), "TEMPORAL_WEIGHT": spell.get_value_spec( neural_args.temporal_weights) }, command=neural_style_cmd, machine_type="K80", github_url="https://github.com/cysmith/neural-style-tf", attached_resources=_mounts(img_group_name)) for run in search.runs: spell.label_run(run, "Style Transfer hyperparams") logFilePath = localfs.filepath(paths["resultsDirLocal"], "log-hyperparams-{}.txt".format(search.id)) with open(logFilePath, "w") as f: f.write("{} = {}\n".format("Search ID", search.id)) f.write("{} = {}\n".format( "Command", "python " + sys.argv[0] + " sthyperparams " + (" ".join(args)))) f.write("{} = {}\n".format("Image group", img_group_name)) f.write("{} = {}\n".format("Parameters", neural_args)) f.write("{} = {}\n".format("Style images", " ".join(style_imgs))) f.write("{} = {}\n".format("Content image", content_img)) msg = "Hyperparameter search {} has started. Visit https://web.spell.run/{}/hyper-searches/{} for progress." msg += "\nWhen all runs have completed, execute 'python run.py stdownload {}-{}'" msg += "\nto download the result files." log( msg.format(search.id, spell.get_username(), search.id, search.runs[0].id, search.runs[-1].id))
def download_latest(args): """Downloads the most recent output image from a training run. Args: args: The command arguments. Accepts a single run id argument. If no argument is provided then we try to retrieve the id from the cache file created during the last training run. Raises: ValueError: If run id argument is not an integer. RuntimeError: If no run id argument is provided or found in cache. """ run_id = _fetch_run_id(args, 0, "pix2pixTrainingRunId") log("Downloading latest training output image from run {}...".format( run_id)) remote_dir = "runs/{}/output/images".format(run_id) if not spell.exists(remote_dir): log("No server output directory available yet.") return def get_output_file(): listing = spell.ls(remote_dir) listing.sort() return listing[-2] f = get_output_file() attempts = 0 while "output" not in f and attempts < 10: f = get_output_file() attempts += 1 if "output" not in f: raise RuntimeError("Unable to find an output file on server.") local_dir = localfs.filepath(paths["imageslocal"], "pix2pix-results") spell.download(remote_dir + "/" + f, local_dir) log("Latest output file downloaded to '{}'.".format( localfs.filepath(local_dir, f)))
def _validate_local(): for d in localfs.ls(paths["imagesBaseLocal"]): style_images = localfs.ls( localfs.filepath(paths["imagesBaseLocal"], d, "styles")) content_images = localfs.ls( localfs.filepath(paths["imagesBaseLocal"], d, "content")) if not style_images: raise FileNotFoundError( "Style images folder [{}] is empty.".format( paths["stylesDirLocal"])) if not content_images: raise FileNotFoundError( "Content images folder [{}] is empty.".format( paths["contentDirLocal"])) def validate_filenames(names): for n in names: if " " in n: raise ValueError( "Image file names cannot contain spaces." ) # TODO add non-alphanumeric character checking validate_filenames(style_images) validate_filenames(content_images)
def upload(args): """ Runs a BigGAN image upload job on Spell. """ log("Preparing to upload images...") d = localfs.filepath(paths["datasetLocal"], paths["datasetName"]) if localfs.isempty(d): raise RuntimeError("Missing images in dataset folder "+d) def validate_filenames(names): for n in names: if " " in n: raise ValueError("Image file names cannot contain spaces. [{}]".format(n)) # TODO add non-alphanumeric character checking validate_filenames(localfs.ls(d)) log("Uploading. Please wait...") spell.upload(paths["datasetLocal"], paths["datasetRemoteDir"]) log("Upload complete.")
def extract_subimages(img_path, output_dir_path, subimage_width, subimage_height, num_subimages_x, num_subimages_y, append=False, rotation=0, flip_h=False, flip_v=False): if num_subimages_x < 2 or num_subimages_y < 2: raise ValueError( "number of subimages arguments must be a value greater than 1") if not append: fs.rm(output_dir_path) if not fs.exists(output_dir_path): fs.mkdir(output_dir_path) img = Image.open(img_path) img = rotate(img, rotation) img = flip(img, flip_h, flip_v) img_width, img_height = img.size dx = float(img_width - subimage_width) / (num_subimages_x - 1) dy = float(img_height - subimage_height) / (num_subimages_y - 1) max_num_subimages = num_subimages_x * num_subimages_y counter = len(fs.ls(output_dir_path)) + 1 for j in range(num_subimages_y): for i in range(num_subimages_x): xo = int(round(dx * i)) yo = int(round(dy * j)) subimage = img.crop( (xo, yo, xo + subimage_width, yo + subimage_height)) num_leading_zeros = len(str(max_num_subimages)) + 1 filename = ("{:0" + str(num_leading_zeros) + "d}.png").format(counter) subimage.save(fs.filepath(output_dir_path, filename)) counter += 1
import _thread import time import skimage import os from app import spell from app import utils from app.utils import log from app import filesystem as localfs # https://github.com/taki0112/BigGAN-Tensorflow # ERRORS OUT WITH MEMORY ERROR (posted to Github issues and waiting for reply) paths = { "imagesLocal": localfs.filepath("images"), "datasetLocal": localfs.filepath("images", "big-gan-dataset"), "datasetName": "images", "datasetRemoteDir": "uploads/big-gan-dataset" } def upload(args): """ Runs a BigGAN image upload job on Spell. """ log("Preparing to upload images...") d = localfs.filepath(paths["datasetLocal"], paths["datasetName"]) if localfs.isempty(d): raise RuntimeError("Missing images in dataset folder "+d)
def image_pairs(args): """Builds pairs of images on local computer. Expects two input images, png or jpg, named A and B in the directory images/pix2pix-sources. Exports image pair files to images/pix2pix-dataset. Args: args: The arguments subimage width subimage height number of subimages in x number of subimages in y rotate 180 (default False) flip horizontal (default False) flip vertical (default False) Raises: RuntimeError: If arguments are missing """ log("Preparing to make image pairs...") source_dir = paths["sourceslocal"] source_a = localfs.findfirst(source_dir, ["A.jpg", "A.jpeg", "A.png"]) source_b = localfs.findfirst(source_dir, ["B.jpg", "B.jpeg", "B.png"]) img_path_a = localfs.filepath(source_dir, source_a) img_path_b = localfs.filepath(source_dir, source_b) log(" Image A: {}".format(img_path_a)) log(" Image B: {}".format(img_path_b)) sub_w = getint(args, 0, 0) sub_h = getint(args, 1, 0) num_x = getint(args, 2, 0) num_y = getint(args, 3, 0) rotate = getboolean(args, 4) flip_h = getboolean(args, 5) output_dir_a = localfs.filepath(paths["datasetlocal"], "A") output_dir_b = localfs.filepath(paths["datasetlocal"], "B") log("Extracting subimages...") localfs.rm(paths["datasetlocal"]) localfs.mkdir(paths["datasetlocal"]) def process(img_path, out_dir): imageutils.extract_subimages(img_path, out_dir, sub_w, sub_h, num_x, num_y, False, 0) if rotate: imageutils.extract_subimages(img_path, out_dir, sub_w, sub_h, num_x, num_y, True, 180) if flip_h: imageutils.extract_subimages(img_path, out_dir, sub_w, sub_h, num_x, num_y, True, 180, True) elif flip_h: imageutils.extract_subimages(img_path, out_dir, sub_w, sub_h, num_x, num_y, True, 0, True) process(img_path_a, output_dir_a) process(img_path_b, output_dir_b) log("Building image pairs...") pairs_dir_path = localfs.filepath(paths["datasetlocal"], "pairs") if not localfs.exists(pairs_dir_path): localfs.mkdir(pairs_dir_path) for a, b in zip(localfs.ls(output_dir_a), localfs.ls(output_dir_b)): img_a_path = localfs.filepath(output_dir_a, a) img_b_path = localfs.filepath(output_dir_b, b) imageutils.create_pair(pairs_dir_path, img_a_path, img_b_path, a, b) #localfs.rm(output_dir_a) #localfs.rm(output_dir_b) for fname in localfs.ls(pairs_dir_path): fpath = localfs.filepath(pairs_dir_path, fname) fpath_new = localfs.filepath(paths["datasetlocal"], fname) localfs.mv(fpath, fpath_new) localfs.rm(pairs_dir_path) log("Done. Image pairs are in the directory '{}'".format( paths["datasetlocal"])) log("You can now send the upload command to send the images to Spell.")
import _thread import time import math from app import spell from app import utils from app import imageutils from app.utils import log from app.utils import getint, getboolean, argequals from app import filesystem as localfs # Expects image pairs in dataset directory paths = { "imageslocal": localfs.filepath("images"), "sourceslocal": localfs.filepath("images", "pix2pix-sources"), "datasetlocal": localfs.filepath("images", "pix2pix-dataset"), "datasetremote": "uploads/pix2pix-dataset" } if not localfs.exists(paths["imageslocal"]): localfs.mkdir(paths["imageslocal"]) if not localfs.exists(paths["datasetlocal"]): localfs.mkdir(paths["datasetlocal"]) def image_pairs(args): """Builds pairs of images on local computer. Expects two input images, png or jpg, named A and B in the directory images/pix2pix-sources. Exports image pair files to images/pix2pix-dataset.
import _thread import time import sys import webbrowser from app import utils from app.utils import log, getstr, getint, getfloat, checkint, checknumeric from app import spell from app import filesystem as localfs from app import params images_local = localfs.filepath("images") images_base_local = localfs.filepath(images_local, "style-transfer-images") images_base_remote = "uploads/style-transfer-images" paths = { "imagesLocal": images_local, "imagesBaseLocal": images_base_local, "resultsDirLocal": localfs.filepath("images", "style-transfer-results"), "imagesBaseRemote": images_base_remote, "vggFileRemote": "uploads/models/imagenet-vgg-verydeep-19.mat", "vggFileRemoteName": "imagenet-vgg-verydeep-19.mat" } if not localfs.exists(paths["imagesLocal"]): localfs.mkdir(paths["imagesLocal"]) if not localfs.exists(paths["imagesBaseLocal"]): localfs.mkdir(paths["imagesBaseLocal"]) if not localfs.exists(paths["resultsDirLocal"]): localfs.mkdir(paths["resultsDirLocal"]) def upload():