Commit 2d4fd64e authored by Sebastian N.'s avatar Sebastian N.
Browse files

Renamed VariableSymbol to ParameterSymbol, introduced layer variable...

Renamed VariableSymbol to ParameterSymbol, introduced layer variable declarations, changed IOSymbol to VariableSymbol which now combines IO variables and layer variables and implemented RNN layer
parent 7184ebe9
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
<properties> <properties>
<!-- .. SE-Libraries .................................................. --> <!-- .. SE-Libraries .................................................. -->
<CNNArch.version>0.3.1-SNAPSHOT</CNNArch.version> <CNNArch.version>0.3.2-SNAPSHOT</CNNArch.version>
<CNNTrain.version>0.3.4-SNAPSHOT</CNNTrain.version> <CNNTrain.version>0.3.4-SNAPSHOT</CNNTrain.version>
<CNNArch2X.version>0.0.2-SNAPSHOT</CNNArch2X.version> <CNNArch2X.version>0.0.3-SNAPSHOT</CNNArch2X.version>
<embedded-montiarc-math-opt-generator>0.1.4</embedded-montiarc-math-opt-generator> <embedded-montiarc-math-opt-generator>0.1.4</embedded-montiarc-math-opt-generator>
<EMADL2PythonWrapper.version>0.0.1</EMADL2PythonWrapper.version> <EMADL2PythonWrapper.version>0.0.1</EMADL2PythonWrapper.version>
...@@ -238,6 +238,7 @@ ...@@ -238,6 +238,7 @@
<version>2.19.1</version> <version>2.19.1</version>
<configuration> <configuration>
<useSystemClassLoader>false</useSystemClassLoader> <useSystemClassLoader>false</useSystemClassLoader>
<trimStackTrace>false</trimStackTrace>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
*/ */
package de.monticore.lang.monticar.cnnarch.gluongenerator; package de.monticore.lang.monticar.cnnarch.gluongenerator;
import de.monticore.lang.monticar.cnnarch._symboltable.IOSymbol; import de.monticore.lang.monticar.cnnarch._symboltable.IODeclarationSymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.VariableDeclarationSymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.VariableSymbol;
import de.monticore.lang.monticar.cnnarch.generator.CNNArchGenerator; import de.monticore.lang.monticar.cnnarch.generator.CNNArchGenerator;
import de.monticore.lang.monticar.cnnarch.generator.Target; import de.monticore.lang.monticar.cnnarch.generator.Target;
import de.monticore.lang.monticar.cnnarch.generator.TemplateConfiguration; import de.monticore.lang.monticar.cnnarch.generator.TemplateConfiguration;
...@@ -28,8 +30,7 @@ import de.monticore.lang.monticar.cnnarch.generator.TemplateConfiguration; ...@@ -28,8 +30,7 @@ import de.monticore.lang.monticar.cnnarch.generator.TemplateConfiguration;
import de.monticore.lang.monticar.cnnarch._symboltable.ArchitectureSymbol; import de.monticore.lang.monticar.cnnarch._symboltable.ArchitectureSymbol;
import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.Log;
import java.util.HashMap; import java.util.*;
import java.util.Map;
public class CNNArch2Gluon extends CNNArchGenerator { public class CNNArch2Gluon extends CNNArchGenerator {
...@@ -52,18 +53,9 @@ public class CNNArch2Gluon extends CNNArchGenerator { ...@@ -52,18 +53,9 @@ public class CNNArch2Gluon extends CNNArchGenerator {
} else { } else {
fileContentMap = compileFileContentMap(architecture); fileContentMap = compileFileContentMap(architecture);
} }
checkValidOutputTypes(architecture);
return fileContentMap; return fileContentMap;
} }
private void checkValidOutputTypes(ArchitectureSymbol architecture) {
if (((IOSymbol)architecture.getOutputs().get(0)).getDefinition().getType().getWidth() != 1
|| ((IOSymbol)architecture.getOutputs().get(0)).getDefinition().getType().getHeight() != 1) {
Log.error("This cnn architecture has a multi-dimensional output, which is currently not supported by" +
" the code generator.", architecture.getSourcePosition());
}
}
private Map<String, String> compilePythonFiles(CNNArch2GluonTemplateController controller, ArchitectureSymbol architecture) { private Map<String, String> compilePythonFiles(CNNArch2GluonTemplateController controller, ArchitectureSymbol architecture) {
Map<String, String> fileContentMap = new HashMap<>(); Map<String, String> fileContentMap = new HashMap<>();
Map.Entry<String, String> temp; Map.Entry<String, String> temp;
......
...@@ -22,9 +22,19 @@ public class CNNArch2GluonArchitectureSupportChecker extends ArchitectureSupport ...@@ -22,9 +22,19 @@ public class CNNArch2GluonArchitectureSupportChecker extends ArchitectureSupport
return true; return true;
} }
@Override
protected boolean checkMultiDimensionalOutput(ArchitectureSymbol architecture) {
return true;
}
@Override @Override
protected boolean checkConstants(ArchitectureSymbol architecture) { protected boolean checkConstants(ArchitectureSymbol architecture) {
return true; return true;
} }
@Override
protected boolean checkLayerVariables(ArchitectureSymbol architecture) {
return true;
}
} }
...@@ -23,6 +23,7 @@ public class CNNArch2GluonLayerSupportChecker extends LayerSupportChecker { ...@@ -23,6 +23,7 @@ public class CNNArch2GluonLayerSupportChecker extends LayerSupportChecker {
supportedLayerList.add(AllPredefinedLayers.CONCATENATE_NAME); supportedLayerList.add(AllPredefinedLayers.CONCATENATE_NAME);
supportedLayerList.add(AllPredefinedLayers.FLATTEN_NAME); supportedLayerList.add(AllPredefinedLayers.FLATTEN_NAME);
supportedLayerList.add(AllPredefinedLayers.ONE_HOT_NAME); supportedLayerList.add(AllPredefinedLayers.ONE_HOT_NAME);
supportedLayerList.add(AllPredefinedLayers.RNN_NAME);
} }
} }
...@@ -46,20 +46,25 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController { ...@@ -46,20 +46,25 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController {
getTemplateConfiguration().processTemplate(ftlContext, templatePath, writer); getTemplateConfiguration().processTemplate(ftlContext, templatePath, writer);
} }
public void include(IOSymbol ioElement, Writer writer, NetDefinitionMode netDefinitionMode){ public void include(VariableSymbol element, Writer writer, NetDefinitionMode netDefinitionMode){
ArchitectureElementData previousElement = getCurrentElement(); ArchitectureElementData previousElement = getCurrentElement();
setCurrentElement(ioElement); setCurrentElement(element);
if (ioElement.isAtomic()){ if (element.isAtomic()){
if (ioElement.isInput()){ if (element.getType() == VariableSymbol.Type.IO) {
include(TEMPLATE_ELEMENTS_DIR_PATH, "Input", writer, netDefinitionMode); if (element.isInput()){
include(TEMPLATE_ELEMENTS_DIR_PATH, "Input", writer, netDefinitionMode);
}
else {
include(TEMPLATE_ELEMENTS_DIR_PATH, "Output", writer, netDefinitionMode);
}
} }
else { else if (element.getType() == VariableSymbol.Type.LAYER) {
include(TEMPLATE_ELEMENTS_DIR_PATH, "Output", writer, netDefinitionMode); include(TEMPLATE_ELEMENTS_DIR_PATH, element.getLayerVariableDeclaration().getLayer().getName(), writer, netDefinitionMode);
} }
} }
else { else {
include(ioElement.getResolvedThis().get(), writer, netDefinitionMode); include(element.getResolvedThis().get(), writer, netDefinitionMode);
} }
setCurrentElement(previousElement); setCurrentElement(previousElement);
...@@ -84,7 +89,6 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController { ...@@ -84,7 +89,6 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController {
setCurrentElement(layer); setCurrentElement(layer);
if (layer.isAtomic()){ if (layer.isAtomic()){
ArchitectureElementSymbol nextElement = layer.getOutputElement().get();
String templateName = layer.getDeclaration().getName(); String templateName = layer.getDeclaration().getName();
include(TEMPLATE_ELEMENTS_DIR_PATH, templateName, writer, netDefinitionMode); include(TEMPLATE_ELEMENTS_DIR_PATH, templateName, writer, netDefinitionMode);
} }
...@@ -117,7 +121,7 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController { ...@@ -117,7 +121,7 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController {
include((ConstantSymbol) architectureElement, writer, netDefinitionMode); include((ConstantSymbol) architectureElement, writer, netDefinitionMode);
} }
else { else {
include((IOSymbol) architectureElement, writer, netDefinitionMode); include((VariableSymbol) architectureElement, writer, netDefinitionMode);
} }
} }
...@@ -132,27 +136,128 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController { ...@@ -132,27 +136,128 @@ public class CNNArch2GluonTemplateController extends CNNArchTemplateController {
include(architectureElement, getWriter(), netDefinitionMode); include(architectureElement, getWriter(), netDefinitionMode);
} }
public String ioNameToCpp(String ioName) { public Set<String> getStreamInputNames(SerialCompositeElementSymbol stream) {
return ioName.replaceAll("_([0-9]+)_", "[$1]"); return getStreamInputs(stream).keySet();
} }
public List<String> getStreamInputNames(SerialCompositeElementSymbol stream) { public Collection<List<String>> getStreamInputDimensions(SerialCompositeElementSymbol stream) {
List<String> names = new ArrayList<>(); return getStreamInputs(stream).values();
}
public Set<String> getStreamOutputNames(SerialCompositeElementSymbol stream) {
Set<String> outputNames = new LinkedHashSet<>();
for (ArchitectureElementSymbol element : stream.getLastAtomicElements()) {
if (element.isOutput()) {
outputNames.add(getName(element));
}
}
outputNames.addAll(getStreamLayerVariableMembers(stream, "1", true).keySet());
return outputNames;
}
// Used to initialize all layer variable members which are passed through the networks
public Map<String, List<String>> getLayerVariableMembers(String batchSize) {
Map<String, List<String>> members = new LinkedHashMap<>();
for (SerialCompositeElementSymbol stream : getArchitecture().getStreams()) {
members.putAll(getStreamLayerVariableMembers(stream, batchSize, true));
}
return members;
}
private Map<String, List<String>> getStreamInputs(SerialCompositeElementSymbol stream) {
Map<String, List<String>> inputs = new LinkedHashMap<>();
for (ArchitectureElementSymbol element : stream.getFirstAtomicElements()) { for (ArchitectureElementSymbol element : stream.getFirstAtomicElements()) {
names.add(getName(element)); if (element.isInput()) {
List<Integer> intDimensions = element.getOutputTypes().get(0).getDimensions();
List<String> dimensions = new ArrayList<>();
for (Integer intDimension : intDimensions) {
dimensions.add(intDimension.toString());
}
// Add batch size dimension
dimensions.add(0, "1");
inputs.put(getName(element), dimensions);
}
} }
return names; inputs.putAll(getStreamLayerVariableMembers(stream, "1", false));
return inputs;
} }
public List<String> getStreamOutputNames(SerialCompositeElementSymbol stream) { private Map<String, List<String>> getStreamLayerVariableMembers(SerialCompositeElementSymbol stream, String batchSize, boolean includeOutput) {
List<String> names = new ArrayList<>(); Map<String, List<String>> members = new HashMap<>();
for (ArchitectureElementSymbol element : stream.getLastAtomicElements()) { List<ArchitectureElementSymbol> elements = stream.getSpannedScope().resolveLocally(ArchitectureElementSymbol.KIND);
names.add(getName(element)); for (ArchitectureElementSymbol element : elements) {
if (element instanceof VariableSymbol) {
VariableSymbol variable = (VariableSymbol) element;
if (variable.getType() == VariableSymbol.Type.LAYER && variable.getMember() == VariableSymbol.Member.NONE) {
LayerVariableDeclarationSymbol layerVariableDeclaration = variable.getLayerVariableDeclaration();
if (layerVariableDeclaration.getLayer().getDeclaration().isPredefined()) {
PredefinedLayerDeclaration predefinedLayerDeclaration =
(PredefinedLayerDeclaration) layerVariableDeclaration.getLayer().getDeclaration();
if (predefinedLayerDeclaration.isValidMember(VariableSymbol.Member.STATE)) {
String name = variable.getName() + "_state_";
List<Integer> intDimensions = predefinedLayerDeclaration.computeOutputTypes(
layerVariableDeclaration.getLayer().getInputTypes(),
layerVariableDeclaration.getLayer(),
VariableSymbol.Member.STATE
).get(0).getDimensions();
List<String> dimensions = new ArrayList<>();
for (Integer intDimension : intDimensions) {
dimensions.add(intDimension.toString());
}
// Add batch size dimension at index 1, since RNN states in Gluon have the format
// (layers, batch_size, units)
dimensions.add(1, batchSize);
members.put(name, dimensions);
}
if (includeOutput) {
if (predefinedLayerDeclaration.isValidMember(VariableSymbol.Member.OUT)) {
String name = variable.getName() + "_output_";
List<Integer> intDimensions = predefinedLayerDeclaration.computeOutputTypes(
layerVariableDeclaration.getLayer().getInputTypes(),
layerVariableDeclaration.getLayer(),
VariableSymbol.Member.OUT
).get(0).getDimensions();
List<String> dimensions = new ArrayList<>();
for (Integer intDimension : intDimensions) {
dimensions.add(intDimension.toString());
}
// Add batch size dimension at index 0, since we use NTC format for RNN output in Gluon
dimensions.add(0, batchSize);
members.put(name, dimensions);
}
}
}
}
}
} }
return names; return members;
} }
} }
package de.monticore.lang.monticar.cnnarch.gluongenerator.annotations; package de.monticore.lang.monticar.cnnarch.gluongenerator.annotations;
import de.monticore.lang.monticar.cnnarch._symboltable.ArchitectureSymbol; import de.monticore.lang.monticar.cnnarch._symboltable.ArchitectureSymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.IOSymbol; import de.monticore.lang.monticar.cnnarch._symboltable.IODeclarationSymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.VariableSymbol;
import de.monticore.lang.monticar.cnntrain.annotations.Range; import de.monticore.lang.monticar.cnntrain.annotations.Range;
import de.monticore.lang.monticar.cnntrain.annotations.TrainedArchitecture; import de.monticore.lang.monticar.cnntrain.annotations.TrainedArchitecture;
import de.monticore.lang.monticar.ranges._ast.ASTRange; import de.monticore.lang.monticar.ranges._ast.ASTRange;
...@@ -40,19 +41,19 @@ public class ArchitectureAdapter implements TrainedArchitecture { ...@@ -40,19 +41,19 @@ public class ArchitectureAdapter implements TrainedArchitecture {
@Override @Override
public Map<String, List<Integer>> getDimensions() { public Map<String, List<Integer>> getDimensions() {
return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName, return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName,
s-> s.getDefinition().getType().getDimensions())); s-> ((IODeclarationSymbol) s.getDeclaration()).getType().getDimensions()));
} }
@Override @Override
public Map<String, Range> getRanges() { public Map<String, Range> getRanges() {
return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName, return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName,
s -> astRangeToTrainRange(s.getDefinition().getType().getDomain().getRangeOpt().orElse(null)))); s -> astRangeToTrainRange(((IODeclarationSymbol) s.getDeclaration()).getType().getDomain().getRangeOpt().orElse(null))));
} }
@Override @Override
public Map<String, String> getTypes() { public Map<String, String> getTypes() {
return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName, return getAllIOSymbols().stream().collect(Collectors.toMap(CommonSymbol::getName,
s -> s.getDefinition().getType().getDomain().getName())); s -> ((IODeclarationSymbol) s.getDeclaration()).getType().getDomain().getName()));
} }
private Range astRangeToTrainRange(final ASTRange range) { private Range astRangeToTrainRange(final ASTRange range) {
...@@ -71,18 +72,18 @@ public class ArchitectureAdapter implements TrainedArchitecture { ...@@ -71,18 +72,18 @@ public class ArchitectureAdapter implements TrainedArchitecture {
} }
} }
private List<IOSymbol> getIOOutputSymbols() { private List<VariableSymbol> getIOOutputSymbols() {
return architectureSymbol.getOutputs(); return architectureSymbol.getOutputs();
} }
private List<IOSymbol> getIOInputSymbols() { private List<VariableSymbol> getIOInputSymbols() {
return architectureSymbol.getInputs(); return architectureSymbol.getInputs();
} }
private List<IOSymbol> getAllIOSymbols() { private List<VariableSymbol> getAllIOSymbols() {
List<IOSymbol> ioSymbols = new ArrayList<>(); List<VariableSymbol> ioSymbols = new ArrayList<>();
ioSymbols.addAll(getIOOutputSymbols()); ioSymbols.addAll(getIOOutputSymbols());
ioSymbols.addAll(getIOInputSymbols()); ioSymbols.addAll(getIOInputSymbols());
return ioSymbols; return ioSymbols;
} }
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ import mxnet as mx ...@@ -2,7 +2,7 @@ import mxnet as mx
import logging import logging
import os import os
<#list tc.architecture.streams as stream> <#list tc.architecture.streams as stream>
<#if stream.isNetwork()> <#if stream.isTrainable()>
from CNNNet_${tc.fullArchitectureName} import Net_${stream?index} from CNNNet_${tc.fullArchitectureName} import Net_${stream?index}
</#if> </#if>
</#list> </#list>
...@@ -52,11 +52,11 @@ class ${tc.fileNameWithoutEnding}: ...@@ -52,11 +52,11 @@ class ${tc.fileNameWithoutEnding}:
def construct(self, context, data_mean=None, data_std=None): def construct(self, context, data_mean=None, data_std=None):
<#list tc.architecture.streams as stream> <#list tc.architecture.streams as stream>
<#if stream.isNetwork()> <#if stream.isTrainable()>
self.networks[${stream?index}] = Net_${stream?index}(data_mean=data_mean, data_std=data_std) self.networks[${stream?index}] = Net_${stream?index}(data_mean=data_mean, data_std=data_std)
self.networks[${stream?index}].collect_params().initialize(self.weight_initializer, ctx=context) self.networks[${stream?index}].collect_params().initialize(self.weight_initializer, ctx=context)
self.networks[${stream?index}].hybridize() self.networks[${stream?index}].hybridize()
self.networks[${stream?index}](<#list stream.getFirstAtomicElements() as input>mx.nd.zeros((1, ${tc.join(input.definition.type.dimensions, ",")},), ctx=context)<#sep>, </#list>) self.networks[${stream?index}](<#list tc.getStreamInputDimensions(stream) as dimensions>mx.nd.zeros((${tc.join(dimensions, ",")},), ctx=context)<#sep>, </#list>)
</#if> </#if>
</#list> </#list>
......
...@@ -6,8 +6,8 @@ import sys ...@@ -6,8 +6,8 @@ import sys
from mxnet import nd from mxnet import nd
class ${tc.fileNameWithoutEnding}: class ${tc.fileNameWithoutEnding}:
_input_names_ = [${tc.join(tc.architectureInputs, ",", "'", "'")}] _input_names_ = [<#list tc.architectureInputs as inputName>'${inputName?keep_before_last("_")}'<#sep>, </#list>]
_output_names_ = [${tc.join(tc.architectureOutputs, ",", "'", "_label'")}] _output_names_ = [${tc.join(tc.architectureOutputs, ",", "'", "label'")}]
def __init__(self): def __init__(self):
self._data_dir = "${tc.dataPath}/" self._data_dir = "${tc.dataPath}/"
...@@ -21,8 +21,8 @@ class ${tc.fileNameWithoutEnding}: ...@@ -21,8 +21,8 @@ class ${tc.fileNameWithoutEnding}:
for input_name in self._input_names_: for input_name in self._input_names_:
train_data[input_name] = train_h5[input_name] train_data[input_name] = train_h5[input_name]
data_mean[input_name] = nd.array(train_h5[input_name][:].mean(axis=0)) data_mean[input_name + '_'] = nd.array(train_h5[input_name][:].mean(axis=0))
data_std[input_name] = nd.array(train_h5[input_name][:].std(axis=0) + 1e-5) data_std[input_name + '_'] = nd.array(train_h5[input_name][:].std(axis=0) + 1e-5)
train_label = {} train_label = {}
for output_name in self._output_names_: for output_name in self._output_names_:
......
...@@ -79,7 +79,7 @@ class NoNormalization(gluon.HybridBlock): ...@@ -79,7 +79,7 @@ class NoNormalization(gluon.HybridBlock):
<#list tc.architecture.streams as stream> <#list tc.architecture.streams as stream>
<#if stream.isNetwork()> <#if stream.isTrainable()>
class Net_${stream?index}(gluon.HybridBlock): class Net_${stream?index}(gluon.HybridBlock):
def __init__(self, data_mean=None, data_std=None, **kwargs): def __init__(self, data_mean=None, data_std=None, **kwargs):
super(Net_${stream?index}, self).__init__(**kwargs) super(Net_${stream?index}, self).__init__(**kwargs)
...@@ -88,12 +88,8 @@ class Net_${stream?index}(gluon.HybridBlock): ...@@ -88,12 +88,8 @@ class Net_${stream?index}(gluon.HybridBlock):
${tc.include(stream, "ARCHITECTURE_DEFINITION")} ${tc.include(stream, "ARCHITECTURE_DEFINITION")}
def hybrid_forward(self, F, ${tc.join(tc.getStreamInputNames(stream), ", ")}): def hybrid_forward(self, F, ${tc.join(tc.getStreamInputNames(stream), ", ")}):
outputs = []
${tc.include(stream, "FORWARD_FUNCTION")} ${tc.include(stream, "FORWARD_FUNCTION")}
<#if tc.getStreamOutputNames(stream)?size gt 1> return ${tc.join(tc.getStreamOutputNames(stream), ", ")}
return tuple(outputs)
<#else>
return outputs[0]
</#if>
</#if> </#if>
</#list> </#list>
\ No newline at end of file
...@@ -10,19 +10,19 @@ ...@@ -10,19 +10,19 @@
#include <CNNBufferFile.h> #include <CNNBufferFile.h>
<#list tc.architecture.streams as stream> <#list tc.architecture.streams as stream>
<#if stream.isNetwork()> <#if stream.isTrainable()>
class ${tc.fileNameWithoutEnding}_${stream?index}{ class ${tc.fileNameWithoutEnding}_${stream?index}{
public: public:
const std::string json_file = "model/${tc.componentName}/model_${stream?index}_newest-symbol.json"; const std::string json_file = "model/${tc.componentName}/model_${stream?index}_newest-symbol.json";
const std::string param_file = "model/${tc.componentName}/model_${stream?index}_newest-0000.params"; const std::string param_file = "model/${tc.componentName}/model_${stream?index}_newest-0000.params";
const std::vector<std::string> input_keys = { const std::vector<std::string> input_keys = {
<#if (tc.getStreamInputNames(stream)?size == 1)> <#if tc.getStreamInputNames(stream)?size == 1>
"data" "data"
<#else> <#else>
<#list tc.getStreamInputNames(stream) as inputName>"data${inputName?index}"<#sep>, </#list> <#list tc.getStreamInputNames(stream) as variable>"data${variable?index}"<#sep>, </#list>
</#if> </#if>
}; };
const std::vector<std::vector<mx_uint>> input_shapes = {<#list stream.getFirstAtomicElements() as input>{1, ${tc.join(input.definition.type.dimens