chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:05 +08:00
commit 4f3b7da785
7394 changed files with 2005594 additions and 0 deletions
@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ /* ******************************************************************************
~ *
~ *
~ * This program and the accompanying materials are made available under the
~ * terms of the Apache License, Version 2.0 which is available at
~ * https://www.apache.org/licenses/LICENSE-2.0.
~ *
~ * See the NOTICE file distributed with this work for additional
~ * information regarding copyright ownership.
~ * 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.
~ *
~ * SPDX-License-Identifier: Apache-2.0
~ ******************************************************************************/
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>deeplearning4j-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>deeplearning4j-modelimport</artifactId>
<packaging>jar</packaging>
<properties>
<test.offheap.size>4g</test.offheap.size>
<test.heap.size>4g</test.heap.size>
<module.name>deeplearning4j.modelimport</module.name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>nd4j-api</artifactId>
<version>${nd4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>deeplearning4j-nn</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>jackson</artifactId>
<version>${nd4j.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>${javacpp.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>hdf5-platform</artifactId>
<version>${hdf5.version}-1.5.10</version>
</dependency>
<!-- For unit tests -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>deeplearning4j-common-tests</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>deeplearning4j-datavec-iterators</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>nd4j-tensorflow</artifactId>
<version>${nd4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.deeplearning4j</groupId>
<artifactId>python4j-numpy</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.8.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,457 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.hdf5.*;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.FloatPointer;
import org.bytedeco.javacpp.Loader;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.shade.jackson.databind.DeserializationFeature;
import org.nd4j.shade.jackson.databind.ObjectMapper;
import java.io.Closeable;
import java.io.IOException;
import java.lang.Exception;
import java.util.ArrayList;
import java.util.List;
import static org.bytedeco.hdf5.global.hdf5.*;
@Slf4j
public class Hdf5Archive implements Closeable {
public static final int MAX_BUFFER_SIZE_BYTES = (int)Math.pow(2, 28); //256 MB
/**
* HDF5 library is not thread safe - possible to crash if multiple reads etc are performed concurrently
* in multiple threads. This object is used for locking read etc activity using synchronized blocks
*/
public static final Object LOCK_OBJECT = new Object();
static {
try {
/* This is necessary for the call to the BytePointer constructor below. */
Loader.load(org.bytedeco.hdf5.global.hdf5.class);
} catch (Exception e) {
log.error("",e);
}
}
private H5File file;
private static DataType dataType = new DataType(PredType.NATIVE_FLOAT());
public Hdf5Archive(String archiveFilename) {
synchronized (LOCK_OBJECT) {
this.file = new H5File(archiveFilename, H5F_ACC_RDONLY());
}
}
@Override public void close() {
synchronized (Hdf5Archive.LOCK_OBJECT) {
file.deallocate();
}
}
public Group[] openGroups(String... groups) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
try {
Group[] groupArray = new Group[groups.length];
groupArray[0] = this.file.openGroup(groups[0]);
for (int i = 1; i < groups.length; i++) {
groupArray[i] = groupArray[i - 1].openGroup(groups[i]);
}
return groupArray;
} catch (RuntimeException e) {
throw new RuntimeException("Error opening HDF5 group " + groups[0], e);
}
}
}
public void closeGroups(Group[] groupArray) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
for (int i = groupArray.length - 1; i >= 0; i--) {
groupArray[i].deallocate();
}
}
}
/**
* Read data set as ND4J array from group path.
*
* @param datasetName Name of data set
* @param groups Array of zero or more ancestor groups from root to parent.
* @return INDArray of HDF5 group data
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public INDArray readDataSet(String datasetName, String... groups) throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0)
return readDataSet(this.file, datasetName);
Group[] groupArray = openGroups(groups);
INDArray a = readDataSet(groupArray[groupArray.length - 1], datasetName);
closeGroups(groupArray);
return a;
}
}
/**
* Read JSON-formatted string attribute from group path.
*
* @param attributeName Name of attribute
* @param groups Array of zero or more ancestor groups from root to parent.
* @return HDF5 attribute as JSON
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public String readAttributeAsJson(String attributeName, String... groups)
throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0) {
Attribute a = this.file.openAttribute(attributeName);
String s = readAttributeAsJson(a);
a.deallocate();
return s;
}
Group[] groupArray = openGroups(groups);
Attribute a = groupArray[groups.length - 1].openAttribute(attributeName);
String s = readAttributeAsJson(a);
a.deallocate();
closeGroups(groupArray);
return s;
}
}
/**
* Read string attribute from group path.
*
* @param attributeName Name of attribute
* @param groups Array of zero or more ancestor groups from root to parent.
* @return HDF5 attribute as String
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public String readAttributeAsString(String attributeName, String... groups)
throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0) {
Attribute a = this.file.openAttribute(attributeName);
String s = readAttributeAsString(a);
a.deallocate();
return s;
}
Group[] groupArray = openGroups(groups);
Attribute a = groupArray[groups.length - 1].openAttribute(attributeName);
String s = readAttributeAsString(a);
a.deallocate();
closeGroups(groupArray);
return s;
}
}
/**
* Check whether group path contains string attribute.
*
* @param attributeName Name of attribute
* @param groups Array of zero or more ancestor groups from root to parent.
* @return Boolean indicating whether attribute exists in group path.
*/
public boolean hasAttribute(String attributeName, String... groups) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0)
return this.file.attrExists(attributeName);
Group[] groupArray = openGroups(groups);
boolean b = groupArray[groupArray.length - 1].attrExists(attributeName);
closeGroups(groupArray);
return b;
}
}
/**
* Get list of data sets from group path.
*
* @param groups Array of zero or more ancestor groups from root to parent.
* @return List of HDF5 data set names
*/
public List<String> getDataSets(String... groups) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0)
return getObjects(this.file, H5O_TYPE_DATASET);
Group[] groupArray = openGroups(groups);
List<String> ls = getObjects(groupArray[groupArray.length - 1], H5O_TYPE_DATASET);
closeGroups(groupArray);
return ls;
}
}
/**
* Get list of groups from group path.
*
* @param groups Array of zero or more ancestor groups from root to parent.
* @return List of HDF5 groups
*/
public List<String> getGroups(String... groups) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
if (groups.length == 0)
return getObjects(this.file, H5O_TYPE_GROUP);
Group[] groupArray = openGroups(groups);
List<String> ls = getObjects(groupArray[groupArray.length - 1], H5O_TYPE_GROUP);
closeGroups(groupArray);
return ls;
}
}
/**
* Read data set as ND4J array from HDF5 group.
*
* @param fileGroup HDF5 file or group
* @param datasetName Name of data set
* @return INDArray from HDF5 data set
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
private INDArray readDataSet(Group fileGroup, String datasetName)
throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
DataSet dataset = fileGroup.openDataSet(datasetName);
DataSpace space = dataset.getSpace();
int nbDims = space.getSimpleExtentNdims();
long[] dims = new long[nbDims];
space.getSimpleExtentDims(dims);
float[] dataBuffer;
FloatPointer fp;
int j;
INDArray data;
switch (nbDims) {
case 5: /* 3D Convolution weights */
dataBuffer = new float[(int) (dims[0] * dims[1] * dims[2] * dims[3] * dims[4])];
fp = new FloatPointer(dataBuffer);
dataset.read(fp, dataType);
fp.get(dataBuffer);
data = Nd4j.create((int) dims[0], (int) dims[1], (int) dims[2], (int) dims[3], (int) dims[4]);
j = 0;
for (int i1 = 0; i1 < dims[0]; i1++)
for (int i2 = 0; i2 < dims[1]; i2++)
for (int i3 = 0; i3 < dims[2]; i3++)
for (int i4 = 0; i4 < dims[3]; i4++)
for (int i5 = 0; i5 < dims[4]; i5++)
data.putScalar(new int[] { i1, i2, i3, i4, i5 }, dataBuffer[j++]);
break;
case 4: /* 2D Convolution weights */
dataBuffer = new float[(int) (dims[0] * dims[1] * dims[2] * dims[3])];
fp = new FloatPointer(dataBuffer);
dataset.read(fp, dataType);
fp.get(dataBuffer);
data = Nd4j.create((int) dims[0], (int) dims[1], (int) dims[2], (int) dims[3]);
j = 0;
for (int i1 = 0; i1 < dims[0]; i1++)
for (int i2 = 0; i2 < dims[1]; i2++)
for (int i3 = 0; i3 < dims[2]; i3++)
for (int i4 = 0; i4 < dims[3]; i4++)
data.putScalar(i1, i2, i3, i4, dataBuffer[j++]);
break;
case 3:
dataBuffer = new float[(int) (dims[0] * dims[1] * dims[2])];
fp = new FloatPointer(dataBuffer);
dataset.read(fp, dataType);
fp.get(dataBuffer);
data = Nd4j.create((int) dims[0], (int) dims[1], (int) dims[2]);
j = 0;
for (int i1 = 0; i1 < dims[0]; i1++)
for (int i2 = 0; i2 < dims[1]; i2++)
for (int i3 = 0; i3 < dims[2]; i3++)
data.putScalar(i1, i2, i3, dataBuffer[j++]);
break;
case 2: /* Dense and Recurrent weights */
dataBuffer = new float[(int) (dims[0] * dims[1])];
fp = new FloatPointer(dataBuffer);
dataset.read(fp, dataType);
fp.get(dataBuffer);
data = Nd4j.create((int) dims[0], (int) dims[1]);
j = 0;
for (int i1 = 0; i1 < dims[0]; i1++)
for (int i2 = 0; i2 < dims[1]; i2++)
data.putScalar(i1, i2, dataBuffer[j++]);
break;
case 1: /* Bias */
dataBuffer = new float[(int) dims[0]];
fp = new FloatPointer(dataBuffer);
dataset.read(fp, dataType);
fp.get(dataBuffer);
data = Nd4j.create((int) dims[0]);
j = 0;
for (int i1 = 0; i1 < dims[0]; i1++)
data.putScalar(i1, dataBuffer[j++]);
break;
default:
throw new UnsupportedKerasConfigurationException("Cannot import weights with rank " + nbDims);
}
space.deallocate();
dataset.deallocate();
return data;
}
}
/**
* Get list of objects with a given type from a file group.
*
* @param fileGroup HDF5 file or group
* @param objType Type of object as integer
* @return List of HDF5 group objects
*/
private List<String> getObjects(Group fileGroup, int objType) {
synchronized (Hdf5Archive.LOCK_OBJECT) {
List<String> groups = new ArrayList<>();
for (int i = 0; i < fileGroup.getNumObjs(); i++) {
BytePointer objPtr = fileGroup.getObjnameByIdx(i);
if (fileGroup.childObjType(objPtr) == objType)
groups.add(fileGroup.getObjnameByIdx(i).getString());
}
return groups;
}
}
/**
* Read JSON-formatted string attribute.
*
* @param attribute HDF5 attribute to read as JSON formatted string.
* @return JSON formatted string from HDF5 attribute
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
private String readAttributeAsJson(Attribute attribute) throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
VarLenType vl = attribute.getVarLenType();
int currBufferLength = 2048;
String s;
/* TODO: find a less hacky way to do this.
* Reading variable length strings (from attributes) is a giant
* pain. There does not appear to be any way to determine the
* length of the string in advance, so we use a hack: choose a
* buffer size and read the config. If Jackson fails to parse
* it, then we must not have read the entire config. Increase
* buffer and repeat.
*/
while (true) {
byte[] attrBuffer = new byte[currBufferLength];
BytePointer attrPointer = new BytePointer(currBufferLength);
attribute.read(vl, attrPointer);
attrPointer.get(attrBuffer);
s = new String(attrBuffer);
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
try {
mapper.readTree(s);
break;
} catch (IOException e) {
//OK - we don't know how long the buffer needs to be, so we'll try again with larger buffer
}
if(currBufferLength == MAX_BUFFER_SIZE_BYTES){
throw new UnsupportedKerasConfigurationException("Could not read abnormally long HDF5 attribute: size exceeds " + currBufferLength + " bytes");
} else {
currBufferLength = (int)Math.min(MAX_BUFFER_SIZE_BYTES, currBufferLength * 4L);
}
}
vl.deallocate();
return s;
}
}
/**
* Read attribute as string.
*
* @param attribute HDF5 attribute to read as string.
* @return HDF5 attribute as string
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
private String readAttributeAsString(Attribute attribute) throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
VarLenType vl = attribute.getVarLenType();
int bufferSizeMult = 1;
String s = null;
/* TODO: find a less hacky way to do this.
* Reading variable length strings (from attributes) is a giant
* pain. There does not appear to be any way to determine the
* length of the string in advance, so we use a hack: choose a
* buffer size and read the config, increase buffer and repeat
* until the buffer ends with \u0000
*/
while (true) {
byte[] attrBuffer = new byte[bufferSizeMult * 2000];
BytePointer attrPointer = new BytePointer(attrBuffer);
attribute.read(vl, attrPointer);
attrPointer.get(attrBuffer);
s = new String(attrBuffer);
if (s.endsWith("\u0000")) {
s = s.replace("\u0000", "");
break;
}
bufferSizeMult++;
if (bufferSizeMult > 1000) {
throw new UnsupportedKerasConfigurationException("Could not read abnormally long HDF5 attribute");
}
}
vl.deallocate();
return s;
}
}
/**
* Read string attribute from group path.
*
* @param attributeName Name of attribute
* @param bufferSize buffer size to read
* @return Fixed-length string read from HDF5 attribute name
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public String readAttributeAsFixedLengthString(String attributeName, int bufferSize)
throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
Attribute a = this.file.openAttribute(attributeName);
String s = readAttributeAsFixedLengthString(a, bufferSize);
a.deallocate();
return s;
}
}
/**
* Read attribute of fixed buffer size as string.
*
* @param attribute HDF5 attribute to read as string.
* @return Fixed-length string read from HDF5 attribute
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
private String readAttributeAsFixedLengthString(Attribute attribute, int bufferSize)
throws UnsupportedKerasConfigurationException {
synchronized (Hdf5Archive.LOCK_OBJECT) {
VarLenType vl = attribute.getVarLenType();
byte[] attrBuffer = new byte[bufferSize];
BytePointer attrPointer = new BytePointer(attrBuffer);
attribute.read(vl, attrPointer);
attrPointer.get(attrBuffer);
vl.deallocate();
return new String(attrBuffer);
}
}
}
@@ -0,0 +1,514 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.graph.GraphVertex;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.FeedForwardLayer;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.layers.samediff.SameDiffLambdaLayer;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfigurationFactory;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasRegularizerUtils;
import org.nd4j.common.util.ArrayUtil;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.*;
@Slf4j
public class KerasLayer {
private static final String LAYER_FIELD_KERAS_VERSION = "keras_version";
static final Map<String, Class<? extends KerasLayer>> customLayers = new HashMap<>();
static final Map<String, SameDiffLambdaLayer> lambdaLayers = new HashMap<>();
public enum DimOrder {NONE, THEANO, TENSORFLOW}
@Getter
protected String className; // Keras layer class name
@Getter
protected String layerName; // Keras layer name
@Getter
protected int[] inputShape; // Keras layer input shape
@Getter
protected DimOrder dimOrder; // Keras layer backend dimension order
@Getter
protected List<String> inboundLayerNames; // List of inbound layers
@Getter
protected List<String> outboundLayerNames; //List of outbound layers
protected Layer layer; // Resulting DL4J layer
protected GraphVertex vertex; // Resulting DL4J vertex
protected Map<String, INDArray> weights; // Weights
protected double weightL1Regularization = 0.0; // L1 regularization
protected double weightL2Regularization = 0.0; // L2 regularization
protected double dropout = 1.0; // Dropout
protected Integer kerasMajorVersion = 2; // Set 2 as default for now
@Getter
protected KerasLayerConfiguration conf;
@Getter
protected Map<String, Object> originalLayerConfig;
/**
* Constructor with Keras version only.
*
* @param kerasVersion major Keras version (1 or 2)
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
protected KerasLayer(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
this.className = null;
this.layerName = null;
this.inputShape = null;
this.dimOrder = DimOrder.NONE;
this.inboundLayerNames = new ArrayList<>();
this.outboundLayerNames = new ArrayList<>();
this.layer = null;
this.vertex = null;
this.weights = null;
this.kerasMajorVersion = kerasVersion;
this.conf = KerasLayerConfigurationFactory.get(this.kerasMajorVersion);
}
/**
* Default constructor.
*
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
protected KerasLayer() throws UnsupportedKerasConfigurationException {
this.className = null;
this.layerName = null;
this.inputShape = null;
this.dimOrder = DimOrder.NONE;
this.inboundLayerNames = new ArrayList<>();
this.outboundLayerNames = new ArrayList<>();
this.layer = null;
this.vertex = null;
this.weights = null;
this.conf = KerasLayerConfigurationFactory.get(this.kerasMajorVersion);
}
/**
* Constructor.
*
* @param layerConfig dictionary containing Keras layer configuration
*/
protected KerasLayer(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor. "enforceTrainingConfig" parameter controls whether layer is built for
* training. This controls behavior of certain exceptions. In training mode, passing
* an unsupported regularizer will generate an error. In non-training mode, it
* generates only a warning.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether layer should be built for training (controls certain exceptions)
*/
protected KerasLayer(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this.originalLayerConfig = layerConfig;
this.kerasMajorVersion = (Integer) layerConfig.get(LAYER_FIELD_KERAS_VERSION);
this.conf = KerasLayerConfigurationFactory.get(this.kerasMajorVersion);
this.className = KerasLayerUtils.getClassNameFromConfig(layerConfig, conf);
if (this.className == null)
throw new InvalidKerasConfigurationException("Keras layer class name is missing");
this.layerName = KerasLayerUtils.getLayerNameFromConfig(layerConfig, conf);
if (this.layerName == null)
throw new InvalidKerasConfigurationException("Keras layer class name is missing");
this.inputShape = KerasLayerUtils.getInputShapeFromConfig(layerConfig, conf);
this.dimOrder = KerasLayerUtils.getDimOrderFromConfig(layerConfig, conf);
this.inboundLayerNames = KerasLayerUtils.getInboundLayerNamesFromConfig(layerConfig, conf);
this.outboundLayerNames = KerasLayerUtils.getOutboundLayerNamesFromConfig(layerConfig,conf);
this.layer = null;
this.vertex = null;
this.weights = null;
this.weightL1Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_W_REGULARIZER(), conf.getREGULARIZATION_TYPE_L1());
this.weightL2Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_W_REGULARIZER(), conf.getREGULARIZATION_TYPE_L2());
this.dropout = KerasLayerUtils.getDropoutFromConfig(layerConfig, conf);
KerasLayerUtils.checkForUnsupportedConfigurations(layerConfig, enforceTrainingConfig, conf);
}
/**
* Register a lambda layer
*
* @param lambdaLayerName name of the lambda layer in the serialized Keras model
* @param sameDiffLambdaLayer SameDiffLambdaLayer instance to map to Keras Lambda layer
*/
public static void registerLambdaLayer(String lambdaLayerName, SameDiffLambdaLayer sameDiffLambdaLayer) {
lambdaLayers.put(lambdaLayerName, sameDiffLambdaLayer);
}
/**
* Clear all lambda layers
*
*/
public static void clearLambdaLayers() {
lambdaLayers.clear();
}
/**
* Register a custom layer
*
* @param layerName name of custom layer class
* @param configClass class of custom layer
*/
public static void registerCustomLayer(String layerName, Class<? extends KerasLayer> configClass) {
customLayers.put(layerName, configClass);
}
/**
* Clear all custom layers
*
*/
public static void clearCustomLayers() {
customLayers.clear();
}
/**
* Get Keras major version of this layer.
*
* @return Keras version as integer
*/
public Integer getKerasMajorVersion() {
return this.kerasMajorVersion;
}
/**
* Get Keras layer class name.
*
* @return Keras layer class name
*/
public String getClassName() {
return this.className;
}
/**
* Get Keras layer name.
*
* @return layer name
*/
public String getLayerName() {
return this.layerName;
}
/**
* Get layer input shape.
*
* @return input shape
*/
public int[] getInputShape() {
if (this.inputShape == null)
return null;
return this.inputShape.clone();
}
/**
* Get Keras layer backend dimension order.
*
* @return Keras layer (backend) dimension order
*/
public DimOrder getDimOrder() {
return this.dimOrder;
}
/**
* Set Keras layer backend dimension order.
*/
void setDimOrder(DimOrder dimOrder) {
this.dimOrder = dimOrder;
}
/**
* Get list of inbound layers.
*
* @return list of inbound layer names
*/
public List<String> getInboundLayerNames() {
if (this.inboundLayerNames == null)
this.inboundLayerNames = new ArrayList<>();
return this.inboundLayerNames;
}
/**
* Set list of inbound layers.
*
* @param inboundLayerNames list of inbound layer names
*/
public void setInboundLayerNames(List<String> inboundLayerNames) {
this.inboundLayerNames = new ArrayList<>(inboundLayerNames);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters
*/
public int getNumParams() {
return 0;
}
/**
* Indicates whether layer uses regularization.
*
* @return boolean
*/
public boolean usesRegularization() {
return (this.weightL1Regularization > 0.0 || this.weightL2Regularization > 0.0 || this.dropout < 1.0);
}
/**
* Set weights for Keras layer.
*
* @param weights Map of named NDArrays
*/
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
//no op
}
public Map<String, INDArray> getWeights() {
return this.weights;
}
/**
* Copy Keras layer weights to DL4J Layer.
*
* @param layer DL4J layer
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public void copyWeightsToLayer(org.deeplearning4j.nn.api.Layer layer) throws InvalidKerasConfigurationException {
if (this.getNumParams() > 0) {
String dl4jLayerName = layer.conf().getLayer().getLayerName();
String kerasLayerName = this.getLayerName();
String msg = "Error when attempting to copy weights from Keras layer " + kerasLayerName + " to DL4J layer "
+ dl4jLayerName;
if (getWeights() == null)
throw new InvalidKerasConfigurationException(msg + "(weights is null)");
Set<String> paramsInLayer = new HashSet<>(layer.paramTable().keySet());
Set<String> paramsInKerasLayer = new HashSet<>(this.weights.keySet());
/* Check for parameters in layer for which we don't have weights. */
paramsInLayer.removeAll(paramsInKerasLayer);
/* Check for parameters NOT in layer for which we DO have weights. */
paramsInKerasLayer.removeAll(layer.paramTable().keySet());
if (!paramsInKerasLayer.isEmpty()) {
String joinedParamsInKerasLayer = StringUtils.join(paramsInKerasLayer, ", ");
throw new InvalidKerasConfigurationException(
msg + "(found no parameters named: " + joinedParamsInKerasLayer + ")");
}
/* Copy weights. */
for (String paramName : layer.paramTable().keySet()) {
try {
long[] dl4jWeights = layer.paramTable().get(paramName).shape();
if(!weights.containsKey(paramName)) {
throw new IllegalArgumentException("No weights found for parameter " + paramName + " in layer " + kerasLayerName);
}
long[] kerasWeights = weights.get(paramName).shape();
INDArray variable = this.weights.get(paramName);
if(!Arrays.equals(dl4jWeights,kerasWeights) &&
ArrayUtil.prod(dl4jWeights) == ArrayUtil.prod(kerasWeights)) {
layer.setParam(paramName, variable.reshape(dl4jWeights));
}
else {
layer.setParam(paramName, variable);
}
} catch (Exception e) {
log.error(e.getMessage());
throw new InvalidKerasConfigurationException(e.getMessage()
+ "\nTried to set weights for layer with name " + this.getLayerName()
+ ", of " + layer.conf().getLayer().getClass() + ".\n"
+ "Failed to set weights for parameter " + paramName + "\n"
+ "Expected shape for this parameter: " + layer.getParam(paramName).shapeInfoToString()
+ ", \ngot: " + this.weights.get(paramName).shapeInfoToString());
}
}
}
}
/**
* Whether this Keras layer maps to a DL4J Layer.
*
* @return true or false
*/
public boolean isLayer() {
return this.layer != null;
}
/**
* Gets corresponding DL4J Layer, if any.
*
* @return DL4J Layer
* @see org.deeplearning4j.nn.api.Layer
*/
public Layer getLayer() {
return this.layer;
}
public void setLayer(Layer layer){
this.layer = layer;
}
/**
* Whether this Keras layer maps to a DL4J Vertex.
*
* @return true or false
*/
public boolean isVertex() {
return this.vertex != null;
}
/**
* Gets corresponding DL4J Vertex, if any.
*
* @return DL4J Vertex
* @see org.deeplearning4j.nn.conf.graph.GraphVertex
*/
public GraphVertex getVertex() {
return this.vertex;
}
/**
* Whether this Keras layer maps to a DL4J InputPreProcessor.
*
* @return true or false
*/
public boolean isInputPreProcessor() {
return false;
}
/**
* Some DL4J layers need explicit specification of number of inputs, which Keras does infer.
* This method searches through previous layers until a FeedForwardLayer is found. These layers
* have nOut values that subsequently correspond to the nIn value of this layer.
*
* @param previousLayers
* @return
* @throws UnsupportedKerasConfigurationException
*/
protected long getNInFromConfig(Map<String, ? extends KerasLayer> previousLayers) throws UnsupportedKerasConfigurationException {
int size = previousLayers.size();
int count = 0;
long nIn;
String inboundLayerName = inboundLayerNames.get(0);
while (count <= size) {
if (previousLayers.containsKey(inboundLayerName)) {
KerasLayer inbound = previousLayers.get(inboundLayerName);
try {
FeedForwardLayer ffLayer = (FeedForwardLayer) inbound.getLayer();
nIn = ffLayer.getNOut();
if (nIn > 0)
return nIn;
count++;
inboundLayerName = inbound.getInboundLayerNames().get(0);
} catch (Exception e) {
inboundLayerName = inbound.getInboundLayerNames().get(0);
}
}
}
throw new UnsupportedKerasConfigurationException("Could not determine number of input channels for" +
"depthwise convolution.");
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
InputPreProcessor preprocessor = null;
if (this.layer != null) {
if (inputType.length > 1) {
InputType toUse = null;
for(int i = 0; i < inputType.length; i++) {
if(inputType[i] != null) {
if(toUse == null)
toUse = inputType[i];
else if(!toUse.equals(inputType[i])) {
throw new InvalidKerasConfigurationException(
"Keras layer of type \"" + this.className + "\" accepts only one input");
}
}
}
if(toUse == null) {
throw new InvalidKerasConfigurationException(
"Keras layer of type \"" + this.className + " did not have any inputs!");
}
preprocessor = this.layer.getPreProcessorForInputType(toUse);
}
else
preprocessor = this.layer.getPreProcessorForInputType(inputType[0]);
}
return preprocessor;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public InputType getOutputType(InputType... inputType)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
throw new UnsupportedOperationException(
"Cannot determine output type for Keras layer of type " + this.className);
}
/**
* Indicates whether this layer a valid inbound layer. Currently, only
* (known) DL4J Layers and inputs are valid inbound layers. "Preprocessor"
* layers (reshaping, merging, etc.) are replaced by their own inbound layers.
*
* @return boolean indicating whether layer is valid inbound layer
* @see org.deeplearning4j.nn.api.Layer
*/
public boolean isValidInboundLayer() throws InvalidKerasConfigurationException {
return (getLayer() != null || getVertex() != null || getInputPreprocessor() != null
|| this.className.equals(conf.getLAYER_CLASS_NAME_INPUT()));
}
}
@@ -0,0 +1,658 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasOptimizerUtils;
import org.deeplearning4j.nn.conf.*;
import org.deeplearning4j.nn.conf.graph.PreprocessorVertex;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Convolution3D;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.layers.samediff.SameDiffLambdaLayer;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasLSTM;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasRnnUtils;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasSimpleRnn;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.config.KerasModelConfiguration;
import org.deeplearning4j.nn.modelimport.keras.layers.KerasInput;
import org.deeplearning4j.nn.modelimport.keras.layers.KerasLoss;
import org.deeplearning4j.nn.modelimport.keras.layers.core.KerasLambda;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder;
import org.deeplearning4j.util.Convolution3DUtils;
import org.deeplearning4j.util.ConvolutionUtils;
import org.nd4j.common.primitives.Counter;
import org.nd4j.common.primitives.Pair;
import org.nd4j.linalg.learning.config.IUpdater;
import org.nd4j.shade.guava.collect.Lists;
import java.io.IOException;
import java.util.*;
import static org.deeplearning4j.nn.modelimport.keras.KerasLayer.customLayers;
import static org.deeplearning4j.nn.modelimport.keras.KerasLayer.lambdaLayers;
@Slf4j
@Data
public class KerasModel {
protected static KerasModelConfiguration config = new KerasModelConfiguration();
protected KerasModelBuilder modelBuilder = new KerasModelBuilder(config);
protected String className; // Keras model class name
protected boolean enforceTrainingConfig; // whether to build model in training mode
protected Map<String, KerasLayer> layers; // map from layer name to KerasLayer
protected List<KerasLayer> layersOrdered; // ordered list of layers
protected Map<String, InputType> outputTypes; // inferred output types for all layers
protected ArrayList<String> inputLayerNames; // list of input layers
protected ArrayList<String> outputLayerNames; // list of output layers
protected boolean useTruncatedBPTT = false; // whether to use truncated BPTT
protected int truncatedBPTT = 0; // truncated BPTT value
protected int kerasMajorVersion;
protected String kerasBackend;
protected KerasLayer.DimOrder dimOrder = null;
protected IUpdater optimizer = null;
public KerasModel() {
}
public KerasModelBuilder modelBuilder() {
return this.modelBuilder;
}
/**
* (Recommended) Builder-pattern constructor for (Functional API) Model.
*
* @param modelBuilder builder object
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasModel(KerasModelBuilder modelBuilder)
throws UnsupportedKerasConfigurationException, IOException, InvalidKerasConfigurationException {
this(modelBuilder.getModelJson(), modelBuilder.getModelYaml(), modelBuilder.getWeightsArchive(),
modelBuilder.getWeightsRoot(), modelBuilder.getTrainingJson(), modelBuilder.getTrainingArchive(),
modelBuilder.isEnforceTrainingConfig(), modelBuilder.getInputShape(), modelBuilder.getDimOrder());
}
/**
* (Not recommended) Constructor for (Functional API) Model from model configuration
* (JSON or YAML), training configuration (JSON), weights, and "training mode"
* boolean indicator. When built in training mode, certain unsupported configurations
* (e.g., unknown regularizers) will throw Exceptions. When enforceTrainingConfig=false, these
* will generate warnings but will be otherwise ignored.
*
* @param modelJson model configuration JSON string
* @param modelYaml model configuration YAML string
* @param enforceTrainingConfig whether to enforce training-related configurations
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
protected KerasModel(String modelJson, String modelYaml, Hdf5Archive weightsArchive, String weightsRoot,
String trainingJson, Hdf5Archive trainingArchive, boolean enforceTrainingConfig,
int[] inputShape, KerasLayer.DimOrder dimOrder)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> modelConfig = KerasModelUtils.parseModelConfig(modelJson, modelYaml);
this.kerasMajorVersion = KerasModelUtils.determineKerasMajorVersion(modelConfig, config);
this.kerasBackend = KerasModelUtils.determineKerasBackend(modelConfig, config);
this.enforceTrainingConfig = enforceTrainingConfig;
this.dimOrder = dimOrder;
/* Determine model configuration type. */
if (!modelConfig.containsKey(config.getFieldClassName()))
throw new InvalidKerasConfigurationException(
"Could not determine Keras model class (no " + config.getFieldClassName() + " field found)");
this.className = (String) modelConfig.get(config.getFieldClassName());
if (!this.className.equals(config.getFieldClassNameModel()) && !this.className.equals(config.getFieldNameClassFunctional()))
throw new InvalidKerasConfigurationException(
"Expected model class name " + config.getFieldClassNameModel() + " or " + config.getFieldNameClassFunctional() + " (found " + this.className + ")");
/* Retrieve lists of input and output layers, layer configurations. */
if (!modelConfig.containsKey(config.getModelFieldConfig()))
throw new InvalidKerasConfigurationException("Could not find model configuration details (no "
+ config.getModelFieldConfig() + " in model config)");
Map<String, Object> layerLists = (Map<String, Object>) modelConfig.get(config.getModelFieldConfig());
/* Construct list of input layers. */
if (!layerLists.containsKey(config.getModelFieldInputLayers()))
throw new InvalidKerasConfigurationException("Could not find list of input layers (no "
+ config.getModelFieldInputLayers() + " field found)");
this.inputLayerNames = new ArrayList<>();
for (Object inputLayerNameObj : (List<Object>) layerLists.get(config.getModelFieldInputLayers()))
this.inputLayerNames.add((String) ((List<Object>) inputLayerNameObj).get(0));
/* Construct list of output layers. */
if (!layerLists.containsKey(config.getModelFieldOutputLayers()))
throw new InvalidKerasConfigurationException("Could not find list of output layers (no "
+ config.getModelFieldOutputLayers() + " field found)");
this.outputLayerNames = new ArrayList<>();
for (Object outputLayerNameObj : (List<Object>) layerLists.get(config.getModelFieldOutputLayers()))
this.outputLayerNames.add((String) ((List<Object>) outputLayerNameObj).get(0));
/* Process layer configurations. */
if (!layerLists.containsKey(config.getModelFieldLayers()))
throw new InvalidKerasConfigurationException(
"Could not find layer configurations (no " + (config.getModelFieldLayers() + " field found)"));
Pair<Map<String, KerasLayer>, List<KerasLayer>> layerPair =
prepareLayers((List<Object>) layerLists.get((config.getModelFieldLayers())));
this.layers = layerPair.getFirst();
this.layersOrdered = layerPair.getSecond();
/* Import training configuration. */
if (enforceTrainingConfig) {
if (trainingJson != null)
importTrainingConfiguration(trainingJson);
else log.warn("If enforceTrainingConfig is true, a training " +
"configuration object has to be provided. Usually the only practical way to do this is to store" +
" your keras model with `model.save('model_path.h5')`. If you store model config and weights" +
" separately no training configuration is attached.");
}
if(inputShape == null) {
inputShape = layersOrdered.get(0).inputShape;
}
/* Infer output types for each layer. */
this.outputTypes = inferOutputTypes(inputShape);
/* Store weights in layers. */
if (weightsArchive != null)
KerasModelUtils.importWeights(weightsArchive, weightsRoot, layers, kerasMajorVersion, kerasBackend);
}
/**
* Helper method called from constructor. Converts layer configuration
* JSON into KerasLayer objects.
*
* @param layerConfigs List of Keras layer configurations
*/
Pair<Map<String, KerasLayer>, List<KerasLayer>> prepareLayers(List<Object> layerConfigs)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, KerasLayer> layers = new HashMap<>(); // map from layer name to KerasLayer
List<KerasLayer> layersOrdered = new ArrayList<>();
for (Object layerConfig : layerConfigs) {
Map<String, Object> layerConfigMap = (Map<String, Object>) layerConfig;
// Append major keras version and backend to each layer config.
layerConfigMap.put(config.getFieldKerasVersion(), this.kerasMajorVersion);
if (kerasMajorVersion == 2 && this.kerasBackend != null)
layerConfigMap.put(config.getFieldBackend(), this.kerasBackend);
KerasLayerConfiguration kerasLayerConf = new KerasLayer(this.kerasMajorVersion).conf;
if (dimOrder != null) { // Force override of dim ordering with value from model builder
String dimOrderString;
if (dimOrder == KerasLayer.DimOrder.TENSORFLOW)
dimOrderString = kerasLayerConf.getDIM_ORDERING_TENSORFLOW();
else if (dimOrder == KerasLayer.DimOrder.THEANO)
dimOrderString = kerasLayerConf.getDIM_ORDERING_THEANO();
else
throw new InvalidKerasConfigurationException("Invalid data format / dim ordering");
layerConfigMap.put(kerasLayerConf.getLAYER_FIELD_DIM_ORDERING(), dimOrderString);
}
KerasLayer layer = KerasLayerUtils.getKerasLayerFromConfig(
layerConfigMap, this.enforceTrainingConfig, kerasLayerConf, customLayers, lambdaLayers, layers);
layersOrdered.add(layer);
layers.put(layer.getLayerName(), layer);
if (layer instanceof KerasLSTM)
this.useTruncatedBPTT = this.useTruncatedBPTT || ((KerasLSTM) layer).getUnroll();
if (layer instanceof KerasSimpleRnn)
this.useTruncatedBPTT = this.useTruncatedBPTT || ((KerasSimpleRnn) layer).getUnroll();
}
List<String> names = new ArrayList<>();
//set of names of lambda nodes
Set<String> lambdaNames = new HashSet<>();
//node inputs by name for looking up which nodes to do replacements for (useful since indices of nodes can change)
Map<String,List<String>> nodesOutputToForLambdas = new HashMap<>();
for(int i = 0; i < layers.size(); i++) {
names.add(layersOrdered.get(i).getLayerName());
if(layersOrdered.get(i) instanceof KerasLambda) {
lambdaNames.add(layersOrdered.get(i).getLayerName());
}
}
Map<String,List<String>> replacementNamesForLambda = new HashMap<>();
Map<Integer,KerasLayer> updatedOrders = new HashMap<>();
for(int i = 0; i < layersOrdered.size(); i++) {
KerasLayer kerasLayer = layers.get(names.get(i));
List<String> tempCopyNames = new ArrayList<>(kerasLayer.getInboundLayerNames());
List<String> removed = new ArrayList<>();
for(String input : tempCopyNames) {
//found a lambda where an input occurs, record the index for input
if(lambdaNames.contains(input)) {
if(!nodesOutputToForLambdas.containsKey(input)) {
nodesOutputToForLambdas.put(input,new ArrayList<String>());
}
nodesOutputToForLambdas.get(input).add(kerasLayer.getLayerName());
}
//potential loop found
int indexOfInput = names.indexOf(input);
if(indexOfInput > i) {
KerasLambda originalLambda = (KerasLambda) kerasLayer;
Map<String,Object> configCopy = new HashMap<String,Object>(kerasLayer.originalLayerConfig);
String newName = kerasLayer.getLayerName() + "-" + input;
if(!replacementNamesForLambda.containsKey(originalLambda.layerName)) {
replacementNamesForLambda.put(originalLambda.layerName,new ArrayList<String>());
}
configCopy.put(kerasLayer.conf.getLAYER_FIELD_NAME(),newName);
replacementNamesForLambda.get(originalLambda.layerName).add(newName);
SameDiffLambdaLayer sameDiffLambdaLayer = (SameDiffLambdaLayer) originalLambda.getSameDiffLayer().clone();
sameDiffLambdaLayer.setLayerName(newName);
KerasLambda kerasLambda = new KerasLambda(configCopy,sameDiffLambdaLayer);
kerasLambda.layerName = newName;
kerasLambda.setInboundLayerNames(new ArrayList<>(Arrays.asList(input)));
layers.put(newName,kerasLambda);
int indexOfNewLayer = names.indexOf(input) + 1;
updatedOrders.put(indexOfNewLayer,kerasLambda);
names.add(indexOfNewLayer,newName);
removed.add(input);
System.out.println("Found input " + input + " at keras node " + names.get(i) + " with potential cycle.");
}
}
kerasLayer.getInboundLayerNames().removeAll(removed);
}
//update the list with all the new layers
for(Map.Entry<Integer,KerasLayer> newLayers : updatedOrders.entrySet()) {
layersOrdered.add(newLayers.getKey(),newLayers.getValue());
}
List<String> oldNames = new ArrayList<>(names);
names.clear();
//old names are used for checking distance from old nodes to new ones
//node inputs by name for looking up which nodes to do replacements for (useful since indices of nodes can change)
if(!replacementNamesForLambda.isEmpty()) {
for (Map.Entry<String, List<String>> replacementEntry : replacementNamesForLambda.entrySet()) {
List<String> nodesToReplaceInputNamesWith = nodesOutputToForLambdas.get(replacementEntry.getKey());
Set<String> processed = new HashSet<>();
for (String nodeName : nodesToReplaceInputNamesWith) {
KerasLayer kerasLayer = layers.get(nodeName);
boolean shouldBeOriginal = true;
if (!processed.isEmpty()) {
for (String process : processed) {
if (kerasLayer.getInboundLayerNames().contains(process)) {
shouldBeOriginal = false;
break;
}
}
}
List<String> nearestNodes = findNearestNodesTo(replacementEntry.getKey(), nodeName, replacementEntry.getValue(), oldNames, 2);
//if the original isn't in the closest top 2 nodes, then we shouldn't replace it
if (nodesToReplaceInputNamesWith.size() > 1) {
if (!nearestNodes.contains(replacementEntry.getKey())) {
shouldBeOriginal = false;
}
}
//layers that contain an already processed
//node as an input need modification
if (shouldBeOriginal) {
processed.add(nodeName);
continue;
}
//replace whatever the final input name is that was last
kerasLayer.getInboundLayerNames().set(kerasLayer.getInboundLayerNames()
.indexOf(replacementEntry.getKey()), nearestNodes.get(0));
processed.add(nodeName);
}
}
}
layers.clear();
for(KerasLayer kerasLayer : layersOrdered) {
layers.put(kerasLayer.getLayerName(),kerasLayer);
}
return new Pair<>(layers, layersOrdered);
}
List<String> findNearestNodesTo(String original,String target,List<String> targetedNodes,List<String> topoSortNodes,int k) {
int idx = topoSortNodes.indexOf(target);
Counter<String> rankByDistance = new Counter<>();
for(int i = 0; i < targetedNodes.size(); i++) {
int currIdx = topoSortNodes.indexOf(targetedNodes.get(i));
int diff = Math.abs(currIdx - idx);
//note we want the top k ranked by the least
rankByDistance.incrementCount(targetedNodes.get(i),-diff);
}
int currIdx = topoSortNodes.indexOf(original);
int diff = Math.abs(currIdx - idx);
//note we want the top k ranked by the least
rankByDistance.incrementCount(original,-diff);
rankByDistance.keepTopNElements(k);
return rankByDistance.keySetSorted();
}
Map<String, Object> getOptimizerConfig(Map<String, Object> trainingConfig) throws InvalidKerasConfigurationException{
if (!trainingConfig.containsKey(config.getOptimizerConfig()))
throw new InvalidKerasConfigurationException("Field "
+ config.getOptimizerConfig() + " missing from layer config");
return (Map<String, Object>) trainingConfig.get(config.getOptimizerConfig());
}
/**
* Helper method called from constructor. Incorporate training configuration details into model.
* Includes loss function, optimization details, etc.
*
* @param trainingConfigJson JSON containing Keras training configuration
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
void importTrainingConfiguration(String trainingConfigJson)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> trainingConfig = KerasModelUtils.parseJsonString(trainingConfigJson);
Map<String, Object> optimizerConfig = getOptimizerConfig(trainingConfig);
this.optimizer = KerasOptimizerUtils.mapOptimizer(optimizerConfig);
/* Add loss layers for each loss function. */
List<KerasLayer> lossLayers = new ArrayList<>();
if (!trainingConfig.containsKey(config.getTrainingLoss()))
throw new InvalidKerasConfigurationException("Could not determine training loss function (no "
+ config.getTrainingLoss() + " field found in training config)");
Object kerasLossObj = trainingConfig.get(config.getTrainingLoss());
if (kerasLossObj instanceof String) {
String kerasLoss = (String) kerasLossObj;
for (String outputLayerName : this.outputLayerNames)
lossLayers.add(new KerasLoss(outputLayerName + "_loss", outputLayerName, kerasLoss));
} else if (kerasLossObj instanceof Map) {
Map<String, Object> kerasLossMap = (Map<String, Object>) kerasLossObj;
//tf.keras double nesting
if(kerasLossMap.containsKey("config")) {
kerasLossMap = (Map<String, Object>) kerasLossMap.get("config");
lossLayers.add(new KerasLoss(layersOrdered.get(layers.size() - 1).getLayerName() + "_loss",layersOrdered.get(layers.size() - 1).getLayerName(),kerasLossMap.get("name").toString()));
} else {
for (String outputLayerName : kerasLossMap.keySet()) {
Object kerasLoss = kerasLossMap.get(outputLayerName);
if (kerasLoss instanceof String)
lossLayers.add(new KerasLoss(outputLayerName + "_loss", outputLayerName, (String) kerasLoss));
else
throw new InvalidKerasConfigurationException("Unknown Keras loss " + kerasLoss.toString());
}
}
}
this.outputLayerNames.clear();
/* Add loss layers to output layer list and layer graph. */
for (KerasLayer lossLayer : lossLayers) {
this.layersOrdered.add(lossLayer);
this.layers.put(lossLayer.getLayerName(), lossLayer);
this.outputLayerNames.add(lossLayer.getLayerName());
}
}
/**
* Helper method called from constructor. Infers and records output type
* for every layer.
*/
Map<String, InputType> inferOutputTypes(int[] inputShape)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, InputType> outputTypes = new HashMap<>();
int kerasLayerIdx = 0;
for (KerasLayer layer : this.layersOrdered) {
InputType outputType;
if (layer instanceof KerasInput) {
if (inputShape != null && layer.inputShape == null) {
layer.inputShape = inputShape;
}
KerasInput kerasInput = (KerasInput) layer;
Layer layer1 = layersOrdered.get(kerasLayerIdx + 1).layer;
//no dim order, try to pull it from the next layer if there is one
if(layer1 != null && ConvolutionUtils.layerHasConvolutionLayout(layer1)) {
CNN2DFormat formatForLayer = ConvolutionUtils.getFormatForLayer(layer1);
if(formatForLayer == CNN2DFormat.NCHW) {
dimOrder = KerasLayer.DimOrder.THEANO;
} else if(formatForLayer == CNN2DFormat.NHWC) {
dimOrder = KerasLayer.DimOrder.TENSORFLOW;
} else {
dimOrder = KerasLayer.DimOrder.NONE;
}
} else if(layer1 != null && Convolution3DUtils.layerHasConvolution3DLayout(layer1)) {
Convolution3D.DataFormat dataFormat = Convolution3DUtils.getFormatForLayer(layer1);
if(dataFormat == Convolution3D.DataFormat.NCDHW) {
dimOrder = KerasLayer.DimOrder.THEANO;
} else if(dataFormat == Convolution3D.DataFormat.NDHWC) {
dimOrder = KerasLayer.DimOrder.TENSORFLOW;
} else {
dimOrder = KerasLayer.DimOrder.NONE;
}
} else if(KerasRnnUtils.isRnnLayer(layersOrdered.get(kerasLayerIdx + 1))) {
if(kerasInput.inputShape == null)
kerasInput.inputShape = layersOrdered.get(kerasLayerIdx + 1).inputShape;
}
if(dimOrder != null)
layer.setDimOrder(dimOrder);
outputType = layer.getOutputType();
this.truncatedBPTT = ((KerasInput) layer).getTruncatedBptt();
} else {
List<InputType> inputTypes = new ArrayList<>();
int i = 0;
for (String inboundLayerName : layer.getInboundLayerNames())
if(outputTypes.containsKey(inboundLayerName))
inputTypes.add(outputTypes.get(inboundLayerName));
outputType = layer.getOutputType(inputTypes.toArray(new InputType[1]));
}
outputTypes.put(layer.getLayerName(), outputType);
kerasLayerIdx++;
}
return outputTypes;
}
/**
* Configure a ComputationGraph from this Keras Model configuration.
*
* @return ComputationGraph
*/
public ComputationGraphConfiguration getComputationGraphConfiguration()
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
if (!this.className.equals(config.getFieldClassNameModel())
&& !this.className.equals(config.getFieldClassNameSequential())
&& !this.className.equals(config.getFieldNameClassFunctional()))
throw new InvalidKerasConfigurationException(
"Keras model class name " + this.className + " incompatible with ComputationGraph");
NeuralNetConfiguration.Builder modelBuilder = new NeuralNetConfiguration.Builder();
if (optimizer != null) {
modelBuilder.updater(optimizer);
}
Map<String,List<String>> outputs = new HashMap<>();
for (KerasLayer layer : Lists.reverse(this.layersOrdered)) {
for(String input : layer.getInboundLayerNames()) {
if(!outputs.containsKey(input)) {
outputs.put(input,new ArrayList<String>());
}
outputs.get(input).add(layer.getLayerName());
}
}
ComputationGraphConfiguration.GraphBuilder graphBuilder = modelBuilder.graphBuilder();
// NOTE: normally this is disallowed in DL4J. However, in Keras you can create disconnected graph vertices.
// The responsibility for doing this correctly is that of the Keras user.
graphBuilder.allowDisconnected(true);
/* Build String array of input layer names, add to ComputationGraph. */
String[] inputLayerNameArray = new String[this.inputLayerNames.size()];
this.inputLayerNames.toArray(inputLayerNameArray);
graphBuilder.addInputs(inputLayerNameArray);
/* Build InputType array of input layer types, add to ComputationGraph. */
List<InputType> inputTypeList = new ArrayList<>();
List<InputType> initialInputTypes = new ArrayList<>();
for (String inputLayerName : this.inputLayerNames) {
this.layers.get(inputLayerName);
inputTypeList.add(this.layers.get(inputLayerName).getOutputType());
}
/* Build String array of output layer names, add to ComputationGraph. */
String[] outputLayerNameArray = new String[this.outputLayerNames.size()];
this.outputLayerNames.toArray(outputLayerNameArray);
graphBuilder.setOutputs(outputLayerNameArray);
Map<String, InputPreProcessor> preprocessors = new HashMap<>();
int idx = 0;
/* Add layersOrdered one at a time. */
for (KerasLayer layer : this.layersOrdered) {
/* Get inbound layer names. */
List<String> inboundLayerNames = layer.getInboundLayerNames();
String[] inboundLayerNamesArray = new String[inboundLayerNames.size()];
inboundLayerNames.toArray(inboundLayerNamesArray);
List<InputType> inboundTypeList = new ArrayList<>();
/* Get inbound InputTypes and InputPreProcessor, if necessary. */
if(!inboundLayerNames.isEmpty()) {
InputType[] inputTypes2 = new InputType[inboundLayerNames.size()];
int inboundIdx = 0;
for (String layerName : inboundLayerNames) {
KerasLayer prevLayer = layers.get(layerName);
if(prevLayer.isInputPreProcessor()) {
InputType inputType = this.outputTypes.get(layerName);
InputPreProcessor preprocessor = prevLayer.getInputPreprocessor(inputType);
KerasModelUtils.setDataFormatIfNeeded(preprocessor,layer);
InputType outputType = preprocessor.getOutputType(inputType);
inputTypes2[inboundIdx] = outputType;
inboundIdx++;
}
else {
InputType inputType = this.outputTypes.get(layerName);
inputTypes2[inboundIdx] = inputType;
inboundIdx++;
}
if(outputTypes.containsKey(layerName))
inboundTypeList.add(this.outputTypes.get(layerName));
}
}
InputType[] inboundTypeArray = new InputType[inboundTypeList.size()];
inboundTypeList.toArray(inboundTypeArray);
InputPreProcessor preprocessor = layer.getInputPreprocessor(inboundTypeArray);
//don't add pre processor if there isn't anymore output, edge case for final layer
if(idx == layersOrdered.size() - 1) {
preprocessor = null;
}
if (layer.isLayer()) {
if (preprocessor != null)
preprocessors.put(layer.getLayerName(), preprocessor);
graphBuilder.addLayer(layer.getLayerName(), layer.getLayer(), inboundLayerNamesArray);
} else if (layer.isVertex()) { // Ignore "preprocessor" layers for now
if (preprocessor != null)
preprocessors.put(layer.getLayerName(), preprocessor);
graphBuilder.addVertex(layer.getLayerName(), layer.getVertex(), inboundLayerNamesArray);
} else if (layer.isInputPreProcessor()) {
if (preprocessor == null)
throw new UnsupportedKerasConfigurationException("Layer " + layer.getLayerName()
+ " could not be mapped to Layer, Vertex, or InputPreProcessor");
graphBuilder.addVertex(layer.getLayerName(), new PreprocessorVertex(preprocessor),
inboundLayerNamesArray);
}
if(layer instanceof KerasInput) {
initialInputTypes.add(this.outputTypes.get(layer.layerName));
}
idx++;
}
graphBuilder.setInputPreProcessors(preprocessors);
/* Whether to use standard backprop (or BPTT) or truncated BPTT. */
if (this.useTruncatedBPTT && this.truncatedBPTT > 0)
graphBuilder.backpropType(BackpropType.TruncatedBPTT).tBPTTForwardLength(truncatedBPTT)
.tBPTTBackwardLength(truncatedBPTT);
else
graphBuilder.backpropType(BackpropType.Standard);
ComputationGraphConfiguration build = graphBuilder.build();
//note we don't forcibly over ride inputs when doing keras import. They are already set.
build.addPreProcessors(false,false,initialInputTypes.toArray(new InputType[initialInputTypes.size()]));
return build;
}
/**
* Build a ComputationGraph from this Keras Model configuration and import weights.
*
* @return ComputationGraph
*/
public ComputationGraph getComputationGraph()
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
return getComputationGraph(true);
}
/**
* Build a ComputationGraph from this Keras Model configuration and (optionally) import weights.
*
* @param importWeights whether to import weights
* @return ComputationGraph
*/
public ComputationGraph getComputationGraph(boolean importWeights)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
ComputationGraph model = new ComputationGraph(getComputationGraphConfiguration());
model.init();
if (importWeights)
model = (ComputationGraph) KerasModelUtils.copyWeightsToModel(model, this.layers);
return model;
}
}
@@ -0,0 +1,379 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.deeplearning4j.common.util.ND4JFileUtils;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.ComputationGraphConfiguration;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import java.io.*;
@Slf4j
public class KerasModelImport {
/**
* Load Keras (Functional API) Model saved using model.save_model(...).
*
* @param modelHdf5Stream InputStream containing HDF5 archive storing Keras Model
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(InputStream modelHdf5Stream, boolean enforceTrainingConfig)
throws IOException, UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
File f = null;
try{
f = toTempFile(modelHdf5Stream);
return importKerasModelAndWeights(f.getAbsolutePath(), enforceTrainingConfig);
} finally {
if(f != null)
f.delete();
}
}
/**
* Load Keras (Functional API) Model saved using model.save_model(...).
*
* @param modelHdf5Stream InputStream containing HDF5 archive storing Keras Model
* @return ComputationGraph
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(InputStream modelHdf5Stream) throws IOException, UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
File f = null;
try{
f = toTempFile(modelHdf5Stream);
return importKerasModelAndWeights(f.getAbsolutePath());
} finally {
if(f != null)
f.delete();
}
}
/**
* Load Keras Sequential model saved using model.save_model(...).
*
* @param modelHdf5Stream InputStream containing HDF5 archive storing Keras Sequential model
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @see ComputationGraph
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(InputStream modelHdf5Stream,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
File f = null;
try{
f = toTempFile(modelHdf5Stream);
return importKerasSequentialModelAndWeights(f.getAbsolutePath(), enforceTrainingConfig);
} finally {
if(f != null)
f.delete();
}
}
/**
* Load Keras Sequential model saved using model.save_model(...).
*
* @param modelHdf5Stream InputStream containing HDF5 archive storing Keras Sequential model
* @return ComputationGraph
* @see ComputationGraph
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(InputStream modelHdf5Stream)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
File f = null;
try{
f = toTempFile(modelHdf5Stream);
return importKerasSequentialModelAndWeights(f.getAbsolutePath());
} finally {
if(f != null)
f.delete();
}
}
/**
* Load Keras (Functional API) Model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Model
* @param inputShape optional input shape for models that come without such (e.g. notop = false models)
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(String modelHdf5Filename, int[] inputShape,
boolean enforceTrainingConfig)
throws IOException, UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder.modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(enforceTrainingConfig).inputShape(inputShape).buildModel();
return kerasModel.getComputationGraph();
}
/**
* Load Keras (Functional API) Model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Model
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(String modelHdf5Filename, boolean enforceTrainingConfig)
throws IOException, UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder.modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(enforceTrainingConfig).buildModel();
return kerasModel.getComputationGraph();
}
/**
* Load Keras (Functional API) Model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Model
* @return ComputationGraph
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(String modelHdf5Filename)
throws IOException, UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder().modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(true).buildModel();
return kerasModel.getComputationGraph();
}
/**
* Load Keras Sequential model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Sequential model
* @param inputShape optional input shape for models that come without such (e.g. notop = false models)
* @param enforceTrainingConfig whether to enforce training configuration options
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(String modelHdf5Filename,
int[] inputShape,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(enforceTrainingConfig).inputShape(inputShape).buildSequential();
return kerasModel.getMultiLayerNetwork();
}
/**
* Load Keras Sequential model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Sequential model
* @param enforceTrainingConfig whether to enforce training configuration options
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(String modelHdf5Filename,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(enforceTrainingConfig).buildSequential();
return kerasModel.getMultiLayerNetwork();
}
/**
* Load Keras Sequential model saved using model.save_model(...).
*
* @param modelHdf5Filename path to HDF5 archive storing Keras Sequential model
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(String modelHdf5Filename)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelHdf5Filename(modelHdf5Filename)
.enforceTrainingConfig(true).buildSequential();
return kerasModel.getMultiLayerNetwork();
}
/**
* Load Keras (Functional API) Model for which the configuration and weights were
* saved separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Model configuration
* @param weightsHdf5Filename path to HDF5 archive storing Keras model weights
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @throws IOException IO exception
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(String modelJsonFilename, String weightsHdf5Filename,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(false)
.weightsHdf5FilenameNoRoot(weightsHdf5Filename).enforceTrainingConfig(enforceTrainingConfig)
.buildModel();
return kerasModel.getComputationGraph();
}
/**
* Load Keras (Functional API) Model for which the configuration and weights were
* saved separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Model configuration
* @param weightsHdf5Filename path to HDF5 archive storing Keras model weights
* @return ComputationGraph
* @throws IOException IO exception
* @see ComputationGraph
*/
public static ComputationGraph importKerasModelAndWeights(String modelJsonFilename, String weightsHdf5Filename)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(false)
.weightsHdf5FilenameNoRoot(weightsHdf5Filename).enforceTrainingConfig(true).buildModel();
return kerasModel.getComputationGraph();
}
/**
* Load Keras Sequential model for which the configuration and weights were
* saved separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Sequential model configuration
* @param weightsHdf5Filename path to HDF5 archive storing Keras model weights
* @param enforceTrainingConfig whether to enforce training configuration options
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(String modelJsonFilename,
String weightsHdf5Filename,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.weightsHdf5FilenameNoRoot(weightsHdf5Filename).enforceTrainingConfig(enforceTrainingConfig)
.buildSequential();
return kerasModel.getMultiLayerNetwork();
}
/**
* Load Keras Sequential model for which the configuration and weights were
* saved separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Sequential model configuration
* @param weightsHdf5Filename path to HDF5 archive storing Keras model weights
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerNetwork importKerasSequentialModelAndWeights(String modelJsonFilename,
String weightsHdf5Filename)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.weightsHdf5FilenameNoRoot(weightsHdf5Filename).enforceTrainingConfig(false).buildSequential();
return kerasModel.getMultiLayerNetwork();
}
/**
* Load Keras (Functional API) Model for which the configuration was saved
* separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Model configuration
* @param enforceTrainingConfig whether to enforce training configuration options
* @return ComputationGraph
* @throws IOException IO exception
* @see ComputationGraph
*/
public static ComputationGraphConfiguration importKerasModelConfiguration(String modelJsonFilename,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(enforceTrainingConfig).buildModel();
return kerasModel.getComputationGraphConfiguration();
}
/**
* Load Keras (Functional API) Model for which the configuration was saved
* separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Model configuration
* @return ComputationGraph
* @throws IOException IO exception
* @see ComputationGraph
*/
public static ComputationGraphConfiguration importKerasModelConfiguration(String modelJsonFilename)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasModel kerasModel = new KerasModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(false).buildModel();
return kerasModel.getComputationGraphConfiguration();
}
/**
* Load Keras Sequential model for which the configuration was saved
* separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Sequential model configuration
* @param enforceTrainingConfig whether to enforce training configuration options
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerConfiguration importKerasSequentialConfiguration(String modelJsonFilename,
boolean enforceTrainingConfig)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(enforceTrainingConfig).buildSequential();
return kerasModel.getMultiLayerConfiguration();
}
/**
* Load Keras Sequential model for which the configuration was saved
* separately using calls to model.to_json() and model.save_weights(...).
*
* @param modelJsonFilename path to JSON file storing Keras Sequential model configuration
* @return MultiLayerNetwork
* @throws IOException IO exception
* @see MultiLayerNetwork
*/
public static MultiLayerConfiguration importKerasSequentialConfiguration(String modelJsonFilename)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel kerasModel = new KerasSequentialModel().modelBuilder().modelJsonFilename(modelJsonFilename)
.enforceTrainingConfig(false).buildSequential();
return kerasModel.getMultiLayerConfiguration();
}
private static File toTempFile(InputStream is) throws IOException {
File f = ND4JFileUtils.createTempFile("DL4JKerasModelImport",".bin");
f.deleteOnExit();
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(f))) {
IOUtils.copy(is, os);
os.flush();
return f;
}
}
}
@@ -0,0 +1,269 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.conf.*;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelUtils;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.modelimport.keras.layers.KerasInput;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.common.base.Preconditions;
import org.nd4j.common.primitives.Pair;
import org.nd4j.common.util.ArrayUtil;
import java.io.IOException;
import java.util.*;
@Slf4j
public class KerasSequentialModel extends KerasModel {
/**
* (Recommended) Builder-pattern constructor for Sequential model.
*
* @param modelBuilder builder object
* @throws IOException I/O exception
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasSequentialModel(KerasModelBuilder modelBuilder)
throws UnsupportedKerasConfigurationException, IOException, InvalidKerasConfigurationException {
this(modelBuilder.getModelJson(), modelBuilder.getModelYaml(), modelBuilder.getWeightsArchive(),
modelBuilder.getWeightsRoot(), modelBuilder.getTrainingJson(), modelBuilder.getTrainingArchive(),
modelBuilder.isEnforceTrainingConfig(), modelBuilder.getInputShape());
}
/**
* (Not recommended) Constructor for Sequential model from model configuration
* (JSON or YAML), training configuration (JSON), weights, and "training mode"
* boolean indicator. When built in training mode, certain unsupported configurations
* (e.g., unknown regularizers) will throw Exceptions. When enforceTrainingConfig=false, these
* will generate warnings but will be otherwise ignored.
*
* @param modelJson model configuration JSON string
* @param modelYaml model configuration YAML string
* @param trainingJson training configuration JSON string
* @throws IOException I/O exception
*/
public KerasSequentialModel(String modelJson, String modelYaml, Hdf5Archive weightsArchive, String weightsRoot,
String trainingJson, Hdf5Archive trainingArchive, boolean enforceTrainingConfig,
int[] inputShape)
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> modelConfig = KerasModelUtils.parseModelConfig(modelJson, modelYaml);
this.kerasMajorVersion = KerasModelUtils.determineKerasMajorVersion(modelConfig, config);
this.kerasBackend = KerasModelUtils.determineKerasBackend(modelConfig, config);
this.enforceTrainingConfig = enforceTrainingConfig;
/* Determine model configuration type. */
if (!modelConfig.containsKey(config.getFieldClassName()))
throw new InvalidKerasConfigurationException(
"Could not determine Keras model class (no " + config.getFieldClassName() + " field found)");
this.className = (String) modelConfig.get(config.getFieldClassName());
if (!this.className.equals(config.getFieldClassNameSequential()))
throw new InvalidKerasConfigurationException("Model class name must be " + config.getFieldClassNameSequential()
+ " (found " + this.className + ")");
/* Process layer configurations. */
if (!modelConfig.containsKey(config.getModelFieldConfig()))
throw new InvalidKerasConfigurationException(
"Could not find layer configurations (no " + config.getModelFieldConfig() + " field found)");
// Prior to Keras 2.2.3 the "config" of a Sequential model was a list of layer configurations. For consistency
// "config" is now an object containing a "name" and "layers", the latter contain the same data as before.
// This change only affects Sequential models.
List<Object> layerList;
if(modelConfig.get(config.getModelFieldConfig()) instanceof List) {
layerList = (List<Object>) modelConfig.get(config.getModelFieldConfig());
} else {
HashMap layerMap = (HashMap<String, Object>) modelConfig.get(config.getModelFieldConfig());
layerList = (List<Object>) layerMap.get("layers");
}
Pair<Map<String, KerasLayer>, List<KerasLayer>> layerPair =
prepareLayers(layerList);
this.layers = layerPair.getFirst();
this.layersOrdered = layerPair.getSecond();
KerasLayer inputLayer;
if (this.layersOrdered.get(0) instanceof KerasInput) {
inputLayer = this.layersOrdered.get(0);
} else {
/* Add placeholder input layer and update lists of input and output layers. */
int[] firstLayerInputShape = this.layersOrdered.get(0).getInputShape();
Preconditions.checkState(ArrayUtil.prod(firstLayerInputShape) > 0,"Input shape must not be zero!");
inputLayer = new KerasInput("input1", firstLayerInputShape);
inputLayer.setDimOrder(this.layersOrdered.get(0).getDimOrder());
this.layers.put(inputLayer.getLayerName(), inputLayer);
this.layersOrdered.add(0, inputLayer);
}
this.inputLayerNames = new ArrayList<>(Collections.singletonList(inputLayer.getLayerName()));
this.outputLayerNames = new ArrayList<>(
Collections.singletonList(this.layersOrdered.get(this.layersOrdered.size() - 1).getLayerName()));
/* Update each layer's inbound layer list to include (only) previous layer. */
KerasLayer prevLayer = null;
for (KerasLayer layer : this.layersOrdered) {
if (prevLayer != null)
layer.setInboundLayerNames(Collections.singletonList(prevLayer.getLayerName()));
prevLayer = layer;
}
/* Import training configuration. */
if (enforceTrainingConfig) {
if (trainingJson != null)
importTrainingConfiguration(trainingJson);
else log.warn("If enforceTrainingConfig is true, a training " +
"configuration object has to be provided. Usually the only practical way to do this is to store" +
" your keras model with `model.save('model_path.h5'. If you store model config and weights" +
" separately no training configuration is attached.");
}
if(inputShape == null) {
inputShape = layersOrdered.get(0).getInputShape();
}
this.outputTypes = inferOutputTypes(inputShape);
if (weightsArchive != null)
KerasModelUtils.importWeights(weightsArchive, weightsRoot, layers, kerasMajorVersion, kerasBackend);
}
/**
* Default constructor
*/
public KerasSequentialModel() {
super();
}
/**
* Configure a MultiLayerConfiguration from this Keras Sequential model configuration.
*
* @return MultiLayerConfiguration
*/
public MultiLayerConfiguration getMultiLayerConfiguration()
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
if (!this.className.equals(config.getFieldClassNameSequential()))
throw new InvalidKerasConfigurationException(
"Keras model class name " + this.className + " incompatible with MultiLayerNetwork");
if (this.inputLayerNames.size() != 1)
throw new InvalidKerasConfigurationException(
"MultiLayerNetwork expects only 1 input (found " + this.inputLayerNames.size() + ")");
if (this.outputLayerNames.size() != 1)
throw new InvalidKerasConfigurationException(
"MultiLayerNetwork expects only 1 output (found " + this.outputLayerNames.size() + ")");
NeuralNetConfiguration.Builder modelBuilder = new NeuralNetConfiguration.Builder();
if (optimizer != null) {
modelBuilder.updater(optimizer);
}
ListBuilder listBuilder = modelBuilder.list();
//don't forcibly over ride for keras import
listBuilder.overrideNinUponBuild(false);
/* Add layers one at a time. */
KerasLayer prevLayer = null;
int layerIndex = 0;
for (KerasLayer layer : this.layersOrdered) {
if (layer.isLayer()) {
int nbInbound = layer.getInboundLayerNames().size();
if (nbInbound != 1)
throw new InvalidKerasConfigurationException(
"Layers in MultiLayerConfiguration must have exactly one inbound layer (found "
+ nbInbound + " for layer " + layer.getLayerName() + ")");
if (prevLayer != null) {
InputType[] inputTypes = new InputType[1];
InputPreProcessor preprocessor;
if (prevLayer.isInputPreProcessor()) {
inputTypes[0] = this.outputTypes.get(prevLayer.getInboundLayerNames().get(0));
preprocessor = prevLayer.getInputPreprocessor(inputTypes);
KerasModelUtils.setDataFormatIfNeeded(preprocessor,layer);
InputType outputType = preprocessor.getOutputType(inputTypes[0]);
layer.getLayer().setNIn(outputType,listBuilder.isOverrideNinUponBuild());
} else {
inputTypes[0] = this.outputTypes.get(prevLayer.getLayerName());
preprocessor = layer.getInputPreprocessor(inputTypes);
if(preprocessor != null) {
InputType outputType = preprocessor.getOutputType(inputTypes[0]);
layer.getLayer().setNIn(outputType,listBuilder.isOverrideNinUponBuild());
}
else
layer.getLayer().setNIn(inputTypes[0],listBuilder.isOverrideNinUponBuild());
KerasModelUtils.setDataFormatIfNeeded(preprocessor,layer);
}
if (preprocessor != null)
listBuilder.inputPreProcessor(layerIndex, preprocessor);
}
listBuilder.layer(layerIndex++, layer.getLayer());
} else if (layer.getVertex() != null)
throw new InvalidKerasConfigurationException("Cannot add vertex to MultiLayerConfiguration (class name "
+ layer.getClassName() + ", layer name " + layer.getLayerName() + ")");
prevLayer = layer;
}
/* Whether to use standard backprop (or BPTT) or truncated BPTT. */
if (this.useTruncatedBPTT && this.truncatedBPTT > 0)
listBuilder.backpropType(BackpropType.TruncatedBPTT).tBPTTForwardLength(truncatedBPTT)
.tBPTTBackwardLength(truncatedBPTT);
else
listBuilder.backpropType(BackpropType.Standard);
MultiLayerConfiguration build = listBuilder.build();
return build;
}
/**
* Build a MultiLayerNetwork from this Keras Sequential model configuration.
*
* @return MultiLayerNetwork
*/
public MultiLayerNetwork getMultiLayerNetwork()
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
return getMultiLayerNetwork(true);
}
/**
* Build a MultiLayerNetwork from this Keras Sequential model configuration and import weights.
*
* @return MultiLayerNetwork
*/
public MultiLayerNetwork getMultiLayerNetwork(boolean importWeights)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
MultiLayerNetwork model = new MultiLayerNetwork(getMultiLayerConfiguration());
model.init();
if (importWeights)
model = (MultiLayerNetwork) KerasModelUtils.copyWeightsToModel(model, this.layers);
return model;
}
}
@@ -0,0 +1,113 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.config;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* All relevant property fields of keras 1.x layers.
*
* @author Max Pumperla
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Keras1LayerConfiguration extends KerasLayerConfiguration {
/* Basic layer names */
private final String LAYER_CLASS_NAME_CONVOLUTION_1D = "Convolution1D";
private final String LAYER_CLASS_NAME_CONVOLUTION_2D = "Convolution2D";
private final String LAYER_CLASS_NAME_CONVOLUTION_3D = "Convolution3D";
private final String LAYER_CLASS_NAME_SEPARABLE_CONVOLUTION_2D = "SeparableConvolution2D";
private final String LAYER_CLASS_NAME_DECONVOLUTION_2D = "Deconvolution2D";
/* Partially shared layer configurations. */
private final String LAYER_FIELD_OUTPUT_DIM = "output_dim";
private final String LAYER_FIELD_DROPOUT_RATE = "p";
private final String LAYER_FIELD_USE_BIAS = "bias";
private final String KERAS_PARAM_NAME_W = "W";
private final String KERAS_PARAM_NAME_B = "b";
private final String KERAS_PARAM_NAME_RW = "U";
/* Keras dimension ordering for, e.g., convolutional layersOrdered. */
private final String LAYER_FIELD_DIM_ORDERING = "dim_ordering";
private final String DIM_ORDERING_THEANO = "th";
private final String DIM_ORDERING_TENSORFLOW = "tf";
/* Recurrent layers */
private final String LAYER_FIELD_DROPOUT_W = "dropout_W";
private final String LAYER_FIELD_DROPOUT_U = "dropout_U";
private final String LAYER_FIELD_INNER_INIT = "inner_init";
private final String LAYER_FIELD_INNER_ACTIVATION = "inner_activation";
/* Embedding layer properties */
private final String LAYER_FIELD_EMBEDDING_INIT = "init";
private final String LAYER_FIELD_EMBEDDING_WEIGHTS = "W";
private final String LAYER_FIELD_EMBEDDINGS_REGULARIZER = "W_regularizer";
private final String LAYER_FIELD_EMBEDDINGS_CONSTRAINT = "W_constraint";
/* Normalisation layers */
private final String LAYER_FIELD_BATCHNORMALIZATION_BETA_INIT = "beta_init";
private final String LAYER_FIELD_BATCHNORMALIZATION_GAMMA_INIT = "gamma_init";
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN = "running_mean";
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE = "running_std";
/* Advanced activations */
private final String LAYER_FIELD_PRELU_INIT = "init";
/* Convolutional layer properties */
private final String LAYER_FIELD_NB_FILTER = "nb_filter";
private final String LAYER_FIELD_CONVOLUTION_STRIDES = "subsample";
private final String LAYER_FIELD_FILTER_LENGTH = "filter_length";
private final String LAYER_FIELD_SUBSAMPLE_LENGTH = "subsample_length";
private final String LAYER_FIELD_DILATION_RATE = "atrous_rate";
/* Pooling / Upsampling layer properties */
private final String LAYER_FIELD_POOL_1D_SIZE = "pool_length";
private final String LAYER_FIELD_POOL_1D_STRIDES = "stride";
private final String LAYER_FIELD_UPSAMPLING_1D_SIZE = "length";
/* Keras convolution border modes. */
private final String LAYER_FIELD_BORDER_MODE = "border_mode";
/* Noise layers */
private final String LAYER_FIELD_GAUSSIAN_VARIANCE = "sigma";
/* Keras weight regularizers. */
private final String LAYER_FIELD_W_REGULARIZER = "W_regularizer";
private final String LAYER_FIELD_B_REGULARIZER = "b_regularizer";
/* Keras constraints */
private final String LAYER_FIELD_CONSTRAINT_NAME = "name";
private final String LAYER_FIELD_W_CONSTRAINT = "W_constraint";
private final String LAYER_FIELD_B_CONSTRAINT = "b_constraint";
private final String LAYER_FIELD_MAX_CONSTRAINT = "m";
private final String LAYER_FIELD_MINMAX_MIN_CONSTRAINT = "low";
private final String LAYER_FIELD_MINMAX_MAX_CONSTRAINT = "high";
/* Keras weight initializers. */
private final String LAYER_FIELD_INIT = "init";
}
@@ -0,0 +1,112 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.config;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* All relevant property fields of keras 2.x layers.
*
* @author Max Pumperla
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Keras2LayerConfiguration extends KerasLayerConfiguration {
/* Basic layer names */
private final String LAYER_CLASS_NAME_CONVOLUTION_1D = "Conv1D";
private final String LAYER_CLASS_NAME_CONVOLUTION_2D = "Conv2D";
private final String LAYER_CLASS_NAME_CONVOLUTION_3D = "Conv3D";
private final String LAYER_CLASS_NAME_SEPARABLE_CONVOLUTION_2D = "SeparableConv2D";
private final String LAYER_CLASS_NAME_DECONVOLUTION_2D = "Conv2DTranspose";
/* Partially shared layer configurations. */
private final String LAYER_FIELD_OUTPUT_DIM = "units";
private final String LAYER_FIELD_DROPOUT_RATE = "rate";
private final String LAYER_FIELD_USE_BIAS = "use_bias";
private final String KERAS_PARAM_NAME_W = "kernel";
private final String KERAS_PARAM_NAME_B = "bias";
private final String KERAS_PARAM_NAME_RW = "recurrent_kernel";
/* Keras dimension ordering for, e.g., convolutional layersOrdered. */
private final String LAYER_FIELD_DIM_ORDERING = "data_format";
private final String DIM_ORDERING_THEANO = "channels_first";
private final String DIM_ORDERING_TENSORFLOW = "channels_last";
/* Recurrent layers */
private final String LAYER_FIELD_DROPOUT_W = "dropout";
private final String LAYER_FIELD_DROPOUT_U = "recurrent_dropout";
private final String LAYER_FIELD_INNER_INIT = "recurrent_initializer";
private final String LAYER_FIELD_INNER_ACTIVATION = "recurrent_activation";
/* Embedding layer properties */
private final String LAYER_FIELD_EMBEDDING_INIT = "embeddings_initializer";
private final String LAYER_FIELD_EMBEDDING_WEIGHTS = "embeddings";
private final String LAYER_FIELD_EMBEDDINGS_REGULARIZER = "embeddings_regularizer";
private final String LAYER_FIELD_EMBEDDINGS_CONSTRAINT = "embeddings_constraint";
/* Normalisation layers */
private final String LAYER_FIELD_BATCHNORMALIZATION_BETA_INIT = "beta_initializer";
private final String LAYER_FIELD_BATCHNORMALIZATION_GAMMA_INIT = "gamma_initializer";
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN = "moving_mean";
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE = "moving_variance";
/* Advanced activations */
private final String LAYER_FIELD_PRELU_INIT = "alpha_initializer";
/* Convolutional layer properties */
private final String LAYER_FIELD_NB_FILTER = "filters";
private final String LAYER_FIELD_CONVOLUTION_STRIDES = "strides";
private final String LAYER_FIELD_FILTER_LENGTH = "kernel_size";
private final String LAYER_FIELD_SUBSAMPLE_LENGTH = "strides";
private final String LAYER_FIELD_DILATION_RATE = "dilation_rate";
/* Pooling / Upsampling layer properties */
private final String LAYER_FIELD_POOL_1D_SIZE = "pool_size";
private final String LAYER_FIELD_POOL_1D_STRIDES = "strides";
private final String LAYER_FIELD_UPSAMPLING_1D_SIZE = "size";
/* Keras convolution border modes. */
private final String LAYER_FIELD_BORDER_MODE = "padding";
/* Noise layers */
private final String LAYER_FIELD_GAUSSIAN_VARIANCE = "stddev";
/* Keras weight regularizers. */
private final String LAYER_FIELD_W_REGULARIZER = "kernel_regularizer";
private final String LAYER_FIELD_B_REGULARIZER = "bias_regularizer";
/* Keras constraints */
private final String LAYER_FIELD_CONSTRAINT_NAME = "class_name";
private final String LAYER_FIELD_W_CONSTRAINT = "kernel_constraint";
private final String LAYER_FIELD_B_CONSTRAINT = "bias_constraint";
private final String LAYER_FIELD_MAX_CONSTRAINT = "max_value";
private final String LAYER_FIELD_MINMAX_MIN_CONSTRAINT = "min_value";
private final String LAYER_FIELD_MINMAX_MAX_CONSTRAINT = "max_value";
/* Keras weight initializers. */
private final String LAYER_FIELD_INIT = "kernel_initializer";
private final String TENSORFLOW_OP_LAYER = "TensorFlowOpLayer";
}
@@ -0,0 +1,378 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.config;
import lombok.Data;
/**
* All relevant property fields of keras layers.
* <p>
* Empty String fields mean Keras 1 and 2 implementations differ,
* supplied fields stand for shared properties.
*
* @author Max Pumperla
*/
@Data
public class KerasLayerConfiguration {
private final String LAYER_FIELD_KERAS_VERSION = "keras_version";
private final String LAYER_FIELD_CLASS_NAME = "class_name";
private final String LAYER_FIELD_LAYER = "layer";
private final String LAYER_CLASS_NAME_ACTIVATION = "Activation";
private final String LAYER_CLASS_NAME_INPUT = "InputLayer";
private final String LAYER_CLASS_NAME_PERMUTE = "Permute";
private final String LAYER_CLASS_NAME_DROPOUT = "Dropout";
private final String LAYER_CLASS_NAME_REPEAT = "RepeatVector";
private final String LAYER_CLASS_NAME_LAMBDA = "Lambda";
private final String LAYER_CLASS_NAME_MASKING = "Masking";
private final String LAYER_CLASS_NAME_SPATIAL_DROPOUT_1D = "SpatialDropout1D";
private final String LAYER_CLASS_NAME_SPATIAL_DROPOUT_2D = "SpatialDropout2D";
private final String LAYER_CLASS_NAME_SPATIAL_DROPOUT_3D = "SpatialDropout3D";
private final String LAYER_CLASS_NAME_ALPHA_DROPOUT = "AlphaDropout";
private final String LAYER_CLASS_NAME_GAUSSIAN_DROPOUT = "GaussianDropout";
private final String LAYER_CLASS_NAME_GAUSSIAN_NOISE = "GaussianNoise";
private final String LAYER_CLASS_NAME_DENSE = "Dense";
private final String LAYER_CLASS_NAME_LSTM = "LSTM";
private final String LAYER_CLASS_NAME_SIMPLE_RNN = "SimpleRNN";
private final String LAYER_CLASS_NAME_BIDIRECTIONAL = "Bidirectional";
private final String LAYER_CLASS_NAME_TIME_DISTRIBUTED = "TimeDistributed";
private final String LAYER_CLASS_NAME_MAX_POOLING_1D = "MaxPooling1D";
private final String LAYER_CLASS_NAME_MAX_POOLING_2D = "MaxPooling2D";
private final String LAYER_CLASS_NAME_MAX_POOLING_3D = "MaxPooling3D";
private final String LAYER_CLASS_NAME_AVERAGE_POOLING_1D = "AveragePooling1D";
private final String LAYER_CLASS_NAME_AVERAGE_POOLING_2D = "AveragePooling2D";
private final String LAYER_CLASS_NAME_AVERAGE_POOLING_3D = "AveragePooling3D";
private final String LAYER_CLASS_NAME_ZERO_PADDING_1D = "ZeroPadding1D";
private final String LAYER_CLASS_NAME_ZERO_PADDING_2D = "ZeroPadding2D";
private final String LAYER_CLASS_NAME_ZERO_PADDING_3D = "ZeroPadding3D";
private final String LAYER_CLASS_NAME_CROPPING_1D = "Cropping1D";
private final String LAYER_CLASS_NAME_CROPPING_2D = "Cropping2D";
private final String LAYER_CLASS_NAME_CROPPING_3D = "Cropping3D";
private final String LAYER_CLASS_NAME_FLATTEN = "Flatten";
private final String LAYER_CLASS_NAME_RESHAPE = "Reshape";
private final String LAYER_CLASS_NAME_MERGE = "Merge";
private final String LAYER_CLASS_NAME_ADD = "Add";
private final String LAYER_CLASS_NAME_FUNCTIONAL_ADD = "add";
private final String LAYER_CLASS_NAME_SUBTRACT = "Subtract";
private final String LAYER_CLASS_NAME_FUNCTIONAL_SUBTRACT = "subtract";
private final String LAYER_CLASS_NAME_MULTIPLY = "Multiply";
private final String LAYER_CLASS_NAME_FUNCTIONAL_MULTIPLY = "multiply";
private final String LAYER_CLASS_NAME_AVERAGE = "Average";
private final String LAYER_CLASS_NAME_FUNCTIONAL_AVERAGE = "average";
private final String LAYER_CLASS_NAME_MAXIMUM = "Maximum";
private final String LAYER_CLASS_NAME_FUNCTIONAL_MAXIMUM = "maximum";
private final String LAYER_CLASS_NAME_CONCATENATE = "Concatenate";
private final String LAYER_CLASS_NAME_FUNCTIONAL_CONCATENATE = "concatenate";
private final String LAYER_CLASS_NAME_DOT = "Dot";
private final String LAYER_CLASS_NAME_FUNCTIONAL_DOT = "dot";
private final String LAYER_CLASS_NAME_ATTENTION = "Attention";
private final String LAYER_CLASS_NAME_BATCHNORMALIZATION = "BatchNormalization";
private final String LAYER_CLASS_NAME_EMBEDDING = "Embedding";
private final String LAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D = "GlobalMaxPooling1D";
private final String LAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D = "GlobalMaxPooling2D";
private final String LAYER_CLASS_NAME_GLOBAL_MAX_POOLING_3D = "GlobalMaxPooling3D";
private final String LAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D = "GlobalAveragePooling1D";
private final String LAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D = "GlobalAveragePooling2D";
private final String LAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_3D = "GlobalAveragePooling3D";
private final String LAYER_CLASS_NAME_TIME_DISTRIBUTED_DENSE = "TimeDistributedDense"; // Keras 1 only
private final String LAYER_CLASS_NAME_ATROUS_CONVOLUTION_1D = "AtrousConvolution1D"; // Keras 1 only
private final String LAYER_CLASS_NAME_ATROUS_CONVOLUTION_2D = "AtrousConvolution2D"; // Keras 1 only
private final String LAYER_CLASS_NAME_CONVOLUTION_1D = ""; // 1: Convolution1D, 2: Conv1D
private final String LAYER_CLASS_NAME_CONVOLUTION_2D = ""; // 1: Convolution2D, 2: Conv2D
private final String LAYER_CLASS_NAME_CONVOLUTION_3D = ""; // 1: Convolution2D, 2: Conv2D
private final String LAYER_CLASS_NAME_LEAKY_RELU = "LeakyReLU";
private final String LAYER_CLASS_NAME_PRELU = "PReLU";
private final String LAYER_CLASS_NAME_THRESHOLDED_RELU = "ThresholdedReLU";
private final String LAYER_CLASS_NAME_RELU = "ReLU";
private final String LAYER_CLASS_NAME_ELU = "ELU";
private final String LAYER_CLASS_NAME_SOFTMAX = "Softmax";
private final String LAYER_CLASS_NAME_UPSAMPLING_1D = "UpSampling1D";
private final String LAYER_CLASS_NAME_UPSAMPLING_2D = "UpSampling2D";
private final String LAYER_CLASS_NAME_UPSAMPLING_3D = "UpSampling3D";
private final String LAYER_CLASS_NAME_DEPTHWISE_CONVOLUTION_2D = "DepthwiseConv2D"; // Keras 2 only
private final String LAYER_CLASS_NAME_SEPARABLE_CONVOLUTION_1D = "SeparableConv1D"; // Keras 2 only
private final String LAYER_CLASS_NAME_SEPARABLE_CONVOLUTION_2D = ""; // 1: SeparableConvolution2D, 2: SeparableConv2D
private final String LAYER_CLASS_NAME_DECONVOLUTION_2D = ""; // 1: Deconvolution2D, 2: Conv2DTranspose
private final String LAYER_CLASS_NAME_DECONVOLUTION_3D = "Conv3DTranspose"; // Keras 2 only
// Locally connected layers
private final String LAYER_CLASS_NAME_LOCALLY_CONNECTED_2D = "LocallyConnected2D";
private final String LAYER_CLASS_NAME_LOCALLY_CONNECTED_1D = "LocallyConnected1D";
/* Partially shared layer configurations. */
private final String LAYER_FIELD_INPUT_SHAPE = "input_shape";
private final String LAYER_FIELD_CONFIG = "config";
private final String LAYER_FIELD_NAME = "name";
private final String LAYER_FIELD_BATCH_INPUT_SHAPE = "batch_input_shape";
private final String LAYER_FIELD_INBOUND_NODES = "inbound_nodes";
private final String LAYER_FIELD_OUTBOUND_NODES = "outbound_nodes";
private final String LAYER_FIELD_DROPOUT = "dropout";
private final String LAYER_FIELD_ACTIVITY_REGULARIZER = "activity_regularizer";
private final String LAYER_FIELD_EMBEDDING_OUTPUT_DIM = "output_dim";
private final String LAYER_FIELD_OUTPUT_DIM = ""; // 1: output_dim, 2: units
private final String LAYER_FIELD_DROPOUT_RATE = ""; // 1: p, 2: rate
private final String LAYER_FIELD_USE_BIAS = ""; // 1: bias, 2: use_bias
private final String KERAS_PARAM_NAME_W = ""; // 1: W, 2: kernel
private final String KERAS_PARAM_NAME_B = ""; // 1: b, 2: bias
private final String KERAS_PARAM_NAME_RW = ""; // 1: U, 2: recurrent_kernel
/* Utils */
private final String LAYER_FIELD_REPEAT_MULTIPLIER = "n";
/* Keras dimension ordering for, e.g., convolutional layersOrdered. */
private final String LAYER_FIELD_BACKEND = "backend"; // not available in keras 1, caught in code
private final String LAYER_FIELD_DIM_ORDERING = ""; // 1: dim_ordering, 2: data_format
private final String DIM_ORDERING_THEANO = ""; // 1: th, 2: channels_first
private final String DIM_ORDERING_TENSORFLOW = ""; // 1: tf, 2: channels_last
/* Recurrent layers */
private final String LAYER_FIELD_DROPOUT_W = ""; // 1: dropout_W, 2: dropout
private final String LAYER_FIELD_DROPOUT_U = ""; // 2: dropout_U, 2: recurrent_dropout
private final String LAYER_FIELD_INNER_INIT = ""; // 1: inner_init, 2: recurrent_initializer
private final String LAYER_FIELD_RECURRENT_CONSTRAINT = "recurrent_constraint"; // keras 2 only
private final String LAYER_FIELD_RECURRENT_DROPOUT = ""; // 1: dropout_U, 2: recurrent_dropout
private final String LAYER_FIELD_INNER_ACTIVATION = ""; // 1: inner_activation, 2: recurrent_activation
private final String LAYER_FIELD_FORGET_BIAS_INIT = "forget_bias_init"; // keras 1 only: string
private final String LAYER_FIELD_UNIT_FORGET_BIAS = "unit_forget_bias";
private final String LAYER_FIELD_RETURN_SEQUENCES = "return_sequences";
private final String LAYER_FIELD_UNROLL = "unroll";
/* Embedding layer properties */
private final String LAYER_FIELD_INPUT_DIM = "input_dim";
private final String LAYER_FIELD_EMBEDDING_INIT = ""; // 1: "init", 2: "embeddings_initializer"
private final String LAYER_FIELD_EMBEDDING_WEIGHTS = ""; // 1: "W", 2: "embeddings"
private final String LAYER_FIELD_EMBEDDINGS_REGULARIZER = ""; // 1: W_regularizer, 2: embeddings_regularizer
private final String LAYER_FIELD_EMBEDDINGS_CONSTRAINT = ""; // 1: W_constraint, 2: embeddings_constraint
private final String LAYER_FIELD_MASK_ZERO = "mask_zero";
private final String LAYER_FIELD_INPUT_LENGTH = "input_length";
/* Masking layer properties */
private final String LAYER_FIELD_MASK_VALUE = "mask_value";
/* Keras separable convolution types */
private final String LAYER_PARAM_NAME_DEPTH_WISE_KERNEL = "depthwise_kernel";
private final String LAYER_PARAM_NAME_POINT_WISE_KERNEL = "pointwise_kernel";
private final String LAYER_FIELD_DEPTH_MULTIPLIER = "depth_multiplier";
private final String LAYER_FIELD_DEPTH_WISE_INIT = "depthwise_initializer";
private final String LAYER_FIELD_POINT_WISE_INIT = "pointwise_initializer";
private final String LAYER_FIELD_DEPTH_WISE_REGULARIZER = "depthwise_regularizer";
private final String LAYER_FIELD_POINT_WISE_REGULARIZER = "pointwise_regularizer";
private final String LAYER_FIELD_DEPTH_WISE_CONSTRAINT = "depthwise_constraint";
private final String LAYER_FIELD_POINT_WISE_CONSTRAINT = "pointwise_constraint";
/* Normalisation layers */
// Missing: keras 2 moving_mean_initializer, moving_variance_initializer
private final String LAYER_FIELD_BATCHNORMALIZATION_MODE = "mode"; // keras 1 only
private final String LAYER_FIELD_BATCHNORMALIZATION_BETA_INIT = ""; // 1: beta_init, 2: beta_initializer
private final String LAYER_FIELD_BATCHNORMALIZATION_GAMMA_INIT = ""; // 1: gamma_init, 2: gamma_initializer
private final String LAYER_FIELD_BATCHNORMALIZATION_BETA_CONSTRAINT = "beta_constraint"; // keras 2 only
private final String LAYER_FIELD_BATCHNORMALIZATION_GAMMA_CONSTRAINT = "gamma_constraint"; // keras 2 only
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN = ""; // 1: running_mean, 2: moving_mean
private final String LAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE = ""; // 1: running_std, 2: moving_variance
/* Advanced activations */
// Missing: LeakyReLU, PReLU, ThresholdedReLU, ParametricSoftplus, SReLu
private final String LAYER_FIELD_PRELU_INIT = ""; // 1: init, 2: alpha_initializer
/* Convolutional layer properties */
private final String LAYER_FIELD_NB_FILTER = ""; // 1: nb_filter, 2: filters
private final String LAYER_FIELD_NB_ROW = "nb_row"; // keras 1 only
private final String LAYER_FIELD_NB_COL = "nb_col"; // keras 1 only
private final String LAYER_FIELD_KERNEL_SIZE = "kernel_size"; // keras 2 only
private final String LAYER_FIELD_POOL_SIZE = "pool_size";
private final String LAYER_FIELD_CONVOLUTION_STRIDES = ""; // 1: subsample, 2: strides
private final String LAYER_FIELD_FILTER_LENGTH = ""; // 1: filter_length, 2: kernel_size
private final String LAYER_FIELD_SUBSAMPLE_LENGTH = ""; // 1: subsample_length, 2: strides
private final String LAYER_FIELD_DILATION_RATE = ""; // 1: atrous_rate, 2: dilation_rate
private final String LAYER_FIELD_ZERO_PADDING = "padding";
private final String LAYER_FIELD_CROPPING = "cropping";
private final String LAYER_FIELD_3D_KERNEL_1 = "kernel_dim1"; // keras 1 only
private final String LAYER_FIELD_3D_KERNEL_2 = "kernel_dim2"; // keras 1 only
private final String LAYER_FIELD_3D_KERNEL_3 = "kernel_dim3"; // keras 1 only
/* Pooling / Upsampling layer properties */
private final String LAYER_FIELD_POOL_STRIDES = "strides";
private final String LAYER_FIELD_POOL_1D_SIZE = ""; // 1: pool_length, 2: pool_size
private final String LAYER_FIELD_POOL_1D_STRIDES = ""; // 1: stride, 2: strides
private final String LAYER_FIELD_UPSAMPLING_1D_SIZE = ""; // 1: length, 2: size
private final String LAYER_FIELD_UPSAMPLING_2D_SIZE = "size";
private final String LAYER_FIELD_UPSAMPLING_3D_SIZE = "size";
/* Keras convolution border modes. */
private final String LAYER_FIELD_BORDER_MODE = ""; // 1: border_mode, 2: padding
private final String LAYER_BORDER_MODE_SAME = "same";
private final String LAYER_BORDER_MODE_VALID = "valid";
private final String LAYER_BORDER_MODE_FULL = "full";
private final String LAYER_BORDER_MODE_CAUSAL = "causal";
/* Noise layers */
private final String LAYER_FIELD_RATE = "rate";
private final String LAYER_FIELD_GAUSSIAN_VARIANCE = ""; // 1: sigma, 2: stddev
/* Layer wrappers */
// Missing: TimeDistributed
/* Keras weight regularizers. */
private final String LAYER_FIELD_W_REGULARIZER = ""; // 1: W_regularizer, 2: kernel_regularizer
private final String LAYER_FIELD_B_REGULARIZER = ""; // 1: b_regularizer, 2: bias_regularizer
private final String REGULARIZATION_TYPE_L1 = "l1";
private final String REGULARIZATION_TYPE_L2 = "l2";
/* Keras constraints */
private final String LAYER_FIELD_MINMAX_NORM_CONSTRAINT = "MinMaxNorm";
private final String LAYER_FIELD_MINMAX_NORM_CONSTRAINT_ALIAS = "min_max_norm";
private final String LAYER_FIELD_MAX_NORM_CONSTRAINT = "MaxNorm";
private final String LAYER_FIELD_MAX_NORM_CONSTRAINT_ALIAS = "max_norm";
private final String LAYER_FIELD_MAX_NORM_CONSTRAINT_ALIAS_2 = "maxnorm";
private final String LAYER_FIELD_NON_NEG_CONSTRAINT = "NonNeg";
private final String LAYER_FIELD_NON_NEG_CONSTRAINT_ALIAS = "nonneg";
private final String LAYER_FIELD_NON_NEG_CONSTRAINT_ALIAS_2 = "non_neg";
private final String LAYER_FIELD_UNIT_NORM_CONSTRAINT = "UnitNorm";
private final String LAYER_FIELD_UNIT_NORM_CONSTRAINT_ALIAS = "unitnorm";
private final String LAYER_FIELD_UNIT_NORM_CONSTRAINT_ALIAS_2 = "unit_norm";
private final String LAYER_FIELD_CONSTRAINT_NAME = ""; // 1: name, 2: class_name
private final String LAYER_FIELD_W_CONSTRAINT = ""; // 1: W_constraint, 2: kernel_constraint
private final String LAYER_FIELD_B_CONSTRAINT = ""; // 1: b_constraint, 2: bias_constraint
private final String LAYER_FIELD_MAX_CONSTRAINT = ""; // 1: m, 2: max_value
private final String LAYER_FIELD_MINMAX_MIN_CONSTRAINT = ""; // 1: low, 2: min_value
private final String LAYER_FIELD_MINMAX_MAX_CONSTRAINT = ""; // 1: high, 2: max_value
private final String LAYER_FIELD_CONSTRAINT_DIM = "axis";
private final String LAYER_FIELD_CONSTRAINT_RATE = "rate";
/* Keras weight initializers. */
private final String LAYER_FIELD_INIT = ""; // 1: init, 2: kernel_initializer
private final String LAYER_FIELD_BIAS_INIT = "bias_initializer"; // keras 2 only
private final String LAYER_FIELD_INIT_MEAN = "mean";
private final String LAYER_FIELD_INIT_STDDEV = "stddev";
private final String LAYER_FIELD_INIT_SCALE = "scale";
private final String LAYER_FIELD_INIT_MINVAL = "minval";
private final String LAYER_FIELD_INIT_MAXVAL = "maxval";
private final String LAYER_FIELD_INIT_VALUE = "value";
private final String LAYER_FIELD_INIT_GAIN = "gain";
private final String LAYER_FIELD_INIT_MODE = "mode";
private final String LAYER_FIELD_INIT_DISTRIBUTION = "distribution";
private final String INIT_UNIFORM = "uniform";
private final String INIT_RANDOM_UNIFORM = "random_uniform";
private final String INIT_RANDOM_UNIFORM_ALIAS = "RandomUniform";
private final String INIT_ZERO = "zero";
private final String INIT_ZEROS = "zeros";
private final String INIT_ZEROS_ALIAS = "Zeros";
private final String INIT_ONE = "one";
private final String INIT_ONES = "ones";
private final String INIT_ONES_ALIAS = "Ones";
private final String INIT_CONSTANT = "constant";
private final String INIT_CONSTANT_ALIAS = "Constant";
private final String INIT_TRUNCATED_NORMAL = "truncated_normal";
private final String INIT_TRUNCATED_NORMAL_ALIAS = "TruncatedNormal";
private final String INIT_GLOROT_NORMAL = "glorot_normal";
private final String INIT_GLOROT_NORMAL_ALIAS = "GlorotNormal";
private final String INIT_GLOROT_UNIFORM = "glorot_uniform";
private final String INIT_GLOROT_UNIFORM_ALIAS = "GlorotUniform";
private final String INIT_HE_NORMAL = "he_normal";
private final String INIT_HE_NORMAL_ALIAS = "HeNormal";
private final String INIT_HE_UNIFORM = "he_uniform";
private final String INIT_HE_UNIFORM_ALIAS = "HeUniform";
private final String INIT_LECUN_UNIFORM = "lecun_uniform";
private final String INIT_LECUN_UNIFORM_ALIAS = "LecunUniform";
private final String INIT_LECUN_NORMAL = "lecun_normal";
private final String INIT_LECUN_NORMAL_ALIAS = "LecunNormal";
private final String INIT_NORMAL = "normal";
private final String INIT_RANDOM_NORMAL = "random_normal";
private final String INIT_RANDOM_NORMAL_ALIAS = "RandomNormal";
private final String INIT_ORTHOGONAL = "orthogonal";
private final String INIT_ORTHOGONAL_ALIAS = "Orthogonal";
private final String INIT_IDENTITY = "identity";
private final String INIT_IDENTITY_ALIAS = "Identity";
private final String INIT_VARIANCE_SCALING = "VarianceScaling"; // keras 2 only
/* Keras and DL4J activation types. */
private final String LAYER_FIELD_ACTIVATION = "activation";
private final String KERAS_ACTIVATION_SOFTMAX = "softmax";
private final String KERAS_ACTIVATION_SOFTPLUS = "softplus";
private final String KERAS_ACTIVATION_SOFTSIGN = "softsign";
private final String KERAS_ACTIVATION_RELU = "relu";
private final String KERAS_ACTIVATION_RELU6 = "relu6";
private final String KERAS_ACTIVATION_TANH = "tanh";
private final String KERAS_ACTIVATION_SIGMOID = "sigmoid";
private final String KERAS_ACTIVATION_HARD_SIGMOID = "hard_sigmoid";
private final String KERAS_ACTIVATION_LINEAR = "linear";
private final String KERAS_ACTIVATION_SWISH = "swish";
private final String KERAS_ACTIVATION_ELU = "elu"; // keras 2 only
private final String KERAS_ACTIVATION_SELU = "selu"; // keras 2 only
/* Keras loss functions. */
private final String KERAS_LOSS_MEAN_SQUARED_ERROR = "mean_squared_error";
private final String TF_KERAS_LOSS_MEAN_SQUARED_ERROR = "meansquarederror";
private final String KERAS_LOSS_MSE = "mse";
private final String KERAS_LOSS_MEAN_ABSOLUTE_ERROR = "mean_absolute_error";
private final String TF_KERAS_LOSS_MEAN_ABSOLUTE_ERROR = "meanabsoluteerror";
private final String KERAS_LOSS_MAE = "mae";
private final String KERAS_LOSS_MEAN_ABSOLUTE_PERCENTAGE_ERROR = "mean_absolute_percentage_error";
private final String TF_KERAS_LOSS_MEAN_ABSOLUTE_PERCENTAGE_ERROR = "meanabsolutepercentageerror";
private final String KERAS_LOSS_MAPE = "mape";
private final String KERAS_LOSS_MEAN_SQUARED_LOGARITHMIC_ERROR = "mean_squared_logarithmic_error";
private final String TF_KERAS_LOSS_MEAN_SQUARED_LOGARITHMIC_ERROR = "meansquaredlogarithmicerror";
private final String KERAS_LOSS_MSLE = "msle";
private final String KERAS_LOSS_SQUARED_HINGE = "squared_hinge";
private final String TF_KERAS_LOSS_SQUARED_HINGE = "squaredhinge";
private final String KERAS_LOSS_HINGE = "hinge";
private final String KERAS_LOSS_CATEGORICAL_HINGE = "categorical_hinge"; // keras 2 only
private final String KERAS_LOSS_BINARY_CROSSENTROPY = "binary_crossentropy";
private final String TF_KERAS_LOSS_BINARY_CROSSENTROPY = "binarycrossentropy";
private final String KERAS_LOSS_CATEGORICAL_CROSSENTROPY = "categorical_crossentropy";
private final String KERAS_LOSS_SPARSE_CATEGORICAL_CROSSENTROPY = "sparse_categorical_crossentropy";
private final String TF_KERAS_LOSS_SPARSE_CATEGORICAL_CROSS_ENTROPY = "sparsecategoricalcrossentropy";
private final String KERAS_LOSS_KULLBACK_LEIBLER_DIVERGENCE = "kullback_leibler_divergence";
private final String TF_KERAS_LOSS_KLDIVERGENCE = "kldivergence";
private final String KERAS_LOSS_KLD = "kld";
private final String KERAS_LOSS_POISSON = "poisson";
private final String KERAS_LOSS_COSINE_PROXIMITY = "cosine_proximity";
private final String TF_KERAS_LOSS_COSINE_SIMILARITY = "cosinesimilarity";
private final String KERAS_LOSS_LOG_COSH = "logcosh"; // keras 2 only
}
@@ -0,0 +1,41 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.config;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
@Slf4j
public class KerasLayerConfigurationFactory {
public KerasLayerConfigurationFactory() {
}
public static KerasLayerConfiguration get(Integer kerasMajorVersion) throws UnsupportedKerasConfigurationException {
if (kerasMajorVersion != 1 && kerasMajorVersion != 2)
throw new UnsupportedKerasConfigurationException(
"Keras major version has to be either 1 or 2 (" + kerasMajorVersion + " provided)");
else if (kerasMajorVersion == 1)
return new Keras1LayerConfiguration();
else
return new Keras2LayerConfiguration();
}
}
@@ -0,0 +1,53 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.config;
import lombok.Data;
@Data
public class KerasModelConfiguration {
/* Model meta information fields */
private final String fieldClassName = "class_name";
private final String fieldClassNameSequential = "Sequential";
private final String fieldClassNameModel = "Model";
private final String fieldNameClassFunctional = "Functional";
private final String fieldKerasVersion = "keras_version";
private final String fieldBackend = "backend";
/* Model configuration field. */
private final String modelFieldConfig = "config";
private final String modelFieldLayers = "layers";
private final String modelFieldInputLayers = "input_layers";
private final String modelFieldOutputLayers = "output_layers";
/* Training configuration field. */
private final String trainingLoss = "loss";
private final String trainingWeightsRoot = "model_weights";
private final String trainingModelConfigAttribute = "model_config";
private final String trainingTrainingConfigAttribute = "training_config";
private final String optimizerConfig = "optimizer_config";
//The model weight values as dictionaries. Introduced with keras 2.7.0
public final static String topLevelModelWeights = "top_level_model_weights";
}
@@ -0,0 +1,41 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.exceptions;
public class InvalidKerasConfigurationException extends Exception {
public InvalidKerasConfigurationException(String message) {
super(appendDocumentationURL(message));
}
public InvalidKerasConfigurationException(String message, Throwable cause) {
super(appendDocumentationURL(message), cause);
}
public InvalidKerasConfigurationException(Throwable cause) {
super(cause);
}
private static String appendDocumentationURL(String message) {
return message + ". For more information, see https://deeplearning4j.konduit.ai/keras-import/overview";
}
}
@@ -0,0 +1,41 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.exceptions;
public class UnsupportedKerasConfigurationException extends Exception {
public UnsupportedKerasConfigurationException(String message) {
super(appendDocumentationURL(message));
}
public UnsupportedKerasConfigurationException(String message, Throwable cause) {
super(appendDocumentationURL(message), cause);
}
public UnsupportedKerasConfigurationException(Throwable cause) {
super(cause);
}
private static String appendDocumentationURL(String message) {
return message + ". Please file an issue at https://github.com/eclipse/deeplearning4j/issues.";
}
}
@@ -0,0 +1,215 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Convolution3D;
import java.util.ArrayList;
import java.util.Map;
/**
* Imports an Input layer from Keras. Used to set InputType of DL4J model.
*
* @author dave@skymind.io
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasInput extends KerasLayer {
private final int NO_TRUNCATED_BPTT = 0;
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasInput(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasInput(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
if (this.inputShape.length > 4)
throw new UnsupportedKerasConfigurationException(
"Inputs with " + this.inputShape.length + " dimensions not supported");
}
/**
* Constructor from layer name and input shape.
*
* @param layerName layer name
* @param inputShape input shape as array
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasInput(String layerName, int[] inputShape) throws
UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
this(layerName, inputShape, true);
}
/**
* Constructor from layer name and input shape.
*
* @param layerName layer name
* @param inputShape input shape as array
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasInput(String layerName, int[] inputShape, boolean enforceTrainingConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
this.className = conf.getLAYER_CLASS_NAME_INPUT();
this.layerName = layerName;
this.inputShape = inputShape;
this.inboundLayerNames = new ArrayList<>();
this.layer = null;
this.vertex = null;
if (this.inputShape.length > 4)
throw new UnsupportedKerasConfigurationException(
"Inputs with " + this.inputShape.length + " dimensions not supported");
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
@Override
public InputType getOutputType(InputType... inputType)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
if (inputType.length > 0)
log.warn("Keras Input layer does not accept inputs (received " + inputType.length + "). Ignoring.");
InputType myInputType;
switch (this.inputShape.length) {
case 1:
myInputType = new InputType.InputTypeFeedForward(this.inputShape[0], null);
break;
case 2:
if(this.dimOrder != null) {
switch (this.dimOrder) {
case TENSORFLOW: //NWC == channels_last
myInputType = new InputType.InputTypeRecurrent(this.inputShape[1], this.inputShape[0], RNNFormat.NWC);
break;
case THEANO: //NCW == channels_first
myInputType = new InputType.InputTypeRecurrent(this.inputShape[0], this.inputShape[1], RNNFormat.NCW);
break;
case NONE:
//Assume RNN in [mb, seqLen, size] format
myInputType = new InputType.InputTypeRecurrent(this.inputShape[1], this.inputShape[0], RNNFormat.NWC);
break;
default:
throw new IllegalStateException("Unknown/not supported dimension ordering: " + this.dimOrder);
}
} else {
//Assume RNN in [mb, seqLen, size] format
myInputType = new InputType.InputTypeRecurrent(this.inputShape[1], this.inputShape[0], RNNFormat.NWC);
}
break;
case 3:
switch (this.dimOrder) {
case TENSORFLOW:
/* TensorFlow convolutional input: # rows, # cols, # channels */
myInputType = new InputType.InputTypeConvolutional(this.inputShape[0], this.inputShape[1],
this.inputShape[2], CNN2DFormat.NHWC);
break;
case THEANO:
/* Theano convolutional input: # channels, # rows, # cols */
myInputType = new InputType.InputTypeConvolutional(this.inputShape[1], this.inputShape[2],
this.inputShape[0], CNN2DFormat.NCHW);
break;
default:
this.dimOrder = DimOrder.THEANO;
myInputType = new InputType.InputTypeConvolutional(this.inputShape[1], this.inputShape[2],
this.inputShape[0], CNN2DFormat.NCHW);
log.warn("Couldn't determine dim ordering / data format from model file. Older Keras " +
"versions may come without specified backend, in which case we assume the model was " +
"built with theano." );
}
break;
case 4:
switch (this.dimOrder) {
case TENSORFLOW:
myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NDHWC,
this.inputShape[0], this.inputShape[1],
this.inputShape[2],this.inputShape[3]);
break;
case THEANO:
myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NCDHW,
this.inputShape[3], this.inputShape[0],
this.inputShape[1],this.inputShape[2]);
break;
default:
this.dimOrder = DimOrder.THEANO;
myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NCDHW,
this.inputShape[3], this.inputShape[0],
this.inputShape[1],this.inputShape[2]);
log.warn("Couldn't determine dim ordering / data format from model file. Older Keras " +
"versions may come without specified backend, in which case we assume the model was " +
"built with theano." );
}
break;
default:
throw new UnsupportedKerasConfigurationException(
"Inputs with " + this.inputShape.length + " dimensions not supported");
}
return myInputType;
}
/**
* Returns value of truncated BPTT, if any found.
*
* @return value of truncated BPTT
*/
public int getTruncatedBptt() {
if (this.inputShape.length == 2 && this.inputShape[0] > 0)
return this.inputShape[0];
return NO_TRUNCATED_BPTT;
}
}
@@ -0,0 +1,128 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLossUtils;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.CnnLossLayer;
import org.deeplearning4j.nn.conf.layers.FeedForwardLayer;
import org.deeplearning4j.nn.conf.layers.LossLayer;
import org.deeplearning4j.nn.conf.layers.RnnLossLayer;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.lossfunctions.ILossFunction;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import java.util.ArrayList;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasLoss extends KerasLayer {
private final String KERAS_CLASS_NAME_LOSS = "Loss";
private ILossFunction loss;
/**
* Constructor from layer name and input shape.
*
* @param layerName layer name
* @param inboundLayerName name of inbound layer
* @param kerasLoss name of Keras loss function
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLoss(String layerName, String inboundLayerName, String kerasLoss)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
this(layerName, inboundLayerName, kerasLoss, true);
}
/**
* Constructor from layer name and input shape.
*
* @param layerName layer name
* @param inboundLayerName name of inbound layer
* @param kerasLoss name of Keras loss function
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLoss(String layerName, String inboundLayerName, String kerasLoss, boolean enforceTrainingConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
this.className = KERAS_CLASS_NAME_LOSS;
this.layerName = layerName;
this.inputShape = null;
this.dimOrder = DimOrder.NONE;
this.inboundLayerNames = new ArrayList<>();
this.inboundLayerNames.add(inboundLayerName);
try {
loss = KerasLossUtils.mapLossFunction(kerasLoss, conf);
} catch (UnsupportedKerasConfigurationException e) {
if (enforceTrainingConfig)
throw e;
log.warn("Unsupported Keras loss function. Replacing with MSE.");
loss = LossFunctions.LossFunction.SQUARED_LOSS.getILossFunction();
}
}
/**
* Get DL4J LossLayer.
*
* @return LossLayer
*/
public FeedForwardLayer getLossLayer(InputType type) throws UnsupportedKerasConfigurationException {
if (type instanceof InputType.InputTypeFeedForward) {
this.layer = new LossLayer.Builder(loss).name(this.layerName).activation(Activation.IDENTITY).build();
}
else if (type instanceof InputType.InputTypeRecurrent) {
this.layer = new RnnLossLayer.Builder(loss).name(this.layerName).activation(Activation.IDENTITY).build();
}
else if (type instanceof InputType.InputTypeConvolutional) {
this.layer = new CnnLossLayer.Builder(loss).name(this.layerName).activation(Activation.IDENTITY).build();
} else {
throw new UnsupportedKerasConfigurationException("Unsupported output layer type"
+ "got : " + type.toString());
}
return (FeedForwardLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException,
UnsupportedKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Loss layer accepts only one input (received " + inputType.length + ")");
return this.getLossLayer(inputType[0]).getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,78 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import java.util.Map;
public class KerasTFOpLayer extends KerasLayer {
public KerasTFOpLayer(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
if (kerasVersion != 2){
throw new UnsupportedKerasConfigurationException("KerasTFOpLayer expects Keras version 2");
}
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasTFOpLayer(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasTFOpLayer(Map<String, Object> layerConfig, boolean enforceTrainingConfig) throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException{
super(layerConfig, enforceTrainingConfig);
this.layer = new TFOpLayer((Map)((Map)layerConfig.get("config")).get("node_def"), (Map)((Map)layerConfig.get("config")).get("constants"));
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public InputType getOutputType(InputType... inputType){
return this.layer.getOutputType(0, inputType[0]);
}
}
@@ -0,0 +1,113 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers;
import org.deeplearning4j.nn.api.ParamInitializer;
import org.deeplearning4j.nn.conf.GradientNormalization;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.memory.LayerMemoryReport;
import org.deeplearning4j.nn.params.EmptyParamInitializer;
import org.deeplearning4j.optimize.api.TrainingListener;
import org.nd4j.linalg.api.buffer.DataType;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.learning.regularization.Regularization;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class TFOpLayer extends Layer {
private Map nodeDef;
private Map constants;
public TFOpLayer(Map nodeDef, Map constants){
super();
this.nodeDef = nodeDef;
this.constants = constants;
}
@Override
public ParamInitializer initializer() {
return EmptyParamInitializer.getInstance();
}
@Override
public InputPreProcessor getPreProcessorForInputType(InputType inputType) {
return null;
}
@Override
public boolean isPretrainParam(String param){
return false;
}
@Override
public InputType getOutputType(int idx, InputType inputType){
long[] shape = inputType.getShape(true);
TFOpLayerImpl tempLayer = new TFOpLayerImpl(nodeDef, constants, null, null);
long[] outputShape = tempLayer.getOutputShape(shape);
if (outputShape.length == 3){
return InputType.recurrent(outputShape[2], outputShape[1], RNNFormat.NWC);
}
return InputType.inferInputType(Nd4j.create(outputShape));
}
@Override
public void setNIn(InputType inputType, boolean override){}
@Override
public GradientNormalization getGradientNormalization(){return null;}
@Override
public org.deeplearning4j.nn.api.Layer instantiate(NeuralNetConfiguration conf,
Collection<TrainingListener> trainingListeners, int layerIndex, INDArray layerParamsView,
boolean initializeParams, DataType networkDataType) {
TFOpLayerImpl tfOpLayerImpl = new TFOpLayerImpl(nodeDef, constants, conf, networkDataType);
tfOpLayerImpl.setListeners(trainingListeners);
tfOpLayerImpl.setIndex(layerIndex);
return tfOpLayerImpl;
}
@Override
public double getGradientNormalizationThreshold(){return 0.;}
@Override
public List<Regularization> getRegularizationByParam(String paramName){return null;}
@Override
public LayerMemoryReport getMemoryReport(InputType inputType) {
return new LayerMemoryReport(); //TODO
}
}
@@ -0,0 +1,165 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.deeplearning4j.config.DL4JClassLoading;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.gradient.Gradient;
import org.deeplearning4j.nn.layers.AbstractLayer;
import org.deeplearning4j.nn.workspace.LayerWorkspaceMgr;
import org.nd4j.TFGraphRunnerService;
import org.nd4j.linalg.api.buffer.DataType;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.common.primitives.Pair;
import org.tensorflow.framework.AttrValue;
import org.tensorflow.framework.GraphDef;
import org.tensorflow.framework.NodeDef;
import com.google.gson.Gson;
import org.nd4j.shade.protobuf.TextFormat;
import java.util.*;
import java.util.List;
@Slf4j
@Data
public class TFOpLayerImpl extends AbstractLayer<TFOpLayer> {
private Map nodeDef;
private Map constants;
private List<String> inputNames;
TFGraphRunnerService graphRunnerService;
public TFOpLayerImpl(Map nodeDef, Map constants, NeuralNetConfiguration conf, DataType dtype){
super(conf, dtype);
this.nodeDef = nodeDef;
this.constants = constants;
setGraphRunner();
}
@Override
public Pair<Gradient, INDArray> backpropGradient(INDArray epsilon, LayerWorkspaceMgr workspaceMgr){
throw new RuntimeException("Backprop through TFOpLayerImpl is not supported yet." +
" TFOpLayerImpl is created when importing TensorFlow 2.0 Keras models " +
"(tf.keras) into DL4J, that contains TensorFlow operations not just Keras layers.");
}
/**
* Converts a Map representation of Nodedef to a singleton TF Graph and instantiates a GraphRunner.
*/
private void setGraphRunner() {
try{
String json = new Gson().toJson(nodeDef);
NodeDef.Builder builder = NodeDef.newBuilder();
org.nd4j.shade.protobuf.util.JsonFormat.parser().merge(json, builder);
NodeDef nodeDef = builder.build();
List<String> allInputNames = new ArrayList<>(); // including constants
Map<String, String> inputDataTypes = new HashMap<>();
Map<String, INDArray> constArrays = new HashMap();
this.inputNames = new ArrayList<>();
List<String> outputNames = Arrays.asList(nodeDef.getName());
Map<String, AttrValue> attrMap = nodeDef.getAttrMap();
for (int i = 0; i < nodeDef.getInputCount(); i++){
String inputName = nodeDef.getInput(i);
String[] split = inputName.split("/");
String attrKey;
if (split.length == 1){
attrKey = "T";
}
else{
attrKey = "T" + split[split.length - 1];
}
allInputNames.add(nodeDef.getInput(i));
inputDataTypes.put(nodeDef.getInput(i), attrMap.get(attrKey).getType().toString());
if (constants.containsKey(String.valueOf(i))){
constArrays.put(nodeDef.getInput(i), Nd4j.create((List<Number>)constants.get(String.valueOf(i))));
}
else{
this.inputNames.add(nodeDef.getInput(i));
}
}
String graph = "node{\n" + nodeDef.toString() + "\n}\nversions {\n producer: 22\n}";
for (int i = 0; i < allInputNames.size(); i++){
String inpName = allInputNames.get(i);
String dtype = inputDataTypes.get(inpName);
graph = "node{\nname: \"" + inpName + "\"\nop: \"Placeholder\"\nattr{\nkey: \"dtype\"\n value {\n type: " + dtype + "}\n}\n}\n" + graph;
}
//log.info(graph);
GraphDef.Builder graphDefBuilder = GraphDef.newBuilder();
TextFormat.getParser().merge(graph, graphDefBuilder);
GraphDef graphDef = graphDefBuilder.build();
org.nd4j.shade.protobuf.ByteString serialized = graphDef.toByteString();
byte[] graphBytes = serialized.toByteArray();
ServiceLoader<TFGraphRunnerService> sl = DL4JClassLoading.loadService(TFGraphRunnerService.class);
Iterator<TFGraphRunnerService> iter = sl.iterator();
if (!iter.hasNext()){
throw new RuntimeException("The model contains a Tensorflow Op, which requires the nd4j-tensorflow dependency to execute.");
}
this.graphRunnerService = iter.next().init(allInputNames, outputNames, graphBytes, constArrays, inputDataTypes);
}
catch (Exception e){
throw new RuntimeException("Error parsing protobuf", e);
}
}
private INDArray runGraph(INDArray input){
Map<String, INDArray> inputMap = new HashMap<>();
inputMap.put(inputNames.get(0), input);
INDArray out = graphRunnerService.run(inputMap).values().toArray(new INDArray[0])[0];
return out;
}
public long[] getOutputShape(long[] inputShape){
long[] shape = ArrayUtils.clone(inputShape);
for(int i = 0; i < shape.length; i++){
if (shape[i] < 0){
shape[i] = 1;
}
}
INDArray dummyArr = Nd4j.zeros(shape);
return runGraph(dummyArr).shape();
}
@Override
public INDArray activate(boolean training, LayerWorkspaceMgr workspaceMgr) {
return runGraph(input);
}
@Override
public boolean isPretrainLayer(){
return false;
}
@Override
public void clearNoiseWeightParams(){
}
}
@@ -0,0 +1,93 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.linalg.activations.IActivation;
import org.nd4j.linalg.activations.impl.ActivationELU;
import java.util.Map;
public class KerasELU extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasELU(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasELU(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
double alpha = 1.0; // Set default alpha to default in nd4j
String layerFieldLeakyReluAlpha = "alpha";
if (innerConfig.containsKey(layerFieldLeakyReluAlpha)) {
alpha = (double) innerConfig.get(layerFieldLeakyReluAlpha);
}
IActivation leakyReLU = new ActivationELU(alpha);
this.layer = new ActivationLayer.Builder().name(this.layerName).activation(leakyReLU).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,98 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.linalg.activations.IActivation;
import org.nd4j.linalg.activations.impl.ActivationLReLU;
import java.util.Map;
/**
* Imports LeakyReLU layer from Keras
*
* @author Max Pumperla
*/
public class KerasLeakyReLU extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasLeakyReLU(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasLeakyReLU(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
double alpha = 0.01; // Set default alpha to default in nd4j
String layerFieldLeakyReluAlpha = "alpha";
if (innerConfig.containsKey(layerFieldLeakyReluAlpha)) {
alpha = (double) innerConfig.get(layerFieldLeakyReluAlpha);
}
IActivation leakyReLU = new ActivationLReLU(alpha);
this.layer = new ActivationLayer.Builder().name(this.layerName).activation(leakyReLU).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,163 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.PReLULayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.PReLUParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.common.util.ArrayUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Imports PReLU layer from Keras
*
* @author Max Pumperla
*/
@Slf4j
public class KerasPReLU extends KerasLayer {
private final String ALPHA = "alpha";
private final String ALPHA_INIT = "alpha_initializer";
private final String ALPHA_CONSTRAINT = "alpha_constraint";
private final String SHARED_AXES = "shared_axes";
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasPReLU(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasPReLU(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, ALPHA_CONSTRAINT, conf, kerasMajorVersion);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, ALPHA_INIT,
enforceTrainingConfig, conf, kerasMajorVersion);
long[] axes = getSharedAxes(layerConfig);
PReLULayer.Builder builder = new PReLULayer.Builder().sharedAxes(axes)
.weightInit(init).name(layerName);
if (weightConstraint != null){
builder.constrainWeights(weightConstraint);
}
this.layer = builder.build();
}
private long[] getSharedAxes(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
long[] axes = null;
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
try {
@SuppressWarnings("unchecked")
List<Integer> axesList = (List<Integer>) innerConfig.get(SHARED_AXES);
int[] intAxes = ArrayUtil.toArray(axesList);
axes = new long[intAxes.length];
for (int i = 0; i < intAxes.length; i++) {
axes[i] = (long) intAxes[i];
}
} catch (Exception e) {
// no shared axes
}
return axes;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras PReLU layer accepts only one input (received " + inputType.length + ")");
InputType inType = inputType[0];
// Dynamically infer input shape of PReLU layer from input type
PReLULayer shapedLayer = (PReLULayer) this.layer;
shapedLayer.setInputShape(inType.getShape());
this.layer = shapedLayer;
return this.getPReLULayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public PReLULayer getPReLULayer() {
return (PReLULayer) this.layer;
}
/**
* Set weights for layer.
*
* @param weights Dense layer weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(ALPHA))
this.weights.put(PReLUParamInitializer.WEIGHT_KEY, weights.get(ALPHA));
else
throw new InvalidKerasConfigurationException("Parameter " + ALPHA + " does not exist in weights");
if (weights.size() > 1) {
Set<String> paramNames = weights.keySet();
paramNames.remove(ALPHA);
String unknownParamNames = paramNames.toString();
log.warn("Attemping to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
}
}
@@ -0,0 +1,96 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.linalg.activations.impl.ActivationReLU;
import java.util.Map;
public class KerasReLU extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasReLU(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasReLU(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
Double maxValue = (Double) innerConfig.get("max_value");
double negativeSlope = 0.0;
double threshold = 0.0;
if (innerConfig.containsKey("negative_slope")) {
negativeSlope = ((Number)innerConfig.get("negative_slope")).doubleValue();
}
if (innerConfig.containsKey("threshold")) {
threshold = ((Number)innerConfig.get("threshold")).doubleValue();
}
this.layer = new ActivationLayer.Builder().name(this.layerName)
.activation(new ActivationReLU(maxValue, threshold, negativeSlope)).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,84 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import org.nd4j.linalg.activations.impl.ActivationSoftmax;
import java.util.Map;
public class KerasSoftmax extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasSoftmax(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasSoftmax(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.layer = new ActivationLayer.Builder().name(this.layerName).activation(new ActivationSoftmax()).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,98 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.linalg.activations.IActivation;
import org.nd4j.linalg.activations.impl.ActivationThresholdedReLU;
import java.util.Map;
/**
* Imports ThresholdedReLU layer from Keras
*
* @author Max Pumperla
*/
public class KerasThresholdedReLU extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Invalid Keras config
*/
public KerasThresholdedReLU(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasThresholdedReLU(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
double theta = 1.0;
String layerFieldThresholdTheta = "theta";
if (innerConfig.containsKey(layerFieldThresholdTheta)) {
theta = (double) innerConfig.get(layerFieldThresholdTheta);
}
IActivation thresholdedReLU = new ActivationThresholdedReLU(theta);
this.layer = new ActivationLayer.Builder().name(this.layerName).activation(thresholdedReLU).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,143 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.attention;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.graph.DotProductAttentionVertex;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.preprocessor.CnnToRnnPreProcessor;
import org.deeplearning4j.nn.conf.preprocessor.FeedForwardToRnnPreProcessor;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.List;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getNOutFromConfig;
/**
* Docs from https://keras.io/api/layers/attention_layers/attention/
* @author Adam Gibson
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasAttentionLayer extends KerasLayer {
private boolean useScale;
private double dropOut;
private String scoreMode;
private List<String> inputNames;
/**
* Float between 0 and 1. Fraction of the units to drop for the attention scores. Defaults to 0.0.
*/
private final String LAYER_DROP_OUT = "dropout";
/**
* Function to use to compute attention scores, one of {"dot", "concat"}. "dot" refers to
* the dot product between the query and key vectors.\
* "concat" refers to the hyperbolic tangent of the concatenation of the query and key vectors.
*/
private final String LAYER_SCORE_MODE = "score_mode";
private final String LAYER_SCORE_MODE_DOT = "dot";
private final String LAYER_SCORE_MODE_CONCAT = "concat";
private final String LAYER_USE_SCALE = "use_scale";
public KerasAttentionLayer(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
public KerasAttentionLayer() throws UnsupportedKerasConfigurationException {
}
public KerasAttentionLayer(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig,false);
}
public KerasAttentionLayer(Map<String, Object> layerConfig, boolean enforceTrainingConfig) throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
this.useScale = Boolean.parseBoolean(innerConfig.getOrDefault(LAYER_USE_SCALE,"false").toString());
this.dropOut = Double.parseDouble(innerConfig.getOrDefault(LAYER_DROP_OUT,"0.0").toString());
this.inputNames = KerasLayerUtils.getInboundLayerNamesFromConfig(layerConfig, conf);
String scoreMode = innerConfig.getOrDefault(LAYER_SCORE_MODE,LAYER_SCORE_MODE_DOT).toString();
if(!scoreMode.equals(LAYER_SCORE_MODE_DOT) )
throw new InvalidKerasConfigurationException("Invalid score mode " + scoreMode);
this.vertex = new DotProductAttentionVertex.Builder()
.dropoutProbability(dropout)
.scale(useScale ? 0.2 : 1.0)
.inputNames(inputNames)
.build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
switch (inputType[0].getType()) {
case FF:
InputType.InputTypeFeedForward ff = (InputType.InputTypeFeedForward) inputType[0];
this.getAttentionVertex().setNIn(ff.getSize());
this.getAttentionVertex().setNOut(ff.getSize());
break;
case CNN:
InputType.InputTypeConvolutional cnn = (InputType.InputTypeConvolutional) inputType[0];
this.getAttentionVertex().setNIn(cnn.getChannels());
this.getAttentionVertex().setNOut(cnn.getChannels());
break;
case RNN:
InputType.InputTypeRecurrent rnn = (InputType.InputTypeRecurrent) inputType[0];
this.getAttentionVertex().setNIn(rnn.getSize());
this.getAttentionVertex().setNOut(rnn.getSize());
break;
case CNN3D:
case CNNFlat:
throw new InvalidKerasConfigurationException("Unsupported input type for attention layer: " + inputType[0].getType());
}
if (preprocessor != null) {
return this.getAttentionVertex().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getAttentionVertex().getOutputType(-1, inputType[0]);
}
private DotProductAttentionVertex getAttentionVertex() {
return (DotProductAttentionVertex) vertex;
}
}
@@ -0,0 +1,134 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Convolution1DLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
public class KerasAtrousConvolution1D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution1D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
Convolution1DLayer.Builder builder = new Convolution1DLayer.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.dilation(getDilationRate(layerConfig, 1, conf, true)[0])
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfig(layerConfig, 1, conf, kerasMajorVersion)[0])
.hasBias(hasBias)
.rnnDataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? RNNFormat.NWC : RNNFormat.NCW)
.stride(getStrideFromConfig(layerConfig, 1, conf)[0]);
int[] padding = getPaddingFromBorderModeConfig(layerConfig, 1, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding[0]);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
Convolution1DLayer convolution1DLayer = (Convolution1DLayer) layer;
convolution1DLayer.setDefaultValueOverriden(true);
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public Convolution1DLayer getAtrousConvolution1D() {
return (Convolution1DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
return this.getAtrousConvolution1D().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,135 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ConvolutionLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
public class KerasAtrousConvolution2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAtrousConvolution2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
ConvolutionLayer.Builder builder = new ConvolutionLayer.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.dilation(getDilationRateLong(layerConfig, 2, conf, true))
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.dataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.hasBias(hasBias)
.stride(getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public ConvolutionLayer getAtrousConvolution2D() {
return (ConvolutionLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
return this.getAtrousConvolution2D().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,159 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.ConvolutionParamInitializer;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
abstract public class KerasConvolution extends KerasLayer {
protected int numTrainableParams;
protected boolean hasBias;
public KerasConvolution() throws UnsupportedKerasConfigurationException {
}
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (2)
*/
@Override
public int getNumParams() {
return numTrainableParams;
}
/**
* Set weights for layer.
*
* @param weights Map from parameter name to INDArray.
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W())) {
INDArray kerasParamValue = weights.get(conf.getKERAS_PARAM_NAME_W());
INDArray paramValue = getConvParameterValues(kerasParamValue);
this.weights.put(ConvolutionParamInitializer.WEIGHT_KEY, paramValue);
} else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_W() + " does not exist in weights");
if (hasBias) {
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
this.weights.put(ConvolutionParamInitializer.BIAS_KEY, weights.get(conf.getKERAS_PARAM_NAME_B()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_B() + " does not exist in weights");
}
KerasLayerUtils.removeDefaultWeights(weights, conf);
}
/**
* Return processed parameter values obtained from Keras convolutional layers.
*
* @param kerasParamValue INDArray containing raw Keras weights to be processed
* @return Processed weights, according to which backend was used.
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception.
*/
public INDArray getConvParameterValues(INDArray kerasParamValue) throws InvalidKerasConfigurationException {
INDArray paramValue;
switch (this.getDimOrder()) {
case TENSORFLOW:
if (kerasParamValue.rank() == 5)
// CNN 3D case
paramValue = kerasParamValue.permute(4, 3, 0, 1, 2);
else
/* TensorFlow convolutional weights: # rows, # cols, # inputs, # outputs */
paramValue = kerasParamValue.permute(3, 2, 0, 1);
break;
case THEANO:
/* Theano convolutional weights match DL4J: # outputs, # inputs, # rows, # cols
* Theano's default behavior is to rotate filters by 180 degree before application.
*/
paramValue = kerasParamValue.dup();
for (int i = 0; i < paramValue.tensorsAlongDimension(2, 3); i++) {
//dup required since we only want data from the view not the whole array
INDArray copyFilter = paramValue.tensorAlongDimension(i, 2, 3).dup();
double[] flattenedFilter = copyFilter.ravel().data().asDouble();
ArrayUtils.reverse(flattenedFilter);
INDArray newFilter = Nd4j.create(flattenedFilter, copyFilter.shape());
//manipulating weights in place to save memory
INDArray inPlaceFilter = paramValue.tensorAlongDimension(i, 2, 3);
inPlaceFilter.muli(0).addi(newFilter.castTo(inPlaceFilter.dataType()));
}
break;
default:
throw new InvalidKerasConfigurationException("Unknown keras backend " + this.getDimOrder());
}
return paramValue;
}
}
@@ -0,0 +1,222 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Convolution1DLayer;
import org.deeplearning4j.nn.conf.layers.InputTypeUtil;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.ConvolutionParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasConvolution1D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException
*/
public KerasConvolution1D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException
* @throws UnsupportedKerasConfigurationException
*/
public KerasConvolution1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException
* @throws UnsupportedKerasConfigurationException
*/
public KerasConvolution1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
//verify against python
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
int[] dilationRate = KerasConvolutionUtils.getDilationRate(layerConfig, 1, conf, false);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
Convolution1DLayer.Builder builder = new Convolution1DLayer.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(KerasConvolutionUtils.getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(KerasConvolutionUtils.getKernelSizeFromConfig(layerConfig, 1, conf, kerasMajorVersion)[0])
.hasBias(hasBias)
.stride(KerasConvolutionUtils.getStrideFromConfig(layerConfig, 1, conf)[0])
.rnnDataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? RNNFormat.NWC: RNNFormat.NCW);
int[] padding = KerasConvolutionUtils.getPaddingFromBorderModeConfig(layerConfig, 1, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding[0]);
if (dilationRate != null)
builder.dilation(dilationRate[0]);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
//set this in order to infer the dimensional format
Convolution1DLayer convolution1DLayer = (Convolution1DLayer) this.layer;
convolution1DLayer.setCnn2dDataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW);
convolution1DLayer.setDefaultValueOverriden(true);
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public Convolution1DLayer getConvolution1DLayer() {
return (Convolution1DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getConvolution1DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getConvolution1DLayer().getOutputType(-1, inputType[0]);
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Conv1D layer accepts only one input (received " + inputType.length + ")");
if(inputType[0] != null && inputType[0].getType() != InputType.Type.RNN || inputType[0] == null)
return InputTypeUtil.getPreprocessorForInputTypeRnnLayers(inputType[0], RNNFormat.NCW,layerName);
else {
InputType.InputTypeRecurrent inputTypeRecurrent = (InputType.InputTypeRecurrent) inputType[0];
return InputTypeUtil.getPreprocessorForInputTypeRnnLayers(inputType[0],inputTypeRecurrent.getFormat(),layerName);
}
}
/**
* Set weights for layer.
*
* @param weights Map from parameter name to INDArray.
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W())) {
INDArray kerasParamValue = weights.get(conf.getKERAS_PARAM_NAME_W());
INDArray paramValue;
switch (this.getDimOrder()) {
case TENSORFLOW:
paramValue = kerasParamValue;
paramValue = paramValue.reshape(
paramValue.size(0), paramValue.size(1),
paramValue.size(2), 1);
break;
case THEANO:
//Convert from keras [k,nIn,nOut] to DL4J conv2d [nOut, nIn, k, 1]
long k = kerasParamValue.size(0);
long nIn = kerasParamValue.size(1);
long nOut = kerasParamValue.size(2);
paramValue = kerasParamValue.dup('c').reshape(nOut, nIn, k, 1);
break;
default:
throw new InvalidKerasConfigurationException("Unknown keras backend " + this.getDimOrder());
}
this.weights.put(ConvolutionParamInitializer.WEIGHT_KEY, paramValue);
} else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_W() + " does not exist in weights");
if (hasBias) {
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
this.weights.put(ConvolutionParamInitializer.BIAS_KEY, weights.get(conf.getKERAS_PARAM_NAME_B()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_B() + " does not exist in weights");
}
KerasLayerUtils.removeDefaultWeights(weights, conf);
}
}
@@ -0,0 +1,149 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ConvolutionLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import java.util.Map;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasConvolution2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = KerasConvolutionUtils.getDilationRateLong(layerConfig, 2, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
ConvolutionLayer.Builder builder = new ConvolutionLayer.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.dataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(KerasConvolutionUtils.getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(KerasConvolutionUtils.getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.stride(KerasConvolutionUtils.getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = KerasConvolutionUtils.getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
ConvolutionLayer convolutionLayer = (ConvolutionLayer) layer;
convolutionLayer.setDefaultValueOverriden(true);
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public ConvolutionLayer getConvolution2DLayer() {
return (ConvolutionLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getConvolution2DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getConvolution2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,147 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Convolution3D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasConvolution3D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution3D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasConvolution3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = getDilationRateLong(layerConfig, 3, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
Convolution3D.Builder builder = new Convolution3D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 3, conf, kerasMajorVersion))
.hasBias(hasBias)
.dataFormat(getCNN3DDataFormatFromConfig(layerConfig,conf))
.stride(getStrideFromConfigLong(layerConfig, 3, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 3, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public Convolution3D getConvolution3DLayer() {
return (Convolution3D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getConvolution3DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getConvolution3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,602 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.ConvolutionMode;
import org.deeplearning4j.nn.conf.layers.Convolution3D;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.common.util.ArrayUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class KerasConvolutionUtils {
/**
* Get (convolution) stride from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Strides array from Keras configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static long[] getStrideFromConfigLong(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
return Arrays.stream(getStrideFromConfig(layerConfig, dimension, conf)).mapToLong(i -> i).toArray();
}
/**
* Get (convolution) stride from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Strides array from Keras configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int[] getStrideFromConfig(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int[] strides;
if (innerConfig.containsKey(conf.getLAYER_FIELD_CONVOLUTION_STRIDES()) && dimension >= 2) {
/* 2D/3D Convolutional layers. */
@SuppressWarnings("unchecked")
List<Integer> stridesList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_CONVOLUTION_STRIDES());
strides = ArrayUtil.toArray(stridesList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_SUBSAMPLE_LENGTH()) && dimension == 1) {
/* 1D Convolutional layers. */
if ((int) layerConfig.get("keras_version") == 2) {
@SuppressWarnings("unchecked")
List<Integer> stridesList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_SUBSAMPLE_LENGTH());
strides = ArrayUtil.toArray(stridesList);
} else {
int subsampleLength = (int) innerConfig.get(conf.getLAYER_FIELD_SUBSAMPLE_LENGTH());
strides = new int[]{subsampleLength};
}
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_STRIDES()) && dimension >= 2) {
/* 2D/3D Pooling layers. */
@SuppressWarnings("unchecked")
List<Integer> stridesList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_POOL_STRIDES());
strides = ArrayUtil.toArray(stridesList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_1D_STRIDES()) && dimension == 1) {
/* 1D Pooling layers. */
int stride = (int) innerConfig.get(conf.getLAYER_FIELD_POOL_1D_STRIDES());
strides = new int[]{stride};
} else
throw new InvalidKerasConfigurationException("Could not determine layer stride: no "
+ conf.getLAYER_FIELD_CONVOLUTION_STRIDES() + " or "
+ conf.getLAYER_FIELD_POOL_STRIDES() + " field found");
return strides;
}
static int getDepthMultiplier(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
return (int) innerConfig.get(conf.getLAYER_FIELD_DEPTH_MULTIPLIER());
}
/**
* Get atrous / dilation rate from config
*
* @param layerConfig dictionary containing Keras layer configuration
* @param dimension dimension of the convolution layer (1 or 2)
* @param conf Keras layer configuration
* @param forceDilation boolean to indicate if dilation argument should be in config
* @return list of integers with atrous rates
*
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static long[] getDilationRateLong(Map<String, Object> layerConfig, int dimension, KerasLayerConfiguration conf,
boolean forceDilation)
throws InvalidKerasConfigurationException {
return Arrays.stream(getDilationRate(layerConfig, dimension, conf, forceDilation)).mapToLong(i -> i).toArray();
}
/**
* Get atrous / dilation rate from config
*
* @param layerConfig dictionary containing Keras layer configuration
* @param dimension dimension of the convolution layer (1 or 2)
* @param conf Keras layer configuration
* @param forceDilation boolean to indicate if dilation argument should be in config
* @return list of integers with atrous rates
*
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int[] getDilationRate(Map<String, Object> layerConfig, int dimension, KerasLayerConfiguration conf,
boolean forceDilation)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int[] atrousRate;
if (innerConfig.containsKey(conf.getLAYER_FIELD_DILATION_RATE()) && dimension >= 2) {
@SuppressWarnings("unchecked")
List<Integer> atrousRateList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_DILATION_RATE());
atrousRate = ArrayUtil.toArray(atrousRateList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_DILATION_RATE()) && dimension == 1) {
if ((int) layerConfig.get("keras_version") == 2) {
@SuppressWarnings("unchecked")
List<Integer> atrousRateList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_DILATION_RATE());
atrousRate = new int[]{atrousRateList.get(0), atrousRateList.get(0)};
} else {
int atrous = (int) innerConfig.get(conf.getLAYER_FIELD_DILATION_RATE());
atrousRate = new int[]{atrous, atrous};
}
} else {
// If we are using keras 1, for regular convolutions, there is no "atrous" argument, for keras
// 2 there always is.
if (forceDilation)
throw new InvalidKerasConfigurationException("Could not determine dilation rate: no "
+ conf.getLAYER_FIELD_DILATION_RATE() + " field found");
else
atrousRate = null;
}
return atrousRate;
}
/**
* Return the {@link Convolution3D.DataFormat}
* from the configuration .
* If the value is {@link KerasLayerConfiguration#getDIM_ORDERING_TENSORFLOW()}
* then the value is {@link Convolution3D.DataFormat#NDHWC }
* else it's {@link KerasLayerConfiguration#getDIM_ORDERING_THEANO()}
* which is {@link Convolution3D.DataFormat#NDHWC}
* @param layerConfig the layer configuration to get the values from
* @param layerConfiguration the keras configuration used for retrieving
* values from the configuration
* @return the {@link CNN2DFormat} given the configuration
* @throws InvalidKerasConfigurationException
*/
public static Convolution3D.DataFormat getCNN3DDataFormatFromConfig(Map<String,Object> layerConfig, KerasLayerConfiguration layerConfiguration) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig,layerConfiguration);
String dataFormat = innerConfig.containsKey(layerConfiguration.getLAYER_FIELD_DIM_ORDERING()) ?
innerConfig.get(layerConfiguration.getLAYER_FIELD_DIM_ORDERING()).toString() : "channels_last";
return dataFormat.equals("channels_last") ? Convolution3D.DataFormat.NDHWC : Convolution3D.DataFormat.NCDHW;
}
/**
* Return the {@link CNN2DFormat}
* from the configuration .
* If the value is {@link KerasLayerConfiguration#getDIM_ORDERING_TENSORFLOW()}
* then the value is {@link CNN2DFormat#NHWC}
* else it's {@link KerasLayerConfiguration#getDIM_ORDERING_THEANO()}
* which is {@link CNN2DFormat#NCHW}
* @param layerConfig the layer configuration to get the values from
* @param layerConfiguration the keras configuration used for retrieving
* values from the configuration
* @return the {@link CNN2DFormat} given the configuration
* @throws InvalidKerasConfigurationException
*/
public static CNN2DFormat getDataFormatFromConfig(Map<String,Object> layerConfig,KerasLayerConfiguration layerConfiguration) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig,layerConfiguration);
String dataFormat = innerConfig.containsKey(layerConfiguration.getLAYER_FIELD_DIM_ORDERING()) ?
innerConfig.get(layerConfiguration.getLAYER_FIELD_DIM_ORDERING()).toString() : "channels_last";
return dataFormat.equals("channels_last") ? CNN2DFormat.NHWC : CNN2DFormat.NCHW;
}
/**
* Get upsampling size from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
*
* @return Upsampling integer array from Keras config
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
static int[] getUpsamplingSizeFromConfig(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int[] size;
if (innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE()) && dimension == 2
|| innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_3D_SIZE()) && dimension == 3) {
@SuppressWarnings("unchecked")
List<Integer> sizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE());
size = ArrayUtil.toArray(sizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE()) && dimension == 1) {
int upsamplingSize1D = (int) innerConfig.get(conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE());
size = new int[]{upsamplingSize1D};
} else {
throw new InvalidKerasConfigurationException("Could not determine kernel size: no "
+ conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE() + ", "
+ conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE());
}
return size;
}
/**
* Get upsampling size from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
*
* @return Upsampling integer array from Keras config
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
static long[] getUpsamplingSizeFromConfigLong(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
long[] size;
if (innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE()) && dimension == 2
|| innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_3D_SIZE()) && dimension == 3) {
@SuppressWarnings("unchecked")
List<Long> sizeList = (List<Long>) innerConfig.get(conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE());
size = ArrayUtil.toArrayLong(sizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE()) && dimension == 1) {
int upsamplingSize1D = (int) innerConfig.get(conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE());
size = new long[]{upsamplingSize1D};
} else {
throw new InvalidKerasConfigurationException("Could not determine kernel size: no "
+ conf.getLAYER_FIELD_UPSAMPLING_1D_SIZE() + ", "
+ conf.getLAYER_FIELD_UPSAMPLING_2D_SIZE());
}
return size;
}
/**
* Get (convolution) kernel size from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
*
* @return Convolutional kernel sizes
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static long[] getKernelSizeFromConfigLong(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf, int kerasMajorVersion)
throws InvalidKerasConfigurationException {
return Arrays.stream(getKernelSizeFromConfig(layerConfig, dimension, conf, kerasMajorVersion)).mapToLong(i -> i).toArray();
}
/**
* Get (convolution) kernel size from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
*
* @return Convolutional kernel sizes
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int[] getKernelSizeFromConfig(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf, int kerasMajorVersion)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int[] kernelSize;
if (kerasMajorVersion != 2) {
if (innerConfig.containsKey(conf.getLAYER_FIELD_NB_ROW()) && dimension == 2
&& innerConfig.containsKey(conf.getLAYER_FIELD_NB_COL())) {
/* 2D Convolutional layers. */
List<Integer> kernelSizeList = new ArrayList<>();
kernelSizeList.add((Integer) innerConfig.get(conf.getLAYER_FIELD_NB_ROW()));
kernelSizeList.add((Integer) innerConfig.get(conf.getLAYER_FIELD_NB_COL()));
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_3D_KERNEL_1()) && dimension == 3
&& innerConfig.containsKey(conf.getLAYER_FIELD_3D_KERNEL_2())
&& innerConfig.containsKey(conf.getLAYER_FIELD_3D_KERNEL_3())) {
/* 3D Convolutional layers. */
List<Integer> kernelSizeList = new ArrayList<>();
kernelSizeList.add((Integer) innerConfig.get(conf.getLAYER_FIELD_3D_KERNEL_1()));
kernelSizeList.add((Integer) innerConfig.get(conf.getLAYER_FIELD_3D_KERNEL_2()));
kernelSizeList.add((Integer) innerConfig.get(conf.getLAYER_FIELD_3D_KERNEL_3()));
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_FILTER_LENGTH()) && dimension == 1) {
/* 1D Convolutional layers. */
int filterLength = (int) innerConfig.get(conf.getLAYER_FIELD_FILTER_LENGTH());
kernelSize = new int[]{filterLength};
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_SIZE()) && dimension >= 2) {
/* 2D/3D Pooling layers. */
@SuppressWarnings("unchecked")
List<Integer> kernelSizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_POOL_SIZE());
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_1D_SIZE()) && dimension == 1) {
/* 1D Pooling layers. */
int poolSize1D = (int) innerConfig.get(conf.getLAYER_FIELD_POOL_1D_SIZE());
kernelSize = new int[]{poolSize1D};
} else {
throw new InvalidKerasConfigurationException("Could not determine kernel size: no "
+ conf.getLAYER_FIELD_NB_ROW() + ", "
+ conf.getLAYER_FIELD_NB_COL() + ", or "
+ conf.getLAYER_FIELD_FILTER_LENGTH() + ", or "
+ conf.getLAYER_FIELD_POOL_1D_SIZE() + ", or "
+ conf.getLAYER_FIELD_POOL_SIZE() + " field found");
}
} else {
/* 2D/3D Convolutional layers. */
if (innerConfig.containsKey(conf.getLAYER_FIELD_KERNEL_SIZE()) && dimension >= 2) {
@SuppressWarnings("unchecked")
List<Integer> kernelSizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_KERNEL_SIZE());
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_FILTER_LENGTH()) && dimension == 1) {
/* 1D Convolutional layers. */
@SuppressWarnings("unchecked")
List<Integer> kernelSizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_FILTER_LENGTH());
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_SIZE()) && dimension >= 2) {
/* 2D Pooling layers. */
@SuppressWarnings("unchecked")
List<Integer> kernelSizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_POOL_SIZE());
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_POOL_1D_SIZE()) && dimension == 1) {
/* 1D Pooling layers. */
@SuppressWarnings("unchecked")
List<Integer> kernelSizeList = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_POOL_1D_SIZE());
kernelSize = ArrayUtil.toArray(kernelSizeList);
} else {
throw new InvalidKerasConfigurationException("Could not determine kernel size: no "
+ conf.getLAYER_FIELD_KERNEL_SIZE() + ", or "
+ conf.getLAYER_FIELD_FILTER_LENGTH() + ", or "
+ conf.getLAYER_FIELD_POOL_SIZE() + " field found");
}
}
return kernelSize;
}
/**
* Get convolution border mode from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Border mode of convolutional layers
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static ConvolutionMode getConvolutionModeFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_BORDER_MODE()))
throw new InvalidKerasConfigurationException("Could not determine convolution border mode: no "
+ conf.getLAYER_FIELD_BORDER_MODE() + " field found");
String borderMode = (String) innerConfig.get(conf.getLAYER_FIELD_BORDER_MODE());
ConvolutionMode convolutionMode;
if (borderMode.equals(conf.getLAYER_BORDER_MODE_SAME())) {
/* Keras relies upon the Theano and TensorFlow border mode definitions and operations:
* TH: http://deeplearning.net/software/theano/library/tensor/nnet/conv.html#theano.tensor.nnet.conv.conv2d
* TF: https://www.tensorflow.org/api_docs/python/nn/convolution#conv2d
*/
convolutionMode = ConvolutionMode.Same;
} else if (borderMode.equals(conf.getLAYER_BORDER_MODE_VALID()) ||
borderMode.equals(conf.getLAYER_BORDER_MODE_FULL())) {
convolutionMode = ConvolutionMode.Truncate;
} else if(borderMode.equals(conf.getLAYER_BORDER_MODE_CAUSAL())) {
convolutionMode = ConvolutionMode.Causal;
} else {
throw new UnsupportedKerasConfigurationException("Unsupported convolution border mode: " + borderMode);
}
return convolutionMode;
}
/**
* Get (convolution) padding from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Padding values derived from border mode
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static long[] getPaddingFromBorderModeConfigLong(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf, int kerasMajorVersion)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
return Arrays.stream(getPaddingFromBorderModeConfig(layerConfig, dimension, conf, kerasMajorVersion)).mapToLong(i -> i).toArray();
}
/**
* Get (convolution) padding from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Padding values derived from border mode
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int[] getPaddingFromBorderModeConfig(Map<String, Object> layerConfig, int dimension,
KerasLayerConfiguration conf, int kerasMajorVersion)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int[] padding = null;
if (!innerConfig.containsKey(conf.getLAYER_FIELD_BORDER_MODE()))
throw new InvalidKerasConfigurationException("Could not determine convolution border mode: no "
+ conf.getLAYER_FIELD_BORDER_MODE() + " field found");
String borderMode = (String) innerConfig.get(conf.getLAYER_FIELD_BORDER_MODE());
if (borderMode.equals(conf.getLAYER_FIELD_BORDER_MODE())) {
padding = getKernelSizeFromConfig(layerConfig, dimension, conf, kerasMajorVersion);
for (int i = 0; i < padding.length; i++)
padding[i]--;
}
return padding;
}
/**
* Get padding and cropping configurations from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param conf KerasLayerConfiguration
* @param layerField String value of the layer config name to check for (e.g. "padding" or "cropping")
* @param dimension Dimension of the padding layer
* @return padding list of integers
* @throws InvalidKerasConfigurationException Invalid keras configuration
*/
static long[] getPaddingFromConfigLong(Map<String, Object> layerConfig,
KerasLayerConfiguration conf,
String layerField,
int dimension)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(layerField))
throw new InvalidKerasConfigurationException(
"Field " + layerField + " not found in Keras cropping or padding layer");
long[] padding;
if (dimension >= 2) {
List<Long> paddingList;
// For 2D layers, padding/cropping can either be a pair [[x_0, x_1].[y_0, y_1]] or a pair [x, y]
// or a single integer x. Likewise for the 3D case.
try {
List paddingNoCast = (List) innerConfig.get(layerField);
boolean isNested;
try {
@SuppressWarnings("unchecked")
List<Integer> firstItem = (List<Integer>) paddingNoCast.get(0);
isNested = true;
paddingList = new ArrayList<>(2 * dimension);
} catch (Exception e) {
int firstItem = (int) paddingNoCast.get(0);
isNested = false;
paddingList = new ArrayList<>(dimension);
}
if ((paddingNoCast.size() == dimension) && !isNested) {
for (int i = 0; i < dimension; i++)
paddingList.add((Long) paddingNoCast.get(i));
padding = ArrayUtil.toArrayLong(paddingList);
} else if ((paddingNoCast.size() == dimension) && isNested) {
for (int j = 0; j < dimension; j++) {
@SuppressWarnings("unchecked")
List<Long> item = (List<Long>) paddingNoCast.get(j);
paddingList.add((item.get(0)));
paddingList.add((item.get(1)));
}
padding = ArrayUtil.toArrayLong(paddingList);
} else {
throw new InvalidKerasConfigurationException("Found Keras ZeroPadding" + dimension
+ "D layer with invalid " + paddingList.size() + "D padding.");
}
} catch (Exception e) {
int paddingInt = (int) innerConfig.get(layerField);
if (dimension == 2) {
padding = new long[]{paddingInt, paddingInt, paddingInt, paddingInt};
} else {
padding = new long[]{paddingInt, paddingInt, paddingInt, paddingInt, paddingInt, paddingInt};
}
}
} else if (dimension == 1) {
Object paddingObj = innerConfig.get(layerField);
if (paddingObj instanceof List) {
List<Long> paddingList = (List)paddingObj;
padding = new long[]{
paddingList.get(0),
paddingList.get(1)
};
}
else{
int paddingInt = (int) innerConfig.get(layerField);
padding = new long[]{paddingInt, paddingInt};
}
} else {
throw new UnsupportedKerasConfigurationException(
"Keras padding layer not supported");
}
return padding;
}
/**
* Get padding and cropping configurations from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param conf KerasLayerConfiguration
* @param layerField String value of the layer config name to check for (e.g. "padding" or "cropping")
* @param dimension Dimension of the padding layer
* @return padding list of integers
* @throws InvalidKerasConfigurationException Invalid keras configuration
*/
static int[] getPaddingFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf,
String layerField,
int dimension)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(layerField))
throw new InvalidKerasConfigurationException(
"Field " + layerField + " not found in Keras cropping or padding layer");
int[] padding;
if (dimension >= 2) {
List<Integer> paddingList;
// For 2D layers, padding/cropping can either be a pair [[x_0, x_1].[y_0, y_1]] or a pair [x, y]
// or a single integer x. Likewise for the 3D case.
try {
List paddingNoCast = (List) innerConfig.get(layerField);
boolean isNested;
try {
@SuppressWarnings("unchecked")
List<Integer> firstItem = (List<Integer>) paddingNoCast.get(0);
isNested = true;
paddingList = new ArrayList<>(2 * dimension);
} catch (Exception e) {
int firstItem = (int) paddingNoCast.get(0);
isNested = false;
paddingList = new ArrayList<>(dimension);
}
if ((paddingNoCast.size() == dimension) && !isNested) {
for (int i = 0; i < dimension; i++)
paddingList.add((int) paddingNoCast.get(i));
padding = ArrayUtil.toArray(paddingList);
} else if ((paddingNoCast.size() == dimension) && isNested) {
for (int j = 0; j < dimension; j++) {
@SuppressWarnings("unchecked")
List<Integer> item = (List<Integer>) paddingNoCast.get(j);
paddingList.add((item.get(0)));
paddingList.add((item.get(1)));
}
padding = ArrayUtil.toArray(paddingList);
} else {
throw new InvalidKerasConfigurationException("Found Keras ZeroPadding" + dimension
+ "D layer with invalid " + paddingList.size() + "D padding.");
}
} catch (Exception e) {
int paddingInt = (int) innerConfig.get(layerField);
if (dimension == 2) {
padding = new int[]{paddingInt, paddingInt, paddingInt, paddingInt};
} else {
padding = new int[]{paddingInt, paddingInt, paddingInt, paddingInt, paddingInt, paddingInt};
}
}
} else if (dimension == 1) {
Object paddingObj = innerConfig.get(layerField);
if (paddingObj instanceof List){
List<Integer> paddingList = (List)paddingObj;
padding = new int[]{
paddingList.get(0),
paddingList.get(1)
};
}
else{
int paddingInt = (int) innerConfig.get(layerField);
padding = new int[]{paddingInt, paddingInt};
}
} else {
throw new UnsupportedKerasConfigurationException(
"Keras padding layer not supported");
}
return padding;
}
}
@@ -0,0 +1,95 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.convolutional.Cropping1D;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasCropping1D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String croppingField = conf.getLAYER_FIELD_CROPPING();
int[] cropping = getPaddingFromConfig(layerConfig, conf, croppingField, 1);
Cropping1D.Builder builder = new Cropping1D.Builder(cropping)
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Cropping1D layer.
*
* @return Cropping1D layer
*/
public Cropping1D getCropping1DLayer() {
return (Cropping1D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Cropping layer accepts only one input (received " + inputType.length + ")");
return this.getCropping1DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,98 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.convolutional.Cropping2D;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfigLong;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasCropping2D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String croppingField = conf.getLAYER_FIELD_CROPPING();
long[] cropping = getPaddingFromConfigLong(layerConfig, conf, croppingField, 2);
Cropping2D.Builder builder = new Cropping2D.Builder(cropping)
.dataFormat(dimOrder == DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Cropping2D layer.
*
* @return Cropping2D layer
*/
public Cropping2D getCropping2DLayer() {
return (Cropping2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Cropping layer accepts only one input (received " + inputType.length + ")");
return this.getCropping2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,95 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.convolutional.Cropping3D;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasCropping3D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasCropping3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String croppingField = conf.getLAYER_FIELD_CROPPING();
int[] cropping = getPaddingFromConfig(layerConfig, conf, croppingField, 3);
Cropping3D.Builder builder = new Cropping3D.Builder(cropping)
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Cropping3D layer.
*
* @return Cropping3D layer
*/
public Cropping3D getCropping3DLayer() {
return (Cropping3D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Cropping 3D layer accepts only one input (received " + inputType.length + ")");
return this.getCropping3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,143 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Deconvolution2D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasDeconvolution2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = getDilationRateLong(layerConfig, 2, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
Deconvolution2D.Builder builder = new Deconvolution2D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.dataFormat(KerasConvolutionUtils.getDataFormatFromConfig(layerConfig,conf))
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.stride(getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
Deconvolution2D deconvolution2D = (Deconvolution2D) layer;
deconvolution2D.setDefaultValueOverriden(true);
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public Deconvolution2D getDeconvolution2DLayer() {
return (Deconvolution2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
return this.getDeconvolution2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,143 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Deconvolution3D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.weights.IWeightInit;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasDeconvolution3D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution3D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDeconvolution3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = getDilationRateLong(layerConfig, 3, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
Deconvolution3D.Builder builder = new Deconvolution3D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.dataFormat(KerasConvolutionUtils.getCNN3DDataFormatFromConfig(layerConfig,conf))
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.stride(getStrideFromConfigLong(layerConfig, 3, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 3, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
Deconvolution3D deconvolution3D = (Deconvolution3D) layer;
deconvolution3D.setDefaultValueOverriden(true);
}
/**
* Get DL4J ConvolutionLayer.
*
* @return ConvolutionLayer
*/
public Deconvolution3D getDeconvolution3DLayer() {
return (Deconvolution3D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
return this.getDeconvolution3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,231 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DepthwiseConvolution2D;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasRegularizerUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.*;
import org.deeplearning4j.nn.params.SeparableConvolutionParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasDepthwiseConvolution2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasDepthwiseConvolution2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasDepthwiseConvolution2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, Collections.<String, KerasLayer>emptyMap(), true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasDepthwiseConvolution2D(Map<String, Object> layerConfig,
Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, previousLayers, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasDepthwiseConvolution2D(Map<String, Object> layerConfig,
Map<String, ? extends KerasLayer> previousLayers, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, previousLayers, null, enforceTrainingConfig);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasDepthwiseConvolution2D(Map<String, Object> layerConfig,
Map<String, ? extends KerasLayer> previousLayers,
List<String> layerNamesToCheck, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
if (layerNamesToCheck != null) {
inboundLayerNames.addAll(layerNamesToCheck);
}
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = getDilationRateLong(layerConfig, 2, conf, false);
IWeightInit depthWiseInit = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig,
conf.getLAYER_FIELD_DEPTH_WISE_INIT(), enforceTrainingConfig, conf, kerasMajorVersion);
val nIn = getNInFromConfig(previousLayers);
int depthMultiplier = getDepthMultiplier(layerConfig, conf);
this.weightL1Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_DEPTH_WISE_REGULARIZER(), conf.getREGULARIZATION_TYPE_L1());
this.weightL2Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_DEPTH_WISE_REGULARIZER(), conf.getREGULARIZATION_TYPE_L2());
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint depthWiseWeightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_DEPTH_WISE_CONSTRAINT(), conf, kerasMajorVersion);
DepthwiseConvolution2D.Builder builder = new DepthwiseConvolution2D.Builder().name(this.layerName)
.dropOut(this.dropout)
.nIn(nIn)
.nOut(nIn * depthMultiplier)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(depthWiseInit)
.depthMultiplier(depthMultiplier)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.dataFormat(dimOrder == KerasLayer.DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.stride(getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (depthWiseWeightConstraint != null)
builder.constrainWeights(depthWiseWeightConstraint);
this.layer = builder.build();
DepthwiseConvolution2D depthwiseConvolution2D = (DepthwiseConvolution2D) layer;
depthwiseConvolution2D.setDefaultValueOverriden(true);
}
/**
* Set weights for layer.
*
* @param weights Map of weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
INDArray dW;
if (weights.containsKey(conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL()))
dW = weights.get(conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL());
else
throw new InvalidKerasConfigurationException(
"Keras DepthwiseConvolution2D layer does not contain parameter "
+ conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL());
this.weights.put(SeparableConvolutionParamInitializer.DEPTH_WISE_WEIGHT_KEY, dW);
if (hasBias) {
INDArray bias;
if (kerasMajorVersion == 2 && weights.containsKey("bias"))
bias = weights.get("bias");
else if (kerasMajorVersion == 1 && weights.containsKey("b"))
bias = weights.get("b");
else
throw new InvalidKerasConfigurationException(
"Keras DepthwiseConvolution2D layer does not contain bias parameter");
this.weights.put(SeparableConvolutionParamInitializer.BIAS_KEY, bias);
}
}
/**
* Get DL4J DepthwiseConvolution2D.
*
* @return DepthwiseConvolution2D
*/
public DepthwiseConvolution2D getDepthwiseConvolution2DLayer() {
return (DepthwiseConvolution2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras depth-wise convolution 2D layer accepts only one input (received " + inputType.length + ")");
return this.getDepthwiseConvolution2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,217 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.SeparableConvolution2D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasRegularizerUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.*;
import org.deeplearning4j.nn.params.SeparableConvolutionParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.HashMap;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasSeparableConvolution2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasSeparableConvolution2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasSeparableConvolution2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration
*/
public KerasSeparableConvolution2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 3 : 2;
long[] dilationRate = getDilationRateLong(layerConfig, 2, conf, false);
int depthMultiplier = getDepthMultiplier(layerConfig, conf);
IWeightInit depthWiseInit = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig,
conf.getLAYER_FIELD_DEPTH_WISE_INIT(), enforceTrainingConfig, conf, kerasMajorVersion);
IWeightInit pointWiseInit = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig,
conf.getLAYER_FIELD_POINT_WISE_INIT(), enforceTrainingConfig, conf, kerasMajorVersion);
if ( !depthWiseInit.getClass().equals(pointWiseInit.getClass()) )
if (enforceTrainingConfig)
throw new UnsupportedKerasConfigurationException(
"Specifying different initialization for depth- and point-wise weights not supported.");
else
log.warn("Specifying different initialization for depth- and point-wise weights not supported.");
this.weightL1Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_DEPTH_WISE_REGULARIZER(), conf.getREGULARIZATION_TYPE_L1());
this.weightL2Regularization = KerasRegularizerUtils.getWeightRegularizerFromConfig(
layerConfig, conf, conf.getLAYER_FIELD_DEPTH_WISE_REGULARIZER(), conf.getREGULARIZATION_TYPE_L2());
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint depthWiseWeightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_DEPTH_WISE_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint pointWiseWeightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_POINT_WISE_CONSTRAINT(), conf, kerasMajorVersion);
SeparableConvolution2D.Builder builder = new SeparableConvolution2D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(depthWiseInit)
.depthMultiplier(depthMultiplier)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.dataFormat(KerasConvolutionUtils.getDataFormatFromConfig(layerConfig,conf))
.stride(getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (hasBias)
builder.biasInit(0.0);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (depthWiseWeightConstraint != null)
builder.constrainWeights(depthWiseWeightConstraint);
if (pointWiseWeightConstraint != null)
builder.constrainPointWise(pointWiseWeightConstraint);
this.layer = builder.build();
SeparableConvolution2D separableConvolution2D = (SeparableConvolution2D) layer;
separableConvolution2D.setDefaultValueOverriden(true);
}
/**
* Set weights for layer.
*
* @param weights Map of weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
INDArray dW;
if (weights.containsKey(conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL())) {
dW = weights.get(conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL());
dW = dW.permute(3, 2, 0, 1);
} else
throw new InvalidKerasConfigurationException(
"Keras SeparableConvolution2D layer does not contain parameter "
+ conf.getLAYER_PARAM_NAME_DEPTH_WISE_KERNEL());
this.weights.put(SeparableConvolutionParamInitializer.DEPTH_WISE_WEIGHT_KEY, dW);
INDArray pW;
if (weights.containsKey(conf.getLAYER_PARAM_NAME_POINT_WISE_KERNEL())) {
pW = weights.get(conf.getLAYER_PARAM_NAME_POINT_WISE_KERNEL());
pW = pW.permute(3, 2, 0, 1);
}
else
throw new InvalidKerasConfigurationException(
"Keras SeparableConvolution2D layer does not contain parameter "
+ conf.getLAYER_PARAM_NAME_POINT_WISE_KERNEL());
this.weights.put(SeparableConvolutionParamInitializer.POINT_WISE_WEIGHT_KEY, pW);
if (hasBias) {
INDArray bias;
if (kerasMajorVersion == 2 && weights.containsKey("bias"))
bias = weights.get("bias");
else if (kerasMajorVersion == 1 && weights.containsKey("b"))
bias = weights.get("b");
else
throw new InvalidKerasConfigurationException(
"Keras SeparableConvolution2D layer does not contain bias parameter");
this.weights.put(SeparableConvolutionParamInitializer.BIAS_KEY, bias);
}
}
/**
* Get DL4J SeparableConvolution2D.
*
* @return SeparableConvolution2D
*/
public SeparableConvolution2D getSeparableConvolution2DLayer() {
return (SeparableConvolution2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras separable convolution 2D layer accepts only one input (received " + inputType.length + ")");
return this.getSeparableConvolution2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,93 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.SpaceToDepthLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
public class KerasSpaceToDepth extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration exception
*/
public KerasSpaceToDepth(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration exception
*/
public KerasSpaceToDepth(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
// TODO: we hard-code block size here to import YOLO9000. This size is not available as property
// in the hdf5 file outside of the serialized lambda function (that we can't really well deserialize).
SpaceToDepthLayer.Builder builder = new SpaceToDepthLayer.Builder()
.blocks(2)
//the default data format is tensorflow/NWHC for keras import
.dataFormat(SpaceToDepthLayer.DataFormat.NHWC)
.name(layerName);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J SpaceToDepth layer.
*
* @return SpaceToDepth layer
*/
public SpaceToDepthLayer getSpaceToDepthLayer() {
return (SpaceToDepthLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Space to Depth layer accepts only one input (received " + inputType.length + ")");
return this.getSpaceToDepthLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,98 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Upsampling1D;
import java.util.Map;
/**
* Keras Upsampling1D layer support
*
* @author Max Pumperla
*/
public class KerasUpsampling1D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration exception
*/
public KerasUpsampling1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Invalid Keras configuration exception
*/
public KerasUpsampling1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
int[] size = KerasConvolutionUtils.getUpsamplingSizeFromConfig(layerConfig, 1, conf);
Upsampling1D.Builder builder = new Upsampling1D.Builder()
.name(this.layerName)
.dropOut(this.dropout)
.size(size[0]);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Upsampling1D layer.
*
* @return Upsampling1D layer
*/
public Upsampling1D getUpsampling1DLayer() {
return (Upsampling1D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Upsampling 1D layer accepts only one input (received " + inputType.length + ")");
return this.getUpsampling1DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,97 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Upsampling2D;
import java.util.Map;
/**
* Keras Upsampling2D layer support
*
* @author Max Pumperla
*/
public class KerasUpsampling2D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration exception
*/
public KerasUpsampling2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Invalid Keras configuration exception
*/
public KerasUpsampling2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
long[] size = KerasConvolutionUtils.getUpsamplingSizeFromConfigLong(layerConfig, 2, conf);
Upsampling2D.Builder builder = new Upsampling2D.Builder()
.name(this.layerName)
.dropOut(this.dropout)
.size(size);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Upsampling2D layer.
*
* @return Upsampling2D layer
*/
public Upsampling2D getUpsampling2DLayer() {
return (Upsampling2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Upsampling layer accepts only one input (received " + inputType.length + ")");
return this.getUpsampling2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,102 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Upsampling3D;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getCNN3DDataFormatFromConfig;
/**
* Keras Upsampling3D layer support
*
* @author Max Pumperla
*/
public class KerasUpsampling3D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Unsupported Keras configuration exception
*/
public KerasUpsampling3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @throws UnsupportedKerasConfigurationException Invalid Keras configuration exception
*/
public KerasUpsampling3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
int[] size = KerasConvolutionUtils.getUpsamplingSizeFromConfig(layerConfig, 3, conf);
// TODO: make sure to allow different sizes.
Upsampling3D.Builder builder = new Upsampling3D.Builder()
.name(this.layerName)
.dropOut(this.dropout)
.dataFormat(getCNN3DDataFormatFromConfig(layerConfig,conf))
.size(size[0]);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Upsampling3D layer.
*
* @return Upsampling3D layer
*/
public Upsampling3D getUpsampling3DLayer() {
return (Upsampling3D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Upsampling 3D layer accepts only one input (received " + inputType.length + ")");
return this.getUpsampling3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,101 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ZeroPadding1DLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
/**
* Imports a Keras ZeroPadding 1D layer.
*
* @author Max Pumperla
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasZeroPadding1D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String paddingField = conf.getLAYER_FIELD_ZERO_PADDING();
ZeroPadding1DLayer.Builder builder = new ZeroPadding1DLayer.Builder(
getPaddingFromConfig(layerConfig, conf, paddingField, 1))
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J ZeroPadding1DLayer.
*
* @return ZeroPadding1DLayer
*/
public ZeroPadding1DLayer getZeroPadding1DLayer() {
return (ZeroPadding1DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras ZeroPadding layer accepts only one input (received " + inputType.length + ")");
return this.getZeroPadding1DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,104 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ZeroPaddingLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfigLong;
/**
* Imports a Keras ZeroPadding 2D layer.
*
* @author dave@skymind.io
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasZeroPadding2D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
*
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String paddingField = conf.getLAYER_FIELD_ZERO_PADDING();
ZeroPaddingLayer.Builder builder = new ZeroPaddingLayer.Builder(
getPaddingFromConfigLong(layerConfig, conf, paddingField, 2))
.dataFormat(dimOrder == DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J ZeroPadding2DLayer.
*
* @return ZeroPadding2DLayer
*/
public ZeroPaddingLayer getZeroPadding2DLayer() {
return (ZeroPaddingLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras ZeroPadding layer accepts only one input (received " + inputType.length + ")");
return this.getZeroPadding2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,101 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.convolutional;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ZeroPadding3DLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.getPaddingFromConfig;
/**
* Imports a Keras ZeroPadding 3D layer.
*
* @author Max Pumperla
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasZeroPadding3D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
*
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasZeroPadding3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
String paddingField = conf.getLAYER_FIELD_ZERO_PADDING();
int[] padding = getPaddingFromConfig(layerConfig, conf, paddingField,3);
ZeroPadding3DLayer.Builder builder = new ZeroPadding3DLayer.Builder(padding)
.name(this.layerName).dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J ZeroPadding3DLayer.
*
* @return ZeroPadding3DLayer
*/
public ZeroPadding3DLayer getZeroPadding3DLayer() {
return (ZeroPadding3DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras ZeroPadding3D layer accepts only one input (received " + inputType.length + ")");
return this.getZeroPadding3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,86 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ActivationLayer;
import java.util.Map;
@Slf4j
public class KerasActivation extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasActivation(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasActivation(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.layer = new ActivationLayer.Builder().name(this.layerName)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Activation layer accepts only one input (received " + inputType.length + ")");
return this.getActivationLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J ActivationLayer.
*
* @return ActivationLayer
*/
public ActivationLayer getActivationLayer() {
return (ActivationLayer) this.layer;
}
}
@@ -0,0 +1,174 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DenseLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.DefaultParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.HashMap;
import java.util.Map;
/**
* Imports a Dense layer from Keras.
*
* @author dave@skymind.io
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasDense extends KerasLayer {
/* Keras layer parameter names. */
private int numTrainableParams = 2;
private boolean hasBias;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDense(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDense(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDense(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
DenseLayer.Builder builder = new DenseLayer.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf))
.dropOut(this.dropout).activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.biasInit(0.0)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.hasBias(hasBias);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
}
/**
* Get DL4J DenseLayer.
*
* @return DenseLayer
*/
public DenseLayer getDenseLayer() {
return (DenseLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
/* Check whether layer requires a preprocessor for this InputType. */
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getDenseLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getDenseLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (2)
*/
@Override
public int getNumParams() {
return numTrainableParams;
}
/**
* Set weights for layer.
*
* @param weights Dense layer weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W()))
this.weights.put(DefaultParamInitializer.WEIGHT_KEY, weights.get(conf.getKERAS_PARAM_NAME_W()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_W() + " does not exist in weights");
if (hasBias) {
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
this.weights.put(DefaultParamInitializer.BIAS_KEY, weights.get(conf.getKERAS_PARAM_NAME_B()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_B() + " does not exist in weights");
}
KerasLayerUtils.removeDefaultWeights(weights, conf);
}
}
@@ -0,0 +1,89 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DropoutLayer;
import java.util.Map;
/**
* Imports a Dropout layer from Keras.
*
* @author dave@skymind.io
*/
@Slf4j
public class KerasDropout extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDropout(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasDropout(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.layer = new DropoutLayer.Builder().name(this.layerName).dropOut(this.dropout).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Dropout layer accepts only one input (received " + inputType.length + ")");
return this.getDropoutLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J DropoutLayer.
*
* @return DropoutLayer
*/
public DropoutLayer getDropoutLayer() {
return (DropoutLayer) this.layer;
}
}
@@ -0,0 +1,153 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.inputs.InputType.InputTypeConvolutional;
import org.deeplearning4j.nn.conf.layers.Convolution3D;
import org.deeplearning4j.nn.conf.preprocessor.Cnn3DToFeedForwardPreProcessor;
import org.deeplearning4j.nn.conf.preprocessor.CnnToFeedForwardPreProcessor;
import org.deeplearning4j.preprocessors.KerasFlattenRnnPreprocessor;
import org.deeplearning4j.preprocessors.ReshapePreprocessor;
import java.util.Map;
@Slf4j
public class KerasFlatten extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasFlatten(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasFlatten(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
}
/**
* Whether this Keras layer maps to a DL4J InputPreProcessor.
*
* @return true
*/
@Override
public boolean isInputPreProcessor() {
return true;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras config
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Flatten layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = null;
if (inputType[0] instanceof InputTypeConvolutional) {
InputTypeConvolutional it = (InputTypeConvolutional) inputType[0];
switch (this.getDimOrder()) {
case NONE:
case THEANO:
preprocessor = new CnnToFeedForwardPreProcessor(it.getHeight(), it.getWidth(), it.getChannels(), CNN2DFormat.NCHW);
break;
case TENSORFLOW:
preprocessor = new CnnToFeedForwardPreProcessor(it.getHeight(), it.getWidth(), it.getChannels(), CNN2DFormat.NHWC);
break;
default:
throw new InvalidKerasConfigurationException("Unknown Keras backend " + this.getDimOrder());
}
} else if (inputType[0] instanceof InputType.InputTypeRecurrent) {
InputType.InputTypeRecurrent it = (InputType.InputTypeRecurrent) inputType[0];
preprocessor = new KerasFlattenRnnPreprocessor(it.getSize(), it.getTimeSeriesLength());
} else if (inputType[0] instanceof InputType.InputTypeFeedForward) {
// NOTE: The output of an embedding layer in DL4J is of feed-forward type. Only if an FF to RNN input
// preprocessor is set or we explicitly provide 3D input data to start with, will the its output be set
// to RNN type. Otherwise we add this trivial preprocessor (since there's nothing to flatten).
InputType.InputTypeFeedForward it = (InputType.InputTypeFeedForward) inputType[0];
val inputShape = new long[]{it.getSize()};
preprocessor = new ReshapePreprocessor(inputShape, inputShape, false, null);
} else if(inputType[0] instanceof InputType.InputTypeConvolutional3D) {
InputType.InputTypeConvolutional3D it = (InputType.InputTypeConvolutional3D) inputType[0];
switch (this.getDimOrder()) {
case NONE:
case THEANO:
preprocessor = new Cnn3DToFeedForwardPreProcessor(it.getDepth(),it.getHeight(),it.getWidth(),
it.getChannels(),it.getDataFormat() == Convolution3D.DataFormat.NCDHW);
break;
case TENSORFLOW:
preprocessor = new Cnn3DToFeedForwardPreProcessor(it.getDepth(),it.getHeight(),it.getWidth(),
it.getChannels(),it.getDataFormat() != Convolution3D.DataFormat.NCDHW);
break;
default:
throw new InvalidKerasConfigurationException("Unknown Keras backend " + this.getDimOrder());
}
}
return preprocessor;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Flatten layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = getInputPreprocessor(inputType);
if (preprocessor != null) {
return preprocessor.getOutputType(inputType[0]);
}
return inputType[0];
}
}
@@ -0,0 +1,92 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.samediff.SameDiffLayer;
import java.util.Map;
/**
* Wraps a DL4J SameDiffLambda into a KerasLayer
*
* @author Max Pumperla
*/
@Slf4j
public class KerasLambda extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLambda(Map<String, Object> layerConfig, SameDiffLayer sameDiffLayer)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, sameDiffLayer);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLambda(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
SameDiffLayer sameDiffLayer)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
sameDiffLayer.setLayerName(this.layerName);
this.layer = sameDiffLayer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1) {
log.warn("Note: only first input type will be counted for lambda on layer with name " + layerName);
}
return this.getSameDiffLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J SameDiffLayer.
*
* @return SameDiffLayer
*/
public SameDiffLayer getSameDiffLayer() {
return (SameDiffLayer) this.layer;
}
}
@@ -0,0 +1,100 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.util.MaskZeroLayer;
import org.deeplearning4j.nn.layers.util.IdentityLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
/**
* Imports Keras masking layers.
*
* @author Max Pumperla
*/
@Slf4j
@Data
public class KerasMasking extends KerasLayer {
private double maskingValue;
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMasking(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMasking(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
maskingValue = KerasLayerUtils.getMaskingValueFromConfig(layerConfig, conf);
this.layer = new MaskZeroLayer.Builder()
.setMaskValue(maskingValue)
.setUnderlying(new IdentityLayer(this.layerName))
.name(this.layerName)
.build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Masking layer accepts only one input (received " + inputType.length + ")");
return this.getMaskingLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J MaskZeroLayer.
*
* @return MaskZeroLayer
*/
public MaskZeroLayer getMaskingLayer() {
return (MaskZeroLayer) this.layer;
}
}
@@ -0,0 +1,180 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.graph.ElementWiseVertex;
import org.deeplearning4j.nn.conf.graph.MergeVertex;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
@Slf4j
@Data
public class KerasMerge extends KerasLayer {
private final String LAYER_FIELD_MODE = "mode";
private final String LAYER_MERGE_MODE_SUM = "sum";
private final String LAYER_MERGE_MODE_MUL = "mul";
private final String LAYER_MERGE_MODE_CONCAT = "concat";
private final String LAYER_MERGE_MODE_AVE = "ave";
private final String LAYER_MERGE_MODE_COS = "cos";
private final String LAYER_MERGE_MODE_DOT = "dot";
private final String LAYER_MERGE_MODE_MAX = "max";
private ElementWiseVertex.Op mergeMode = null;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMerge(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMerge(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary and merge mode passed in.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param mergeMode ElementWiseVertex merge mode
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMerge(Map<String, Object> layerConfig, ElementWiseVertex.Op mergeMode, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.mergeMode = mergeMode;
if (this.mergeMode == null) {
this.vertex = new MergeVertex();
MergeVertex mergeVertex = (MergeVertex) this.vertex;
if(hasMergeAxis(layerConfig)) {
mergeVertex.setMergeAxis(getMergeAxisFromConfig(layerConfig));
}
}
else
this.vertex = new ElementWiseVertex(mergeMode);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasMerge(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.mergeMode = getMergeMode(layerConfig);
if (this.mergeMode == null) {
this.vertex = new MergeVertex();
MergeVertex mergeVertex = (MergeVertex) this.vertex;
if(hasMergeAxis(layerConfig)) {
mergeVertex.setMergeAxis(getMergeAxisFromConfig(layerConfig));
}
}
else
this.vertex = new ElementWiseVertex(mergeMode);
}
private ElementWiseVertex.Op getMergeMode(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(LAYER_FIELD_MODE))
throw new InvalidKerasConfigurationException(
"Keras Merge layer config missing " + LAYER_FIELD_MODE + " field");
ElementWiseVertex.Op op = null;
String mergeMode = (String) innerConfig.get(LAYER_FIELD_MODE);
switch (mergeMode) {
case LAYER_MERGE_MODE_SUM:
op = ElementWiseVertex.Op.Add;
break;
case LAYER_MERGE_MODE_MUL:
op = ElementWiseVertex.Op.Product;
break;
case LAYER_MERGE_MODE_CONCAT:
// leave null
break;
case LAYER_MERGE_MODE_AVE:
op = ElementWiseVertex.Op.Average;
break;
case LAYER_MERGE_MODE_MAX:
op = ElementWiseVertex.Op.Max;
break;
case LAYER_MERGE_MODE_COS:
case LAYER_MERGE_MODE_DOT:
default:
throw new UnsupportedKerasConfigurationException(
"Keras Merge layer mode " + mergeMode + " not supported");
}
return op;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
*/
@Override
public InputType getOutputType(InputType... inputType) {
return this.vertex.getOutputType(-1, inputType);
}
private boolean hasMergeAxis(Map<String,Object> config) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(config, conf);
return innerConfig.containsKey(conf.getLAYER_FIELD_CONSTRAINT_DIM());
}
private Integer getMergeAxisFromConfig(Map<String,Object> config) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(config, conf);
if(innerConfig.containsKey(conf.getLAYER_FIELD_CONSTRAINT_DIM())) {
Integer dim = (Integer) innerConfig.get(conf.getLAYER_FIELD_CONSTRAINT_DIM());
return dim;
}
return null;
}
}
@@ -0,0 +1,143 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.preprocessors.PermutePreprocessor;
import org.nd4j.common.util.ArrayUtil;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* Imports Permute layer from Keras
*
* @author Max Pumperla
*/
public class KerasPermute extends KerasLayer {
private int[] permutationIndices;
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPermute(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPermute(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
String permutationInfo = "dims";
if (innerConfig.containsKey(permutationInfo)) {
@SuppressWarnings("unchecked")
List<Integer> targetShapeList = (List<Integer>) innerConfig.get(permutationInfo);
this.permutationIndices = ArrayUtil.toArray(targetShapeList);
}
}
/**
* KerasPermute is an InputPreProcessor
*/
@Override
public boolean isInputPreProcessor() {
return true;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras config
* @see InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws
InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Permute layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = null;
if (inputType[0] instanceof InputType.InputTypeConvolutional) {
switch (this.getDimOrder()) {
case THEANO:
preprocessor = new PermutePreprocessor(permutationIndices);
break;
case NONE: // TF by default
case TENSORFLOW:
// account for channels last
permutationIndices = new int[] {permutationIndices[2], permutationIndices[0], permutationIndices[1]};
preprocessor = new PermutePreprocessor(new int[]{1, 3, 2});
}
} else if (inputType[0] instanceof InputType.InputTypeRecurrent) {
if (Arrays.equals(permutationIndices, new int[] {2, 1}))
preprocessor = new PermutePreprocessor(permutationIndices);
else
throw new InvalidKerasConfigurationException("For RNN type input data, permutation dims have to be" +
"(2, 1) in Permute layer, got " + Arrays.toString(permutationIndices));
} else if (inputType[0] instanceof InputType.InputTypeFeedForward) {
preprocessor = null;
} else {
throw new InvalidKerasConfigurationException("Input type not supported: " + inputType[0]);
}
return preprocessor;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Permute layer accepts only one input (received " + inputType.length + ")");
PermutePreprocessor reshape = (PermutePreprocessor) getInputPreprocessor(inputType);
return reshape.getOutputType(inputType[0]);
}
}
@@ -0,0 +1,98 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.misc.RepeatVector;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
@Slf4j
public class KerasRepeatVector extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasRepeatVector(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasRepeatVector(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.layer = new RepeatVector.Builder().repetitionFactor(getRepeatMultiplier(layerConfig, conf))
.dataFormat(RNNFormat.NWC)
.name(this.layerName).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras RepeatVector layer accepts only one input (received " + inputType.length + ")");
return this.getRepeatVectorLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J RepeatVector.
*
* @return RepeatVector
*/
public RepeatVector getRepeatVectorLayer() {
return (RepeatVector) this.layer;
}
static int getRepeatMultiplier(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
return (int) innerConfig.get(conf.getLAYER_FIELD_REPEAT_MULTIPLIER());
}
}
@@ -0,0 +1,185 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import lombok.val;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.preprocessors.ReshapePreprocessor;
import java.util.List;
import java.util.Map;
/**
* Imports Reshape layer from Keras
*
* @author Max Pumperla
*/
public class KerasReshape extends KerasLayer {
private long[] targetShape;
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasReshape(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
private long[] listToLongArray(List<Integer> list) {
long[] retVal = new long[list.size()];
for (int i = 0; i < list.size(); ++i) {
retVal[i] = list.get(i);
}
return retVal;
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasReshape(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
String targetShape = "target_shape";
if (innerConfig.containsKey(targetShape)) {
@SuppressWarnings("unchecked")
List<Integer> targetShapeList = (List<Integer>) innerConfig.get(targetShape);
this.targetShape = listToLongArray(targetShapeList);
}
}
/**
* Whether this Keras layer maps to a DL4J InputPreProcessor.
*
* @return true
*/
@Override
public boolean isInputPreProcessor() {
return true;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras config
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Reshape layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor = null;
if (inputType[0] instanceof InputType.InputTypeConvolutional) {
InputType.InputTypeConvolutional it = (InputType.InputTypeConvolutional) inputType[0];
val inputShape = new long[]{it.getChannels(), it.getHeight(), it.getWidth()};
val dimOrder = getDimOrder();
if (dimOrder == DimOrder.THEANO || dimOrder == DimOrder.NONE && kerasMajorVersion == 1) {
if (targetShape.length == 2) { // edge caseKeras
targetShape = new long[]{targetShape[1], targetShape[0]};
} else {
targetShape = new long[]{targetShape[1], targetShape[0], targetShape[2]};
}
preprocessor = new ReshapePreprocessor(inputShape, targetShape, false, CNN2DFormat.NCHW);
} else { // (dimOrder == DimOrder.TENSORFLOW || dimOrder == DimOrder.NONE && kerasMajorVersion == 2)
preprocessor = new ReshapePreprocessor(inputShape, targetShape, false, CNN2DFormat.NHWC);
}
} else if (inputType[0] instanceof InputType.InputTypeConvolutional3D) {
InputType.InputTypeConvolutional3D it = (InputType.InputTypeConvolutional3D) inputType[0];
val inputShape = new long[] { it.getDepth(), it.getHeight(), it.getWidth(), it.getChannels() };
val dimOrder = getDimOrder();
if (dimOrder == DimOrder.THEANO || dimOrder == DimOrder.NONE && kerasMajorVersion == 1) {
if (targetShape.length == 3) { // Keras edge case
targetShape = new long[] { targetShape[1], targetShape[0], targetShape[2] };
} else {
targetShape = new long[] { targetShape[2], targetShape[1], targetShape[0], targetShape[3] };
}
preprocessor = new ReshapePreprocessor(inputShape, targetShape, false, null);
} else {
if (inputShape[0] != targetShape[0])
targetShape = new long[] { targetShape[3], targetShape[0], targetShape[1], targetShape[2] };
preprocessor = new ReshapePreprocessor(inputShape, targetShape, false, null);
}
} else if (inputType[0] instanceof InputType.InputTypeRecurrent) {
InputType.InputTypeRecurrent it = (InputType.InputTypeRecurrent) inputType[0];
val inputShape = new long[]{it.getSize(), it.getTimeSeriesLength()};
preprocessor = new ReshapePreprocessor(inputShape, this.targetShape, false, null);
} else if (inputType[0] instanceof InputType.InputTypeFeedForward) {
InputType.InputTypeFeedForward it = (InputType.InputTypeFeedForward) inputType[0];
val inputShape = new long[]{it.getSize()};
if (targetShape.length == 3) {
targetShape = targetShapeForDimOrder(inputShape, targetShape);
}
preprocessor = new ReshapePreprocessor(inputShape, this.targetShape, false, null);
}
return preprocessor;
}
public long[] targetShapeForDimOrder(long[] inputShape, long[] targetShape) {
if (dimOrder == DimOrder.THEANO || dimOrder == DimOrder.NONE && kerasMajorVersion == 1) {
if (dimOrder == DimOrder.NONE) {
targetShape = new long[]{targetShape[2], targetShape[0], targetShape[1]};
} else {
targetShape = new long[]{targetShape[1], targetShape[2], targetShape[0]};
}
} else {
if (inputShape[0] != targetShape[0]) {
targetShape = new long[]{targetShape[0], targetShape[1], targetShape[2]};
}
}
return targetShape;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Reshape layer accepts only one input (received " + inputType.length + ")");
ReshapePreprocessor reshape = (ReshapePreprocessor) getInputPreprocessor(inputType);
return reshape.getOutputType(inputType[0]);
}
}
@@ -0,0 +1,112 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.core;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.dropout.SpatialDropout;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DropoutLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
/**
* Keras wrapper for DL4J dropout layer with SpatialDropout, works 1D-3D.
*
* @author Max Pumperla
*/
public class KerasSpatialDropout extends KerasLayer {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSpatialDropout(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSpatialDropout(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSpatialDropout(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_RATE())) {
throw new InvalidKerasConfigurationException("Keras configuration does not contain " +
"parameter" + conf.getLAYER_FIELD_RATE() +
"needed for spatial dropout");
}
double rate = (double) innerConfig.get(conf.getLAYER_FIELD_RATE()); // Keras stores drop rates
double retainRate = 1 - rate;
this.layer = new DropoutLayer.Builder().name(this.layerName)
.dropOut(new SpatialDropout(retainRate)).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras SpatialDropout layer accepts only one input (received " + inputType.length + ")");
return this.getSpatialDropoutLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J DropoutLayer with spatial dropout.
*
* @return DropoutLayer
*/
public DropoutLayer getSpatialDropoutLayer() {
return (DropoutLayer) this.layer;
}
}
@@ -0,0 +1,92 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.custom;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.LocalResponseNormalization;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
@Slf4j
public class KerasLRN extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
*
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLRN(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLRN(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> lrnParams = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
LocalResponseNormalization.Builder builder = new LocalResponseNormalization.Builder().name(this.layerName)
.dropOut(this.dropout).alpha((double) lrnParams.get("alpha"))
.beta((double) lrnParams.get("beta")).k((int) lrnParams.get("k")).n((int) lrnParams.get("n"));
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J LRN.
*
* @return LocalResponseNormalization
*/
public LocalResponseNormalization getLocalResponseNormalization() {
return (LocalResponseNormalization) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras LRN layer accepts only one input (received " + inputType.length + ")");
return this.getLocalResponseNormalization().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,72 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.custom;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.graph.PoolHelperVertex;
import org.deeplearning4j.nn.conf.inputs.InputType;
import java.util.Map;
@Slf4j
public class KerasPoolHelper extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
*
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPoolHelper(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPoolHelper(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.vertex = new PoolHelperVertex();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
*/
@Override
public InputType getOutputType(InputType... inputType) {
return this.vertex.getOutputType(-1, inputType);
}
}
@@ -0,0 +1,236 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.embeddings;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.EmbeddingLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.DefaultParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Imports an Embedding layer from Keras.
*
* @author dave@skymind.io
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class Keras2DEmbedding extends KerasLayer {
private final int NUM_TRAINABLE_PARAMS = 1;
private boolean zeroMasking;
private int inputDim;
private int inputLength;
private boolean inferInputLength;
/**
* Pass through constructor for unit tests
*
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public Keras2DEmbedding() throws UnsupportedKerasConfigurationException {
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public Keras2DEmbedding(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public Keras2DEmbedding(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.inputDim = getInputDimFromConfig(layerConfig);
this.inputLength = getInputLengthFromConfig(layerConfig);
this.inferInputLength = this.inputLength == 0;
if (this.inferInputLength)
this.inputLength = 1; // set dummy value, so shape inference works
this.zeroMasking = KerasLayerUtils.getZeroMaskingFromConfig(layerConfig, conf);
if (zeroMasking)
log.warn("Masking in keras and DL4J work differently. We do not completely support mask_zero flag " +
"on Embedding layers. Zero Masking for the Embedding layer only works with unidirectional LSTM for now."
+ " If you want to have this behaviour for your imported model " +
"in DL4J, apply masking as a pre-processing step to your input." +
"See https://deeplearning4j.konduit.ai/models/recurrent#masking-one-to-many-many-to-one-and-sequence-classification for more on this.");
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig,
conf.getLAYER_FIELD_EMBEDDING_INIT(),
enforceTrainingConfig,
conf, kerasMajorVersion);
LayerConstraint embeddingConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_EMBEDDINGS_CONSTRAINT(), conf, kerasMajorVersion);
int nOutFromConfig = KerasLayerUtils.getNOutFromConfig(layerConfig, conf);
EmbeddingLayer.Builder builder = new EmbeddingLayer.Builder()
.name(this.layerName)
.nIn(inputDim)
.nOut(nOutFromConfig)
.dropOut(this.dropout).activation(Activation.IDENTITY)
.weightInit(init)
.biasInit(0.0)
.l1(this.weightL1Regularization)
.l2(this.weightL2Regularization)
.hasBias(false);
if (embeddingConstraint != null)
builder.constrainWeights(embeddingConstraint);
this.layer = builder.build();
this.inputShape = new int[]{inputDim,1};
}
/**
* Get DL4J Embedding Sequence layer.
*
* @return Embedding Sequence layer
*/
public EmbeddingLayer getEmbeddingLayer() {
return (EmbeddingLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
/* Check whether layer requires a preprocessor for this InputType. */
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getEmbeddingLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getEmbeddingLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (1)
*/
@Override
public int getNumParams() {
return NUM_TRAINABLE_PARAMS;
}
/**
* Set weights for layer.
*
* @param weights Embedding layer weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
// TODO: "embeddings" is incorrectly read as "s" for some applications
if (weights.containsKey("s")) {
INDArray kernel = weights.get("s");
weights.remove("s");
weights.put(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS(), kernel);
}
if (!weights.containsKey(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS()))
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getLAYER_FIELD_EMBEDDING_WEIGHTS() + " does not exist in weights");
INDArray kernel = weights.get(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS());
if (this.zeroMasking) {
kernel.putRow(0, Nd4j.zeros(kernel.columns()));
}
this.weights.put(DefaultParamInitializer.WEIGHT_KEY, kernel);
if (weights.size() > 2) {
Set<String> paramNames = weights.keySet();
paramNames.remove(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS());
String unknownParamNames = paramNames.toString();
log.warn("Attempting to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
}
/**
* Get Keras input length from Keras layer configuration. In Keras input_length, if present, denotes
* the number of indices to embed per mini-batch, i.e. input will be of shape (mb, input_length)
* and (mb, 1) else.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return input length as int
*/
private int getInputLengthFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_INPUT_LENGTH()))
throw new InvalidKerasConfigurationException(
"Keras Embedding layer config missing " + conf.getLAYER_FIELD_INPUT_LENGTH() + " field");
if (innerConfig.get(conf.getLAYER_FIELD_INPUT_LENGTH()) == null) {
return 0;
} else {
return (int) innerConfig.get(conf.getLAYER_FIELD_INPUT_LENGTH());
}
}
/**
* Get Keras input dimension from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return input dim as int
*/
private int getInputDimFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_INPUT_DIM()))
throw new InvalidKerasConfigurationException(
"Keras Embedding layer config missing " + conf.getLAYER_FIELD_INPUT_DIM() + " field");
return (int) innerConfig.get(conf.getLAYER_FIELD_INPUT_DIM());
}
}
@@ -0,0 +1,242 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.embeddings;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.EmbeddingSequenceLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.DefaultParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils.getWeightInitFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getNOutFromConfig;
/**
* Imports an Embedding layer from Keras.
*
* @author dave@skymind.io
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasEmbedding extends KerasLayer {
private final int NUM_TRAINABLE_PARAMS = 1;
private boolean zeroMasking;
private int inputDim;
private int inputLength;
private boolean inferInputLength;
/**
* Pass through constructor for unit tests
*
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasEmbedding() throws UnsupportedKerasConfigurationException {
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasEmbedding(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasEmbedding(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.inputDim = getInputDimFromConfig(layerConfig);
this.inputLength = getInputLengthFromConfig(layerConfig);
this.inferInputLength = this.inputLength == 0;
if (this.inferInputLength)
this.inputLength = 1; // set dummy value, so shape inference works
this.zeroMasking = KerasLayerUtils.getZeroMaskingFromConfig(layerConfig, conf);
if (zeroMasking)
log.warn("Masking in keras and DL4J work differently. We do not completely support mask_zero flag " +
"on Embedding layers. Zero Masking for the Embedding layer only works with unidirectional LSTM for now."
+ " If you want to have this behaviour for your imported model " +
"in DL4J, apply masking as a pre-processing step to your input." +
"See https://deeplearning4j.konduit.ai/models/recurrent#masking-one-to-many-many-to-one-and-sequence-classification for more on this.");
IWeightInit init = getWeightInitFromConfig(layerConfig,
conf.getLAYER_FIELD_EMBEDDING_INIT(),
enforceTrainingConfig,
conf, kerasMajorVersion);
LayerConstraint embeddingConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_EMBEDDINGS_CONSTRAINT(), conf, kerasMajorVersion);
int nOutFromConfig = getNOutFromConfig(layerConfig, conf);
EmbeddingSequenceLayer.Builder builder = new EmbeddingSequenceLayer.Builder()
.name(this.layerName)
.nIn(inputDim)
.inputLength(inputLength)
.inferInputLength(inferInputLength)
.nOut(nOutFromConfig)
.dropOut(this.dropout).activation(Activation.IDENTITY)
.weightInit(init)
.biasInit(0.0)
.l1(this.weightL1Regularization)
.l2(this.weightL2Regularization)
.outputDataFormat(RNNFormat.NWC)
.hasBias(false);
if (embeddingConstraint != null)
builder.constrainWeights(embeddingConstraint);
this.layer = builder.build();
this.inputShape = new int[]{inputDim,1};
}
/**
* Get DL4J Embedding Sequence layer.
*
* @return Embedding Sequence layer
*/
public EmbeddingSequenceLayer getEmbeddingLayer() {
return (EmbeddingSequenceLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
/* Check whether layer requires a preprocessor for this InputType. */
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getEmbeddingLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getEmbeddingLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (1)
*/
@Override
public int getNumParams() {
return NUM_TRAINABLE_PARAMS;
}
/**
* Set weights for layer.
*
* @param weights Embedding layer weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
// TODO: "embeddings" is incorrectly read as "s" for some applications
if (weights.containsKey("s")) {
INDArray kernel = weights.get("s");
weights.remove("s");
weights.put(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS(), kernel);
}
if (!weights.containsKey(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS()))
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getLAYER_FIELD_EMBEDDING_WEIGHTS() + " does not exist in weights");
INDArray kernel = weights.get(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS());
if (this.zeroMasking) {
kernel.putRow(0, Nd4j.zeros(kernel.columns()));
}
this.weights.put(DefaultParamInitializer.WEIGHT_KEY, kernel);
if (weights.size() > 2) {
Set<String> paramNames = weights.keySet();
paramNames.remove(conf.getLAYER_FIELD_EMBEDDING_WEIGHTS());
String unknownParamNames = paramNames.toString();
log.warn("Attempting to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
}
/**
* Get Keras input length from Keras layer configuration. In Keras input_length, if present, denotes
* the number of indices to embed per mini-batch, i.e. input will be of shape (mb, input_length)
* and (mb, 1) else.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return input length as int
*/
private int getInputLengthFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_INPUT_LENGTH()))
throw new InvalidKerasConfigurationException(
"Keras Embedding layer config missing " + conf.getLAYER_FIELD_INPUT_LENGTH() + " field");
if (innerConfig.get(conf.getLAYER_FIELD_INPUT_LENGTH()) == null) {
return 0;
} else {
return (int) innerConfig.get(conf.getLAYER_FIELD_INPUT_LENGTH());
}
}
/**
* Get Keras input dimension from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return input dim as int
*/
private int getInputDimFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_INPUT_DIM()))
throw new InvalidKerasConfigurationException(
"Keras Embedding layer config missing " + conf.getLAYER_FIELD_INPUT_DIM() + " field");
return (int) innerConfig.get(conf.getLAYER_FIELD_INPUT_DIM());
}
}
@@ -0,0 +1,181 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.local;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolution;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.LocallyConnected1D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.ConvolutionParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.HashMap;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasLocallyConnected1D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected1D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
int[] dilationRate = getDilationRate(layerConfig, 1, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
LocallyConnected1D.Builder builder = new LocallyConnected1D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getActivationFromConfig(layerConfig, conf))
.weightInit(conf.getKERAS_PARAM_NAME_W(), init)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfig(layerConfig, 1, conf, kerasMajorVersion)[0])
.hasBias(hasBias)
.stride(getStrideFromConfig(layerConfig, 1, conf)[0]);
int[] padding = getPaddingFromBorderModeConfig(layerConfig, 1, conf, kerasMajorVersion);
if (padding != null)
builder.padding(padding[0]);
if (dilationRate != null)
builder.dilation(dilationRate[0]);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
}
/**
* Get DL4J LocallyConnected1D layer.
*
* @return Locally connected 1D layer.
*/
public LocallyConnected1D getLocallyConnected1DLayer() {
return (LocallyConnected1D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
InputType.InputTypeRecurrent rnnType = (InputType.InputTypeRecurrent) inputType[0];
// Override input/output shape and input channels dynamically. This works since getOutputType will always
// be called when initializing the model.
((LocallyConnected1D) this.layer).setInputSize((int) rnnType.getTimeSeriesLength());
((LocallyConnected1D) this.layer).setNIn(rnnType.getSize());
((LocallyConnected1D) this.layer).computeOutputSize();
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getLocallyConnected1DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getLocallyConnected1DLayer().getOutputType(-1, inputType[0]);
}
/**
* Set weights for 1D locally connected layer.
*
* @param weights Map from parameter name to INDArray.
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W())) {
INDArray kerasParamValue = weights.get(conf.getKERAS_PARAM_NAME_W());
this.weights.put(ConvolutionParamInitializer.WEIGHT_KEY, kerasParamValue);
} else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_W() + " does not exist in weights");
if (hasBias) {
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
this.weights.put(ConvolutionParamInitializer.BIAS_KEY, weights.get(conf.getKERAS_PARAM_NAME_B()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_B() + " does not exist in weights");
}
KerasLayerUtils.removeDefaultWeights(weights, conf);
}
}
@@ -0,0 +1,181 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.local;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolution;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.LocallyConnected2D;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.ConvolutionParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.HashMap;
import java.util.Map;
import static org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasLocallyConnected2D extends KerasConvolution {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected2D(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLocallyConnected2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
hasBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
numTrainableParams = hasBias ? 2 : 1;
long[] dilationRate = getDilationRateLong(layerConfig, 2, conf, false);
IWeightInit init = KerasInitilizationUtils.getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
// TODO: take care of bias init
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
LocallyConnected2D.Builder builder = new LocallyConnected2D.Builder().name(this.layerName)
.nOut(KerasLayerUtils.getNOutFromConfig(layerConfig, conf)).dropOut(this.dropout)
.activation(KerasActivationUtils.getActivationFromConfig(layerConfig, conf))
.weightInit(conf.getKERAS_PARAM_NAME_W(), init)
.l1(this.weightL1Regularization).l2(this.weightL2Regularization)
.convolutionMode(getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.hasBias(hasBias)
.stride(getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (padding != null)
builder.padding(padding);
if (dilationRate != null)
builder.dilation(dilationRate);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainWeights(weightConstraint);
this.layer = builder.build();
}
/**
* Get DL4J LocallyConnected2D layer.
*
* @return Locally connected 2D layer.
*/
public LocallyConnected2D getLocallyConnected2DLayer() {
return (LocallyConnected2D) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Convolution layer accepts only one input (received " + inputType.length + ")");
InputType.InputTypeConvolutional convType = (InputType.InputTypeConvolutional) inputType[0];
// Override input/output shape and input channels dynamically. This works since getOutputType will always
// be called when initializing the model.
((LocallyConnected2D) this.layer).setInputSize(new long[] {convType.getHeight(),convType.getWidth()});
((LocallyConnected2D) this.layer).setNIn(convType.getChannels());
((LocallyConnected2D) this.layer).computeOutputSize();
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getLocallyConnected2DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getLocallyConnected2DLayer().getOutputType(-1, inputType[0]);
}
/**
* Set weights for 2D locally connected layer.
*
* @param weights Map from parameter name to INDArray.
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W())) {
INDArray kerasParamValue = weights.get(conf.getKERAS_PARAM_NAME_W());
this.weights.put(ConvolutionParamInitializer.WEIGHT_KEY, kerasParamValue);
} else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_W() + " does not exist in weights");
if (hasBias) {
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
this.weights.put(ConvolutionParamInitializer.BIAS_KEY, weights.get(conf.getKERAS_PARAM_NAME_B()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getKERAS_PARAM_NAME_B() + " does not exist in weights");
}
KerasLayerUtils.removeDefaultWeights(weights, conf);
}
}
@@ -0,0 +1,112 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.noise;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.dropout.AlphaDropout;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DropoutLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
/**
* Keras wrapper for DL4J dropout layer with AlphaDropout.
*
* @author Max Pumperla
*/
public class KerasAlphaDropout extends KerasLayer {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAlphaDropout(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAlphaDropout(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasAlphaDropout(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_RATE())) {
throw new InvalidKerasConfigurationException("Keras configuration does not contain " +
"parameter" + conf.getLAYER_FIELD_RATE() +
"needed for AlphaDropout");
}
double rate = (double) innerConfig.get(conf.getLAYER_FIELD_RATE()); // Keras stores drop rates
double retainRate = 1 - rate;
this.layer = new DropoutLayer.Builder().name(this.layerName)
.dropOut(new AlphaDropout(retainRate)).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Alpha Dropout layer accepts only one input (received " + inputType.length + ")");
return this.getAlphaDropoutLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J DropoutLayer with Alpha dropout.
*
* @return DropoutLayer
*/
public DropoutLayer getAlphaDropoutLayer() {
return (DropoutLayer) this.layer;
}
}
@@ -0,0 +1,110 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.noise;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.dropout.GaussianDropout;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DropoutLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
/**
* Keras wrapper for DL4J dropout layer with GaussianDropout.
*
* @author Max Pumperla
*/
public class KerasGaussianDropout extends KerasLayer {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Invalid Keras config
*/
public KerasGaussianDropout(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGaussianDropout(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGaussianDropout(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_RATE())) {
throw new InvalidKerasConfigurationException("Keras configuration does not contain " +
"parameter" + conf.getLAYER_FIELD_RATE() +
"needed for GaussianDropout");
}
double rate = (double) innerConfig.get(conf.getLAYER_FIELD_RATE()); // Keras stores drop rates
double retainRate = 1 - rate;
this.layer = new DropoutLayer.Builder().name(this.layerName)
.dropOut(new GaussianDropout(retainRate)).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Gaussian Dropout layer accepts only one input (received " + inputType.length + ")");
return this.getGaussianDropoutLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J DropoutLayer with Gaussian dropout.
*
* @return DropoutLayer
*/
public DropoutLayer getGaussianDropoutLayer() {
return (DropoutLayer) this.layer;
}
}
@@ -0,0 +1,109 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.noise;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.dropout.GaussianNoise;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.DropoutLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
/**
* Keras wrapper for DL4J dropout layer with GaussianNoise.
*
* @author Max Pumperla
*/
public class KerasGaussianNoise extends KerasLayer {
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGaussianNoise(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGaussianNoise(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGaussianNoise(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_GAUSSIAN_VARIANCE())) {
throw new InvalidKerasConfigurationException("Keras configuration does not contain "
+ conf.getLAYER_FIELD_GAUSSIAN_VARIANCE() + " parameter" +
"needed for GaussianNoise");
}
double stddev = (double) innerConfig.get(conf.getLAYER_FIELD_GAUSSIAN_VARIANCE());
this.layer = new DropoutLayer.Builder().name(this.layerName)
.dropOut(new GaussianNoise(stddev)).build();
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Gaussian Noise layer accepts only one input (received " + inputType.length + ")");
return this.getGaussianNoiseLayer().getOutputType(-1, inputType[0]);
}
/**
* Get DL4J DropoutLayer with Gaussian dropout.
*
* @return DropoutLayer
*/
public DropoutLayer getGaussianNoiseLayer() {
return (DropoutLayer) this.layer;
}
}
@@ -0,0 +1,395 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.normalization;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.BatchNormalization;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.BatchNormalizationParamInitializer;
import org.nd4j.common.util.OneTimeLogger;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.util.*;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasBatchNormalization extends KerasLayer {
/* Keras layer configuration fields. */
private final int LAYER_BATCHNORM_MODE_1 = 1;
private final int LAYER_BATCHNORM_MODE_2 = 2;
private final String LAYER_FIELD_GAMMA_REGULARIZER = "gamma_regularizer";
private final String LAYER_FIELD_BETA_REGULARIZER = "beta_regularizer";
private final String LAYER_FIELD_MODE = "mode";
private final String LAYER_FIELD_AXIS = "axis";
private final String LAYER_FIELD_MOMENTUM = "momentum";
private final String LAYER_FIELD_EPSILON = "epsilon";
private final String LAYER_FIELD_SCALE = "scale";
private final String LAYER_FIELD_CENTER = "center";
/* Keras layer parameter names. */
private final int NUM_TRAINABLE_PARAMS = 4;
private final String PARAM_NAME_GAMMA = "gamma";
private final String PARAM_NAME_BETA = "beta";
private final String PARAM_NAME_RUNNING_MEAN = "running_mean";
private final String PARAM_NAME_RUNNING_STD = "running_std";
private boolean scale = true;
private boolean center = true;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBatchNormalization(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBatchNormalization(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBatchNormalization(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig,enforceTrainingConfig, Collections.emptyMap());
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBatchNormalization(Map<String, Object> layerConfig, boolean enforceTrainingConfig,Map<String,? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Object config2 = layerConfig.get("config");
Map<String,Object> config1 = (Map<String,Object>) config2;
//default ordering
List<Object> inboundNodes = (List<Object>) layerConfig.get(conf.getLAYER_FIELD_INBOUND_NODES());
CNN2DFormat cnn2DFormat = CNN2DFormat.NCHW;
if(inboundNodes != null && !inboundNodes.isEmpty()) {
List<Object> list = (List<Object>) inboundNodes.get(0);
List<Object> list1 = (List<Object>) list.get(0);
String inputName = list1.get(0).toString();
KerasLayer kerasLayer = previousLayers.get(inputName);
DimOrder dimOrderFromConfig = KerasLayerUtils.getDimOrderFromConfig(kerasLayer.getOriginalLayerConfig(), kerasLayer.getConf());
if(dimOrderFromConfig == DimOrder.NONE || dimOrderFromConfig == DimOrder.TENSORFLOW)
cnn2DFormat = CNN2DFormat.NHWC;
} else if(!previousLayers.isEmpty()) {
KerasLayer prevLayer = previousLayers.values().stream().findFirst().get();
if(prevLayer.getDimOrder() != null) {
this.dimOrder = prevLayer.getDimOrder();
cnn2DFormat = CNN2DFormat.NHWC;
}
}
this.scale = getScaleParameter(layerConfig);
this.center = getCenterParameter(layerConfig);
// TODO: these helper functions should return regularizers that we use in constructor
getGammaRegularizerFromConfig(layerConfig, enforceTrainingConfig);
getBetaRegularizerFromConfig(layerConfig, enforceTrainingConfig);
int batchNormMode = getBatchNormMode(layerConfig, enforceTrainingConfig);
if (batchNormMode != 0)
throw new UnsupportedKerasConfigurationException("Unsupported batch normalization mode " + batchNormMode +
"Keras modes 1 and 2 have been removed from keras 2.x altogether." +
"Try running with mode 0.");
int batchNormAxis = getBatchNormAxis(layerConfig);
if (!(batchNormAxis == 3 || batchNormAxis == -1))
OneTimeLogger.warn(log,"Warning: batch normalization axis " + batchNormAxis +
"\n DL4J currently picks batch norm dimensions for you, according to industry" +
"standard conventions. If your results do not match, please file an issue.");
LayerConstraint betaConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_BATCHNORMALIZATION_BETA_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint gammaConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_BATCHNORMALIZATION_GAMMA_CONSTRAINT(), conf, kerasMajorVersion);
BatchNormalization.Builder builder = new BatchNormalization.Builder()
.name(this.layerName)
.dropOut(this.dropout)
.minibatch(true)
.lockGammaBeta(false)
.useLogStd(false)
.decay(getMomentumFromConfig(layerConfig))
.eps(getEpsFromConfig(layerConfig));
if (betaConstraint != null)
builder.constrainBeta(betaConstraint);
if (gammaConstraint != null)
builder.constrainGamma(gammaConstraint);
builder.setCnn2DFormat(cnn2DFormat);
this.layer = builder.build();
}
/**
* Get DL4J BatchNormalizationLayer.
*
* @return BatchNormalizationLayer
*/
public BatchNormalization getBatchNormalizationLayer() {
return (BatchNormalization) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras BatchNorm layer accepts only one input (received " + inputType.length + ")");
return this.getBatchNormalizationLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (4)
*/
@Override
public int getNumParams() {
return NUM_TRAINABLE_PARAMS;
}
/**
* Set weights for layer.
*
* @param weights Map from parameter name to INDArray.
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
if (center) {
if (weights.containsKey(PARAM_NAME_BETA))
this.weights.put(BatchNormalizationParamInitializer.BETA, weights.get(PARAM_NAME_BETA));
else
throw new InvalidKerasConfigurationException("Parameter " + PARAM_NAME_BETA + " does not exist in weights");
} else {
INDArray dummyBeta = Nd4j.zerosLike(weights.get(PARAM_NAME_BETA));
this.weights.put(BatchNormalizationParamInitializer.BETA, dummyBeta);
}
if (scale) {
if (weights.containsKey(PARAM_NAME_GAMMA))
this.weights.put(BatchNormalizationParamInitializer.GAMMA, weights.get(PARAM_NAME_GAMMA));
else
throw new InvalidKerasConfigurationException(
"Parameter " + PARAM_NAME_GAMMA + " does not exist in weights");
} else {
INDArray dummyGamma = weights.containsKey(PARAM_NAME_GAMMA)
? Nd4j.onesLike(weights.get(PARAM_NAME_GAMMA))
: Nd4j.onesLike(weights.get(PARAM_NAME_BETA));
this.weights.put(BatchNormalizationParamInitializer.GAMMA, dummyGamma);
}
if (weights.containsKey(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN()))
this.weights.put(BatchNormalizationParamInitializer.GLOBAL_MEAN, weights.get(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN() + " does not exist in weights");
if (weights.containsKey(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE()))
this.weights.put(BatchNormalizationParamInitializer.GLOBAL_VAR, weights.get(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE()));
else
throw new InvalidKerasConfigurationException(
"Parameter " + conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE() + " does not exist in weights");
if (weights.size() > 4) {
Set<String> paramNames = weights.keySet();
paramNames.remove(PARAM_NAME_BETA);
paramNames.remove(PARAM_NAME_GAMMA);
paramNames.remove(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_MEAN());
paramNames.remove(conf.getLAYER_FIELD_BATCHNORMALIZATION_MOVING_VARIANCE());
String unknownParamNames = paramNames.toString();
log.warn("Attempting to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
}
/**
* Get BatchNormalization epsilon parameter from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return epsilon
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private double getEpsFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(LAYER_FIELD_EPSILON))
throw new InvalidKerasConfigurationException(
"Keras BatchNorm layer config missing " + LAYER_FIELD_EPSILON + " field");
return (double) innerConfig.get(LAYER_FIELD_EPSILON);
}
/**
* Get BatchNormalization momentum parameter from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return momentum
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private double getMomentumFromConfig(Map<String, Object> layerConfig) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(LAYER_FIELD_MOMENTUM))
throw new InvalidKerasConfigurationException(
"Keras BatchNorm layer config missing " + LAYER_FIELD_MOMENTUM + " field");
return (double) innerConfig.get(LAYER_FIELD_MOMENTUM);
}
/**
* Get BatchNormalization gamma regularizer from Keras layer configuration. Currently unsupported.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Batchnormalization gamma regularizer
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private void getGammaRegularizerFromConfig(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.get(LAYER_FIELD_GAMMA_REGULARIZER) != null) {
if (enforceTrainingConfig)
throw new UnsupportedKerasConfigurationException(
"Regularization for BatchNormalization gamma parameter not supported");
else
log.warn("Regularization for BatchNormalization gamma parameter not supported...ignoring.");
}
}
private boolean getScaleParameter(Map<String, Object> layerConfig)
throws UnsupportedOperationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(LAYER_FIELD_SCALE)) {
return (boolean) innerConfig.get(LAYER_FIELD_SCALE);
} else {
return true;
}
}
private boolean getCenterParameter(Map<String, Object> layerConfig)
throws UnsupportedOperationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(LAYER_FIELD_CENTER)) {
return (boolean) innerConfig.get(LAYER_FIELD_CENTER);
} else {
return true;
}
}
/**
* Get BatchNormalization beta regularizer from Keras layer configuration. Currently unsupported.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Batchnormalization beta regularizer
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private void getBetaRegularizerFromConfig(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.get(LAYER_FIELD_BETA_REGULARIZER) != null) {
if (enforceTrainingConfig)
throw new UnsupportedKerasConfigurationException(
"Regularization for BatchNormalization beta parameter not supported");
else
log.warn("Regularization for BatchNormalization beta parameter not supported...ignoring.");
}
}
/**
* Get BatchNormalization "mode" from Keras layer configuration. Most modes currently unsupported.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return batchnormalization mode
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private int getBatchNormMode(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int batchNormMode = 0;
if (this.kerasMajorVersion == 1 & !innerConfig.containsKey(LAYER_FIELD_MODE))
throw new InvalidKerasConfigurationException(
"Keras BatchNorm layer config missing " + LAYER_FIELD_MODE + " field");
if (this.kerasMajorVersion == 1)
batchNormMode = (int) innerConfig.get(LAYER_FIELD_MODE);
switch (batchNormMode) {
case LAYER_BATCHNORM_MODE_1:
throw new UnsupportedKerasConfigurationException("Keras BatchNormalization mode "
+ LAYER_BATCHNORM_MODE_1 + " (sample-wise) not supported");
case LAYER_BATCHNORM_MODE_2:
throw new UnsupportedKerasConfigurationException(
"Keras BatchNormalization (per-batch statistics during testing) "
+ LAYER_BATCHNORM_MODE_2 + " not supported");
}
return batchNormMode;
}
/**
* Get BatchNormalization axis from Keras layer configuration. Currently unused.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return batchnorm axis
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
private int getBatchNormAxis(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
Object batchNormAxis = innerConfig.get(LAYER_FIELD_AXIS);
if (batchNormAxis instanceof List){
return ((Number)((List)batchNormAxis).get(0)).intValue();
}
return ((Number)innerConfig.get(LAYER_FIELD_AXIS)).intValue();
}
}
@@ -0,0 +1,132 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.pooling;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.GlobalPoolingLayer;
import org.deeplearning4j.nn.conf.preprocessor.FeedForwardToRnnPreProcessor;
import java.util.Map;
/**
* Imports a Keras Pooling layer as a DL4J Subsampling layer.
*
* @author dave@skymind.io, Max Pumperla
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasGlobalPooling extends KerasLayer {
private final long[] dimensions;
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGlobalPooling(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasGlobalPooling(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
this.dimensions = KerasPoolingUtils.mapGlobalPoolingDimensionsLong(this.className, conf, dimOrder);
GlobalPoolingLayer.Builder builder =
new GlobalPoolingLayer.Builder(KerasPoolingUtils.mapPoolingType(this.className, conf))
.poolingDimensions(dimensions)
.collapseDimensions(true) // keras 2 collapses dimensions
.name(this.layerName)
.dropOut(this.dropout);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J SubsamplingLayer.
*
* @return SubsamplingLayer
*/
public GlobalPoolingLayer getGlobalPoolingLayer() {
return (GlobalPoolingLayer) this.layer;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras config
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras GlobalPooling layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preprocessor;
if (inputType[0].getType() == InputType.Type.FF && this.dimensions.length == 1) {
preprocessor = new FeedForwardToRnnPreProcessor();
} else {
preprocessor = this.getGlobalPoolingLayer().getPreProcessorForInputType(inputType[0]);
}
return preprocessor;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Subsampling layer accepts only one input (received " + inputType.length + ")");
/* Check whether layer requires a preprocessor for this InputType. */
InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
if (preprocessor != null) {
return this.getGlobalPoolingLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
}
return this.getGlobalPoolingLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,104 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.pooling;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Subsampling1DLayer;
import java.util.Map;
/**
* Imports a Keras 1D Pooling layer as a DL4J Subsampling layer.
*
* @author Max Pumperla
*/
@Slf4j
public class KerasPooling1D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling1D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling1D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Subsampling1DLayer.Builder builder = new Subsampling1DLayer.Builder(
KerasPoolingUtils.mapPoolingType(this.className, conf)).name(this.layerName)
.dropOut(this.dropout)
.dataFormat(dimOrder == DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.convolutionMode(KerasConvolutionUtils.getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(KerasConvolutionUtils.getKernelSizeFromConfig(layerConfig, 1, conf, kerasMajorVersion)[0])
.stride(KerasConvolutionUtils.getStrideFromConfig(layerConfig, 1, conf)[0]);
int[] padding = KerasConvolutionUtils.getPaddingFromBorderModeConfig(layerConfig, 1, conf, kerasMajorVersion);
if (padding != null)
builder.padding(padding[0]);
this.layer = builder.build();
Subsampling1DLayer subsampling1DLayer = (Subsampling1DLayer) this.layer;
subsampling1DLayer.setDefaultValueOverridden(true);
this.vertex = null;
}
/**
* Get DL4J Subsampling1DLayer.
*
* @return Subsampling1DLayer
*/
public Subsampling1DLayer getSubsampling1DLayer() {
return (Subsampling1DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Subsampling 1D layer accepts only one input (received " + inputType.length + ")");
return this.getSubsampling1DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,105 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.pooling;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils;
import org.deeplearning4j.nn.conf.CNN2DFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.SubsamplingLayer;
import java.util.Map;
/**
* Imports a Keras 2D Pooling layer as a DL4J Subsampling layer.
*
* @author dave@skymind.io
*/
@Slf4j
public class KerasPooling2D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling2D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling2D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
SubsamplingLayer.Builder builder = new SubsamplingLayer.Builder(
KerasPoolingUtils.mapPoolingType(this.className, conf)).name(this.layerName)
.dropOut(this.dropout)
.dataFormat(dimOrder == DimOrder.TENSORFLOW ? CNN2DFormat.NHWC : CNN2DFormat.NCHW)
.convolutionMode(KerasConvolutionUtils.getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(KerasConvolutionUtils.getKernelSizeFromConfigLong(layerConfig, 2, conf, kerasMajorVersion))
.stride(KerasConvolutionUtils.getStrideFromConfigLong(layerConfig, 2, conf));
long[] padding = KerasConvolutionUtils.getPaddingFromBorderModeConfigLong(layerConfig, 2, conf, kerasMajorVersion);
if (padding != null)
builder.padding(padding);
this.layer = builder.build();
SubsamplingLayer subsamplingLayer = (SubsamplingLayer) layer;
//ensure the default value stays
subsamplingLayer.setDefaultValueOverridden(true);
this.vertex = null;
}
/**
* Get DL4J SubsamplingLayer.
*
* @return SubsamplingLayer
*/
public SubsamplingLayer getSubsampling2DLayer() {
return (SubsamplingLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Subsampling 2D layer accepts only one input (received " + inputType.length + ")");
return this.getSubsampling2DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,101 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.pooling;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolutionUtils;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.Subsampling3DLayer;
import java.util.Map;
/**
* Imports a Keras 3D Pooling layer as a DL4J Subsampling3D layer.
*
* @author Max Pumperla
*/
@Slf4j
public class KerasPooling3D extends KerasLayer {
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling3D(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasPooling3D(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Subsampling3DLayer.Builder builder = new Subsampling3DLayer.Builder(
KerasPoolingUtils.mapPoolingType(this.className, conf)).name(this.layerName)
.dropOut(this.dropout)
.dataFormat(KerasConvolutionUtils.getCNN3DDataFormatFromConfig(layerConfig,conf))
.convolutionMode(KerasConvolutionUtils.getConvolutionModeFromConfig(layerConfig, conf))
.kernelSize(KerasConvolutionUtils.getKernelSizeFromConfig(layerConfig, 3, conf, kerasMajorVersion))
.stride(KerasConvolutionUtils.getStrideFromConfig(layerConfig, 3, conf));
int[] padding = KerasConvolutionUtils.getPaddingFromBorderModeConfig(layerConfig, 3, conf, kerasMajorVersion);
if (padding != null)
builder.padding(padding);
this.layer = builder.build();
this.vertex = null;
}
/**
* Get DL4J Subsampling3DLayer.
*
* @return Subsampling3DLayer
*/
public Subsampling3DLayer getSubsampling3DLayer() {
return (Subsampling3DLayer) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Subsampling/Pooling 3D layer accepts only one input (received " + inputType.length + ")");
return this.getSubsampling3DLayer().getOutputType(-1, inputType[0]);
}
}
@@ -0,0 +1,167 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.pooling;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.layers.PoolingType;
public class KerasPoolingUtils {
/**
* Map Keras pooling layers to DL4J pooling types.
*
* @param className name of the Keras pooling class
* @return DL4J pooling type
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static PoolingType mapPoolingType(String className, KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException {
PoolingType poolingType;
if (className.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_2D()) ||
className.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_3D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D())) {
poolingType = PoolingType.MAX;
} else if (className.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_2D()) ||
className.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_3D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D())) {
poolingType = PoolingType.AVG;
} else {
throw new UnsupportedKerasConfigurationException("Unsupported Keras pooling layer " + className);
}
return poolingType;
}
/**
* Map Keras pooling layers to DL4J pooling dimensions.
*
* @param className name of the Keras pooling class
* @param dimOrder the dimension order to determine which pooling dimensions to use
* @return pooling dimensions as int array
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static long[] mapGlobalPoolingDimensionsLong(String className, KerasLayerConfiguration conf, KerasLayer.DimOrder dimOrder)
throws UnsupportedKerasConfigurationException {
long[] dimensions = null;
if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new long[]{1};
break;
case THEANO:
dimensions = new long[]{2};
break;
}
} else if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new long[]{1,2};
break;
case THEANO:
dimensions = new long[]{2, 3};
break;
}
} else if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_3D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_3D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new long[]{1,2,3};
break;
case THEANO:
dimensions = new long[]{2, 3, 4};
break;
}
} else {
throw new UnsupportedKerasConfigurationException("Unsupported Keras pooling layer " + className);
}
return dimensions;
}
/**
* Map Keras pooling layers to DL4J pooling dimensions.
*
* @param className name of the Keras pooling class
* @param dimOrder the dimension order to determine which pooling dimensions to use
* @return pooling dimensions as int array
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static int[] mapGlobalPoolingDimensions(String className, KerasLayerConfiguration conf, KerasLayer.DimOrder dimOrder)
throws UnsupportedKerasConfigurationException {
int[] dimensions = null;
if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new int[]{1};
break;
case THEANO:
dimensions = new int[]{2};
break;
}
} else if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new int[]{1,2};
break;
case THEANO:
dimensions = new int[]{2, 3};
break;
}
} else if (className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_3D()) ||
className.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_3D())) {
switch(dimOrder) {
case NONE:
case TENSORFLOW:
default:
dimensions = new int[]{1,2,3};
break;
case THEANO:
dimensions = new int[]{2, 3, 4};
break;
}
} else {
throw new UnsupportedKerasConfigurationException("Unsupported Keras pooling layer " + className);
}
return dimensions;
}
}
@@ -0,0 +1,529 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.recurrent;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.*;
import org.deeplearning4j.nn.conf.layers.recurrent.LastTimeStep;
import org.deeplearning4j.nn.conf.layers.util.MaskZeroLayer;
import org.deeplearning4j.nn.conf.layers.wrapper.BaseWrapperLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.LSTMParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.deeplearning4j.util.TimeSeriesUtils;
import org.nd4j.linalg.activations.IActivation;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.indexing.INDArrayIndex;
import org.nd4j.linalg.indexing.NDArrayIndex;
import org.nd4j.common.primitives.Pair;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils.getWeightInitFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getHasBiasFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getNOutFromConfig;
/**
* Imports a Keras LSTM layer as a DL4J LSTM layer.
*
* @author dave@skymind.io, Max Pumperla
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasLSTM extends KerasLayer {
private final String LSTM_FORGET_BIAS_INIT_ZERO = "zero";
private final String LSTM_FORGET_BIAS_INIT_ONE = "one";
private final int NUM_TRAINABLE_PARAMS_KERAS_2 = 3;
private final int NUM_TRAINABLE_PARAMS = 12;
private final String KERAS_PARAM_NAME_W_C = "W_c";
private final String KERAS_PARAM_NAME_W_F = "W_f";
private final String KERAS_PARAM_NAME_W_I = "W_i";
private final String KERAS_PARAM_NAME_W_O = "W_o";
private final String KERAS_PARAM_NAME_U_C = "U_c";
private final String KERAS_PARAM_NAME_U_F = "U_f";
private final String KERAS_PARAM_NAME_U_I = "U_i";
private final String KERAS_PARAM_NAME_U_O = "U_o";
private final String KERAS_PARAM_NAME_B_C = "b_c";
private final String KERAS_PARAM_NAME_B_F = "b_f";
private final String KERAS_PARAM_NAME_B_I = "b_i";
private final String KERAS_PARAM_NAME_B_O = "b_o";
private final int NUM_WEIGHTS_IN_KERAS_LSTM = 12;
protected boolean unroll = false;
protected boolean returnSequences;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLSTM(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLSTM(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @param enforceTrainingConfig whether to load Keras training configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLSTM(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, enforceTrainingConfig, Collections.<String, KerasLayer>emptyMap());
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @param previousLayers dictionary containing the previous layers in the topology
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLSTM(Map<String, Object> layerConfig, Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, previousLayers);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @param previousLayers - dictionary containing the previous layers in the topology
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasLSTM(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
IWeightInit init = getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
IWeightInit recurrentInit = getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INNER_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
boolean hasBias = getHasBiasFromConfig(layerConfig, conf);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
this.returnSequences = (Boolean) innerConfig.get(conf.getLAYER_FIELD_RETURN_SEQUENCES());
// TODO: support recurrent dropout
// double recurrentDropout = KerasRnnUtils.getRecurrentDropout(conf, layerConfig);
this.unroll = KerasRnnUtils.getUnrollRecurrentLayer(conf, layerConfig);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint recurrentConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_RECURRENT_CONSTRAINT(), conf, kerasMajorVersion);
Pair<Boolean, Double> maskingConfig = KerasLayerUtils.getMaskingConfiguration(inboundLayerNames, previousLayers);
LSTM.Builder builder = new LSTM.Builder()
.gateActivationFunction(getGateActivationFromConfig(layerConfig))
.forgetGateBiasInit(getForgetBiasInitFromConfig(layerConfig, enforceTrainingConfig))
.name(this.layerName)
.nOut(getNOutFromConfig(layerConfig, conf))
.dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.weightInitRecurrent(recurrentInit)
.biasInit(0.0) // TODO: this is incorrect
.l1(this.weightL1Regularization)
.l2(this.weightL2Regularization).dataFormat(RNNFormat.NWC);
Integer nIn = KerasLayerUtils.getNInFromInputDim(layerConfig, conf);
if(nIn != null)
builder.setNIn(nIn);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainInputWeights(weightConstraint);
if (recurrentConstraint != null)
builder.constrainRecurrent(recurrentConstraint);
this.layer = builder.build();
if (!returnSequences) {
this.layer = new LastTimeStep(this.layer);
}
if (maskingConfig.getFirst()) {
this.layer = new MaskZeroLayer(this.layer, maskingConfig.getSecond());
}
}
/**
* Get DL4J Layer. If returnSequences is true, this can be casted to an "LSTM" layer, otherwise it can be casted
* to a "LastTimeStep" layer.
*
* @return LSTM Layer
*/
public Layer getLSTMLayer() {
return layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1 && inputType.length != 3)
throw new InvalidKerasConfigurationException("Keras LSTM layer accepts only one single input" +
"or three (input to LSTM and two states tensors, but " +
"received " + inputType.length + ".");
InputPreProcessor preProcessor = getInputPreprocessor(inputType);
if (preProcessor != null) {
if (returnSequences) {
return preProcessor.getOutputType(inputType[0]);
} else {
return this.getLSTMLayer().getOutputType(-1, preProcessor.getOutputType(inputType[0]));
}
} else
return this.getLSTMLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (12)
*/
@Override
public int getNumParams() {
return kerasMajorVersion == 2 ? NUM_TRAINABLE_PARAMS_KERAS_2 : NUM_TRAINABLE_PARAMS;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1 && inputType.length != 3)
throw new InvalidKerasConfigurationException("Keras LSTM layer accepts only one single input" +
"or three (input to LSTM and two states tensors, but " +
"received " + inputType.length + ".");
RNNFormat f = TimeSeriesUtils.getFormatFromRnnLayer(layer);
return InputTypeUtil.getPreprocessorForInputTypeRnnLayers(inputType[0], f,layerName);
}
/**
* Set weights for layer.
*
* @param weights LSTM layer weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
/* Keras stores LSTM parameters in distinct arrays (e.g., the recurrent weights
* are stored in four matrices: U_c, U_f, U_i, U_o) while DL4J stores them
* concatenated into one matrix (e.g., U = [ U_c U_f U_o U_i ]). Thus we have
* to map the Keras weight matrix to its corresponding DL4J weight submatrix.
*/
INDArray W_i;
INDArray W_f;
INDArray W_c;
INDArray W_o;
INDArray U_i;
INDArray U_f;
INDArray U_c;
INDArray U_o;
INDArray b_i;
INDArray b_f;
INDArray b_c;
INDArray b_o;
if (kerasMajorVersion == 2) {
INDArray W;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W()))
W = weights.get(conf.getKERAS_PARAM_NAME_W());
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_W());
INDArray U;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_RW()))
U = weights.get(conf.getKERAS_PARAM_NAME_RW());
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_RW());
INDArray b;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
b = weights.get(conf.getKERAS_PARAM_NAME_B());
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_B());
val sliceInterval = b.length() / 4;
W_i = W.get(NDArrayIndex.all(), NDArrayIndex.interval(0, sliceInterval));
W_f = W.get(NDArrayIndex.all(), NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
W_c = W.get(NDArrayIndex.all(), NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
W_o = W.get(NDArrayIndex.all(), NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
U_i = U.get(NDArrayIndex.all(), NDArrayIndex.interval(0, sliceInterval));
U_f = U.get(NDArrayIndex.all(), NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
U_c = U.get(NDArrayIndex.all(), NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
U_o = U.get(NDArrayIndex.all(), NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
b_i = b.get(NDArrayIndex.interval(0, sliceInterval));
b_f = b.get(NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
b_c = b.get(NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
b_o = b.get(NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
} else {
if (weights.containsKey(KERAS_PARAM_NAME_W_C))
W_c = weights.get(KERAS_PARAM_NAME_W_C);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_C);
if (weights.containsKey(KERAS_PARAM_NAME_W_F))
W_f = weights.get(KERAS_PARAM_NAME_W_F);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_F);
if (weights.containsKey(KERAS_PARAM_NAME_W_O))
W_o = weights.get(KERAS_PARAM_NAME_W_O);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_O);
if (weights.containsKey(KERAS_PARAM_NAME_W_I))
W_i = weights.get(KERAS_PARAM_NAME_W_I);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_I);
if (weights.containsKey(KERAS_PARAM_NAME_U_C))
U_c = weights.get(KERAS_PARAM_NAME_U_C);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_C);
if (weights.containsKey(KERAS_PARAM_NAME_U_F))
U_f = weights.get(KERAS_PARAM_NAME_U_F);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_F);
if (weights.containsKey(KERAS_PARAM_NAME_U_O))
U_o = weights.get(KERAS_PARAM_NAME_U_O);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_O);
if (weights.containsKey(KERAS_PARAM_NAME_U_I))
U_i = weights.get(KERAS_PARAM_NAME_U_I);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_I);
if (weights.containsKey(KERAS_PARAM_NAME_B_C))
b_c = weights.get(KERAS_PARAM_NAME_B_C);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_C);
if (weights.containsKey(KERAS_PARAM_NAME_B_F))
b_f = weights.get(KERAS_PARAM_NAME_B_F);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_F);
if (weights.containsKey(KERAS_PARAM_NAME_B_O))
b_o = weights.get(KERAS_PARAM_NAME_B_O);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_O);
if (weights.containsKey(KERAS_PARAM_NAME_B_I))
b_i = weights.get(KERAS_PARAM_NAME_B_I);
else
throw new InvalidKerasConfigurationException(
"Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_I);
}
// Need to convert from IFCO to CFOI order
int wCols = W_c.columns();
int wRows = W_c.rows();
INDArray W = Nd4j.zeros(wRows, 4 * wCols);
W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(0, wCols)}, W_c);
W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(wCols, 2 * wCols)}, W_f);
W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(2 * wCols, 3 * wCols)}, W_o);
W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(3 * wCols, 4 * wCols)}, W_i);
this.weights.put(LSTMParamInitializer.INPUT_WEIGHT_KEY, W);
int uCols = U_c.columns();
int uRows = U_c.rows();
INDArray U = Nd4j.zeros(uRows, 4 * uCols);
U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(0, uCols)}, U_c);
U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(uCols, 2 * uCols)}, U_f);
U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(2 * uCols, 3 * uCols)}, U_o);
U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(3 * uCols, 4 * uCols)}, U_i);
this.weights.put(LSTMParamInitializer.RECURRENT_WEIGHT_KEY, U);
int bCols = b_c.columns();
int bRows = b_c.rows();
INDArray b = Nd4j.zeros(bRows, 4 * bCols);
b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(0, bCols)}, b_c);
b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(bCols, 2 * bCols)}, b_f);
b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(2 * bCols, 3 * bCols)}, b_o);
b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(3 * bCols, 4 * bCols)}, b_i);
this.weights.put(LSTMParamInitializer.BIAS_KEY, b);
if (weights.size() > NUM_WEIGHTS_IN_KERAS_LSTM) {
Set<String> paramNames = weights.keySet();
paramNames.remove(KERAS_PARAM_NAME_W_C);
paramNames.remove(KERAS_PARAM_NAME_W_F);
paramNames.remove(KERAS_PARAM_NAME_W_I);
paramNames.remove(KERAS_PARAM_NAME_W_O);
paramNames.remove(KERAS_PARAM_NAME_U_C);
paramNames.remove(KERAS_PARAM_NAME_U_F);
paramNames.remove(KERAS_PARAM_NAME_U_I);
paramNames.remove(KERAS_PARAM_NAME_U_O);
paramNames.remove(KERAS_PARAM_NAME_B_C);
paramNames.remove(KERAS_PARAM_NAME_B_F);
paramNames.remove(KERAS_PARAM_NAME_B_I);
paramNames.remove(KERAS_PARAM_NAME_B_O);
String unknownParamNames = paramNames.toString();
log.warn("Attemping to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
FeedForwardLayer ffl;
if(this.layer instanceof BaseWrapperLayer){
BaseWrapperLayer bwl = (BaseWrapperLayer)this.layer;
ffl = (FeedForwardLayer)bwl.getUnderlying();
} else {
ffl = (FeedForwardLayer) this.layer;
}
if(ffl.getNIn() != wRows){
//Workaround/hack for ambiguous input shapes (nIn inference) for some RNN models (using NCW format but not recorded in config)
//We can reliably infer nIn from the shape of the weights array however
ffl.setNIn(wRows);
}
}
/**
* Get whether LSTM layer should be unrolled (for truncated BPTT).
*
* @return whether to unroll the LSTM
*/
public boolean getUnroll() {
return this.unroll;
}
/**
* Get LSTM gate activation function from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return LSTM inner activation function
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public IActivation getGateActivationFromConfig(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_INNER_ACTIVATION()))
throw new InvalidKerasConfigurationException(
"Keras LSTM layer config missing " + conf.getLAYER_FIELD_INNER_ACTIVATION() + " field");
return KerasActivationUtils.mapToIActivation((String) innerConfig.get(conf.getLAYER_FIELD_INNER_ACTIVATION()), conf);
}
/**
* Get LSTM forget gate bias initialization from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return LSTM forget gate bias init
* @throws InvalidKerasConfigurationException Unsupported Keras config
*/
public double getForgetBiasInitFromConfig(Map<String, Object> layerConfig, boolean train)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
String kerasForgetBiasInit;
if (innerConfig.containsKey(conf.getLAYER_FIELD_UNIT_FORGET_BIAS())) {
kerasForgetBiasInit = LSTM_FORGET_BIAS_INIT_ONE;
} else if (!innerConfig.containsKey(conf.getLAYER_FIELD_FORGET_BIAS_INIT())) {
throw new InvalidKerasConfigurationException(
"Keras LSTM layer config missing " + conf.getLAYER_FIELD_FORGET_BIAS_INIT() + " field");
} else {
kerasForgetBiasInit = (String) innerConfig.get(conf.getLAYER_FIELD_FORGET_BIAS_INIT());
}
double init;
switch (kerasForgetBiasInit) {
case LSTM_FORGET_BIAS_INIT_ZERO:
init = 0.0;
break;
case LSTM_FORGET_BIAS_INIT_ONE:
init = 1.0;
break;
default:
if (train)
throw new UnsupportedKerasConfigurationException(
"Unsupported LSTM forget gate bias initialization: " + kerasForgetBiasInit);
else {
init = 1.0;
log.warn("Unsupported LSTM forget gate bias initialization: " + kerasForgetBiasInit
+ " (using 1 instead)");
}
break;
}
return init;
}
}
@@ -0,0 +1,93 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.recurrent;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.attention.KerasAttentionLayer;
import org.deeplearning4j.nn.modelimport.keras.layers.embeddings.KerasEmbedding;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.layers.wrappers.KerasBidirectional;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import java.util.Map;
public class KerasRnnUtils {
/**
* Returns true if the given layer is an
* {@link KerasLSTM}, {@link KerasSimpleRnn},
* {@link KerasBidirectional}
* @param kerasLayer the input layer
* @return
*/
public static boolean isRnnLayer(KerasLayer kerasLayer) {
return kerasLayer instanceof KerasLSTM ||
kerasLayer instanceof KerasSimpleRnn ||
kerasLayer instanceof KerasBidirectional ||
kerasLayer instanceof KerasEmbedding ||
kerasLayer instanceof KerasAttentionLayer;
}
/**
* Get unroll parameter to decide whether to unroll RNN with BPTT or not.
*
* @param conf KerasLayerConfiguration
* @param layerConfig dictionary containing Keras layer properties
* @return boolean unroll parameter
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static boolean getUnrollRecurrentLayer(KerasLayerConfiguration conf, Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_UNROLL()))
throw new InvalidKerasConfigurationException(
"Keras LSTM layer config missing " + conf.getLAYER_FIELD_UNROLL() + " field");
return (boolean) innerConfig.get(conf.getLAYER_FIELD_UNROLL());
}
/**
* Get recurrent weight dropout from Keras layer configuration.
* Non-zero dropout rates are currently not supported.
*
* @param conf KerasLayerConfiguration
* @param layerConfig dictionary containing Keras layer properties
* @return recurrent dropout rate
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static double getRecurrentDropout(KerasLayerConfiguration conf, Map<String, Object> layerConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
double dropout = 1.0;
if (innerConfig.containsKey(conf.getLAYER_FIELD_DROPOUT_U()))
try {
dropout = 1.0 - (double) innerConfig.get(conf.getLAYER_FIELD_DROPOUT_U());
} catch (Exception e) {
int kerasDropout = (int) innerConfig.get(conf.getLAYER_FIELD_DROPOUT_U());
dropout = 1.0 - (double) kerasDropout;
}
if (dropout < 1.0)
throw new UnsupportedKerasConfigurationException(
"Dropout > 0 on recurrent connections not supported.");
return dropout;
}
}
@@ -0,0 +1,315 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.recurrent;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasActivationUtils;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.RNNFormat;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.FeedForwardLayer;
import org.deeplearning4j.nn.conf.layers.InputTypeUtil;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.layers.recurrent.LastTimeStep;
import org.deeplearning4j.nn.conf.layers.recurrent.SimpleRnn;
import org.deeplearning4j.nn.conf.layers.util.MaskZeroLayer;
import org.deeplearning4j.nn.conf.layers.wrapper.BaseWrapperLayer;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasConstraintUtils;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.deeplearning4j.nn.params.SimpleRnnParamInitializer;
import org.deeplearning4j.nn.weights.IWeightInit;
import org.deeplearning4j.util.TimeSeriesUtils;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.common.primitives.Pair;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasInitilizationUtils.getWeightInitFromConfig;
import static org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getNOutFromConfig;
/**
* Imports a Keras SimpleRNN layer as a DL4J SimpleRnn layer.
*
* @author Max Pumperla
*/
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
public class KerasSimpleRnn extends KerasLayer {
private final int NUM_TRAINABLE_PARAMS = 3;
protected boolean unroll = false;
protected boolean returnSequences;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSimpleRnn(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSimpleRnn(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, Collections.<String, KerasLayer>emptyMap());
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @param previousLayers dictionary containing the previous layers in the topology
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSimpleRnn(Map<String, Object> layerConfig, Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, previousLayers);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration.
* @param enforceTrainingConfig whether to load Keras training configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSimpleRnn(Map<String, Object> layerConfig, boolean enforceTrainingConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, enforceTrainingConfig, Collections.<String, KerasLayer>emptyMap());
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @param previousLayers dictionary containing the previous layers in the topology
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasSimpleRnn(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
IWeightInit init = getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
IWeightInit recurrentInit = getWeightInitFromConfig(layerConfig, conf.getLAYER_FIELD_INNER_INIT(),
enforceTrainingConfig, conf, kerasMajorVersion);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
this.returnSequences = (Boolean) innerConfig.get(conf.getLAYER_FIELD_RETURN_SEQUENCES());
this.dropout = KerasRnnUtils.getRecurrentDropout(conf, layerConfig);
this.unroll = KerasRnnUtils.getUnrollRecurrentLayer(conf, layerConfig);
Pair<Boolean, Double> maskingConfig = KerasLayerUtils.getMaskingConfiguration(inboundLayerNames, previousLayers);
LayerConstraint biasConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_B_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint weightConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_W_CONSTRAINT(), conf, kerasMajorVersion);
LayerConstraint recurrentConstraint = KerasConstraintUtils.getConstraintsFromConfig(
layerConfig, conf.getLAYER_FIELD_RECURRENT_CONSTRAINT(), conf, kerasMajorVersion);
boolean useBias = KerasLayerUtils.getHasBiasFromConfig(layerConfig, conf);
SimpleRnn.Builder builder = new SimpleRnn.Builder()
.name(this.layerName)
.nOut(getNOutFromConfig(layerConfig, conf))
.dropOut(this.dropout)
.activation(KerasActivationUtils.getIActivationFromConfig(layerConfig, conf))
.weightInit(init)
.weightInitRecurrent(recurrentInit)
.biasInit(0.0)
.l1(this.weightL1Regularization)
.l2(this.weightL2Regularization).dataFormat(RNNFormat.NWC);
builder.setUseBias(useBias);
Integer nIn = KerasLayerUtils.getNInFromInputDim(layerConfig, conf);
builder.setRnnDataFormat(RNNFormat.NWC);
if(nIn != null)
builder.setNIn(nIn);
if (biasConstraint != null)
builder.constrainBias(biasConstraint);
if (weightConstraint != null)
builder.constrainInputWeights(weightConstraint);
if (recurrentConstraint != null)
builder.constrainRecurrent(recurrentConstraint);
this.layer = builder.build();
if (!returnSequences) {
this.layer = new LastTimeStep(this.layer);
}
if (maskingConfig.getFirst()) {
this.layer = new MaskZeroLayer(this.layer, maskingConfig.getSecond());
}
}
/**
* Get DL4J SimpleRnn layer.
*
* @return SimpleRnn Layer
*/
public Layer getSimpleRnnLayer() {
return this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras SimpleRnn layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preProcessor = getInputPreprocessor(inputType);
if (preProcessor != null)
return preProcessor.getOutputType(inputType[0]);
else
return this.getSimpleRnnLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters (12)
*/
@Override
public int getNumParams() {
return NUM_TRAINABLE_PARAMS;
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras SimpleRnn layer accepts only one input (received " + inputType.length + ")");
RNNFormat f = TimeSeriesUtils.getFormatFromRnnLayer(layer);
return InputTypeUtil.getPreprocessorForInputTypeRnnLayers(inputType[0], f, layerName);
}
/**
* Get whether SimpleRnn layer should be unrolled (for truncated BPTT).
*
* @return whether RNN should be unrolled (boolean)
*/
public boolean getUnroll() {
return this.unroll;
}
/**
* Set weights for layer.
*
* @param weights Simple RNN weights
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
this.weights = new HashMap<>();
INDArray W;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_W()))
W = weights.get(conf.getKERAS_PARAM_NAME_W());
else
throw new InvalidKerasConfigurationException(
"Keras SimpleRNN layer does not contain parameter " + conf.getKERAS_PARAM_NAME_W());
this.weights.put(SimpleRnnParamInitializer.WEIGHT_KEY, W);
INDArray RW;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_RW()))
RW = weights.get(conf.getKERAS_PARAM_NAME_RW());
else
throw new InvalidKerasConfigurationException(
"Keras SimpleRNN layer does not contain parameter " + conf.getKERAS_PARAM_NAME_RW());
this.weights.put(SimpleRnnParamInitializer.RECURRENT_WEIGHT_KEY, RW);
INDArray b;
if (weights.containsKey(conf.getKERAS_PARAM_NAME_B())) {
b = weights.get(conf.getKERAS_PARAM_NAME_B());
this.weights.put(SimpleRnnParamInitializer.BIAS_KEY, b);
}
if (weights.size() > NUM_TRAINABLE_PARAMS) {
Set<String> paramNames = weights.keySet();
paramNames.remove(conf.getKERAS_PARAM_NAME_B());
paramNames.remove(conf.getKERAS_PARAM_NAME_W());
paramNames.remove(conf.getKERAS_PARAM_NAME_RW());
String unknownParamNames = paramNames.toString();
log.warn("Attemping to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
FeedForwardLayer ffl;
if(this.layer instanceof BaseWrapperLayer) {
BaseWrapperLayer bwl = (BaseWrapperLayer)this.layer;
ffl = (FeedForwardLayer)bwl.getUnderlying();
} else {
ffl = (FeedForwardLayer) this.layer;
}
if(ffl.getNIn() != W.rows()) {
//Workaround/hack for ambiguous input shapes (nIn inference) for some RNN models (using NCW format but not recorded in config)
//We can reliably infer nIn from the shape of the weights array however
ffl.setNIn(W.rows());
}
}
}
@@ -0,0 +1,279 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.layers.wrappers;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasLSTM;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasSimpleRnn;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.InputTypeUtil;
import org.deeplearning4j.nn.conf.layers.LSTM;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.layers.recurrent.Bidirectional;
import org.deeplearning4j.nn.conf.layers.recurrent.LastTimeStep;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils;
import org.nd4j.linalg.api.ndarray.INDArray;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class KerasBidirectional extends KerasLayer {
private KerasLayer kerasRnnlayer;
/**
* Pass-through constructor from KerasLayer
*
* @param kerasVersion major keras version
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBidirectional(Integer kerasVersion) throws UnsupportedKerasConfigurationException {
super(kerasVersion);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBidirectional(Map<String, Object> layerConfig)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, Collections.<String, KerasLayer>emptyMap());
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBidirectional(Map<String, Object> layerConfig, Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
this(layerConfig, true, previousLayers);
}
/**
* Constructor from parsed Keras layer configuration dictionary.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce training-related configuration options
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public KerasBidirectional(Map<String, Object> layerConfig, boolean enforceTrainingConfig,
Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
super(layerConfig, enforceTrainingConfig);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey("merge_mode")) {
throw new InvalidKerasConfigurationException("Field 'merge_mode' not found in configuration of " +
"Bidirectional layer.");
}
if (!innerConfig.containsKey("layer")) {
throw new InvalidKerasConfigurationException("Field 'layer' not found in configuration of" +
"Bidirectional layer, i.e. no layer to be wrapped found.");
}
@SuppressWarnings("unchecked")
Map<String, Object> innerRnnConfig = (Map<String, Object>) innerConfig.get("layer");
if (!innerRnnConfig.containsKey("class_name")) {
throw new InvalidKerasConfigurationException("No 'class_name' specified within Bidirectional layer" +
"configuration.");
}
Bidirectional.Mode mode;
String mergeModeString = (String) innerConfig.get("merge_mode");
switch (mergeModeString) {
case "sum":
mode = Bidirectional.Mode.ADD;
break;
case "concat":
mode = Bidirectional.Mode.CONCAT;
break;
case "mul":
mode = Bidirectional.Mode.MUL;
break;
case "ave":
mode = Bidirectional.Mode.AVERAGE;
break;
default:
// Note that this is only for "None" mode, which we currently can't do.
throw new UnsupportedKerasConfigurationException("Merge mode " + mergeModeString + " not supported.");
}
innerRnnConfig.put(conf.getLAYER_FIELD_KERAS_VERSION(), kerasMajorVersion);
String rnnClass = (String) innerRnnConfig.get("class_name");
switch (rnnClass) {
case "LSTM":
kerasRnnlayer = new KerasLSTM(innerRnnConfig, enforceTrainingConfig, previousLayers);
try {
LSTM rnnLayer = (LSTM) ((KerasLSTM) kerasRnnlayer).getLSTMLayer();
layer = new Bidirectional(mode, rnnLayer);
layer.setLayerName(layerName);
} catch (Exception e) {
LastTimeStep rnnLayer = (LastTimeStep) ((KerasLSTM) kerasRnnlayer).getLSTMLayer();
this.layer = new Bidirectional(mode, rnnLayer);
layer.setLayerName(layerName);
}
break;
case "SimpleRNN":
kerasRnnlayer = new KerasSimpleRnn(innerRnnConfig, enforceTrainingConfig, previousLayers);
Layer rnnLayer = ((KerasSimpleRnn) kerasRnnlayer).getSimpleRnnLayer();
this.layer = new Bidirectional(mode, rnnLayer);
layer.setLayerName(layerName);
break;
default:
throw new UnsupportedKerasConfigurationException("Currently only two types of recurrent Keras layers are" +
"supported, 'LSTM' and 'SimpleRNN'. You tried to load a layer of class:" + rnnClass);
}
}
/**
* Return the underlying recurrent layer of this bidirectional layer
*
* @return Layer, recurrent layer
*/
public Layer getUnderlyingRecurrentLayer() {
return kerasRnnlayer.getLayer();
}
/**
* Get DL4J Bidirectional layer.
*
* @return Bidirectional Layer
*/
public Bidirectional getBidirectionalLayer() {
return (Bidirectional) this.layer;
}
/**
* Get layer output type.
*
* @param inputType Array of InputTypes
* @return output type as InputType
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
@Override
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Bidirectional layer accepts only one input (received " + inputType.length + ")");
InputPreProcessor preProcessor = getInputPreprocessor(inputType);
if (preProcessor != null)
return this.getBidirectionalLayer().getOutputType(-1, preProcessor.getOutputType(inputType[0]));
else
return this.getBidirectionalLayer().getOutputType(-1, inputType[0]);
}
/**
* Returns number of trainable parameters in layer.
*
* @return number of trainable parameters
*/
@Override
public int getNumParams() {
return 2 * kerasRnnlayer.getNumParams();
}
/**
* Gets appropriate DL4J InputPreProcessor for given InputTypes.
*
* @param inputType Array of InputTypes
* @return DL4J InputPreProcessor
* @throws InvalidKerasConfigurationException Invalid Keras configuration exception
* @see org.deeplearning4j.nn.conf.InputPreProcessor
*/
@Override
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
if (inputType.length > 1)
throw new InvalidKerasConfigurationException(
"Keras Bidirectional layer accepts only one input (received " + inputType.length + ")");
return InputTypeUtil.getPreprocessorForInputTypeRnnLayers(inputType[0], ((Bidirectional)layer).getRNNDataFormat(), layerName);
}
/**
* Set weights for Bidirectional layer.
*
* @param weights Map of weights
*/
@Override
public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
Map<String, INDArray> forwardWeights = getUnderlyingWeights(((Bidirectional)this.layer).getFwd(), weights, "forward");
Map<String, INDArray> backwardWeights = getUnderlyingWeights(((Bidirectional)this.layer).getBwd(), weights, "backward");
this.weights = new HashMap<>();
for (String key : forwardWeights.keySet())
this.weights.put("f" + key, forwardWeights.get(key));
for (String key : backwardWeights.keySet())
this.weights.put("b" + key, backwardWeights.get(key));
}
private Map<String, INDArray> getUnderlyingWeights(Layer l, Map<String, INDArray> weights, String direction)
throws InvalidKerasConfigurationException {
int keras1SubstringLength;
if (kerasRnnlayer instanceof KerasLSTM)
keras1SubstringLength = 3;
else if (kerasRnnlayer instanceof KerasSimpleRnn)
keras1SubstringLength = 1;
else throw new InvalidKerasConfigurationException("Unsupported layer type " + kerasRnnlayer.getClassName());
Map newWeights = new HashMap<String, INDArray>();
for (String key : weights.keySet()) {
if (key.contains(direction)) {
String newKey;
if (kerasMajorVersion == 2) {
String[] subKeys = key.split("_");
if (key.contains("recurrent"))
newKey = subKeys[subKeys.length - 2] + "_" + subKeys[subKeys.length - 1];
else
newKey = subKeys[subKeys.length - 1];
} else {
newKey = key.substring(key.length() - keras1SubstringLength);
}
newWeights.put(newKey, weights.get(key));
}
}
if (!newWeights.isEmpty()) {
weights = newWeights;
}
Layer layerBefore = kerasRnnlayer.getLayer();
kerasRnnlayer.setLayer(l);
kerasRnnlayer.setWeights(weights);
Map<String,INDArray> ret = kerasRnnlayer.getWeights();
kerasRnnlayer.setLayer(layerBefore);
return ret;
}
}
@@ -0,0 +1,168 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.preprocessing.sequence;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.Data;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelUtils;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.indexing.INDArrayIndex;
import org.nd4j.linalg.indexing.NDArrayIndex;
import org.nd4j.common.primitives.Pair;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
@Data
public class TimeSeriesGenerator {
private final static int DEFAULT_SAMPLING_RATE = 1;
private final static int DEFAULT_STRIDE = 1;
private final static Integer DEFAULT_START_INDEX = 0;
private final static Integer DEFAULT_END_INDEX = null;
private final static boolean DEFAULT_SHUFFLE = false;
private final static boolean DEFAULT_REVERSE = false;
private final static int DEFAULT_BATCH_SIZE = 128;
private INDArray data;
private INDArray targets;
private int length;
private int samplingRate;
private int stride;
private int startIndex;
private int endIndex;
private boolean shuffle;
private boolean reverse;
private int batchSize;
// TODO: add pad_sequences, make_sampling_table, skipgrams utils
public static TimeSeriesGenerator fromJson(String jsonFileName)
throws IOException, InvalidKerasConfigurationException {
String json = new String(Files.readAllBytes(Paths.get(jsonFileName)));
Map<String, Object> timeSeriesBaseConfig = KerasModelUtils.parseJsonString(json);
Map<String, Object> timeSeriesConfig;
if (timeSeriesBaseConfig.containsKey("config"))
timeSeriesConfig = (Map<String, Object>) timeSeriesBaseConfig.get("config");
else
throw new InvalidKerasConfigurationException("No configuration found for Keras tokenizer");
int length = (int) timeSeriesConfig.get("length");
int samplingRate = (int) timeSeriesConfig.get("sampling_rate");
int stride = (int) timeSeriesConfig.get("stride");
int startIndex = (int) timeSeriesConfig.get("start_index");
int endIndex = (int) timeSeriesConfig.get("end_index");
int batchSize = (int) timeSeriesConfig.get("batch_size");
boolean shuffle = (boolean) timeSeriesConfig.get("shuffle");
boolean reverse = (boolean) timeSeriesConfig.get("reverse");
Gson gson = new Gson();
List<List<Double>> dataList = gson.fromJson((String) timeSeriesConfig.get("data"), new TypeToken<List<List<Double>>>() {}.getType());
List<List<Double>> targetsList = gson.fromJson((String) timeSeriesConfig.get("targets"), new TypeToken<List<List<Double>>>() {}.getType());
int dataPoints = dataList.size();
int dataPointsPerRow = dataList.get(0).size();
INDArray data = Nd4j.create(dataPoints, dataPointsPerRow);
INDArray targets = Nd4j.create(dataPoints, dataPointsPerRow);
for (int i = 0; i < dataPoints; i ++) {
data.put(i, Nd4j.create(dataList.get(i)));
targets.put(i, Nd4j.create(targetsList.get(i)));
}
TimeSeriesGenerator gen = new TimeSeriesGenerator(data, targets, length,
samplingRate, stride, startIndex, endIndex, shuffle, reverse, batchSize);
return gen;
}
public TimeSeriesGenerator(INDArray data, INDArray targets, int length, int samplingRate, int stride,
Integer startIndex, Integer endIndex, boolean shuffle, boolean reverse,
int batchSize) throws InvalidKerasConfigurationException {
this.data = data;
this.targets = targets;
this.length = length;
this.samplingRate = samplingRate;
if (stride != 1)
throw new InvalidKerasConfigurationException("currently no strides > 1 supported, got: " + stride);
this.stride = stride;
this.startIndex = startIndex + length;
if (endIndex == null)
endIndex = data.rows() -1;
this.endIndex = endIndex;
this.shuffle = shuffle;
this.reverse = reverse;
this.batchSize = batchSize;
if (this.startIndex > this.endIndex)
throw new IllegalArgumentException("Start index of sequence has to be smaller then end index, got " +
"startIndex : " + this.startIndex + " and endIndex: " + this.endIndex);
}
public TimeSeriesGenerator(INDArray data, INDArray targets, int length) throws InvalidKerasConfigurationException {
this(data, targets, length, DEFAULT_SAMPLING_RATE, DEFAULT_STRIDE, DEFAULT_START_INDEX, DEFAULT_END_INDEX,
DEFAULT_SHUFFLE, DEFAULT_REVERSE, DEFAULT_BATCH_SIZE);
}
public int length() {
return (endIndex - startIndex + batchSize * stride) / (batchSize * stride);
}
public Pair<INDArray, INDArray> next(int index) {
INDArray rows;
if (shuffle) {
rows = Nd4j.getRandom().nextInt(endIndex, new int[] {batchSize});
rows.addi(startIndex);
} else {
int i = startIndex + batchSize + stride * index;
// TODO: add stride arg to arange
rows = Nd4j.arange(i, Math.min(i + batchSize * stride, endIndex + 1));
}
INDArray samples = Nd4j.create(rows.length(), length / samplingRate, data.columns());
INDArray targets = Nd4j.create(rows.length(), this.targets.columns());
for (int j = 0; j < rows.rows(); j++) {
long idx = (long) rows.getDouble(j);
INDArrayIndex indices = NDArrayIndex.interval(idx - this.length, this.samplingRate, idx);
INDArray slice = this.data.get(indices);
samples.putSlice(j, slice);
INDArrayIndex point = NDArrayIndex.point((long) rows.getDouble(j));
targets.putSlice(j, this.targets.get(point));
}
if (reverse)
samples = Nd4j.reverse(samples);
return new Pair<>(samples, targets);
}
}
@@ -0,0 +1,405 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.preprocessing.text;
import lombok.Data;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.utils.KerasModelUtils;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
@Data
public class KerasTokenizer {
// TODO: might want to recreate "one_hot" util for tokenizer
private static final String DEFAULT_FILTER = "!\"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n";
private static final String DEFAULT_SPLIT = " ";
private Integer numWords;
private String filters;
private boolean lower;
private String split;
private boolean charLevel;
private String outOfVocabularyToken;
private Map<String, Integer> wordCounts = new LinkedHashMap<>();
private HashMap<String, Integer> wordDocs = new HashMap<>();
private Map<String, Integer> wordIndex = new HashMap<>();
private Map<Integer, String> indexWord = new HashMap<>();
private Map<Integer, Integer> indexDocs = new HashMap<>();
private Integer documentCount;
/**
* Create a Keras Tokenizer instance with full set of properties.
*
* @param numWords The maximum vocabulary size, can be null
* @param filters Characters to filter
* @param lower whether to lowercase input or not
* @param split by which string to split words (usually single space)
* @param charLevel whether to operate on character- or word-level
* @param outOfVocabularyToken replace items outside the vocabulary by this token
*/
public KerasTokenizer(Integer numWords, String filters, boolean lower, String split, boolean charLevel,
String outOfVocabularyToken) {
this.numWords = numWords;
this.filters = filters;
this.lower = lower;
this.split = split;
this.charLevel = charLevel;
this.outOfVocabularyToken = outOfVocabularyToken;
}
/**
* Tokenizer constructor with only numWords specified
*
* @param numWords The maximum vocabulary size, can be null
*/
public KerasTokenizer(Integer numWords) {
this(numWords, DEFAULT_FILTER, true, DEFAULT_SPLIT, false, null);
}
/**
* Default Keras tokenizer constructor
*/
public KerasTokenizer() {
this(null, DEFAULT_FILTER, true, DEFAULT_SPLIT, false, null);
}
/**
* Import Keras Tokenizer from JSON file created with `tokenizer.to_json()` in Python.
*
* @param jsonFileName Full path of the JSON file to load
* @return Keras Tokenizer instance loaded from JSON
* @throws IOException I/O exception
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static KerasTokenizer fromJson(String jsonFileName) throws IOException, InvalidKerasConfigurationException {
String json = new String(Files.readAllBytes(Paths.get(jsonFileName)));
Map<String, Object> tokenizerBaseConfig = KerasModelUtils.parseJsonString(json);
Map<String, Object> tokenizerConfig;
if (tokenizerBaseConfig.containsKey("config"))
tokenizerConfig = (Map<String, Object>) tokenizerBaseConfig.get("config");
else
throw new InvalidKerasConfigurationException("No configuration found for Keras tokenizer");
Integer numWords = (Integer) tokenizerConfig.get("num_words");
String filters = (String) tokenizerConfig.get("filters");
Boolean lower = (Boolean) tokenizerConfig.get("lower");
String split = (String) tokenizerConfig.get("split");
Boolean charLevel = (Boolean) tokenizerConfig.get("char_level");
String oovToken = (String) tokenizerConfig.get("oov_token");
Integer documentCount = (Integer) tokenizerConfig.get("document_count");
@SuppressWarnings("unchecked")
Map<String, Integer> wordCounts = (Map) KerasModelUtils.parseJsonString((String) tokenizerConfig.get("word_counts"));
@SuppressWarnings("unchecked")
Map<String, Integer> wordDocs = (Map) KerasModelUtils.parseJsonString((String) tokenizerConfig.get("word_docs"));
@SuppressWarnings("unchecked")
Map<String, Integer> wordIndex = (Map) KerasModelUtils.parseJsonString((String) tokenizerConfig.get("word_index"));
@SuppressWarnings("unchecked")
Map<Integer, String> indexWord = (Map) KerasModelUtils.parseJsonString((String) tokenizerConfig.get("index_word"));
@SuppressWarnings("unchecked")
Map<Integer, Integer> indexDocs = (Map) KerasModelUtils.parseJsonString((String) tokenizerConfig.get("index_docs"));
KerasTokenizer tokenizer = new KerasTokenizer(numWords, filters, lower, split, charLevel, oovToken);
tokenizer.setDocumentCount(documentCount);
tokenizer.setWordCounts(wordCounts);
tokenizer.setWordDocs(new HashMap<>(wordDocs));
tokenizer.setWordIndex(wordIndex);
tokenizer.setIndexWord(indexWord);
tokenizer.setIndexDocs(indexDocs);
return tokenizer;
}
/**
* Turns a String text into a sequence of tokens.
*
* @param text input text
* @param filters characters to filter
* @param lower whether to lowercase input or not
* @param split by which string to split words (usually single space)
* @return Sequence of tokens as String array
*/
public static String[] textToWordSequence(String text, String filters, boolean lower, String split) {
if (lower)
text = text.toLowerCase();
for (String filter: filters.split("")) {
text = text.replace(filter, split);
}
String[] sequences = text.split(split);
List<String> seqList = new ArrayList(Arrays.asList(sequences));
seqList.removeAll(Arrays.asList("", null));
return seqList.toArray(new String[seqList.size()]);
}
/**
* Fit this tokenizer on a corpus of texts.
*
* @param texts array of strings to fit tokenizer on.
*/
public void fitOnTexts(String[] texts) {
String[] sequence;
for (String text : texts) {
if (documentCount == null)
documentCount = 1;
else
documentCount += 1;
if (charLevel) {
if (lower)
text = text.toLowerCase();
sequence = text.split("");
} else {
sequence = textToWordSequence(text, filters, lower, split);
}
for (String word : sequence) {
if (wordCounts.containsKey(word))
wordCounts.put(word, wordCounts.get(word) + 1);
else
wordCounts.put(word, 1);
}
Set<String> sequenceSet = new HashSet<>(Arrays.asList(sequence));
for (String word: sequenceSet) {
if (wordDocs.containsKey(word))
wordDocs.put(word, wordDocs.get(word) + 1);
else
wordDocs.put(word, 1);
}
}
Map<String, Integer> sortedWordCounts = reverseSortByValues((HashMap) wordCounts);
ArrayList<String> sortedVocabulary = new ArrayList<>();
if (outOfVocabularyToken != null)
sortedVocabulary.add(outOfVocabularyToken);
for (String word: sortedWordCounts.keySet()) {
sortedVocabulary.add(word);
}
for (int i = 0; i < sortedVocabulary.size(); i++)
wordIndex.put(sortedVocabulary.get(i), i+1);
for(String key : wordIndex.keySet()){
indexWord.put(wordIndex.get(key), key);
}
for (String key: wordDocs.keySet())
indexDocs.put(wordIndex.get(key), wordDocs.get(key));
}
/**
* Sort HashMap by values in reverse order
*
* @param map input HashMap
* @return sorted HashMap
*/
private static HashMap reverseSortByValues(HashMap map) {
List list = new LinkedList(map.entrySet());
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getValue())
.compareTo(((Map.Entry) (o2)).getValue());
}
});
HashMap sortedHashMap = new LinkedHashMap();
for (Iterator it = list.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
sortedHashMap.put(entry.getKey(), entry.getValue());
}
return sortedHashMap;
}
/**
* Fit this tokenizer on a corpus of word indices
*
* @param sequences array of indices derived from a text.
*/
public void fitOnSequences(Integer[][] sequences) {
documentCount += 1;
for (Integer[] sequence: sequences) {
Set<Integer> sequenceSet = new HashSet<>(Arrays.asList(sequence));
for (Integer index: sequenceSet)
indexDocs.put(index, indexDocs.get(index) + 1);
}
}
/**
* Transforms a bunch of texts into their index representations.
*
* @param texts input texts
* @return array of indices of the texts
*/
public Integer[][] textsToSequences(String[] texts) {
Integer oovTokenIndex = wordIndex.get(outOfVocabularyToken);
String[] wordSequence;
ArrayList<Integer[]> sequences = new ArrayList<>();
for (String text: texts) {
if (charLevel) {
if (lower) {
text = text.toLowerCase();
}
wordSequence = text.split("");
} else {
wordSequence = textToWordSequence(text, filters, lower, split);
}
ArrayList<Integer> indexVector = new ArrayList<>();
for (String word: wordSequence) {
if (wordIndex.containsKey(word)) {
int index = wordIndex.get(word);
if (numWords != null && index >= numWords) {
if (oovTokenIndex != null)
indexVector.add(oovTokenIndex);
} else {
indexVector.add(index);
}
} else if (oovTokenIndex != null) {
indexVector.add(oovTokenIndex);
}
}
Integer[] indices = indexVector.toArray(new Integer[indexVector.size()]);
sequences.add(indices);
}
return sequences.toArray(new Integer[sequences.size()][]);
}
/**
* Turns index sequences back into texts
*
* @param sequences index sequences
* @return text reconstructed from sequences
*/
public String[] sequencesToTexts(Integer[][] sequences) {
Integer oovTokenIndex = wordIndex.get(outOfVocabularyToken);
ArrayList<String> texts = new ArrayList<>();
for (Integer[] sequence: sequences) {
ArrayList<String> wordVector = new ArrayList<>();
for (Integer index: sequence) {
if (indexWord.containsKey(index)) {
String word = indexWord.get(index);
if (numWords != null && index >= numWords) {
if (oovTokenIndex != null) {
wordVector.add(indexWord.get(oovTokenIndex));
} else {
wordVector.add(word);
}
}
} else if (oovTokenIndex != null) {
wordVector.add(indexWord.get(oovTokenIndex));
}
}
StringBuilder builder = new StringBuilder();
for (String word: wordVector) {
builder.append(word + split);
}
String text = builder.toString();
texts.add(text);
}
return texts.toArray(new String[texts.size()]);
}
/**
* Turns an array of texts into an ND4J matrix of shape
* (number of texts, number of words in vocabulary)
*
* @param texts input texts
* @param mode TokenizerMode that controls how to vectorize data
* @return resulting matrix representation
*/
public INDArray textsToMatrix(String[] texts, TokenizerMode mode) {
Integer[][] sequences = textsToSequences(texts);
return sequencesToMatrix(sequences, mode);
}
/**
* Turns an array of index sequences into an ND4J matrix of shape
* (number of texts, number of words in vocabulary)
*
* @param sequences input sequences
* @param mode TokenizerMode that controls how to vectorize data
* @return resulting matrix representatio
*/
public INDArray sequencesToMatrix(Integer[][] sequences, TokenizerMode mode) {
if (numWords == null) {
if (!wordIndex.isEmpty()) {
numWords = wordIndex.size();
} else {
throw new IllegalArgumentException("Either specify numWords argument" +
"or fit Tokenizer on data first, i.e. by using fitOnTexts");
}
}
if (mode.equals(TokenizerMode.TFIDF) && documentCount == null) {
throw new IllegalArgumentException("To use TFIDF mode you need to" +
"fit the Tokenizer instance with fitOnTexts first.");
}
INDArray x = Nd4j.zeros(sequences.length, numWords);
for (int i=0; i< sequences.length; i++) {
Integer[] sequence = sequences[i];
if (sequence == null)
continue;
HashMap<Integer, Integer> counts = new HashMap<>();
for (int j: sequence) {
if (j >= numWords)
continue;
if (counts.containsKey(j))
counts.put(j, counts.get(j) + 1);
else
counts.put(j, 1);
}
for (int j: counts.keySet()) {
int count = counts.get(j);
switch (mode) {
case COUNT:
x.put(i, j, count);
break;
case FREQ:
x.put(i, j, count / sequence.length);
break;
case BINARY:
x.put(i, j, 1);
break;
case TFIDF:
double tf = 1.0 + Math.log(count);
int index = indexDocs.containsKey(j) ? indexDocs.get(j) : 0;
double idf = Math.log(1 + documentCount / (1.0 + index));
x.put(i, j, tf * idf);
break;
}
}
}
return x;
}
}
@@ -0,0 +1,25 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.preprocessing.text;
public enum TokenizerMode {
BINARY, COUNT, TFIDF, FREQ
}
@@ -0,0 +1,83 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.preprocessors;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.deeplearning4j.nn.conf.preprocessor.CnnToFeedForwardPreProcessor;
import org.deeplearning4j.nn.workspace.ArrayType;
import org.deeplearning4j.nn.workspace.LayerWorkspaceMgr;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.api.shape.Shape;
import org.nd4j.shade.jackson.annotation.JsonCreator;
import org.nd4j.shade.jackson.annotation.JsonProperty;
@Slf4j @Deprecated
public class TensorFlowCnnToFeedForwardPreProcessor extends CnnToFeedForwardPreProcessor {
@JsonCreator @Deprecated
public TensorFlowCnnToFeedForwardPreProcessor(@JsonProperty("inputHeight") long inputHeight,
@JsonProperty("inputWidth") long inputWidth,
@JsonProperty("numChannels") long numChannels) {
super(inputHeight, inputWidth, numChannels);
}
@Deprecated
public TensorFlowCnnToFeedForwardPreProcessor(long inputHeight, long inputWidth) {
super(inputHeight, inputWidth);
}
@Deprecated
public TensorFlowCnnToFeedForwardPreProcessor() {
super();
}
@Override
public INDArray preProcess(INDArray input, int miniBatchSize, LayerWorkspaceMgr workspaceMgr) {
if (input.rank() == 2)
return workspaceMgr.leverageTo(ArrayType.ACTIVATIONS, input); //Should usually never happen
/* DL4J convolutional input: # channels, # rows, # cols
* TensorFlow convolutional input: # rows, # cols, # channels
* Theano convolutional input: # channels, # rows, # cols
*/
INDArray permuted = workspaceMgr.dup(ArrayType.ACTIVATIONS, input.permute(0, 2, 3, 1), 'c'); //To: [n, h, w, c]
val inShape = input.shape(); //[miniBatch,depthOut,outH,outW]
val outShape = new long[]{inShape[0], inShape[1] * inShape[2] * inShape[3]};
return workspaceMgr.leverageTo(ArrayType.ACTIVATIONS, permuted.reshape('c', outShape));
}
@Override
public INDArray backprop(INDArray epsilons, int miniBatchSize, LayerWorkspaceMgr workspaceMgr) {
if (epsilons.ordering() != 'c' || !Shape.hasDefaultStridesForShape(epsilons))
epsilons = workspaceMgr.dup(ArrayType.ACTIVATION_GRAD, epsilons, 'c');
INDArray epsilonsReshaped = epsilons.reshape('c', epsilons.size(0), inputHeight, inputWidth, numChannels);
return workspaceMgr.leverageTo(ArrayType.ACTIVATION_GRAD, epsilonsReshaped.permute(0, 3, 1, 2)); //To [n, c, h, w]
}
@Override
public TensorFlowCnnToFeedForwardPreProcessor clone() {
return (TensorFlowCnnToFeedForwardPreProcessor) super.clone();
}
}
@@ -0,0 +1,107 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.NonNull;
import org.deeplearning4j.nn.modelimport.keras.Hdf5Archive;
import org.deeplearning4j.nn.modelimport.keras.config.KerasModelConfiguration;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.common.validation.Nd4jCommonValidator;
import org.nd4j.common.validation.ValidationResult;
import java.io.File;
import java.util.Collections;
public class DL4JKerasModelValidator {
private DL4JKerasModelValidator(){ }
/**
* Validate whether the file represents a valid Keras Sequential model (HDF5 archive)
*
* @param f File that should represent an saved Keras Sequential model (HDF5 archive)
* @return Result of validation
*/
public static ValidationResult validateKerasSequential(@NonNull File f){
return validateKeras(f, "Keras Sequential Model HDF5", MultiLayerNetwork.class);
}
/**
* Validate whether the file represents a valid Keras Functional model (HDF5 archive)
*
* @param f File that should represent an saved Keras Functional model (HDF5 archive)
* @return Result of validation
*/
public static ValidationResult validateKerasFunctional(@NonNull File f){
return validateKeras(f, "Keras Functional Model HDF5", ComputationGraph.class);
}
protected static ValidationResult validateKeras(@NonNull File f, String format, Class<?> cl){
ValidationResult vr = Nd4jCommonValidator.isValidFile(f, format, false);
if(vr != null && !vr.isValid()) {
return vr;
}
KerasModelConfiguration c = new KerasModelConfiguration();
Hdf5Archive archive = null;
try{
archive = new Hdf5Archive(f.getPath());
//Check JSON
try{
String json = archive.readAttributeAsJson(c.getTrainingModelConfigAttribute());
vr = Nd4jCommonValidator.isValidJSON(json);
if(vr != null && !vr.isValid()){
vr.setFormatType(format);
return vr;
}
} catch (Throwable t){
return ValidationResult.builder()
.formatType(format)
.formatClass(cl)
.valid(false)
.path(Nd4jCommonValidator.getPath(f))
.issues(Collections.singletonList("Unable to read JSON configuration from Keras Sequential model HDF5 file"))
.exception(t)
.build();
}
} catch (Throwable t){
return ValidationResult.builder()
.formatType(format)
.formatClass(cl)
.valid(false)
.path(Nd4jCommonValidator.getPath(f))
.issues(Collections.singletonList("Unable to read from " + format + " file - file is corrupt or not a valid Keras HDF5 archive?"))
.exception(t)
.build();
}
return ValidationResult.builder()
.formatType(format)
.formatClass(cl)
.valid(true)
.path(Nd4jCommonValidator.getPath(f))
.build();
}
}
@@ -0,0 +1,116 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.activations.IActivation;
import java.util.Map;
public class KerasActivationUtils {
/**
* Map Keras to DL4J activation functions.
*
* @param conf Keras layer configuration
* @param kerasActivation String containing Keras activation function name
* @return Activation enum value containing DL4J activation function name
*/
public static Activation mapToActivation(String kerasActivation, KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException {
Activation dl4jActivation;
if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SOFTMAX())) {
dl4jActivation = Activation.SOFTMAX;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SOFTPLUS())) {
dl4jActivation = Activation.SOFTPLUS;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SOFTSIGN())) {
dl4jActivation = Activation.SOFTSIGN;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_RELU())) {
dl4jActivation = Activation.RELU;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_RELU6())) {
dl4jActivation = Activation.RELU6;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_ELU())) {
dl4jActivation = Activation.ELU;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SELU())) {
dl4jActivation = Activation.SELU;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_TANH())) {
dl4jActivation = Activation.TANH;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SIGMOID())) {
dl4jActivation = Activation.SIGMOID;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_HARD_SIGMOID())) {
dl4jActivation = Activation.HARDSIGMOID;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_LINEAR())) {
dl4jActivation = Activation.IDENTITY;
} else if (kerasActivation.equals(conf.getKERAS_ACTIVATION_SWISH())) {
dl4jActivation = Activation.SWISH;
} else {
throw new UnsupportedKerasConfigurationException(
"Unknown Keras activation function " + kerasActivation);
}
return dl4jActivation;
}
/**
* Map Keras to DL4J activation functions.
*
* @param kerasActivation String containing Keras activation function name
* @return DL4J activation function
*/
public static IActivation mapToIActivation(String kerasActivation, KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException {
Activation activation = mapToActivation(kerasActivation, conf);
return activation.getActivationFunction();
}
/**
* Get activation function from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return DL4J activation function
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static IActivation getIActivationFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
return getActivationFromConfig(layerConfig, conf).getActivationFunction();
}
/**
* Get activation enum value from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return DL4J activation enum value
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static Activation getActivationFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_ACTIVATION()))
throw new InvalidKerasConfigurationException("Keras layer is missing "
+ conf.getLAYER_FIELD_ACTIVATION() + " field");
return mapToActivation((String) innerConfig.get(conf.getLAYER_FIELD_ACTIVATION()), conf);
}
}
@@ -0,0 +1,121 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.api.layers.LayerConstraint;
import org.deeplearning4j.nn.conf.constraint.MaxNormConstraint;
import org.deeplearning4j.nn.conf.constraint.MinMaxNormConstraint;
import org.deeplearning4j.nn.conf.constraint.NonNegativeConstraint;
import org.deeplearning4j.nn.conf.constraint.UnitNormConstraint;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class KerasConstraintUtils {
/**
* Map Keras to DL4J constraint.
*
* @param kerasConstraint String containing Keras constraint name
* @param conf Keras layer configuration
* @return DL4J LayerConstraint
* @see LayerConstraint
*/
public static LayerConstraint mapConstraint(String kerasConstraint, KerasLayerConfiguration conf,
Map<String, Object> constraintConfig)
throws UnsupportedKerasConfigurationException {
LayerConstraint constraint;
if (kerasConstraint.equals(conf.getLAYER_FIELD_MINMAX_NORM_CONSTRAINT())
|| kerasConstraint.equals(conf.getLAYER_FIELD_MINMAX_NORM_CONSTRAINT_ALIAS())) {
double min = (double) constraintConfig.get(conf.getLAYER_FIELD_MINMAX_MIN_CONSTRAINT());
double max = (double) constraintConfig.get(conf.getLAYER_FIELD_MINMAX_MAX_CONSTRAINT());
double rate = (double) constraintConfig.get(conf.getLAYER_FIELD_CONSTRAINT_RATE());
int dim = (int) constraintConfig.get(conf.getLAYER_FIELD_CONSTRAINT_DIM());
constraint = new MinMaxNormConstraint(min, max, rate, dim + 1);
} else if (kerasConstraint.equals(conf.getLAYER_FIELD_MAX_NORM_CONSTRAINT())
|| kerasConstraint.equals(conf.getLAYER_FIELD_MAX_NORM_CONSTRAINT_ALIAS())
|| kerasConstraint.equals(conf.getLAYER_FIELD_MAX_NORM_CONSTRAINT_ALIAS_2())) {
double max = (double) constraintConfig.get(conf.getLAYER_FIELD_MAX_CONSTRAINT());
int dim = (int) constraintConfig.get(conf.getLAYER_FIELD_CONSTRAINT_DIM());
constraint = new MaxNormConstraint(max, dim + 1);
} else if (kerasConstraint.equals(conf.getLAYER_FIELD_UNIT_NORM_CONSTRAINT())
|| kerasConstraint.equals(conf.getLAYER_FIELD_UNIT_NORM_CONSTRAINT_ALIAS())
|| kerasConstraint.equals(conf.getLAYER_FIELD_UNIT_NORM_CONSTRAINT_ALIAS_2())) {
int dim = (int) constraintConfig.get(conf.getLAYER_FIELD_CONSTRAINT_DIM());
constraint = new UnitNormConstraint(dim + 1);
} else if (kerasConstraint.equals(conf.getLAYER_FIELD_NON_NEG_CONSTRAINT())
|| kerasConstraint.equals(conf.getLAYER_FIELD_NON_NEG_CONSTRAINT_ALIAS())
|| kerasConstraint.equals(conf.getLAYER_FIELD_NON_NEG_CONSTRAINT_ALIAS_2())) {
constraint = new NonNegativeConstraint();
} else {
throw new UnsupportedKerasConfigurationException("Unknown keras constraint " + kerasConstraint);
}
return constraint;
}
/**
* Get constraint initialization from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param constraintField string in configuration representing parameter to constrain
* @param conf Keras layer configuration
* @param kerasMajorVersion Major keras version as integer (1 or 2)
* @return a valid LayerConstraint
* @throws InvalidKerasConfigurationException Invalid configuration
* @throws UnsupportedKerasConfigurationException Unsupported configuration
*/
public static LayerConstraint getConstraintsFromConfig(Map<String, Object> layerConfig, String constraintField,
KerasLayerConfiguration conf, int kerasMajorVersion)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(constraintField)) {
// log.warn("Keras layer is missing " + constraintField + " field");
return null;
}
HashMap constraintMap = (HashMap) innerConfig.get(constraintField);
if (constraintMap == null)
return null;
String kerasConstraint;
if (constraintMap.containsKey(conf.getLAYER_FIELD_CONSTRAINT_NAME())) {
kerasConstraint = (String) constraintMap.get(conf.getLAYER_FIELD_CONSTRAINT_NAME());
} else {
throw new InvalidKerasConfigurationException("Keras layer is missing " +
conf.getLAYER_FIELD_CONSTRAINT_NAME() + " field");
}
Map<String, Object> constraintConfig;
if (kerasMajorVersion == 2) {
constraintConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(constraintMap, conf);
} else {
constraintConfig = constraintMap;
}
LayerConstraint layerConstraint = mapConstraint(kerasConstraint, conf, constraintConfig);
return layerConstraint;
}
}
@@ -0,0 +1,234 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.conf.distribution.*;
import org.deeplearning4j.nn.weights.*;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class KerasInitilizationUtils {
/**
* Map Keras to DL4J weight initialization functions.
*
* @param kerasInit String containing Keras initialization function name
* @return DL4J weight initialization enum
* @see WeightInit
*/
public static IWeightInit mapWeightInitialization(String kerasInit,
KerasLayerConfiguration conf,
Map<String, Object> initConfig,
int kerasMajorVersion)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
// TODO: Identity and VarianceScaling need "scale" factor
if (kerasInit != null) {
if (kerasInit.equals(conf.getINIT_GLOROT_NORMAL()) ||
kerasInit.equals(conf.getINIT_GLOROT_NORMAL_ALIAS())) {
return WeightInit.XAVIER.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_GLOROT_UNIFORM()) ||
kerasInit.equals(conf.getINIT_GLOROT_UNIFORM_ALIAS())) {
return WeightInit.XAVIER_UNIFORM.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_LECUN_NORMAL()) ||
kerasInit.equals(conf.getINIT_LECUN_NORMAL_ALIAS())) {
return WeightInit.LECUN_NORMAL.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_LECUN_UNIFORM()) ||
kerasInit.equals(conf.getINIT_LECUN_UNIFORM_ALIAS())) {
return WeightInit.LECUN_UNIFORM.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_HE_NORMAL()) ||
kerasInit.equals(conf.getINIT_HE_NORMAL_ALIAS())) {
return WeightInit.RELU.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_HE_UNIFORM()) ||
kerasInit.equals(conf.getINIT_HE_UNIFORM_ALIAS())) {
return WeightInit.RELU_UNIFORM.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_ONE()) ||
kerasInit.equals(conf.getINIT_ONES()) ||
kerasInit.equals(conf.getINIT_ONES_ALIAS())) {
return WeightInit.ONES.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_ZERO()) ||
kerasInit.equals(conf.getINIT_ZEROS()) ||
kerasInit.equals(conf.getINIT_ZEROS_ALIAS())) {
return WeightInit.ZERO.getWeightInitFunction();
} else if (kerasInit.equals(conf.getINIT_UNIFORM()) ||
kerasInit.equals(conf.getINIT_RANDOM_UNIFORM()) ||
kerasInit.equals(conf.getINIT_RANDOM_UNIFORM_ALIAS())) {
if (kerasMajorVersion == 2) {
double minVal = (double) initConfig.get(conf.getLAYER_FIELD_INIT_MINVAL());
double maxVal = (double) initConfig.get(conf.getLAYER_FIELD_INIT_MAXVAL());
return new WeightInitDistribution(new UniformDistribution(minVal, maxVal));
} else {
double scale = 0.05;
if (initConfig.containsKey(conf.getLAYER_FIELD_INIT_SCALE()))
scale = (double) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
return new WeightInitDistribution(new UniformDistribution(-scale, scale));
}
} else if (kerasInit.equals(conf.getINIT_NORMAL()) ||
kerasInit.equals(conf.getINIT_RANDOM_NORMAL()) ||
kerasInit.equals(conf.getINIT_RANDOM_NORMAL_ALIAS())) {
if (kerasMajorVersion == 2) {
double mean = (double) initConfig.get(conf.getLAYER_FIELD_INIT_MEAN());
double stdDev = (double) initConfig.get(conf.getLAYER_FIELD_INIT_STDDEV());
return new WeightInitDistribution(new NormalDistribution(mean, stdDev));
} else {
double scale = 0.05;
if (initConfig.containsKey(conf.getLAYER_FIELD_INIT_SCALE()))
scale = (double) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
return new WeightInitDistribution(new NormalDistribution(0, scale));
}
} else if (kerasInit.equals(conf.getINIT_CONSTANT()) ||
kerasInit.equals(conf.getINIT_CONSTANT_ALIAS())) {
double value = (double) initConfig.get(conf.getLAYER_FIELD_INIT_VALUE());
return new WeightInitDistribution(new ConstantDistribution(value));
} else if (kerasInit.equals(conf.getINIT_ORTHOGONAL()) ||
kerasInit.equals(conf.getINIT_ORTHOGONAL_ALIAS())) {
if (kerasMajorVersion == 2) {
double gain;
try {
gain = (double) initConfig.get(conf.getLAYER_FIELD_INIT_GAIN());
} catch (Exception e) {
gain = (int) initConfig.get(conf.getLAYER_FIELD_INIT_GAIN());
}
return new WeightInitDistribution(new OrthogonalDistribution(gain));
} else {
double scale = 1.1;
if (initConfig.containsKey(conf.getLAYER_FIELD_INIT_SCALE()))
scale = (double) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
return new WeightInitDistribution(new OrthogonalDistribution(scale));
}
} else if (kerasInit.equals(conf.getINIT_TRUNCATED_NORMAL()) ||
kerasInit.equals(conf.getINIT_TRUNCATED_NORMAL_ALIAS())) {
double mean = (double) initConfig.get(conf.getLAYER_FIELD_INIT_MEAN());
double stdDev = (double) initConfig.get(conf.getLAYER_FIELD_INIT_STDDEV());
return new WeightInitDistribution(new TruncatedNormalDistribution(mean, stdDev));
} else if (kerasInit.equals(conf.getINIT_IDENTITY()) ||
kerasInit.equals(conf.getINIT_IDENTITY_ALIAS())) {
if (kerasMajorVersion == 2) {
double gain = (double) initConfig.get(conf.getLAYER_FIELD_INIT_GAIN());
if (gain != 1.0)
if (gain != 1.0) {
return new WeightInitIdentity(gain);
} else {
return new WeightInitIdentity();
}
} else {
double scale = 1.;
if (initConfig.containsKey(conf.getLAYER_FIELD_INIT_SCALE()))
scale = (double) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
if (scale != 1.0) {
return new WeightInitIdentity(scale);
} else {
return new WeightInitIdentity();
}
}
} else if (kerasInit.equals(conf.getINIT_VARIANCE_SCALING())) {
double scale;
try {
scale = (double) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
} catch (Exception e) {
scale = (int) initConfig.get(conf.getLAYER_FIELD_INIT_SCALE());
}
String mode = (String) initConfig.get(conf.getLAYER_FIELD_INIT_MODE());
String distribution = (String) initConfig.get(conf.getLAYER_FIELD_INIT_DISTRIBUTION());
switch (mode) {
case "fan_in":
if (distribution.equals("normal")) {
return new WeightInitVarScalingNormalFanIn(scale);
} else {
return new WeightInitVarScalingUniformFanIn(scale);
}
case "fan_out":
if (distribution.equals("normal")) {
return new WeightInitVarScalingNormalFanOut(scale);
} else {
return new WeightInitVarScalingUniformFanOut(scale);
}
case "fan_avg":
if (distribution.equals("normal")) {
return new WeightInitVarScalingNormalFanAvg(scale);
} else {
return new WeightInitVarScalingUniformFanAvg(scale);
}
default:
throw new InvalidKerasConfigurationException("Initialization argument 'mode' has to be either " +
"fan_in, fan_out or fan_avg");
}
} else {
throw new UnsupportedKerasConfigurationException("Unknown keras weight initializer " + kerasInit);
}
}
throw new IllegalStateException("Error getting Keras weight initialization");
}
/**
* Get weight initialization from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to enforce loading configuration for further training
* @return Pair of DL4J weight initialization and distribution
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static IWeightInit getWeightInitFromConfig(Map<String, Object> layerConfig, String initField,
boolean enforceTrainingConfig,
KerasLayerConfiguration conf,
int kerasMajorVersion)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(initField))
throw new InvalidKerasConfigurationException("Keras layer is missing " + initField + " field");
String kerasInit;
Map<String, Object> initMap;
if (kerasMajorVersion != 2) {
kerasInit = (String) innerConfig.get(initField);
initMap = innerConfig;
} else {
@SuppressWarnings("unchecked")
Map<String, Object> fullInitMap = (HashMap) innerConfig.get(initField);
initMap = (HashMap) fullInitMap.get("config");
if (fullInitMap.containsKey("class_name")) {
kerasInit = (String) fullInitMap.get("class_name");
} else {
throw new UnsupportedKerasConfigurationException("Incomplete initialization class");
}
}
IWeightInit init;
try {
init = mapWeightInitialization(kerasInit, conf, initMap, kerasMajorVersion);
} catch (UnsupportedKerasConfigurationException e) {
if (enforceTrainingConfig)
throw e;
else {
init = new WeightInitXavier();
log.warn("Unknown weight initializer " + kerasInit + " (Using XAVIER instead).");
}
}
return init;
}
}
@@ -0,0 +1,709 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.config.Keras2LayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.KerasInput;
import org.deeplearning4j.nn.modelimport.keras.layers.attention.KerasAttentionLayer;
import org.deeplearning4j.nn.modelimport.keras.layers.convolutional.*;
import org.deeplearning4j.nn.modelimport.keras.layers.core.*;
import org.deeplearning4j.nn.modelimport.keras.layers.embeddings.KerasEmbedding;
import org.deeplearning4j.nn.modelimport.keras.layers.local.KerasLocallyConnected1D;
import org.deeplearning4j.nn.modelimport.keras.layers.noise.KerasAlphaDropout;
import org.deeplearning4j.nn.modelimport.keras.layers.noise.KerasGaussianDropout;
import org.deeplearning4j.nn.modelimport.keras.layers.noise.KerasGaussianNoise;
import org.deeplearning4j.nn.modelimport.keras.layers.normalization.KerasBatchNormalization;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasGlobalPooling;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasPooling1D;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasPooling2D;
import org.deeplearning4j.nn.modelimport.keras.layers.pooling.KerasPooling3D;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasLSTM;
import org.deeplearning4j.nn.modelimport.keras.layers.recurrent.KerasSimpleRnn;
import org.deeplearning4j.nn.modelimport.keras.layers.wrappers.KerasBidirectional;
import org.deeplearning4j.nn.conf.graph.ElementWiseVertex;
import org.deeplearning4j.nn.conf.layers.Layer;
import org.deeplearning4j.nn.conf.layers.samediff.SameDiffLambdaLayer;
import org.deeplearning4j.nn.modelimport.keras.layers.advanced.activations.*;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.common.primitives.Pair;
import java.lang.reflect.Constructor;
import java.util.*;
@Slf4j
public class KerasLayerUtils {
/**
* Checks whether layer config contains unsupported options.
*
* @param layerConfig dictionary containing Keras layer configuration
* @param enforceTrainingConfig whether to use Keras training configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
* @throws UnsupportedKerasConfigurationException Unsupported Keras config
*/
public static void checkForUnsupportedConfigurations(Map<String, Object> layerConfig,
boolean enforceTrainingConfig,
KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
getBiasL1RegularizationFromConfig(layerConfig, enforceTrainingConfig, conf);
getBiasL2RegularizationFromConfig(layerConfig, enforceTrainingConfig, conf);
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(conf.getLAYER_FIELD_W_REGULARIZER())) {
checkForUnknownRegularizer((Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_W_REGULARIZER()),
enforceTrainingConfig, conf);
}
if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER())) {
checkForUnknownRegularizer((Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER()),
enforceTrainingConfig, conf);
}
}
/**
* Get L1 bias regularization (if any) from Keras bias regularization configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return L1 regularization strength (0.0 if none)
*/
public static double getBiasL1RegularizationFromConfig(Map<String, Object> layerConfig,
boolean enforceTrainingConfig,
KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER())) {
Map<String, Object> regularizerConfig =
(Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER());
if (regularizerConfig != null && regularizerConfig.containsKey(conf.getREGULARIZATION_TYPE_L1()))
throw new UnsupportedKerasConfigurationException("L1 regularization for bias parameter not supported");
}
return 0.0;
}
/**
* Get L2 bias regularization (if any) from Keras bias regularization configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return L1 regularization strength (0.0 if none)
*/
private static double getBiasL2RegularizationFromConfig(Map<String, Object> layerConfig,
boolean enforceTrainingConfig,
KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(conf.getLAYER_FIELD_B_REGULARIZER())) {
Map<String, Object> regularizerConfig =
(Map<String, Object>) innerConfig.get(conf.getLAYER_FIELD_B_REGULARIZER());
if (regularizerConfig != null && regularizerConfig.containsKey(conf.getREGULARIZATION_TYPE_L2()))
throw new UnsupportedKerasConfigurationException("L2 regularization for bias parameter not supported");
}
return 0.0;
}
/**
* Check whether Keras weight regularization is of unknown type. Currently prints a warning
* since main use case for model import is inference, not further training. Unlikely since
* standard Keras weight regularizers are L1 and L2.
*
* @param regularizerConfig Map containing Keras weight reguarlization configuration
*/
private static void checkForUnknownRegularizer(Map<String, Object> regularizerConfig, boolean enforceTrainingConfig,
KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException {
if (regularizerConfig != null) {
for (String field : regularizerConfig.keySet()) {
if (!field.equals(conf.getREGULARIZATION_TYPE_L1()) && !field.equals(conf.getREGULARIZATION_TYPE_L2())
&& !field.equals(conf.getLAYER_FIELD_NAME())
&& !field.equals(conf.getLAYER_FIELD_CLASS_NAME())
&& !field.equals(conf.getLAYER_FIELD_CONFIG())) {
if (enforceTrainingConfig)
throw new UnsupportedKerasConfigurationException("Unknown regularization field " + field);
else
log.warn("Ignoring unknown regularization field " + field);
}
}
}
}
/**
* Build KerasLayer from a Keras layer configuration.
*
* @param layerConfig map containing Keras layer properties
* @return KerasLayer
* @see Layer
*/
public static KerasLayer getKerasLayerFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf,
Map<String, Class<? extends KerasLayer>> customLayers,
Map<String, SameDiffLambdaLayer> lambdaLayers,
Map<String, ? extends KerasLayer> previousLayers)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
return getKerasLayerFromConfig(layerConfig, false, conf, customLayers, lambdaLayers, previousLayers);
}
/**
* Build KerasLayer from a Keras layer configuration. Building layer with
* enforceTrainingConfig=true will throw exceptions for unsupported Keras
* options related to training (e.g., unknown regularizers). Otherwise
* we only generate warnings.
*
* @param layerConfig map containing Keras layer properties
* @param enforceTrainingConfig whether to enforce training-only configurations
* @return KerasLayer
* @see Layer
*/
public static KerasLayer getKerasLayerFromConfig(Map<String, Object> layerConfig,
boolean enforceTrainingConfig,
KerasLayerConfiguration conf,
Map<String, Class<? extends KerasLayer>> customLayers,
Map<String, SameDiffLambdaLayer> lambdaLayers,
Map<String, ? extends KerasLayer> previousLayers
)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
String layerClassName = getClassNameFromConfig(layerConfig, conf);
if (layerClassName.equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED())) {
layerConfig = getTimeDistributedLayerConfig(layerConfig, conf);
layerClassName = getClassNameFromConfig(layerConfig, conf);
}
KerasLayer layer = null;
if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ACTIVATION())) {
layer = new KerasActivation(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LEAKY_RELU())) {
layer = new KerasLeakyReLU(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MASKING())) {
layer = new KerasMasking(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_THRESHOLDED_RELU())) {
layer = new KerasThresholdedReLU(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_PRELU())) {
layer = new KerasPReLU(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DROPOUT())) {
layer = new KerasDropout(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_SPATIAL_DROPOUT_1D())
|| layerClassName.equals(conf.getLAYER_CLASS_NAME_SPATIAL_DROPOUT_2D())
|| layerClassName.equals(conf.getLAYER_CLASS_NAME_SPATIAL_DROPOUT_3D())) {
layer = new KerasSpatialDropout(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ALPHA_DROPOUT())) {
layer = new KerasAlphaDropout(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_GAUSSIAN_DROPOUT())) {
layer = new KerasGaussianDropout(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_GAUSSIAN_NOISE())) {
layer = new KerasGaussianNoise(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DENSE()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED_DENSE())) {
layer = new KerasDense(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_BIDIRECTIONAL())) {
layer = new KerasBidirectional(layerConfig, enforceTrainingConfig, previousLayers);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LSTM())) {
layer = new KerasLSTM(layerConfig, enforceTrainingConfig, previousLayers);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_SIMPLE_RNN())) {
layer = new KerasSimpleRnn(layerConfig, enforceTrainingConfig, previousLayers);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONVOLUTION_3D())) {
layer = new KerasConvolution3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONVOLUTION_2D())) {
layer = new KerasConvolution2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DECONVOLUTION_2D())) {
layer = new KerasDeconvolution2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DECONVOLUTION_3D())) {
layer = new KerasDeconvolution3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONVOLUTION_1D())) {
layer = new KerasConvolution1D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ATROUS_CONVOLUTION_2D())) {
layer = new KerasAtrousConvolution2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ATROUS_CONVOLUTION_1D())) {
layer = new KerasAtrousConvolution1D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_DEPTHWISE_CONVOLUTION_2D())) {
layer = new KerasDepthwiseConvolution2D(layerConfig, previousLayers, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_SEPARABLE_CONVOLUTION_2D())) {
layer = new KerasSeparableConvolution2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_3D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_3D())) {
layer = new KerasPooling3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_2D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_2D())) {
layer = new KerasPooling2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAX_POOLING_1D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE_POOLING_1D())) {
layer = new KerasPooling1D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_1D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_2D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_AVERAGE_POOLING_3D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_1D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_2D()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_GLOBAL_MAX_POOLING_3D())) {
layer = new KerasGlobalPooling(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_BATCHNORMALIZATION())) {
layer = new KerasBatchNormalization(layerConfig, enforceTrainingConfig, previousLayers);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_EMBEDDING())) {
layer = new KerasEmbedding(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_INPUT())) {
layer = new KerasInput(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_REPEAT())) {
layer = new KerasRepeatVector(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_PERMUTE())) {
layer = new KerasPermute(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MERGE())) {
layer = new KerasMerge(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ADD()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_ADD())) {
layer = new KerasMerge(layerConfig, ElementWiseVertex.Op.Add, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_SUBTRACT()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_FUNCTIONAL_SUBTRACT())) {
layer = new KerasMerge(layerConfig, ElementWiseVertex.Op.Subtract, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_AVERAGE()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_FUNCTIONAL_AVERAGE())) {
layer = new KerasMerge(layerConfig, ElementWiseVertex.Op.Average, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MULTIPLY()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_FUNCTIONAL_MULTIPLY())) {
layer = new KerasMerge(layerConfig, ElementWiseVertex.Op.Product, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_MAXIMUM()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_FUNCTIONAL_MAXIMUM())) {
layer = new KerasMerge(layerConfig, ElementWiseVertex.Op.Max, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CONCATENATE()) ||
layerClassName.equals(conf.getLAYER_CLASS_NAME_FUNCTIONAL_CONCATENATE())) {
layer = new KerasMerge(layerConfig, null, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_FLATTEN())) {
layer = new KerasFlatten(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_RESHAPE())) {
layer = new KerasReshape(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ZERO_PADDING_1D())) {
layer = new KerasZeroPadding1D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ZERO_PADDING_2D())) {
layer = new KerasZeroPadding2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ZERO_PADDING_3D())) {
layer = new KerasZeroPadding3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_UPSAMPLING_1D())) {
layer = new KerasUpsampling1D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_UPSAMPLING_2D())) {
layer = new KerasUpsampling2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_UPSAMPLING_3D())) {
layer = new KerasUpsampling3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CROPPING_3D())) {
layer = new KerasCropping3D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CROPPING_2D())) {
layer = new KerasCropping2D(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_CROPPING_1D())) {
layer = new KerasCropping1D(layerConfig, enforceTrainingConfig);
} else if(layerClassName.equals(conf.getLAYER_CLASS_NAME_ATTENTION())) {
layer = new KerasAttentionLayer(layerConfig,enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LAMBDA())) {
String lambdaLayerName = KerasLayerUtils.getLayerNameFromConfig(layerConfig, conf);
if (!lambdaLayers.containsKey(lambdaLayerName) && !customLayers.containsKey(layerClassName)) {
throw new UnsupportedKerasConfigurationException("No SameDiff Lambda layer found for Lambda " +
"layer " + lambdaLayerName + ". You can register a SameDiff Lambda layer using KerasLayer." +
"registerLambdaLayer(lambdaLayerName, sameDiffLambdaLayer);");
}
SameDiffLambdaLayer lambdaLayer = lambdaLayers.get(lambdaLayerName);
if (lambdaLayer != null) {
layer = new KerasLambda(layerConfig, enforceTrainingConfig, lambdaLayer);
}
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_RELU())) {
layer = new KerasReLU(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_ELU())) {
layer = new KerasELU(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_SOFTMAX())) {
layer = new KerasSoftmax(layerConfig, enforceTrainingConfig);
} else if (layerClassName.equals(conf.getLAYER_CLASS_NAME_LOCALLY_CONNECTED_1D())) {
layer = new KerasLocallyConnected1D(layerConfig, enforceTrainingConfig);
} else if (conf instanceof Keras2LayerConfiguration) {
Keras2LayerConfiguration k2conf = (Keras2LayerConfiguration) conf;
if (layerClassName.equals(k2conf.getTENSORFLOW_OP_LAYER())) {
//this was never really tested/worked better to remove/redo
throw new UnsupportedKerasConfigurationException("Tensorflow op layers are not supported yet.");
}
}
if (layer == null) {
Class<? extends KerasLayer> customConfig = customLayers.get(layerClassName);
if (customConfig == null)
throw new UnsupportedKerasConfigurationException("Unsupported keras layer type " + layerClassName);
try {
Constructor constructor = customConfig.getConstructor(Map.class);
layer = (KerasLayer) constructor.newInstance(layerConfig);
} catch (Exception e) {
throw new RuntimeException("The keras custom class " + layerClassName + " needs to have a constructor with only Map<String,Object> as the argument. Please ensure this is defined."
, e);
}
}
return layer;
}
/**
* Get Keras layer class name from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Keras layer class name
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static String getClassNameFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
if (!layerConfig.containsKey(conf.getLAYER_FIELD_CLASS_NAME()))
throw new InvalidKerasConfigurationException(
"Field " + conf.getLAYER_FIELD_CLASS_NAME() + " missing from layer config");
return (String) layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME());
}
/**
* Extract inner layer config from TimeDistributed configuration and merge
* it into the outer config.
*
* @param layerConfig dictionary containing Keras TimeDistributed configuration
* @return Time distributed layer config
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static Map<String, Object> getTimeDistributedLayerConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
if (!layerConfig.containsKey(conf.getLAYER_FIELD_CLASS_NAME()))
throw new InvalidKerasConfigurationException(
"Field " + conf.getLAYER_FIELD_CLASS_NAME() + " missing from layer config");
if (!layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME()).equals(conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED()))
throw new InvalidKerasConfigurationException("Expected " + conf.getLAYER_CLASS_NAME_TIME_DISTRIBUTED()
+ " layer, found " + layerConfig.get(conf.getLAYER_FIELD_CLASS_NAME()));
if (!layerConfig.containsKey(conf.getLAYER_FIELD_CONFIG()))
throw new InvalidKerasConfigurationException("Field "
+ conf.getLAYER_FIELD_CONFIG() + " missing from layer config");
Map<String, Object> outerConfig = getInnerLayerConfigFromConfig(layerConfig, conf);
Map<String, Object> innerLayer = (Map<String, Object>) outerConfig.get(conf.getLAYER_FIELD_LAYER());
layerConfig.put(conf.getLAYER_FIELD_CLASS_NAME(), innerLayer.get(conf.getLAYER_FIELD_CLASS_NAME()));
Map<String, Object> innerConfig = getInnerLayerConfigFromConfig(innerLayer, conf);
innerConfig.put(conf.getLAYER_FIELD_NAME(), outerConfig.get(conf.getLAYER_FIELD_NAME()));
outerConfig.putAll(innerConfig);
outerConfig.remove(conf.getLAYER_FIELD_LAYER());
return layerConfig;
}
/**
* Get inner layer config from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Inner layer config for a nested Keras layer configuration
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static Map<String, Object> getInnerLayerConfigFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
if (!layerConfig.containsKey(conf.getLAYER_FIELD_CONFIG()))
throw new InvalidKerasConfigurationException("Field "
+ conf.getLAYER_FIELD_CONFIG() + " missing from layer config");
return (Map<String, Object>) layerConfig.get(conf.getLAYER_FIELD_CONFIG());
}
/**
* Get layer name from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Keras layer name
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static String getLayerNameFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
if (conf instanceof Keras2LayerConfiguration) {
Keras2LayerConfiguration k2conf = (Keras2LayerConfiguration) conf;
if (getClassNameFromConfig(layerConfig, conf).equals(((Keras2LayerConfiguration) conf).getTENSORFLOW_OP_LAYER())) {
if (!layerConfig.containsKey(conf.getLAYER_FIELD_NAME()))
throw new InvalidKerasConfigurationException("Field " + conf.getLAYER_FIELD_NAME()
+ " missing from layer config");
return (String) layerConfig.get(conf.getLAYER_FIELD_NAME());
}
}
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_NAME()))
throw new InvalidKerasConfigurationException("Field " + conf.getLAYER_FIELD_NAME()
+ " missing from layer config");
return (String) innerConfig.get(conf.getLAYER_FIELD_NAME());
}
/**
* Get Keras input shape from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return input shape array
*/
public static int[] getInputShapeFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
// TODO: validate this. shouldn't we also have INPUT_SHAPE checked?
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (!innerConfig.containsKey(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE()))
return null;
List<Integer> batchInputShape = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE());
int[] inputShape = new int[batchInputShape.size() - 1];
for (int i = 1; i < batchInputShape.size(); i++) {
inputShape[i - 1] = batchInputShape.get(i) != null ? batchInputShape.get(i) : 0;
}
return inputShape;
}
/**
* Get Keras (backend) dimension order from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Dimension order
*/
public static KerasLayer.DimOrder getDimOrderFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
KerasLayer.DimOrder dimOrder = KerasLayer.DimOrder.NONE;
if (layerConfig.containsKey(conf.getLAYER_FIELD_BACKEND())) {
String backend = (String) layerConfig.get(conf.getLAYER_FIELD_BACKEND());
if (backend.equals("tensorflow") || backend.equals("cntk")) {
dimOrder = KerasLayer.DimOrder.TENSORFLOW;
} else if (backend.equals("theano")) {
dimOrder = KerasLayer.DimOrder.THEANO;
}
}
if (innerConfig.containsKey(conf.getLAYER_FIELD_DIM_ORDERING())) {
String dimOrderStr = (String) innerConfig.get(conf.getLAYER_FIELD_DIM_ORDERING());
if (dimOrderStr.equals(conf.getDIM_ORDERING_TENSORFLOW())) {
dimOrder = KerasLayer.DimOrder.TENSORFLOW;
} else if (dimOrderStr.equals(conf.getDIM_ORDERING_THEANO())) {
dimOrder = KerasLayer.DimOrder.THEANO;
} else {
log.warn("Keras layer has unknown Keras dimension order: " + dimOrder);
}
}
return dimOrder;
}
/**
* Get list of inbound layers from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return List of inbound layer names
*/
public static List<String> getInboundLayerNamesFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf) {
List<String> inboundLayerNames = new ArrayList<>();
if (layerConfig.containsKey(conf.getLAYER_FIELD_INBOUND_NODES())) {
List<Object> inboundNodes = (List<Object>) layerConfig.get(conf.getLAYER_FIELD_INBOUND_NODES());
if (!inboundNodes.isEmpty()) {
for (Object nodeName : inboundNodes) {
List<Object> list = (List<Object>) nodeName;
for (Object o : list) {
List<Object> list2 = (List<Object>) o;
inboundLayerNames.add(list2.get(0).toString());
}
}
}
}
return inboundLayerNames;
}
/**
* Get list of inbound layers from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return List of inbound layer names
*/
public static List<String> getOutboundLayerNamesFromConfig(Map<String, Object> layerConfig, KerasLayerConfiguration conf) {
List<String> outputLayerNames = new ArrayList<>();
if (layerConfig.containsKey(conf.getLAYER_FIELD_OUTBOUND_NODES())) {
List<Object> outboundNodes = (List<Object>) layerConfig.get(conf.getLAYER_FIELD_OUTBOUND_NODES());
if (!outboundNodes.isEmpty()) {
outboundNodes = (List<Object>) outboundNodes.get(0);
for (Object o : outboundNodes) {
String nodeName = (String) ((List<Object>) o).get(0);
outputLayerNames.add(nodeName);
}
}
}
return outputLayerNames;
}
/**
* Get number of outputs from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return Number of output neurons of the Keras layer
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int getNOutFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
int nOut;
if (innerConfig.containsKey(conf.getLAYER_FIELD_OUTPUT_DIM()))
/* Most feedforward layers: Dense, RNN, etc. */
nOut = (int) innerConfig.get(conf.getLAYER_FIELD_OUTPUT_DIM());
else if (innerConfig.containsKey(conf.getLAYER_FIELD_EMBEDDING_OUTPUT_DIM()))
/* Embedding layers. */
nOut = (int) innerConfig.get(conf.getLAYER_FIELD_EMBEDDING_OUTPUT_DIM());
else if (innerConfig.containsKey(conf.getLAYER_FIELD_NB_FILTER()))
/* Convolutional layers. */
nOut = (int) innerConfig.get(conf.getLAYER_FIELD_NB_FILTER());
else
throw new InvalidKerasConfigurationException("Could not determine number of outputs for layer: no "
+ conf.getLAYER_FIELD_OUTPUT_DIM() + " or " + conf.getLAYER_FIELD_NB_FILTER() + " field found");
return nOut;
}
public static Integer getNInFromInputDim(Map<String, Object> layerConfig, KerasLayerConfiguration conf) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(conf.getLAYER_FIELD_INPUT_DIM())) {
Object id = innerConfig.get(conf.getLAYER_FIELD_INPUT_DIM());
if (id instanceof Number) {
return ((Number) id).intValue();
}
}
return null;
}
/**
* Get dropout from Keras layer configuration.
*
* @param layerConfig dictionary containing Keras layer configuration
* @return get dropout value from Keras config
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static double getDropoutFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf) throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
/* NOTE: Keras "dropout" parameter determines dropout probability,
* while DL4J "dropout" parameter determines retention probability.
*/
double dropout = 1.0;
if (innerConfig.containsKey(conf.getLAYER_FIELD_DROPOUT())) {
/* For most feedforward layers. */
try {
dropout = 1.0 - (double) innerConfig.get(conf.getLAYER_FIELD_DROPOUT());
} catch (Exception e) {
int kerasDropout = (int) innerConfig.get(conf.getLAYER_FIELD_DROPOUT());
dropout = 1.0 - kerasDropout;
}
} else if (innerConfig.containsKey(conf.getLAYER_FIELD_DROPOUT_W())) {
/* For LSTMs. */
try {
dropout = 1.0 - (double) innerConfig.get(conf.getLAYER_FIELD_DROPOUT_W());
} catch (Exception e) {
int kerasDropout = (int) innerConfig.get(conf.getLAYER_FIELD_DROPOUT_W());
dropout = 1.0 - kerasDropout;
}
}
return dropout;
}
/**
* Determine if layer should be instantiated with bias
*
* @param layerConfig dictionary containing Keras layer configuration
* @return whether layer has a bias term
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static boolean getHasBiasFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
boolean hasBias = true;
if (innerConfig.containsKey(conf.getLAYER_FIELD_USE_BIAS())) {
hasBias = (boolean) innerConfig.get(conf.getLAYER_FIELD_USE_BIAS());
}
return hasBias;
}
/**
* Get zero masking flag
*
* @param layerConfig dictionary containing Keras layer configuration
* @return if masking zeros or not
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static boolean getZeroMaskingFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
boolean hasZeroMasking = true;
if (innerConfig.containsKey(conf.getLAYER_FIELD_MASK_ZERO())) {
hasZeroMasking = (boolean) innerConfig.get(conf.getLAYER_FIELD_MASK_ZERO());
}
return hasZeroMasking;
}
/**
* Get mask value
*
* @param layerConfig dictionary containing Keras layer configuration
* @return mask value, defaults to 0.0
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static double getMaskingValueFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf)
throws InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
double maskValue = 0.0;
if (innerConfig.containsKey(conf.getLAYER_FIELD_MASK_VALUE())) {
try {
maskValue = (double) innerConfig.get(conf.getLAYER_FIELD_MASK_VALUE());
} catch (Exception e) {
log.warn("Couldn't read masking value, default to 0.0");
}
} else {
throw new InvalidKerasConfigurationException("No mask value found, field "
+ conf.getLAYER_FIELD_MASK_VALUE());
}
return maskValue;
}
/**
* Remove weights from config after weight setting.
*
* @param weights layer weights
* @param conf Keras layer configuration
*/
public static void removeDefaultWeights(Map<String, INDArray> weights, KerasLayerConfiguration conf) {
if (weights.size() > 2) {
Set<String> paramNames = weights.keySet();
paramNames.remove(conf.getKERAS_PARAM_NAME_W());
paramNames.remove(conf.getKERAS_PARAM_NAME_B());
String unknownParamNames = paramNames.toString();
log.warn("Attemping to set weights for unknown parameters: "
+ unknownParamNames.substring(1, unknownParamNames.length() - 1));
}
}
public static Pair<Boolean, Double> getMaskingConfiguration(List<String> inboundLayerNames,
Map<String, ? extends KerasLayer> previousLayers) {
Boolean hasMasking = false;
Double maskingValue = 0.0;
for (String inboundLayerName : inboundLayerNames) {
if (previousLayers.containsKey(inboundLayerName)) {
KerasLayer inbound = previousLayers.get(inboundLayerName);
if (inbound instanceof KerasEmbedding && ((KerasEmbedding) inbound).isZeroMasking()) {
hasMasking = true;
} else if (inbound instanceof KerasMasking) {
hasMasking = true;
maskingValue = ((KerasMasking) inbound).getMaskingValue();
}
}
}
return new Pair<>(hasMasking, maskingValue);
}
}
@@ -0,0 +1,113 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.nd4j.linalg.lossfunctions.ILossFunction;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class KerasLossUtils {
static final Map<String, ILossFunction> customLoss = new HashMap<>();
/**
* Register a custom loss function
*
* @param lossName name of the lambda layer in the serialized Keras model
* @param lossFunction SameDiffLambdaLayer instance to map to Keras Lambda layer
*/
public static void registerCustomLoss(String lossName, ILossFunction lossFunction) {
customLoss.put(lossName, lossFunction);
}
/**
* Clear all lambda layers
*
*/
public static void clearCustomLoss() {
customLoss.clear();
}
/**
* Map Keras to DL4J loss functions.
*
* @param kerasLoss String containing Keras loss function name
* @return String containing DL4J loss function
*/
public static ILossFunction mapLossFunction(String kerasLoss, KerasLayerConfiguration conf)
throws UnsupportedKerasConfigurationException {
LossFunctions.LossFunction dl4jLoss;
kerasLoss = kerasLoss.toLowerCase();
if (kerasLoss.equals(conf.getKERAS_LOSS_MEAN_SQUARED_ERROR()) ||
kerasLoss.equals(conf.getKERAS_LOSS_MSE()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_MEAN_SQUARED_ERROR())) {
dl4jLoss = LossFunctions.LossFunction.SQUARED_LOSS;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_MEAN_ABSOLUTE_ERROR()) ||
kerasLoss.equals(conf.getKERAS_LOSS_MAE()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_MEAN_ABSOLUTE_ERROR())) {
dl4jLoss = LossFunctions.LossFunction.MEAN_ABSOLUTE_ERROR;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_MEAN_ABSOLUTE_PERCENTAGE_ERROR()) ||
kerasLoss.equals(conf.getKERAS_LOSS_MAPE()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_MEAN_ABSOLUTE_PERCENTAGE_ERROR())) {
dl4jLoss = LossFunctions.LossFunction.MEAN_ABSOLUTE_PERCENTAGE_ERROR;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_MEAN_SQUARED_LOGARITHMIC_ERROR()) ||
kerasLoss.equals(conf.getKERAS_LOSS_MSLE()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_MEAN_SQUARED_LOGARITHMIC_ERROR())) {
dl4jLoss = LossFunctions.LossFunction.MEAN_SQUARED_LOGARITHMIC_ERROR;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_SQUARED_HINGE()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_SQUARED_HINGE())) {
dl4jLoss = LossFunctions.LossFunction.SQUARED_HINGE;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_HINGE())) {
dl4jLoss = LossFunctions.LossFunction.HINGE;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_SPARSE_CATEGORICAL_CROSSENTROPY()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_SPARSE_CATEGORICAL_CROSS_ENTROPY())) {
dl4jLoss = LossFunctions.LossFunction.SPARSE_MCXENT;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_BINARY_CROSSENTROPY()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_BINARY_CROSSENTROPY())) {
dl4jLoss = LossFunctions.LossFunction.XENT;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_CATEGORICAL_CROSSENTROPY())) {
dl4jLoss = LossFunctions.LossFunction.MCXENT;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_KULLBACK_LEIBLER_DIVERGENCE()) ||
kerasLoss.equals(conf.getKERAS_LOSS_KLD()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_KLDIVERGENCE())) {
dl4jLoss = LossFunctions.LossFunction.KL_DIVERGENCE;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_POISSON())) {
dl4jLoss = LossFunctions.LossFunction.POISSON;
} else if (kerasLoss.equals(conf.getKERAS_LOSS_COSINE_PROXIMITY()) ||
kerasLoss.equals(conf.getTF_KERAS_LOSS_COSINE_SIMILARITY())) {
dl4jLoss = LossFunctions.LossFunction.COSINE_PROXIMITY;
} else {
ILossFunction lossClass = customLoss.get(kerasLoss);
if(lossClass != null){
return lossClass;
}else{
throw new UnsupportedKerasConfigurationException("Unknown Keras loss function " + kerasLoss);
}
}
return dl4jLoss.getILossFunction();
}
}
@@ -0,0 +1,363 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.Data;
import org.apache.commons.io.IOUtils;
import org.deeplearning4j.nn.modelimport.keras.Hdf5Archive;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.KerasModel;
import org.deeplearning4j.nn.modelimport.keras.KerasSequentialModel;
import org.deeplearning4j.nn.modelimport.keras.config.KerasModelConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.nd4j.shade.jackson.databind.ObjectMapper;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
@Data
public class KerasModelBuilder implements Cloneable, Closeable {
protected String modelJson = null;
protected String modelYaml = null;
protected String trainingJson = null;
protected String trainingYaml = null;
protected Hdf5Archive weightsArchive = null;
protected String weightsRoot = null;
protected Hdf5Archive trainingArchive = null;
protected boolean enforceTrainingConfig = false;
protected KerasModelConfiguration config;
protected int[] inputShape = null;
protected KerasLayer.DimOrder dimOrder = null;
/**
* KerasModelBuilder constructed from a model configuration.
*
* @param config KerasModelConfiguration
*/
public KerasModelBuilder(KerasModelConfiguration config) {
this.config = config;
}
/**
* Set model architecture from model JSON string.
*
* @param modelJson model as JSON string.
* @return Model Builder
*/
public KerasModelBuilder modelJson(String modelJson) {
this.modelJson = modelJson;
return this;
}
/**
* Set model architecture from model YAML string.
*
* @param modelYaml model as YAML string.
* @return Model Builder
*/
public KerasModelBuilder modelYaml(String modelYaml) {
this.modelYaml = modelYaml;
return this;
}
/**
* Set model architecture from file name pointing to model JSON string.
*
* @param modelJsonFilename Name of file containing model JSON string
* @return Model Builder
* @throws IOException I/O Exception
*/
public KerasModelBuilder modelJsonFilename(String modelJsonFilename) throws IOException {
checkForExistence(modelJsonFilename);
this.modelJson = new String(Files.readAllBytes(Paths.get(modelJsonFilename)));
return this;
}
/**
* Set model architecture from file name pointing to model YAML string.
*
* @param modelYamlFilename Name of file containing model YAML string
* @return Model Builder
* @throws IOException I/O Exception
*/
public KerasModelBuilder modelYamlFilename(String modelYamlFilename) throws IOException {
checkForExistence(modelYamlFilename);
this.modelJson = new String(Files.readAllBytes(Paths.get(modelYamlFilename)));
return this;
}
/**
* Set model architecture from input stream of model JSON.
*
* @param modelJsonInputStream Input stream of model JSON
* @return Model builder
* @throws IOException I/O exception
*/
public KerasModelBuilder modelJsonInputStream(InputStream modelJsonInputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(modelJsonInputStream, byteArrayOutputStream);
this.modelJson = new String(byteArrayOutputStream.toByteArray());
return this;
}
/**
* Set model architecture from input stream of model YAML.
*
* @param modelYamlInputStream Input stream of model YAML
* @return Model builder
* @throws IOException I/O exception
*/
public KerasModelBuilder modelYamlInputStream(InputStream modelYamlInputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(modelYamlInputStream, byteArrayOutputStream);
this.modelJson = new String(byteArrayOutputStream.toByteArray());
return this;
}
/**
* Provide input shape for Keras models that have been compiled without one. DL4J
* needs this shape information on import to infer shapes of later layers and do
* shape validation.
*
* @param inputShape Input shape as int array
* @return Model Builder
*/
public KerasModelBuilder inputShape(int[] inputShape) {
this.inputShape = inputShape;
return this;
}
/**
* Provide training configuration as JSON string
*
* @param trainingJson Training JSON string
* @return Model builder
*/
public KerasModelBuilder trainingJson(String trainingJson) {
this.trainingJson = trainingJson;
return this;
}
/**
* Provide training configuration as YAML string
*
* @param trainingYaml Training YAML string
* @return Model builder
*/
public KerasModelBuilder trainingYaml(String trainingYaml) {
this.trainingYaml = trainingYaml;
return this;
}
/**
* Manually set dim order for Keras model, i.e. either TENSORFLOW (channels last)
* or THEANO (channels first).
*
* Dim ordering will be automatically inferred from your model file, so don't
* tamper with this option unless you're sure what you're doing. Explicitly
* setting dim ordering can be useful for very old Keras models (before version 1.2),
* for which inference can be difficult.
*
* @param dimOrder Ordering of dimensions (channels first vs. last)
* @return Model builder
*/
public KerasModelBuilder dimOrder(KerasLayer.DimOrder dimOrder){
this.dimOrder = dimOrder;
return this;
}
/**
* Provide training configuration as file input stream from JSON
*
* @param trainingJsonInputStream Input stream of training JSON string
* @return Model builder
*/
public KerasModelBuilder trainingJsonInputStream(InputStream trainingJsonInputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(trainingJsonInputStream, byteArrayOutputStream);
this.trainingJson = new String(byteArrayOutputStream.toByteArray());
return this;
}
/**
* Provide training configuration as file input stream from YAML
*
* @param trainingYamlInputStream Input stream of training YAML string
* @return Model builder
*/
public KerasModelBuilder trainingYamlInputStream(InputStream trainingYamlInputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
IOUtils.copy(trainingYamlInputStream, byteArrayOutputStream);
this.trainingYaml = new String(byteArrayOutputStream.toByteArray());
return this;
}
/**
* Set full model HDF5 (architecture, weights and training configuration) by providing the HDF5 filename.
*
* @param modelHdf5Filename File name of HDF5 file containing full model
* @return Model builder
* @throws UnsupportedKerasConfigurationException Unsupported configuration
* @throws InvalidKerasConfigurationException Invalid configuration
* @throws IOException I/O exception
*/
public KerasModelBuilder modelHdf5Filename(String modelHdf5Filename)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException, IOException {
checkForExistence(modelHdf5Filename);
synchronized (Hdf5Archive.LOCK_OBJECT) {
try {
this.weightsArchive = this.trainingArchive = new Hdf5Archive(modelHdf5Filename);
this.weightsRoot = config.getTrainingWeightsRoot();
if (!this.weightsArchive.hasAttribute(config.getTrainingModelConfigAttribute()))
throw new InvalidKerasConfigurationException(
"Model configuration attribute missing from " + modelHdf5Filename + " archive.");
String initialModelJson = this.weightsArchive.readAttributeAsJson(
config.getTrainingModelConfigAttribute());
String kerasVersion = this.weightsArchive.readAttributeAsFixedLengthString(
config.getFieldKerasVersion(), 5);
Map<String, Object> modelMapper = KerasModelUtils.parseJsonString(initialModelJson);
modelMapper.put(config.getFieldKerasVersion(), kerasVersion);
int majorKerasVersion = Character.getNumericValue(kerasVersion.charAt(0));
if (majorKerasVersion == 2) {
String backend = this.weightsArchive.readAttributeAsString(config.getFieldBackend());
modelMapper.put(config.getFieldBackend(), backend);
}
this.modelJson = new ObjectMapper().writeValueAsString(modelMapper);
if (this.trainingArchive.hasAttribute(config.getTrainingTrainingConfigAttribute()))
this.trainingJson = this.trainingArchive
.readAttributeAsJson(config.getTrainingTrainingConfigAttribute());
} catch (Throwable t) {
close();
throw t;
}
}
return this;
}
/**
* Set weights of the model by providing the file name of the corresponding weights HDF5 file.
* The root of the HDF5 group containing weights won't be set by this method.
*
* @param weightsHdf5Filename File name of weights HDF5
* @return Model builder
*/
public KerasModelBuilder weightsHdf5FilenameNoRoot(String weightsHdf5Filename) throws IOException {
checkForExistence(weightsHdf5Filename);
this.weightsArchive = new Hdf5Archive(weightsHdf5Filename);
return this;
}
/**
* Set weights of the model by providing the file name of the corresponding weights HDF5 file.
* The root of the HDF5 group containing weights will be read and set from the configuration of this
* model builder instance.
*
* @param weightsHdf5Filename File name of weights HDF5
* @return Model builder
*/
public KerasModelBuilder weightsHdf5Filename(String weightsHdf5Filename) throws IOException {
checkForExistence(weightsHdf5Filename);
this.weightsArchive = new Hdf5Archive(weightsHdf5Filename);
this.weightsRoot = config.getTrainingWeightsRoot();
return this;
}
/**
* Determine whether to enforce loading a training configuration or not.
*
* @param enforceTrainingConfig boolean, read training config or not
* @return Model builder
*/
public KerasModelBuilder enforceTrainingConfig(boolean enforceTrainingConfig) {
this.enforceTrainingConfig = enforceTrainingConfig;
return this;
}
/**
* Build a KerasModel (corresponding to ComputationGraph) from this model builder.
*
* @return KerasModel
* @throws IOException I/O exception
* @throws InvalidKerasConfigurationException Invalid configuration
* @throws UnsupportedKerasConfigurationException Unsupported configuration
*/
public KerasModel buildModel()
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasModel model = new KerasModel(this);
close();
return model;
}
/**
* Build a KerasSequentialModel (corresponding to MultiLayerNetwork) from this model builder.
*
* @return KerasSequentialModel
* @throws IOException I/O exception
* @throws InvalidKerasConfigurationException Invalid configuration
* @throws UnsupportedKerasConfigurationException Unsupported configuration
*/
public KerasSequentialModel buildSequential()
throws IOException, InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
KerasSequentialModel sequentialModel = new KerasSequentialModel(this);
close();
return sequentialModel;
}
/**
* Close all HDF5 archives for this model builder.
*/
@Override
public void close() {
if (trainingArchive != null && trainingArchive != weightsArchive) {
trainingArchive.close();
trainingArchive = null;
}
if (weightsArchive != null) {
weightsArchive.close();
weightsArchive = null;
}
}
/**
* Check if the file corresponding to model JSON/YAML or HDF5 files actually exists
* and throw an explicit exception.
*
* @param fileName File name to check for existence
* @throws FileNotFoundException File not found
*/
private void checkForExistence(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
throw new FileNotFoundException("File with name " + fileName + " does not exist.");
}
if (!file.isFile()) {
throw new IOException("Provided string does not correspond to an actual file.");
}
}
}
@@ -0,0 +1,433 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.hdf5.Group;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.api.Model;
import org.deeplearning4j.nn.conf.InputPreProcessor;
import org.deeplearning4j.nn.conf.layers.*;
import org.deeplearning4j.nn.graph.ComputationGraph;
import org.deeplearning4j.nn.modelimport.keras.Hdf5Archive;
import org.deeplearning4j.nn.modelimport.keras.KerasLayer;
import org.deeplearning4j.nn.modelimport.keras.config.KerasModelConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.layers.wrappers.KerasBidirectional;
import org.deeplearning4j.preprocessors.ReshapePreprocessor;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.shade.jackson.core.type.TypeReference;
import org.nd4j.shade.jackson.databind.ObjectMapper;
import org.nd4j.shade.jackson.dataformat.yaml.YAMLFactory;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class KerasModelUtils {
/**
* Set the {@link org.deeplearning4j.nn.conf.DataFormat}
* for certain input preprocessors to ensure that
* model import propagates properly for cases like reshapes.
*
* @param inputPreProcessor
* @param currLayer
*/
public static void setDataFormatIfNeeded(InputPreProcessor inputPreProcessor, KerasLayer currLayer) {
if(inputPreProcessor instanceof ReshapePreprocessor) {
ReshapePreprocessor reshapePreprocessor = (ReshapePreprocessor) inputPreProcessor;
if(currLayer.isLayer()) {
if(currLayer.getDimOrder() != null) {
Layer layer = currLayer.getLayer();
if(layer instanceof ConvolutionLayer) {
ConvolutionLayer convolutionLayer = (ConvolutionLayer) layer;
if(convolutionLayer instanceof Convolution3D) {
Convolution3D convolution3D = (Convolution3D) convolutionLayer;
reshapePreprocessor.setFormat(convolution3D.getDataFormat());
} else if(convolutionLayer instanceof Deconvolution3D) {
Deconvolution3D deconvolution3D = (Deconvolution3D) convolutionLayer;
reshapePreprocessor.setFormat(deconvolution3D.getDataFormat());
} else {
reshapePreprocessor.setFormat(convolutionLayer.getCnn2dDataFormat());
}
} else if(layer instanceof BaseRecurrentLayer) {
BaseRecurrentLayer baseRecurrentLayer = (BaseRecurrentLayer) layer;
reshapePreprocessor.setFormat(baseRecurrentLayer.getRnnDataFormat());
}
}
}
}
}
/**
* Helper function to import weights from nested Map into existing model. Depends critically
* on matched layer and parameter names. In general this seems to be straightforward for most
* Keras models and layersOrdered, but there may be edge cases.
*
* @param model DL4J Model interface
* @return DL4J Model interface
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static Model copyWeightsToModel(Model model, Map<String, KerasLayer> kerasLayers)
throws InvalidKerasConfigurationException {
/* Get list if layers from model. */
org.deeplearning4j.nn.api.Layer[] layersFromModel;
if (model instanceof MultiLayerNetwork)
layersFromModel = ((MultiLayerNetwork) model).getLayers();
else
layersFromModel = ((ComputationGraph) model).getLayers();
/* Iterate over layers in model, setting weights when relevant. */
Set<String> layerNames = new HashSet<>(kerasLayers.keySet());
for (org.deeplearning4j.nn.api.Layer layer : layersFromModel) {
String layerName = layer.conf().getLayer().getLayerName();
if (!kerasLayers.containsKey(layerName))
throw new InvalidKerasConfigurationException(
"No weights found for layer in model (named " + layerName + ")");
kerasLayers.get(layerName).copyWeightsToLayer(layer);
layerNames.remove(layerName);
}
for (String layerName : layerNames) {
if (kerasLayers.get(layerName).getNumParams() > 0)
throw new InvalidKerasConfigurationException(
"Attempting to copy weights for layer not in model (named " + layerName + ")");
}
return model;
}
/**
* Determine Keras major version
*
* @param modelConfig parsed model configuration for keras model
* @param config basic model configuration (KerasModelConfiguration)
* @return Major Keras version (1 or 2)
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static int determineKerasMajorVersion(Map<String, Object> modelConfig, KerasModelConfiguration config)
throws InvalidKerasConfigurationException {
int kerasMajorVersion;
if (!modelConfig.containsKey(config.getFieldKerasVersion())) {
log.warn("Could not read keras version used (no "
+ config.getFieldKerasVersion() + " field found) \n"
+ "assuming keras version is 1.0.7 or earlier."
);
kerasMajorVersion = 1;
} else {
String kerasVersionString = (String) modelConfig.get(config.getFieldKerasVersion());
if (Character.isDigit(kerasVersionString.charAt(0))) {
kerasMajorVersion = Character.getNumericValue(kerasVersionString.charAt(0));
} else {
throw new InvalidKerasConfigurationException(
"Keras version was not readable (" + config.getFieldKerasVersion() + " provided)"
);
}
}
return kerasMajorVersion;
}
/**
* Determine Keras backend
*
* @param modelConfig parsed model configuration for keras model
* @param config basic model configuration (KerasModelConfiguration)
* @return Keras backend string
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static String determineKerasBackend(Map<String, Object> modelConfig, KerasModelConfiguration config) {
String kerasBackend = null;
if (!modelConfig.containsKey(config.getFieldBackend())) {
// TODO: H5 files unfortunately do not seem to have this property in keras 1.
log.warn("Could not read keras backend used (no "
+ config.getFieldBackend() + " field found) \n"
);
} else {
kerasBackend = (String) modelConfig.get(config.getFieldBackend());
}
return kerasBackend;
}
private static String findParameterName(String parameter, String[] fragmentList) {
Matcher layerNameMatcher =
Pattern.compile(fragmentList[fragmentList.length - 1]).matcher(parameter);
String parameterNameFound = layerNameMatcher.replaceFirst("");
/* Usually layer name is separated from parameter name by an underscore. */
Matcher paramNameMatcher = Pattern.compile("^_(.+)$").matcher(parameterNameFound);
if (paramNameMatcher.find())
parameterNameFound = paramNameMatcher.group(1);
/* TensorFlow backend often appends ":" followed by one or more digits to parameter names. */
Matcher tfSuffixMatcher = Pattern.compile(":\\d+?$").matcher(parameterNameFound);
if (tfSuffixMatcher.find())
parameterNameFound = tfSuffixMatcher.replaceFirst("");
/* TensorFlow backend also may append "_" followed by one or more digits to parameter names.*/
Matcher tfParamNbMatcher = Pattern.compile("_\\d+$").matcher(parameterNameFound);
if (tfParamNbMatcher.find())
parameterNameFound = tfParamNbMatcher.replaceFirst("");
return parameterNameFound;
}
/**
* Store weights to import with each associated Keras layer.
*
* @param weightsArchive Hdf5Archive
* @param weightsRoot root of weights in HDF5 archive
* @throws InvalidKerasConfigurationException Invalid Keras configuration
*/
public static void importWeights(Hdf5Archive weightsArchive, String weightsRoot, Map<String, KerasLayer> layers,
int kerasVersion, String backend)
throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
// check to ensure naming scheme doesn't include forward slash
boolean includesSlash = false;
for (String layerName : layers.keySet()) {
if (layerName.contains("/"))
includesSlash = true;
}
synchronized (KerasModelUtils.class) {
List<String> layerGroups;
if (!includesSlash) {
layerGroups = weightsRoot != null ? weightsArchive.getGroups(weightsRoot) : weightsArchive.getGroups();
} else {
layerGroups = new ArrayList<>(layers.keySet());
}
/* Set weights in KerasLayer for each entry in weights map. */
for (String layerName : layerGroups) {
if(layerName.equals(KerasModelConfiguration.topLevelModelWeights)) {
//new way of saving parameter weights
synchronized(Hdf5Archive.LOCK_OBJECT) {
Group[] rootGroup = weightsArchive.openGroups(weightsRoot + "/" + layerName);
if(rootGroup[0].getNumObjs() < 1)
weightsArchive.closeGroups(rootGroup);
}
}
else {
//older layers where weights are stored per layer
List<String> layerParamNames;
// there's a bug where if a layer name contains a forward slash, the first fragment must be appended
// to the name of the dataset; it appears h5 interprets the forward slash as a data group
String[] layerFragments = layerName.split("/");
// Find nested groups when using Tensorflow
String rootPrefix = weightsRoot != null ? weightsRoot + "/" : "";
List<String> attributeStrParts = new ArrayList<>();
String attributeStr = weightsArchive.readAttributeAsString(
"weight_names", rootPrefix + layerName
);
String attributeJoinStr;
Matcher attributeMatcher = Pattern.compile(":\\d+").matcher(attributeStr);
Boolean foundTfGroups = attributeMatcher.find();
if (foundTfGroups) {
for (String part : attributeStr.split("/")) {
part = part.trim();
if (part.length() == 0)
break;
Matcher tfSuffixMatcher = Pattern.compile(":\\d+").matcher(part);
if (tfSuffixMatcher.find())
break;
attributeStrParts.add(part);
}
attributeJoinStr = StringUtils.join(attributeStrParts, "/");
} else {
attributeJoinStr = layerFragments[0];
}
String baseAttributes = layerName + "/" + attributeJoinStr;
if (layerFragments.length > 1) {
try {
layerParamNames = weightsArchive.getDataSets(rootPrefix + baseAttributes);
} catch (Exception e) {
layerParamNames = weightsArchive.getDataSets(rootPrefix + layerName);
}
} else {
if (foundTfGroups) {
layerParamNames = weightsArchive.getDataSets(rootPrefix + baseAttributes);
} else {
if (kerasVersion == 2) {
if (backend.equals("theano") && layerName.contains("bidirectional")) {
for (String part : attributeStr.split("/")) {
if (part.contains("forward"))
baseAttributes = baseAttributes + "/" + part;
}
}
if (layers.get(layerName).getNumParams() > 0) {
try {
layerParamNames = weightsArchive.getDataSets(rootPrefix + baseAttributes);
} catch (Exception e) {
log.warn("No HDF5 group with weights found for layer with name "
+ layerName + ", continuing import.");
layerParamNames = Collections.emptyList();
}
} else {
layerParamNames = weightsArchive.getDataSets(rootPrefix + layerName);
}
} else {
layerParamNames = weightsArchive.getDataSets(rootPrefix + layerName);
}
}
}
if (layerParamNames.isEmpty())
continue;
if (!layers.containsKey(layerName))
throw new InvalidKerasConfigurationException(
"Found weights for layer not in model (named " + layerName + ")");
KerasLayer layer = layers.get(layerName);
//note we used to have bidirectional specific validation here.
//it assumed that a bias always existed. This isn't the case
//and would rnns without biases to fail.
Map<String, INDArray> weights = new HashMap<>();
/**
* TODO: check what weights are being read. Do we have the wrong file or something?
*/
for (String layerParamName : layerParamNames) {
String paramName = KerasModelUtils.findParameterName(layerParamName, layerFragments);
INDArray paramValue;
if (kerasVersion == 2 && layer instanceof KerasBidirectional) {
String backwardAttributes = baseAttributes.replace("forward", "backward");
String[] split = backwardAttributes.split("/");
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < split.length - 1; i++) {
if(i < split.length - 1)
stringBuilder.append(split[i]).append("/");
}
//note: this used to be somewhat hardcoded
//now we dynamically check for the group name
//underneath instead.
StringBuilder parentGroup = new StringBuilder();
parentGroup.append(rootPrefix );
parentGroup.append(stringBuilder);
List<String> groups = weightsArchive.getGroups(parentGroup.toString());
parentGroup.append(groups.get(0));
INDArray forwardParamValue = weightsArchive.readDataSet(layerParamName,
rootPrefix + baseAttributes);
INDArray backwardParamValue = weightsArchive.readDataSet(
layerParamName, parentGroup.toString());
weights.put("forward_" + paramName, forwardParamValue);
weights.put("backward_" + paramName, backwardParamValue);
} else {
if (foundTfGroups) {
paramValue = weightsArchive.readDataSet(layerParamName, rootPrefix + baseAttributes);
} else {
if (layerFragments.length > 1) {
paramValue = weightsArchive.readDataSet(
layerFragments[0] + "/" + layerParamName, rootPrefix, layerName);
} else {
if (kerasVersion == 2) {
paramValue = weightsArchive.readDataSet(
layerParamName, rootPrefix + baseAttributes);
} else {
paramValue = weightsArchive.readDataSet(layerParamName, rootPrefix, layerName);
}
}
}
weights.put(paramName, paramValue);
}
}
layer.setWeights(weights);
}
}
/* Look for layers in model with no corresponding entries in weights map. */
Set<String> layerNames = new HashSet<>(layers.keySet());
layerNames.removeAll(layerGroups);
for (String layerName : layerNames) {
if (layers.get(layerName).getNumParams() > 0)
throw new InvalidKerasConfigurationException("Could not find weights required for layer " + layerName);
}
}
}
/**
* Parse Keras model configuration from JSON or YAML string representation
*
* @param modelJson JSON string representing model (potentially null)
* @param modelYaml YAML string representing model (potentially null)
* @return Model configuration as Map<String, Object>
* @throws IOException IO exception
* @throws InvalidKerasConfigurationException Invalid Keras config
*/
public static Map<String, Object> parseModelConfig(String modelJson, String modelYaml)
throws IOException, InvalidKerasConfigurationException {
Map<String, Object> modelConfig;
if (modelJson != null)
modelConfig = parseJsonString(modelJson);
else if (modelYaml != null)
modelConfig = parseYamlString(modelYaml);
else
throw new InvalidKerasConfigurationException("Requires model configuration as either JSON or YAML string.");
return modelConfig;
}
/**
* Convenience function for parsing JSON strings.
*
* @param json String containing valid JSON
* @return Nested (key,value) map of arbitrary depth
* @throws IOException IO exception
*/
public static Map<String, Object> parseJsonString(String json) throws IOException {
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
};
return mapper.readValue(json, typeRef);
}
/**
* Convenience function for parsing YAML strings.
*
* @param yaml String containing valid YAML
* @return Nested (key,value) map of arbitrary depth
* @throws IOException IO exception
*/
public static Map<String, Object> parseYamlString(String yaml) throws IOException {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
};
return mapper.readValue(yaml, typeRef);
}
}
@@ -0,0 +1,161 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import lombok.extern.slf4j.Slf4j;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import org.nd4j.linalg.learning.config.*;
import org.nd4j.linalg.schedule.InverseSchedule;
import org.nd4j.linalg.schedule.ScheduleType;
import java.util.Map;
@Slf4j
public class KerasOptimizerUtils {
protected static final String LR = "lr";
protected static final String LR2 = "learning_rate";
protected static final String EPSILON = "epsilon";
protected static final String MOMENTUM = "momentum";
protected static final String BETA_1 = "beta_1";
protected static final String BETA_2 = "beta_2";
protected static final String DECAY = "decay";
protected static final String RHO = "rho";
protected static final String SCHEDULE_DECAY = "schedule_decay";
/**
* Map Keras optimizer to DL4J IUpdater.
*
* @param optimizerConfig Optimizer configuration map
* @return DL4J IUpdater instance
*/
public static IUpdater mapOptimizer(Map<String, Object> optimizerConfig)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
if (!optimizerConfig.containsKey("class_name")) {
throw new InvalidKerasConfigurationException("Optimizer config does not contain a name field.");
}
String optimizerName = (String) optimizerConfig.get("class_name");
//newer keras versions
if(optimizerName != null && optimizerName.startsWith("Custom>")) {
optimizerName = optimizerName.replace("Custom>","");
}
if (!optimizerConfig.containsKey("config"))
throw new InvalidKerasConfigurationException("Field config missing from layer config");
Map<String, Object> optimizerParameters = (Map<String, Object>) optimizerConfig.get("config");
IUpdater dl4jOptimizer;
switch (optimizerName.toLowerCase()) {
case "adam": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double beta1 = (double) optimizerParameters.get(BETA_1);
double beta2 = (double) optimizerParameters.get(BETA_2);
double epsilon = (double) optimizerParameters.get(EPSILON);
double decay = (double) (optimizerParameters.containsKey(DECAY) ? optimizerParameters.get(DECAY) : Adam.DEFAULT_ADAM_BETA1_MEAN_DECAY);
dl4jOptimizer = new Adam.Builder()
.beta1(beta1).beta2(beta2)
.epsilon(epsilon).learningRate(lr)
.learningRateSchedule(decay == 0 ? null : new InverseSchedule(ScheduleType.ITERATION, lr, decay, 1))
.build();
break;
}
case "adadelta": {
double rho = (double) optimizerParameters.get(RHO);
double epsilon = (double) optimizerParameters.get(EPSILON);
dl4jOptimizer = new AdaDelta.Builder()
.epsilon(epsilon).rho(rho)
.build();
break;
}
case "adagrad": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double epsilon = (double) optimizerParameters.get(EPSILON);
double decay = (double) optimizerParameters.get(DECAY);
dl4jOptimizer = new AdaGrad.Builder()
.epsilon(epsilon).learningRate(lr)
.learningRateSchedule(decay == 0 ? null : new InverseSchedule(ScheduleType.ITERATION, lr, decay, 1))
.build();
break;
}
case "adamax": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double beta1 = (double) optimizerParameters.get(BETA_1);
double beta2 = (double) optimizerParameters.get(BETA_2);
double epsilon = (double) optimizerParameters.get(EPSILON);
dl4jOptimizer = new AdaMax(lr, beta1, beta2, epsilon);
break;
}
case "nadam": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double beta1 = (double) optimizerParameters.get(BETA_1);
double beta2 = (double) optimizerParameters.get(BETA_2);
double epsilon = (double) optimizerParameters.get(EPSILON);
double scheduleDecay = (double) optimizerParameters.getOrDefault(SCHEDULE_DECAY,0.0);
dl4jOptimizer = new Nadam.Builder()
.beta1(beta1).beta2(beta2)
.epsilon(epsilon).learningRate(lr)
.learningRateSchedule(scheduleDecay == 0 ? null : new InverseSchedule(ScheduleType.ITERATION, lr,
scheduleDecay, 1))
.build();
break;
}
case "sgd": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double momentum = (double) (optimizerParameters.containsKey(EPSILON) ? optimizerParameters.get(EPSILON) : optimizerParameters.get(MOMENTUM));
double decay = (double) optimizerParameters.get(DECAY);
dl4jOptimizer = new Nesterovs.Builder()
.momentum(momentum).learningRate(lr)
.learningRateSchedule(decay == 0 ? null : new InverseSchedule(ScheduleType.ITERATION, lr, decay, 1))
.build();
break;
}
case "rmsprop": {
double lr = (double) (optimizerParameters.containsKey(LR) ? optimizerParameters.get(LR) : optimizerParameters.get(LR2));
double rho = (double) optimizerParameters.get(RHO);
double epsilon = (double) optimizerParameters.get(EPSILON);
double decay = (double) optimizerParameters.get(DECAY);
dl4jOptimizer = new RmsProp.Builder()
.epsilon(epsilon).rmsDecay(rho).learningRate(lr)
.learningRateSchedule(decay == 0 ? null : new InverseSchedule(ScheduleType.ITERATION, lr, decay, 1))
.build();
break;
}
default:
throw new UnsupportedKerasConfigurationException("Optimizer with name " + optimizerName + "can not be" +
"matched to a DL4J optimizer. Note that custom TFOptimizers are not supported by model import");
}
return dl4jOptimizer;
}
}
@@ -0,0 +1,68 @@
/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
package org.deeplearning4j.nn.modelimport.keras.utils;
import org.deeplearning4j.nn.modelimport.keras.config.KerasLayerConfiguration;
import org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException;
import org.deeplearning4j.nn.modelimport.keras.exceptions.UnsupportedKerasConfigurationException;
import java.util.Map;
public class KerasRegularizerUtils {
/**
* Get weight regularization from Keras weight regularization configuration.
*
* @param layerConfig Map containing Keras weight regularization configuration
* @param conf Keras layer configuration
* @param configField regularization config field to use
* @param regularizerType type of regularization as string (e.g. "l2")
* @return L1 or L2 regularization strength (0.0 if none)
*/
public static double getWeightRegularizerFromConfig(Map<String, Object> layerConfig,
KerasLayerConfiguration conf,
String configField,
String regularizerType)
throws UnsupportedKerasConfigurationException, InvalidKerasConfigurationException {
Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
if (innerConfig.containsKey(configField)) {
Map<String, Object> regularizerConfig = (Map<String, Object>) innerConfig.get(configField);
if (regularizerConfig != null) {
if (regularizerConfig.containsKey(regularizerType)) {
return (double) regularizerConfig.get(regularizerType);
}
if (regularizerConfig.containsKey(conf.getLAYER_FIELD_CLASS_NAME()) &&
regularizerConfig.get(conf.getLAYER_FIELD_CLASS_NAME()).equals("L1L2")) {
Map<String, Object> innerRegularizerConfig =
KerasLayerUtils.getInnerLayerConfigFromConfig(regularizerConfig, conf);
try {
return (double) innerRegularizerConfig.get(regularizerType);
} catch (Exception e) {
return (double) (int) innerRegularizerConfig.get(regularizerType);
}
}
}
}
return 0.0;
}
}
@@ -0,0 +1,34 @@
open module deeplearning4j.modelimport {
requires commons.io;
requires gson;
requires guava;
requires org.apache.commons.lang3;
requires org.bytedeco.javacpp;
requires protobuf;
requires resources;
requires slf4j.api;
requires deeplearning4j.nn;
requires jackson;
requires nd4j.api;
requires nd4j.common;
requires org.bytedeco.hdf5;
exports org.deeplearning4j.frameworkimport.keras.keras;
exports org.deeplearning4j.frameworkimport.keras.keras.config;
exports org.deeplearning4j.frameworkimport.keras.keras.exceptions;
exports org.deeplearning4j.frameworkimport.keras.keras.layers;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.advanced.activations;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.convolutional;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.core;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.custom;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.embeddings;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.local;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.noise;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.normalization;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.pooling;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.recurrent;
exports org.deeplearning4j.frameworkimport.keras.keras.layers.wrappers;
exports org.deeplearning4j.frameworkimport.keras.keras.preprocessing.sequence;
exports org.deeplearning4j.frameworkimport.keras.keras.preprocessing.text;
exports org.deeplearning4j.frameworkimport.keras.keras.preprocessors;
exports org.deeplearning4j.frameworkimport.keras.keras.utils;
}