diff --git a/.directory b/.directory new file mode 100644 index 0000000000000000000000000000000000000000..1cca69de539ff4f46938f8774fbbd9fd68c02f90 --- /dev/null +++ b/.directory @@ -0,0 +1,6 @@ +[Dolphin] +Timestamp=2021,9,23,17,57,14 +Version=4 + +[Settings] +HiddenFilesShown=true diff --git a/README.md b/README.md index aa19bb40e7a1526d0f918b110e6b804aa60572c8..3e6139fcbb9684662e2bbc9e50e22d14d99245c4 100644 --- a/README.md +++ b/README.md @@ -548,7 +548,7 @@ All predefined methods start with a capital letter and all constructed methods h * **Convolution(kernel, channels, stride=(1,1), padding="same", no_bias=false)** - Creates a convolutional layer. Currently, only 2D convolutions are allowed + Creates a convolutional layer. * **kernel** (integer tuple > 0, required): convolution kernel size: (height, width). * **channels** (integer > 0, required): number of convolution filters and number of output channels. @@ -774,7 +774,7 @@ All predefined methods start with a capital letter and all constructed methods h * **UpConvolution(kernel, channels, stride=(1,1), no_bias=false, padding="same")** - Creates a up convolutional layer (also known as transposed convolution ). Is currently only supported in the tesnsorflow backend. + Creates a up convolutional layer (also known as transposed convolution ). * **kernel** (integer tuple > 0, required): convolution kernel size: (height, width). * **channels** (integer > 0, required): number of up convolution filters and number of output channels. @@ -782,6 +782,26 @@ All predefined methods start with a capital letter and all constructed methods h * **padding** ({"valid", "same", "no_loss"}, optional, default="same"): One of "valid", "same" or "no_loss". "valid" means no padding. "same" results in padding the input such that the output has the same length as the original input divided by the stride (rounded up). "no_loss" results in minimal padding such that each input is used by at least one filter (identical to "valid" if *stride* equals 1). * **no_bias** (boolean, optional, default=false): Whether to disable the bias parameter. +* **Convolution3D(kernel, channels, stride=(1,1,1), padding="same3d", no_bias=false)** + + Creates a convolutional layer for 3 dimension. + + * **kernel** (integer tuple > 0, required): convolution kernel size: (height, width, depth). + * **channels** (integer > 0, required): number of convolution filters and number of output channels. + * **stride** (integer tuple > 0, optional, default=(1,1,1)): convolution stride: (height, width, depth). + * **padding** ({"valid", "same", "no_loss"}, optional, default="same3d"): One of "valid3d", "same3d" or "simple3d". "valid" means no padding. "same" results in padding the input such that the output has the same length as the original input divided by the stride (rounded up). "simple3d" results constant padding of size 1 (same as (1,1,1). Convolution3D also accepts tuples of form (height, widht, depth) as input. + * **no_bias** (boolean, optional, default=false): Whether to disable the bias parameter. + +* **UpConvolution3D(kernel, channels, stride=(1,1,1), padding="same3d", no_bias=false)** + + Creates a transposed convolutional layer for 3 dimensional data + + * **kernel** (integer tuple > 0, required): convolution kernel size: (height, width, depth). + * **channels** (integer > 0, required): number of convolution filters and number of output channels. + * **stride** (integer tuple > 0, optional, default=(1,1,1)): convolution stride: (height, width, depth). + * **padding** ({"valid", "same", "no_loss"}, optional, default="same3d"): One of "valid3d", "same3d" or "simple3d". "valid" means no padding. "same" results in padding the input such that the output has the same length as the original input divided by the stride (rounded up). "simple3d" results constant padding of size 1 (same as (1,1,1). UpConvolution3D also accepts tuples of form (height, widht, depth) as input. + * **no_bias** (boolean, optional, default=false): Whether to disable the bias parameter. + * **EpisodicMemory(replayMemoryStoreProb=1, maxStoredSamples=-1, memoryReplacementStrategy="replace_oldest", useReplay=true, replayInterval, replayBatchSize=-1, replaySteps, replayGradientSteps=1, useLocalAdaption=true, localAdaptionGradientSteps=1, localAdaptionK=1, queryNetDir=-1, queryNetPrefix=-1, queryNetNumInputs=1)** diff --git a/pom.xml b/pom.xml index 00d5d7b9dcc6fe99147931ba8ce6073f8ec54693..052e4616a490909ebc779778d6f0fbe602856559 100644 --- a/pom.xml +++ b/pom.xml @@ -19,9 +19,7 @@ de.monticore.lang.monticar cnn-arch - 0.4.7-SNAPSHOT - - + 0.4.8-SNAPSHOT diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/ArchTypeSymbol.java b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/ArchTypeSymbol.java index 908fe20f6188d6e7e549103e0cdba653fb434e52..3755375a4063001d68a8ab3a1c95dc9842abcd9f 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/ArchTypeSymbol.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/ArchTypeSymbol.java @@ -28,6 +28,7 @@ public class ArchTypeSymbol extends CommonSymbol { private int channelIndex = -1; private int heightIndex = -1; private int widthIndex = -1; + private int depthIndex = -1; private List dimensions = new ArrayList<>(); public ArchTypeSymbol() { @@ -88,7 +89,15 @@ public class ArchTypeSymbol extends CommonSymbol { public void setChannelIndex(int channelIndex) { this.channelIndex = channelIndex; } - +//NEW + public int getDepthIndex(){ + return depthIndex; + } + + public void setDepthIndex(int depthIndex){ + this.depthIndex = depthIndex; + } +//END NEW public ArchSimpleExpressionSymbol getHeightSymbol() { if (getHeightIndex() == -1){ return ArchSimpleExpressionSymbol.of(1); @@ -110,6 +119,19 @@ public class ArchTypeSymbol extends CommonSymbol { return getDimensionSymbols().get(getChannelIndex()); } +//NEW + public ArchSimpleExpressionSymbol getDepthSymbol() { + if (getDepthIndex() == -1){ + return ArchSimpleExpressionSymbol.of(1); + } + return getDimensionSymbols().get(getDepthIndex()); + } + + public Integer getDepth(){ + return getDepthSymbol().getIntValue().get(); + } +//END NEW + public Integer getWidth(){ return getWidthSymbol().getIntValue().get(); } @@ -139,7 +161,7 @@ public class ArchTypeSymbol extends CommonSymbol { } public List getDimensions(){ - List dimensionList = new ArrayList<>(3); + List dimensionList = new ArrayList<>(); for (ArchSimpleExpressionSymbol exp : getDimensionSymbols()){ dimensionList.add(exp.getIntValue().get()); } @@ -219,6 +241,7 @@ public class ArchTypeSymbol extends CommonSymbol { copy.setWidthIndex(getWidthIndex()); copy.setChannelIndex(getChannelIndex()); copy.setHeightIndex(getHeightIndex()); + copy.setDepthIndex(getDepthIndex()); List dimensionCopies = new ArrayList<>(); for (ArchSimpleExpressionSymbol dimension : getDimensionSymbols()){ dimensionCopies.add(dimension.preResolveDeepCopy()); @@ -228,10 +251,17 @@ public class ArchTypeSymbol extends CommonSymbol { return copy; } + public void printDimensions(){ + for (ArchSimpleExpressionSymbol dimension : getDimensionSymbols()){ + //System.out.println("From Dimension list: " + dimension.getTextualRepresentation()); + } + } + public static class Builder{ private int height = 1; private int width = 1; private int channels = 1; + private int depth = 0; private ASTElementType domain = null; public Builder height(int height){ @@ -246,6 +276,10 @@ public class ArchTypeSymbol extends CommonSymbol { this.channels = channels; return this; } + public Builder depth(int depth){ + this.depth = depth; + return this; + } public Builder elementType(ASTElementType domain){ this.domain = domain; return this; @@ -274,7 +308,18 @@ public class ArchTypeSymbol extends CommonSymbol { sym.setChannelIndex(0); sym.setHeightIndex(1); sym.setWidthIndex(2); - sym.setDimensions(Arrays.asList(channels, height, width)); + + if (this.depth != 0){ + sym.setHeightIndex(2); + sym.setWidthIndex(3); + sym.setDepthIndex(1); + sym.setDimensions(Arrays.asList(channels, depth, height, width)); //Dimensions are in this order for mxnet + //sym.printDimensions(); + } + + else { + sym.setDimensions(Arrays.asList(channels, height, width)); + } if (domain == null){ domain = new ASTElementType(); @@ -283,5 +328,6 @@ public class ArchTypeSymbol extends CommonSymbol { sym.setDomain(domain); return sym; } + } } diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/CNNArchSymbolTableCreator.java b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/CNNArchSymbolTableCreator.java index 1a8eb42236fab35b53c31f6d975909701ed3c7fa..3c799e4a9ecc1ccc356fa226f90c14321c21282b 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/CNNArchSymbolTableCreator.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/CNNArchSymbolTableCreator.java @@ -294,29 +294,37 @@ public class CNNArchSymbolTableCreator extends de.monticore.symboltable.CommonSy ArchTypeSymbol sym = new ArchTypeSymbol(); addToScopeAndLinkWithNode(sym, ast); } - +//NEW @Override public void endVisit(ASTArchType node) { ArchTypeSymbol sym = (ArchTypeSymbol) node.getSymbolOpt().get(); List astDimensions = node.getShape().getDimensionsList(); - + Integer size = new Integer(astDimensions.size()); + java.lang.System.out.println("Size of astDimension is: " + size.toString()); if (astDimensions.size() >= 1){ sym.setChannelIndex(0); } if (astDimensions.size() >= 2){ + java.lang.System.out.println("Setting Height Index in CNNArchSymbolTable"); sym.setHeightIndex(1); } if (astDimensions.size() >= 3){ sym.setWidthIndex(2); } - List dimensionList = new ArrayList<>(3); + if (astDimensions.size() >= 4){ + java.lang.System.out.println("Setting Depth Index to 1 in CNNArchSymbolTable"); + sym.setDepthIndex(1); + sym.setHeightIndex(2); + sym.setWidthIndex(3); + } + List dimensionList = new ArrayList<>(4); for (ASTArchSimpleExpression astExp : astDimensions){ dimensionList.add((ArchSimpleExpressionSymbol) astExp.getSymbolOpt().get()); } sym.setDimensionSymbols(dimensionList); sym.setDomain(node.getElementType()); } - +//END NEW @Override public void visit(ASTLayerDeclaration ast) { LayerDeclarationSymbol layerDeclaration = new LayerDeclarationSymbol(ast.getName()); diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/Constraints.java b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/Constraints.java index 41d487da41a3aade01264700431cafec437befb6..8cdf99d40d00347677fd612321f465cebbb420cc 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/Constraints.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/Constraints.java @@ -202,7 +202,7 @@ public enum Constraints { @Override protected String msgString() { return AllPredefinedLayers.PADDING_VALID + ", " - + AllPredefinedLayers.PADDING_SAME + " or " + + AllPredefinedLayers.PADDING_SAME + ", " + AllPredefinedLayers.PADDING_NO_LOSS; } }, @@ -220,10 +220,52 @@ public enum Constraints { } @Override protected String msgString() { - return AllPredefinedLayers.PADDING_VALID + "or " + return AllPredefinedLayers.PADDING_VALID + ", " + AllPredefinedLayers.PADDING_SAME; } }, + PADDING_TYPE3D { + @Override + public boolean isValid(ArchSimpleExpressionSymbol exp) { + Optional optString= exp.getStringValue(); + if (optString.isPresent()){ + if (optString.get().equals(AllPredefinedLayers.PADDING_VALID) + || optString.get().equals(AllPredefinedLayers.PADDING_VALID3D) + || optString.get().equals(AllPredefinedLayers.PADDING_SAME3D) + || optString.get().equals(AllPredefinedLayers.PADDING_SIMPLE3D)){ + return true; + } + } + return false || exp.isIntTuple().get(); + } + @Override + protected String msgString() { + return AllPredefinedLayers.PADDING_VALID3D + ", " + + AllPredefinedLayers.PADDING_SAME3D + ", " + + AllPredefinedLayers.PADDING_NO_LOSS + " or " + + AllPredefinedLayers.PADDING_SIMPLE3D; + } + }, + TRANSPADDING_TYPE3D { + @Override + public boolean isValid(ArchSimpleExpressionSymbol exp) { + Optional optString= exp.getStringValue(); + if (optString.isPresent()){ + if (optString.get().equals(AllPredefinedLayers.PADDING_VALID3D) + || optString.get().equals(AllPredefinedLayers.PADDING_SAME3D) + || optString.get().equals(AllPredefinedLayers.PADDING_SIMPLE3D)){ + return true; + } + } + return false || exp.isIntTuple().get(); + } + @Override + protected String msgString() { + return AllPredefinedLayers.PADDING_VALID3D + ", " + + AllPredefinedLayers.PADDING_SAME3D + " or " + + AllPredefinedLayers.PADDING_SIMPLE3D; + } + }, POOL_TYPE { @Override public boolean isValid(ArchSimpleExpressionSymbol exp) { diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/PredefinedLayerDeclaration.java b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/PredefinedLayerDeclaration.java index 355ad37ff1a0e738d7d56568c401806a36003482..cfede4ba8865433ac1c3472b00734294e06a15a3 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/PredefinedLayerDeclaration.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/_symboltable/PredefinedLayerDeclaration.java @@ -131,11 +131,55 @@ abstract public class PredefinedLayerDeclaration extends LayerDeclarationSymbol } } + protected void errorIfInputDepthIsInvalid(List inputTypes, LayerSymbol layer, int depth){ + for (ArchTypeSymbol inputType : inputTypes) { + if (inputType.getDepth() != depth){ + Log.error("0" + ErrorCodes.INVALID_ELEMENT_INPUT_SHAPE + " Invalid layer input. Input depth is " + + inputType.getDepth() + " but needs to be " + depth + ".", layer.getSourcePosition()); + } + } + } + + protected static void errorIfInputSmallerThanKernel3D(List inputTypes, LayerSymbol layer){ + if (!inputTypes.isEmpty()) { + int inputHeight = inputTypes.get(0).getHeight(); + int inputWidth = inputTypes.get(0).getWidth(); + int inputDepth = inputTypes.get(0).getDepth(); + Integer depthI = new Integer(inputTypes.get(0).getDepthIndex()); + + int kernelHeight = layer.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = layer.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = layer.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + if (kernelHeight > inputHeight || kernelWidth > inputWidth || kernelDepth > inputDepth) { + if (layer.getStringValue(AllPredefinedLayers.PADDING_NAME).equals(AllPredefinedLayers.PADDING_VALID3D)) { + Log.error("0" + ErrorCodes.INVALID_ELEMENT_INPUT_SHAPE + " Invalid layer input. " + + "The input resolution is smaller than the kernel and the padding mode is 'valid'." + + "This would result in an output resolution of 0x0." + , layer.getSourcePosition()); + } else { + Integer height = new Integer(kernelHeight); + Integer width = new Integer(kernelWidth); + Integer depth = new Integer(kernelDepth); + Integer iheight = new Integer(inputHeight); + Integer iwidth = new Integer(inputWidth); + Integer idepth = new Integer(inputDepth); + Integer channel = new Integer(inputTypes.get(0).getChannels()); + Log.warn("The input resolution is smaller than the kernel. " + " " + + "This results in an output resolution of 1x1. " + " " + + "If this warning appears multiple times, consider changing your architecture" + , layer.getSourcePosition()); + } + } + } + } + //check input for convolution and pooling protected static void errorIfInputSmallerThanKernel(List inputTypes, LayerSymbol layer) { if (!inputTypes.isEmpty()) { int inputHeight = inputTypes.get(0).getHeight(); int inputWidth = inputTypes.get(0).getWidth(); + int kernelHeight = layer.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); int kernelWidth = layer.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); @@ -146,39 +190,63 @@ abstract public class PredefinedLayerDeclaration extends LayerDeclarationSymbol "This would result in an output resolution of 0x0." , layer.getSourcePosition()); } else { - Log.warn("The input resolution is smaller than the kernel. " + + Integer height = new Integer(kernelHeight); + Integer width = new Integer(kernelWidth); + Integer iheight = new Integer(inputHeight); + Integer iwidth = new Integer(inputWidth); + Log.warn("The input resolution is smaller than the kernel. " + " " + "This results in an output resolution of 1x1. " + "If this warning appears multiple times, consider changing your architecture" , layer.getSourcePosition()); } - } + } } } - //output type function for convolution and pooling + //output type function for convolution and poolingee protected static List computeConvAndPoolOutputShape(ArchTypeSymbol inputType, LayerSymbol method, int channels) { - String borderModeSetting = method.getStringValue(AllPredefinedLayers.PADDING_NAME).get(); - if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME)) { - return computeOutputShapeWithSamePadding(inputType, method, channels); - } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID)) { - return computeOutputShapeWithValidPadding(inputType, method, channels); - } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_NO_LOSS)) { - return computeOutputShapeWithNoLossPadding(inputType, method, channels); + if (method.getIntTupleValue(AllPredefinedLayers.PADDING_NAME).isPresent()){ //If the Padding is given in Tuple + return computeOutputShapeWithTupelPadding3D(inputType, method, channels); } else { - throw new IllegalStateException("border_mode is " + borderModeSetting + ". This should never happen."); + String borderModeSetting = method.getStringValue(AllPredefinedLayers.PADDING_NAME).get(); + if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME)) { + return computeOutputShapeWithSamePadding(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID)) { + return computeOutputShapeWithValidPadding(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_NO_LOSS)) { + return computeOutputShapeWithNoLossPadding(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME3D)){ //Add 3D PADDING CASES + return computeOutputShapeWithSamePadding3D(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID3D)){ + return computeOutputShapeWithValidPadding3D (inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SIMPLE3D)){ + return computeOutputShapeWithSimplePadding3D (inputType, method, channels); + } else { + throw new IllegalStateException("border_mode is " + borderModeSetting + ". This should never happen."); + } } } //output type function for transposed convolution protected static List computeUpConvOutputShape(ArchTypeSymbol inputType, LayerSymbol method, int channels) { - String borderModeSetting = method.getStringValue(AllPredefinedLayers.TRANSPADDING_NAME).get(); - if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME)) { - return computeUpConvOutputShapeWithSamePadding(inputType, method, channels); - } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID)) { - return computeUpConvOutputShapeWithValidPadding(inputType, method, channels); + if (method.getIntTupleValue(AllPredefinedLayers.TRANSPADDING_NAME).isPresent()){ //If the Padding is given in Tuple + return computeUpOutputShapeWithTupelPadding3D(inputType, method, channels); } else { - throw new IllegalStateException("border_mode is " + borderModeSetting + ". This should never happen."); + String borderModeSetting = method.getStringValue(AllPredefinedLayers.TRANSPADDING_NAME).get(); + if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME)) { + return computeUpConvOutputShapeWithSamePadding(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID)) { + return computeUpConvOutputShapeWithValidPadding(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SAME3D)){ //Add 3D PADDING CASES + return computeUpConvOutputShapeWithSamePadding3D(inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_VALID3D)){ + return computeUpConvOutputShapeWithValidPadding3D (inputType, method, channels); + } else if (borderModeSetting.equals(AllPredefinedLayers.PADDING_SIMPLE3D)){ + return computeUpConvOutputShapeWithSimplePadding3D (inputType, method, channels); + } else { + throw new IllegalStateException("border_mode is " + borderModeSetting + ". This should never happen."); + } } } @@ -191,6 +259,259 @@ abstract public class PredefinedLayerDeclaration extends LayerDeclarationSymbol layer.setIntValue(AllPredefinedLayers.SIZE_NAME, outputChannels); } + //Same padding should result in the output shape having the same size as the input shape + private static List computeOutputShapeWithSamePadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth = (inputWidth + strideWidth - 1) / strideWidth; + int outputHeight = (inputHeight + strideHeight - 1) / strideHeight; + int outputDepth = (inputDepth + strideDepth - 1) / strideDepth; + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + //Padding of size (0,0,0) + private static List computeOutputShapeWithValidPadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels) { + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth; + int outputHeight; + int outputDepth; + if (inputWidth < kernelWidth || inputHeight < kernelHeight || inputDepth < kernelDepth) { + outputWidth = 0; + outputHeight = 0; + outputDepth = 0; + } else { + outputWidth = 1 + ((inputWidth - kernelWidth) / strideWidth); + outputHeight = 1 + ((inputHeight - kernelHeight) / strideHeight); + outputDepth = 1 + ((inputDepth - kernelDepth) / strideDepth); + } + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + //Padding of size (1,1,1) + private static List computeOutputShapeWithSimplePadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int pad = 1; + + int outputWidth; + int outputHeight; + int outputDepth; + + if (inputWidth + 2*pad < kernelWidth || inputHeight + 2*pad < kernelHeight || inputDepth + 2*pad < kernelDepth) { + outputWidth = 0; + outputHeight = 0; + outputDepth = 0; + } else { + outputWidth = 1 + ((inputWidth - kernelWidth + 2* pad) / strideWidth); + outputHeight = 1 + ((inputHeight - kernelHeight + 2* pad) / strideHeight); + outputDepth = 1 + ((inputDepth - kernelDepth + 2* pad) / strideDepth); + } + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + private static List computeOutputShapeWithTupelPadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int paddingHeight = method.getIntTupleValue(AllPredefinedLayers.PADDING_NAME).get().get(1); + int paddingWidth = method.getIntTupleValue(AllPredefinedLayers.PADDING_NAME).get().get(2); + int paddingDepth = method.getIntTupleValue(AllPredefinedLayers.PADDING_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth = 1 + ((inputWidth - kernelWidth + 2*paddingWidth) / strideWidth); + int outputHeight = 1 + ((inputHeight - kernelHeight + 2*paddingHeight) / strideHeight); + int outputDepth = 1 + ((inputDepth - kernelDepth + 2*paddingDepth) / strideDepth); + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + + private static List computeUpConvOutputShapeWithSamePadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth; + int outputHeight; + int outputDepth; + + outputWidth = strideWidth*inputWidth; + outputHeight = strideHeight*inputHeight; + outputDepth = strideDepth*inputDepth; + + //Integer oDepth = new Integer(outputDepth); + //System.out.println("In computeUpConvShape: " + iDepth.toString() + " " + stride.toString() + " " + oDepth.toString()); + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + private static List computeUpConvOutputShapeWithValidPadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth; + int outputHeight; + int outputDepth; + + //TEMPORARY + int pad = 0; + + outputWidth = (inputWidth - 1) * strideWidth + kernelWidth - 2*pad; + outputHeight = (inputHeight - 1) * strideHeight + kernelHeight - 2*pad; + outputDepth = (inputDepth - 1) * strideDepth + kernelDepth - 2*pad; + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + private static List computeUpConvOutputShapeWithSimplePadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth; + int outputHeight; + int outputDepth; + + int pad = 1; + + outputWidth = (inputWidth - 1) * strideWidth + kernelWidth - 2*pad; + outputHeight = (inputHeight - 1) * strideHeight + kernelHeight - 2*pad; + outputDepth = (inputDepth - 1) * strideDepth + kernelDepth - 2*pad; + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + + private static List computeUpOutputShapeWithTupelPadding3D(ArchTypeSymbol inputType, LayerSymbol method, int channels){ + int strideHeight = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(1); + int strideWidth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(2); + int strideDepth = method.getIntTupleValue(AllPredefinedLayers.STRIDE_NAME).get().get(0); + int kernelHeight = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(1); + int kernelWidth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(2); + int kernelDepth = method.getIntTupleValue(AllPredefinedLayers.KERNEL_NAME).get().get(0); + + int paddingHeight = method.getIntTupleValue(AllPredefinedLayers.TRANSPADDING_NAME).get().get(1); + int paddingWidth = method.getIntTupleValue(AllPredefinedLayers.TRANSPADDING_NAME).get().get(2); + int paddingDepth = method.getIntTupleValue(AllPredefinedLayers.TRANSPADDING_NAME).get().get(0); + + int inputHeight = inputType.getHeight(); + int inputWidth = inputType.getWidth(); + int inputDepth = inputType.getDepth(); + + int outputWidth = (inputWidth - 1) * strideWidth + kernelWidth - 2*paddingWidth; + int outputHeight = (inputHeight - 1) * strideHeight + kernelHeight - 2*paddingHeight; + int outputDepth = (inputDepth - 1) * strideDepth + kernelDepth - 2*paddingDepth; + + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(outputHeight) + .width(outputWidth) + .depth(outputDepth) + .channels(channels) + .elementType("-oo", "oo") + .build()); + } + //padding with border_mode=valid, no padding private static List computeOutputShapeWithValidPadding(ArchTypeSymbol inputType, LayerSymbol method, int channels) { diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/AllPredefinedLayers.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/AllPredefinedLayers.java index f86b62958042561cb51aeb5e3e4c13bfd372e77f..d670086c30317a166e742e69fdaf23bc1c78fc9e 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/AllPredefinedLayers.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/AllPredefinedLayers.java @@ -59,6 +59,10 @@ public class AllPredefinedLayers { public static final String RESHAPE_NAME = "Reshape"; public static final String DOT_PRODUCT_SELF_ATTENTION_NAME = "DotProductSelfAttention"; public static final String LOAD_NETWORK_NAME = "LoadNetwork"; + public static final String CUSTOM_LAYER = "CustomLayer"; + public static final String CONVOLUTION3D_NAME = "Convolution3D"; + public static final String UP_CONVOLUTION3D_NAME = "UpConvolution3D"; + public static final String AdaNet_Name = "AdaNet"; //AdaNet layer //replay layers @@ -151,6 +155,9 @@ public class AllPredefinedLayers { public static final String PADDING_VALID = "valid"; public static final String PADDING_SAME = "same"; public static final String PADDING_NO_LOSS = "no_loss"; + public static final String PADDING_VALID3D = "valid3d"; + public static final String PADDING_SAME3D = "same3d"; + public static final String PADDING_SIMPLE3D = "simple3d"; public static final String POOL_MAX = "max"; public static final String POOL_AVG = "avg"; public static final String RANDOM = "random"; @@ -206,6 +213,8 @@ public class AllPredefinedLayers { DotProductSelfAttention.create(), LargeMemory.create(), EpisodicMemory.create(), + Convolution3D.create(), + UpConvolution3D.create(), AdaNet.create()); } diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Concatenate.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Concatenate.java index 1e07d1330c8881c47376e420b1ea8c97813778c9..f80870ce3368f6ce27f7e5c802ea72573787a701 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Concatenate.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Concatenate.java @@ -29,6 +29,9 @@ public class Concatenate extends PredefinedLayerDeclaration { int channels = layer.getInputTypes().get(0).getChannels(); int height = layer.getInputTypes().get(0).getHeight(); int width = layer.getInputTypes().get(0).getWidth(); + if (inputTypes.get(0).getDepthIndex() > -1) { + int depth = layer.getInputTypes().get(0).getDepth(); + } int axis = layer.getIntValue(AllPredefinedLayers.AXIS_NAME).get(); @@ -50,13 +53,24 @@ public class Concatenate extends PredefinedLayerDeclaration { width += inputShape.getWidth(); } } - - return Collections.singletonList(new ArchTypeSymbol.Builder() - .channels(channels) - .height(height) - .width(width) - .elementType(range.get(0), range.get(1)) - .build()); + if (inputTypes.get(0).getDepthIndex() > -1) { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .depth(layer.getInputTypes().get(0).getDepth()) + .elementType(range.get(0), range.get(1)) + .build()); + } else { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(channels) + .height(height) + .width(width) + .elementType(range.get(0), range.get(1)) + .build()); + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java new file mode 100644 index 0000000000000000000000000000000000000000..b972080e306d37151b849e93903b5f29f108210c --- /dev/null +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java @@ -0,0 +1,71 @@ +/** + * + * (c) https://github.com/MontiCore/monticore + * + * The license generally applicable for this project + * can be found under https://github.com/MontiCore/monticore. + */ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.monticar.cnnarch.predefined; + +import de.monticore.lang.monticar.cnnarch._symboltable.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Convolution3D extends PredefinedLayerDeclaration { + + private Convolution3D() { + super(AllPredefinedLayers.CONVOLUTION3D_NAME); + } + + @Override + public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + // TODO check here + return computeConvAndPoolOutputShape(layer.getInputTypes().get(0), + layer, + layer.getIntValue(AllPredefinedLayers.CHANNELS_NAME).get()); + } + + @Override + public void checkInput(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + errorIfInputSizeIsNotOne(inputTypes, layer); + errorIfInputSmallerThanKernel3D(inputTypes, layer); + } + + public static Convolution3D create(){ + Convolution3D declaration = new Convolution3D(); + List parameters = new ArrayList<>(Arrays.asList( + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.KERNEL_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.CHANNELS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.STRIDE_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .defaultValue(Arrays.asList(1, 1, 1)) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.NOBIAS_NAME) + .constraints(Constraints.BOOLEAN) + .defaultValue(false) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.PADDING_NAME) + .constraints(Constraints.PADDING_TYPE3D) //3D Padding Type also allows Tupels + .defaultValue(AllPredefinedLayers.PADDING_SAME3D) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.GROUPS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .defaultValue(1) + .build())); + declaration.setParameters(parameters); + return declaration; + } +} diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java~HEAD b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java~HEAD new file mode 100644 index 0000000000000000000000000000000000000000..5a0dd73b0b7fee1e03bcb290c44662bc645fb1ba --- /dev/null +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Convolution3D.java~HEAD @@ -0,0 +1,71 @@ +/** + * + * (c) https://github.com/MontiCore/monticore + * + * The license generally applicable for this project + * can be found under https://github.com/MontiCore/monticore. + */ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.monticar.cnnarch.predefined; + +import de.monticore.lang.monticar.cnnarch._symboltable.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Convolution3D extends PredefinedLayerDeclaration { + + private Convolution3D() { + super(AllPredefinedLayers.CONVOLUTION3D_NAME); + } + + @Override + public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + // TODO check here + return computeConvAndPoolOutputShape(layer.getInputTypes().get(0), + layer, + layer.getIntValue(AllPredefinedLayers.CHANNELS_NAME).get()); + } + + @Override + public void checkInput(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + errorIfInputSizeIsNotOne(inputTypes, layer); + errorIfInputSmallerThanKernel3D(inputTypes, layer); + } + + public static Convolution3D create(){ + Convolution3D declaration = new Convolution3D(); + List parameters = new ArrayList<>(Arrays.asList( + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.KERNEL_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.CHANNELS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.STRIDE_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .defaultValue(Arrays.asList(1, 1, 1)) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.NOBIAS_NAME) + .constraints(Constraints.BOOLEAN) + .defaultValue(false) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.PADDING_NAME) + .constraints(Constraints.PADDING_TYPE) + .defaultValue(AllPredefinedLayers.PADDING_SAME3D) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.GROUPS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .defaultValue(1) + .build())); + declaration.setParameters(parameters); + return declaration; + } +} diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Flatten.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Flatten.java index b0460feb19bd781530f3177116a5c80c7120b0ff..bfe744c220c7c21fb75ce7f0f322e04fbc839442 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Flatten.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Flatten.java @@ -25,14 +25,27 @@ public class Flatten extends PredefinedLayerDeclaration { @Override public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { - return Collections.singletonList(new ArchTypeSymbol.Builder() - .height(1) - .width(1) - .channels(layer.getInputTypes().get(0).getHeight() - * layer.getInputTypes().get(0).getWidth() - * layer.getInputTypes().get(0).getChannels()) - .elementType(layer.getInputTypes().get(0).getDomain()) - .build()); + if (inputTypes.get(0).getDepthIndex() == -1){ + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(1) + .width(1) + .channels(layer.getInputTypes().get(0).getHeight() + * layer.getInputTypes().get(0).getWidth() + * layer.getInputTypes().get(0).getChannels()) + .elementType(layer.getInputTypes().get(0).getDomain()) + .build()); + } else { + return Collections.singletonList(new ArchTypeSymbol.Builder() + .height(1) + .width(1) + .depth(1) + .channels(layer.getInputTypes().get(0).getHeight() + * layer.getInputTypes().get(0).getWidth() + * layer.getInputTypes().get(0).getChannels() + * layer.getInputTypes().get(0).getDepth()) + .elementType(layer.getInputTypes().get(0).getDomain()) + .build()); + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/FullyConnected.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/FullyConnected.java index 320dbdace83c9764d809d05550aa8a36eb9a1a27..bd3e44401653c8fa34c003f5f0da43880127a868 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/FullyConnected.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/FullyConnected.java @@ -27,21 +27,41 @@ public class FullyConnected extends PredefinedLayerDeclaration { int units = layer.getIntValue(AllPredefinedLayers.UNITS_NAME).get(); if (flatten) { - return Collections.singletonList(new ArchTypeSymbol.Builder() - .channels(units) - .height(1) - .width(1) - .elementType("-oo", "oo") - .build()); + if (inputTypes.get(0).getDepthIndex() == -1){ + return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(units) + .height(1) + .width(1) + .elementType("-oo", "oo") + .build()); + } else { + + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(units) + .height(1) + .width(1) + .depth(1) + .elementType("0", "oo") + .build()); + } } else { ArchTypeSymbol inputType = layer.getInputTypes().get(0); + if (inputTypes.get(0).getDepthIndex() == -1){ //2D Cases + if (inputType.getWidth() == 1) { + if (inputType.getHeight() == 1) { + return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(units) + .height(1) + .width(1) + .elementType("-oo", "oo") + .build()); + } - if (inputType.getWidth() == 1) { - if (inputType.getHeight() == 1) { return Collections.singletonList(new ArchTypeSymbol.Builder() - .channels(units) - .height(1) + .channels(inputType.getChannels()) + .height(units) .width(1) .elementType("-oo", "oo") .build()); @@ -49,19 +69,44 @@ public class FullyConnected extends PredefinedLayerDeclaration { return Collections.singletonList(new ArchTypeSymbol.Builder() .channels(inputType.getChannels()) - .height(units) - .width(1) + .height(inputType.getHeight()) + .width(units) .elementType("-oo", "oo") .build()); - } - - return Collections.singletonList(new ArchTypeSymbol.Builder() - .channels(inputType.getChannels()) - .height(inputType.getHeight()) - .width(units) - .elementType("-oo", "oo") - .build()); - } + } else { //3D Cases + if (inputType.getWidth() == 1) { + if (inputType.getHeight() == 1) { + if (inputType.getDepth() == 1){ + return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(units) + .height(1) + .width(1) + .depth(1) + .elementType("-oo", "oo") + .build()); + } return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(inputType.getChannels()) + .height(1) + .width(1) + .depth(units) + .elementType("-oo", "oo") + .build()); + } return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(inputType.getChannels()) + .height(units) + .width(1) + .depth(inputType.getDepth()) + .elementType("-oo", "oo") + .build()); + } return Collections.singletonList(new ArchTypeSymbol.Builder() + .channels(inputType.getChannels()) + .height(inputType.getHeight()) + .width(units) + .depth(inputType.getDepth()) + .elementType("-oo", "oo") + .build()); + } + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/LeakyRelu.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/LeakyRelu.java index abd1d0c22522ca3973617cfc7adfcfdd97a7b95e..4c730b98e0641d2b1d6a07ec500e29714ddde49c 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/LeakyRelu.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/LeakyRelu.java @@ -22,13 +22,25 @@ public class LeakyRelu extends PredefinedLayerDeclaration { @Override public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { - return Collections.singletonList( - new ArchTypeSymbol.Builder() - .channels(layer.getInputTypes().get(0).getChannels()) - .height(layer.getInputTypes().get(0).getHeight()) - .width(layer.getInputTypes().get(0).getWidth()) - .elementType("0", "oo") - .build()); + if (inputTypes.get(0).getDepthIndex() == -1) { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .elementType("0", "oo") + .build()); + } + else { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .depth(layer.getInputTypes().get(0).getDepth()) + .elementType("0", "oo") + .build()); + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Relu.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Relu.java index 321c8868ee359275425315d7fbc72ff67f2e8bca..2954e0489a3d6badaae02307e512f50a6b2e5d6f 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Relu.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Relu.java @@ -25,13 +25,25 @@ public class Relu extends PredefinedLayerDeclaration { @Override public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { - return Collections.singletonList( - new ArchTypeSymbol.Builder() - .channels(layer.getInputTypes().get(0).getChannels()) - .height(layer.getInputTypes().get(0).getHeight()) - .width(layer.getInputTypes().get(0).getWidth()) - .elementType("0", "oo") - .build()); + if (inputTypes.get(0).getDepthIndex() == -1) { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .elementType("0", "oo") + .build()); + } + else { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .depth(layer.getInputTypes().get(0).getDepth()) + .elementType("0", "oo") + .build()); + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Reshape.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Reshape.java index 83eea2d4a0afde6d86c4597ff6ccc27c8172d00d..8d73406bf5d645209becfe8be0047711d0f3d9da 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Reshape.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Reshape.java @@ -30,24 +30,31 @@ public class Reshape extends PredefinedLayerDeclaration { int channels = -1; int height = -1; int width = -1; + int depth = -1; + + if (shape.size() >= 4) { + depth = shape.get(1); + height = shape.get(2); + width = shape.get(3); + channels = shape.get(0); + } else { + + if (shape.size() >= 3) { + width = shape.get(2); + } + if (shape.size() >= 2) { + height = shape.get(1); + } - if (shape.size() >= 3) { - width = shape.get(2); - } - - if (shape.size() >= 2) { - height = shape.get(1); - } - - if (shape.size() >= 1) { - channels = shape.get(0); - } else { - Log.error("0" + ErrorCodes.ILLEGAL_PARAMETER_VALUE + "\"Shape\" argument needs to contain at least one entry" - , layer.getSourcePosition()); + if (shape.size() >= 1) { + channels = shape.get(0); + } else { + Log.error("0" + ErrorCodes.ILLEGAL_PARAMETER_VALUE + "\"Shape\" argument needs to contain at least one entry" + , layer.getSourcePosition()); + } } - - int totalSize = layer.getInputTypes().get(0).getChannels() * layer.getInputTypes().get(0).getHeight() * layer.getInputTypes().get(0).getWidth(); + int totalSize = layer.getInputTypes().get(0).getChannels() * layer.getInputTypes().get(0).getHeight() * layer.getInputTypes().get(0).getWidth() * layer.getInputTypes().get(0).getDepth(); int newTotalSize = shape.stream().reduce(1, (x, y) -> x * y); if (totalSize != newTotalSize && newTotalSize != 0) { @@ -56,8 +63,16 @@ public class Reshape extends PredefinedLayerDeclaration { } if (newTotalSize != 0) { - - if (width != -1) { + if (depth != -1) { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(channels) + .height(height) + .width(width) + .depth(depth) + .elementType(layer.getInputTypes().get(0).getDomain()) + .build()); + } else if (width != -1) { return Collections.singletonList( new ArchTypeSymbol.Builder() .channels(channels) @@ -98,4 +113,4 @@ public class Reshape extends PredefinedLayerDeclaration { declaration.setParameters(parameters); return declaration; } -} \ No newline at end of file +} diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Sigmoid.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Sigmoid.java index 8bd782ebbeebb0300d4ab97c284592da5169bafe..8b087feda71eda49cc660d9f375122d408b97a55 100644 --- a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Sigmoid.java +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/Sigmoid.java @@ -25,13 +25,25 @@ public class Sigmoid extends PredefinedLayerDeclaration { @Override public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { - return Collections.singletonList( - new ArchTypeSymbol.Builder() - .channels(layer.getInputTypes().get(0).getChannels()) - .height(layer.getInputTypes().get(0).getHeight()) - .width(layer.getInputTypes().get(0).getWidth()) - .elementType("0", "1") - .build()); + if (inputTypes.get(0).getDepthIndex() > -1) { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .depth(layer.getInputTypes().get(0).getDepth()) + .elementType("0", "1") + .build()); + } + else { + return Collections.singletonList( + new ArchTypeSymbol.Builder() + .channels(layer.getInputTypes().get(0).getChannels()) + .height(layer.getInputTypes().get(0).getHeight()) + .width(layer.getInputTypes().get(0).getWidth()) + .elementType("0", "1") + .build()); + } } @Override diff --git a/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/UpConvolution3D.java b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/UpConvolution3D.java new file mode 100644 index 0000000000000000000000000000000000000000..e44a631fa70b5154b20a3107a1e8afb8b58f119e --- /dev/null +++ b/src/main/java/de/monticore/lang/monticar/cnnarch/predefined/UpConvolution3D.java @@ -0,0 +1,68 @@ +/** + * + * (c) https://github.com/MontiCore/monticore + * + * The license generally applicable for this project + * can be found under https://github.com/MontiCore/monticore. + */ +package de.monticore.lang.monticar.cnnarch.predefined; + +import de.monticore.lang.monticar.cnnarch._symboltable.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class UpConvolution3D extends PredefinedLayerDeclaration { + + private UpConvolution3D() { + super(AllPredefinedLayers.UP_CONVOLUTION3D_NAME); + } + + @Override + public List computeOutputTypes(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + return computeUpConvOutputShape(layer.getInputTypes().get(0), + layer, + layer.getIntValue(AllPredefinedLayers.CHANNELS_NAME).get()); + } + + @Override + public void checkInput(List inputTypes, LayerSymbol layer, VariableSymbol.Member member) { + errorIfInputSizeIsNotOne(inputTypes, layer); + } + + public static UpConvolution3D create(){ + UpConvolution3D declaration = new UpConvolution3D(); + List parameters = new ArrayList<>(Arrays.asList( + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.KERNEL_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.CHANNELS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.STRIDE_NAME) + .constraints(Constraints.INTEGER_TUPLE, Constraints.POSITIVE) + .defaultValue(Arrays.asList(1, 1, 1)) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.NOBIAS_NAME) + .constraints(Constraints.BOOLEAN) + .defaultValue(false) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.TRANSPADDING_NAME) + .constraints(Constraints.TRANSPADDING_TYPE3D) + .defaultValue(AllPredefinedLayers.PADDING_SAME3D) + .build(), + new ParameterSymbol.Builder() + .name(AllPredefinedLayers.GROUPS_NAME) + .constraints(Constraints.INTEGER, Constraints.POSITIVE) + .defaultValue(1) + .build())); + declaration.setParameters(parameters); + return declaration; + } +} diff --git a/src/test/java/de/monticore/lang/monticar/cnnarch/cocos/AllCoCoTest.java b/src/test/java/de/monticore/lang/monticar/cnnarch/cocos/AllCoCoTest.java index 4f107d30d05895487083f871006417819eccc2a6..6a771766db5c7fe31631d3ec3b6b29d6461a09f4 100644 --- a/src/test/java/de/monticore/lang/monticar/cnnarch/cocos/AllCoCoTest.java +++ b/src/test/java/de/monticore/lang/monticar/cnnarch/cocos/AllCoCoTest.java @@ -58,6 +58,7 @@ public class AllCoCoTest extends AbstractCoCoTest { checkValid("valid_tests", "RNNtest"); checkValid("valid_tests", "EpisodicMemoryNetwork"); checkValid("valid_tests", "LargeMemoryNetwork"); + checkValid("valid_tests", "Small3DGan"); } @Test diff --git a/src/test/resources/valid_tests/Small3DGan.cnna b/src/test/resources/valid_tests/Small3DGan.cnna new file mode 100644 index 0000000000000000000000000000000000000000..033d1c55bc887674a4460afe6454d36083be1ad0 --- /dev/null +++ b/src/test/resources/valid_tests/Small3DGan.cnna @@ -0,0 +1,25 @@ +/* (c) https://github.com/MontiCore/monticore */ +architecture Small3DGan{ + def input Q(0:1)^{200} data + def output Q(0:1)^{1} discriminated + + data -> + Reshape (shape=(200,1,1,1)) -> + UpConvolution3D(kernel=(4,4,4), channels=64 , stride = (2,2,2), padding="simple3d") -> + BatchNorm() -> + Relu() -> + UpConvolution3D(kernel=(4,4,4), channels=32 , stride = (2,2,2), padding="simple3d") -> + BatchNorm() -> + Relu() -> + UpConvolution3D(kernel=(4,4,4), channels=1 , stride = (2,2,2), padding="simple3d") -> + Sigmoid() -> + Convolution3D(kernel=(4,4,4), channels=32, stride=(2,2,2), padding=(1,1,1)) -> + BatchNorm() -> + LeakyRelu(alpha=0.2) -> + Convolution3D(kernel=(4,4,4), channels=64, stride=(2,2,2), padding=(1,1,1)) -> + BatchNorm() -> + LeakyRelu(alpha=0.2) -> + Convolution3D(kernel=(4,4,4), channels=1, stride=(2,2,2), padding="simple3d") -> + Sigmoid() -> + discriminated; +}