Commit 45f18417 authored by Evgeny Kusmenko's avatar Evgeny Kusmenko

Merge branch 'release' into 'master'

Pipeline fix and new CNNTrain Integration

See merge request !22
parents 7aeb41ef 7cd16d16
Pipeline #191322 passed with stages
in 5 minutes and 16 seconds
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<groupId>de.monticore.lang.monticar</groupId> <groupId>de.monticore.lang.monticar</groupId>
<artifactId>cnnarch-gluon-generator</artifactId> <artifactId>cnnarch-gluon-generator</artifactId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= --> <!-- == PROJECT DEPENDENCIES ============================================= -->
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<!-- .. SE-Libraries .................................................. --> <!-- .. SE-Libraries .................................................. -->
<CNNArch.version>0.3.3-SNAPSHOT</CNNArch.version> <CNNArch.version>0.3.3-SNAPSHOT</CNNArch.version>
<CNNTrain.version>0.3.6-SNAPSHOT</CNNTrain.version> <CNNTrain.version>0.3.7-SNAPSHOT</CNNTrain.version>
<CNNArch2X.version>0.0.4-SNAPSHOT</CNNArch2X.version> <CNNArch2X.version>0.0.4-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.2-SNAPSHOT</EMADL2PythonWrapper.version> <EMADL2PythonWrapper.version>0.0.2-SNAPSHOT</EMADL2PythonWrapper.version>
......
...@@ -151,7 +151,14 @@ public class CNNTrain2Gluon extends CNNTrainGenerator { ...@@ -151,7 +151,14 @@ public class CNNTrain2Gluon extends CNNTrainGenerator {
// Generate Reward function if necessary // Generate Reward function if necessary
if (configuration.getRlRewardFunction().isPresent()) { if (configuration.getRlRewardFunction().isPresent()) {
generateRewardFunction(configuration.getRlRewardFunction().get(), Paths.get(rootProjectModelsDir)); if (configuration.getTrainedArchitecture().isPresent()) {
generateRewardFunction(configuration.getTrainedArchitecture().get(),
configuration.getRlRewardFunction().get(), Paths.get(rootProjectModelsDir));
} else {
Log.error("No architecture model for the trained neural network but is required for " +
"reinforcement learning configuration.");
}
} }
ftlContext.put("trainerName", trainerName); ftlContext.put("trainerName", trainerName);
...@@ -167,7 +174,8 @@ public class CNNTrain2Gluon extends CNNTrainGenerator { ...@@ -167,7 +174,8 @@ public class CNNTrain2Gluon extends CNNTrainGenerator {
return fileContentMap; return fileContentMap;
} }
private void generateRewardFunction(RewardFunctionSymbol rewardFunctionSymbol, Path modelsDirPath) { private void generateRewardFunction(NNArchitectureSymbol trainedArchitecture,
RewardFunctionSymbol rewardFunctionSymbol, Path modelsDirPath) {
GeneratorPythonWrapperStandaloneApi pythonWrapperApi = new GeneratorPythonWrapperStandaloneApi(); GeneratorPythonWrapperStandaloneApi pythonWrapperApi = new GeneratorPythonWrapperStandaloneApi();
List<String> fullNameOfComponent = rewardFunctionSymbol.getRewardFunctionComponentName(); List<String> fullNameOfComponent = rewardFunctionSymbol.getRewardFunctionComponentName();
...@@ -200,7 +208,7 @@ public class CNNTrain2Gluon extends CNNTrainGenerator { ...@@ -200,7 +208,7 @@ public class CNNTrain2Gluon extends CNNTrainGenerator {
componentPortInformation = pythonWrapperApi.generate(emaSymbol, pythonWrapperOutputPath); componentPortInformation = pythonWrapperApi.generate(emaSymbol, pythonWrapperOutputPath);
} }
RewardFunctionParameterAdapter functionParameter = new RewardFunctionParameterAdapter(componentPortInformation); RewardFunctionParameterAdapter functionParameter = new RewardFunctionParameterAdapter(componentPortInformation);
new FunctionParameterChecker().check(functionParameter); new FunctionParameterChecker().check(functionParameter, trainedArchitecture);
rewardFunctionSymbol.setRewardFunctionParameter(functionParameter); rewardFunctionSymbol.setRewardFunctionParameter(functionParameter);
} }
......
/* (c) https://github.com/MontiCore/monticore */ /* (c) https://github.com/MontiCore/monticore */
package de.monticore.lang.monticar.cnnarch.gluongenerator.reinforcement; package de.monticore.lang.monticar.cnnarch.gluongenerator.reinforcement;
import de.monticore.lang.monticar.cnntrain._symboltable.NNArchitectureSymbol;
import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.Log;
import java.util.List;
/** /**
* *
*/ */
...@@ -11,21 +14,42 @@ public class FunctionParameterChecker { ...@@ -11,21 +14,42 @@ public class FunctionParameterChecker {
private String inputTerminalParameterName; private String inputTerminalParameterName;
private String outputParameterName; private String outputParameterName;
private RewardFunctionParameterAdapter rewardFunctionParameter; private RewardFunctionParameterAdapter rewardFunctionParameter;
private NNArchitectureSymbol trainedArchitecture;
public FunctionParameterChecker() { public FunctionParameterChecker() {
} }
public void check(final RewardFunctionParameterAdapter rewardFunctionParameter) { public void check(final RewardFunctionParameterAdapter rewardFunctionParameter,
final NNArchitectureSymbol trainedArchitecture) {
assert rewardFunctionParameter != null;
assert trainedArchitecture != null;
this.rewardFunctionParameter = rewardFunctionParameter; this.rewardFunctionParameter = rewardFunctionParameter;
this.trainedArchitecture = trainedArchitecture;
retrieveParameterNames(); retrieveParameterNames();
checkHasExactlyTwoInputs(); checkHasExactlyTwoInputs();
checkHasExactlyOneOutput(); checkHasExactlyOneOutput();
checkHasStateAndTerminalInput(); checkHasStateAndTerminalInput();
checkInputStateDimension();
checkInputTerminalTypeAndDimension(); checkInputTerminalTypeAndDimension();
checkStateDimensionEqualsTrainedArchitectureState();
checkInputStateDimension();
checkOutputDimension(); checkOutputDimension();
} }
private void checkStateDimensionEqualsTrainedArchitectureState() {
failIfConditionFails(stateInputOfNNArchitectureIsEqualToRewardState(),
"State dimension of trained architecture is not equal to reward state dimensions.");
}
private boolean stateInputOfNNArchitectureIsEqualToRewardState() {
assert trainedArchitecture.getInputs().size() == 1: "Trained architecture is not a policy network.";
final String nnStateInputName = trainedArchitecture.getInputs().get(0);
final List<Integer> dimensions = trainedArchitecture.getDimensions().get(nnStateInputName);
return rewardFunctionParameter.getInputPortDimensionOfPort(inputStateParameterName).isPresent()
&& rewardFunctionParameter.getInputPortDimensionOfPort(inputStateParameterName).get().equals(dimensions);
}
private void checkHasExactlyTwoInputs() { private void checkHasExactlyTwoInputs() {
failIfConditionFails(functionHasTwoInputs(), "Reward function must have exactly two input parameters: " failIfConditionFails(functionHasTwoInputs(), "Reward function must have exactly two input parameters: "
+ "One input needs to represents the environment's state and another input needs to be a " + "One input needs to represents the environment's state and another input needs to be a "
......
package de.monticore.lang.monticar.cnnarch.gluongenerator.reinforcement;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import de.monticore.lang.monticar.cnntrain._symboltable.NNArchitectureSymbol;
import de.monticore.lang.monticar.generator.pythonwrapper.symbolservices.data.ComponentPortInformation;
import de.monticore.lang.monticar.generator.pythonwrapper.symbolservices.data.EmadlType;
import de.monticore.lang.monticar.generator.pythonwrapper.symbolservices.data.PortDirection;
import de.monticore.lang.monticar.generator.pythonwrapper.symbolservices.data.PortVariable;
import de.se_rwth.commons.logging.Finding;
import de.se_rwth.commons.logging.Log;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FunctionParameterCheckerTest {
private static final List<Integer> STATE_DIMENSIONS = Lists.newArrayList(3,2,4);
private static final PortVariable STATE_PORT = PortVariable.multidimensionalVariableFrom("input1", EmadlType.Q,
PortDirection.INPUT, STATE_DIMENSIONS);
private static final PortVariable TERMINAL_PORT = PortVariable.primitiveVariableFrom("input2", EmadlType.B,
PortDirection.INPUT);
private static final PortVariable OUTPUT_PORT = PortVariable.primitiveVariableFrom("output1", EmadlType.Q,
PortDirection.OUTPUT);
private static final String COMPONENT_NAME = "TestRewardComponent";
FunctionParameterChecker uut = new FunctionParameterChecker();
@Before
public void setup() {
Log.getFindings().clear();
Log.enableFailQuick(false);
}
@Test
public void validReward() {
// given
RewardFunctionParameterAdapter adapter = getValidRewardAdapter();
// when
uut.check(adapter, getValidTrainedArchitecture());
List<Finding> findings = Log.getFindings();
assertEquals(0, findings.stream().filter(Finding::isError).count());
}
@Test
public void invalidRewardWithOneInput() {
// given
RewardFunctionParameterAdapter adapter = getComponentWithOneInput();
// when
uut.check(adapter, getValidTrainedArchitecture());
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().anyMatch(Finding::isError));
}
@Test
public void invalidRewardWithTwoOutputs() {
// given
RewardFunctionParameterAdapter adapter = getComponentWithTwoOutputs();
// when
uut.check(adapter, getValidTrainedArchitecture());
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().anyMatch(Finding::isError));
}
@Test
public void invalidRewardWithTerminalHasQType() {
// given
RewardFunctionParameterAdapter adapter = getComponentWithTwoQInputs();
// when
uut.check(adapter, getValidTrainedArchitecture());
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().anyMatch(Finding::isError));
}
@Test
public void invalidRewardWithNonScalarOutput() {
// given
RewardFunctionParameterAdapter adapter = getComponentWithNonScalarOutput();
// when
uut.check(adapter, getValidTrainedArchitecture());
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().filter(Finding::isError).count() == 1);
}
@Test
public void invalidRewardStateUnequalToTrainedArchitectureState1() {
// given
RewardFunctionParameterAdapter adapter = getValidRewardAdapter();
NNArchitectureSymbol trainedArchitectureWithDifferenDimension = getTrainedArchitectureWithStateDimensions(
Lists.newArrayList(6));
// when
uut.check(adapter, trainedArchitectureWithDifferenDimension);
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().filter(Finding::isError).count() == 1);
}
@Test
public void invalidRewardStateUnequalToTrainedArchitectureState2() {
// given
RewardFunctionParameterAdapter adapter = getValidRewardAdapter();
NNArchitectureSymbol trainedArchitectureWithDifferenDimension = getTrainedArchitectureWithStateDimensions(
Lists.newArrayList(3, 8));
// when
uut.check(adapter, trainedArchitectureWithDifferenDimension);
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().filter(Finding::isError).count() == 1);
}
@Test
public void invalidRewardStateUnequalToTrainedArchitectureState3() {
// given
RewardFunctionParameterAdapter adapter = getValidRewardAdapter();
NNArchitectureSymbol trainedArchitectureWithDifferenDimension = getTrainedArchitectureWithStateDimensions(
Lists.newArrayList(2,4,3));
// when
uut.check(adapter, trainedArchitectureWithDifferenDimension);
List<Finding> findings = Log.getFindings();
assertTrue(findings.stream().filter(Finding::isError).count() == 1);
}
private RewardFunctionParameterAdapter getComponentWithNonScalarOutput() {
ComponentPortInformation componentPortInformation = new ComponentPortInformation(COMPONENT_NAME);
componentPortInformation.addAllInputs(getValidInputPortVariables());
List<PortVariable> outputs = Lists.newArrayList(PortVariable.multidimensionalVariableFrom(
"output", EmadlType.Q, PortDirection.OUTPUT, Lists.newArrayList(2,2)));
componentPortInformation.addAllOutputs(outputs);
return new RewardFunctionParameterAdapter(componentPortInformation);
}
private RewardFunctionParameterAdapter getComponentWithTwoQInputs() {
ComponentPortInformation componentPortInformation
= new ComponentPortInformation(COMPONENT_NAME);
List<PortVariable> inputs = Lists.newArrayList(STATE_PORT,
PortVariable.multidimensionalVariableFrom("input2", EmadlType.Q, PortDirection.INPUT,
Lists.newArrayList(2,3,2)));
componentPortInformation.addAllInputs(inputs);
componentPortInformation.addAllOutputs(getValidOutputPorts());
return new RewardFunctionParameterAdapter(componentPortInformation);
}
private RewardFunctionParameterAdapter getComponentWithTwoOutputs() {
ComponentPortInformation componentPortInformation
= new ComponentPortInformation(COMPONENT_NAME);
componentPortInformation.addAllInputs(getValidInputPortVariables());
List<PortVariable> outputs = getValidOutputPorts();
outputs.add(PortVariable.primitiveVariableFrom("output2", EmadlType.B, PortDirection.OUTPUT));
componentPortInformation.addAllOutputs(outputs);
return new RewardFunctionParameterAdapter(componentPortInformation);
}
private RewardFunctionParameterAdapter getComponentWithOneInput() {
ComponentPortInformation componentPortInformation
= new ComponentPortInformation(COMPONENT_NAME);
componentPortInformation.addAllInputs(Lists.newArrayList(STATE_PORT));
componentPortInformation.addAllOutputs(getValidOutputPorts());
return new RewardFunctionParameterAdapter(componentPortInformation);
}
private RewardFunctionParameterAdapter getValidRewardAdapter() {
ComponentPortInformation componentPortInformation
= new ComponentPortInformation(COMPONENT_NAME);
componentPortInformation.addAllInputs(getValidInputPortVariables());
componentPortInformation.addAllOutputs(getValidOutputPorts());
return new RewardFunctionParameterAdapter(componentPortInformation);
}
private List<PortVariable> getValidOutputPorts() {
return Lists.newArrayList(OUTPUT_PORT);
}
private List<PortVariable> getValidInputPortVariables() {
return Lists.newArrayList(STATE_PORT, TERMINAL_PORT);
}
private NNArchitectureSymbol getValidTrainedArchitecture() {
NNArchitectureSymbol nnArchitectureSymbol = mock(NNArchitectureSymbol.class);
final String stateInputName = "stateInput";
when(nnArchitectureSymbol.getInputs()).thenReturn(Lists.newArrayList(stateInputName));
when(nnArchitectureSymbol.getDimensions()).thenReturn(ImmutableMap.<String, List<Integer>>builder()
.put(stateInputName, STATE_DIMENSIONS)
.build());
return nnArchitectureSymbol;
}
private NNArchitectureSymbol getTrainedArchitectureWithStateDimensions(final List<Integer> dimensions) {
NNArchitectureSymbol nnArchitectureSymbol = mock(NNArchitectureSymbol.class);
final String stateInputName = "stateInput";
when(nnArchitectureSymbol.getInputs()).thenReturn(Lists.newArrayList(stateInputName));
when(nnArchitectureSymbol.getDimensions()).thenReturn(ImmutableMap.<String, List<Integer>>builder()
.put(stateInputName, dimensions)
.build());
return nnArchitectureSymbol;
}
}
\ No newline at end of file
/* (c) https://github.com/MontiCore/monticore */
#ifndef CNNBUFFERFILE_H #ifndef CNNBUFFERFILE_H
#define CNNBUFFERFILE_H #define CNNBUFFERFILE_H
......
# (c) https://github.com/MontiCore/monticore
import mxnet as mx import mxnet as mx
import logging import logging
import os import os
......
# (c) https://github.com/MontiCore/monticore
import mxnet as mx import mxnet as mx
import logging import logging
import os import os
......
# (c) https://github.com/MontiCore/monticore
import mxnet as mx import mxnet as mx
import logging import logging
import os import os
......
# (c) https://github.com/MontiCore/monticore
import os import os
import h5py import h5py
import mxnet as mx import mxnet as mx
......
# (c) https://github.com/MontiCore/monticore
import os import os
import h5py import h5py
import mxnet as mx import mxnet as mx
......
# (c) https://github.com/MontiCore/monticore
import os import os
import h5py import h5py
import mxnet as mx import mxnet as mx
......
# (c) https://github.com/MontiCore/monticore
import mxnet as mx import mxnet as mx
import numpy as np import numpy as np
from mxnet import gluon from mxnet import gluon
...@@ -91,13 +90,14 @@ class Net_0(gluon.HybridBlock): ...@@ -91,13 +90,14 @@ class Net_0(gluon.HybridBlock):
else: else:
self.input_normalization_data_ = NoNormalization() self.input_normalization_data_ = NoNormalization()
self.conv1_padding = Padding(padding=(0,0,0,0,2,1,2,1)) self.conv1_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.conv1_ = gluon.nn.Conv2D(channels=96, self.conv1_ = gluon.nn.Conv2D(channels=96,
kernel_size=(11,11), kernel_size=(11,11),
strides=(4,4), strides=(4,4),
use_bias=True) use_bias=True)
# conv1_, output shape: {[96,55,55]} # conv1_, output shape: {[96,55,55]}
self.pool1_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.pool1_ = gluon.nn.MaxPool2D( self.pool1_ = gluon.nn.MaxPool2D(
pool_size=(3,3), pool_size=(3,3),
strides=(2,2)) strides=(2,2))
...@@ -114,6 +114,7 @@ class Net_0(gluon.HybridBlock): ...@@ -114,6 +114,7 @@ class Net_0(gluon.HybridBlock):
use_bias=True) use_bias=True)
# conv2_1_, output shape: {[128,27,27]} # conv2_1_, output shape: {[128,27,27]}
self.pool2_1_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.pool2_1_ = gluon.nn.MaxPool2D( self.pool2_1_ = gluon.nn.MaxPool2D(
pool_size=(3,3), pool_size=(3,3),
strides=(2,2)) strides=(2,2))
...@@ -127,6 +128,7 @@ class Net_0(gluon.HybridBlock): ...@@ -127,6 +128,7 @@ class Net_0(gluon.HybridBlock):
use_bias=True) use_bias=True)
# conv2_2_, output shape: {[128,27,27]} # conv2_2_, output shape: {[128,27,27]}
self.pool2_2_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.pool2_2_ = gluon.nn.MaxPool2D( self.pool2_2_ = gluon.nn.MaxPool2D(
pool_size=(3,3), pool_size=(3,3),
strides=(2,2)) strides=(2,2))
...@@ -162,6 +164,7 @@ class Net_0(gluon.HybridBlock): ...@@ -162,6 +164,7 @@ class Net_0(gluon.HybridBlock):
use_bias=True) use_bias=True)
# conv5_1_, output shape: {[128,13,13]} # conv5_1_, output shape: {[128,13,13]}
self.pool5_1_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.pool5_1_ = gluon.nn.MaxPool2D( self.pool5_1_ = gluon.nn.MaxPool2D(
pool_size=(3,3), pool_size=(3,3),
strides=(2,2)) strides=(2,2))
...@@ -183,6 +186,7 @@ class Net_0(gluon.HybridBlock): ...@@ -183,6 +186,7 @@ class Net_0(gluon.HybridBlock):
use_bias=True) use_bias=True)
# conv5_2_, output shape: {[128,13,13]} # conv5_2_, output shape: {[128,13,13]}
self.pool5_2_padding = Padding(padding=(0,0,-1,0,0,0,0,0))
self.pool5_2_ = gluon.nn.MaxPool2D( self.pool5_2_ = gluon.nn.MaxPool2D(
pool_size=(3,3), pool_size=(3,3),
strides=(2,2)) strides=(2,2))
...@@ -217,7 +221,8 @@ class Net_0(gluon.HybridBlock): ...@@ -217,7 +221,8 @@ class Net_0(gluon.HybridBlock):
beta=0.75, beta=0.75,
knorm=2, knorm=2,
nsize=5) nsize=5)
pool1_ = self.pool1_(lrn1_) pool1_padding = self.pool1_padding(lrn1_)
pool1_ = self.pool1_(pool1_padding)
relu1_ = self.relu1_(pool1_) relu1_ = self.relu1_(pool1_)
split1_ = self.split1_(relu1_) split1_ = self.split1_(relu1_)
get2_1_ = split1_[0] get2_1_ = split1_[0]
...@@ -228,7 +233,8 @@ class Net_0(gluon.HybridBlock): ...@@ -228,7 +233,8 @@ class Net_0(gluon.HybridBlock):
beta=0.75, beta=0.75,
knorm=2, knorm=2,
nsize=5) nsize=5)
pool2_1_ = self.pool2_1_(lrn2_1_) pool2_1_padding = self.pool2_1_padding(lrn2_1_)
pool2_1_ = self.pool2_1_(pool2_1_padding)
relu2_1_ = self.relu2_1_(pool2_1_) relu2_1_ = self.relu2_1_(pool2_1_)
get2_2_ = split1_[1] get2_2_ = split1_[1]
conv2_2_padding = self.conv2_2_padding(get2_2_) conv2_2_padding = self.conv2_2_padding(get2_2_)
...@@ -238,7 +244,8 @@ class Net_0(gluon.HybridBlock): ...@@ -238,7 +244,8 @@ class Net_0(gluon.HybridBlock):
beta=0.75, beta=0.75,
knorm=2, knorm=2,
nsize=5) nsize=5)
pool2_2_ = self.pool2_2_(lrn2_2_) pool2_2_padding = self.pool2_2_padding(lrn2_2_)
pool2_2_ = self.pool2_2_(pool2_2_padding)
relu2_2_ = self.relu2_2_(pool2_2_) relu2_2_ = self.relu2_2_(pool2_2_)
concatenate3_ = self.concatenate3_(relu2_1_, relu2_2_) concatenate3_ = self.concatenate3_(relu2_1_, relu2_2_)
conv3_padding = self.conv3_padding(concatenate3_) conv3_padding = self.conv3_padding(concatenate3_)
...@@ -251,7 +258,8 @@ class Net_0(gluon.HybridBlock): ...@@ -251,7 +258,8 @@ class Net_0(gluon.HybridBlock):
relu4_1_ = self.relu4_1_(conv4_1_) relu4_1_ = self.relu4_1_(conv4_1_)
conv5_1_padding = self.conv5_1_padding(relu4_1_)