com.simiacryptus.mindseye.applications.ArtistryUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.simiacryptus.mindseye.applications.ArtistryUtil.java

Source

/*
 * Copyright (c) 2018 by Andrew Charneski.
 *
 * The author licenses this file to you under the
 * Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance
 * with the License.  You may obtain a copy
 * of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.simiacryptus.mindseye.applications;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.simiacryptus.mindseye.lang.Layer;
import com.simiacryptus.mindseye.lang.Tensor;
import com.simiacryptus.mindseye.lang.cudnn.MultiPrecision;
import com.simiacryptus.mindseye.lang.cudnn.Precision;
import com.simiacryptus.mindseye.layers.cudnn.ActivationLayer;
import com.simiacryptus.mindseye.layers.cudnn.BandAvgReducerLayer;
import com.simiacryptus.mindseye.layers.cudnn.BandReducerLayer;
import com.simiacryptus.mindseye.layers.cudnn.BinarySumLayer;
import com.simiacryptus.mindseye.layers.cudnn.GramianLayer;
import com.simiacryptus.mindseye.layers.cudnn.ImgBandBiasLayer;
import com.simiacryptus.mindseye.layers.cudnn.ImgTileCycleLayer;
import com.simiacryptus.mindseye.layers.cudnn.PoolingLayer;
import com.simiacryptus.mindseye.layers.cudnn.SquareActivationLayer;
import com.simiacryptus.mindseye.layers.cudnn.conv.ConvolutionLayer;
import com.simiacryptus.mindseye.layers.java.AvgReducerLayer;
import com.simiacryptus.mindseye.layers.java.ImgTileSubnetLayer;
import com.simiacryptus.mindseye.layers.java.LinearActivationLayer;
import com.simiacryptus.mindseye.network.DAGNetwork;
import com.simiacryptus.mindseye.network.DAGNode;
import com.simiacryptus.mindseye.network.PipelineNetwork;
import com.simiacryptus.mindseye.test.PCAUtil;
import com.simiacryptus.mindseye.test.TestUtil;
import com.simiacryptus.util.FastRandom;
import com.simiacryptus.util.FileNanoHTTPD;
import com.simiacryptus.util.data.DoubleStatistics;
import com.simiacryptus.util.io.JsonUtil;
import com.simiacryptus.util.io.NotebookOutput;
import com.simiacryptus.util.lang.Tuple2;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.hadoop.yarn.webapp.MimeType;

import javax.annotation.Nonnull;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.function.DoubleUnaryOperator;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * The type Artistry util.
 */
