chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen;
|
||||
|
||||
import org.nd4j.codegen.api.NamespaceOps;
|
||||
import org.nd4j.codegen.ops.*;
|
||||
|
||||
public enum Namespace {
|
||||
BITWISE,
|
||||
NEURALNETWORK,
|
||||
RANDOM,
|
||||
IMAGE,
|
||||
CNN,
|
||||
RNN,
|
||||
MATH,
|
||||
BASE,
|
||||
LOSS,
|
||||
LINALG;
|
||||
|
||||
|
||||
public static Namespace fromString(String in){
|
||||
switch (in.toLowerCase()){
|
||||
case "bitwise":
|
||||
return BITWISE;
|
||||
case "nn":
|
||||
case "neuralnetwork":
|
||||
return NEURALNETWORK;
|
||||
case "random":
|
||||
return RANDOM;
|
||||
case "math":
|
||||
return MATH;
|
||||
case "image":
|
||||
return IMAGE;
|
||||
case "cnn":
|
||||
return CNN;
|
||||
case "rnn":
|
||||
return RNN;
|
||||
case "base":
|
||||
return BASE;
|
||||
case "loss":
|
||||
return LOSS;
|
||||
case "linalg":
|
||||
return LINALG;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String javaClassName() {
|
||||
switch (this){
|
||||
case BITWISE:
|
||||
return "NDBitwise";
|
||||
case NEURALNETWORK:
|
||||
return "NDNN";
|
||||
case RANDOM:
|
||||
return "NDRandom";
|
||||
case IMAGE:
|
||||
return "NDImage";
|
||||
case CNN:
|
||||
return "NDCNN";
|
||||
case RNN:
|
||||
return "NDRNN";
|
||||
case MATH:
|
||||
return "NDMath";
|
||||
case BASE:
|
||||
return "NDBase";
|
||||
case LOSS:
|
||||
return "NDLoss";
|
||||
case LINALG:
|
||||
return "NDLinalg";
|
||||
}
|
||||
throw new IllegalStateException("No java class name defined for: " + this);
|
||||
}
|
||||
|
||||
public String javaSameDiffClassName() {
|
||||
switch (this){
|
||||
case BITWISE:
|
||||
return "SDBitwise";
|
||||
case NEURALNETWORK:
|
||||
return "SDNN";
|
||||
case RANDOM:
|
||||
return "SDRandom";
|
||||
case IMAGE:
|
||||
return "SDImage";
|
||||
case CNN:
|
||||
return "SDCNN";
|
||||
case RNN:
|
||||
return "SDRNN";
|
||||
case MATH:
|
||||
return "SDMath";
|
||||
case BASE:
|
||||
return "SDBaseOps";
|
||||
case LOSS:
|
||||
return "SDLoss";
|
||||
/*case VALIDATION:
|
||||
return "SDValidation";*/
|
||||
case LINALG:
|
||||
return "SDLinalg";
|
||||
}
|
||||
throw new IllegalStateException("No java SameDiff class name defined for: " + this);
|
||||
}
|
||||
|
||||
public NamespaceOps getNamespace() {
|
||||
switch (this){
|
||||
case BITWISE:
|
||||
return BitwiseKt.Bitwise();
|
||||
case RANDOM:
|
||||
return RandomKt.Random();
|
||||
case MATH:
|
||||
return MathKt.Math();
|
||||
case IMAGE:
|
||||
return ImageKt.SDImage();
|
||||
case CNN:
|
||||
return CNNKt.SDCNN();
|
||||
case RNN:
|
||||
return RNNKt.SDRNN();
|
||||
case NEURALNETWORK:
|
||||
return NeuralNetworkKt.NN();
|
||||
case BASE:
|
||||
return SDBaseOpsKt.SDBaseOps();
|
||||
case LOSS:
|
||||
return SDLossKt.SDLoss();
|
||||
case LINALG:
|
||||
return LinalgKt.Linalg();
|
||||
}
|
||||
throw new IllegalStateException("No namespace definition available for: " + this);
|
||||
}
|
||||
}
|
||||
@@ -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.nd4j.codegen.cli;
|
||||
|
||||
import com.beust.jcommander.IParameterValidator;
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nd4j.codegen.Namespace;
|
||||
import org.nd4j.codegen.api.NamespaceOps;
|
||||
import org.nd4j.codegen.impl.java.DocsGenerator;
|
||||
import org.nd4j.codegen.impl.java.Nd4jNamespaceGenerator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Planned CLI for generating classes
|
||||
*/
|
||||
@Slf4j
|
||||
public class CLI {
|
||||
private static final String relativePath = "nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/";
|
||||
private static final String allProjects = "all";
|
||||
private static final String sdProject = "sd";
|
||||
private static final String ndProject = "nd4j";
|
||||
|
||||
public static class ProjectsValidator implements IParameterValidator {
|
||||
|
||||
@Override
|
||||
public void validate(String name, String value) throws ParameterException {
|
||||
if (name.equals("-projects")) {
|
||||
if (!(value.equals(allProjects) || value.equals(ndProject) || value.equals(sdProject))) {
|
||||
throw new ParameterException("Wrong projects " + value + " passed! Must be one of [all, sd, nd4j]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Parameter(names = "-dir", description = "Root directory of deeplearning4j mono repo")
|
||||
private String repoRootDir;
|
||||
|
||||
@Parameter(names = "-docsdir", description = "Root directory for generated docs")
|
||||
private String docsdir;
|
||||
|
||||
@Parameter(names = "-namespaces", description = "List of namespaces to generate, or 'ALL' to generate all namespaces", required = true)
|
||||
private List<String> namespaces;
|
||||
|
||||
@Parameter(names = "-projects", description = "List of sub-projects - ND4J, SameDiff or both", required = false, validateWith = ProjectsValidator.class)
|
||||
private List<String> projects = Collections.singletonList("all");
|
||||
|
||||
enum NS_PROJECT {
|
||||
ND4J,
|
||||
SAMEDIFF;
|
||||
}
|
||||
|
||||
private void generateNamespaces(NS_PROJECT project, File outputDir, String basePackage) throws IOException {
|
||||
|
||||
List<Namespace> usedNamespaces = new ArrayList<>();
|
||||
|
||||
for(String s : namespaces) {
|
||||
if ("all".equalsIgnoreCase(s)) {
|
||||
Collections.addAll(usedNamespaces, Namespace.values());
|
||||
break;
|
||||
}
|
||||
Namespace ns = null;
|
||||
if (project == NS_PROJECT.ND4J) {
|
||||
ns = Namespace.fromString(s);
|
||||
if (ns == null) {
|
||||
log.error("Invalid/unknown ND4J namespace provided: " + s);
|
||||
}
|
||||
else {
|
||||
usedNamespaces.add(ns);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ns = Namespace.fromString(s);
|
||||
if (ns == null) {
|
||||
log.error("Invalid/unknown SD namespace provided: " + s);
|
||||
}
|
||||
else {
|
||||
usedNamespaces.add(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < usedNamespaces.size(); ++i) {
|
||||
Namespace ns = usedNamespaces.get(i);
|
||||
log.info("Starting generation of namespace: {}", ns);
|
||||
|
||||
String javaClassName = project == NS_PROJECT.ND4J ? ns.javaClassName() : ns.javaSameDiffClassName();
|
||||
NamespaceOps ops = ns.getNamespace();
|
||||
|
||||
String basePackagePath = basePackage.replace(".", "/") + "/ops/";
|
||||
|
||||
if (StringUtils.isNotEmpty(docsdir)) {
|
||||
DocsGenerator.generateDocs(i, ops, docsdir, basePackage);
|
||||
}
|
||||
if (outputDir != null) {
|
||||
File outputPath = new File(outputDir, basePackagePath + javaClassName + ".java");
|
||||
log.info("Output path: {}", outputPath.getAbsolutePath());
|
||||
|
||||
if (NS_PROJECT.ND4J == project)
|
||||
Nd4jNamespaceGenerator.generate(ops, null, outputDir, javaClassName, basePackage, docsdir);
|
||||
else
|
||||
Nd4jNamespaceGenerator.generate(ops, null, outputDir, javaClassName, basePackage,
|
||||
"org.nd4j.autodiff.samediff.ops.SDOps", docsdir);
|
||||
}
|
||||
++cnt;
|
||||
}
|
||||
log.info("Complete - generated {} namespaces", cnt);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new CLI().runMain(args);
|
||||
}
|
||||
|
||||
public void runMain(String[] args) throws Exception {
|
||||
JCommander.newBuilder()
|
||||
.addObject(this)
|
||||
.build()
|
||||
.parse(args);
|
||||
|
||||
// Either root directory for source code generation or docs directory must be present. If root directory is
|
||||
// absenbt - then it's "generate docs only" mode.
|
||||
if (StringUtils.isEmpty(repoRootDir) && StringUtils.isEmpty(docsdir)) {
|
||||
throw new IllegalStateException("Provide one or both of arguments : -dir, -docsdir");
|
||||
}
|
||||
File outputDir = null;
|
||||
if (StringUtils.isNotEmpty(repoRootDir)) {
|
||||
//First: Check root directory.
|
||||
File dir = new File(repoRootDir);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException("Provided root directory does not exist (or not a directory): " + dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
outputDir = new File(dir, relativePath);
|
||||
if (!outputDir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException("Expected output directory does not exist: " + outputDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
if(namespaces == null || namespaces.isEmpty()){
|
||||
throw new IllegalStateException("No namespaces were provided");
|
||||
}
|
||||
|
||||
try {
|
||||
if (projects == null)
|
||||
projects.add(allProjects);
|
||||
boolean forAllProjects = projects.isEmpty() || projects.contains(allProjects);
|
||||
if (forAllProjects || projects.contains(ndProject)) {
|
||||
generateNamespaces(NS_PROJECT.ND4J, outputDir, "org.nd4j.linalg.factory");
|
||||
}
|
||||
if (forAllProjects || projects.contains(sdProject)) {
|
||||
generateNamespaces(NS_PROJECT.SAMEDIFF, outputDir, "org.nd4j.autodiff.samediff");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.cli;
|
||||
|
||||
import com.beust.jcommander.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nd4j.autodiff.samediff.SDVariable;
|
||||
import org.nd4j.codegen.Namespace;
|
||||
import org.nd4j.codegen.api.LossReduce;
|
||||
import org.nd4j.linalg.api.buffer.DataType;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Planned CLI for generating classes
|
||||
*/
|
||||
@Slf4j
|
||||
public class PicoCliCodeGen {
|
||||
private static final String relativePath = "nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/";
|
||||
private static final String allProjects = "all";
|
||||
|
||||
|
||||
@Parameter(names = "-dir", description = "Root directory of deeplearning4j mono repo")
|
||||
private String repoRootDir;
|
||||
|
||||
@Parameter(names = "-docsdir", description = "Root directory for generated docs")
|
||||
private String docsdir;
|
||||
|
||||
@Parameter(names = "-namespaces", description = "List of namespaces to generate, or 'ALL' to generate all namespaces", required = true)
|
||||
private List<String> namespaces;
|
||||
|
||||
|
||||
|
||||
private void generateNamespaces() {
|
||||
|
||||
List<Namespace> usedNamespaces = new ArrayList<>();
|
||||
|
||||
for (String s : namespaces) {
|
||||
if ("all".equalsIgnoreCase(s)) {
|
||||
Collections.addAll(usedNamespaces, Namespace.values());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
CommandLine.Model.CommandSpec commandSpec = CommandLine.Model.CommandSpec.create();
|
||||
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < usedNamespaces.size(); ++i) {
|
||||
Namespace ns = usedNamespaces.get(i);
|
||||
CommandLine.Model.CommandSpec subCommand = CommandLine.Model.CommandSpec.create();
|
||||
commandSpec.addSubcommand(ns.name(), subCommand);
|
||||
ns.getNamespace().getOps().forEach(op -> {
|
||||
CommandLine.Model.CommandSpec commandSpec1 = CommandLine.Model.CommandSpec.create();
|
||||
subCommand.addSubcommand(op.name(), commandSpec1);
|
||||
op.inputs().forEach(input -> {
|
||||
//TODO: Add SDVariable converter for picocli and figure out where to put that converter
|
||||
commandSpec1.addOption(CommandLine.Model.OptionSpec.builder("--" + input.getName())
|
||||
.type(SDVariable.class)
|
||||
.required(true)
|
||||
.description(input.getDescription())
|
||||
.build());
|
||||
});
|
||||
|
||||
op.getArgs().forEach(arg -> {
|
||||
CommandLine.Model.OptionSpec.Builder builder = CommandLine.Model.OptionSpec.builder("--" + arg.getName())
|
||||
.description(arg.getDescription());
|
||||
|
||||
switch (arg.getType()) {
|
||||
case INT:
|
||||
builder.type(Integer.class);
|
||||
break;
|
||||
case BOOL:
|
||||
builder.type(Boolean.class);
|
||||
break;
|
||||
case ENUM:
|
||||
break;
|
||||
case LONG:
|
||||
builder.type(Long.class);
|
||||
break;
|
||||
case STRING:
|
||||
builder.type(String.class);
|
||||
break;
|
||||
case NDARRAY:
|
||||
break;
|
||||
case NUMERIC:
|
||||
break;
|
||||
case CONDITION:
|
||||
break;
|
||||
case DATA_TYPE:
|
||||
builder.type(DataType.class);
|
||||
break;
|
||||
case LOSS_REDUCE:
|
||||
builder.type(LossReduce.class);
|
||||
break;
|
||||
case FLOATING_POINT:
|
||||
break;
|
||||
}
|
||||
|
||||
builder.required(arg.getDefaultValue() == null);
|
||||
|
||||
if (arg.getDefaultValue() != null) {
|
||||
builder.defaultValue(arg.getDefaultValue().toString());
|
||||
}
|
||||
|
||||
commandSpec1.addOption(builder.build());
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
log.info("Starting generation of namespace: {}", ns);
|
||||
|
||||
++cnt;
|
||||
}
|
||||
|
||||
|
||||
log.info("Complete - generated {} namespaces", cnt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new CLI().runMain(args);
|
||||
}
|
||||
|
||||
public void runMain(String[] args) throws Exception {
|
||||
JCommander.newBuilder()
|
||||
.addObject(this)
|
||||
.build()
|
||||
.parse(args);
|
||||
|
||||
// Either root directory for source code generation or docs directory must be present. If root directory is
|
||||
// absenbt - then it's "generate docs only" mode.
|
||||
if (StringUtils.isEmpty(repoRootDir) && StringUtils.isEmpty(docsdir)) {
|
||||
throw new IllegalStateException("Provide one or both of arguments : -dir, -docsdir");
|
||||
}
|
||||
|
||||
File outputDir = null;
|
||||
if (StringUtils.isNotEmpty(repoRootDir)) {
|
||||
//First: Check root directory.
|
||||
File dir = new File(repoRootDir);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException("Provided root directory does not exist (or not a directory): " + dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
outputDir = new File(dir, relativePath);
|
||||
if (!outputDir.exists() || !dir.isDirectory()) {
|
||||
throw new IllegalStateException("Expected output directory does not exist: " + outputDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
if(namespaces == null || namespaces.isEmpty() ) {
|
||||
throw new IllegalStateException("No namespaces were provided");
|
||||
}
|
||||
|
||||
generateNamespaces();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.cpp;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.nd4j.codegen.api.*;
|
||||
import org.nd4j.codegen.api.generator.Generator;
|
||||
import org.nd4j.codegen.api.generator.GeneratorConfig;
|
||||
import org.nd4j.codegen.util.GenUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A very simple, manual CPP generator
|
||||
* As per Python, this could be implemented using a templating library such as freemarker
|
||||
*/
|
||||
public class CppGenerator implements Generator {
|
||||
@Override
|
||||
public Language language() {
|
||||
return Language.CPP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNamespaceNd4j(NamespaceOps namespace, GeneratorConfig config, File directory, String fileName) throws IOException {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("#include <NDArrayFactory.h>\n\n")
|
||||
.append("namespace nd4j {\n");
|
||||
|
||||
append(4, sb, "namespace " + namespace.getName().toLowerCase());
|
||||
|
||||
List<Op> ops = new ArrayList<>();
|
||||
for(Op o : namespace.getOps()){
|
||||
if(o.isAbstract())
|
||||
continue;
|
||||
ops.add(o);
|
||||
}
|
||||
|
||||
//TODO: handle includes
|
||||
|
||||
for(Op o : ops){
|
||||
String s = generateFunction(o);
|
||||
sb.append(GenUtil.addIndent(s, 8));
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
append(4, sb, "}");
|
||||
sb.append("}");
|
||||
|
||||
//TODO generate header also
|
||||
|
||||
String out = sb.toString();
|
||||
File outFile = new File(directory, GenUtil.ensureFirstIsCap(namespace.getName()) + ".cpp");
|
||||
FileUtils.writeStringToFile(outFile, out, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
protected static void append(int indent, StringBuilder sb, String line){
|
||||
sb.append(GenUtil.repeat(" ", indent))
|
||||
.append(line)
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
protected static String generateFunction(Op op){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
List<Output> outputs = op.getOutputs();
|
||||
boolean singleOut = outputs.size() == 1;
|
||||
if(singleOut){
|
||||
sb.append("NDArray* ");
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Multi-output op generation not yet implemented");
|
||||
}
|
||||
|
||||
sb.append(GenUtil.ensureFirstIsNotCap(op.getOpName())).append("(");
|
||||
|
||||
//Add inputs to signature
|
||||
boolean firstArg = true;
|
||||
if(op.getInputs() != null){
|
||||
for(Input i : op.getInputs()){
|
||||
if(!firstArg)
|
||||
sb.append(", ");
|
||||
|
||||
sb.append("NDArray* ").append(i.getName());
|
||||
|
||||
firstArg = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Add arguments and default args to signature
|
||||
sb.append("):\n");
|
||||
|
||||
|
||||
sb.append(" Context c(1);\n");
|
||||
int j=0;
|
||||
for(Input i : op.getInputs()){
|
||||
sb.append(" c.setInputArray(").append(j++).append(", ").append(i.getName()).append(");\n");
|
||||
}
|
||||
|
||||
sb.append("\n //TODO: args\n\n");
|
||||
|
||||
|
||||
sb.append(" nd4j::ops::").append(op.getLibnd4jOpName()).append(" op;\n");
|
||||
|
||||
sb.append(" ShapeList shapeList({");
|
||||
j = 0;
|
||||
for(Input i : op.getInputs()){
|
||||
if(j > 0)
|
||||
sb.append(",");
|
||||
sb.append(i.getName());
|
||||
j++;
|
||||
}
|
||||
|
||||
sb.append("});\n\n")
|
||||
.append(" auto outShape = op.calculateOutputShape(&shapeList, c);\n");
|
||||
|
||||
sb.append(" auto out = nullptr; //TODO\n\n")
|
||||
.append(" op.exec(c);\n")
|
||||
.append(" delete shapes;\n");
|
||||
|
||||
sb.append(" return out;\n")
|
||||
.append("}\n");
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNamespaceSameDiff(NamespaceOps namespace, GeneratorConfig config, File directory, String fileName) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.java;
|
||||
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nd4j.codegen.api.*;
|
||||
import org.nd4j.codegen.api.doc.DocSection;
|
||||
import org.nd4j.codegen.api.doc.DocTokens;
|
||||
import org.nd4j.codegen.util.GenUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import static org.nd4j.codegen.impl.java.Nd4jNamespaceGenerator.exactlyOne;
|
||||
|
||||
public class DocsGenerator {
|
||||
|
||||
// Markdown marker for start-end of code section
|
||||
private static final String MD_CODE = "```";
|
||||
// Javadoc constants which should be dropped or replaced for markdown generation
|
||||
private static final String JD_CODE = "{@code ";
|
||||
private static final String JD_CODE_END = "}";
|
||||
private static final String JD_INPUT_TYPE = "%INPUT_TYPE%";
|
||||
|
||||
public static class JavaDocToMDAdapter {
|
||||
private String current;
|
||||
|
||||
public JavaDocToMDAdapter(String original) {
|
||||
this.current = original;
|
||||
}
|
||||
|
||||
public JavaDocToMDAdapter filter(String pattern, String replaceWith) {
|
||||
String result = StringUtils.replace(current, pattern, replaceWith);
|
||||
this.current = result;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMethodText(Op op, Signature s, boolean isSameDiff, boolean isLoss, boolean withName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
MethodSpec.Builder c = MethodSpec.methodBuilder(GenUtil.ensureFirstIsNotCap(op.getOpName()));
|
||||
List<Parameter> params = s.getParameters();
|
||||
List<Output> outs = op.getOutputs();
|
||||
String retType = "void";
|
||||
|
||||
if (outs.size() == 1) {
|
||||
retType = isSameDiff ? "SDVariable" : "INDArray";
|
||||
}
|
||||
else if (outs.size() >= 1) {
|
||||
retType = isSameDiff ? "SDVariable[]" : "INDArray[]";
|
||||
}
|
||||
sb.append(retType).append(" ").append(op.getOpName()).append("(");
|
||||
boolean first = true;
|
||||
for (Parameter param : params) {
|
||||
if (param instanceof Arg) {
|
||||
Arg arg = (Arg) param;
|
||||
if (!first)
|
||||
sb.append(", ");
|
||||
else if (withName)
|
||||
sb.append("String name, ");
|
||||
String className;
|
||||
if(arg.getType() == DataType.ENUM) {
|
||||
className = GenUtil.ensureFirstIsCap(arg.name());
|
||||
} else {
|
||||
TypeName tu = Nd4jNamespaceGenerator.getArgType(arg);
|
||||
className = tu.toString();
|
||||
}
|
||||
if(className.contains(".")){
|
||||
className = className.substring(className.lastIndexOf('.')+1);
|
||||
}
|
||||
sb.append(className).append(" ").append(arg.name());
|
||||
first = false;
|
||||
}
|
||||
else if (param instanceof Input) {
|
||||
Input arg = (Input) param;
|
||||
if (!first)
|
||||
sb.append(", ");
|
||||
else if (withName)
|
||||
sb.append("String name, ");
|
||||
sb.append(isSameDiff ? "SDVariable " : "INDArray ").append(arg.name());
|
||||
first = false;
|
||||
} else if(param instanceof Config){
|
||||
if(!first)
|
||||
sb.append(", ");
|
||||
Config conf = (Config)param;
|
||||
String name = conf.getName();
|
||||
sb.append(name).append(" ").append(GenUtil.ensureFirstIsNotCap(name));
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static StringBuilder buildDocSectionText(List<DocSection> docSections) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DocSection ds : docSections) {
|
||||
//if(ds.applies(Language.JAVA, CodeComponent.OP_CREATOR)){
|
||||
String text = ds.getText();
|
||||
String[] lines = text.split("\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (!lines[i].endsWith("<br>")) {
|
||||
String filteredLine = new JavaDocToMDAdapter(lines[i])
|
||||
.filter(JD_CODE, "`")
|
||||
.filter(JD_CODE_END, "`")
|
||||
.filter(JD_INPUT_TYPE, "INDArray").toString();
|
||||
|
||||
lines[i] = filteredLine + System.lineSeparator();
|
||||
}
|
||||
}
|
||||
text = String.join("\n", lines);
|
||||
sb.append(text).append(System.lineSeparator());
|
||||
//}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static void generateDocs(int namespaceNum, NamespaceOps namespace, String docsDirectory, String basePackage) throws IOException {
|
||||
File outputDirectory = new File(docsDirectory);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String headerName = namespace.getName();
|
||||
if(headerName.startsWith("SD"))
|
||||
headerName = headerName.substring(2);
|
||||
|
||||
// File Header for Gitbook
|
||||
sb.append("---").append(System.lineSeparator());
|
||||
sb.append("title: ").append(headerName).append(System.lineSeparator());
|
||||
sb.append("short_title: ").append(headerName).append(System.lineSeparator());
|
||||
sb.append("description: ").append(System.lineSeparator());
|
||||
sb.append("category: Operations").append(System.lineSeparator());
|
||||
sb.append("weight: ").append(namespaceNum * 10).append(System.lineSeparator());
|
||||
sb.append("---").append(System.lineSeparator());
|
||||
|
||||
List<Op> ops = namespace.getOps();
|
||||
|
||||
ops.sort(Comparator.comparing(Op::getOpName));
|
||||
|
||||
if (ops.size() > 0)
|
||||
sb.append("# Operation classes").append(System.lineSeparator());
|
||||
for (Op op : ops) {
|
||||
sb.append("## ").append(op.getOpName()).append(System.lineSeparator());
|
||||
List<DocSection> doc = op.getDoc();
|
||||
if(!doc.isEmpty()) {
|
||||
boolean first = true;
|
||||
StringBuilder ndSignatures = new StringBuilder();
|
||||
StringBuilder sdSignatures = new StringBuilder();
|
||||
StringBuilder sdNameSignatures = new StringBuilder();
|
||||
for(Signature s : op.getSignatures()) {
|
||||
if (first) {
|
||||
Language lang = doc.get(0).getLanguage();
|
||||
sb.append(MD_CODE).append(lang.equals(Language.ANY) ? Language.JAVA : lang).append(System.lineSeparator());
|
||||
first = false;
|
||||
}
|
||||
String ndCode = generateMethodText(op, s, false, false, false);
|
||||
ndSignatures.append(ndCode).append(System.lineSeparator());
|
||||
String sdCode = generateMethodText(op, s, true, false, false);
|
||||
sdSignatures.append(sdCode).append(System.lineSeparator());
|
||||
String withNameCode = generateMethodText(op, s, true, false, true);
|
||||
sdNameSignatures.append(withNameCode).append(System.lineSeparator());
|
||||
}
|
||||
sb.append(ndSignatures.toString());
|
||||
sb.append(System.lineSeparator()); // New line between INDArray and SDVariable signatures
|
||||
|
||||
sb.append(sdSignatures.toString());
|
||||
sb.append(sdNameSignatures.toString());
|
||||
|
||||
sb.append(MD_CODE).append(System.lineSeparator());
|
||||
StringBuilder tsb = buildDocSectionText(doc);
|
||||
sb.append(tsb.toString());
|
||||
List<Signature> l = op.getSignatures();
|
||||
Set<Parameter> alreadySeen = new HashSet<>();
|
||||
for(Signature s : l) {
|
||||
List<Parameter> params = s.getParameters();
|
||||
for (Parameter p : params) {
|
||||
if(alreadySeen.contains(p)) continue;
|
||||
alreadySeen.add(p);
|
||||
if(p instanceof Input){
|
||||
Input i = (Input)p;
|
||||
sb.append("* **").append(i.getName()).append("** ").append(" (").append(i.getType()).append(") - ").append(i.getDescription() == null ? "" : DocTokens.processDocText(i.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)).append(System.lineSeparator());
|
||||
}
|
||||
else if (p instanceof Config) {
|
||||
Config c = (Config)p;
|
||||
sb.append("* **").append(c.getName()).append("** - see ").append("[").append(c.getName()).append("]").append("(#").append(toAnchor(c.getName())).append(")").append(System.lineSeparator());
|
||||
}
|
||||
else if(p instanceof Arg) {
|
||||
Arg arg = (Arg) p;
|
||||
final Count count = arg.getCount();
|
||||
if (count == null || count.equals(exactlyOne)) {
|
||||
sb.append("* **").append(arg.getName()).append("** - ").append(arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)); //.append(System.lineSeparator());
|
||||
} else {
|
||||
sb.append("* **").append(arg.getName()).append("** - ").append(arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)).append(" (Size: ").append(count.toString()).append(")"); //.append(System.lineSeparator());
|
||||
}
|
||||
|
||||
Object defaultValue = arg.defaultValue();
|
||||
if(defaultValue != null){
|
||||
sb.append(" - default = ").append(formatDefaultValue(defaultValue));
|
||||
}
|
||||
|
||||
sb.append(System.lineSeparator());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(System.lineSeparator());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (namespace.getConfigs().size() > 0)
|
||||
sb.append("# Configuration Classes").append(System.lineSeparator());
|
||||
for (Config config : namespace.getConfigs()) {
|
||||
sb.append("## ").append(config.getName()).append(System.lineSeparator());
|
||||
for (Input i : config.getInputs()) {
|
||||
sb.append("* **").append(i.getName()).append("**- ").append(i.getDescription()).append(" (").append(i.getType()).append(" type)");
|
||||
if (i.hasDefaultValue() && (i.defaultValue() != null))
|
||||
sb.append(" Default value:").append(formatDefaultValue(i.defaultValue())).append(System.lineSeparator());
|
||||
else
|
||||
sb.append(System.lineSeparator());
|
||||
}
|
||||
for (Arg arg : config.getArgs()) {
|
||||
sb.append("* **").append(arg.getName()).append("** ").append("(").append(arg.getType()).append(") - ").append(arg.getDescription());
|
||||
if (arg.hasDefaultValue() && (arg.defaultValue() != null))
|
||||
sb.append(" - default = ").append(formatDefaultValue(arg.defaultValue())).append(System.lineSeparator());
|
||||
else
|
||||
sb.append(System.lineSeparator());
|
||||
}
|
||||
StringBuilder tsb = buildDocSectionText(config.getDoc());
|
||||
sb.append(tsb.toString());
|
||||
sb.append(System.lineSeparator());
|
||||
for (Op op : ops) {
|
||||
if (op.getConfigs().contains(config)) {
|
||||
sb.append("Used in these ops: " + System.lineSeparator());
|
||||
break;
|
||||
}
|
||||
}
|
||||
ops.stream().filter(op -> op.getConfigs().contains(config)).forEach(op ->
|
||||
sb.append("[").append(op.getOpName()).append("]").append("(#").append(toAnchor(op.getOpName())).append(")").
|
||||
append(System.lineSeparator()));
|
||||
|
||||
}
|
||||
File outFile = new File(outputDirectory + "/operation-namespaces", "/" + namespace.getName().toLowerCase() + ".md");
|
||||
FileUtils.writeStringToFile(outFile, sb.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static String formatDefaultValue(Object v){
|
||||
if(v == null){ return "null"; }
|
||||
else if(v instanceof int[]){ return Arrays.toString((int[]) v); }
|
||||
else if(v instanceof long[]){ return Arrays.toString((long[]) v); }
|
||||
else if(v instanceof float[]){ return Arrays.toString((float[]) v); }
|
||||
else if(v instanceof double[]){ return Arrays.toString((double[]) v); }
|
||||
else if(v instanceof boolean[]){ return Arrays.toString((boolean[]) v); }
|
||||
else if(v instanceof Input){ return ((Input)v).getName(); }
|
||||
else if(v instanceof org.nd4j.linalg.api.buffer.DataType){ return "DataType." + v; }
|
||||
else if(v instanceof LossReduce || v instanceof org.nd4j.autodiff.loss.LossReduce){ return "LossReduce." + v; }
|
||||
else return v.toString();
|
||||
}
|
||||
|
||||
private static String toAnchor(String name){
|
||||
int[] codepoints = name.toLowerCase().codePoints().toArray();
|
||||
int type = Character.getType(codepoints[0]);
|
||||
StringBuilder anchor = new StringBuilder(new String(Character.toChars(codepoints[0])));
|
||||
for (int i = 1; i < codepoints.length; i++) {
|
||||
int curType = Character.getType(codepoints[i]);
|
||||
if(curType != type){
|
||||
anchor.append("-");
|
||||
}
|
||||
type = curType;
|
||||
anchor.append(new String(Character.toChars(codepoints[i])));
|
||||
}
|
||||
return anchor.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.java;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nd4j.codegen.api.Language;
|
||||
import org.nd4j.codegen.api.NamespaceOps;
|
||||
import org.nd4j.codegen.api.generator.Generator;
|
||||
import org.nd4j.codegen.api.generator.GeneratorConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class JavaPoetGenerator implements Generator {
|
||||
|
||||
|
||||
@Override
|
||||
public Language language() {
|
||||
return Language.JAVA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNamespaceNd4j(NamespaceOps namespace, GeneratorConfig config, File directory, String className) throws java.io.IOException {
|
||||
Nd4jNamespaceGenerator.generate(namespace, config, directory, className, "org.nd4j.linalg.factory", StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNamespaceSameDiff(NamespaceOps namespace, GeneratorConfig config, File directory, String className) throws java.io.IOException {
|
||||
//throw new UnsupportedOperationException("Not yet implemented");
|
||||
Nd4jNamespaceGenerator.generate(namespace, config, directory, className, "org.nd4j.autodiff.samediff", StringUtils.EMPTY);
|
||||
}
|
||||
}
|
||||
+989
@@ -0,0 +1,989 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.java;
|
||||
|
||||
import com.squareup.javapoet.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.nd4j.autodiff.samediff.SDVariable;
|
||||
import org.nd4j.autodiff.samediff.SameDiff;
|
||||
import org.nd4j.autodiff.samediff.ops.SDOps;
|
||||
import org.nd4j.autodiff.samediff.ops.SDValidation;
|
||||
import org.nd4j.codegen.api.*;
|
||||
import org.nd4j.codegen.api.doc.DocSection;
|
||||
import org.nd4j.codegen.api.doc.DocTokens;
|
||||
import org.nd4j.codegen.api.generator.ConstraintCodeGenerator;
|
||||
import org.nd4j.codegen.api.generator.GeneratorConfig;
|
||||
import org.nd4j.codegen.util.GenUtil;
|
||||
import org.nd4j.common.base.Preconditions;
|
||||
import org.nd4j.linalg.api.ndarray.INDArray;
|
||||
import org.nd4j.linalg.factory.NDValidation;
|
||||
import org.nd4j.linalg.factory.Nd4j;
|
||||
import org.nd4j.linalg.indexing.conditions.Condition;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class Nd4jNamespaceGenerator {
|
||||
private static Map<DataType, Class<?>> typeMapping = new HashMap<>();
|
||||
private static Map<DataType, String> validationMapping = new HashMap<>();
|
||||
private static Map<Arg, TypeName> enumMapping = new HashMap<>();
|
||||
private static Map<Config, TypeName> configMapping = new HashMap<>();
|
||||
public static Count exactlyOne = new Exactly(1);
|
||||
private static String copyright =
|
||||
"/*\n" +
|
||||
" * ******************************************************************************\n" +
|
||||
" * *\n" +
|
||||
" * *\n" +
|
||||
" * * This program and the accompanying materials are made available under the\n" +
|
||||
" * * terms of the Apache License, Version 2.0 which is available at\n" +
|
||||
" * * https://www.apache.org/licenses/LICENSE-2.0.\n" +
|
||||
" * *\n" +
|
||||
" * * See the NOTICE file distributed with this work for additional\n" +
|
||||
" * * information regarding copyright ownership.\n" +
|
||||
" * * Unless required by applicable law or agreed to in writing, software\n" +
|
||||
" * * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n" +
|
||||
" * * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n" +
|
||||
" * * License for the specific language governing permissions and limitations\n" +
|
||||
" * * under the License.\n" +
|
||||
" * *\n" +
|
||||
" * * SPDX-License-Identifier: Apache-2.0\n" +
|
||||
" * *****************************************************************************\n" +
|
||||
" */\n";
|
||||
private static String codeGenWarning =
|
||||
"\n//================== GENERATED CODE - DO NOT MODIFY THIS FILE ==================\n\n";
|
||||
|
||||
static {
|
||||
typeMapping.put(DataType.BOOL, boolean.class);
|
||||
typeMapping.put(DataType.FLOATING_POINT, double.class);
|
||||
typeMapping.put(DataType.NUMERIC, double.class);
|
||||
typeMapping.put(DataType.INT, int.class);
|
||||
typeMapping.put(DataType.LONG, long.class);
|
||||
typeMapping.put(DataType.DATA_TYPE, org.nd4j.linalg.api.buffer.DataType.class);
|
||||
typeMapping.put(DataType.LOSS_REDUCE, org.nd4j.autodiff.loss.LossReduce.class);
|
||||
typeMapping.put(DataType.CONDITION, Condition.class);
|
||||
typeMapping.put(DataType.STRING, String.class);
|
||||
|
||||
validationMapping.put(DataType.BOOL, "validateBool");
|
||||
validationMapping.put(DataType.FLOATING_POINT, "validateFloatingPoint");
|
||||
validationMapping.put(DataType.NUMERIC, "validateNumerical");
|
||||
validationMapping.put(DataType.INT, "validateInteger");
|
||||
validationMapping.put(DataType.LONG, "validateInteger");
|
||||
}
|
||||
|
||||
private static ConstraintCodeGenerator constraintCodeGenerator = new JavaConstraintCodeGenerator();
|
||||
|
||||
private Nd4jNamespaceGenerator() { }
|
||||
|
||||
public static void generate(NamespaceOps namespace, GeneratorConfig config, File outputDirectory, String className,
|
||||
String basePackage, String docsDirectory) throws IOException {
|
||||
//String basePackage = "org.nd4j.linalg.factory";
|
||||
|
||||
generateEnums(outputDirectory, basePackage);
|
||||
generateConfigs(outputDirectory, basePackage);
|
||||
try {
|
||||
generateOpFactory(namespace, outputDirectory, className, basePackage, StringUtils.EMPTY);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void generate(NamespaceOps namespace, GeneratorConfig config, File outputDirectory, String className,
|
||||
String basePackage, String parentClass, String docsDirectory) throws IOException {
|
||||
//String basePackage = "org.nd4j.linalg.factory";
|
||||
|
||||
generateEnums(outputDirectory, basePackage);
|
||||
generateConfigs(outputDirectory, basePackage);
|
||||
try {
|
||||
generateOpFactory(namespace, outputDirectory, className, basePackage, parentClass);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateOpFactory(NamespaceOps namespace, File outputDirectory, String className, String basePackage,
|
||||
String parentClass) throws IOException, ClassNotFoundException {
|
||||
boolean isBaseSameDiff = StringUtils.equals("SDBaseOps", className);
|
||||
boolean isSameDiff = StringUtils.isNotEmpty(parentClass);
|
||||
boolean isLoss = StringUtils.equals("SDLoss", className);
|
||||
|
||||
TypeSpec.Builder builder = !isSameDiff || isBaseSameDiff ?
|
||||
TypeSpec.classBuilder(className)
|
||||
.addModifiers(Modifier.PUBLIC) :
|
||||
|
||||
TypeSpec.classBuilder(className)
|
||||
.superclass(Class.forName(parentClass))
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
if (isSameDiff && !isBaseSameDiff) {
|
||||
addSameDiffConstructor(builder);
|
||||
}
|
||||
else if (isBaseSameDiff) {
|
||||
builder.addField(TypeName.get(SameDiff.class), "sd", Modifier.PROTECTED);
|
||||
addBaseSameDiffConstructor(builder);
|
||||
}
|
||||
else
|
||||
addDefaultConstructor(builder);
|
||||
|
||||
//Add ops
|
||||
namespace.getOps()
|
||||
.stream()
|
||||
.filter(it -> !it.isAbstract())
|
||||
.sorted(Comparator.comparing(Op::getOpName))
|
||||
.forEachOrdered(o -> generateMethods(builder, o, isSameDiff, isLoss));
|
||||
|
||||
|
||||
TypeSpec ts = builder.build();
|
||||
|
||||
final String opsPackage = basePackage + ".ops";
|
||||
JavaFile jf = StringUtils.isEmpty(parentClass) ?
|
||||
|
||||
JavaFile.builder(opsPackage, ts)
|
||||
.addStaticImport(NDValidation.class, "isSameType")
|
||||
.build() :
|
||||
|
||||
JavaFile.builder(opsPackage, ts)
|
||||
.addStaticImport(SDValidation.class, "isSameType")
|
||||
.build();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(copyright);
|
||||
sb.append(codeGenWarning);
|
||||
jf.writeTo(sb);
|
||||
|
||||
File outFile = new File(outputDirectory, packageToDirectory(opsPackage) + "/" + className + ".java");
|
||||
FileUtils.writeStringToFile(outFile, sb.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static String packageToDirectory(String packageName){
|
||||
return packageName.replace(".", File.separator);
|
||||
}
|
||||
|
||||
private static void addDefaultConstructor(TypeSpec.Builder builder) {
|
||||
//Add private no-arg constructor
|
||||
MethodSpec noArg = MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.build();
|
||||
|
||||
builder.addMethod(noArg);
|
||||
}
|
||||
|
||||
private static void addBaseSameDiffConstructor(TypeSpec.Builder builder) {
|
||||
|
||||
MethodSpec ctor = MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(SameDiff.class, "sameDiff")
|
||||
.addStatement("this.sd = sameDiff")
|
||||
.build();
|
||||
|
||||
builder.addMethod(ctor);
|
||||
}
|
||||
|
||||
private static void addSameDiffConstructor(TypeSpec.Builder builder) {
|
||||
MethodSpec ctor = MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(SameDiff.class, "sameDiff")
|
||||
.addStatement("super(sameDiff)")
|
||||
.build();
|
||||
|
||||
builder.addMethod(ctor);
|
||||
}
|
||||
|
||||
private static void generateMethods(TypeSpec.Builder builder, Op op, boolean isSameDiff, boolean isLoss ){
|
||||
List<Signature> l = op.getSignatures();
|
||||
for(Signature s : l){
|
||||
builder.addMethod(signatureCreatorMethod(op, s, isSameDiff, false, isLoss));
|
||||
if (isSameDiff)
|
||||
builder.addMethod(signatureCreatorMethod(op, s, true, true, isLoss));
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodSpec signatureCreatorMethod(Op op, Signature s, boolean isSameDiff, boolean withName,
|
||||
boolean isLoss){
|
||||
MethodSpec.Builder c = MethodSpec.methodBuilder(GenUtil.ensureFirstIsNotCap(op.getOpName()))
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
enableVarargsOnLastArg(c, op, s);
|
||||
|
||||
buildJavaDoc(op, s, c, withName);
|
||||
List<String> inNames = buildParameters(c, op, s, isSameDiff, withName);
|
||||
buildConstraints(c, op.getConstraints());
|
||||
buildExecution(c, op, inNames, isSameDiff, withName, isLoss);
|
||||
|
||||
return c.build();
|
||||
}
|
||||
|
||||
private static void buildJavaDoc(Op op, Signature s, MethodSpec.Builder c, boolean withName) {
|
||||
//Method javadoc:
|
||||
List<DocSection> doc = op.getDoc();
|
||||
if(!doc.isEmpty()){
|
||||
for(DocSection ds : doc){
|
||||
if(ds.applies(Language.JAVA, CodeComponent.OP_CREATOR)){
|
||||
String text = DocTokens.processDocText(ds.getText(), op, DocTokens.GenerationType.ND4J);
|
||||
//Add <br> tags at the end of each line, where none already exists
|
||||
String[] lines = text.split("\n");
|
||||
for( int i = 0; i < lines.length; i++) {
|
||||
if(!lines[i].endsWith("<br>")){
|
||||
lines[i] = lines[i] + "<br>";
|
||||
}
|
||||
}
|
||||
text = String.join("\n", lines);
|
||||
c.addJavadoc(text + "\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Document Constraints:
|
||||
//TODO what if constraint is on default value arg/s - no point specifying them here...
|
||||
final List<Constraint> constraints = op.getConstraints();
|
||||
if(!constraints.isEmpty()){
|
||||
c.addJavadoc("Inputs must satisfy the following constraints: <br>\n");
|
||||
for (Constraint constraint : constraints) {
|
||||
c.addJavadoc(constraint.getMessage() +": " + constraintCodeGenerator.generateExpression(constraint.getCheck()) + "<br>\n");
|
||||
}
|
||||
|
||||
c.addJavadoc("\n");
|
||||
}
|
||||
if (withName) {
|
||||
if (op.getOutputs().size() == 1 && !op.getOutputs().get(0).getMultiOutput())
|
||||
c.addJavadoc("@param name name May be null. Name for the output variable\n");
|
||||
else
|
||||
c.addJavadoc("@param names names May be null. Arrays of names for the output variables.\n");
|
||||
}
|
||||
List<Parameter> params = s.getParameters();
|
||||
if(!params.isEmpty()){
|
||||
for(Parameter p : params){
|
||||
if(p instanceof Input){
|
||||
Input i = (Input)p;
|
||||
c.addJavadoc("@param " + i.getName() + " " + (i.getDescription() == null ? "" : DocTokens.processDocText(i.getDescription(), op, DocTokens.GenerationType.ND4J)) + " (" + i.getType() + " type)\n");
|
||||
} else if(p instanceof Arg) {
|
||||
Arg arg = (Arg) p;
|
||||
final Count count = arg.getCount();
|
||||
if (count == null || count.equals(exactlyOne)) {
|
||||
c.addJavadoc("@param " + arg.getName() + " " + (arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(), op, DocTokens.GenerationType.ND4J)) + "\n");
|
||||
} else {
|
||||
c.addJavadoc("@param " + arg.getName() + " " + (arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(), op, DocTokens.GenerationType.ND4J)) + " (Size: " + count.toString() + ")\n");
|
||||
}
|
||||
} else if(p instanceof Config){
|
||||
Config config = (Config) p;
|
||||
c.addJavadoc("@param " + config.getName() + " Configuration Object\n");
|
||||
} else {
|
||||
throw new RuntimeException("Unknown parameter type: " + p + " - " + p.getClass() + " - op = " + op.getOpName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Outputs:
|
||||
List<Output> outputs = op.getOutputs();
|
||||
if(!outputs.isEmpty()){
|
||||
if(outputs.size() == 1 && !outputs.get(0).getMultiOutput()){
|
||||
Output o = outputs.get(0);
|
||||
c.addJavadoc("@return " + o.getName() + " " + (o.getDescription() == null ? "" : DocTokens.processDocText(o.getDescription(), op, DocTokens.GenerationType.ND4J)) + " (" + o.getType() + " type)\n");
|
||||
} else {
|
||||
//throw new UnsupportedOperationException("Javadoc for multi-output ops not yet implemented");
|
||||
log.error("Javadoc for multi-output ops not yet implemented");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> buildParameters(MethodSpec.Builder c, Op op, Signature s, boolean isSameDiff, boolean withName) {
|
||||
List<String> inNames = new ArrayList<>();
|
||||
|
||||
List<Parameter> params = s.getParameters();
|
||||
|
||||
if(op.getArgsFirst()){
|
||||
//Assuming sort is stable (doesn't change order of equal elements)
|
||||
params.sort((p1,p2) -> Boolean.compare(p1 instanceof Input, p2 instanceof Input));
|
||||
}
|
||||
|
||||
if (withName) {
|
||||
if (op.getOutputs().size() == 1 && !op.getOutputs().get(0).getMultiOutput())
|
||||
c.addParameter(String.class, "name");
|
||||
else
|
||||
c.addParameter(String[].class, "names");
|
||||
}
|
||||
if(!params.isEmpty()){
|
||||
int pCount = 0;
|
||||
for(Parameter p : params){
|
||||
pCount++;
|
||||
boolean isLast = pCount == params.size();
|
||||
if(p instanceof Input){
|
||||
Input i = (Input)p;
|
||||
final String inputName = i.getName();
|
||||
inNames.add(inputName);
|
||||
|
||||
final Count count = i.getCount();
|
||||
if(count == null || count.equals(exactlyOne)) {
|
||||
//Single input
|
||||
if (isSameDiff)
|
||||
c.addParameter(SDVariable.class, inputName);
|
||||
else
|
||||
c.addParameter(INDArray.class, inputName);
|
||||
} else {
|
||||
//Array input
|
||||
if (isSameDiff)
|
||||
c.addParameter(SDVariable[].class, inputName).varargs(isLast);
|
||||
else
|
||||
c.addParameter(INDArray[].class, inputName).varargs(isLast);
|
||||
}
|
||||
// Check for parameter types
|
||||
final DataType paramType = i.getType();
|
||||
String validationName = validationMapping.get(paramType);
|
||||
if(validationName != null) {
|
||||
c.addStatement(CodeBlock.of("$T.$L($S, $S, $L)", isSameDiff ? SDValidation.class : NDValidation.class, validationName, op.getOpName(), inputName, inputName));
|
||||
}
|
||||
checkParameterCount(c, count, inputName);
|
||||
} else if(p instanceof Arg){
|
||||
Arg arg = (Arg)p;
|
||||
final String argName = arg.getName();
|
||||
if(argName.isEmpty()){
|
||||
throw new IllegalStateException("Got null argument name for op " + op.getOpName());
|
||||
}
|
||||
inNames.add(argName);
|
||||
|
||||
|
||||
final Count count = arg.getCount();
|
||||
TypeName type = getArgType(arg);
|
||||
if(type == null){
|
||||
throw new IllegalStateException("No type mapping has been specified for type " + arg.getType() + " (op=" + op.getOpName() + ", arg=" + arg.getName() + ")" );
|
||||
}
|
||||
c.addParameter(type, argName);
|
||||
|
||||
checkParameterCount(c, count, argName);
|
||||
} else if(p instanceof Config) {
|
||||
Config config = (Config) p;
|
||||
final String configName = config.getName();
|
||||
inNames.add(configName);
|
||||
c.addParameter(configMapping.get(config), config.name());
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown parameter type: " + p + " - " + p.getClass());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return inNames;
|
||||
}
|
||||
|
||||
public static TypeName getArgType(Arg arg) {
|
||||
DataType argType = arg.getType();
|
||||
Count count = arg.getCount();
|
||||
TypeName type;
|
||||
if(argType == DataType.ENUM){
|
||||
type = enumMapping.get(arg);
|
||||
if(type == null){
|
||||
throw new IllegalStateException(arg + " is using an unregistered ENUM. This is probably a bug.");
|
||||
}
|
||||
}else{
|
||||
if(!typeMapping.containsKey(argType)){
|
||||
return null;
|
||||
}
|
||||
type = TypeName.get(typeMapping.get(argType));
|
||||
}
|
||||
|
||||
if (!(count == null || count.equals(exactlyOne))) {
|
||||
// array Arg
|
||||
type = ArrayTypeName.of(type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void buildConstraints(MethodSpec.Builder c, List<Constraint> constraints) {
|
||||
if(constraints.isEmpty())
|
||||
return;
|
||||
|
||||
//TODO not all contsraints apply to all signatures?
|
||||
|
||||
// Don't materialize the Backend Constraints
|
||||
for (Constraint constraint : constraints.stream().filter(it -> !(it instanceof BackendConstraint)).collect(Collectors.toList())) {
|
||||
c.addStatement(CodeBlock.of("$T.checkArgument($L, $S)", Preconditions.class, constraintCodeGenerator.generateExpression(constraint.getCheck()), constraint.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildExecution(MethodSpec.Builder c, Op op, List<String> inNames, boolean isSameDiff,
|
||||
boolean withName, boolean isLoss) {
|
||||
boolean singleOut = op.getOutputs().size() == 1 && !op.getOutputs().get(0).getMultiOutput();
|
||||
if(singleOut){
|
||||
if (isSameDiff)
|
||||
c.returns(SDVariable.class);
|
||||
else
|
||||
c.returns(INDArray.class);
|
||||
} else {
|
||||
if (isSameDiff)
|
||||
c.returns(SDVariable[].class);
|
||||
else
|
||||
c.returns(INDArray[].class);
|
||||
}
|
||||
|
||||
// We have to pass all parameters, always. But not all signatures will be taking all parameters.
|
||||
// inNames tells us which parameters this signatures has. For all others we want to pass default values
|
||||
List<String> parameters = op.allParameters().stream().sorted(
|
||||
(p1,p2) -> {
|
||||
if (p1.isVararg()) return 1;
|
||||
else if (p2.isVararg()) return -1;
|
||||
return 0;
|
||||
}
|
||||
).map(it -> {
|
||||
if(inNames.contains(it.name())){
|
||||
return it.name();
|
||||
}else{
|
||||
if(!it.hasDefaultValue()) throw new IllegalStateException("The parameter "+it.name()+" has no default value, but is also not part of "+inNames.toString());
|
||||
return anyToCode(it, it.defaultValue());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
//Op execution:
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (isSameDiff) {
|
||||
if (withName) {
|
||||
if (singleOut)
|
||||
sb.append("SDVariable out = ");
|
||||
else
|
||||
sb.append("SDVariable[] out = ");
|
||||
|
||||
sb.append(" new ")
|
||||
.append(op.getJavaPackage())
|
||||
.append(".")
|
||||
.append(op.getJavaOpClass() == null ? GenUtil.ensureFirstIsCap(op.getOpName()) : op.getJavaOpClass())
|
||||
.append("(sd,")
|
||||
.append(String.join(", ", parameters))
|
||||
.append(")");
|
||||
|
||||
if (singleOut)
|
||||
sb.append(".outputVariable()");
|
||||
else
|
||||
sb.append(".outputVariables()");
|
||||
|
||||
c.addStatement(sb.toString());
|
||||
if (isLoss)
|
||||
c.addStatement("out.markAsLoss()");
|
||||
|
||||
if (singleOut)
|
||||
c.addStatement("return sd.updateVariableNameAndReference(out, name)");
|
||||
else
|
||||
c.addStatement("return sd.updateVariableNamesAndReferences(out, names)");
|
||||
}
|
||||
else {
|
||||
if (isLoss) {
|
||||
sb.append("SDVariable out = new ")
|
||||
.append(op.getJavaPackage())
|
||||
.append(".")
|
||||
.append(op.getJavaOpClass() == null ? GenUtil.ensureFirstIsCap(op.getOpName()) : op.getJavaOpClass())
|
||||
.append("(sd,")
|
||||
.append(String.join(", ", parameters))
|
||||
.append(")");
|
||||
}
|
||||
else {
|
||||
sb.append("return new ")
|
||||
.append(op.getJavaPackage())
|
||||
.append(".")
|
||||
.append(op.getJavaOpClass() == null ? GenUtil.ensureFirstIsCap(op.getOpName()) : op.getJavaOpClass())
|
||||
.append("(sd,")
|
||||
.append(String.join(", ", parameters))
|
||||
.append(")");
|
||||
}
|
||||
//if (!op.getLegacy()) {
|
||||
if (singleOut)
|
||||
sb.append(".outputVariable()");
|
||||
else
|
||||
sb.append(".outputVariables()");
|
||||
//}
|
||||
c.addStatement(sb.toString());
|
||||
if (isLoss) {
|
||||
c.addStatement("out.markAsLoss()");
|
||||
c.addStatement("return out");
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
sb.append("return $T.exec(new ")
|
||||
.append(op.getJavaPackage())
|
||||
.append(".")
|
||||
.append(op.getJavaOpClass() == null ? GenUtil.ensureFirstIsCap(op.getOpName()) : op.getJavaOpClass())
|
||||
.append("(")
|
||||
.append(String.join(", ", parameters))
|
||||
.append("))");
|
||||
if (!op.getLegacy() && singleOut) //Note: legacy ops Nd4j.exec(Op) returns INDArray; Nd4j.exec(CustomOp) returns INDArray[]
|
||||
sb.append("[0]");
|
||||
|
||||
c.addStatement(sb.toString(), Nd4j.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static void enableVarargsOnLastArg(MethodSpec.Builder c, Op op, Signature s) {
|
||||
List<Parameter> p = s.getParameters();
|
||||
if(!p.isEmpty()){
|
||||
Parameter lastP = p.get(p.size() - 1);
|
||||
if (lastP instanceof Arg) {
|
||||
Arg arg = (Arg) lastP;
|
||||
final Count count = arg.getCount();
|
||||
if (count != null && !count.equals(exactlyOne)) {
|
||||
c.varargs(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String countToJava(Count count,String paramName) {
|
||||
final String paramLength = paramName + ".length";
|
||||
if(count instanceof Exactly){
|
||||
return paramLength + " == " + ((Exactly) count).getCount();
|
||||
}else if(count instanceof AtLeast){
|
||||
return paramLength + " >= " + ((AtLeast) count).getMin();
|
||||
}else if(count instanceof AtMost){
|
||||
return paramLength + " <= "+ ((AtMost) count).getMax();
|
||||
}else if(count instanceof Range){
|
||||
return ((Range) count).getFrom() + " <= " + paramLength + " && " + paramLength + " <= " + ((Range) count).getTo();
|
||||
}else{
|
||||
throw new IllegalArgumentException("Can not deal with Count of type " + count.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkParameterCount(MethodSpec.Builder c, Count count, String paramName) {
|
||||
// Check for parameter counts
|
||||
if(count != null && !count.equals(exactlyOne)){
|
||||
final String errorMessage = paramName + " has incorrect size/length. Expected: " + countToJava(count, paramName) + ", got %s";
|
||||
if(count instanceof Exactly){
|
||||
c.addStatement(CodeBlock.of("$T.checkArgument($L.length == $L, $S, $L)", Preconditions.class, paramName, ((Exactly) count).getCount(), errorMessage, paramName + ".length"));
|
||||
}else if(count instanceof AtLeast){
|
||||
c.addStatement(CodeBlock.of("$T.checkArgument($L.length >= $L, $S, $L)", Preconditions.class, paramName, ((AtLeast) count).getMin(), errorMessage, paramName + ".length"));
|
||||
}else if(count instanceof AtMost){
|
||||
c.addStatement(CodeBlock.of("$T.checkArgument($L.length <= $L, $S, $L)", Preconditions.class, paramName, ((AtMost) count).getMax(), errorMessage, paramName + ".length"));
|
||||
}else if(count instanceof Range){
|
||||
c.addStatement(CodeBlock.of("$T.checkArgument($L.length >= $L && $L.length <= $L, $S, $L)", Preconditions.class, paramName, ((Range) count).getFrom(), paramName, ((Range) count).getTo(), errorMessage, paramName + ".length"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateEnums(File outputDirectory, String basePackage) throws IOException {
|
||||
for (Arg it : Registry.INSTANCE.enums()) {
|
||||
generateEnum(outputDirectory, "org.nd4j.enums", it);
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMethodText(Op op, Signature s, boolean isSameDiff, boolean isLoss, boolean withName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
MethodSpec.Builder c = MethodSpec.methodBuilder(GenUtil.ensureFirstIsNotCap(op.getOpName()));
|
||||
List<Parameter> params = s.getParameters();
|
||||
List<Output> outs = op.getOutputs();
|
||||
String retType = "void";
|
||||
|
||||
if (outs.size() == 1) {
|
||||
retType = isSameDiff ? "SDVariable" : "INDArray";
|
||||
}
|
||||
else if (outs.size() >= 1) {
|
||||
retType = isSameDiff ? "SDVariable[]" : "INDArray[]";
|
||||
}
|
||||
sb.append(retType + " " + op.getOpName() + "(");
|
||||
boolean first = true;
|
||||
for (Parameter param : params) {
|
||||
if (param instanceof Arg) {
|
||||
Arg arg = (Arg) param;
|
||||
if (!first)
|
||||
sb.append(",");
|
||||
else if (withName)
|
||||
sb.append("String name,");
|
||||
TypeName tu = getArgType(arg);
|
||||
sb.append(tu.toString() + " " + arg.name());
|
||||
first = false;
|
||||
}
|
||||
else if (param instanceof Input) {
|
||||
Input arg = (Input) param;
|
||||
if (!first)
|
||||
sb.append(",");
|
||||
else if (withName)
|
||||
sb.append("String name,");
|
||||
sb.append((isSameDiff ? "SDVariable " : "INDArray ") + arg.name());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static StringBuilder buildDocSectionText(List<DocSection> docSections) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DocSection ds : docSections) {
|
||||
//if(ds.applies(Language.JAVA, CodeComponent.OP_CREATOR)){
|
||||
String text = ds.getText();
|
||||
String[] lines = text.split("\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (!lines[i].endsWith("<br>")) {
|
||||
lines[i] = lines[i] + System.lineSeparator();
|
||||
}
|
||||
}
|
||||
text = String.join("\n", lines);
|
||||
sb.append(text + System.lineSeparator());
|
||||
//}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static void generateDocs(NamespaceOps namespace, File outputDirectory, String basePackage) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("# Namespace " + namespace.getName() + System.lineSeparator());
|
||||
List<Op> ops = namespace.getOps();
|
||||
for (Op op : ops) {
|
||||
sb.append("## <a name=" + "\"").append(op.name()).append("\">").append(op.name()).append("</a>").append(System.lineSeparator());
|
||||
List<DocSection> doc = op.getDoc();
|
||||
if(!doc.isEmpty()) {
|
||||
boolean first = true;
|
||||
for(Signature s : op.getSignatures()) {
|
||||
if (first) {
|
||||
sb.append("````" + doc.get(0).getLanguage() + System.lineSeparator());
|
||||
first = false;
|
||||
}
|
||||
String ndCode = generateMethodText(op, s, false, false, false);
|
||||
sb.append(ndCode).append(System.lineSeparator());
|
||||
String sdCode = generateMethodText(op, s, true, false, false);
|
||||
sb.append(sdCode).append(System.lineSeparator());
|
||||
String withNameCode = generateMethodText(op, s, true, false, true);
|
||||
sb.append(withNameCode).append(System.lineSeparator());
|
||||
}
|
||||
sb.append("````").append(System.lineSeparator());
|
||||
StringBuilder tsb = buildDocSectionText(doc);
|
||||
sb.append(tsb.toString());
|
||||
List<Signature> l = op.getSignatures();
|
||||
for(Signature s : l) {
|
||||
List<Parameter> params = s.getParameters();
|
||||
for (Parameter p : params) {
|
||||
if(p instanceof Input){
|
||||
Input i = (Input)p;
|
||||
sb.append("* " + i.getName() + " " + (i.getDescription() == null ? "" : DocTokens.processDocText(i.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)) + " (" + i.getType() + " type)" + System.lineSeparator());
|
||||
} else if(p instanceof Arg) {
|
||||
Arg arg = (Arg) p;
|
||||
final Count count = arg.getCount();
|
||||
if (count == null || count.equals(exactlyOne)) {
|
||||
sb.append("* " + arg.getName() + " " + (arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)) + System.lineSeparator());
|
||||
} else {
|
||||
sb.append("* " + arg.getName() + " " + (arg.getDescription() == null ? "" : DocTokens.processDocText(arg.getDescription(),
|
||||
op, DocTokens.GenerationType.ND4J)) + " (Size: " + count.toString() + System.lineSeparator());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(System.lineSeparator());
|
||||
tsb = buildDocSectionText(doc);
|
||||
sb.append(tsb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
for (Config config : Registry.INSTANCE.configs()) {
|
||||
sb.append("## " + config.getName() + System.lineSeparator());
|
||||
boolean first = true;
|
||||
for (Input i : config.getInputs()) {
|
||||
if (first) {
|
||||
sb.append("````" + System.lineSeparator());
|
||||
first = false;
|
||||
}
|
||||
sb.append("* " + i.getName() + " " + i.getDescription() + " (" + i.getType() + " type)" + System.lineSeparator());
|
||||
}
|
||||
for (Arg arg : config.getArgs()) {
|
||||
if (first) {
|
||||
sb.append("````" + System.lineSeparator());
|
||||
first = false;
|
||||
}
|
||||
sb.append("* " + arg.getName() + " " + " (" + arg.getType() + " type)" + System.lineSeparator());
|
||||
}
|
||||
StringBuilder tsb = buildDocSectionText(config.getDoc());
|
||||
sb.append(tsb.toString());
|
||||
sb.append("````" + System.lineSeparator());
|
||||
ops.stream().filter(op -> op.getConfigs().contains(config)).forEach(op ->
|
||||
sb.append("[" + op.getOpName() + "]" + "(#" + op.getOpName() + ")" + System.lineSeparator()));
|
||||
}
|
||||
File outFile = new File(outputDirectory + "/ops", "/namespace-" + namespace.getName() + ".md");
|
||||
FileUtils.writeStringToFile(outFile, sb.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static void generateEnum(File outputDirectory, String targetPackage, Arg arg) throws IOException {
|
||||
final String className = GenUtil.ensureFirstIsCap(arg.name());
|
||||
enumMapping.put(arg, ClassName.get(targetPackage, className));
|
||||
|
||||
TypeSpec.Builder builder = TypeSpec.enumBuilder(className)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addJavadoc(CodeBlock.of(arg.getDescription()));
|
||||
|
||||
for (String possibleValue : arg.getPossibleValues()) {
|
||||
builder.addEnumConstant(possibleValue);
|
||||
}
|
||||
|
||||
TypeSpec ts = builder.build();
|
||||
|
||||
JavaFile jf = JavaFile.builder(targetPackage, ts)
|
||||
.build();
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(copyright);
|
||||
sb.append(codeGenWarning);
|
||||
jf.writeTo(sb);
|
||||
|
||||
File outFile = new File(outputDirectory, packageToDirectory(targetPackage) + "/" + className + ".java");
|
||||
FileUtils.writeStringToFile(outFile, sb.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static void generateConfigs(File outputDirectory, String basePackage) throws IOException {
|
||||
for (Config config : Registry.INSTANCE.configs()) {
|
||||
generateConfig(outputDirectory, basePackage+".configs", config);
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateConfig(File outputDirectory, String targetPackage, Config config) throws IOException {
|
||||
if(config.getJavaClassOverride() != null && !config.getJavaClassOverride().isEmpty()){
|
||||
//Java class override means "don't generate, use the existing one instead"
|
||||
String c = config.getJavaClassOverride();
|
||||
int idx = c.lastIndexOf('.');
|
||||
String pkg = c.substring(0,idx);
|
||||
String className = c.substring(idx+1);
|
||||
configMapping.put(config, ClassName.get(pkg, className));
|
||||
return;
|
||||
}
|
||||
|
||||
final String className = GenUtil.ensureFirstIsCap(config.name());
|
||||
configMapping.put(config, ClassName.get(targetPackage, className));
|
||||
|
||||
// Build Config Builder Class
|
||||
final TypeSpec.Builder sdb = TypeSpec.classBuilder("SdBuilder").addModifiers(Modifier.STATIC, Modifier.PUBLIC);
|
||||
final TypeSpec.Builder ndb = TypeSpec.classBuilder("NdBuilder").addModifiers(Modifier.STATIC, Modifier.PUBLIC);
|
||||
|
||||
for (Input input : config.getInputs()) {
|
||||
addConfigBuilderParam(className, sdb, input.getName(), input.getType(), getType(TypeName.get(SDVariable.class), input.getCount()), input.getDescription(), input.getCount());
|
||||
addConfigBuilderParam(className, ndb, input.getName(), input.getType(), getType(TypeName.get(INDArray.class), input.getCount()), input.getDescription(), input.getCount());
|
||||
}
|
||||
|
||||
for (Arg arg : config.getArgs()) {
|
||||
addConfigBuilderParam(className, sdb, arg.getName(), null, getArgType(arg), arg.getDescription(), arg.getCount());
|
||||
addConfigBuilderParam(className, ndb, arg.getName(), null, getArgType(arg), arg.getDescription(), arg.getCount());
|
||||
}
|
||||
|
||||
ArrayList<String> parts = new ArrayList<>();
|
||||
ArrayList<Object> parameters = new ArrayList<>();
|
||||
for (Input input : config.getInputs()) {
|
||||
parts.add("$L");
|
||||
parameters.add(
|
||||
input.hasDefaultValue() ?
|
||||
input.name() + " == null ? " + ((Input)input.defaultValue()).getName() +" : "+input.name()
|
||||
: input.name()
|
||||
); }
|
||||
for (Arg input : config.getArgs()) {
|
||||
parts.add("$L");
|
||||
parameters.add(
|
||||
input.hasDefaultValue() ?
|
||||
input.name() + " == null ? " + anyToCode(input, input.defaultValue()) +" : "+input.name()
|
||||
: input.name()
|
||||
);
|
||||
}
|
||||
parameters.add(0, className);
|
||||
|
||||
final MethodSpec.Builder build = MethodSpec.methodBuilder("build")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.returns(ClassName.bestGuess(className));
|
||||
buildConstraints(build, config.getConstraints());
|
||||
build.addStatement("return new $N("+(String.join(", ", parts))+")", parameters.toArray());
|
||||
|
||||
sdb.addMethod(build.build());
|
||||
ndb.addMethod(build.build());
|
||||
|
||||
|
||||
final TypeSpec ndBuilder = ndb.build();
|
||||
final TypeSpec sdBuilder = sdb.build();
|
||||
|
||||
|
||||
// Build Config Holder Class
|
||||
TypeSpec.Builder holder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||
|
||||
final MethodSpec.Builder ndConstructorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE);
|
||||
final MethodSpec.Builder sdConstructorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE);
|
||||
|
||||
|
||||
for (Input input : config.getInputs()) {
|
||||
final String inputName = GenUtil.ensureFirstIsCap(input.getName());
|
||||
addConfigParam(holder, ndConstructorBuilder, "nd" + inputName, getType(TypeName.get(INDArray.class), input.getCount()), input.getDescription(), true);
|
||||
addConfigParam(holder, sdConstructorBuilder, "sd" + inputName, getType(TypeName.get(SDVariable.class), input.getCount()), input.getDescription(), true);
|
||||
}
|
||||
|
||||
for (Arg arg : config.getArgs()) {
|
||||
addConfigParam(holder, ndConstructorBuilder, arg.getName(), getArgType(arg), arg.getDescription(), true);
|
||||
addConfigParam(holder, sdConstructorBuilder, arg.getName(), getArgType(arg), arg.getDescription(), false);
|
||||
}
|
||||
holder.addMethod(sdConstructorBuilder.build());
|
||||
holder.addMethod(ndConstructorBuilder.build());
|
||||
|
||||
holder.addMethod(MethodSpec.methodBuilder("sdBuilder")
|
||||
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
|
||||
.addStatement("return new $N()", sdBuilder.name)
|
||||
.returns(ClassName.bestGuess(sdBuilder.name))
|
||||
.build());
|
||||
holder.addType(sdBuilder);
|
||||
holder.addMethod(MethodSpec.methodBuilder("ndBuilder")
|
||||
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
|
||||
.addStatement("return new $N()", ndBuilder.name)
|
||||
.returns(ClassName.bestGuess(ndBuilder.name))
|
||||
.build());
|
||||
holder.addType(ndBuilder);
|
||||
|
||||
// add javadoc
|
||||
//Method javadoc:
|
||||
List<DocSection> doc = config.getDoc();
|
||||
if(!doc.isEmpty()){
|
||||
for(DocSection ds : doc){
|
||||
if(ds.applies(Language.JAVA, CodeComponent.OP_CREATOR)){
|
||||
String text = ds.getText();
|
||||
//Add <br> tags at the end of each line, where none already exists
|
||||
String[] lines = text.split("\n");
|
||||
for( int i=0; i<lines.length; i++ ){
|
||||
if(!lines[i].endsWith("<br>")){
|
||||
lines[i] = lines[i] + "<br>";
|
||||
}
|
||||
}
|
||||
text = String.join("\n", lines);
|
||||
holder.addJavadoc(text + "\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Document Constraints:
|
||||
final List<Constraint> constraints = config.getConstraints();
|
||||
if(!constraints.isEmpty()){
|
||||
holder.addJavadoc("Inputs must satisfy the following constraints: <br>\n");
|
||||
for (Constraint constraint : constraints) {
|
||||
holder.addJavadoc(constraint.getMessage() +": " + constraintCodeGenerator.generateExpression(constraint.getCheck()) + "<br>\n");
|
||||
}
|
||||
|
||||
holder.addJavadoc("\n");
|
||||
}
|
||||
|
||||
TypeSpec ts = holder.build();
|
||||
|
||||
|
||||
JavaFile jf = JavaFile.builder(targetPackage, ts)
|
||||
.build();
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(copyright);
|
||||
sb.append(codeGenWarning);
|
||||
jf.writeTo(sb);
|
||||
|
||||
File outFile = new File(outputDirectory, packageToDirectory(targetPackage) + "/" + className + ".java");
|
||||
FileUtils.writeStringToFile(outFile, sb.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static void addConfigParam(TypeSpec.Builder builder, MethodSpec.Builder constructorBuilder, String paramName, TypeName paramType, String paramDescription, boolean addField) {
|
||||
if(addField){
|
||||
// Add param fields
|
||||
builder.addField(paramType, paramName, Modifier.PRIVATE);
|
||||
|
||||
// Add param getters
|
||||
builder.addMethod(generateGetter(paramType, paramName, paramDescription, false));
|
||||
}
|
||||
|
||||
// Add param constructor parameters
|
||||
constructorBuilder.addParameter(paramType, paramName, Modifier.FINAL);
|
||||
constructorBuilder.addStatement("this.$L = $L", paramName, paramName);
|
||||
}
|
||||
|
||||
private static void addConfigBuilderParam(String configClassName, TypeSpec.Builder builder, String paramName, DataType inputType, TypeName paramType, String paramDescription, Count count) {
|
||||
final String builderName = builder.build().name;
|
||||
// Add param fields
|
||||
builder.addField(paramType.box(), paramName, Modifier.PRIVATE);
|
||||
|
||||
// Add param getters
|
||||
builder.addMethod(generateGetter(paramType, paramName, paramDescription, true));
|
||||
|
||||
// Add param setter
|
||||
final MethodSpec.Builder setter = MethodSpec.methodBuilder(paramName)
|
||||
.addParameter(paramType, paramName)
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
checkParameterCount(setter, count, paramName);
|
||||
if(inputType != null){
|
||||
if(builderName.equals("SdBuilder")){
|
||||
setter.addStatement("$T.$L($S, $S, $L)", SDValidation.class, validationMapping.get(inputType), "Config: " + configClassName, paramName, paramName);
|
||||
}else if(builderName.equals("NdBuilder")){
|
||||
setter.addStatement("$T.$L($S, $S, $L)", NDValidation.class, validationMapping.get(inputType), "Config: " + configClassName, paramName, paramName);
|
||||
}else{
|
||||
throw new IllegalArgumentException("Unknown Builder Type "+builderName);
|
||||
}
|
||||
}
|
||||
setter.addStatement("this.$L = $L", paramName, paramName)
|
||||
.addStatement("return this")
|
||||
.returns(ClassName.bestGuess(builderName));
|
||||
|
||||
if(count != null && !count.equals(exactlyOne)){
|
||||
setter.varargs(true);
|
||||
}
|
||||
|
||||
if(paramDescription != null){
|
||||
setter.addJavadoc(paramDescription);
|
||||
}
|
||||
builder.addMethod(setter.build());
|
||||
}
|
||||
|
||||
private static TypeName getType(TypeName typeVariable, Count count) {
|
||||
if(count != null && !count.equals(exactlyOne)){
|
||||
return ArrayTypeName.of(typeVariable);
|
||||
}else{
|
||||
return typeVariable;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static MethodSpec generateGetter(TypeName typeVariable, String paramName, String paramDescription, boolean fluent) {
|
||||
final MethodSpec.Builder getter = MethodSpec.methodBuilder((fluent ? paramName : "get" + GenUtil.ensureFirstIsCap(paramName)))
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.returns(typeVariable);
|
||||
if(paramDescription != null){
|
||||
getter.addJavadoc(paramDescription);
|
||||
}
|
||||
getter.addStatement("return this.$L", paramName);
|
||||
return getter.build();
|
||||
}
|
||||
|
||||
private static String anyToCode(Parameter parameter, Object v){
|
||||
if(v == null){ return "null"; }
|
||||
else if(v instanceof int[]){ return "new int[]"+Arrays.toString((int[]) v).replace("[", "{").replace("]", "}"); }
|
||||
else if(v instanceof long[]){ return "new long[]"+Arrays.toString((long[]) v).replace("[", "{").replace("]", "}"); }
|
||||
else if(v instanceof float[]){ return "new float[]"+Arrays.toString((float[]) v).replace("[", "{").replace("]", "}"); }
|
||||
else if(v instanceof double[]){ return "new double[]"+Arrays.toString((double[]) v).replace("[", "{").replace("]", "}"); }
|
||||
else if(v instanceof boolean[]){ return "new boolean[]"+Arrays.toString((boolean[]) v).replace("[", "{").replace("]", "}"); }
|
||||
else if(v instanceof Input){ return ((Input)v).getName(); }
|
||||
else if(v instanceof org.nd4j.linalg.api.buffer.DataType){ return "DataType." + v; }
|
||||
else if(v instanceof LossReduce || v instanceof org.nd4j.autodiff.loss.LossReduce){ return "org.nd4j.autodiff.loss.LossReduce." + v; }
|
||||
else if(parameter instanceof Arg && ((Arg)parameter).getType() == DataType.ENUM){
|
||||
return GenUtil.ensureFirstIsCap(parameter.name()) + "." + v.toString();
|
||||
} else return v.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.python;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.nd4j.codegen.api.*;
|
||||
import org.nd4j.codegen.api.doc.DocTokens;
|
||||
import org.nd4j.codegen.api.generator.Generator;
|
||||
import org.nd4j.codegen.api.generator.GeneratorConfig;
|
||||
import org.nd4j.codegen.util.GenUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is a very simple, manual namespace generator
|
||||
* We could of course use a templating library such as Freemarker, which woudl work fine - but:
|
||||
* (a) on the one hand, it's overkill/unnecessary
|
||||
* (b) on the other hand, may provide less flexibility than a manual implementation
|
||||
*
|
||||
*/
|
||||
public class PythonGenerator implements Generator {
|
||||
|
||||
private static final String I4 = " ";
|
||||
|
||||
@Override
|
||||
public Language language() {
|
||||
return Language.PYTHON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNamespaceNd4j(NamespaceOps namespace, GeneratorConfig config, File directory, String fileName) throws IOException {
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class ").append(GenUtil.ensureFirstIsCap(namespace.getName())).append(":\n\n");
|
||||
|
||||
List<Op> ops = new ArrayList<>();
|
||||
for(Op o : namespace.getOps()){
|
||||
if(o.isAbstract())
|
||||
continue;
|
||||
ops.add(o);
|
||||
}
|
||||
|
||||
//TODO: handle includes
|
||||
|
||||
for(Op o : ops){
|
||||
String s = generateMethod(o);
|
||||
sb.append(GenUtil.addIndent(s, 4));
|
||||
sb.append("\n\n");
|
||||
}
|
||||
|
||||
File f = new File(directory, GenUtil.ensureFirstIsCap(namespace.getName()) + ".py");
|
||||
String content = sb.toString();
|
||||
|
||||
FileUtils.writeStringToFile(f, content, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
protected static String generateMethod(Op op){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("@staticmethod\n")
|
||||
.append("def ").append(GenUtil.ensureFirstIsNotCap(op.getOpName())).append("(");
|
||||
|
||||
//Add inputs to signature
|
||||
boolean firstArg = true;
|
||||
if(op.getInputs() != null){
|
||||
for(Input i : op.getInputs()){
|
||||
if(!firstArg)
|
||||
sb.append(", ");
|
||||
|
||||
sb.append(i.getName());
|
||||
|
||||
firstArg = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Add arguments and default args to signature
|
||||
|
||||
sb.append("):\n");
|
||||
|
||||
String docString = genDocString(op);
|
||||
sb.append(GenUtil.addIndent(docString, 4));
|
||||
|
||||
sb.append(I4).append("# Execution code here\n");
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected static String genDocString(Op op){
|
||||
//Following roughly: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\"\"\"")
|
||||
.append(op.getOpName())
|
||||
.append(" operation")
|
||||
.append("\n\n");
|
||||
if(op.getInputs() != null){
|
||||
sb.append("Args:");
|
||||
sb.append("\n");
|
||||
for(Input i : op.getInputs()){
|
||||
sb.append(I4).append(i.getName()).append(" (ndarray): ");
|
||||
if(i.getDescription() != null)
|
||||
sb.append(DocTokens.processDocText(i.getDescription(), op, DocTokens.GenerationType.ND4J));
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
|
||||
if(op.getOutputs() != null){
|
||||
sb.append("Returns:\n");
|
||||
List<Output> o = op.getOutputs();
|
||||
|
||||
if(o.size() == 1){
|
||||
sb.append(I4).append("ndarray: ").append(o.get(0).getName());
|
||||
String d = o.get(0).getDescription();
|
||||
if(d != null){
|
||||
sb.append(" - ").append(DocTokens.processDocText(d, op, DocTokens.GenerationType.ND4J));
|
||||
}
|
||||
sb.append("\n");
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Not yet implemented: Python docstring generation for multiple output ops");
|
||||
}
|
||||
}
|
||||
|
||||
if(op.getArgs() != null){
|
||||
//Args and default args
|
||||
throw new UnsupportedOperationException("Generating method with args not yet implemented");
|
||||
}
|
||||
|
||||
sb.append("\"\"\"\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void generateNamespaceSameDiff(NamespaceOps namespace, GeneratorConfig config, File directory, String fileName) throws IOException {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.util;
|
||||
|
||||
import org.nd4j.codegen.api.Op;
|
||||
|
||||
public class GenUtil {
|
||||
|
||||
private GenUtil(){ }
|
||||
|
||||
public static String ensureFirstIsCap(String in){
|
||||
if(Character.isUpperCase(in.charAt(0))){
|
||||
return in;
|
||||
}
|
||||
|
||||
return Character.toUpperCase(in.charAt(0)) + in.substring(1);
|
||||
}
|
||||
|
||||
public static String ensureFirstIsNotCap(String in){
|
||||
if(Character.isLowerCase(in.charAt(0))){
|
||||
return in;
|
||||
}
|
||||
|
||||
return Character.toLowerCase(in.charAt(0)) + in.substring(1);
|
||||
}
|
||||
|
||||
public static String repeat(String in, int count){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for( int i=0; i<count; i++ ){
|
||||
sb.append(in);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String addIndent(String in, int count){
|
||||
if(in == null)
|
||||
return null;
|
||||
String[] lines = in.split("\n");
|
||||
StringBuilder out = new StringBuilder();
|
||||
String indent = repeat(" ", count);
|
||||
for(String s : lines){
|
||||
out.append(indent).append(s).append("\n");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.util;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
public class JsonMapper {
|
||||
|
||||
public static ObjectMapper getMapper(){
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
// om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
om.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
|
||||
om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
om.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY);
|
||||
om.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.ANY);
|
||||
|
||||
return om;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
enum class CodeComponent { CLASS_DOC, CONSTRUCTOR, OP_CREATOR }
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
enum class DataType {
|
||||
NDARRAY, // Any NDArray type (input only) - INDArray or SDVariable
|
||||
FLOATING_POINT, // Any floating point data type
|
||||
INT, // integer data type
|
||||
LONG, //long, signed int64 datatype
|
||||
NUMERIC, // any floating point or integer data type
|
||||
BOOL, // boolean data type
|
||||
STRING, //String value
|
||||
// Arg only
|
||||
DATA_TYPE, // tensor data type
|
||||
CONDITION, // A condition
|
||||
LOSS_REDUCE, // Loss reduction mode
|
||||
ENUM; // defines an enum along with possibleValues property in Arg
|
||||
|
||||
fun isTensorDataType() = setOf(NDARRAY, FLOATING_POINT, INT, LONG, NUMERIC, BOOL).contains(this)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
enum class Language { ANY, JAVA, SCALA, KOTLIN, PYTHON, CPP }
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
/**
|
||||
* See org.nd4j.autodiff.los.LossReduce in nd4j for documentation.
|
||||
*/
|
||||
enum class LossReduce {
|
||||
NONE,
|
||||
SUM,
|
||||
MEAN_BY_WEIGHT,
|
||||
MEAN_BY_NONZERO_WEIGHT_COUNT
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
data class NamespaceOps @JvmOverloads constructor(
|
||||
var name: String,
|
||||
var include: MutableList<String>? = null,
|
||||
var ops: MutableList<Op> = mutableListOf(),
|
||||
var configs: MutableList<Config> = mutableListOf(),
|
||||
var parentNamespaceOps: Map<String,MutableList<Op>> = mutableMapOf()
|
||||
) {
|
||||
fun addConfig(config: Config) {
|
||||
configs.add(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that all required properties are set
|
||||
*/
|
||||
fun checkInvariants() {
|
||||
val usedConfigs = mutableSetOf<Config>()
|
||||
ops.forEach { op ->
|
||||
usedConfigs.addAll(op.configs)
|
||||
}
|
||||
val unusedConfigs = configs.toSet() - usedConfigs
|
||||
if(unusedConfigs.size > 0){
|
||||
throw IllegalStateException("Found unused configs: ${unusedConfigs.joinToString(", ") { it.name }}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get op by name
|
||||
*/
|
||||
fun op(name:String):Op {
|
||||
val op = ops.find { op -> op.opName.equals(name) } ?: throw java.lang.IllegalStateException("Operation $name not found")
|
||||
return op
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
import org.nd4j.codegen.api.doc.DocSection
|
||||
|
||||
interface OpLike {
|
||||
fun name(): String
|
||||
fun inputs(): List<Input>
|
||||
fun args(): List<Arg>
|
||||
fun configs(): List<Config>
|
||||
fun outputs(): List<Output>
|
||||
|
||||
fun allParameters(): List<Parameter>
|
||||
|
||||
fun addInput(input: Input)
|
||||
fun addArgument(arg: Arg)
|
||||
fun addOutput(output: Output)
|
||||
fun addDoc(docs: DocSection)
|
||||
fun addSignature(signature: Signature)
|
||||
fun addConstraint(constraint: Constraint)
|
||||
fun addConfig(config: Config)
|
||||
|
||||
fun Config.input(name: String) = inputs.find { it.name == name }!!
|
||||
fun Config.arg(name: String) = args.find { it.name == name }!!
|
||||
|
||||
fun Mixin.input(name: String) = inputs.find { it.name == name }!!
|
||||
fun Mixin.arg(name: String) = args.find { it.name == name }!!
|
||||
fun Mixin.output(name: String) = outputs.find { it.name == name }!!
|
||||
fun Mixin.config(name: String) = configs.find { it.name == name }!!
|
||||
}
|
||||
|
||||
data class Op (
|
||||
val opName: String,
|
||||
var libnd4jOpName: String? = null,
|
||||
var javaOpClass: String? = null,
|
||||
var isAbstract: Boolean = false,
|
||||
var legacy: Boolean = false,
|
||||
var argsFirst: Boolean = false,
|
||||
var javaPackage: String? = null,
|
||||
val inputs: MutableList<Input> = mutableListOf(),
|
||||
val outputs: MutableList<Output> = mutableListOf(),
|
||||
val args: MutableList<Arg> = mutableListOf(),
|
||||
val constraints: MutableList<Constraint> = mutableListOf(),
|
||||
val signatures: MutableList<Signature> = mutableListOf(),
|
||||
val doc: MutableList<DocSection> = mutableListOf(),
|
||||
val configs: MutableList<Config> = mutableListOf()
|
||||
): OpLike {
|
||||
override fun name() = opName
|
||||
override fun inputs(): List<Input> = inputs
|
||||
override fun args(): List<Arg> = args
|
||||
override fun configs(): List<Config> = configs
|
||||
override fun outputs(): List<Output> = outputs
|
||||
override fun allParameters(): List<Parameter> = inputs + args + configs
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "Op(opName=$opName, libnd4jOpName=$libnd4jOpName, isAbstract=$isAbstract)"
|
||||
}
|
||||
|
||||
override fun addInput(input: Input) { inputs.addOrReplace(input) }
|
||||
override fun addArgument(arg: Arg) { args.addOrReplace(arg) }
|
||||
override fun addOutput(output: Output) { outputs.addOrReplace(output) }
|
||||
override fun addDoc(docs: DocSection){ doc.add(docs) }
|
||||
override fun addSignature(signature: Signature){ signatures.add(signature) }
|
||||
override fun addConstraint(constraint: Constraint){ constraints.add(constraint) }
|
||||
override fun addConfig(config: Config) { configs.addOrReplace(config) }
|
||||
|
||||
/**
|
||||
* Check that all required properties are set
|
||||
*/
|
||||
fun checkInvariants() {
|
||||
if( !isAbstract && (doc.size == 0 || doc.all { it.text.isNullOrBlank() } != false )){
|
||||
throw IllegalStateException("$opName: Ops must be documented!")
|
||||
}
|
||||
|
||||
signatures.forEach {
|
||||
val opParameters = mutableListOf<Parameter>()
|
||||
opParameters.addAll(inputs)
|
||||
opParameters.addAll(args)
|
||||
|
||||
val notCovered = opParameters.fold(mutableListOf<Parameter>()){acc, parameter ->
|
||||
if(!(it.parameters.contains(parameter) || parameter.defaultValueIsApplicable(it.parameters))){
|
||||
acc.add(parameter)
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
if(notCovered.size > 0){
|
||||
throw IllegalStateException("$opName: $it does not cover all parameters! Missing: ${notCovered.joinToString(", ") { it.name() }}")
|
||||
}
|
||||
}
|
||||
|
||||
args.filter { it.type == DataType.ENUM }.forEach {
|
||||
if(it.description == null){
|
||||
throw IllegalStateException("$opName: Argument ${it.name} is ENUM but has no documentation!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Mixin (
|
||||
val name: String,
|
||||
|
||||
val inputs: MutableList<Input> = mutableListOf(),
|
||||
val outputs: MutableList<Output> = mutableListOf(),
|
||||
val args: MutableList<Arg> = mutableListOf(),
|
||||
val constraints: MutableList<Constraint> = mutableListOf(),
|
||||
val signatures: MutableList<Signature> = mutableListOf(),
|
||||
val doc: MutableList<DocSection> = mutableListOf(),
|
||||
val configs: MutableList<Config> = mutableListOf()
|
||||
): OpLike {
|
||||
override fun name() = name
|
||||
override fun inputs(): List<Input> = inputs
|
||||
override fun args(): List<Arg> = args
|
||||
override fun configs(): List<Config> = configs
|
||||
override fun outputs(): List<Output> = outputs
|
||||
override fun allParameters(): List<Parameter> = inputs + args + configs
|
||||
|
||||
override fun toString(): String {
|
||||
return "Mixin($name)"
|
||||
}
|
||||
|
||||
override fun addInput(input: Input) { inputs.addOrReplace(input) }
|
||||
override fun addArgument(arg: Arg) { args.addOrReplace(arg) }
|
||||
override fun addOutput(output: Output) { outputs.addOrReplace(output) }
|
||||
override fun addDoc(docs: DocSection){ doc.add(docs) }
|
||||
override fun addSignature(signature: Signature){ signatures.add(signature) }
|
||||
override fun addConstraint(constraint: Constraint){ constraints.add(constraint) }
|
||||
override fun addConfig(config: Config) { configs.addOrReplace(config) }
|
||||
|
||||
|
||||
var legacyWasSet: Boolean = false
|
||||
var legacy: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
legacyWasSet = true
|
||||
}
|
||||
var javaPackageWasSet: Boolean = false
|
||||
var javaPackage: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
javaPackageWasSet = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that all required properties are set
|
||||
*/
|
||||
fun checkInvariants() {
|
||||
signatures.forEach {
|
||||
val opParameters = mutableListOf<Parameter>()
|
||||
opParameters.addAll(inputs)
|
||||
opParameters.addAll(args)
|
||||
|
||||
val notCovered = opParameters.fold(mutableListOf<Parameter>()){acc, parameter ->
|
||||
if(!(it.parameters.contains(parameter) || parameter.defaultValueIsApplicable(it.parameters))){
|
||||
acc.add(parameter)
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
if(notCovered.size > 0){
|
||||
throw IllegalStateException("$this: $it does not cover all parameters! Missing: ${notCovered.joinToString(", ") { it.name() }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T: Parameter> MutableList<T>.addOrReplaceAll(params: List<T>){
|
||||
params.forEach {
|
||||
this.addOrReplace(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T: Parameter> MutableList<T>.addOrReplace(param: T){
|
||||
val found = this.find { it.name() == param.name() }
|
||||
if(found != null){
|
||||
this.replaceAll { if(it.name() == param.name()){ param } else { it } }
|
||||
}else{
|
||||
this.add(param)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
object Registry {
|
||||
private val enums: MutableMap<String, Arg> = mutableMapOf()
|
||||
private val configs: MutableMap<String, Config> = mutableMapOf()
|
||||
|
||||
fun enums() = enums.values.sortedBy { it.name }
|
||||
fun configs() = configs.values.sortedBy { it.name }
|
||||
|
||||
fun registerEnum(arg: Arg){
|
||||
when(enums[arg.name]){
|
||||
null -> enums[arg.name] = arg
|
||||
arg -> { /* noop */ }
|
||||
else -> throw IllegalStateException("Another enum with the name ${arg.name} already exists! Enums have to use unique names. If you want to use an enum in multiple places, use mixins to define them.")
|
||||
}
|
||||
}
|
||||
|
||||
fun registerConfig(config: Config){
|
||||
when(configs[config.name]){
|
||||
null -> configs[config.name] = config
|
||||
config -> { /* noop */ }
|
||||
else -> throw IllegalStateException("Another config with the name ${config.name} already exists! Configs have to use unique names.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api
|
||||
|
||||
import org.nd4j.codegen.api.doc.DocSection
|
||||
import java.util.*
|
||||
|
||||
|
||||
open class Constraint (
|
||||
var message: String? = null,
|
||||
var check: Expression
|
||||
)
|
||||
|
||||
class BackendConstraint(message: String? = null, check: Expression): Constraint(message, check)
|
||||
|
||||
// Used in Constraint Expressions
|
||||
sealed class Reference
|
||||
data class NumberReference<T: Number>(val value: T): Reference()
|
||||
data class BooleanReference(val value: Boolean): Reference()
|
||||
data class InputShapeReference(val input: Input, val idx: Int): Reference()
|
||||
data class InputRankReference(val input: Input): Reference()
|
||||
sealed class Expression: Reference()
|
||||
data class BooleanExpression(val left: Reference, val right: Reference, val op: BooleanOperation): Expression()
|
||||
data class SameTypeExpression(val inputs: List<Input>): Expression()
|
||||
data class SameShapeExpression(val inputs: List<Input>): Expression()
|
||||
data class BroadcastableShapesExpression(val inputs: List<Input>): Expression()
|
||||
enum class BooleanOperation{EQ, NEQ, LT, LTE, GT, GTE, AND, OR}
|
||||
|
||||
|
||||
// Used to define array sizes
|
||||
sealed class Count
|
||||
data class Range(val from: Int, val to: Int): Count()
|
||||
data class AtLeast(val min: Int): Count()
|
||||
data class AtMost(val max: Int): Count()
|
||||
data class Exactly(val count: Int): Count()
|
||||
|
||||
// Actual parameters
|
||||
interface Parameter {
|
||||
fun name(): String
|
||||
fun defaultValue() : Any?
|
||||
|
||||
fun hasDefaultValue(): Boolean
|
||||
|
||||
fun isVararg():Boolean
|
||||
|
||||
/**
|
||||
* A default value only is applicable if it is a literal value, or the referenced value is either directly a part of
|
||||
* the signature, or there is a reference chain that ends in something that is actually a part of the signature
|
||||
*/
|
||||
fun defaultValueIsApplicable(otherParams: List<Parameter>): Boolean = if(hasDefaultValue()){
|
||||
when(val defaultValue = this.defaultValue()){
|
||||
is Number, is Boolean, null -> true
|
||||
is IntArray, is BooleanArray, is DoubleArray -> true
|
||||
is String -> true
|
||||
is org.nd4j.linalg.api.buffer.DataType -> true
|
||||
is org.nd4j.codegen.api.LossReduce -> true
|
||||
is Parameter -> otherParams.contains(defaultValue) || defaultValue.defaultValueIsApplicable(otherParams)
|
||||
is TensorDataTypeValue -> otherParams.contains(defaultValue.tensor) || defaultValue.tensor.defaultValueIsApplicable(otherParams)
|
||||
is TensorShapeValue -> otherParams.contains(defaultValue.tensor) || defaultValue.tensor.defaultValueIsApplicable(otherParams)
|
||||
else -> false
|
||||
}
|
||||
}else{
|
||||
false
|
||||
}
|
||||
}
|
||||
interface Tensor: Parameter
|
||||
|
||||
data class Arg(
|
||||
val name: String,
|
||||
val type: DataType,
|
||||
var description: String? = null,
|
||||
var isVargarg: Boolean = false
|
||||
) : Reference(), Parameter {
|
||||
override fun name(): String = name
|
||||
override fun defaultValue(): Any? = defaultValue
|
||||
override fun hasDefaultValue(): Boolean = defaultValueIsSet
|
||||
override fun isVararg(): Boolean {
|
||||
return isVargarg
|
||||
}
|
||||
|
||||
private var defaultValueIsSet = false
|
||||
var defaultValue: Any? = null
|
||||
set(value) = if(isAssignableFrom(value)) {
|
||||
field = value
|
||||
defaultValueIsSet = true
|
||||
}else{
|
||||
throw IllegalArgumentException("Illegal default value for $this. Got ${value.toDescriptiveString()} (${value?.javaClass?.name})")
|
||||
}
|
||||
|
||||
var possibleValues: List<String>? = null
|
||||
set(value) = if(type == DataType.ENUM) when {
|
||||
value == null -> field = null
|
||||
value.isEmpty() -> throw IllegalArgumentException("$this: Can not set empty possibleValues.")
|
||||
else -> field = value
|
||||
} else {
|
||||
throw IllegalArgumentException("$this: Can not set possibleValues on non ENUM typed Arg.")
|
||||
}
|
||||
|
||||
var count: Count? = null
|
||||
set(value) = if(type == DataType.ENUM && value != Exactly(1)) {
|
||||
throw IllegalArgumentException("$this: ENUM typed Arg can not be array")
|
||||
}else{
|
||||
field = value
|
||||
}
|
||||
|
||||
private fun matchesDataType(value: Any?) = when(type){
|
||||
DataType.FLOATING_POINT -> value is Double
|
||||
DataType.INT -> (value is Int) || (value is Long)
|
||||
DataType.LONG -> (value is Int) || (value is Long)
|
||||
DataType.NUMERIC -> value is Number
|
||||
DataType.BOOL -> value is Boolean
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun isAssignableFrom(value: Any?) = when(value){
|
||||
is TensorShapeValue -> isArray() && type == DataType.INT
|
||||
is TensorDataTypeValue -> type == DataType.DATA_TYPE
|
||||
is Number, is Boolean -> matchesDataType(value)
|
||||
is IntArray -> isArray() && (type == DataType.INT || type == DataType.NUMERIC) && countMatches(value.size)
|
||||
is DoubleArray -> isArray() && (type == DataType.FLOATING_POINT || type == DataType.NUMERIC) && countMatches(value.size)
|
||||
is BooleanArray -> isArray() && type == DataType.BOOL && countMatches(value.size)
|
||||
is Arg -> value.count == count && value.type == type
|
||||
is String -> type == DataType.STRING || type == DataType.ENUM && possibleValues != null && possibleValues?.contains(value) ?: false
|
||||
//is String -> type == DataType.ENUM && possibleValues != null && possibleValues?.contains(value) ?: false
|
||||
is org.nd4j.linalg.api.buffer.DataType -> type == DataType.DATA_TYPE
|
||||
is org.nd4j.codegen.api.LossReduce -> type == DataType.LOSS_REDUCE
|
||||
null -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun isArray() = count != Exactly(1) && count != null
|
||||
fun countMatches(size: Int) = when(val c = count!!){
|
||||
is Range -> c.from <= size && size <= c.to
|
||||
is AtLeast -> c.min <= size
|
||||
is AtMost -> size <= c.max
|
||||
is Exactly -> c.count == size
|
||||
}
|
||||
|
||||
fun Tensor.shape() = TensorShapeValue(this)
|
||||
fun Tensor.dataType() = TensorDataTypeValue(this)
|
||||
|
||||
override fun toString() = "Arg(${if(type == DataType.ENUM){
|
||||
"ENUM(${possibleValues?.joinToString(", ")})"
|
||||
}else{
|
||||
type.toString()
|
||||
}}, $name)${if(count != null) "{ count = $count }" else "" }"
|
||||
}
|
||||
|
||||
data class Input (
|
||||
val name: String,
|
||||
val type: DataType,
|
||||
var description: String? = null,
|
||||
var count: Count? = null
|
||||
) : Parameter, Tensor {
|
||||
override fun isVararg(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun name(): String = name
|
||||
override fun defaultValue(): Any? = defaultValue
|
||||
override fun hasDefaultValue(): Boolean = defaultValueIsSet
|
||||
|
||||
private var defaultValueIsSet = false
|
||||
var defaultValue: Input? = null
|
||||
set(value) = if(matchesDataType(value)){
|
||||
field = value
|
||||
defaultValueIsSet = true
|
||||
}else{
|
||||
throw IllegalArgumentException("Illegal default value for Input($name). Allowed values have to match data type $type, but got ${value.toDescriptiveString()} (${value?.javaClass?.name})")
|
||||
}
|
||||
|
||||
private fun matchesDataType(value: Input?) = when(value){
|
||||
null -> true
|
||||
else -> value.type == type
|
||||
}
|
||||
}
|
||||
|
||||
data class Output(
|
||||
var name: String,
|
||||
var type: DataType,
|
||||
var multiOutput: Boolean,
|
||||
var description: String? = null
|
||||
) : Parameter, Tensor{
|
||||
override fun isVararg(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun name(): String = name
|
||||
override fun defaultValue(): Any? = null
|
||||
override fun hasDefaultValue(): Boolean = false
|
||||
}
|
||||
|
||||
data class Signature(
|
||||
val parameters: List<Parameter>,
|
||||
val description: String? = null
|
||||
){
|
||||
override fun toString(): String {
|
||||
return "Signature(${parameters.joinToString {it.name()}})"
|
||||
}
|
||||
}
|
||||
|
||||
// Used in defining default values
|
||||
data class TensorShapeValue(val tensor: Tensor) {
|
||||
override fun toString(): String = "${tensor.name()}.shape()"
|
||||
}
|
||||
data class TensorDataTypeValue(val tensor: Tensor){
|
||||
override fun toString(): String = "${tensor.name()}.dataType()"
|
||||
}
|
||||
|
||||
fun Any?.toDescriptiveString() = when(this){
|
||||
null -> "null"
|
||||
is IntArray -> Arrays.toString(this)
|
||||
is LongArray -> Arrays.toString(this)
|
||||
is DoubleArray -> Arrays.toString(this)
|
||||
is FloatArray -> Arrays.toString(this)
|
||||
is BooleanArray -> Arrays.toString(this)
|
||||
is Array<*> -> Arrays.toString(this)
|
||||
else -> this.toString()
|
||||
}
|
||||
|
||||
data class Config(
|
||||
val name: String,
|
||||
val inputs: MutableList<Input> = mutableListOf(),
|
||||
val args: MutableList<Arg> = mutableListOf(),
|
||||
val constraints: MutableList<Constraint> = mutableListOf(),
|
||||
val doc: MutableList<DocSection> = mutableListOf()
|
||||
): Parameter {
|
||||
override fun isVararg(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun name(): String = name
|
||||
override fun defaultValue(): Any? = null
|
||||
override fun hasDefaultValue(): Boolean = false
|
||||
|
||||
fun addInput(input: Input) { inputs.add(input) }
|
||||
fun addArgument(arg: Arg) { args.add(arg) }
|
||||
fun addConstraint(constraint: Constraint){ constraints.add(constraint) }
|
||||
fun addDoc(doc: DocSection){ this.doc.add(doc) }
|
||||
|
||||
var javaClassOverride: String = ""
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.doc
|
||||
|
||||
import org.nd4j.codegen.api.CodeComponent
|
||||
|
||||
enum class DocScope {
|
||||
ALL, CLASS_DOC_ONLY, CREATORS_ONLY, CONSTRUCTORS_ONLY;
|
||||
|
||||
fun applies(codeComponent: CodeComponent): Boolean {
|
||||
return when (this) {
|
||||
ALL -> true
|
||||
CLASS_DOC_ONLY -> codeComponent === CodeComponent.CLASS_DOC
|
||||
CREATORS_ONLY -> codeComponent === CodeComponent.OP_CREATOR
|
||||
CONSTRUCTORS_ONLY -> codeComponent === CodeComponent.CONSTRUCTOR
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.doc
|
||||
|
||||
import org.nd4j.codegen.api.CodeComponent
|
||||
import org.nd4j.codegen.api.Language
|
||||
|
||||
|
||||
data class DocSection(var scope: DocScope? = null,
|
||||
var language: Language? = null,
|
||||
var text: String? = null) {
|
||||
|
||||
fun applies(language: Language, codeComponent: CodeComponent): Boolean {
|
||||
return (this.language === Language.ANY || language === this.language) && scope!!.applies(codeComponent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.doc
|
||||
|
||||
import org.nd4j.codegen.api.Op
|
||||
|
||||
object DocTokens {
|
||||
enum class GenerationType { SAMEDIFF, ND4J }
|
||||
private val OPNAME = "%OPNAME%".toRegex()
|
||||
private val LIBND4J_OPNAME = "%LIBND4J_OPNAME%".toRegex()
|
||||
private val INPUT_TYPE = "%INPUT_TYPE%".toRegex()
|
||||
|
||||
@JvmStatic fun processDocText(doc: String?, op: Op, type: GenerationType): String {
|
||||
return doc
|
||||
?.replace(OPNAME, op.opName)
|
||||
?.replace(LIBND4J_OPNAME, op.libnd4jOpName!!)
|
||||
?.replace(INPUT_TYPE, when(type){
|
||||
GenerationType.SAMEDIFF -> "SDVariable"
|
||||
GenerationType.ND4J -> "INDArray"
|
||||
}) ?: ""
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.generator
|
||||
|
||||
import org.nd4j.codegen.api.Expression
|
||||
|
||||
|
||||
interface ConstraintCodeGenerator {
|
||||
fun generateExpression(expression: Expression): String
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.generator
|
||||
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.NamespaceOps
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
interface Generator {
|
||||
fun language(): Language?
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun generateNamespaceNd4j(namespace: NamespaceOps?, config: GeneratorConfig?, directory: File?, className: String?)
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun generateNamespaceSameDiff(namespace: NamespaceOps?, config: GeneratorConfig?, directory: File?, className: String?)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.api.generator
|
||||
|
||||
import org.nd4j.codegen.api.Op
|
||||
|
||||
class GeneratorConfig {
|
||||
fun acceptOp(op: Op?): Boolean = true
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl
|
||||
|
||||
import org.nd4j.codegen.api.*
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.api.doc.DocSection
|
||||
import org.nd4j.codegen.ops.SDBaseOps
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
fun Namespace(name: String, block: NamespaceOps.() -> Unit): NamespaceOps {
|
||||
val ns = NamespaceOps(name)
|
||||
ns.block()
|
||||
|
||||
ns.checkInvariants()
|
||||
return ns
|
||||
}
|
||||
|
||||
fun Mixin(name: String, block: Mixin.() -> Unit): Mixin {
|
||||
return Mixin(name).apply(block).also {
|
||||
it.checkInvariants()
|
||||
}
|
||||
}
|
||||
|
||||
fun NamespaceOps.Alias(ns:NamespaceOps, opName:String):Op {
|
||||
val op:Op? = ns.op(opName)
|
||||
op?.let {
|
||||
this.parentNamespaceOps[ns.name]?.add(op)
|
||||
this.ops.add(op)
|
||||
return op
|
||||
}
|
||||
throw IllegalStateException("Failed to create alias for op: $opName")
|
||||
}
|
||||
|
||||
fun NamespaceOps.Op(name: String, block: Op.() -> Unit): Op {
|
||||
val op = Op(name)
|
||||
op.libnd4jOpName = name
|
||||
|
||||
op.block()
|
||||
|
||||
if (!op.isAbstract && op.signatures.isEmpty()) {
|
||||
op.AllParamSignature()
|
||||
op.AllDefaultsSignature()
|
||||
}
|
||||
|
||||
op.checkInvariants()
|
||||
|
||||
this.ops.add(op)
|
||||
return op
|
||||
}
|
||||
|
||||
fun NamespaceOps.Op(name: String,
|
||||
extends: Mixin,
|
||||
keepArgs: Boolean = true,
|
||||
keepInputs: Boolean = true,
|
||||
keepOutputs: Boolean = true,
|
||||
keepConstraints: Boolean = true,
|
||||
keepSignatures: Boolean = true,
|
||||
keepDocs: Boolean = true,
|
||||
block: (Op.() -> Unit)? = null): Op {
|
||||
return this.Op(name) {
|
||||
useMixin(extends, keepArgs = keepArgs, keepInputs = keepInputs, keepOutputs = keepOutputs, keepConstraints = keepConstraints, keepSignatures = keepSignatures, keepDocs = keepDocs)
|
||||
|
||||
if (block != null) {
|
||||
this.block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun OpLike.Input(dataType: DataType, name: String, block: (Input.() -> Unit)? = null): Input {
|
||||
val input = Input(name, dataType)
|
||||
if (block != null) input.block()
|
||||
|
||||
if (!dataType.isTensorDataType()) {
|
||||
throw IllegalArgumentException("Invalid datatype for input \"$name\" of op ${this.name()}: inputs arrays cannot have type $dataType - wrong type, or should be Arg type?");
|
||||
}
|
||||
|
||||
this.addInput(input)
|
||||
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
fun OpLike.Arg(dataType: DataType, name: String, block: (Arg.() -> Unit)? = null): Arg {
|
||||
val input = Arg(name, dataType)
|
||||
if (block != null) input.block()
|
||||
|
||||
this.addArgument(input)
|
||||
if(dataType == DataType.ENUM){
|
||||
Registry.registerEnum(input)
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
fun OpLike.Output(dataType: DataType, name: String, block: (Output.() -> Unit)? = null): Output {
|
||||
val output = Output(name, dataType, false)
|
||||
if (block != null) output.block()
|
||||
|
||||
if (!dataType.isTensorDataType()) {
|
||||
throw IllegalArgumentException("Invalid datatype for output \"$name\" of op ${this.name()}: output arrays cannot have type $dataType");
|
||||
}
|
||||
|
||||
this.addOutput(output)
|
||||
return output
|
||||
}
|
||||
|
||||
fun OpLike.Doc(language: Language, scope: DocScope, block: DocSection.() -> String): DocSection {
|
||||
val doc = DocSection().apply {
|
||||
this.language = language
|
||||
this.scope = scope
|
||||
text = this.block()
|
||||
}
|
||||
this.addDoc(doc)
|
||||
return doc
|
||||
}
|
||||
|
||||
fun OpLike.AllParamSignature(withOutput: Boolean = false) {
|
||||
val allParameters = allParameters()
|
||||
|
||||
this.addSignature(Signature(allParameters))
|
||||
if (withOutput) {
|
||||
val withOutputParams = mutableListOf<Parameter>().also {
|
||||
it.addAll(this.outputs())
|
||||
it.addAll(allParameters)
|
||||
}
|
||||
this.addSignature(Signature(withOutputParams))
|
||||
}
|
||||
}
|
||||
|
||||
fun OpLike.AllDefaultsSignature(withOutput: Boolean = false) {
|
||||
val allParameters = allParameters()
|
||||
|
||||
if (allParameters.find { it.hasDefaultValue() } != null) {
|
||||
val params = allParameters.filterNot { it.hasDefaultValue() }
|
||||
this.addSignature(Signature(params))
|
||||
if (withOutput) {
|
||||
val withOutputParams = mutableListOf<Parameter>().also {
|
||||
it.addAll(this.outputs())
|
||||
it.addAll(allParameters)
|
||||
}
|
||||
this.addSignature(Signature(withOutputParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun OpLike.Signature(vararg params: Parameter, block: (Signature.() -> String)? = null): Signature {
|
||||
if (params.toSet().size < params.size) {
|
||||
throw IllegalArgumentException("A parameter may not be used twice in a signature!")
|
||||
}
|
||||
val paramsAndOutputs = allParameters() + outputs()
|
||||
if (!paramsAndOutputs.containsAll(params.toList())) {
|
||||
throw IllegalArgumentException("You can only use parameters in a signature that are actually defined in $this! Did you forget to useMixin(...) a mixin?")
|
||||
}
|
||||
|
||||
val signature = Signature(params.toList())
|
||||
if (block != null) {
|
||||
signature.block()
|
||||
}
|
||||
this.addSignature(signature)
|
||||
return signature
|
||||
}
|
||||
|
||||
fun OpLike.Constraint(desc: String, block: ConstraintBuilder.() -> Expression): Constraint {
|
||||
val check = ConstraintBuilder().block()
|
||||
val constraint = Constraint(desc, check)
|
||||
this.addConstraint(constraint)
|
||||
return constraint
|
||||
}
|
||||
|
||||
fun OpLike.BackendConstraint(desc: String, block: ConstraintBuilder.() -> Expression): Constraint {
|
||||
val check = ConstraintBuilder().block()
|
||||
val constraint = BackendConstraint(desc, check)
|
||||
this.addConstraint(constraint)
|
||||
return constraint
|
||||
}
|
||||
|
||||
class ConstraintBuilder {
|
||||
fun broadcastableShapes(vararg inputs: Input) = BroadcastableShapesExpression(inputs.toList())
|
||||
fun sameShape(vararg inputs: Input) = SameShapeExpression(inputs.toList())
|
||||
fun sameType(vararg inputs: Input) = SameTypeExpression(inputs.toList())
|
||||
|
||||
fun Input.sizeAt(i: Int) = InputShapeReference(this, i)
|
||||
fun Input.rank() = InputRankReference(this)
|
||||
fun Input.isScalar() = this.rank() eq 0
|
||||
|
||||
fun some(expr: BooleanExpression, vararg exprs: BooleanExpression) = exprs.fold(expr, { acc, cur -> acc or cur })
|
||||
fun all(expr: BooleanExpression, vararg exprs: BooleanExpression) = exprs.fold(expr, { acc, cur -> acc and cur })
|
||||
fun not(expr: BooleanExpression) = expr eq false
|
||||
|
||||
infix fun BooleanExpression.and(other: BooleanExpression) = BooleanExpression(this, other, BooleanOperation.AND)
|
||||
infix fun BooleanExpression.or(other: BooleanExpression) = BooleanExpression(this, other, BooleanOperation.OR)
|
||||
|
||||
|
||||
infix fun Reference.eq(other: Reference) = BooleanExpression(this, other, BooleanOperation.EQ)
|
||||
infix fun Reference.eq(other: Number) = this eq NumberReference(other)
|
||||
infix fun Reference.eq(other: Boolean) = this eq BooleanReference(other)
|
||||
|
||||
|
||||
infix fun Reference.neq(other: Reference) = BooleanExpression(this, other, BooleanOperation.NEQ)
|
||||
infix fun <T : Number> Reference.neq(other: T) = this neq NumberReference(other)
|
||||
infix fun Reference.neq(other: Boolean) = this neq BooleanReference(other)
|
||||
|
||||
infix fun Reference.gt(other: Reference) = BooleanExpression(this, other, BooleanOperation.GT)
|
||||
infix fun <T : Number> Reference.gt(other: T) = this gt NumberReference(other)
|
||||
|
||||
infix fun Reference.lt(other: Reference) = BooleanExpression(this, other, BooleanOperation.LT)
|
||||
infix fun <T : Number> Reference.lt(other: T) = this lt NumberReference(other)
|
||||
|
||||
|
||||
infix fun <T : Number> Reference.gte(other: T) = this gte NumberReference(other)
|
||||
infix fun Reference.gte(other: Reference) = BooleanExpression(this, other, BooleanOperation.GTE)
|
||||
|
||||
infix fun <T : Number> Reference.lte(other: T) = this lte NumberReference(other)
|
||||
infix fun Reference.lte(other: Reference) = BooleanExpression(this, other, BooleanOperation.LTE)
|
||||
}
|
||||
|
||||
fun NamespaceOps.Config(name: String, block: (Config.() -> Unit)): Config {
|
||||
val config = Config(name)
|
||||
config.block()
|
||||
this.addConfig(config)
|
||||
Registry.registerConfig(config)
|
||||
return config
|
||||
}
|
||||
|
||||
fun Config.Input(dataType: DataType, name: String, block: (Input.() -> Unit)? = null): Input {
|
||||
val input = Input(name, dataType)
|
||||
if (block != null) input.block()
|
||||
|
||||
if (!dataType.isTensorDataType()) {
|
||||
throw IllegalArgumentException("Invalid datatype for input \"$name\" of config ${this.name}: inputs arrays cannot have type $dataType - wrong type, or should be Arg type?");
|
||||
}
|
||||
|
||||
this.addInput(input)
|
||||
return input
|
||||
}
|
||||
|
||||
fun Config.Arg(dataType: DataType, name: String, block: (Arg.() -> Unit)? = null): Arg {
|
||||
val input = Arg(name, dataType)
|
||||
if (block != null) input.block()
|
||||
|
||||
this.addArgument(input)
|
||||
if(dataType == DataType.ENUM){
|
||||
Registry.registerEnum(input)
|
||||
}
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
fun Config.Constraint(desc: String, block: ConstraintBuilder.() -> Expression): Constraint {
|
||||
val check = ConstraintBuilder().block()
|
||||
val constraint = Constraint(desc, check)
|
||||
this.addConstraint(constraint)
|
||||
return constraint
|
||||
}
|
||||
|
||||
fun Config.BackendConstraint(desc: String, block: ConstraintBuilder.() -> Expression): Constraint {
|
||||
val check = ConstraintBuilder().block()
|
||||
val constraint = BackendConstraint(desc, check)
|
||||
this.addConstraint(constraint)
|
||||
return constraint
|
||||
}
|
||||
|
||||
fun Config.Doc(language: Language, scope: DocScope, block: DocSection.() -> String): DocSection {
|
||||
val doc = DocSection().apply {
|
||||
this.language = language
|
||||
this.scope = scope
|
||||
text = this.block()
|
||||
}
|
||||
this.addDoc(doc)
|
||||
return doc
|
||||
}
|
||||
|
||||
fun OpLike.useConfig(config: Config): Config {
|
||||
this.addConfig(config)
|
||||
return config
|
||||
}
|
||||
|
||||
fun Op.useMixin(mixin: Mixin,
|
||||
keepArgs: Boolean = true,
|
||||
keepInputs: Boolean = true,
|
||||
keepOutputs: Boolean = true,
|
||||
keepConstraints: Boolean = true,
|
||||
keepSignatures: Boolean = true,
|
||||
keepDocs: Boolean = true,
|
||||
keepConfigs: Boolean = true
|
||||
) {
|
||||
if(mixin.legacyWasSet){
|
||||
legacy = mixin.legacy
|
||||
}
|
||||
if(mixin.javaPackageWasSet){
|
||||
javaPackage = mixin.javaPackage
|
||||
}
|
||||
if (keepArgs) {
|
||||
args.addOrReplaceAll(mixin.args)
|
||||
}
|
||||
if (keepInputs) {
|
||||
inputs.addOrReplaceAll(mixin.inputs)
|
||||
}
|
||||
if (keepOutputs) {
|
||||
outputs.addOrReplaceAll(mixin.outputs)
|
||||
}
|
||||
if (keepConstraints) {
|
||||
constraints.addAll(mixin.constraints)
|
||||
}
|
||||
if (keepSignatures) {
|
||||
signatures.addAll(mixin.signatures)
|
||||
}
|
||||
if (keepDocs) {
|
||||
doc.addAll(mixin.doc)
|
||||
}
|
||||
if(keepConfigs){
|
||||
configs.addOrReplaceAll(mixin.configs)
|
||||
}
|
||||
}
|
||||
|
||||
fun Mixin.useMixin(mixin: Mixin,
|
||||
keepArgs: Boolean = true,
|
||||
keepInputs: Boolean = true,
|
||||
keepOutputs: Boolean = true,
|
||||
keepConstraints: Boolean = true,
|
||||
keepSignatures: Boolean = true,
|
||||
keepDocs: Boolean = true,
|
||||
keepConfigs: Boolean = true) {
|
||||
if(mixin.legacyWasSet){
|
||||
legacy = mixin.legacy
|
||||
}
|
||||
if(mixin.javaPackageWasSet){
|
||||
javaPackage = mixin.javaPackage
|
||||
}
|
||||
if (keepArgs) {
|
||||
args.addOrReplaceAll(mixin.args)
|
||||
}
|
||||
if (keepInputs) {
|
||||
inputs.addOrReplaceAll(mixin.inputs)
|
||||
}
|
||||
if (keepOutputs) {
|
||||
outputs.addOrReplaceAll(mixin.outputs)
|
||||
}
|
||||
if (keepConstraints) {
|
||||
constraints.addAll(mixin.constraints)
|
||||
}
|
||||
if (keepSignatures) {
|
||||
signatures.addAll(mixin.signatures)
|
||||
}
|
||||
if (keepDocs) {
|
||||
doc.addAll(mixin.doc)
|
||||
}
|
||||
if(keepConfigs){
|
||||
configs.addOrReplaceAll(mixin.configs)
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.java
|
||||
|
||||
import org.nd4j.codegen.api.*
|
||||
import org.nd4j.codegen.api.generator.ConstraintCodeGenerator
|
||||
|
||||
class JavaConstraintCodeGenerator: ConstraintCodeGenerator {
|
||||
override fun generateExpression(expression: Expression): String = when(expression) {
|
||||
is BooleanExpression -> {
|
||||
val left = generateReference(expression.left)
|
||||
val right = generateReference(expression.right)
|
||||
when(expression.op){
|
||||
BooleanOperation.EQ -> "$left == $right"
|
||||
BooleanOperation.NEQ -> "$left != $right"
|
||||
BooleanOperation.LT -> "$left < $right"
|
||||
BooleanOperation.LTE -> "$left <= $right"
|
||||
BooleanOperation.GT -> "$left > $right"
|
||||
BooleanOperation.GTE -> "$left >= $right"
|
||||
BooleanOperation.AND -> "$left && $right"
|
||||
BooleanOperation.OR -> "$left || $right"
|
||||
}
|
||||
}
|
||||
is SameTypeExpression -> "isSameType(${expression.inputs.joinToString(", "){ it.name }})"
|
||||
is SameShapeExpression -> "isSameShape(${expression.inputs.joinToString(", "){ it.name }})"
|
||||
is BroadcastableShapesExpression -> "isBroadcastableShapes(${expression.inputs.joinToString(", "){ it.name }})"
|
||||
}
|
||||
|
||||
private fun generateReference(reference: Reference): String = when(reference){
|
||||
is NumberReference<*> -> reference.value.toString()
|
||||
is BooleanReference -> reference.value.toString()
|
||||
is InputShapeReference -> "${reference.input.name}.sizeAt(${reference.idx})"
|
||||
is InputRankReference -> "${reference.input.name}.rank()"
|
||||
is Arg -> reference.name
|
||||
is Expression -> "(${generateExpression(reference)})"
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.impl.python
|
||||
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.NamespaceOps
|
||||
import org.nd4j.codegen.api.Op
|
||||
import org.nd4j.codegen.api.doc.DocTokens
|
||||
import org.nd4j.codegen.api.generator.Generator
|
||||
import org.nd4j.codegen.api.generator.GeneratorConfig
|
||||
import org.nd4j.codegen.util.GenUtil
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class KotlinExamplePythonGenerator: Generator {
|
||||
override fun language() = Language.PYTHON
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun generateNamespaceNd4j(namespace: NamespaceOps?, config: GeneratorConfig?, directory: File?, className: String?) {
|
||||
val f = File(directory, GenUtil.ensureFirstIsCap(namespace!!.name) + ".py")
|
||||
val content =
|
||||
"""
|
||||
|class ${GenUtil.ensureFirstIsCap(namespace.name)}:
|
||||
|${namespace.ops.filterNot { it.isAbstract }.joinToString("\n\n") { generateMethod(it).addIndent(4) }}
|
||||
""".trimMargin()
|
||||
FileUtils.writeStringToFile(f, content, StandardCharsets.UTF_8)
|
||||
}
|
||||
|
||||
fun generateMethod(op: Op): String =
|
||||
"""
|
||||
|@staticmethod
|
||||
|def ${GenUtil.ensureFirstIsNotCap(op.opName)}(${op.inputs.joinToString(", "){it.name}}):
|
||||
|${genDocString(op).addIndent(4)}
|
||||
|${"# Execution code here".addIndent(4)}
|
||||
|
||||
""".trimMargin()
|
||||
|
||||
fun genDocString(op: Op): String {
|
||||
//Following roughly: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
|
||||
// python docstring / multiline string delimiter is the same as in kotlin, so use this little workaround
|
||||
if (op.args.isNotEmpty()) {
|
||||
//Args and default args
|
||||
throw UnsupportedOperationException("Generating method with args not yet implemented")
|
||||
}
|
||||
if(op.outputs.size != 1) throw UnsupportedOperationException("Not yet implemented: Python docstring generation for multiple output ops")
|
||||
|
||||
val docStringDelimiter = "\"\"\""
|
||||
return """
|
||||
|$docStringDelimiter
|
||||
|${op.opName} operation
|
||||
|
|
||||
|${op.inputs.let { """
|
||||
|Args:
|
||||
|${it.joinToString("\n") {
|
||||
"| ${it.name} (ndarray): ${DocTokens.processDocText(it.description, op, DocTokens.GenerationType.ND4J)}"
|
||||
}}
|
||||
|""".trimMargin() }}
|
||||
|${op.outputs.let {"""
|
||||
|Returns:
|
||||
| ndarray: ${it[0].name} ${it[0].description?.let {"- ${DocTokens.processDocText(it, op, DocTokens.GenerationType.ND4J)}"
|
||||
}}""".trimMargin()
|
||||
}}
|
||||
|$docStringDelimiter
|
||||
""".trimMargin()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun generateNamespaceSameDiff(namespace: NamespaceOps?, config: GeneratorConfig?, directory: File?, className: String?) {
|
||||
throw UnsupportedOperationException("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun String.addIndent(size: Int): String = GenUtil.addIndent(this, size)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.util
|
||||
|
||||
import org.nd4j.codegen.impl.java.JavaPoetGenerator
|
||||
import org.nd4j.codegen.ops.Bitwise
|
||||
import org.nd4j.codegen.ops.Random
|
||||
import java.io.File
|
||||
|
||||
fun main() {
|
||||
val outDir = File("F:\\dl4j-builds\\deeplearning4j\\nd4j\\nd4j-backends\\nd4j-api-parent\\nd4j-api\\src\\main\\java\\")
|
||||
outDir.mkdirs()
|
||||
|
||||
listOf(Bitwise(), Random()).forEach {
|
||||
val generator = JavaPoetGenerator()
|
||||
generator.generateNamespaceNd4j(it, null, outDir, it.name + ".java")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.mixins
|
||||
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.DataType
|
||||
import org.nd4j.codegen.api.Exactly
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
|
||||
val broadcastingDoc = Mixin("broadcastingDoc"){
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
//TODO: finalize content for this broadcasting mixin doc.
|
||||
"""
|
||||
Note: supports broadcasting if x and y have different shapes and are broadcastable.
|
||||
For example, if X has shape [1,10] and Y has shape [5,10] then op(X,Y) has output shape [5,10]
|
||||
Broadcast rules are the same as NumPy: https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
val transform = Mixin("transform"){
|
||||
legacy = true
|
||||
Input(DataType.NUMERIC, "x") { description = "Input variable" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Output variable" }
|
||||
}
|
||||
|
||||
val transformArithmetic = Mixin("transformArithmetic"){
|
||||
useMixin(transform)
|
||||
legacy = false
|
||||
Input(DataType.NUMERIC, "y") { description = "Input variable" }
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.pairwise.arithmetic"
|
||||
}
|
||||
|
||||
val transformCustom2 = Mixin("transformCustom2"){
|
||||
Input(DataType.NUMERIC, "x") { description = "First input variable, x" }
|
||||
Input(DataType.NUMERIC, "y") { description = "Second input variable, y" }
|
||||
Output(DataType.NUMERIC, "out"){ description = "Output"}
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
}
|
||||
|
||||
val transformStrict = Mixin("transformStrict"){
|
||||
useMixin(transform)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.strict"
|
||||
}
|
||||
|
||||
val transformSame = Mixin("transformSame"){
|
||||
useMixin(transform)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.same"
|
||||
}
|
||||
|
||||
val transformBool = Mixin("transformBool"){
|
||||
useMixin(transform)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.bool"
|
||||
}
|
||||
|
||||
val transformAny = Mixin("transformAny"){
|
||||
useMixin(transform)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.any"
|
||||
}
|
||||
|
||||
val transformFloating = Mixin("transformFloating"){
|
||||
useMixin(transform)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.floating"
|
||||
}
|
||||
|
||||
val scalar = Mixin("scalar"){
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.scalar"
|
||||
Input(DataType.NUMERIC, "x") { description = "Input variable" }
|
||||
Arg(DataType.NUMERIC, "value") { description = "Scalar value for op" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Output variable" }
|
||||
}
|
||||
|
||||
val reduce = Mixin("reduce"){
|
||||
Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
Arg(DataType.BOOL,"keepDims"){ description = "Whether to keep the original dimensions or produce a shrunk array with less dimensions"; defaultValue = false}
|
||||
Arg(DataType.LONG, "dimensions"){ count = AtLeast(0); isVargarg = true; description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
}
|
||||
|
||||
val reduceVariableDimensions = Mixin("reduceVariable") {
|
||||
Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
Arg(DataType.BOOL,"keepDims"){ description = "Whether to keep the original dimensions or produce a shrunk array with less dimensions"; defaultValue = false}
|
||||
Input(DataType.NUMERIC, name = "dimensions"){description = "Dimensions to reduce along"; }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
}
|
||||
|
||||
val reduceFloating = Mixin("reduceFloating"){
|
||||
useMixin(reduce)
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.floating"
|
||||
}
|
||||
|
||||
val reduceFloatingVariable = Mixin("reduceFloatingVariable"){
|
||||
useMixin(reduceVariableDimensions)
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.floating"
|
||||
}
|
||||
|
||||
|
||||
val reduceSame = Mixin("reduceSame"){
|
||||
useMixin(reduce)
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.same"
|
||||
}
|
||||
|
||||
val reduceSameVariable = Mixin("reduceSameVariable"){
|
||||
useMixin(reduceVariableDimensions)
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.same"
|
||||
}
|
||||
|
||||
val reduceLong = Mixin("reduceLong"){
|
||||
useMixin(reduce)
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.longer"
|
||||
}
|
||||
|
||||
val reduceLongVariable = Mixin("reduceLongVariable"){
|
||||
useMixin(reduceVariableDimensions)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce.longer"
|
||||
}
|
||||
|
||||
val reduce3 = Mixin("reduce3"){
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce3"
|
||||
Input(DataType.NUMERIC, "x") { description = "Input variable x" }
|
||||
Input(DataType.NUMERIC, "y") { description = "Input variable y" }
|
||||
Arg(DataType.BOOL,"keepDims",{description = "Whether to preserve original dimensions or not"; defaultValue = false})
|
||||
Arg(DataType.BOOL,"isComplex",{description = "Depending on the implementation, such as distance calculations, this can determine whether all distance calculations for all points should be done."; defaultValue = false})
|
||||
val dims = Arg(DataType.LONG, "dimensions"){ count = AtLeast(0); isVargarg = true; description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Output variable" }
|
||||
}
|
||||
|
||||
val reduce3Variable = Mixin("reduce3Variable"){
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce3"
|
||||
Input(DataType.NUMERIC, "x") { description = "Input variable x" }
|
||||
Input(DataType.NUMERIC, "y") { description = "Input variable y" }
|
||||
Input(DataType.NUMERIC, "dimensions"){ description = "Dimensions to calculate %OPNAME% over" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Output variable" }
|
||||
Arg(DataType.BOOL,"keepDims",{description = "Whether to preserve original dimensions or not"; defaultValue = false})
|
||||
Arg(DataType.BOOL,"isComplex",{description = "Depending on the implementation, such as distance calculations, this can determine whether all distance calculations for all points should be done."; defaultValue = false})
|
||||
|
||||
}
|
||||
|
||||
val indexAccum = Mixin("indexAccum"){
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.indexaccum"
|
||||
val input = Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
val keepDims = Arg(DataType.BOOL, "keepDims") { description = "If true: keep the dimensions that are reduced on (as length 1). False: remove the reduction dimensions"; defaultValue = false }
|
||||
val dims = Arg(DataType.LONG, "dimensions"){ count = AtLeast(1); isVargarg = true; description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
|
||||
Signature(input, dims)
|
||||
AllParamSignature(withOutput = false)
|
||||
}
|
||||
|
||||
val indexAccumVariable = Mixin("indexAccumVariable"){
|
||||
legacy = true
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.indexaccum"
|
||||
val input = Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
val keepDims = Arg(DataType.BOOL, "keepDims") { description = "If true: keep the dimensions that are reduced on (as length 1). False: remove the reduction dimensions"; defaultValue = false }
|
||||
val dims = Input(DataType.NUMERIC, "dimensions"){ description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
|
||||
Signature(input, dims)
|
||||
AllParamSignature(withOutput = false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val indexAccumCustom = Mixin("indexAccumCustom"){
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.indexaccum.custom"
|
||||
val input = Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
val keepDims = Arg(DataType.BOOL, "keepDims") { description = "If true: keep the dimensions that are reduced on (as length 1). False: remove the reduction dimensions"; defaultValue = false }
|
||||
val dims = Arg(DataType.LONG, "dimensions"){ count = AtLeast(1); isVargarg = true; description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
|
||||
Signature(input, dims)
|
||||
AllParamSignature(withOutput = false)
|
||||
}
|
||||
|
||||
val indexAccumVariableCustom = Mixin("indexAccumVariableCustom"){
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.indexaccum.custom"
|
||||
val input = Input(DataType.NUMERIC, "in") { description = "Input variable" }
|
||||
val keepDims = Arg(DataType.BOOL, "keepDims") { description = "If true: keep the dimensions that are reduced on (as length 1). False: remove the reduction dimensions"; defaultValue = false }
|
||||
val dims = Input(DataType.NUMERIC, "dimensions"){ description = "Dimensions to reduce over. If dimensions are not specified, full array reduction is performed" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Reduced array of rank (input rank - num dimensions)" }
|
||||
|
||||
Signature(input, dims)
|
||||
AllParamSignature(withOutput = false)
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.DataType.INT
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
|
||||
|
||||
fun Bitwise() = Namespace("Bitwise"){
|
||||
val namespaceJavaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
|
||||
Op("leftShift") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "ShiftBits"
|
||||
|
||||
Input(INT, "x") { description = "Input to be bit shifted" }
|
||||
Input(INT, "y") { description = "Amount to shift elements of x array" }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise shifted input x" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise left shift operation. Supports broadcasting.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("rightShift") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "RShiftBits"
|
||||
|
||||
Input(INT, "x") { description = "Input to be bit shifted" }
|
||||
Input(INT, "y") { description = "Amount to shift elements of x array" }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise shifted input x" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise right shift operation. Supports broadcasting.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("leftShiftCyclic") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "CyclicShiftBits"
|
||||
|
||||
Input(INT, "x") { description = "Input to be bit shifted" }
|
||||
Input(INT, "y") { description = "Amount to shift elements of x array" }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise cyclic shifted input x" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise left cyclical shift operation. Supports broadcasting.
|
||||
Unlike #leftShift(%INPUT_TYPE%, %INPUT_TYPE%) the bits will "wrap around":
|
||||
{@code leftShiftCyclic(01110000, 2) -> 11000001}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("rightShiftCyclic") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "CyclicRShiftBits"
|
||||
|
||||
Input(INT, "x") { description = "Input to be bit shifted" }
|
||||
Input(INT, "y") { description = "Amount to shift elements of x array" }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise cyclic shifted input x" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise right cyclical shift operation. Supports broadcasting.
|
||||
Unlike rightShift(%INPUT_TYPE%, %INPUT_TYPE%) the bits will "wrap around":
|
||||
{@code rightShiftCyclic(00001110, 2) -> 10000011}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("bitsHammingDistance") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "BitsHammingDistance"
|
||||
|
||||
val x = Input(INT, "x") { description = "First input array." }
|
||||
val y = Input(INT, "y") { description = "Second input array." }
|
||||
Constraint("Must be same types"){ sameType(x, y) }
|
||||
|
||||
Output(INT, "output"){ description = "bitwise Hamming distance" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise Hamming distance reduction over all elements of both input arrays.<br>
|
||||
For example, if x=01100000 and y=1010000 then the bitwise Hamming distance is 2 (due to differences at positions 0 and 1)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("and") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "BitwiseAnd"
|
||||
|
||||
val x = Input(INT, "x") { description = "First input array" }
|
||||
val y = Input(INT, "y") { description = "Second input array" }
|
||||
Constraint("Must be same types"){ sameType(x, y) }
|
||||
BackendConstraint("Must have broadcastable shapes"){ broadcastableShapes(x, y) }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise AND array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise AND operation. Supports broadcasting.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("or") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "BitwiseOr"
|
||||
|
||||
val x = Input(INT, "x") { description = "First input array" }
|
||||
val y = Input(INT, "y") { description = "First input array" }
|
||||
Constraint("Must be same types"){ sameType(x, y) }
|
||||
BackendConstraint("Must have broadcastable shapes"){ broadcastableShapes(x, y) }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise OR array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise OR operation. Supports broadcasting.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("xor") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "BitwiseXor"
|
||||
|
||||
val x = Input(INT, "x") { description = "First input array" }
|
||||
val y = Input(INT, "y") { description = "First input array" }
|
||||
Constraint("Must be same types"){ sameType(x, y) }
|
||||
BackendConstraint("Must have broadcastable shapes"){ broadcastableShapes(x, y) }
|
||||
|
||||
Output(INT, "output"){ description = "Bitwise XOR array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Bitwise XOR operation (exclusive OR). Supports broadcasting.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("bitShift") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "ShiftBits"
|
||||
Input(INT, "x") { description = "Input 1" }
|
||||
Input(INT, "shift") { description = "Number of bits to shift." }
|
||||
Output(INT, "output"){ description = "SDVariable with shifted bits" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Shift integer bits to the left, i.e. var << 4
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("bitShiftRight") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "RShiftBits"
|
||||
Input(INT, "x") { description = "Input 1" }
|
||||
Input(INT, "shift") { description = "Number of bits to shift." }
|
||||
Output(INT, "output"){ description = "SDVariable with shifted bits" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Shift integer bits to the right, i.e. var >> 4
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("bitRotl") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "CyclicShiftBits"
|
||||
Input(INT, "x") { description = "Input 1" }
|
||||
Input(INT, "shift") { description = "Number of bits to shift." }
|
||||
Output(INT, "output"){ description = "SDVariable with shifted bits" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Roll integer bits to the left, i.e. var << 4 | var >> (32 - 4)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("bitRotr") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "CyclicRShiftBits"
|
||||
Input(INT, "x") { description = "Input 1" }
|
||||
Input(INT, "shift") { description = "Number of bits to shift." }
|
||||
Output(INT, "output"){ description = "SDVariable with shifted bits" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Roll integer bits to the right, i.e. var >> 4 | var << (32 - 4)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Exactly
|
||||
|
||||
fun SDCNN() = Namespace("CNN"){
|
||||
val namespaceJavaPackage = "org.nd4j.linalg.api.ops.impl.layers.convolution"
|
||||
|
||||
val dataFormat = Mixin("dataFormat"){
|
||||
Arg(ENUM, "dataFormat") { possibleValues = listOf("NCHW", "NHWC"); description = "Data format: \"NCHW\" or \"NHWC\"" }
|
||||
}
|
||||
|
||||
|
||||
val conv1DConfig = Config("Conv1DConfig"){
|
||||
Arg(LONG, "k"){ description = "Kernel"; defaultValue=-1L}
|
||||
Arg(LONG, "s"){ description = "stride"; defaultValue=1}
|
||||
Arg(LONG, "p"){ description = "padding"; defaultValue=0}
|
||||
Arg(LONG, "d"){ description = "dilation"; defaultValue=1}
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=true}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NCW"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.Conv1DConfig"
|
||||
}
|
||||
|
||||
val conv2DConfig = Config("Conv2DConfig"){
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1L}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1L}
|
||||
Arg(LONG, "sH"){ description = "Stride along height dimension"; defaultValue=1};
|
||||
Arg(LONG, "sW"){ description = "Stride along width dimension"; defaultValue=1};
|
||||
Arg(LONG, "pH"){ description = "Padding along height dimension"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding along width dimension"; defaultValue=0};
|
||||
Arg(LONG, "dH"){ description = "Dilation along height dimension"; defaultValue=1};
|
||||
Arg(LONG, "dW"){ description = "Dilation along width dimension"; defaultValue=1};
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=true}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NCHW"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.Conv2DConfig"
|
||||
}
|
||||
|
||||
val conv3DConfig = Config("Conv3DConfig"){
|
||||
Arg(LONG, "kD"){ description = "Kernel depth"; defaultValue=-1}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1}
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1};
|
||||
Arg(LONG, "sD"){ description = "Stride depth"; defaultValue=1};
|
||||
Arg(LONG, "sW"){ description = "Stride width"; defaultValue=1};
|
||||
Arg(LONG, "sH"){ description = "Stride height"; defaultValue=1};
|
||||
Arg(LONG, "pD"){ description = "Padding depth"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding width"; defaultValue=0};
|
||||
Arg(LONG, "pH"){ description = "Padding height"; defaultValue=0};
|
||||
Arg(LONG, "dD"){ description = "Dilation depth"; defaultValue=1};
|
||||
Arg(LONG, "dW"){ description = "Dilation width"; defaultValue=1};
|
||||
Arg(LONG, "dH"){ description = "Dilation height"; defaultValue=1};
|
||||
Arg(BOOL, "biasUsed"){ description = "biasUsed"; defaultValue=false}
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=true}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NDHWC"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.Conv3DConfig"
|
||||
}
|
||||
|
||||
|
||||
val deconv2DConfig = Config("DeConv2DConfig"){
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1L}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1L}
|
||||
Arg(LONG, "sH"){ description = "Stride along height dimension"; defaultValue=1L};
|
||||
Arg(LONG, "sW"){ description = "Stride along width dimension"; defaultValue=1L};
|
||||
Arg(LONG, "pH"){ description = "Padding along height dimension"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding along width dimension"; defaultValue=0};
|
||||
Arg(LONG, "dH"){ description = "Dilation along height dimension"; defaultValue=1L};
|
||||
Arg(LONG, "dW"){ description = "Dilation along width dimension"; defaultValue=1L};
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=false}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NCHW"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.DeConv2DConfig"
|
||||
}
|
||||
|
||||
|
||||
val deconv3DConfig = Config("DeConv3DConfig"){
|
||||
Arg(LONG, "kD"){ description = "Kernel depth"; defaultValue=-1L}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1L}
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1L};
|
||||
Arg(LONG, "sD"){ description = "Stride depth"; defaultValue=1L};
|
||||
Arg(LONG, "sW"){ description = "Stride width"; defaultValue=1L};
|
||||
Arg(LONG, "sH"){ description = "Stride height"; defaultValue=1L};
|
||||
Arg(LONG, "pD"){ description = "Padding depth"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding width"; defaultValue=0};
|
||||
Arg(LONG, "pH"){ description = "Padding height"; defaultValue=0};
|
||||
Arg(LONG, "dD"){ description = "Dilation depth"; defaultValue=1L};
|
||||
Arg(LONG, "dW"){ description = "Dilation width"; defaultValue=1L};
|
||||
Arg(LONG, "dH"){ description = "Dilation height"; defaultValue=1L};
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=false}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NCDHW"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.DeConv3DConfig"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
val pooling2DConfig = Config("Pooling2DConfig"){
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1}
|
||||
Arg(LONG, "sH"){ description = "Stride along height dimension"; defaultValue=1};
|
||||
Arg(LONG, "sW"){ description = "Stride along width dimension"; defaultValue=1};
|
||||
Arg(LONG, "pH"){ description = "Padding along height dimension"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding along width dimension"; defaultValue=0};
|
||||
Arg(LONG, "dH"){ description = "Dilation along height dimension"; defaultValue=1};
|
||||
Arg(LONG, "dW"){ description = "Dilation along width dimension"; defaultValue=1};
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=true}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="nchw"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.Pooling2DConfig"
|
||||
}
|
||||
|
||||
val pooling3DConfig = Config("Pooling3DConfig"){
|
||||
Arg(LONG, "kD"){ description = "Kernel depth"; defaultValue=-1}
|
||||
Arg(LONG, "kW"){ description = "Kernel width"; defaultValue=-1}
|
||||
Arg(LONG, "kH"){ description = "Kernel height"; defaultValue=-1};
|
||||
Arg(LONG, "sD"){ description = "Stride depth"; defaultValue=1};
|
||||
Arg(LONG, "sW"){ description = "Stride width"; defaultValue=1};
|
||||
Arg(LONG, "sH"){ description = "Stride height"; defaultValue=1};
|
||||
Arg(LONG, "pD"){ description = "Padding depth"; defaultValue=0};
|
||||
Arg(LONG, "pW"){ description = "Padding width"; defaultValue=0};
|
||||
Arg(LONG, "pH"){ description = "Padding height"; defaultValue=0};
|
||||
Arg(LONG, "dD"){ description = "Dilation depth"; defaultValue=1};
|
||||
Arg(LONG, "dW"){ description = "Dilation width"; defaultValue=1};
|
||||
Arg(LONG, "dH"){ description = "Dilation height"; defaultValue=1};
|
||||
Arg(BOOL, "isSameMode"){ description = "Same mode"; defaultValue=true}
|
||||
Arg(STRING, "dataFormat"){ description = "Data format"; defaultValue="NCDHW"}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.Pooling3DConfig"
|
||||
}
|
||||
|
||||
|
||||
val LocalResponseNormalizationConfig = Config("LocalResponseNormalizationConfig"){
|
||||
Arg(NUMERIC, "alpha"){ description = "alpha"; defaultValue=1}
|
||||
Arg(NUMERIC, "beta"){ description = "beta"; defaultValue=0.5}
|
||||
Arg(NUMERIC, "bias"){ description = "bias"; defaultValue=1}
|
||||
Arg(INT, "depth"){ description = "depth"; defaultValue=5}
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.convolution.config.LocalResponseNormalizationConfig"
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Op("avgPooling2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "AvgPooling2D"
|
||||
Input(NUMERIC, "input") { description = "the input to average pooling 2d operation - 4d CNN (image) activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
useConfig(pooling2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Result after applying average pooling on the input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D Convolution layer operation - average pooling 2d
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("avgPooling3d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "AvgPooling3D"
|
||||
Input(NUMERIC, "input") {description = "the input to average pooling 3d operation - 5d activations in NCDHW format (shape [minibatch, channels, depth, height, width]) or NDHWC format (shape [minibatch, depth, height, width, channels])" }
|
||||
useConfig(pooling3DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "after applying average pooling on the input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
3D convolution layer operation - average pooling 3d
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("batchToSpace") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "BatchToSpace"
|
||||
Input(NUMERIC, "x") { description = "Input variable. 4d input" }
|
||||
Arg(INT, "blocks") { count=Exactly(2); description = "Block size, in the height/width dimension" }
|
||||
Arg(INT, "croppingTop") { count=Exactly(2)}
|
||||
Arg(INT, "croppingBottom") { count=Exactly(2)}
|
||||
Output(NUMERIC, "output"){ description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Convolution 2d layer batch to space operation on 4d input.
|
||||
Reduces input batch dimension by rearranging data into a larger spatial dimensions
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("col2Im") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Col2Im"
|
||||
|
||||
Input(NUMERIC, "in") { description = "Input - rank 6 input with shape [minibatch, inputChannels, kernelHeight, kernelWidth, outputHeight, outputWidth]" }
|
||||
useConfig(conv2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Col2Im output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
col2im operation for use in 2D convolution operations. Outputs a 4d array with shape
|
||||
[minibatch, inputChannels, height, width]
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("conv1d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Conv1D"
|
||||
Input(NUMERIC, "input") { description = "the inputs to conv1d" }
|
||||
Input(NUMERIC, "weights") { description = "weights for conv1d op - rank 3 array with shape [kernelSize, inputChannels, outputChannels]" }
|
||||
Input(NUMERIC, "bias") { description = "bias for conv1d op - rank 1 array with shape [outputChannels]. May be null."; defaultValue=null }
|
||||
useConfig(conv1DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "result of conv1d op" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Conv1d operation.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("conv2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Conv2D"
|
||||
Input(NUMERIC, "layerInput") { description = "the input to max pooling 2d operation - 4d CNN (image) activations in NCHW format" }
|
||||
Input(NUMERIC, "weights") { description = "Weights for the convolution operation. 4 dimensions with format [kernelHeight, kernelWidth, inputChannels, outputChannels]" }
|
||||
Input(NUMERIC, "bias") { description = "Optional 1D bias array with shape [outputChannels]. May be null."; defaultValue=null }
|
||||
useConfig(conv2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "result of conv2d op" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D Convolution operation with optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Op("conv3d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Conv3D"
|
||||
Input(NUMERIC, "input") { description = "the input to average pooling 3d operation - 5d activations in NCDHW format (shape [minibatch, channels, depth, height, width]) or NDHWC format (shape [minibatch, depth, height, width, channels])" }
|
||||
Input(NUMERIC, "weights") { description = " Weights for conv3d. Rank 5 with shape [kernelDepth, kernelHeight, kernelWidth, inputChannels, outputChannels]." }
|
||||
Input(NUMERIC, "bias") { description = " Optional 1D bias array with shape [outputChannels]. May be null."; defaultValue=null }
|
||||
useConfig(conv3DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Conv3d output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Convolution 3D operation with optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("deconv2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "DeConv2D"
|
||||
Input(NUMERIC, "layerInput") { description = "the input to deconvolution 2d operation - 4d CNN (image) activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
Input(NUMERIC, "weights") { description = "Weights for the 2d deconvolution operation. 4 dimensions with format [inputChannels, outputChannels, kernelHeight, kernelWidth]" }
|
||||
Input(NUMERIC, "bias") { description = "Optional 1D bias array with shape [outputChannels]. May be null."; defaultValue=null }
|
||||
useConfig(deconv2DConfig)
|
||||
Output(NUMERIC, "output"){ description = "result of deconv2d op" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D deconvolution operation with optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Op("deconv3d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "DeConv3D"
|
||||
Input(NUMERIC, "input") { description = "Input array - shape [bS, iD, iH, iW, iC] (NDHWC) or [bS, iC, iD, iH, iW] (NCDHW)" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array - shape [kD, kH, kW, oC, iC]" }
|
||||
Input(NUMERIC, "bias") { description = "Bias array - optional, may be null. If non-null, must have shape [outputChannels]"; defaultValue=null }
|
||||
useConfig(deconv3DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "result of 3D CNN deconvolution operation" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
3D CNN deconvolution operation with or without optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("depthToSpace") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "DepthToSpace"
|
||||
Input(NUMERIC, "x") { description = "the input to depth to space pooling 2d operation - 4d activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
Arg(INT, "blockSize") { description = "Block size, in the height/width dimension" }
|
||||
useMixin(dataFormat)
|
||||
Output(NUMERIC, "output"){ description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Convolution 2d layer batch to space operation on 4d input.<br>
|
||||
Reduces input channels dimension by rearranging data into a larger spatial dimensions<br>
|
||||
Example: if input has shape [mb, 8, 2, 2] and block size is 2, then output size is [mb, 8/(2*2), 2*2, 2*2]
|
||||
= [mb, 2, 4, 4]
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("depthWiseConv2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "DepthwiseConv2D"
|
||||
Input(NUMERIC, "layerInput") { description = "the input to max pooling 2d operation - 4d CNN (image) activations in NCHW format" }
|
||||
Input(NUMERIC, "depthWeights") { description = "Depth-wise conv2d weights. 4 dimensions with format [kernelHeight, kernelWidth, inputChannels, depthMultiplier]" }
|
||||
Input(NUMERIC, "bias") { description = "Optional 1D bias array with shape [outputChannels]. May be null."; defaultValue=null }
|
||||
useConfig(conv2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "result of depthwise conv2d op" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Depth-wise 2D convolution operation with optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("dilation2D") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "Dilation2D"
|
||||
Input(NUMERIC, "df") { description = "" }
|
||||
Input(NUMERIC, "weights") { description = "df" }
|
||||
Arg(INT, "strides") { count = Exactly(2); description = "weights" }
|
||||
Arg(INT, "rates") {count = Exactly(2); description = "strides" }
|
||||
Arg(BOOL, "isSameMode") { description = "isSameMode" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Computed the grayscale dilation of 4-D input and 3-D filters tensors." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
TODO doc string
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("extractImagePatches") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "ExtractImagePatches"
|
||||
Input(NUMERIC, "input") { description = "Input array. Must be rank 4, with shape [minibatch, height, width, channels]" }
|
||||
Arg(INT, "kH") { description = "Kernel height" }
|
||||
Arg(INT, "kW") { description = "Kernel width" }
|
||||
Arg(INT, "sH") { description = "Stride height" }
|
||||
Arg(INT, "sW") { description = "Stride width" }
|
||||
Arg(INT, "rH") { description = "Rate height" }
|
||||
Arg(INT, "rW") { description = "Rate width" }
|
||||
Arg(BOOL, "sameMode") { description = "If true: use same mode padding. If false" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "The result is a 4D tensor which is indexed by batch, row, and column." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Extract image patches
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("im2Col") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Im2col"
|
||||
Input(NUMERIC, "in") { description = "Input - rank 4 input with shape [minibatch, inputChannels, height, width]" }
|
||||
useConfig(conv2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Im2Col output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
im2col operation for use in 2D convolution operations. Outputs a 6d array with shape
|
||||
[minibatch, inputChannels, kernelHeight, kernelWidth, outputHeight, outputWidth]
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("localResponseNormalization") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "LocalResponseNormalization"
|
||||
Input(NUMERIC, "input") { description = "the inputs to lrn" }
|
||||
useConfig(LocalResponseNormalizationConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Result after Local Response Normalization"}
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D convolution layer operation - local response normalization
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("maxPooling2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "MaxPooling2D"
|
||||
Input(NUMERIC, "input") { description = "the input to max pooling 2d operation - 4d CNN (image) activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
useConfig(pooling2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Result after applying max pooling on the input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D Convolution layer operation - max pooling 2d
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("maxPoolWithArgmax") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "MaxPoolWithArgmax"
|
||||
Input(NUMERIC, "input") { description = "the input to max pooling 2d operation - 4d CNN (image) activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
useConfig(pooling2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Result after applying max pooling on the input" }
|
||||
Output(NUMERIC, "indexes"){ description = "Argmax array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D Convolution layer operation - Max pooling on the input and outputs both max values and indices
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("maxPooling3d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "MaxPooling3D"
|
||||
Input(NUMERIC, "input") { description = "the input to average pooling 3d operation - 5d activations in NCDHW format (shape [minibatch, channels, depth, height, width]) or NDHWC format (shape [minibatch, depth, height, width, channels])" }
|
||||
useConfig(pooling3DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Result after applying max pooling on the input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
3D convolution layer operation - max pooling 3d operation.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("separableConv2d") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.layers.convolution"
|
||||
javaOpClass = "SConv2D"
|
||||
Input(NUMERIC, "layerInput") { description = "the input to max pooling 2d operation - 4d CNN (image) activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
Input(NUMERIC, "depthWeights") { description = "Separable conv2d depth weights. 4 dimensions with format [kernelHeight, kernelWidth, inputChannels, depthMultiplier]" }
|
||||
Input(NUMERIC, "pointWeights") { description = "Point weights, rank 4 with format [1, 1, inputChannels*depthMultiplier, outputChannels]. May be null" }
|
||||
Input(NUMERIC, "bias") { description = "Optional bias, rank 1 with shape [outputChannels]. May be null."; defaultValue=null}
|
||||
useConfig(conv2DConfig)
|
||||
|
||||
Output(NUMERIC, "output"){ description = "result of separable convolution 2d operation" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Separable 2D convolution operation with optional bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("spaceToBatch") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "SpaceToBatch"
|
||||
Input(NUMERIC, "x") { description = "Input variable. 4d input" }
|
||||
Arg(INT, "blocks") { count = Exactly(2); description = "Block size, in the height/width dimension" }
|
||||
Arg(INT, "paddingTop") {count = Exactly(2); description = "Optional 2d int[] array for padding the result: values [[pad top, pad bottom], [pad left, pad right]]" }
|
||||
Arg(INT, "paddingBottom") {count = Exactly(2); description = "Optional 2d int[] array for padding the result: values [[pad top, pad bottom], [pad left, pad right]]" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Convolution 2d layer space to batch operation on 4d input.
|
||||
Increases input batch dimension by rearranging data from spatial dimensions into batch dimension
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("spaceToDepth") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
Input(NUMERIC, "x") { description = "the input to depth to space pooling 2d operation - 4d activations in NCHW format (shape [minibatch, channels, height, width]) or NHWC format (shape [minibatch, height, width, channels])" }
|
||||
Arg(INT, "blockSize") { description = " Block size, in the height/width dimension" }
|
||||
useMixin(dataFormat)
|
||||
Output(NUMERIC, "output"){ description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Convolution 2d layer space to depth operation on 4d input.<br>
|
||||
Increases input channels (reduced spatial dimensions) by rearranging data into a larger channels dimension<br>
|
||||
Example: if input has shape [mb, 2, 4, 4] and block size is 2, then output size is [mb, 8/(2*2), 2*2, 2*2]
|
||||
= [mb, 2, 4, 4]
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("upsampling2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
Input(NUMERIC, "input") { description = "Input in NCHW format" }
|
||||
Arg(INT, "scale") { description = "The scale for both height and width dimensions." }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Upsampled input"}
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Upsampling layer for 2D inputs.
|
||||
scale is used for both height and width dimensions.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("upsampling2d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
Input(NUMERIC, "input") { description = "Input in NCHW format" }
|
||||
Arg(INT, "scaleH") { description = "Scale to upsample in height dimension" }
|
||||
Arg(INT, "scaleW") { description = "Scale to upsample in width dimension" }
|
||||
Arg(BOOL ,"nchw") { description = "If true: input is in NCHW (minibatch, channels, height, width) format. False: NHWC format" }
|
||||
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Upsampled input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
2D Convolution layer operation - Upsampling 2d
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("upsampling3d") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "Upsampling3d"
|
||||
Input(NUMERIC, "input") { description = "Input in NCHW format" }
|
||||
Arg(BOOL ,"ncdhw") { description = "If true: input is in NCDHW (minibatch, channels, depth, height, width) format. False: NDHWC format" }
|
||||
Arg(INT, "scaleD") { description = "Scale to upsample in depth dimension" }
|
||||
Arg(INT, "scaleH") { description = "Scale to upsample in height dimension" }
|
||||
Arg(INT, "scaleW") { description = "Scale to upsample in width dimension" }
|
||||
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Upsampled input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
3D Convolution layer operation - Upsampling 3d
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Exactly
|
||||
|
||||
|
||||
fun SDImage() = Namespace("Image"){
|
||||
val namespaceJavaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
Op("CropAndResize") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "CropAndResize"
|
||||
Input(NUMERIC, "image") { description = "Input image, with shape [batch, height, width, channels]" }
|
||||
Input(NUMERIC, "cropBoxes") { description = "Float32 crop, shape [numBoxes, 4] with values in range 0 to 1" }
|
||||
Input(NUMERIC, "boxIndices") { description = "Indices: which image (index to dimension 0) the cropBoxes belong to. Rank 1, shape [numBoxes]" }
|
||||
Input(INT, "cropOutSize") { description = "Output size for the images - int32, rank 1 with values [outHeight, outWidth]" }
|
||||
Arg(NUMERIC, "extrapolationValue") { description = "Used for extrapolation, when applicable. 0.0 should be used for the default"; defaultValue=0.0 }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Cropped and resized images" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Given an input image and some crop boxes, extract out the image subsets and resize them to the specified size.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("extractImagePatches") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "ExtractImagePatches"
|
||||
Input(NUMERIC, "image") { description = "Input image to extract image patches from - shape [batch, height, width, channels]" }
|
||||
Arg(INT, "kSizes") { count = Exactly(2); description = "Kernel size - size of the image patches, [height, width]" }
|
||||
Arg(INT, "strides") { count = Exactly(2);description = "Stride in the input dimension for extracting image patches, [stride_height, stride_width]" }
|
||||
Arg(INT, "rates") { count = AtLeast(0); description = "Usually [1,1]. Equivalent to dilation rate in dilated convolutions - how far apart the output pixels\n" +
|
||||
" in the patches should be, in the input. A dilation of [a,b] means every {@code a}th pixel is taken\n" +
|
||||
" along the height/rows dimension, and every {@code b}th pixel is take along the width/columns dimension" }
|
||||
Arg(BOOL, "sameMode") { description = "Padding algorithm. If true: use Same padding" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "The extracted image patches" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Given an input image, extract out image patches (of size kSizes - h x w) and place them in the depth dimension.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("nonMaxSuppression") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "NonMaxSuppression"
|
||||
Input(NUMERIC, "boxes") { description = "Might be null. Name for the output variable" }
|
||||
Input(NUMERIC, "scores") { description = "vector of shape [num_boxes]" }
|
||||
Arg(INT, "maxOutSize") { description = "scalar representing the maximum number of boxes to be selected" }
|
||||
Arg(NUMERIC, "iouThreshold") { description = "threshold for deciding whether boxes overlap too much with respect to IOU" }
|
||||
Arg(NUMERIC, "scoreThreshold") { description = "threshold for deciding when to remove boxes based on score" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "vectort of shape [M] representing the selected indices from the boxes tensor, where M <= max_output_size" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Greedily selects a subset of bounding boxes in descending order of score
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("adjustContrast") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "AdjustContrast"
|
||||
Input(NUMERIC, "in") { description = "images to adjust. 3D shape or higher" }
|
||||
Arg(FLOATING_POINT, "factor") { description = "multiplier for adjusting contrast" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Contrast-adjusted image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Adjusts contrast of RGB or grayscale images.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("adjustSaturation") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "AdjustSaturation"
|
||||
Input(NUMERIC, "in") { description = "RGB image as 3D array" }
|
||||
Arg(FLOATING_POINT, "factor") { description = "factor for saturation" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "adjusted image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Adjust saturation of RGB images
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("adjustHue") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "AdjustHue"
|
||||
Input(NUMERIC, "in") { description = "image as 3D array" }
|
||||
Arg(NUMERIC, "delta") { description = "value to add to hue channel" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "adjusted image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Adjust hue of RGB image
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("pad") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms"
|
||||
javaOpClass = "Pad"
|
||||
Input(NUMERIC, "input") { description = "input array" }
|
||||
Input(NUMERIC, "padding") { description = "padding input" }
|
||||
Arg(ENUM,"Mode") {possibleValues = listOf("CONSTANT", "REFLECT", "SYMMETRIC"); description = "padding mode: CONSTANT, REFLECT, SYMMETRIC"}
|
||||
Arg(NUMERIC, "padValue") { description = "The value to pad with" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "the padded array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Pads an image according to the given padding type
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("randomCrop") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "RandomCrop"
|
||||
Input(NUMERIC, "input") { description = "input array" }
|
||||
Input(INT, "shape") { description = "shape for crop" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "cropped array" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Randomly crops image
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("rgbToHsv") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "RgbToHsv"
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting array from HSV to RGB format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("hsvToRgb") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "HsvToRgb"
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting image from HSV to RGB format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("rgbToYiq") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "RgbToYiq"
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting array from RGB to YIQ format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("yiqToRgb") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "YiqToRgb"
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting image from YIQ to RGB format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("rgbToYuv") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "RgbToYuv"
|
||||
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting array from RGB to YUV format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("yuvToRgb") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "YuvToRgb"
|
||||
|
||||
Input(NUMERIC, "input") { description = "3D image" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "3D image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Converting image from YUV to RGB format
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("imageResize") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "ImageResize"
|
||||
|
||||
Input(NUMERIC, "input") { description = "4D image [NHWC]" }
|
||||
Input(INT, "size") { description = "new height and width" }
|
||||
Arg(BOOL, "preserveAspectRatio") { description = "Whether to preserve the aspect ratio." +
|
||||
" If this is set, then images will be resized to a size that fits in size while preserving the aspect ratio" +
|
||||
" of the original image. Scales up the image if size is bigger than the current size of the image. Defaults to False."; defaultValue=false; }
|
||||
Arg(BOOL, "antialias") { description = "Whether to use an anti-aliasing filter when downsampling an image"; defaultValue=false; }
|
||||
Arg(ENUM, "ImageResizeMethod") { possibleValues = listOf( "ResizeBilinear", "ResizeBicubic", "ResizeNearest", "ResizeGaussian",
|
||||
"ResizeLanczos5", "ResizeMitchellcubic", "ResizeArea"); description = "ResizeBilinear: Bilinear interpolation. If 'antialias' is true, becomes a hat/tent filter function with radius 1 when downsampling.\n" +
|
||||
"ResizeLanczos5: Lanczos kernel with radius 5. Very-high-quality filter but may have stronger ringing.\n" +
|
||||
"ResizeBicubic: Cubic interpolant of Keys. Equivalent to Catmull-Rom kernel. Reasonably good quality and faster than Lanczos3Kernel, particularly when upsampling.\n" +
|
||||
"ResizeGaussian: Gaussian kernel with radius 3, sigma = 1.5 / 3.0.\n" +
|
||||
"ResizeNearest: Nearest neighbor interpolation. 'antialias' has no effect when used with nearest neighbor interpolation.\n" +
|
||||
"ResizeArea: Anti-aliased resampling with area interpolation. 'antialias' has no effect when used with area interpolation; it always anti-aliases.\n" +
|
||||
"ResizeMitchellcubic: Mitchell-Netravali Cubic non-interpolating filter. For synthetic images (especially those lacking proper prefiltering), less ringing than Keys cubic kernel but less sharp." }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Output image" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Resize images to size using the specified method.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("resizeBiLinear") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "ResizeBilinear"
|
||||
Input(NUMERIC,"input") { description = "4D image"}
|
||||
Arg(INT ,"height") { description = "target height for resizing to "}
|
||||
Arg(INT ,"width") { description = "target width for resizing to"}
|
||||
Arg(BOOL ,"alignCorners") { description = "whether to align corners during resizing. Images are aligned to preserve corners."}
|
||||
Arg(BOOL,"halfPixelCenters") { description = "When resizing, assumes pixels are centered at 0.5."}
|
||||
Output(NUMERIC, "output"){ description = "Output image" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Resize images to size using the specified method.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("resizeBiCubic") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.image"
|
||||
javaOpClass = "ResizeBicubic"
|
||||
Input(NUMERIC,"input") { description = "4D image"}
|
||||
Input(INT ,"size") { description = "the target size to resize to "}
|
||||
Arg(BOOL ,"alignCorners") { description = "whether to align corners during resizing. Images are aligned to preserve corners."}
|
||||
Arg(BOOL,"alignPixelCenters") { description = "When resizing, assumes pixels are centered at 0.5."}
|
||||
Output(NUMERIC, "output"){ description = "Output image" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Resize images to size using the specified method.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.DataType
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
import org.nd4j.codegen.api.Range
|
||||
|
||||
|
||||
fun Linalg() = Namespace("Linalg") {
|
||||
//val namespaceJavaPackage = "org.nd4j.linalg"
|
||||
|
||||
Op("Cholesky") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms"
|
||||
javaOpClass = "Cholesky"
|
||||
Input(DataType.NUMERIC, "input") { description = "Input tensor with inner-most 2 dimensions forming square matrices" }
|
||||
Output(DataType.NUMERIC, "output"){ description = "Transformed tensor" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Computes the Cholesky decomposition of one or more square matrices.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("Lstsq") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Lstsq"
|
||||
|
||||
Input(DataType.NUMERIC, "matrix") {description = "input tensor"}
|
||||
Input(DataType.NUMERIC, "rhs") {description = "input tensor"}
|
||||
Arg(DataType.FLOATING_POINT, "l2_reguralizer") {description = "regularizer"}
|
||||
Arg(DataType.BOOL, "fast") {description = "fast mode, defaults to True"; defaultValue = true}
|
||||
Output(DataType.FLOATING_POINT, "output"){ description = "Transformed tensor" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Solver for linear squares problems.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("Solve") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "LinearSolve"
|
||||
|
||||
Input(DataType.NUMERIC, "matrix") {description = "input tensor"}
|
||||
Input(DataType.NUMERIC, "rhs") {description = "input tensor"}
|
||||
Arg(DataType.BOOL, "adjoint") {description = "adjoint mode, defaults to False"; defaultValue = false}
|
||||
Output(FLOATING_POINT, "output"){ description = "Output tensor" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Solver for systems of linear equations.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("TriangularSolve") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "TriangularSolve"
|
||||
|
||||
Input(DataType.NUMERIC, "matrix") {description = "input tensor"}
|
||||
Input(DataType.NUMERIC, "rhs") {description = "input tensor"}
|
||||
Arg(DataType.BOOL, "lower") {description = "defines whether innermost matrices in matrix are lower or upper triangular"}
|
||||
Arg(DataType.BOOL, "adjoint") {description = "adjoint mode"}
|
||||
Output(DataType.FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Solver for systems of linear questions.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("Lu") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Lu"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {description = "input tensor"}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Computes LU decomposition.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("Matmul") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.reduce"
|
||||
javaOpClass = "Mmul"
|
||||
|
||||
Input(DataType.NUMERIC, "a") {description = "input tensor"}
|
||||
Input(DataType.NUMERIC, "b") {description = "input tensor"}
|
||||
Arg(DataType.FLOATING_POINT,"alpha",{defaultValue = 1.0; description = "Defaults to 1.0: the scalar multiplier for the product of a* b "})
|
||||
Arg(DataType.FLOATING_POINT,"beta",{defaultValue = 1.0; description = "Defaults to 1.0: the scalar multiplier for c "})
|
||||
Arg(DataType.BOOL,"transA",{defaultValue = false; description = "Whether to transpose a when running multiply "})
|
||||
Arg(DataType.BOOL,"transB",{defaultValue = false; description = "Whether to transpose b when running multiply "})
|
||||
Output(DataType.FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Performs matrix multiplication on input tensors.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("Qr") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "Qr"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {description = "input tensor"}
|
||||
Arg(DataType.BOOL, "full") {description = "full matrices mode"; defaultValue = false}
|
||||
Output(FLOATING_POINT, "outputQ")
|
||||
Output(FLOATING_POINT, "outputR")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Computes the QR decompositions of input matrix.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("MatrixBandPart") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "MatrixBandPart"
|
||||
|
||||
Input(DataType.NUMERIC, "input") { description = "input tensor" }
|
||||
Arg(DataType.INT, "minLower") { description = "lower diagonal count" }
|
||||
Arg(DataType.INT, "maxUpper") { description = "upper diagonal count" }
|
||||
Output(DataType.FLOATING_POINT, "output1")
|
||||
Output(DataType.FLOATING_POINT, "output2")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Copy a tensor setting outside a central band in each innermost matrix.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("cross") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.shape"
|
||||
javaOpClass = "Cross"
|
||||
|
||||
Input(DataType.NUMERIC, "a") {"Input tensor a"}
|
||||
Input(DataType.NUMERIC, "b") {"Input tensor b"}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Computes pairwise cross product.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("diag") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.shape"
|
||||
javaOpClass = "Diag"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(DataType.FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates diagonal tensor.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("diag_part") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.shape"
|
||||
javaOpClass = "DiagPart"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(DataType.FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates diagonal tensor.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Op("matrixDeterminant") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "MatrixDeterminant"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates matrix determinant.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("logdet") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Logdet"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates log of determinant.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("matrixInverse") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "MatrixInverse"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Inverts a matrix
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("eig") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Eig"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Output(FLOATING_POINT, "eigenValues")
|
||||
Output(FLOATING_POINT, "eigenVectors")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates eigen values
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("svd") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "Svd"
|
||||
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Arg(DataType.BOOL, "fullUV") {"Full matrices mode"}
|
||||
Arg(DataType.BOOL, "computeUV") {"Compute U and V"}
|
||||
Arg(DataType.INT, "switchNum") {"Switch number"; defaultValue = 16}
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Calculates singular value decomposition.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("tri") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Tri"
|
||||
|
||||
Arg(DATA_TYPE, "dataType") { description = "Data type"; defaultValue = org.nd4j.linalg.api.buffer.DataType.FLOAT }
|
||||
Arg(INT, "row") {"Number of rows in the array"; }
|
||||
Arg(INT, "column") {"Number of columns in the array"; }
|
||||
Arg(INT, "diagonal") {"The sub-diagonal at and below which the array is filled. k = 0 is the main diagonal, while k < 0 is below it, and k > 0 is above. The default is 0."; defaultValue = 0}
|
||||
|
||||
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
An array with ones at and below the given diagonal and zeros elsewhere.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("triu") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.custom"
|
||||
javaOpClass = "Triu"
|
||||
Input(DataType.NUMERIC, "input") {"Input tensor"}
|
||||
Arg(DataType.INT, "diag") {"diagonal"; defaultValue = 0}
|
||||
|
||||
Output(FLOATING_POINT, "output")
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Upper triangle of an array. Return a copy of a input tensor with the elements below the k-th diagonal zeroed.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Alias(SDBaseOps(), "mmul")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
import org.nd4j.codegen.mixins.transformStrict
|
||||
|
||||
fun NN() = Namespace("NN") {
|
||||
val convPkg = "org.nd4j.linalg.api.ops.impl.layers.convolution"
|
||||
|
||||
Op("batchNorm") {
|
||||
javaPackage = convPkg
|
||||
Input(NUMERIC, "input") { description = "Input variable." }
|
||||
Input(NUMERIC, "mean") { description = "Mean value. For 1d axis, this should match input.size(axis)" }
|
||||
Input(NUMERIC, "variance") { description = "Variance value. For 1d axis, this should match input.size(axis)" }
|
||||
Input(NUMERIC, "gamma") { description = "Gamma value. For 1d axis, this should match input.size(axis)" }
|
||||
Input(NUMERIC, "beta") { description = "Beta value. For 1d axis, this should match input.size(axis)" }
|
||||
Arg(NUMERIC, "epsilon") { description = "Epsilon constant for numerical stability (to avoid division by 0)" }
|
||||
Arg(INT, "axis") {
|
||||
count = AtLeast(1)
|
||||
description = "For 2d CNN activations: 1 for NCHW format activations, or 3 for NHWC format activations.\n" +
|
||||
"For 3d CNN activations: 1 for NCDHW format, 4 for NDHWC\n" +
|
||||
"For 1d/RNN activations: 1 for NCW format, 2 for NWC"
|
||||
}
|
||||
|
||||
Output(NUMERIC, "output") { description = "variable for batch normalization" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Neural network batch normalization operation.
|
||||
For details, see <a href="https://arxiv.org/abs/1502.03167">https://arxiv.org/abs/1502.03167</a>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("biasAdd") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.broadcast"
|
||||
Input(NUMERIC, "input") { description = "4d input variable" }
|
||||
Input(NUMERIC, "bias") { description = "1d bias" }
|
||||
Arg(BOOL, "nchw") { description = "The format - nchw=true means [minibatch, channels, height, width] format; nchw=false - [minibatch, height, width, channels].\n" +
|
||||
"Unused for 2d inputs" }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Output variable, after applying bias add operation" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Bias addition operation: a special case of addition, typically used with CNN 4D activations and a 1D bias vector
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("dropout") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.random.impl"
|
||||
javaOpClass = "CustomDropOut"
|
||||
Input(NUMERIC, "input") { description = "Input array" }
|
||||
Arg(BOOL, "inverted") { description = "Whether dropout should be inverted or not." }
|
||||
Arg(INT, "seed") { description = "the seed for dropout"; defaultValue = 0 }
|
||||
Arg(NUMERIC,"probabilityValue") { description = "the chance of dropping a value to 0. Maybe interpreted as 1 - p if inverted is true."}
|
||||
Output(NUMERIC, "output") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Dropout operation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("elu", transformStrict) {
|
||||
javaOpClass = "ELU"
|
||||
legacy = false
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise exponential linear unit (ELU) function:
|
||||
out = x if x > 0
|
||||
out = a * (exp(x) - 1) if x <= 0
|
||||
with constant a = 1.0
|
||||
<p>
|
||||
See: <a href="https://arxiv.org/abs/1511.07289">https://arxiv.org/abs/1511.07289</a>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("gelu", transformStrict) {
|
||||
javaOpClass = "GELU"
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
GELU activation function - Gaussian Error Linear Units
|
||||
For more details, see <i>Gaussian Error Linear Units (GELUs)</i> - <a href="https://arxiv.org/abs/1606.08415">https://arxiv.org/abs/1606.08415</a>
|
||||
This method uses the sigmoid approximation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("hardSigmoid", transformStrict) {
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise hard sigmoid function:
|
||||
out[i] = 0 if in[i] <= -2.5
|
||||
out[1] = 0.2*in[i]+0.5 if -2.5 < in[i] < 2.5
|
||||
out[i] = 1 if in[i] >= 2.5
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("hardTanh", transformStrict) {
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise hard tanh function:
|
||||
out[i] = -1 if in[i] <= -1
|
||||
out[1] = in[i] if -1 < in[i] < 1
|
||||
out[i] = 1 if in[i] >= 1
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("hardTanhDerivative") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.gradient"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input variable" }
|
||||
Output(NUMERIC, "output"){ description = "Output variable" }
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Derivative (dOut/dIn) of the element-wise hard Tanh function - hardTanh(%INPUT_TYPE%)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("leakyRelu") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.scalar"
|
||||
javaOpClass = "LeakyReLU"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input variable" }
|
||||
Arg(NUMERIC, "alpha") { description = "Cutoff - commonly 0.01" }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise leaky ReLU function:
|
||||
out = x if x >= 0.0
|
||||
out = alpha * x if x < cutoff
|
||||
Alpha value is most commonly set to 0.01
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("leakyReluDerivative") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.gradient"
|
||||
javaOpClass = "LeakyReLUDerivative"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input variable" }
|
||||
Arg(FLOATING_POINT, "alpha") { description = "Cutoff - commonly 0.01" }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Leaky ReLU derivative: dOut/dIn given input.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("CReLU") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "CReLU"
|
||||
Input(NUMERIC, "x") { description = "Input variable" }
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Concatenates a ReLU which selects only the positive part of the activation with a ReLU which selects only the negative part of the activation. Note that as a result this non-linearity doubles the depth of the activations.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("linear") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "XwPlusB"
|
||||
Input(NUMERIC, "input") { description = "Input data" }
|
||||
Input(NUMERIC, "weights") { description = "Weights variable, shape [nIn, nOut]" }
|
||||
Input(NUMERIC, "bias") { description = "Optional bias variable (may be null)" /*; optional = true*/ }
|
||||
Arg(BOOL,"transposeA") { description = "Whether to transpose input or not"; defaultValue= false}
|
||||
Arg(BOOL,"transposeB") { description = "Whether to transpose second input or not"; defaultValue= false}
|
||||
Arg(BOOL,"transposeC") { description = "Whether to transpose result or not"; defaultValue= false}
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Linear layer operation: out = mmul(in,w) + bias
|
||||
Note that bias array is optional
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("logSigmoid", transformStrict) {
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise sigmoid function: out[i] = log(sigmoid(in[i]))
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("logSoftmax") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "LogSoftMax"
|
||||
Input(NUMERIC, "x") { description = "" }
|
||||
Output(NUMERIC, "output") { description = "" }
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Log softmax activation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("logSoftmax") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "LogSoftMax"
|
||||
Input(NUMERIC, "x") { description = "Input" }
|
||||
Arg(INT, "dimension") { description = "Dimension along which to apply log softmax" }
|
||||
Output(NUMERIC, "output") { description = "Output - log(softmax(input))" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Log softmax activation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("relu") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.scalar"
|
||||
javaOpClass = "RectifiedLinear"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input" }
|
||||
Arg(NUMERIC, "cutoff") { description = "Cutoff value for ReLU operation - x > cutoff ? x : 0. Usually 0" }
|
||||
Output(NUMERIC, "output") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise rectified linear function with specified cutoff:
|
||||
out[i] = in[i] if in[i] >= cutoff
|
||||
out[i] = 0 otherwise
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("relu6") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.scalar"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input" }
|
||||
Arg(NUMERIC, "cutoff") { description = "Cutoff value for ReLU operation. Usually 0" }
|
||||
Output(NUMERIC, "output") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise "rectified linear 6" function with specified cutoff:
|
||||
out[i] = min(max(in, cutoff), 6)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("reluLayer") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms"
|
||||
Input(NUMERIC, "input") { description = "Input data" }
|
||||
Input(NUMERIC, "weights") { description = "Weights variable" }
|
||||
Input(NUMERIC, "bias") { description = " Bias variable" }
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
ReLU (Rectified Linear Unit) layer operation: out = relu(mmul(in,w) + bias)
|
||||
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("preciseGelu", transformStrict) {
|
||||
javaOpClass = "PreciseGELU"
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
GELU activation function - Gaussian Error Linear Units
|
||||
For more details, see <i>Gaussian Error Linear Units (GELUs)</i> - <a href="https://arxiv.org/abs/1606.08415">https://arxiv.org/abs/1606.08415</a>
|
||||
This method uses the precise method
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("prelu") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.scalar"
|
||||
javaOpClass = "PRelu"
|
||||
Input(NUMERIC, "input") { description = "Input data" }
|
||||
Input(NUMERIC, "alpha") { description = "The cutoff variable. Note that the batch dimension (the 0th, whether it is batch or not) should not be part of alpha." }
|
||||
Arg(INT, "sharedAxes") { count = AtLeast(1); description = "Which axes to share cutoff parameters along." }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
PReLU (Parameterized Rectified Linear Unit) operation. Like LeakyReLU with a learnable alpha:
|
||||
out[i] = in[i] if in[i] >= 0
|
||||
out[i] = in[i] * alpha[i] otherwise
|
||||
|
||||
sharedAxes allows you to share learnable parameters along axes.
|
||||
For example, if the input has shape [batchSize, channels, height, width]
|
||||
and you want each channel to have its own cutoff, use sharedAxes = [2, 3] and an
|
||||
alpha with shape [channels].
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("selu", transformStrict) {
|
||||
javaOpClass = "SELU"
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise SeLU function - Scaled exponential Lineal Unit: see <a href="https://arxiv.org/abs/1706.02515">Self-Normalizing Neural Networks</a>
|
||||
|
||||
out[i] = scale * alpha * (exp(in[i])-1) if in[i]>0, or 0 if in[i] <= 0
|
||||
Uses default scale and alpha values.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("sigmoid", transformStrict) {
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise sigmoid function: out[i] = 1.0/(1+exp(-in[i]))
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("sigmoidDerivative") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.gradient"
|
||||
Input(NUMERIC, "x") { description = "Input Variable" }
|
||||
Input(NUMERIC, "wrt") { description = "Gradient at the output - dL/dOut. Must have same shape as the input" }
|
||||
Output(NUMERIC, "output") { description = "Output (gradient at input of sigmoid)" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise sigmoid function derivative: dL/dIn given input and dL/dOut
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("softmax") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
javaOpClass = "SoftMax"
|
||||
Input(NUMERIC, "x") { description = "Input" }
|
||||
Arg(INT, "dimension") { description = "Dimension along which to apply softmax"; defaultValue = -1 }
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Softmax activation, along the specified dimension
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("softplus", transformStrict) {
|
||||
javaOpClass = "SoftPlus"
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise softplus function: out = log(exp(x) + 1)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("softsign", transformStrict) {
|
||||
javaOpClass = "SoftSign"
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise softsign function: out = x / (abs(x) + 1)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("softsignDerivative") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.gradient"
|
||||
javaOpClass = "SoftSignDerivative"
|
||||
legacy = true
|
||||
Input(NUMERIC, "x") { description = "Input variable" }
|
||||
Output(NUMERIC, "output") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise derivative (dOut/dIn) of the softsign function softsign(%INPUT_TYPE%)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("swish", transformStrict) {
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Element-wise "swish" function: out = x * sigmoid(b*x) with b=1.0
|
||||
See: <a href="https://arxiv.org/abs/1710.05941">https://arxiv.org/abs/1710.05941</a>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("layerNorm") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
val input = Input(NUMERIC, "input") { description = "Input variable" }
|
||||
val g = Input(NUMERIC, "gain") { description = "Gain" }
|
||||
Input(NUMERIC, "bias") { description = "Bias"; defaultValue = null}
|
||||
val ch = Arg(BOOL, "channelsFirst") { description = "For 2D input - unused. True for NCHW (minibatch, channels, height, width), false for NHWC data" }
|
||||
val dim = Arg(LONG, "dimensions") { count = AtLeast(1); description = "Dimensions to perform layer norm over - dimension=1 for 2d/MLP data, dimension=1,2,3 for CNNs" }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Output variable" }
|
||||
|
||||
AllParamSignature()
|
||||
Signature(input, g, ch, dim)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Apply Layer Normalization
|
||||
|
||||
y = gain * standardize(x) + bias
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("dotProductAttentionV2") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
val q = Input(NUMERIC, "queries") { description = "A {@link SDVariable} representing the query tensor. Shape: [batchSize, numQueries, queryDim]" }
|
||||
val v = Input(NUMERIC, "values") { description = "A {@link SDVariable} representing the value tensor. Shape: [batchSize, numValues, valueDim]" }
|
||||
|
||||
val k = Input(NUMERIC, "keys") { description = "A {@link SDVariable} representing the key tensor. Shape: [batchSize, numValues, keyDim]" }
|
||||
val queryMask = Input(NUMERIC, "queryMask") { description = "A {@link SDVariable} representing the query mask tensor. Shape: [batchSize, numQueries]" }
|
||||
val valueMask = Input(NUMERIC, "valueMask") { description = "@param valueMask A {@link SDVariable} representing the value mask tensor. Shape: [batchSize, numValues]" }
|
||||
|
||||
val s = Arg(FLOATING_POINT, "scaleFactor") { defaultValue = 1.0; description = "@param scaleFactor A {@code double} scaling factor applied to the dot product between queries and keys." }
|
||||
val dropout = Arg(FLOATING_POINT, "dropoutProbability") { defaultValue = 0.0; description = "A {@code double} specifying the dropout probability to be applied to attention weights." }
|
||||
val useCausalMask = Arg(BOOL, "useCausalMask") { defaultValue = false; description = " A {@code boolean} flag to indicate whether to apply a causal mask to the attention scores, for autoregressive tasks." }
|
||||
val training = Arg(BOOL, "training") { defaultValue = false; description = " A {@code boolean} flag to indicate whether the layer is in training mode or inference mode, affecting dropout." }
|
||||
|
||||
Output(NUMERIC, "output") { description = " A {@link SDVariable} representing the output tensor of the dot product attention operation. Shape: [batchSize, numQueries, valueDim]"}
|
||||
|
||||
Signature(q,v,k,queryMask,valueMask, s,dropout,useCausalMask,training)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
This operation performs dot product attention on the given timeseries input with the given queries
|
||||
out = sum(similarity(k_i, q) * v_i)
|
||||
|
||||
similarity(k, q) = softmax(k * q) where x * q is the dot product of x and q
|
||||
|
||||
Optionally with normalization step:
|
||||
similarity(k, q) = softmax(k * q / sqrt(size(q))
|
||||
|
||||
See also "Attention is all you need" (https://arxiv.org/abs/1706.03762, p. 4, eq. 1)
|
||||
|
||||
Note: This supports multiple queries at once, if only one query is available the queries vector still has to
|
||||
be 3D but can have queryCount = 1
|
||||
|
||||
Note: keys and values usually is the same array. If you want to use it as the same array, simply pass it for
|
||||
both.
|
||||
|
||||
Note: Queries, keys and values must either be all rank 3 or all rank 4 arrays. Mixing them doesn't work. The
|
||||
output rank will depend on the input rank.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("dotProductAttention") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
val q = Input(NUMERIC, "queries") { description = "input 3D array \"queries\" of shape [batchSize, featureKeys, queryCount]\n" +
|
||||
"or 4D array of shape [batchSize, numHeads, featureKeys, queryCount]" }
|
||||
val k = Input(NUMERIC, "keys") { description = "input 3D array \"keys\" of shape [batchSize, featureKeys, timesteps]\n" +
|
||||
"or 4D array of shape [batchSize, numHeads, featureKeys, timesteps]" }
|
||||
val v = Input(NUMERIC, "values") { description = "input 3D array \"values\" of shape [batchSize, featureValues, timesteps]\n" +
|
||||
"or 4D array of shape [batchSize, numHeads, featureValues, timesteps]" }
|
||||
val m = Input(NUMERIC, "mask") { description = "OPTIONAL; array that defines which values should be skipped of shape [batchSize, timesteps]" }
|
||||
val s = Arg(BOOL, "scaled") { description = "normalization, false -> do not apply normalization, true -> apply normalization" }
|
||||
Arg(BOOL, "withWeights") { defaultValue = false; description = "withWeights return attention weights as well, false -> only one output, true -> two outputs" }
|
||||
|
||||
Output(NUMERIC, "output") { description = " Attention result arrays of shape [batchSize, featureValues, queryCount] or [batchSize, numHeads, featureValues, queryCount],\n" +
|
||||
"(optionally) Attention Weights of shape [batchSize, timesteps, queryCount] or [batchSize, numHeads, timesteps, queryCount]" }
|
||||
|
||||
Signature(q, k, v, m, s)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
This operation performs dot product attention on the given timeseries input with the given queries
|
||||
out = sum(similarity(k_i, q) * v_i)
|
||||
|
||||
similarity(k, q) = softmax(k * q) where x * q is the dot product of x and q
|
||||
|
||||
Optionally with normalization step:
|
||||
similarity(k, q) = softmax(k * q / sqrt(size(q))
|
||||
|
||||
See also "Attention is all you need" (https://arxiv.org/abs/1706.03762, p. 4, eq. 1)
|
||||
|
||||
Note: This supports multiple queries at once, if only one query is available the queries vector still has to
|
||||
be 3D but can have queryCount = 1
|
||||
|
||||
Note: keys and values usually is the same array. If you want to use it as the same array, simply pass it for
|
||||
both.
|
||||
|
||||
Note: Queries, keys and values must either be all rank 3 or all rank 4 arrays. Mixing them doesn't work. The
|
||||
output rank will depend on the input rank.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("multiHeadDotProductAttention") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
val q = Input(NUMERIC, "queries") { description = "input 3D array \"queries\" of shape [batchSize, featureKeys, queryCount]" }
|
||||
val k = Input(NUMERIC, "keys") { description = "input 3D array \"keys\" of shape [batchSize, featureKeys, timesteps]" }
|
||||
val v = Input(NUMERIC, "values") { description = "input 3D array \"values\" of shape [batchSize, featureValues, timesteps]" }
|
||||
val wq = Input(NUMERIC, "Wq") { description = "input query projection weights of shape [numHeads, projectedKeys, featureKeys]" }
|
||||
val wk = Input(NUMERIC, "Wk") { description = "input key projection weights of shape [numHeads, projectedKeys, featureKeys]" }
|
||||
val wv = Input(NUMERIC, "Wv") { description = "input value projection weights of shape [numHeads, projectedValues, featureValues]" }
|
||||
val wo = Input(NUMERIC, "Wo") { description = "output projection weights of shape [numHeads * projectedValues, outSize]" }
|
||||
val m = Input(NUMERIC, "mask") { description = "OPTIONAL; array that defines which values should be skipped of shape [batchSize, timesteps]" }
|
||||
val s = Arg(BOOL, "scaled") { description = "normalization, false -> do not apply normalization, true -> apply normalization" }
|
||||
Arg(BOOL, "withWeights") { defaultValue = false; description = "return attention weights as well, false -> only one output, true -> two outputs" }
|
||||
|
||||
Output(NUMERIC, "output") { description = "Attention result arrays of shape [batchSize, outSize, queryCount]\n" +
|
||||
"(optionally) Attention Weights of shape [batchSize, numHeads, timesteps, queryCount]" }
|
||||
|
||||
Signature(q, k, v, wq, wk, wv, wo, m, s)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
This performs multi-headed dot product attention on the given timeseries input
|
||||
out = concat(head_1, head_2, ..., head_n) * Wo
|
||||
head_i = dot_product_attention(Wq_i*q, Wk_i*k, Wv_i*v)
|
||||
|
||||
Optionally with normalization when calculating the attention for each head.
|
||||
|
||||
See also "Attention is all you need" (https://arxiv.org/abs/1706.03762, pp. 4,5, "3.2.2 Multi-Head Attention")
|
||||
|
||||
This makes use of dot_product_attention OP support for rank 4 inputs.
|
||||
see dotProductAttention(%INPUT_TYPE%, %INPUT_TYPE%, %INPUT_TYPE%, %INPUT_TYPE%, boolean, boolean)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("pad") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms"
|
||||
Input(NUMERIC, "input") { description = "Input tensor"}
|
||||
Input(NUMERIC, "padding") { description = "Padding value" }
|
||||
Arg(ENUM, "PadMode") { possibleValues = listOf("CONSTANT", "REFLECT", "SYMMETRIC"); description = "Padding format"; defaultValue="CONSTANT" }
|
||||
Arg(NUMERIC, "constant") { description = "Padding constant" }
|
||||
|
||||
Output(NUMERIC, "output"){ description = "Padded input" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Padding operation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("topK") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.custom"
|
||||
Input(NUMERIC, "input") { description = "Input data" }
|
||||
Arg(NUMERIC, "k") { description = "The number of values to return" }
|
||||
Arg(BOOL, "sorted") { description = "Whether to return the values sorted or not" }
|
||||
Output(NUMERIC, "output") { description = "the top k values in the input" }
|
||||
Output(NUMERIC, "indices") { description = "the indices of the top k values" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Find values and indices for the largest k entries along the last dimension.<br>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Alias(Math(), "tanh")
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
|
||||
fun SDRNN() = Namespace("RNN") {
|
||||
|
||||
|
||||
val LSTMConfiguration = Config("LSTMConfiguration") {
|
||||
|
||||
Arg(ENUM, "RnnDataFormat") {
|
||||
possibleValues = listOf("TNS", "NST", "NTS"); description = " The data format of the input. Input shape depends on data format (in config):<br>\n" +
|
||||
" TNS -> [timeSteps, batchSize, inSize]<br>\n" +
|
||||
" NST -> [batchSize, inSize, timeSteps]<br>\n" +
|
||||
" NTS -> [batchSize, timeSteps, inSize]<br>"
|
||||
}
|
||||
|
||||
|
||||
Arg(BOOL, "peepHole") { description = "Whether to provide peephole connections"; }
|
||||
Arg(NUMERIC, "forgetBias") { description = "The bias added to forget gates in order to reduce the scale of forgetting in the beginning of the training."; }
|
||||
Arg(NUMERIC, "clippingCellValue") { description = "The bias added to forget gates in order to reduce the scale of forgetting in the beginning of the training."; }
|
||||
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.config.LSTMConfiguration"
|
||||
}
|
||||
|
||||
|
||||
val LSTMLayerConfig = Config("LSTMLayerConfig") {
|
||||
|
||||
Arg(ENUM, "LSTMDataFormat") {
|
||||
possibleValues = listOf("TNS", "NST", "NTS", "T2NS");
|
||||
description = "for unidirectional:" +
|
||||
" TNS: shape [timeLength, numExamples, inOutSize] - sometimes referred to as \"time major\"<br>\n" +
|
||||
" NST: shape [numExamples, inOutSize, timeLength]<br>\n" +
|
||||
" NTS: shape [numExamples, timeLength, inOutSize] - TF \"time_major=false\" layout<br>" +
|
||||
" for bidirectional:\n" +
|
||||
" T2NS: 3 = [timeLength, 2, numExamples, inOutSize] (for ONNX)"
|
||||
}
|
||||
|
||||
|
||||
Arg(ENUM, "LSTMDirectionMode") {
|
||||
possibleValues = listOf("FWD", "BWD", "BIDIR_SUM", "BIDIR_CONCAT", "BIDIR_EXTRA_DIM"); description = "direction <br>\n" +
|
||||
" FWD: 0 = fwd\n" +
|
||||
" BWD: 1 = bwd\n" +
|
||||
" BIDIR_SUM: 2 = bidirectional sum\n" +
|
||||
" BIDIR_CONCAT: 3 = bidirectional concat\n" +
|
||||
" BIDIR_EXTRA_DIM: 4 = bidirectional extra output dim (in conjunction with format dataFormat = 3)"
|
||||
}
|
||||
|
||||
Arg(ENUM, "gateAct") {
|
||||
possibleValues = listOf("TANH",
|
||||
"RELU",
|
||||
"SIGMOID",
|
||||
"AFFINE",
|
||||
"LEAKY_RELU",
|
||||
"THRESHHOLD_RELU",
|
||||
"SCALED_TAHN",
|
||||
"HARD_SIGMOID",
|
||||
"ELU",
|
||||
"SOFTSIGN",
|
||||
"SOFTPLUS"); description = "Activations"
|
||||
}
|
||||
|
||||
|
||||
Arg(ENUM, "cellAct") {
|
||||
possibleValues = listOf("TANH",
|
||||
"RELU",
|
||||
"SIGMOID",
|
||||
"AFFINE",
|
||||
"LEAKY_RELU",
|
||||
"THRESHHOLD_RELU",
|
||||
"SCALED_TAHN",
|
||||
"HARD_SIGMOID",
|
||||
"ELU",
|
||||
"SOFTSIGN",
|
||||
"SOFTPLUS"); description = "Activations"
|
||||
}
|
||||
|
||||
|
||||
Arg(ENUM, "outAct") {
|
||||
possibleValues = listOf("TANH",
|
||||
"RELU",
|
||||
"SIGMOID",
|
||||
"AFFINE",
|
||||
"LEAKY_RELU",
|
||||
"THRESHHOLD_RELU",
|
||||
"SCALED_TAHN",
|
||||
"HARD_SIGMOID",
|
||||
"ELU",
|
||||
"SOFTSIGN",
|
||||
"SOFTPLUS"); description = "Activations"
|
||||
}
|
||||
|
||||
|
||||
Arg(BOOL, "retFullSequence") { description = "indicates whether to return whole time sequence h {h_0, h_1, ... , h_sL-1}"; defaultValue = true }
|
||||
Arg(BOOL, "retLastH") {
|
||||
description = "indicates whether to return output at last time step only,\n" +
|
||||
" in this case shape would be [bS, nOut] (exact shape depends on dataFormat argument)"; defaultValue = false
|
||||
}
|
||||
Arg(BOOL, "retLastC") {
|
||||
description = "indicates whether to return cells state at last time step only,\n" +
|
||||
" in this case shape would be [bS, nOut] (exact shape depends on dataFormat argument)"; defaultValue = false
|
||||
}
|
||||
Arg(NUMERIC, "cellClip") { description = "Cell clipping value, if it = 0 then do not apply clipping"; defaultValue = 0.0}
|
||||
|
||||
Arg(NUMERIC, "gateAlpha") {defaultValue=0.0}
|
||||
Arg(NUMERIC, "gateBeta") {defaultValue=0.0}
|
||||
Arg(NUMERIC, "cellAlpha") {defaultValue=0.0}
|
||||
Arg(NUMERIC, "cellBeta") {defaultValue=0.0}
|
||||
Arg(NUMERIC, "outAlpha") {defaultValue=0.0}
|
||||
Arg(NUMERIC, "outBeta") {defaultValue=0.0}
|
||||
|
||||
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.config.LSTMLayerConfig"
|
||||
}
|
||||
|
||||
|
||||
val GRUWeights = Config("GRUWeights") {
|
||||
Input(NUMERIC, "ruWeight")
|
||||
Input(NUMERIC, "cWeight")
|
||||
Input(NUMERIC, "ruBias")
|
||||
Input(NUMERIC, "cBias")
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.weights.GRUWeights"
|
||||
}
|
||||
|
||||
val SRUWeights = Config("SRUWeights") {
|
||||
Input(NUMERIC, "weights")
|
||||
Input(NUMERIC, "bias")
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.weights.SRUWeights"
|
||||
}
|
||||
|
||||
val LSTMWeights = Config("LSTMWeights") {
|
||||
Input(NUMERIC, "ruWeight")
|
||||
Input(NUMERIC, "inputPeepholeWeights")
|
||||
Input(NUMERIC, "forgetPeepholeWeights")
|
||||
Input(NUMERIC, "outputPeepholeWeights")
|
||||
Input(NUMERIC, "bias")
|
||||
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.weights.LSTMWeights"
|
||||
}
|
||||
|
||||
val LSTMLayerWeights = Config("LSTMLayerWeights") {
|
||||
Input(NUMERIC, "inputWeights") {description="input weights Wx:\n" +
|
||||
" 1) shapes `[nIn, 4*nOut]` for FWD,BWD " +
|
||||
" 2) shapes `[2, nIn, 4*nOut]` BIDIR_SUM, BIDIR_CONCAT and BIDIR_EXTRA_DIM"}
|
||||
Input(NUMERIC, "recurrentWeights") {description="recurrent weights Wr:\n" +
|
||||
" 1) shapes `[nIn, 4*nOut]` for FWD, BWD " +
|
||||
" 2) shapes `[2, nIn, 4*nOut]` BIDIR_SUM, BIDIR_CONCAT and BIDIR_EXTRA_DIM"}
|
||||
Input(NUMERIC, "biases") {description="biases\n"+
|
||||
" 1) shapes `[4*nOut]` for FWD, BWD " +
|
||||
" 2) shapes `[2, 4*nOut]` for BIDIR_SUM, BIDIR_CONCAT and BIDIR_EXTRA_DIM"
|
||||
defaultValue=null}
|
||||
Input(NUMERIC, "peepholeWeights") {description="peephole weights Wp:\n" +
|
||||
" 1) `[3*nOut]` when directionMode < 2\n" +
|
||||
" 2) `[2, 3*nOut]` when directionMode >= 2"; defaultValue=null}
|
||||
|
||||
|
||||
javaClassOverride = "org.nd4j.linalg.api.ops.impl.layers.recurrent.weights.LSTMLayerWeights"
|
||||
}
|
||||
|
||||
|
||||
val namespaceJavaPackage = "org.nd4j.linalg.api.ops.impl.layers.recurrent"
|
||||
Op("gruCell") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "GRUCell"
|
||||
Input(NUMERIC, "x") { description = "Input, with shape [batchSize, inSize]" }
|
||||
Input(NUMERIC, "hLast") { description = "Output of the previous cell/time step, with shape [batchSize, numUnits]" }
|
||||
useConfig(GRUWeights)
|
||||
Output(NUMERIC, "r") { description = "Reset gate output" }
|
||||
Output(NUMERIC, "u") { description = "Update gate output" }
|
||||
Output(NUMERIC, "c") { description = "Cell gate output" }
|
||||
Output(NUMERIC, "h") { description = "Cell output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The GRU cell. Does a single time step operation
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("gru") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "GRU"
|
||||
Input(NUMERIC, "x") { description = "input [time, bS, nIn]" }
|
||||
Input(NUMERIC, "hLast") { description = "initial cell output (at time step = 0) [bS, nOut]" }
|
||||
Input(NUMERIC, "Wx") { description = "input-to-hidden weights, [nIn, 3*nOut]" }
|
||||
Input(NUMERIC, "Wh") { description = "hidden-to-hidden weights, [nOut, 3*nOut]" }
|
||||
Input(NUMERIC, "biases") { description = "biases, [3*nOut]" }
|
||||
|
||||
Output(NUMERIC, "h") { description = "cell outputs [time, bS, nOut], that is per each time step" }
|
||||
|
||||
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The GRU operation. Gated Recurrent Unit - Cho et al. 2014.
|
||||
|
||||
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Op("lstmCell") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "LSTMBlockCell"
|
||||
Input(NUMERIC, "x") { description = "Input, with shape [batchSize, inSize]" }
|
||||
Input(NUMERIC, "cLast") { description = "Previous cell state, with shape [batchSize, numUnits]" }
|
||||
Input(NUMERIC, "yLast") { description = "revious cell output, with shape [batchSize, numUnits]" }
|
||||
useConfig(LSTMWeights)
|
||||
useConfig(LSTMConfiguration)
|
||||
|
||||
Output(NUMERIC, "i") { description = "Output - input modulation gate activations [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "c") { description = "Output - Activations, cell state (pre tanh) [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "f") { description = "Output - forget gate activations [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "o") { description = "Output - output gate activations [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "z") { description = "Output - input gate activations [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "h") { description = "Cell state, post tanh [batchSize, numUnits]." }
|
||||
Output(NUMERIC, "y") { description = "Current cell output [batchSize, numUnits]." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The LSTM cell. Does a single time step operation.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("lstmblock") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "LSTMBlock"
|
||||
Input(NUMERIC, "maxTSLength") {defaultValue=null}
|
||||
Input(NUMERIC, "x") { description = " Input, with shape dependent on the data format (in config)." }
|
||||
Input(NUMERIC, "cLast") { description = "Previous/initial cell state, with shape [batchSize, numUnits]" ; defaultValue=null}
|
||||
Input(NUMERIC, "yLast") { description = "Previous/initial cell output, with shape [batchSize, numUnits]" ; defaultValue=null }
|
||||
useConfig(LSTMWeights)
|
||||
useConfig(LSTMConfiguration)
|
||||
|
||||
Output(NUMERIC, "output") { description = "The layer's outputs." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The LSTM block
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("lstmLayer") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "LSTMLayer"
|
||||
Input(NUMERIC, "x") { description = " Input, with shape dependent on the data format (in config)." }
|
||||
Input(NUMERIC, "cLast") { description = "Previous/initial cell state, with shape [batchSize, numUnits]"; defaultValue=null }
|
||||
Input(NUMERIC, "yLast") { description = "Previous/initial cell output, with shape [batchSize, numUnits]"; defaultValue=null }
|
||||
Input(NUMERIC, "maxTSLength") { description = "maxTSLength with shape [batchSize]"; defaultValue=null }
|
||||
useConfig(LSTMLayerWeights)
|
||||
useConfig(LSTMLayerConfig)
|
||||
|
||||
//TODO these are optional
|
||||
Output(NUMERIC, "output") { description = "The layer's outputs - full time series" }
|
||||
Output(NUMERIC, "yLast") { description = "The layer's outputs - last time step activations (yLast)" }
|
||||
Output(NUMERIC, "cLast") { description = "The layer's outputs - last time step cell state (cLast)" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Long Short-Term Memory layer - Hochreiter 1997.
|
||||
SUPPORTS following data formats:
|
||||
for unidirectional:
|
||||
TNS: shapes [timeLength, numExamples, inOutSize]
|
||||
NST: shapes [numExamples, inOutSize, timeLength]
|
||||
NTS: shapes [numExamples, timeLength, inOutSize]
|
||||
for bidirectional:
|
||||
T2NS: shapes [timeLength, 2, numExamples, inOutSize] (for ONNX)
|
||||
SUPPORTS following direction modes:
|
||||
FWD: forward
|
||||
BWD: backward
|
||||
BIDIR_SUM: bidirectional sum
|
||||
BIDIR_CONCAT: bidirectional concat
|
||||
BIDIR_EXTRA_DIM: bidirectional extra output dim (in conjunction with format dataFormat - T2NS)
|
||||
You may use different gate configurations:
|
||||
specify gate/cell/out aplha/beta and numbers of activations for gate/cell/out described in activations enum
|
||||
("RELU","SIGMOID","AFFINE","LEAKY_RELU","THRESHHOLD_RELU","SCALED_TAHN","HARD_SIGMOID","ELU","SOFTSIGN","SOFTPLUS")
|
||||
Also this layer supports MKLDNN (DNNL) and cuDNN acceleration
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Op("sruCell") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "SRUCell"
|
||||
Input(NUMERIC, "x") { description = "Input, with shape [batchSize, inSize]" }
|
||||
Input(NUMERIC, "cLast") { description = "Previous cell state, with shape [batchSize, inSize]" }
|
||||
useConfig(SRUWeights)
|
||||
|
||||
Output(NUMERIC, "output") { description = "The cell's outputs." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The SRU layer. Does a single time step operation.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("sru") {
|
||||
javaPackage = namespaceJavaPackage
|
||||
javaOpClass = "SRU"
|
||||
Input(NUMERIC, "x") { description = "Input, with shape [batchSize, inSize]" }
|
||||
Input(NUMERIC, "initialC") { description = "Initial cell state, with shape [batchSize, inSize]" }
|
||||
Input(NUMERIC, "mask") { description = "An optional dropout mask, with shape [batchSize, inSize]"; defaultValue = null }
|
||||
|
||||
useConfig(SRUWeights)
|
||||
|
||||
Output(NUMERIC, "output") { description = "The cell's outputs.." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
The SRU layer. Does a single time step operation.
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
|
||||
fun Random() = Namespace("Random") {
|
||||
val random = Mixin("random"){
|
||||
Arg(DATA_TYPE, "datatype"){ description = "Data type of the output variable"}
|
||||
Arg(LONG, "shape") { count = AtLeast(0); description = "Shape of the new random %INPUT_TYPE%, as a 1D array" }
|
||||
Output(NUMERIC, "output") { description = "Tensor with the given shape where values are randomly sampled according to a %OP_NAME% distribution" }
|
||||
}
|
||||
|
||||
val legacyRandom = Mixin("legacyRandom"){
|
||||
useMixin(random)
|
||||
javaPackage = "org.nd4j.linalg.api.ops.random.impl"
|
||||
legacy = true
|
||||
}
|
||||
|
||||
val normalRandom = Mixin("normalRandom"){
|
||||
Arg(FLOATING_POINT, "mean") { description = "Mean value for the random array" }
|
||||
Arg(FLOATING_POINT, "stddev") { description = "Standard deviation for the random array" }
|
||||
useMixin(legacyRandom)
|
||||
}
|
||||
|
||||
Op("bernoulli") {
|
||||
javaOpClass = "BernoulliDistribution"
|
||||
Arg(FLOATING_POINT, "p") { description = "Probability of value 1" }
|
||||
useMixin(legacyRandom)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a Bernoulli distribution,
|
||||
with the specified probability. Array values will have value 1 with probability P and value 0 with probability
|
||||
1-P.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("binomial") {
|
||||
javaOpClass = "BinomialDistribution"
|
||||
|
||||
Arg(INT, "nTrials") { description = "Number of trials parameter for the binomial distribution" }
|
||||
Arg(FLOATING_POINT, "p") { description = "Probability of success for each trial" }
|
||||
useMixin(legacyRandom)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a Binomial distribution,
|
||||
with the specified number of trials and probability.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("exponential") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.random.custom"
|
||||
javaOpClass = "RandomExponential"
|
||||
|
||||
val lambda = Arg(FLOATING_POINT, "lambda") { description = "lambda parameter" }
|
||||
Constraint("Must be positive") { lambda gt 0 }
|
||||
useMixin(random)
|
||||
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a exponential distribution:
|
||||
P(x) = lambda * exp(-lambda * x)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("logNormal", normalRandom) {
|
||||
javaOpClass = "LogNormalDistribution"
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a Log Normal distribution,
|
||||
i.e., {@code log(x) ~ N(mean, stdev)}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("normal", normalRandom) {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.random.impl"
|
||||
javaOpClass = "GaussianDistribution"
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a Gaussian (normal) distribution,
|
||||
N(mean, stdev)<br>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("normalTruncated", normalRandom) {
|
||||
javaOpClass = "TruncatedNormalDistribution"
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a Gaussian (normal) distribution,
|
||||
N(mean, stdev). However, any values more than 1 standard deviation from the mean are dropped and re-sampled
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("uniform") {
|
||||
javaOpClass = "UniformDistribution"
|
||||
|
||||
Arg(FLOATING_POINT, "min") { description = "Minimum value" }
|
||||
Arg(FLOATING_POINT, "max") { description = "Maximum value." }
|
||||
useMixin(legacyRandom)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
Generate a new random %INPUT_TYPE%, where values are randomly sampled according to a uniform distribution,
|
||||
U(min,max)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generated using ExtractFromExisting.kt
|
||||
*/
|
||||
|
||||
package org.nd4j.codegen.ops
|
||||
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.dsl.*
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.LossReduce
|
||||
|
||||
fun SDLoss() = Namespace("Loss"){
|
||||
|
||||
Op("absoluteDifference") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "AbsoluteDifferenceLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Output(NUMERIC, "output"){ description = "loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Absolute difference loss: {@code sum_i abs( label[i] - predictions[i] )}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("ctcLoss") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "CtcLoss"
|
||||
Input(NUMERIC, "targetLabels") { description = "Label array" }
|
||||
Input(NUMERIC, "logitInput") { description = "Inputs" }
|
||||
Input(NUMERIC, "targetLabelLengths") { description = "Length of the target label" }
|
||||
Input(NUMERIC, "logitInputLengths") { description = "Length of the input"}
|
||||
Arg(INT,"blankIndex") {description = "The index of the blank label"; defaultValue = 0}
|
||||
Output(NUMERIC, "output"){ description = "Ctc loss " }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
CTC Loss: Connectionist Temporal Classification Loss. See:
|
||||
https://dl.acm.org/citation.cfm?id=1143891
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("cosineDistance") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "CosineDistanceLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is use" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(INT, "dimension") { description = "Dimension to perform the cosine distance over" }
|
||||
Output(NUMERIC, "output"){ description = "Cosine distance loss " }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Cosine distance loss: {@code 1 - cosineSimilarity(x,y)} or {@code 1 - sum_i label[i] * prediction[i]}, which is
|
||||
equivalent to cosine distance when both the predictions and labels are normalized.<br>
|
||||
<b>Note</b>: This loss function assumes that both the predictions and labels are normalized to have unit l2 norm.
|
||||
If this is not the case, you should normalize them first by dividing by norm2(String, SDVariable, boolean, int...)
|
||||
along the cosine distance dimension (with keepDims=true).
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("hingeLoss") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "HingeLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array. Each value should be 0.0 or 1.0 (internally -1 to 1 is used)" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Hinge loss: a loss function used for training classifiers.
|
||||
Implements {@code L = max(0, 1 - t * predictions)} where t is the label values after internally converting to {-1,1}
|
||||
from the user specified {0,1}. Note that Labels should be provided with values {0,1}.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op("huberLoss") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "HuberLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(FLOATING_POINT, "delta") { description = "Loss function delta value" }
|
||||
Output(NUMERIC, "output"){ description = "Huber loss" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Huber loss function, used for robust regression. It is similar both squared error loss and absolute difference loss,
|
||||
though is less sensitive to outliers than squared error.<br>
|
||||
Huber loss implements:
|
||||
<pre>
|
||||
{@code L = 0.5 * (label[i] - predictions[i])^2 if abs(label[i] - predictions[i]) < delta}
|
||||
{@code L = delta * abs(label[i] - predictions[i]) - 0.5 * delta^2 otherwise}
|
||||
</pre>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("l2Loss") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "L2Loss"
|
||||
Input(NUMERIC, "var") { description = "Variable to calculate L2 loss of" }
|
||||
Output(NUMERIC, "output"){ description = "L2 loss" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
L2 loss: 1/2 * sum(x^2)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("logLoss") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "LogLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used"; defaultValue = null }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(FLOATING_POINT, "epsilon") { description = "epsilon"; defaultValue = 0.0 }
|
||||
Output(NUMERIC, "output"){ description = "Log loss " }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Log loss, i.e., binary cross entropy loss, usually used for binary multi-label classification. Implements:
|
||||
{@code -1/numExamples * sum_i (labels[i] * log(predictions[i] + epsilon) + (1-labels[i]) * log(1-predictions[i] + epsilon))}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("logPoisson") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "LogPoissonLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array. Each value should be 0.0 or 1.0" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array (has to be log(x) of actual predictions)" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(BOOL, "full") {description = "Boolean flag. true for logPoissonFull, false for logPoisson"}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Log poisson loss: a loss function used for training classifiers.
|
||||
Implements {@code L = exp(c) - z * c} where c is log(predictions) and z is labels.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
// logPoissonFull is not implemented. Simply a moniker for logPoisson with full = true
|
||||
|
||||
Op("meanPairwiseSquaredError") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "MeanPairwiseSquaredErrorLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used. Must be either null, scalar, or have shape [batchSize]" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable, scalar output" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Mean pairwise squared error.<br>
|
||||
MPWSE loss calculates the difference between pairs of consecutive elements in the predictions and labels arrays.
|
||||
For example, if predictions = [p0, p1, p2] and labels are [l0, l1, l2] then MPWSE is:
|
||||
{@code [((p0-p1) - (l0-l1))^2 + ((p0-p2) - (l0-l2))^2 + ((p1-p2) - (l1-l2))^2] / 3}<br>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("meanSquaredError") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "MeanSquaredErrorLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictions") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Mean squared error loss function. Implements {@code (label[i] - prediction[i])^2} - i.e., squared error on a per-element basis.
|
||||
When averaged (using LossReduce#MEAN_BY_WEIGHT or LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT (the default))
|
||||
this is the mean squared error loss function.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("sigmoidCrossEntropy") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "SigmoidCrossEntropyLoss"
|
||||
Input(NUMERIC, "label") { description = "Label array" }
|
||||
Input(NUMERIC, "predictionLogits") { description = "Predictions array" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(FLOATING_POINT, "labelSmoothing") { description = "Label smoothing value. Default value: 0"; defaultValue = 0.0}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Sigmoid cross entropy: applies the sigmoid activation function on the input logits (input "pre-sigmoid preductions")
|
||||
and implements the binary cross entropy loss function. This implementation is numerically more stable than using
|
||||
standard (but separate) sigmoid activation function and log loss (binary cross entropy) loss function.<br>
|
||||
Implements:
|
||||
{@code -1/numExamples * sum_i (labels[i] * log(sigmoid(logits[i])) + (1-labels[i]) * log(1-sigmoid(logits[i])))}
|
||||
though this is done in a mathematically equivalent but more numerical stable form.<br>
|
||||
<br>
|
||||
When label smoothing is > 0, the following label smoothing is used:<br>
|
||||
<pre>
|
||||
{@code numClasses = labels.size(1);
|
||||
label = (1.0 - labelSmoothing) * label + 0.5 * labelSmoothing}
|
||||
</pre>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("softmaxCrossEntropy") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "SoftmaxCrossEntropyLoss"
|
||||
Input(NUMERIC, "oneHotLabels") { description = "Label array. Should be one-hot per example and same shape as predictions (for example, [mb, nOut])" }
|
||||
Input(NUMERIC, "logitPredictions") { description = "Predictions array (pre-softmax)" }
|
||||
Input(NUMERIC, "weights") { description = "Weights array. May be null. If null, a weight of 1.0 is used" }
|
||||
Arg(LOSS_REDUCE, "lossReduce") { description = "Reduction type for the loss. See LossReduce for more details. Default: LossReduce#MEAN_BY_NONZERO_WEIGHT_COUNT"; defaultValue = LossReduce.MEAN_BY_NONZERO_WEIGHT_COUNT}
|
||||
Arg(FLOATING_POINT, "labelSmoothing") { description = "Label smoothing value. Default value: 0"; defaultValue = 0.0}
|
||||
Output(NUMERIC, "output"){ description = "Loss variable" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
Applies the softmax activation function to the input, then implement multi-class cross entropy:<br>
|
||||
{@code -sum_classes label[i] * log(p[c])} where {@code p = softmax(logits)}<br>
|
||||
If LossReduce#NONE is used, returned shape is [numExamples] out for [numExamples, numClasses] predicitons/labels;
|
||||
otherwise, the output is a scalar.<br>
|
||||
<p>
|
||||
When label smoothing is > 0, the following label smoothing is used:<br>
|
||||
<pre>
|
||||
{@code numClasses = labels.size(1);
|
||||
oneHotLabel = (1.0 - labelSmoothing) * oneHotLabels + labelSmoothing/numClasses}
|
||||
</pre>
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
Op("sparseSoftmaxCrossEntropy") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.loss"
|
||||
javaOpClass = "SparseSoftmaxCrossEntropyLossWithLogits"
|
||||
Input(NUMERIC, "logits") { description = "Logits array (\"pre-softmax activations\")" }
|
||||
Input(INT, "labels") { description = "Labels array. Must be an integer type." }
|
||||
Output(NUMERIC, "output"){ description = "Softmax cross entropy" }
|
||||
Doc(Language.ANY, DocScope.ALL){
|
||||
"""
|
||||
As per softmaxCrossEntropy(String, SDVariable, SDVariable, LossReduce) but the labels variable
|
||||
is represented as an integer array instead of the equivalent one-hot array.<br>
|
||||
i.e., if logits are rank N, then labels have rank N-1
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<!--
|
||||
~ /* ******************************************************************************
|
||||
~ *
|
||||
~ *
|
||||
~ * 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
|
||||
~ ******************************************************************************/
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
|
||||
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>logs/application.log</file>
|
||||
<encoder>
|
||||
<pattern> %logger{15} - %message%n%xException{5}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern> %logger{15} - %message%n%xException{5}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.apache.catalina.core" level="DEBUG" />
|
||||
<logger name="org.springframework" level="WARN" />
|
||||
<logger name="org.nd4j" level="INFO" />
|
||||
<logger name="org.deeplearning4j" level="INFO" />
|
||||
|
||||
|
||||
<root level="ERROR">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,54 @@
|
||||
{ "name" : "math",
|
||||
|
||||
"include" : [
|
||||
|
||||
],
|
||||
|
||||
"ops": [
|
||||
|
||||
{
|
||||
"opName" : "BaseArithmeticOp",
|
||||
"isAbstract" : true,
|
||||
"javaPackage" : "org.nd4j.linalg.api.ops.impl.transforms.pairwise.arithmetic",
|
||||
"inputs" : [ {
|
||||
"name" : "x",
|
||||
"description" : "First input to %OPNAME%",
|
||||
"constraints" : ["T"]
|
||||
}, {
|
||||
"name" : "y",
|
||||
"description" : "Second input to %OPNAME%",
|
||||
"constraints" : ["T"]
|
||||
} ],
|
||||
"outputs" : [ {
|
||||
"name" : "z",
|
||||
"description" : "Output array after executing %OPNAME% on inputs"
|
||||
} ],
|
||||
"args" : null,
|
||||
"constraints" : {
|
||||
"T": {
|
||||
"type": "allowed_dtype",
|
||||
"values": [
|
||||
"NUMERICAL"
|
||||
]
|
||||
}
|
||||
},
|
||||
"doc" : [ {
|
||||
"scope" : "ALL",
|
||||
"language" : "ANY",
|
||||
"text" : "%OPNAME% op doc text that will appear everywhere - classes, constructors, op creators"
|
||||
} ]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"opName" : "Add",
|
||||
"libnd4jOpName" : "add",
|
||||
"extendsOp" : "BaseArithmeticOp"
|
||||
},
|
||||
|
||||
{
|
||||
"opName" : "Sub",
|
||||
"libnd4jOpName" : "sub",
|
||||
"extendsOp" : "BaseArithmeticOp"
|
||||
}
|
||||
]}
|
||||
@@ -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.nd4j.codegen.dsl;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.nd4j.codegen.impl.java.DocsGenerator;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@DisplayName("Docs Generator Test")
|
||||
class DocsGeneratorTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Test J Dto MD Adapter")
|
||||
void testJDtoMDAdapter() {
|
||||
String original = "{@code %INPUT_TYPE% eye = eye(3,2)\n" + " eye:\n" + " [ 1, 0]\n" + " [ 0, 1]\n" + " [ 0, 0]}";
|
||||
String expected = "{ INDArray eye = eye(3,2)\n" + " eye:\n" + " [ 1, 0]\n" + " [ 0, 1]\n" + " [ 0, 0]}";
|
||||
DocsGenerator.JavaDocToMDAdapter adapter = new DocsGenerator.JavaDocToMDAdapter(original);
|
||||
String out = adapter.filter("@code", StringUtils.EMPTY).filter("%INPUT_TYPE%", "INDArray").toString();
|
||||
assertEquals(out, expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.nd4j.codegen.api.NamespaceOps;
|
||||
import org.nd4j.codegen.impl.java.Nd4jNamespaceGenerator;
|
||||
import org.nd4j.codegen.ops.RNNKt;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
class TestGeneration {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@TempDir
|
||||
public File testDir;
|
||||
|
||||
@Test
|
||||
void test() throws Exception {
|
||||
File f = testDir;
|
||||
|
||||
// List<NamespaceOps> list = Arrays.asList(BitwiseKt.Bitwise(), RandomKt.Random());
|
||||
List<NamespaceOps> list = Arrays.asList(RNNKt.SDRNN());
|
||||
|
||||
for(NamespaceOps ops : list) {
|
||||
Nd4jNamespaceGenerator.generate(ops, null, f, ops.getName() + ".java", "org.nd4j.linalg.factory", StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
File[] files = f.listFiles();
|
||||
Iterator<File> iter = FileUtils.iterateFiles(f, null, true);
|
||||
if(files != null) {
|
||||
while(iter.hasNext()){
|
||||
File file = iter.next();
|
||||
if(file.isDirectory())
|
||||
continue;
|
||||
System.out.println(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
|
||||
System.out.println("\n\n================\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.nd4j.codegen.api.DataType.FLOATING_POINT
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
|
||||
class ConfigTest {
|
||||
@Test
|
||||
fun allGood(){
|
||||
Namespace("RNN"){
|
||||
val sruWeights = Config("SRUWeights"){
|
||||
Input(FLOATING_POINT, "weights"){ description = "Weights, with shape [inSize, 3*inSize]" }
|
||||
Input(FLOATING_POINT, "bias"){ description = "Biases, with shape [2*inSize]" }
|
||||
}
|
||||
|
||||
Op("SRU"){
|
||||
Input(FLOATING_POINT, "x"){ description = "..." }
|
||||
Input(FLOATING_POINT, "initialC"){ description = "..." }
|
||||
Input(FLOATING_POINT, "mask"){ description = "..." }
|
||||
|
||||
useConfig(sruWeights)
|
||||
|
||||
Output(FLOATING_POINT, "out"){ description = "..." }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){ "some doc" }
|
||||
}
|
||||
|
||||
Op("SRUCell"){
|
||||
val x = Input(FLOATING_POINT, "x"){ description = "..." }
|
||||
val cLast = Input(FLOATING_POINT, "cLast"){ description = "..." }
|
||||
|
||||
val conf = useConfig(sruWeights)
|
||||
|
||||
Output(FLOATING_POINT, "out"){ description = "..." }
|
||||
|
||||
// Just for demonstration purposes
|
||||
Signature(x, cLast, conf)
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL){ "some doc" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.nd4j.codegen.api.Arg
|
||||
import org.nd4j.codegen.api.DataType
|
||||
import org.nd4j.codegen.api.Expression
|
||||
import org.nd4j.codegen.api.Input
|
||||
import org.nd4j.codegen.impl.java.JavaConstraintCodeGenerator
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class ConstraintTest {
|
||||
|
||||
|
||||
private fun buildConstraint(block: ConstraintBuilder.() -> Expression): Expression {
|
||||
return ConstraintBuilder().block()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleConstraintTest() {
|
||||
val expected = "x.rank() == 3"
|
||||
val input = Input(name = "x", type = DataType.INT)
|
||||
val constraint = buildConstraint { input.rank() eq 3 }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simple2ConstraintTest() {
|
||||
val expected = "(x.rank() == 3) && (x.sizeAt(2) >= 7)"
|
||||
val input = Input(name = "x", type = DataType.INT)
|
||||
val constraint = buildConstraint { (input.rank() eq 3) and (input.sizeAt(2) gte 7) }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simple3ConstraintTest() {
|
||||
val expected = "((x.rank() == 3) || (x.sizeAt(2) >= 7)) || (x.sizeAt(4) < 5)"
|
||||
val input = Input(name = "x", type = DataType.INT)
|
||||
val constraint = buildConstraint { some(
|
||||
input.rank() eq 3,
|
||||
input.sizeAt(2) gte 7,
|
||||
input.sizeAt(4) lt 5
|
||||
) }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun complexConstraintTest() {
|
||||
val expected = "(x.rank() == 3) == false"
|
||||
val input = Input(name = "x", type = DataType.INT)
|
||||
val constraint = buildConstraint { not(input.rank() eq 3) }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argConstraintTest() {
|
||||
val expected = "(x.rank() == rank) == false"
|
||||
val arg = Arg(name = "rank", type = DataType.NUMERIC)
|
||||
val input = Input(name = "x", type = DataType.INT)
|
||||
val constraint = buildConstraint { not(input.rank() eq arg) }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun specificConstraintTest(){
|
||||
val expected = "isSameType(x, y, z)"
|
||||
val x = Input(name = "x", type = DataType.INT)
|
||||
val y = Input(name = "y", type = DataType.INT)
|
||||
val z = Input(name = "z", type = DataType.INT)
|
||||
val constraint = buildConstraint { sameType(x, y, z) }
|
||||
val out = JavaConstraintCodeGenerator().generateExpression(constraint)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
}
|
||||
@@ -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.nd4j.codegen.dsl
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.nd4j.codegen.api.DataType
|
||||
|
||||
class NamespaceInvariantTest {
|
||||
@Test
|
||||
fun checkForUnusedConfigs(){
|
||||
val thrown = assertThrows<IllegalStateException> {
|
||||
Namespace("RNN"){
|
||||
Config("SRUWeights"){
|
||||
Input(DataType.FLOATING_POINT, "weights"){ description = "Weights, with shape [inSize, 3*inSize]" }
|
||||
Input(DataType.FLOATING_POINT, "bias"){ description = "Biases, with shape [2*inSize]" }
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals("Found unused configs: SRUWeights", thrown.message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl
|
||||
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.nd4j.codegen.api.AtLeast
|
||||
import org.nd4j.codegen.api.AtMost
|
||||
import org.nd4j.codegen.api.DataType.*
|
||||
import org.nd4j.codegen.api.Exactly
|
||||
import org.nd4j.codegen.api.Language
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import org.nd4j.codegen.impl.java.JavaPoetGenerator
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class OpBuilderTest {
|
||||
private var testDir = createTempDir()
|
||||
|
||||
@Test
|
||||
fun opBuilderTest() {
|
||||
val outDir = testDir
|
||||
|
||||
val mathNs = Namespace("math") {
|
||||
val config = Config("bla"){
|
||||
val a = Input(NUMERIC, "a") { description = "This is A!"}
|
||||
Input(NUMERIC, "c") { count = AtLeast(1); description = "This is C!"}
|
||||
Input(NUMERIC, "e") { defaultValue = a}
|
||||
val b = Arg(NUMERIC, "b") { description = "This is B!"}
|
||||
Arg(NUMERIC, "d") { count = AtMost(7); description = "This is D!"}
|
||||
Arg(NUMERIC, "f") { defaultValue = 12}
|
||||
|
||||
Constraint("Some constraint"){
|
||||
a.isScalar()
|
||||
}
|
||||
Constraint("Some different constraint"){
|
||||
b eq 7
|
||||
}
|
||||
|
||||
Doc(Language.JAVA, DocScope.ALL){
|
||||
"This is some config documentation"
|
||||
}
|
||||
}
|
||||
Op("add") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.pairwise.arithmetic"
|
||||
|
||||
val x = Input(NUMERIC, "x") { description = "First input to add" }
|
||||
Input(NUMERIC,"y") { count = AtLeast(1); description = "Second input to add"; defaultValue = x }
|
||||
Arg(INT,"shape") { count = AtLeast(1); description = "shape"; defaultValue = intArrayOf(1,2,3) }
|
||||
|
||||
|
||||
Output(NUMERIC, "z") { description = "Output (x+y)" }
|
||||
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"""
|
||||
(From AddOp) Add op doc text that will appear everywhere - classes, constructors, op creators
|
||||
""".trimIndent()
|
||||
}
|
||||
Doc(Language.ANY, DocScope.CLASS_DOC_ONLY) {
|
||||
"Add op doc text that will appear in all class docs (javadoc etc)"
|
||||
}
|
||||
Doc(Language.ANY, DocScope.CONSTRUCTORS_ONLY) {
|
||||
"Add op doc text for constructors only"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val baseArithmeticOp = Mixin("BaseArithmeticOp") {
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.pairwise.arithmetic"
|
||||
|
||||
Input(NUMERIC,"x") { count = Exactly(1); description = "First operand to %OPNAME%" }
|
||||
Input(NUMERIC,"y") { count = Exactly(1); description = "Second operand" }
|
||||
|
||||
|
||||
Output(NUMERIC,"z") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"(From BaseArithmeticOp) op doc text that will appear everywhere - classes, constructors, op creators"
|
||||
}
|
||||
Doc(Language.ANY, DocScope.CLASS_DOC_ONLY) {
|
||||
"op doc text that will appear in all class docs (javadoc etc)"
|
||||
}
|
||||
Doc(Language.ANY, DocScope.CONSTRUCTORS_ONLY) {
|
||||
"op doc text for constructors only"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Op("sub", extends = baseArithmeticOp)
|
||||
|
||||
Op("mul", extends = baseArithmeticOp)
|
||||
|
||||
Op("rsub", extends = baseArithmeticOp) {
|
||||
isAbstract = false
|
||||
javaPackage = "org.nd4j.some.other.package"
|
||||
Doc(Language.ANY, DocScope.CREATORS_ONLY) {
|
||||
"(From rsub) This doc section will appear only in creator method for %OPNAME%"
|
||||
}
|
||||
}
|
||||
|
||||
Op("div"){
|
||||
javaPackage = "org.nd4j.linalg.api.ops.impl.transforms.pairwise.arithmetic"
|
||||
|
||||
val x = Input(NUMERIC,"x") { description = "First operand to div" }
|
||||
val y = Input(NUMERIC,"y") { description = "Second operand to div" }
|
||||
val idx = Arg(INT, "idx") { description = "Some kind of Index" }
|
||||
Constraint("Compatible Rank"){
|
||||
x.rank() eq idx
|
||||
}
|
||||
|
||||
Constraint("Compatible Shapes"){
|
||||
sameShape(x,y)
|
||||
}
|
||||
|
||||
|
||||
Output(NUMERIC,"z") { description = "Output" }
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"op doc text that will appear everywhere - classes, constructors, op creators"
|
||||
}
|
||||
}
|
||||
|
||||
Op("zfoo"){
|
||||
javaPackage = "bar"
|
||||
javaOpClass = "FooBarOp"
|
||||
val x = Input(NUMERIC,"x") { description = "First operand to %OPNAME% (%INPUT_TYPE%)" }
|
||||
val y = Input(NUMERIC,"y") { description = "Second operand to div" }
|
||||
val z = Arg(ENUM, "fooMode"){ description = "Something or other"; possibleValues = listOf("SOME", "value", "Spam", "eGGs")}
|
||||
val bla = useConfig(config)
|
||||
|
||||
Constraint("foo bar"){
|
||||
x.sizeAt(7) eq 7 and y.isScalar()
|
||||
}
|
||||
|
||||
Doc(Language.ANY, DocScope.ALL) {
|
||||
"op doc text that will appear everywhere - classes, constructors, op creators"
|
||||
}
|
||||
|
||||
Signature(x, y, z, bla)
|
||||
}
|
||||
}
|
||||
|
||||
val generator = JavaPoetGenerator()
|
||||
generator.generateNamespaceNd4j(mathNs, null, outDir, "Nd4jMath")
|
||||
val exp = File(outDir, "org/nd4j/linalg/factory/ops/Nd4jMath.java")
|
||||
assertTrue(exp.isFile)
|
||||
|
||||
println(FileUtils.readFileToString(exp, StandardCharsets.UTF_8))
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,833 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.dsl
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertSame
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.nd4j.codegen.api.*
|
||||
import org.nd4j.codegen.api.doc.DocScope
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotSame
|
||||
|
||||
|
||||
class OpInvariantTest {
|
||||
|
||||
@Test
|
||||
fun opMustBeDocumented() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {}
|
||||
}
|
||||
}
|
||||
assertEquals("foo: Ops must be documented!", thrown.message)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun opMustBeDocumentedAndNotEmpty() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "" }
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals("foo: Ops must be documented!", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opMustBeDocumentedWithDoc() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustCoverAllParameters() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Input(DataType.NUMERIC, "y")
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals("foo: Signature(x) does not cover all parameters! Missing: y", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustCoverAllParameters2() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y")
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("foo: Signature(x) does not cover all parameters! Missing: y", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustCoverAllParametersWithoutDefaults() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y") {
|
||||
defaultValue = 7
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustTakeEachParameterOnlyOnce() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y")
|
||||
|
||||
Signature(x, x, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("A parameter may not be used twice in a signature!", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustAllowOutputs() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y") {
|
||||
defaultValue = 7
|
||||
}
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
|
||||
Signature(out, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureMustAllowOutputsOnlyOnce() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y") {
|
||||
defaultValue = 7
|
||||
}
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
|
||||
Signature(out, x, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("A parameter may not be used twice in a signature!", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultValueMustHaveCorrectShape() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
defaultValue = x.shape()
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y). Got x.shape() (org.nd4j.codegen.api.TensorShapeValue)", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultValue() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
defaultValue = 2
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultValueMustHaveCorrectDataType() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
defaultValue = 1.7
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y). Got 1.7 (java.lang.Double)", thrown.message)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultInputReference() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val z = Input(DataType.NUMERIC, "z")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = z.shape()
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("foo: Signature(x) does not cover all parameters! Missing: z, y", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultOutputReference() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = out.shape()
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("foo: Signature(x) does not cover all parameters! Missing: y", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultWithOutputReference() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = out.shape()
|
||||
}
|
||||
|
||||
Signature(out, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultReferenceChain() {
|
||||
val thrown = assertThrows<java.lang.IllegalStateException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val z = Input(DataType.NUMERIC, "z")
|
||||
val u = Input(DataType.NUMERIC, "u") { defaultValue = z }
|
||||
val v = Input(DataType.NUMERIC, "v") { defaultValue = u }
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = v.shape()
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("foo: Signature(x) does not cover all parameters! Missing: z, u, v, y", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureDefaultReferenceChainWorking() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val z = Input(DataType.NUMERIC, "z") { defaultValue = x }
|
||||
val u = Input(DataType.NUMERIC, "u") { defaultValue = z }
|
||||
val v = Input(DataType.NUMERIC, "v") { defaultValue = u }
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = v.shape()
|
||||
}
|
||||
|
||||
Signature(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureShorthandAllParams() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val z = Input(DataType.NUMERIC, "z") { defaultValue = x }
|
||||
val u = Input(DataType.NUMERIC, "u") { defaultValue = z }
|
||||
val v = Input(DataType.NUMERIC, "v") { defaultValue = u }
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = v.shape()
|
||||
}
|
||||
|
||||
AllParamSignature()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureNullDefaults() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = null
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureNullDefaultsForInputs() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x") { defaultValue = null }
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureShorthandDefaultParams() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val z = Input(DataType.NUMERIC, "z") { defaultValue = x }
|
||||
val u = Input(DataType.NUMERIC, "u") { defaultValue = z }
|
||||
val v = Input(DataType.NUMERIC, "v") { defaultValue = u }
|
||||
val y = Arg(DataType.INT, "y") {
|
||||
count = AtLeast(1)
|
||||
defaultValue = v.shape()
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureSupportsArrayDefaults() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") { count = AtLeast(0); defaultValue = intArrayOf() }
|
||||
val z = Arg(DataType.FLOATING_POINT, "z") { count = Range(2, 5); defaultValue = doubleArrayOf(1.0, 2.0, 3.0) }
|
||||
val a = Arg(DataType.BOOL, "a") { count = AtLeast(1); defaultValue = booleanArrayOf(true) }
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureSupportsArrayDefaultsAtLeast() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "x")
|
||||
Arg(DataType.INT, "y") { count = AtLeast(1); defaultValue = intArrayOf() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y){ count = AtLeast(min=1) }. Got [] ([I)", thrown.message)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureSupportsArrayDefaultsAtMost() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "x")
|
||||
Arg(DataType.INT, "y") { count = AtMost(1); defaultValue = intArrayOf(1, 2) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y){ count = AtMost(max=1) }. Got [1, 2] ([I)", thrown.message)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureSupportsArrayDefaultsRange() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "x")
|
||||
Arg(DataType.INT, "y") { count = Range(3, 7); defaultValue = intArrayOf() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y){ count = Range(from=3, to=7) }. Got [] ([I)", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureSupportsArrayDefaultsExactly() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "x")
|
||||
Arg(DataType.INT, "y") { count = Exactly(7); defaultValue = intArrayOf() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(INT, y){ count = Exactly(count=7) }. Got [] ([I)", thrown.message)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureHasExpectedNumberOfSignatures() {
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") { count = AtLeast(0); defaultValue = intArrayOf() }
|
||||
|
||||
AllParamSignature()
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
|
||||
assertEquals(2, op.signatures.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureHasExpectedNumberOfSignaturesWithOutput() {
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") { count = AtLeast(0); defaultValue = intArrayOf() }
|
||||
|
||||
AllParamSignature(true)
|
||||
AllDefaultsSignature(true)
|
||||
}
|
||||
|
||||
assertEquals(4, op.signatures.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureHasExpectedNumberOfSignaturesNoDefaults() {
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") { count = AtLeast(0); }
|
||||
|
||||
AllParamSignature()
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
|
||||
assertEquals(1, op.signatures.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun opSignatureHasExpectedNumberOfSignaturesWithOutputNoDefaults() {
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.INT, "y") { count = AtLeast(0); }
|
||||
|
||||
AllParamSignature(true)
|
||||
AllDefaultsSignature(true)
|
||||
}
|
||||
|
||||
assertEquals(2, op.signatures.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnum() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") { possibleValues = listOf("FOO", "BAR", "BAZ"); description = "Enums require some docs" }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumDefaultValue() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") {
|
||||
possibleValues = listOf("FOO", "BAR", "BAZ")
|
||||
defaultValue = "BAZ"
|
||||
description = "Enums require some docs"
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumBadDefaultValue() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") {
|
||||
possibleValues = listOf("FOO", "BAR", "BAZ")
|
||||
defaultValue = "SPAM"
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Illegal default value for Arg(ENUM(FOO, BAR, BAZ), y). Got SPAM (java.lang.String)", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumEmptyPossibleValues() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") {
|
||||
possibleValues = listOf()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Arg(ENUM(null), y): Can not set empty possibleValues.", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumBadType() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.NUMERIC, "y") {
|
||||
possibleValues = listOf("FOO", "BAR", "BAZ")
|
||||
defaultValue = "SPAM"
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Arg(NUMERIC, y): Can not set possibleValues on non ENUM typed Arg.", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumBadCount() {
|
||||
val thrown = assertThrows<java.lang.IllegalArgumentException> {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") {
|
||||
count = AtLeast(1)
|
||||
possibleValues = listOf("FOO", "BAR", "BAZ")
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Arg(ENUM(null), y): ENUM typed Arg can not be array", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun argEnumGoodCount() {
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
val y = Arg(DataType.ENUM, "y") {
|
||||
count = Exactly(1)
|
||||
possibleValues = listOf("FOO", "BAR", "BAZ")
|
||||
description = "Enums require some docs"
|
||||
}
|
||||
|
||||
AllDefaultsSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onlyValidParametersAreUsedInSignaturesBadCase() {
|
||||
val thrown = assertThrows<IllegalArgumentException> {
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
|
||||
Signature(out, x, mixin.input("a"), mixin.arg("b"))
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals("You can only use parameters in a signature that are actually defined in Op(opName=foo, libnd4jOpName=foo, isAbstract=false)! Did you forget to useMixin(...) a mixin?", thrown.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onlyValidParametersAreUsedInSignaturesGoodCase() {
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
Op("foo", mixin) {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
val out = Output(DataType.NUMERIC, "out")
|
||||
val x = Input(DataType.NUMERIC, "x")
|
||||
|
||||
Signature(out, x, mixin.input("a"), mixin.arg("b"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun lastMixinDefinitionWins(){
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
val op = Op("foo", mixin) {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "a") { count=Exactly(1)}
|
||||
}
|
||||
|
||||
assertNotSame(mixin.inputs.find { it.name == "a"}, op.inputs.find { it.name == "a"})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun lastMixinDefinitionWins2(){
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "a")
|
||||
useMixin(mixin)
|
||||
}
|
||||
|
||||
assertSame(mixin.inputs.find { it.name == "a"}, op.inputs.find { it.name == "a"})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mixinDoesOnlyOverwritePropertiesIfSetNoneSetCase(){
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
javaPackage = "fooPackage"
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "a")
|
||||
useMixin(mixin)
|
||||
}
|
||||
|
||||
assertEquals("fooPackage", op.javaPackage)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mixinDoesOnlyOverwritePropertiesIfSetSetCase(){
|
||||
val mixin = Mixin("Bar") {
|
||||
javaPackage = "MixinPackage"
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
Namespace("math") {
|
||||
val op = Op("foo") {
|
||||
javaPackage = "fooPackage"
|
||||
Doc(Language.ANY, DocScope.ALL) { "Some Documentation" }
|
||||
Output(DataType.NUMERIC, "out")
|
||||
Input(DataType.NUMERIC, "a")
|
||||
useMixin(mixin)
|
||||
}
|
||||
|
||||
assertEquals("MixinPackage", op.javaPackage)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mixinDoesOnlyOverwritePropertiesIfSetNoneSetCaseOnMixins(){
|
||||
val mixin = Mixin("Bar") {
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
val op = Mixin("foo") {
|
||||
javaPackage = "fooPackage"
|
||||
useMixin(mixin)
|
||||
}
|
||||
|
||||
assertEquals("fooPackage", op.javaPackage)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mixinDoesOnlyOverwritePropertiesIfSetSetCaseOnMixins(){
|
||||
val mixin = Mixin("Bar") {
|
||||
javaPackage = "MixinPackage"
|
||||
Input(DataType.NUMERIC, "a")
|
||||
Arg(DataType.BOOL, "b")
|
||||
}
|
||||
|
||||
val op = Mixin("foo") {
|
||||
javaPackage = "fooPackage"
|
||||
useMixin(mixin)
|
||||
}
|
||||
|
||||
assertEquals("MixinPackage", op.javaPackage)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * 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.nd4j.codegen.ops
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* Test that each Namespace actually constructs properly.
|
||||
*
|
||||
* This is allows us to utilize run-time consistency checks during the build process - if tests are enabled.
|
||||
*/
|
||||
class ConstructionTest {
|
||||
|
||||
@Test
|
||||
fun bitwise() { Bitwise() }
|
||||
|
||||
@Test
|
||||
fun random() { Random() }
|
||||
|
||||
@Test
|
||||
fun math() { Math() }
|
||||
|
||||
@Test
|
||||
fun base() { SDBaseOps() }
|
||||
|
||||
@Test
|
||||
fun loss() { SDLoss() }
|
||||
|
||||
@Test
|
||||
fun cnn() { SDCNN() }
|
||||
|
||||
@Test
|
||||
fun rnn() { SDRNN() }
|
||||
|
||||
@Test
|
||||
fun image() { SDImage() }
|
||||
|
||||
@Test
|
||||
fun nn() { NN() }
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user