Commit 070ca7db authored by Thomas Michael Timmermanns's avatar Thomas Michael Timmermanns
Browse files

New version with direct embedding of architecture.

Created Generator prototype.
parent ba8189a6
# EmbeddedMontiArcDL
[![Build Status](https://travis-ci.org/EmbeddedMontiArc/EmbeddedMontiArcDL.svg?branch=master)](https://travis-ci.org/EmbeddedMontiArc/EmbeddedMontiArcDL)
[![Coverage Status](https://coveralls.io/repos/github/EmbeddedMontiArc/EmbeddedMontiArcDL/badge.svg?branch=master)](https://coveralls.io/github/EmbeddedMontiArc/EmbeddedMontiArcDL?branch=master)
[![Build Status](https://circleci.com/gh/EmbeddedMontiArc/EmbeddedMontiArcDL/tree/master.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/EmbeddedMontiArc/EmbeddedMontiArcDL/tree/master)
# EmbeddedMontiArcDL
**work in progress**
##Examples
```
package mnist;
component SimpleCNN{
ports in Z(0:255)^{1,28,28} data,
out Q(0:1)^{10} predictions;
implementation CNN {
data ->
Convolution(kernel=(5,5), channels=20) ->
Tanh() ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
Convolution(kernel=(5,5), channels=20) ->
Tanh() ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
FullyConnected(units=1000) ->
Tanh() ->
Dropout() ->
FullyConnected(units=10) ->
Softmax() ->
predictions
}
}
```
```
component VGG16{
ports in Z(0:255)^{3, 224, 224} image,
out Q(0:1)^{1000} predictions;
implementation CNN {
def conv(filter, channels){
Convolution(kernel=(filter,filter), channels=channels) ->
Relu()
}
def fc(){
FullyConnected(units=4096) ->
Relu() ->
Dropout(p=0.5)
}
image ->
conv(filter=3, channels=64, ->=2) ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
conv(filter=3, channels=128, ->=2) ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
conv(filter=3, channels=256, ->=3) ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
conv(filter=3, channels=512, ->=3) ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
conv(filter=3, channels=512, ->=3) ->
Pooling(pool_type="max", kernel=(2,2), stride=(2,2)) ->
fc() ->
fc() ->
FullyConnected(units=1000) ->
Softmax() ->
predictions
}
}
```
```
component ResNet34{
ports in Z(0:255)^{3, 224, 224} image,
out Q(0:1)^{1000} predictions;
implementation CNN {
def conv(filter, channels, stride=1, act=true){
Convolution(kernel=(filter,filter), channels=channels, stride=(stride,stride)) ->
BatchNorm() ->
Relu(?=act)
}
def skip(channels, stride){
Convolution(kernel=(1,1), channels=channels, stride=(stride,stride)) ->
BatchNorm()
}
def resLayer(channels, stride=1){
(
conv(filter=3, channels=channels, stride=stride) ->
conv(filter=3, channels=channels, act=false)
|
skip(channels=channels, stride=stride, ? = (stride != 1))
) ->
Add() ->
Relu()
}
image ->
conv(filter=7, channels=64, stride=2) ->
Pooling(pool_type="max", kernel=(3,3), stride=(2,2)) ->
resLayer(channels=64, ->=3) ->
resLayer(channels=128, stride=2) ->
resLayer(channels=128, ->=3) ->
resLayer(channels=256, stride=2) ->
resLayer(channels=256, ->=5) ->
resLayer(channels=512, stride=2) ->
resLayer(channels=512, ->=2) ->
GlobalPooling(pool_type="avg") ->
FullyConnected(units=1000) ->
Softmax() ->
predictions
}
}
```
```
component Alexnet{
ports in Z(0:255)^{3, 224, 224} image,
out Q(0:1)^{10} predictions;
implementation CNN {
def split1(i){
[i] ->
Convolution(kernel=(5,5), channels=128) ->
Lrn(nsize=5, alpha=0.0001, beta=0.75) ->
Pooling(pool_type="max", kernel=(3,3), stride=(2,2), padding="no_loss") ->
Relu()
}
def split2(i){
[i] ->
Convolution(kernel=(3,3), channels=192) ->
Relu() ->
Convolution(kernel=(3,3), channels=128) ->
Pooling(pool_type="max", kernel=(3,3), stride=(2,2), padding="no_loss") ->
Relu()
}
def fc(){
FullyConnected(units=4096) ->
Relu() ->
Dropout()
}
image ->
Convolution(kernel=(11,11), channels=96, stride=(4,4), padding="no_loss") ->
Lrn(nsize=5, alpha=0.0001, beta=0.75) ->
Pooling(pool_type="max", kernel=(3,3), stride=(2,2), padding="no_loss") ->
Relu() ->
Split(n=2) ->
split1(i=[0|1]) ->
Concatenate() ->
Convolution(kernel=(3,3), channels=384) ->
Relu() ->
Split(n=2) ->
split2(i=[0|1]) ->
Concatenate() ->
fc(->=2) ->
FullyConnected(units=10) ->
Softmax() ->
predictions
}
}
```
```
component ResNeXt50{
ports in Z(0:255)^{3, 224, 224} image,
out Q(0:1)^{1000} predictions;
implementation CNN {
def conv(filter, channels, stride=1, act=true){
Convolution(kernel=filter, channels=channels, stride=(stride,stride)) ->
BatchNorm() ->
Relu(?=act)
}
def resGroup(innerChannels, outChannels, stride=1){
conv(filter=(1,1), channels=innerChannels) ->
conv(filter=(3,3), channels=innerChannels, stride=stride) ->
conv(filter=(1,1), channels=outChannels, act=false)
}
def skip(outChannels, stride){
Convolution(kernel=(1,1), channels=outChannels, stride=(stride,stride)) ->
BatchNorm()
}
def resLayer(innerChannels, outChannels, stride=1, changedChannels=false){
(
resGroup(innerChannels=innerChannels,
outChannels=outChannels,
stride=stride,
| = 32) ->
Add()
|
skip(outChannels=outChannels, stride=stride, ? = stride!=1 || changedChannels)
) ->
Add() ->
Relu()
}
image ->
conv(filter=(7,7), channels=64, stride=2) ->
Pooling(pool_type="max", kernel=(3,3), stride=(2,2)) ->
resLayer(innerChannels=4, outChannels=256, changedChannels=true, -> = 3) ->
resLayer(innerChannels=8, outChannels=512, stride=2) ->
resLayer(innerChannels=8, outChannels=512, -> = 3) ->
resLayer(innerChannels=16, outChannels=1024, stride=2) ->
resLayer(innerChannels=16, outChannels=1024, -> = 5) ->
resLayer(innerChannels=32, outChannels=2048, stride=2) ->
resLayer(innerChannels=32, outChannels=2048, -> = 2) ->
GlobalPooling(pool_type="avg") ->
FullyConnected(units=classes) ->
Softmax() ->
predictions
}
}
```
\ No newline at end of file
......@@ -30,7 +30,7 @@
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-deeplearning</artifactId>
<version>0.1.1-SNAPSHOT</version>
<version>0.2.0-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= -->
......@@ -42,11 +42,12 @@
<mc.grammars.assembly.version>0.0.6-SNAPSHOT</mc.grammars.assembly.version>
<SIUnit.version>0.0.10-SNAPSHOT</SIUnit.version>
<Common-MontiCar.version>0.0.10-SNAPSHOT</Common-MontiCar.version>
<Embedded-MontiArc.version>0.0.10-SNAPSHOT</Embedded-MontiArc.version>
<Embedded-MontiArc-Behaviour.version>0.0.10-SNAPSHOT</Embedded-MontiArc-Behaviour.version>
<CNNArch.version>0.1.1-SNAPSHOT</CNNArch.version>
<CNNTrain.version>0.1.1-SNAPSHOT</CNNTrain.version>
<Math.version>0.0.10-SNAPSHOT</Math.version>
<Embedded-MontiArc.version>0.0.11-SNAPSHOT</Embedded-MontiArc.version>
<Embedded-MontiArc-Behaviour.version>0.0.11-SNAPSHOT</Embedded-MontiArc-Behaviour.version>
<CNNArch.version>0.2.0-SNAPSHOT</CNNArch.version>
<Math.version>0.0.11-SNAPSHOT</Math.version>
<Embedded-MontiArc-Math.version>0.0.11-SNAPSHOT</Embedded-MontiArc-Math.version>
<embedded-montiarc-math-generator>0.0.7-SNAPSHOT</embedded-montiarc-math-generator>
<!-- .. Libraries .................................................. -->
<guava.version>18.0</guava.version>
......@@ -194,28 +195,26 @@
<dependency>
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>cnn-arch</artifactId>
<version>${CNNArch.version}</version>
<artifactId>embedded-montiarc-math</artifactId>
<version>${Embedded-MontiArc-Math.version}</version>
</dependency>
<dependency>
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>cnn-arch</artifactId>
<version>${CNNArch.version}</version>
<classifier>${grammars.classifier}</classifier>
<scope>provided</scope>
<artifactId>embedded-montiarc-math-generator</artifactId>
<version>${embedded-montiarc-math-generator}</version>
</dependency>
<dependency>
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>cnn-train</artifactId>
<version>${CNNTrain.version}</version>
<artifactId>cnn-arch</artifactId>
<version>${CNNArch.version}</version>
</dependency>
<dependency>
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>cnn-train</artifactId>
<version>${CNNTrain.version}</version>
<artifactId>cnn-arch</artifactId>
<version>${CNNArch.version}</version>
<classifier>${grammars.classifier}</classifier>
<scope>provided</scope>
</dependency>
......
package de.monticore.lang.monticar;
grammar EMADL extends de.monticore.lang.embeddedmontiarc.EmbeddedMontiArcBehavior,
de.monticore.lang.monticar.Common2,
de.monticore.lang.NumberUnit{
//de.monticore.lang.monticar.MCExpressions,
de.monticore.lang.monticar.CNNArch{
EMADLCompilationUnit = EMACompilationUnit;
BehaviorEmbedding = ArchitectureEmbedding ConfigEmbedding;
BehaviorEmbedding = Architecture | MathStatements;
BehaviorName = "DeepLearning";
ArchitectureEmbedding = "architecture" ":" ArchitectureConstructor;
ConfigEmbedding= "configuration" ":" ConfigConstructor;
ArchitectureConstructor = input:ArchIOPorts "->"
Name "(" arguments:(NamedArgument || ",")* ")"
"->" output:ArchIOPorts;
ArchIOPorts = "{" ports:(ArchIOPort || ",")* "}";
ArchIOPort = Name ("as" alias:Name)?;
ConfigConstructor = Name "("
arguments:(NamedArgument || ",")* ")";
NamedArgument = Name "=" Value;
Num implements Value = Number;
//NamedArgument = Name "=" (optValue:Value | reference:Name);
BehaviorName = name:"CNN" | name:"Math";
token NEWLINETOKEN =
('\r' '\n' |
'\r' |
'\n' ):;
}
\ No newline at end of file
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.emadl._ast;
import de.monticore.lang.monticar.common2._ast.ASTLiteralValue;
import de.monticore.lang.monticar.common2._ast.ASTValue;
import de.monticore.lang.monticar.literals2._ast.ASTBooleanLiteral;
import de.monticore.lang.monticar.literals2._ast.ASTCharLiteral;
import de.monticore.lang.monticar.literals2._ast.ASTStringLiteral;
import de.monticore.lang.numberunit._ast.ASTNumber;
import org.jscience.mathematics.number.Rational;
import java.util.Optional;
public class ASTNamedArgument extends ASTNamedArgumentTOP {
public ASTNamedArgument() {
}
public ASTNamedArgument(String name, ASTValue value) {
super(name, value);
}
public Object getLiteralValue() {
if (getValue() instanceof ASTLiteralValue){
return ((ASTLiteralValue) getValue()).getValue();
}
return super.getValue();
}
public Optional<Rational> getRationalValue(){
if (getLiteralValue() instanceof ASTNum){
ASTNumber number = ((ASTNum) getLiteralValue()).getNumber();
return number.getUnitNumber().get().getNumber();
}
return Optional.empty();
}
public Optional<Integer> getIntValue(){
Optional<Rational> rational = getRationalValue();
if (rational.isPresent() && rational.get().getDivisor().intValue() == 1){
return Optional.of(rational.get().getDividend().intValue());
}
return Optional.empty();
}
public Optional<Double> getDoubleValue(){
return getRationalValue().map(Rational::doubleValue);
}
public Optional<Boolean> getBooleanValue(){
if (getLiteralValue() instanceof ASTBooleanLiteral){
return Optional.of(((ASTBooleanLiteral) getLiteralValue()).getValue());
}
return Optional.empty();
}
public Optional<String> getStringValue(){
if (getLiteralValue() instanceof ASTStringLiteral){
return Optional.of(((ASTStringLiteral) getLiteralValue()).getValue());
}
else if (getLiteralValue() instanceof ASTCharLiteral){
return Optional.of(String.valueOf(((ASTCharLiteral) getLiteralValue()).getValue()));
}
return Optional.empty();
}
}
......@@ -20,16 +20,16 @@
*/
package de.monticore.lang.monticar.emadl._cocos;
import de.monticore.lang.monticar.cnnarch._ast.ASTCNNArchNode;
import de.monticore.lang.monticar.cnnarch._ast.ASTArchitecture;
import de.monticore.lang.monticar.cnnarch._cocos.CNNArchASTArchitectureCoCo;
import de.monticore.lang.monticar.cnnarch._cocos.CNNArchCocos;
import de.monticore.lang.monticar.emadl._ast.ASTArchitectureConstructor;
import de.monticore.lang.monticar.emadl._symboltable.ArchitectureConstructorSymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.ArchitectureSymbol;
public class CheckCNNArchPostResolveCocos implements EMADLASTArchitectureConstructorCoCo {
public class CheckArchitecture implements CNNArchASTArchitectureCoCo{
@Override
public void check(ASTArchitectureConstructor node) {
ArchitectureConstructorSymbol sym = (ArchitectureConstructorSymbol) node.getSymbol().get();
CNNArchCocos.createPostResolveChecker().checkAll((ASTCNNArchNode) sym.getArchitecture().getAstNode().get());
public void check(ASTArchitecture node) {
ArchitectureSymbol architecture = (ArchitectureSymbol) node.getSymbol().get();
CNNArchCocos.checkAll(architecture);
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.emadl._cocos;
import de.monticore.lang.monticar.cnnarch._symboltable.VariableSymbol;
import de.monticore.lang.monticar.emadl._ast.ASTArchitectureConstructor;
import de.monticore.lang.monticar.emadl._ast.ASTNamedArgument;
import de.monticore.lang.monticar.emadl._symboltable.ArchitectureConstructorSymbol;
import de.monticore.lang.monticar.emadl.helper.ErrorCodes;
import de.se_rwth.commons.Joiners;
import de.se_rwth.commons.logging.Log;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
public class CheckArchitectureArgument implements EMADLASTArchitectureConstructorCoCo {
@Override
public void check(ASTArchitectureConstructor node) {
ArchitectureConstructorSymbol symbol = (ArchitectureConstructorSymbol) node.getSymbol().get();
Set<VariableSymbol> remainingParameters = new HashSet<>(symbol.getArchitecture().getParameters());
for (ASTNamedArgument argument : node.getArguments()){
Optional<VariableSymbol> parameter = symbol.getArchitecture().getParameter(argument.getName());
if (parameter.isPresent()){
remainingParameters.remove(parameter.get());
}
else {
Log.error("0"+ ErrorCodes.UNKNOWN_ARGUMENT_CODE + " Unknown Argument. " +
"Parameter with name '" + argument.getName() + "' does not exist. " +
"Existing parameters are: " + Joiners.COMMA.join(symbol.getArchitecture().getParameters())
, argument.get_SourcePositionStart());
}
}
for (VariableSymbol remainingParam : remainingParameters){
if (!remainingParam.getDefaultExpression().isPresent()) {
Log.error("0" + ErrorCodes.MISSING_ARGUMENT_CODE + " Missing argument. " +
"The argument '" + remainingParam.getName() + "' is required."
, node.get_SourcePositionStart());
}
}
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.emadl._cocos;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortArraySymbol;
import de.monticore.lang.monticar.cnnarch._symboltable.IODeclarationSymbol;
import de.monticore.lang.monticar.emadl._ast.ASTArchitectureConstructor;
import de.monticore.lang.monticar.emadl._symboltable.ArchPortConnectorSymbol;
import de.monticore.lang.monticar.emadl._symboltable.ArchitectureConstructorSymbol;
import de.monticore.lang.monticar.emadl.helper.ErrorCodes;
import de.se_rwth.commons.Joiners;
import de.se_rwth.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class CheckArchitectureIO implements EMADLASTArchitectureConstructorCoCo {
@Override
public void check(ASTArchitectureConstructor node) {
ArchitectureConstructorSymbol constructor = (ArchitectureConstructorSymbol) node.getSymbol().get();
List<IODeclarationSymbol> ioDeclarations = new ArrayList<>();
ioDeclarations.addAll(constructor.getArchitecture().getInputs());
ioDeclarations.addAll(constructor.getArchitecture().getOutputs());
for (IODeclarationSymbol ioDeclaration : ioDeclarations){
checkIODeclaration(constructor, ioDeclaration);
}
for (ArchPortConnectorSymbol port : constructor.getInputs()){
checkIfInputPort(port);
checkUnknownInput(constructor, port);
}
for (ArchPortConnectorSymbol port : constructor.getOutputs()){
checkIfOutputPort(port);
checkUnknownOutput(constructor, port);
}
}
private void checkIODeclaration(ArchitectureConstructorSymbol constructor, IODeclarationSymbol ioDeclaration){
if (ioDeclaration.isInput()){
if (!constructor.getInputNames().contains(ioDeclaration.getName())){
Log.error("0" + ErrorCodes.MISSING_IO_CODE + " " +
"Missing input with name '" + ioDeclaration.getName() + "'."
, constructor.getSourcePosition());
}
}
else {
if (!constructor.getOutputNames().contains(ioDeclaration.getName())){
Log.error("0" + ErrorCodes.MISSING_IO_CODE + " " +
"Missing output with name '" + ioDeclaration.getName() + "'."
, constructor.getSourcePosition());
}
}
}
private void checkUnknownInput(ArchitectureConstructorSymbol constructor, ArchPortConnectorSymbol port){
Optional<IODeclarationSymbol> input = constructor.getArchitecture().getInput(port.getAlias());
if (!input.isPresent()){
Log.error("0" + ErrorCodes.UNKNOWN_IO_CODE + " " +
"Input with name '" + port.getAlias() + "' does not exist. " +
"Existing inputs: " + Joiners.COMMA.join(constructor.getArchitecture().getOutputs()) + ". " +
"Tip: You can rename a port such that it fits to the input or output of the architecture in the following way: {portName as newName} -> Architecture() -> {outputPort}"
, port.getSourcePosition());
}
}
private void checkUnknownOutput(ArchitectureConstructorSymbol constructor, ArchPortConnectorSymbol port){
Optional<IODeclarationSymbol> output = constructor.getArchitecture().getOutput(port.getAlias());
if (!output.isPresent()){
Log.error("0" + ErrorCodes.UNKNOWN_IO_CODE + " " +
"Output with name '" + port.getAlias() + "' does not exist. " +
"Existing outputs: " + Joiners.COMMA.join(constructor.getArchitecture().getInputs