public class ArtistryUtil {
    /**
     * Add layers handler.
     *
     * @param painterNetwork the painter network
     * @param server         the server
     */
    public static void addLayersHandler(final DAGNetwork painterNetwork, final FileNanoHTTPD server) {
        if (null != server)
            server.addHandler("layers.json", MimeType.JSON, out -> {
                try {
                    JsonUtil.getMapper().writer().writeValue(out, TestUtil.samplePerformance(painterNetwork));
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
    }

    /**
     * Gram pipeline network.
     *
     * @param network      the network
     * @param mean         the mean
     * @param pcaTransform the pca transform
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork gram(final PipelineNetwork network, Tensor mean, Tensor pcaTransform) {
        int[] dimensions = pcaTransform.getDimensions();
        int inputBands = mean.getDimensions()[2];
        int pcaBands = dimensions[2];
        int outputBands = pcaBands / inputBands;
        int width = dimensions[0];
        int height = dimensions[1];
        network.wrap(new ImgBandBiasLayer(mean.scale(-1)));
        network.wrap(new ConvolutionLayer(width, height, inputBands, outputBands).set(pcaTransform));
        network.wrap(new GramianLayer());
        return network;
    }

    /**
     * Square avg pipeline network.
     *
     * @param network      the network
     * @param mean         the mean
     * @param pcaTransform the pca transform
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork squareAvg(final PipelineNetwork network, Tensor mean, Tensor pcaTransform) {
        int[] dimensions = pcaTransform.getDimensions();
        int inputBands = mean.getDimensions()[2];
        int pcaBands = dimensions[2];
        int outputBands = pcaBands / inputBands;
        int width = dimensions[0];
        int height = dimensions[1];
        network.wrap(new ImgBandBiasLayer(mean.scale(-1)));
        network.wrap(new ConvolutionLayer(width, height, inputBands, outputBands).set(pcaTransform));
        network.wrap(new SquareActivationLayer());
        network.wrap(new BandAvgReducerLayer());
        return network;
    }

    /**
     * Paint low res.
     *
     * @param canvas the canvas
     * @param scale  the scale
     */
    public static void paint_LowRes(final Tensor canvas, final int scale) {
        BufferedImage originalImage = canvas.toImage();
        canvas.set(Tensor
                .fromRGB(TestUtil.resize(TestUtil.resize(originalImage, originalImage.getWidth() / scale, true),
                        originalImage.getWidth(), originalImage.getHeight())));
    }

    /**
     * Paint lines.
     *
     * @param canvas the canvas
     */
    public static void paint_Lines(final Tensor canvas) {
        BufferedImage originalImage = canvas.toImage();
        BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(),
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = (Graphics2D) newImage.getGraphics();
        IntStream.range(0, 100).forEach(i -> {
            Random random = new Random();
            graphics.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
            graphics.drawLine(random.nextInt(originalImage.getWidth()), random.nextInt(originalImage.getHeight()),
                    random.nextInt(originalImage.getWidth()), random.nextInt(originalImage.getHeight()));
        });
        canvas.set(Tensor.fromRGB(newImage));
    }

    /**
     * Paint circles.
     *
     * @param canvas the canvas
     * @param scale  the scale
     */
    public static void paint_Circles(final Tensor canvas, final int scale) {
        BufferedImage originalImage = canvas.toImage();
        BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(),
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = (Graphics2D) newImage.getGraphics();
        IntStream.range(0, 10000).forEach(i -> {
            Random random = new Random();
            int positionX = random.nextInt(originalImage.getWidth());
            int positionY = random.nextInt(originalImage.getHeight());
            int width = 1 + random.nextInt(2 * scale);
            int height = 1 + random.nextInt(2 * scale);
            DoubleStatistics[] stats = { new DoubleStatistics(), new DoubleStatistics(), new DoubleStatistics() };
            canvas.coordStream(false).filter(c -> {
                int[] coords = c.getCoords();
                int x = coords[0];
                int y = coords[1];
                double relX = Math.pow(1 - 2 * ((double) (x - positionX) / width), 2);
                double relY = Math.pow(1 - 2 * ((double) (y - positionY) / height), 2);
                return relX + relY < 1.0;
            }).forEach(c -> stats[c.getCoords()[2]].accept(canvas.get(c)));
            graphics.setStroke(new Stroke() {
                @Override
                public Shape createStrokedShape(final Shape p) {
                    return null;
                }
            });
            graphics.setColor(new Color((int) stats[0].getAverage(), (int) stats[1].getAverage(),
                    (int) stats[2].getAverage()));
            graphics.fillOval(positionX, positionY, width, height);
        });
        canvas.set(Tensor.fromRGB(newImage));
    }

    /**
     * Paint plasma tensor.
     *
     * @param size           the size
     * @param bands          the bands
     * @param noiseAmplitude the noise amplitude
     * @param noisePower     the noise power
     * @return the tensor
     */
    public static Tensor paint_Plasma(final int size, int bands, final double noiseAmplitude,
            final double noisePower) {
        return expandPlasma(initSquare(bands), size, noiseAmplitude, noisePower);
    }

    @Nonnull
    private static Tensor initSquare(final int bands) {
        Tensor baseColor = new Tensor(1, 1, bands).setByCoord(c -> 100 + 200 * (Math.random() - 0.5));
        return new Tensor(2, 2, bands).setByCoord(c -> baseColor.get(0, 0, c.getCoords()[2]));
    }

    /**
     * Expand plasma tensor.
     *
     * @param image          the image
     * @param width          the width
     * @param noiseAmplitude the noise amplitude
     * @param noisePower     the noise power
     * @return the tensor
     */
    @Nonnull
    public static Tensor expandPlasma(Tensor image, final int width, final double noiseAmplitude,
            final double noisePower) {
        while (image.getDimensions()[0] < width) {
            Tensor newImage = expandPlasma(image, Math.pow(noiseAmplitude / image.getDimensions()[0], noisePower));
            image.freeRef();
            image = newImage;

        }
        return Tensor.fromRGB(TestUtil.resize(image.toImage(), width, true));
    }

    /**
     * Expand plasma tensor.
     *
     * @param seed  the seed
     * @param noise the noise
     * @return the tensor
     */
    public static Tensor expandPlasma(final Tensor seed, double noise) {
        int bands = seed.getDimensions()[2];
        int width = seed.getDimensions()[0] * 2;
        int height = seed.getDimensions()[1] * 2;
        Tensor returnValue = new Tensor(width, height, bands);
        DoubleUnaryOperator fn1 = x -> Math.max(Math.min(x + noise * (Math.random() - 0.5), 255), 0);
        DoubleUnaryOperator fn2 = x -> Math.max(Math.min(x + Math.sqrt(2) * noise * (Math.random() - 0.5), 255), 0);
        IntUnaryOperator addrX = x -> {
            while (x >= width)
                x -= width;
            while (x < 0)
                x += width;
            return x;
        };
        IntUnaryOperator addrY = x -> {
            while (x >= height)
                x -= height;
            while (x < 0)
                x += height;
            return x;
        };
        for (int band = 0; band < bands; band++) {
            for (int x = 0; x < width; x += 2) {
                for (int y = 0; y < height; y += 2) {
                    double value = seed.get(x / 2, y / 2, band);
                    returnValue.set(x, y, band, value);
                }
            }
            for (int x = 1; x < width; x += 2) {
                for (int y = 1; y < height; y += 2) {
                    double value = (returnValue.get(addrX.applyAsInt(x - 1), addrY.applyAsInt(y - 1), band))
                            + (returnValue.get(addrX.applyAsInt(x - 1), addrY.applyAsInt(y + 1), band))
                            + (returnValue.get(addrX.applyAsInt(x + 1), addrY.applyAsInt(y - 1), band))
                            + (returnValue.get(addrX.applyAsInt(x + 1), addrY.applyAsInt(y + 1), band));
                    value = fn2.applyAsDouble(value / 4);
                    returnValue.set(x, y, band, value);
                }
            }
            for (int x = 0; x < width; x += 2) {
                for (int y = 1; y < height; y += 2) {
                    double value = (returnValue.get(addrX.applyAsInt(x - 1), addrY.applyAsInt(y), band))
                            + (returnValue.get(addrX.applyAsInt(x + 1), addrY.applyAsInt(y), band))
                            + (returnValue.get(addrX.applyAsInt(x), addrY.applyAsInt(y - 1), band))
                            + (returnValue.get(addrX.applyAsInt(x), addrY.applyAsInt(y + 1), band));
                    value = fn1.applyAsDouble(value / 4);
                    returnValue.set(x, y, band, value);
                }
            }
            for (int x = 1; x < width; x += 2) {
                for (int y = 0; y < height; y += 2) {
                    double value = (returnValue.get(addrX.applyAsInt(x - 1), addrY.applyAsInt(y), band))
                            + (returnValue.get(addrX.applyAsInt(x + 1), addrY.applyAsInt(y), band))
                            + (returnValue.get(addrX.applyAsInt(x), addrY.applyAsInt(y - 1), band))
                            + (returnValue.get(addrX.applyAsInt(x), addrY.applyAsInt(y + 1), band));
                    value = fn1.applyAsDouble(value / 4);
                    returnValue.set(x, y, band, value);
                }
            }
        }
        return returnValue;
    }

    /**
     * Avg pipeline network.
     *
     * @param network the network
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork avg(final PipelineNetwork network) {
        network.wrap(new BandReducerLayer().setMode(PoolingLayer.PoolingMode.Avg));
        return network;
    }

    /**
     * With clamp pipeline network.
     *
     * @param network1 the network 1
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork withClamp(final PipelineNetwork network1) {
        PipelineNetwork network = new PipelineNetwork(1);
        network.wrap(getClamp(255));
        network.wrap(network1);
        return network;
    }

    /**
     * Sets precision.
     *
     * @param network   the network
     * @param precision the precision
     */
    public static void setPrecision(final DAGNetwork network, final Precision precision) {
        network.visitLayers(layer -> {
            if (layer instanceof MultiPrecision) {
                ((MultiPrecision) layer).setPrecision(precision);
            }
        });
    }

    /**
     * Pca tensor.
     *
     * @param cov   the cov
     * @param power the power
     * @return the tensor
     */
    @Nonnull
    public static Tensor pca(final Tensor cov, final double power) {
        final int inputbands = (int) Math.sqrt(cov.getDimensions()[2]);
        final int outputbands = inputbands;
        Array2DRowRealMatrix realMatrix = new Array2DRowRealMatrix(inputbands, inputbands);
        cov.coordStream(false).forEach(c -> {
            double v = cov.get(c);
            int x = c.getIndex() % inputbands;
            int y = (c.getIndex() - x) / inputbands;
            realMatrix.setEntry(x, y, v);
        });
        Tensor[] features = PCAUtil.pcaFeatures(realMatrix, outputbands, new int[] { 1, 1, inputbands }, power);
        Tensor kernel = new Tensor(1, 1, inputbands * outputbands);
        PCAUtil.populatePCAKernel_1(kernel, features);
        return kernel;
    }

    /**
     * Gets clamp.
     *
     * @param max the max
     * @return the clamp
     */
    @Nonnull
    public static PipelineNetwork getClamp(final int max) {
        @Nonnull
        PipelineNetwork clamp = new PipelineNetwork(1);
        clamp.add(new ActivationLayer(ActivationLayer.Mode.RELU));
        clamp.add(new LinearActivationLayer().setBias(max).setScale(-1).freeze());
        clamp.add(new ActivationLayer(ActivationLayer.Mode.RELU));
        clamp.add(new LinearActivationLayer().setBias(max).setScale(-1).freeze());
        return clamp;
    }

    /**
     * To json string.
     *
     * @param obj the style parameters
     * @return the string
     */
    public static CharSequence toJson(final Object obj) {
        String json;
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
            json = mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return json;
    }

    /**
     * Load buffered image.
     *
     * @param image the style
     * @return the buffered image
     */
    @Nonnull
    public static BufferedImage load(final CharSequence image) {
        return HadoopUtil.getImage(image);
    }

    /**
     * Load buffered image.
     *
     * @param image     the image
     * @param imageSize the image size
     * @return the buffered image
     */
    @Nonnull
    public static BufferedImage load(final CharSequence image, final int imageSize) {
        return TestUtil.resize(HadoopUtil.getImage(image), imageSize, true);
    }

    /**
     * Load buffered image.
     *
     * @param image  the image
     * @param width  the width
     * @param height the height
     * @return the buffered image
     */
    @Nonnull
    public static BufferedImage load(final CharSequence image, final int width, final int height) {
        BufferedImage bufferedImage = HadoopUtil.getImage(image);
        bufferedImage = TestUtil.resize(bufferedImage, width, height);
        return bufferedImage;
    }

    /**
     * Gram pipeline network.
     *
     * @param network the network
     * @param mean    the mean
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork gram(final Layer network, Tensor mean) {
        if (!(network instanceof PipelineNetwork)) {
            PipelineNetwork pipelineNetwork = new PipelineNetwork();
            pipelineNetwork.wrap(network);
            return gram(pipelineNetwork, mean);
        } else {
            PipelineNetwork pipelineNetwork = (PipelineNetwork) network;
            pipelineNetwork.wrap(new ImgBandBiasLayer(mean.scale(-1)));
            pipelineNetwork.wrap(new GramianLayer());
            return pipelineNetwork;
        }
    }

    /**
     * Gram pipeline network.
     *
     * @param network the network
     * @return the pipeline network
     */
    @Nonnull
    public static PipelineNetwork gram(final Layer network) {
        if (!(network instanceof PipelineNetwork)) {
            PipelineNetwork pipelineNetwork = new PipelineNetwork();
            pipelineNetwork.wrap(pipelineNetwork);
            return gram(pipelineNetwork);
        } else {
            PipelineNetwork pipelineNetwork = (PipelineNetwork) network;
            pipelineNetwork.wrap(new GramianLayer());
            return pipelineNetwork;
        }
    }

    /**
     * Randomize buffered image.
     *
     * @param contentImage the content image
     * @return the buffered image
     */
    @Nonnull
    public static BufferedImage randomize(final BufferedImage contentImage) {
        return randomize(contentImage, x -> FastRandom.INSTANCE.random());
    }

    /**
     * Randomize buffered image.
     *
     * @param contentImage the content image
     * @param f            the f
     * @return the buffered image
     */
    @Nonnull
    public static BufferedImage randomize(final BufferedImage contentImage, final DoubleUnaryOperator f) {
        return Tensor.fromRGB(contentImage).map(f).toRgbImage();
    }

    /**
     * Paint noise.
     *
     * @param canvas the canvas
     */
    public static void paint_noise(final Tensor canvas) {
        canvas.setByCoord(c -> FastRandom.INSTANCE.random());
    }

    /**
     * Wrap avg layer.
     *
     * @param subnet the subnet
     * @return the layer
     */
    protected static Layer wrapAvg(final Layer subnet) {
        PipelineNetwork network = new PipelineNetwork(1);
        network.wrap(subnet);
        network.wrap(new BandAvgReducerLayer());
        return network;
    }

    protected static Layer wrapTiledAvg(final Layer subnet, final int size) {
        return wrapAvg(new ImgTileSubnetLayer(subnet, size, size, size, size));
    }

    /**
     * Log exception with default t.
     *
     * @param <T>          the type parameter
     * @param log          the log
     * @param fn           the fn
     * @param defaultValue the default value
     * @return the t
     */
    public static <T> T logExceptionWithDefault(@Nonnull final NotebookOutput log, Supplier<T> fn, T defaultValue) {
        try {
            return fn.get();
        } catch (Throwable throwable) {
            try {
                log.code(() -> {
                    return throwable;
                });
            } catch (Throwable e2) {
            }
            return defaultValue;
        }
    }

    /**
     * Reduce.
     *
     * @param network               the network
     * @param functions             the functions
     * @param parallelLossFunctions the parallel loss functions
     */
    public static void reduce(final PipelineNetwork network, final List<Tuple2<Double, DAGNode>> functions,
            final boolean parallelLossFunctions) {
        functions.stream().filter(x -> x._1 != 0).reduce((a, b) -> {
            return new Tuple2<>(1.0,
                    network.wrap(new BinarySumLayer(a._1, b._1), a._2, b._2).setParallel(parallelLossFunctions));
        }).get();
    }

    /**
     * Gets files.
     *
     * @param file the file
     * @return the files
     */
    public static List<CharSequence> getHadoopFiles(CharSequence file) {
        return HadoopUtil.getFiles(file);
    }

    /**
     * Gets local files.
     *
     * @param file the file
     * @return the local files
     */
    public static List<CharSequence> getLocalFiles(CharSequence file) {
        File[] array = new File(file.toString()).listFiles();
        if (null == array)
            throw new IllegalArgumentException("Not Found: " + file);
        return Arrays.stream(array).map(File::getAbsolutePath).sorted(Comparator.naturalOrder())
                .collect(Collectors.toList());
    }

    /**
     * Tile cycle pipeline network.
     *
     * @param network the network
     * @return the pipeline network
     */
    public static PipelineNetwork tileCycle(final PipelineNetwork network) {
        PipelineNetwork netNet = new PipelineNetwork(1);
        netNet.wrap(new AvgReducerLayer(), netNet.wrap(network, netNet.getInput(0)),
                netNet.wrap(network, netNet.wrap(new ImgTileCycleLayer(), netNet.getInput(0))));
        return netNet;
    }
}