Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
basedrhys committed Nov 18, 2020
2 parents 57d5664 + 8b38797 commit 174759d
Show file tree
Hide file tree
Showing 50 changed files with 682 additions and 351 deletions.
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
language: java
install: true

# before_install commands required as of https://www.deps.co/guides/travis-ci-latest-java/
matrix:
include:
- jdk: openjdk11
- jdk:
- openjdk8
- openjdk11
before_install:
- sudo rm "${JAVA_HOME}/lib/security/cacerts"
- sudo ln -s /etc/ssl/certs/java/cacerts "${JAVA_HOME}/lib/security/cacerts"
- sudo ./fix-java-verts.sh

before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
Expand Down
2 changes: 2 additions & 0 deletions GUIEditors.props
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ weka.dl4j.inference.Dl4jCNNExplorer=weka.gui.GenericObjectEditor

weka.dl4j.inference.ModelOutputDecoder=weka.gui.GenericObjectEditor

weka.dl4j.inference.CustomModelSetup=weka.gui.GenericObjectEditor

weka.dl4j.interpretability.AbstractCNNSaliencyMapWrapper=weka.gui.GenericObjectEditor


Expand Down
5 changes: 4 additions & 1 deletion GenericPropertiesCreator.props
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,8 @@ weka.dl4j.inference.Dl4jCNNExplorer =\
weka.dl4j.inference.ModelOutputDecoder =\
weka.dl4j.inference

weka.dl4j.inference.CustomModelSetup =\
weka.dl4j.inference

weka.dl4j.interpretability.AbstractCNNSaliencyMapWrapper =\
weka.dl4j.interpretability
weka.dl4j.interpretability
7 changes: 3 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def is_cuda_version_valid = cuda_version in valid_cuda_versions

// Set JDK compatibility
allprojects {
sourceCompatibility = 1.11
targetCompatibility = 1.11
sourceCompatibility = 1.8
targetCompatibility = 1.8
}

