chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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>
|
||||
+457
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+514
@@ -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()));
|
||||
}
|
||||
}
|
||||
+658
@@ -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;
|
||||
}
|
||||
}
|
||||
+379
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+269
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
# Keras model import
|
||||
+113
@@ -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";
|
||||
|
||||
}
|
||||
+112
@@ -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";
|
||||
}
|
||||
+378
@@ -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
|
||||
|
||||
}
|
||||
+41
@@ -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();
|
||||
}
|
||||
}
|
||||
+53
@@ -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";
|
||||
|
||||
}
|
||||
+41
@@ -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";
|
||||
}
|
||||
}
|
||||
+41
@@ -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.";
|
||||
}
|
||||
}
|
||||
+215
@@ -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;
|
||||
}
|
||||
}
|
||||
+128
@@ -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]);
|
||||
}
|
||||
}
|
||||
+78
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+113
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+165
@@ -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(){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+93
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+163
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+96
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+143
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+134
@@ -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]);
|
||||
}
|
||||
}
|
||||
+135
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+159
@@ -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;
|
||||
}
|
||||
}
|
||||
+222
@@ -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);
|
||||
}
|
||||
}
|
||||
+149
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+147
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+602
@@ -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;
|
||||
}
|
||||
}
|
||||
+95
@@ -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]);
|
||||
}
|
||||
}
|
||||
+98
@@ -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]);
|
||||
}
|
||||
}
|
||||
+95
@@ -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]);
|
||||
}
|
||||
}
|
||||
+143
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+143
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+231
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+217
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+93
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+97
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -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]);
|
||||
}
|
||||
}
|
||||
+104
@@ -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]);
|
||||
}
|
||||
}
|
||||
+101
@@ -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]);
|
||||
}
|
||||
}
|
||||
+86
@@ -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;
|
||||
}
|
||||
}
|
||||
+174
@@ -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);
|
||||
}
|
||||
}
|
||||
+89
@@ -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;
|
||||
}
|
||||
}
|
||||
+153
@@ -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];
|
||||
}
|
||||
}
|
||||
+92
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+100
@@ -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;
|
||||
}
|
||||
}
|
||||
+180
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+143
@@ -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]);
|
||||
}
|
||||
}
|
||||
+98
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+185
@@ -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]);
|
||||
}
|
||||
}
|
||||
+112
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -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]);
|
||||
}
|
||||
}
|
||||
+72
@@ -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);
|
||||
}
|
||||
}
|
||||
+236
@@ -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());
|
||||
}
|
||||
}
|
||||
+242
@@ -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());
|
||||
}
|
||||
}
|
||||
+181
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+181
@@ -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);
|
||||
}
|
||||
}
|
||||
+112
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+110
@@ -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;
|
||||
}
|
||||
}
|
||||
+109
@@ -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;
|
||||
}
|
||||
}
|
||||
+395
@@ -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();
|
||||
}
|
||||
}
|
||||
+132
@@ -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]);
|
||||
}
|
||||
}
|
||||
+104
@@ -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]);
|
||||
}
|
||||
}
|
||||
+105
@@ -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]);
|
||||
}
|
||||
}
|
||||
+101
@@ -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]);
|
||||
}
|
||||
}
|
||||
+167
@@ -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;
|
||||
}
|
||||
}
|
||||
+529
@@ -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;
|
||||
}
|
||||
}
|
||||
+93
@@ -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;
|
||||
}
|
||||
}
|
||||
+315
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+279
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+168
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+405
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -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
|
||||
}
|
||||
+83
@@ -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();
|
||||
}
|
||||
}
|
||||
+107
@@ -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();
|
||||
}
|
||||
}
|
||||
+116
@@ -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);
|
||||
}
|
||||
}
|
||||
+121
@@ -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;
|
||||
}
|
||||
}
|
||||
+234
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+709
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+113
@@ -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();
|
||||
}
|
||||
}
|
||||
+363
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+433
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+161
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
+68
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user