/*
Expand Down Expand Up @@ -335,11 +335,10 @@ task travisTest(type: Test) {
}

filter {
// Excluded from travis due to taking too long / using too much memory
// Excluded from travis due to taking too long / using too much memory and throwing OOM exception.
excludeTestsMatching 'ZooModelTest'
excludeTestsMatching 'Dl4jCNNExplorerTest'
excludeTestsMatching 'Dl4jMlpFilterTest'
excludeTestsMatching 'ScoreCAMTest'
}
}

Expand Down
25 changes: 16 additions & 9 deletions docs/examples/dl4j-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ see the results in the output panel, again correctly predicting the target class
$ java weka.Run .Dl4jCNNExplorer \
-decoder ".ModelOutputDecoder -builtIn VGGFACE" \
-zooModel ".Dl4jVGG -variation VGG16 -pretrained VGGFACE" \
-i src/test/resources/images/ben_stiller.jpg
-i $WEKA_HOME/packages/wekaDeeplearning4j/src/test/resources/images/ben_stiller.jpg
```

```bash
Expand Down Expand Up @@ -125,8 +125,11 @@ which you'd like to experiment with; the process is largely the same as above, w

On the `Dl4j Inference` panel, open the `Dl4jCNNExplorer` settings:

- Set `Use serialized model file` to `True`
- Select your previously saved `.model` file as the `Serialized model file`
- Set `Use custom-trained model file` to `True`
- Open the `CustomModelSetup` settings
- Select your previously saved `.model` file as the `Serialized model file`
- Set the input `channels`, `width`, and `height` with the values used to train the model.
These values will be identical to those set on the `ImageInstanceIterator`.
- Open the `ModelOutputDecoder` settings:
- Set `Built in class map` to `CUSTOM`
- Select the `Class map file` on your machine. This can be in two forms:
Expand Down Expand Up @@ -160,12 +163,16 @@ to classify between different dog breeds isn't going to give accurate answers wh

### Command Line

This example uses a custom-trained model which used an `ImageInstanceIterator` using
`channels`, `width`, and `height` of `3`, `56`, `56`, respectively. These values are explicitly
defined in the `CustomModelSetup`.

```bash
$ java weka.Run .Dl4jCNNExplorer \
-decoder ".ModelOutputDecoder -builtIn CUSTOM -classMapFile /path/to/classmap.txt" \
-model-file /path/to/saved/model/Dl4jMlpClassifier.model \
-use-model-file
-i /path/to/input/image.png
-i path/to/image.jpg \
-custom-model ".CustomModelSetup -channels 3 -height 56 -width 56 -model-file path/to/customModel.model" \
-decoder ".ModelOutputDecoder -builtIn CUSTOM -classMapFile path/to/training.arff" \
-useCustomModel
```

## Example 4: Saliency Map Generation
Expand Down Expand Up @@ -245,7 +252,7 @@ know what the class ID may be.

```bash
$ java weka.Run .Dl4jCNNExplorer \
-i "src/test/resources/images/catAndDog.jpg" \
-i "$WEKA_HOME/packages/wekaDeeplearning4j/src/test/resources/images/catAndDog.jpg" \
-generate-map \
-saliency-map ".WekaScoreCAM -bs 8 -normalize -output output_image.png -target-classes -1" \
-zooModel ".KerasResNet -variation RESNET101"
Expand All @@ -255,7 +262,7 @@ $ java weka.Run .Dl4jCNNExplorer \

```bash
$ java weka.Run .Dl4jCNNExplorer \
-i "src/test/resources/images/catAndDog.jpg" \
-i "$WEKA_HOME/packages/wekaDeeplearning4j/src/test/resources/images/catAndDog.jpg" \
-generate-map \
-saliency-map ".WekaScoreCAM -bs 8 -normalize -output output_image.png -target-classes -1,281" \
-zooModel ".KerasResNet -variation RESNET101"
Expand Down
3 changes: 2 additions & 1 deletion docs/examples/featurize-mnist.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ All zoo models have a **default** feature extraction layer, which is typically t
activations, hence why it's set to the default (although you can use any intermediary layer).

`PoolingType` does not need to be specified when using the default activation layer - the outputs are already the
correct dimensionality.
correct dimensionality (`[batch size, num activations]`). If using an intermediary layer the outputs will
typically be of size `[batch size, width, height, num channels]`.

## Example 1: Default MNIST Minimal
The following example walks through using a pretrained ResNet50 (from the Deeplearning4j model zoo)
Expand Down
Binary file modified docs/img/inference/Dl4jCNNExplorer_customModel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/inference/Dl4jCNNExplorer_default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions fix-java-verts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Commands required as of https://www.deps.co/guides/travis-ci-latest-java/
JAVA_FILE="${JAVA_HOME}/lib/security/cacerts"

if [ -f "$JAVA_FILE" ]; then
sudo rm -f "${JAVA_HOME}/lib/security/cacerts"
sudo ln -s /etc/ssl/certs/java/cacerts "${JAVA_HOME}/lib/security/cacerts"
else
echo "Couldn't find java certificates folder, ignoring..."
fi
39 changes: 31 additions & 8 deletions src/main/java/weka/classifiers/functions/Dl4jMlpClassifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.apache.commons.io.output.CountingOutputStream;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.lucene.util.ThreadInterruptedException;
import org.deeplearning4j.datasets.iterator.AsyncDataSetIterator;
import org.deeplearning4j.exception.DL4JException;
import org.deeplearning4j.exception.DL4JInvalidConfigException;
Expand Down Expand Up @@ -65,7 +64,7 @@
import weka.dl4j.enums.CacheMode;
import weka.dl4j.enums.ConvolutionMode;
import weka.dl4j.enums.PoolingType;
import weka.dl4j.enums.PretrainedType;
import weka.dl4j.inference.CustomModelSetup;
import weka.dl4j.iterators.instance.*;
import weka.dl4j.iterators.instance.api.ConvolutionalIterator;
import weka.dl4j.iterators.instance.sequence.text.cnn.CnnTextEmbeddingInstanceIterator;
Expand Down Expand Up @@ -279,7 +278,7 @@ public class Dl4jMlpClassifier extends RandomizableClassifier implements
*/
protected ProgressManager progressManager;

private SwingWorker<Layer[], Layer> layerSwingWorker;
private SwingWorker<Layer[], Void> layerSwingWorker;

public Dl4jMlpClassifier() {
if (!s_cudaMultiGPUSet) {
Expand Down Expand Up @@ -810,6 +809,18 @@ public void setParameterAveragingFrequency(int frequency) {
averagingFrequency = frequency;
}

/**
* Get the name of the loaded model
* @return Model name
*/
public String getModelName() {
if (useZooModel()) {
return getZooModel().getPrettyName();
} else {
return "Custom trained Dl4jMlpClassifier";
}
}

/**
* The method used to train the classifier.
*
Expand Down Expand Up @@ -1254,7 +1265,18 @@ protected Instances initFilters(Instances data) throws Exception {
return data;
}


public InputType.InputTypeConvolutional getInputShape(CustomModelSetup customModelSetup) {
if (useZooModel()) {
int[] inputShape = getZooModel().getInputShape();
log.debug("Zoo Model shape for image inference is: " + Arrays.toString(inputShape));
return new InputType.InputTypeConvolutional(inputShape[1], inputShape[2], inputShape[0]);
}

return new InputType.InputTypeConvolutional(
customModelSetup.getInputHeight(),
customModelSetup.getInputWidth(),
customModelSetup.getInputChannels());
}

/**
* Build the Zoomodel instance
Expand Down Expand Up @@ -1669,7 +1691,7 @@ public void setZooModel(AbstractZooModel zooModel) {
progressManager = new ProgressManager("Parsing model layers...");
progressManager.start();

layerSwingWorker = new SwingWorker<>() {
layerSwingWorker = new SwingWorker<Layer[], Void>() {
@Override
protected Layer[] doInBackground() throws Exception {
return parseLayers();
Expand Down Expand Up @@ -1705,7 +1727,7 @@ private Layer[] parseLayers() {
Thread.currentThread().setContextClassLoader(
this.getClass().getClassLoader());
ComputationGraph tmpCg =
zooModel.init(dummyNumLabels, getSeed(), zooModel.getShape()[0], isFilterMode());
zooModel.init(dummyNumLabels, getSeed(), zooModel.getInputShape(), isFilterMode());
tmpCg.init();
tmpLayers =
Arrays.stream(tmpCg.getLayers())
Expand Down Expand Up @@ -1737,6 +1759,7 @@ public static Dl4jMlpClassifier tryLoadFromFile(File serializedModelFile, Abstra
// First try load from the WEKA binary model file
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serializedModelFile))) {
model = (Dl4jMlpClassifier) ois.readObject();
model.setCustomNet();
} catch (Exception e) {
throw new WekaException("Couldn't load Dl4jMlpClassifier from model file");
}
Expand Down Expand Up @@ -1786,7 +1809,7 @@ public static Dl4jMlpClassifier loadInferenceModel(File serializedModelFile, Abs
Dl4jMlpClassifier model = tryLoadFromFile(serializedModelFile, zooModelType);

if (!Utils.notDefaultFileLocation(serializedModelFile))
model.loadZooModelNoData(2, 1, zooModelType.getShape()[0]);
model.loadZooModelNoData(2, 1, zooModelType.getInputShape());

return model;
}
Expand Down Expand Up @@ -1986,7 +2009,7 @@ public String toString() {
*
* @return True if zoomodel is not CustomNet
*/
protected boolean useZooModel() {
public boolean useZooModel() {
return !(zooModel instanceof CustomNet);
}

Expand Down
12 changes: 7 additions & 5 deletions src/main/java/weka/core/progress/CommandLineProgressBar.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package weka.core.progress;

import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;

import java.util.Timer;
import java.util.TimerTask;

@Log4j2
/**
* Command line implementation of a progress bar
/*
Command line implementation of a progress bar
*/
public class CommandLineProgressBar extends AbstractProgressBar {

Expand Down Expand Up @@ -67,9 +69,9 @@ public void refreshDisplay() {

System.err.printf("\r%s: [%s%s%s] %s",
getProgressMessage(),
progressRemainingChar.repeat(leftSpace),
progressChar.repeat(currNumDots),
progressRemainingChar.repeat(rightSpace),
StringUtils.repeat(progressRemainingChar, leftSpace),
StringUtils.repeat(progressChar, currNumDots),
StringUtils.repeat(progressRemainingChar, rightSpace),
getETAString());
}

Expand Down
68 changes: 0 additions & 68 deletions src/main/java/weka/dl4j/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -496,74 +496,6 @@ public static String defaultFileLocation() {
return WekaPackageManager.getPackageHome().getPath();
}

public static void saveNDArray(INDArray array, String filenamePrefix) {
BufferedImage img = Utils.imageFromINDArray(array);
try {
ImageIO.write(img, "png", new File(filenamePrefix + ".png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}

/**
* Takes an INDArray containing an image loaded using the native image loader
* libraries associated with DL4J, and converts it into a BufferedImage.
* The INDArray contains the color values split up across three channels (RGB)
* and in the integer range 0-255.
*
* @param array INDArray containing an image in order [N, C, H, W] or [C, H, W]
* @return BufferedImage
*/
public static BufferedImage imageFromINDArray(INDArray array) {
long[] shape = array.shape();

boolean is4d = false;
String dimString = "3D";

if (shape.length == 4) {
is4d = true;
dimString = "4D";
}

log.debug(String.format("Converting %s INDArray to image...", dimString));

long height = shape[1];
long width = shape[2];

if (is4d) {
height = shape[2];
width = shape[3];
}

BufferedImage image = new BufferedImage((int) width, (int) height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int red, green, blue;

if (is4d) {
red = array.getInt(0, 2, y, x);
green = array.getInt(0, 1, y, x);
blue = array.getInt(0, 0, y, x);
} else {
red = array.getInt(2, y, x);
green = array.getInt(1, y, x);
blue = array.getInt(0, y, x);
}

//handle out of bounds pixel values
red = Math.min(red, 255);
green = Math.min(green, 255);
blue = Math.min(blue, 255);

red = Math.max(red, 0);
green = Math.max(green, 0);
blue = Math.max(blue, 0);
image.setRGB(x, y, new Color(red, green, blue).getRGB());
}
}
return image;
}

public static InputType.InputTypeConvolutional decodeCNNShape (int[] shape) {
return decodeCNNShape(Arrays.stream(shape).asLongStream().toArray());
}
Expand Down
Loading

0 comments on commit 174759d

Please sign in to comment.