Get layer output type.

@param inputType Array of InputTypes
@return output type as InputType
@throws InvalidKerasConfigurationException Invalid Keras config
544124
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Convolution layer accepts only one input (received " + inputType.length + ")");
        return this.getDeconvolution2DLayer().getOutputType(-1, inputType[0]);
    }
83612
public static int[] getInputShapeFromConfig(Map<String, Object> layerConfig,
                                                KerasLayerConfiguration conf)
            throws InvalidKerasConfigurationException {
        // TODO: validate this. shouldn't we also have INPUT_SHAPE checked?
        Map<String, Object> innerConfig = KerasLayerUtils.getInnerLayerConfigFromConfig(layerConfig, conf);
        if (!innerConfig.containsKey(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE()))
            return null;
        List<Integer> batchInputShape = (List<Integer>) innerConfig.get(conf.getLAYER_FIELD_BATCH_INPUT_SHAPE());
        int[] inputShape = new int[batchInputShape.size() - 1];
        for (int i = 1; i < batchInputShape.size(); i++) {
            inputShape[i - 1] = batchInputShape.get(i) != null ? batchInputShape.get(i) : 0;
        }
        return inputShape;
    }
541164
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras depth-wise convolution 2D layer accepts only one input (received " + inputType.length + ")");
        return this.getDepthwiseConvolution2DLayer().getOutputType(-1, inputType[0]);
    }
1129136
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Convolution layer accepts only one input (received " + inputType.length + ")");
        InputType.InputTypeRecurrent rnnType = (InputType.InputTypeRecurrent) inputType[0];

        // Override input/output shape and input channels dynamically. This works since getOutputType will always
        // be called when initializing the model.
        ((LocallyConnected1D) this.layer).setInputSize((int) rnnType.getTimeSeriesLength());
        ((LocallyConnected1D) this.layer).setNIn(rnnType.getSize());
        ((LocallyConnected1D) this.layer).computeOutputSize();

        InputPreProcessor preprocessor = getInputPreprocessor(inputType[0]);
        if (preprocessor != null) {
            return this.getLocallyConnected1DLayer().getOutputType(-1, preprocessor.getOutputType(inputType[0]));
        }
        return this.getLocallyConnected1DLayer().getOutputType(-1, inputType[0]);
    }
917064
static <Input extends ImageBase<Input>>
	ImageGradient<Input,GrayF32> createGradient( ImageType<Input> imageType ) {
		ImageGradient<Input,GrayF32> gradient;
		ImageType<GrayF32> typeF32 = ImageType.single(GrayF32.class);

		if( imageType.getDataType() != ImageDataType.F32 )
			throw new IllegalArgumentException("Input image type must be F32");

		if( imageType.getFamily() == ImageType.Family.GRAY) {
			gradient = FactoryDerivative.gradient(DerivativeType.THREE,imageType, typeF32);
		} else if( imageType.getFamily() == ImageType.Family.PLANAR ) {
			ImageType<Planar<GrayF32>> typePF32 = ImageType.pl(imageType.getNumBands(),GrayF32.class);
			ImageGradient<Planar<GrayF32>,Planar<GrayF32>> gradientMB =
					FactoryDerivative.gradient(DerivativeType.THREE,typePF32, typePF32);
			gradient = (ImageGradient)FactoryDerivative.gradientReduce(gradientMB, DerivativeReduceType.MAX_F, GrayF32.class);
		} else {
			throw new IllegalArgumentException("Unsupported image type "+imageType);
		}

		return gradient;
	}
397392
@Override
    public InputType getOutputType(InputType... inputType)
            throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
        if (inputType.length > 0)
            log.warn("Keras Input layer does not accept inputs (received " + inputType.length + "). Ignoring.");
        InputType myInputType;
        switch (this.inputShape.length) {
            case 1:
                myInputType = new InputType.InputTypeFeedForward(this.inputShape[0]);
                break;
            case 2:
                myInputType = new InputType.InputTypeRecurrent(this.inputShape[1], this.inputShape[0]);
                break;
            case 3:
                switch (this.dimOrder) {
                    case TENSORFLOW:
                        /* TensorFlow convolutional input: # rows, # cols, # channels */
                        myInputType = new InputType.InputTypeConvolutional(this.inputShape[0], this.inputShape[1],
                                this.inputShape[2]);
                        break;
                    case THEANO:
                        /* Theano convolutional input:     # channels, # rows, # cols */
                        myInputType = new InputType.InputTypeConvolutional(this.inputShape[1], this.inputShape[2],
                                this.inputShape[0]);
                        break;
                    default:
                        this.dimOrder = DimOrder.THEANO;
                        myInputType = new InputType.InputTypeConvolutional(this.inputShape[1], this.inputShape[2],
                                this.inputShape[0]);
                        log.warn("Couldn't determine dim ordering / data format from model file. Older Keras " +
                                "versions may come without specified backend, in which case we assume the model was " +
                                "built with theano." );
                }
                break;
            case 4:
                switch (this.dimOrder) {
                    case TENSORFLOW:
                        myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NDHWC,
                                this.inputShape[0], this.inputShape[1],
                                this.inputShape[2],this.inputShape[3]);
                        break;
                    case THEANO:
                        myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NCDHW,
                                this.inputShape[3], this.inputShape[0],
                                this.inputShape[1],this.inputShape[2]);
                        break;
                    default:
                        this.dimOrder = DimOrder.THEANO;
                        myInputType = new InputType.InputTypeConvolutional3D(Convolution3D.DataFormat.NCDHW,
                                this.inputShape[3], this.inputShape[0],
                                this.inputShape[1],this.inputShape[2]);
                        log.warn("Couldn't determine dim ordering / data format from model file. Older Keras " +
                                "versions may come without specified backend, in which case we assume the model was " +
                                "built with theano." );
                }
                break;
            default:
                throw new UnsupportedKerasConfigurationException(
                        "Inputs with " + this.inputShape.length + " dimensions not supported");
        }
        return myInputType;
    }
277885
public static <T extends ImageGray<T>>
	InputToBinary<T> threshold( ConfigThreshold config, Class<T> inputType) {

		switch( config.type ) {
			case FIXED:
				return globalFixed(config.fixedThreshold, config.down, inputType);

			case GLOBAL_OTSU:
				return globalOtsu(config.minPixelValue, config.maxPixelValue, config.scale, config.down, inputType);

			case GLOBAL_ENTROPY:
				return globalEntropy(config.minPixelValue, config.maxPixelValue, config.scale, config.down, inputType);

			case GLOBAL_LI:
				return globalLi(config.minPixelValue, config.maxPixelValue, config.scale, config.down, inputType);

			case GLOBAL_HUANG:
				return globalHuang(config.minPixelValue, config.maxPixelValue, config.scale, config.down, inputType);

			case LOCAL_GAUSSIAN:
				return localGaussian(config.width, config.scale, config.down, inputType);

			case LOCAL_SAVOLA:
				return localSauvola(config.width, config.down, config.savolaK, inputType);

			case LOCAL_NICK:
				return localNick(config.width, config.down, config.nickK, inputType);

			case LOCAL_MEAN:
				return localMean(config.width, config.scale, config.down, inputType);

			case LOCAL_OTSU: {
				ConfigThresholdLocalOtsu c = (ConfigThresholdLocalOtsu) config;
				return localOtsu(config.width, config.scale, config.down, c.useOtsu2, c.tuning, inputType);
			}

			case BLOCK_MIN_MAX: {
				ConfigThresholdBlockMinMax c = (ConfigThresholdBlockMinMax) config;
				return blockMinMax(c.width, c.scale , c.down, c.thresholdFromLocalBlocks, c.minimumSpread,
						inputType);
			}

			case BLOCK_MEAN:
				return blockMean(config.width, config.scale , config.down,
						config.thresholdFromLocalBlocks, inputType);

			case BLOCK_OTSU: {
				ConfigThresholdLocalOtsu c = (ConfigThresholdLocalOtsu) config;
				return blockOtsu(c.width, c.scale, c.down, c.thresholdFromLocalBlocks, c.useOtsu2, c.tuning,
						inputType);
			}

		}
		throw new IllegalArgumentException("Unknown type "+config.type);
	}
525969
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Upsampling 3D layer accepts only one input (received " + inputType.length + ")");
        return this.getUpsampling3DLayer().getOutputType(-1, inputType[0]);
    }
95090
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Cropping 3D layer accepts only one input (received " + inputType.length + ")");
        return this.getCropping3DLayer().getOutputType(-1, inputType[0]);
    }
584170
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException,
    UnsupportedKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Loss layer accepts only one input (received " + inputType.length + ")");
        return this.getLossLayer(inputType[0]).getOutputType(-1, inputType[0]);
    }
773464
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Subsampling/Pooling 3D layer accepts only one input (received " + inputType.length + ")");
        return this.getSubsampling3DLayer().getOutputType(-1, inputType[0]);
    }
472877
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras Cropping layer accepts only one input (received " + inputType.length + ")");
        return this.getCropping1DLayer().getOutputType(-1, inputType[0]);
    }
251577
public Class<?> type() {
        Type type = Types.getBaseClass(getClass(), ConsoleAnnotatorFactory.class);
        if (type instanceof ParameterizedType)
            return Types.erasure(Types.getTypeArgument(type,0));
        else
            return Object.class;
    }
168682
public InputPreProcessor getInputPreprocessor(InputType... inputType) throws InvalidKerasConfigurationException {
        InputPreProcessor preprocessor = null;
        if (this.layer != null) {
            if (inputType.length > 1)
                throw new InvalidKerasConfigurationException(
                        "Keras layer of type \"" + this.className + "\" accepts only one input");
            preprocessor = this.layer.getPreProcessorForInputType(inputType[0]);
        }
        return preprocessor;
    }
88359
@Override
    public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                            "Keras Dropout layer accepts only one input (received " + inputType.length + ")");
        return this.getDropoutLayer().getOutputType(-1, inputType[0]);
    }
1137394
public InputType getOutputType(InputType... inputType) throws InvalidKerasConfigurationException {
        if (inputType.length > 1)
            throw new InvalidKerasConfigurationException(
                    "Keras PReLU layer accepts only one input (received " + inputType.length + ")");
        InputType inType = inputType[0];

        // Dynamically infer input shape of PReLU layer from input type
        PReLULayer shapedLayer = (PReLULayer) this.layer;
        shapedLayer.setInputShape(inType.getShape());
        this.layer = shapedLayer;

        return this.getPReLULayer().getOutputType(-1, inputType[0]);
    }
883691
public MultiLayerConfiguration getMultiLayerConfiguration()
            throws InvalidKerasConfigurationException, UnsupportedKerasConfigurationException {
        if (!this.className.equals(config.getFieldClassNameSequential()))
            throw new InvalidKerasConfigurationException(
                    "Keras model class name " + this.className + " incompatible with MultiLayerNetwork");
        if (this.inputLayerNames.size() != 1)
            throw new InvalidKerasConfigurationException(
                    "MultiLayerNetwork expects only 1 input (found " + this.inputLayerNames.size() + ")");
        if (this.outputLayerNames.size() != 1)
            throw new InvalidKerasConfigurationException(
                    "MultiLayerNetwork expects only 1 output (found " + this.outputLayerNames.size() + ")");

        NeuralNetConfiguration.Builder modelBuilder = new NeuralNetConfiguration.Builder();

        if (optimizer != null) {
            modelBuilder.updater(optimizer);
        }

        NeuralNetConfiguration.ListBuilder listBuilder = modelBuilder.list();

        /* Add layers one at a time. */
        KerasLayer prevLayer = null;
        int layerIndex = 0;
        for (KerasLayer layer : this.layersOrdered) {
            if (layer.isLayer()) {
                int nbInbound = layer.getInboundLayerNames().size();
                if (nbInbound != 1)
                    throw new InvalidKerasConfigurationException(
                            "Layers in MultiLayerConfiguration must have exactly one inbound layer (found "
                                    + nbInbound + " for layer " + layer.getLayerName() + ")");
                if (prevLayer != null) {
                    InputType[] inputTypes = new InputType[1];
                    InputPreProcessor preprocessor;
                    if (prevLayer.isInputPreProcessor()) {
                        inputTypes[0] = this.outputTypes.get(prevLayer.getInboundLayerNames().get(0));
                        preprocessor = prevLayer.getInputPreprocessor(inputTypes);
                    } else {
                        inputTypes[0] = this.outputTypes.get(prevLayer.getLayerName());
                        preprocessor = layer.getInputPreprocessor(inputTypes);
                    }
                    if (preprocessor != null)
                        listBuilder.inputPreProcessor(layerIndex, preprocessor);
                }
                listBuilder.layer(layerIndex++, layer.getLayer());
            } else if (layer.getVertex() != null)
                throw new InvalidKerasConfigurationException("Cannot add vertex to MultiLayerConfiguration (class name "
                        + layer.getClassName() + ", layer name " + layer.getLayerName() + ")");
            prevLayer = layer;
        }

        InputType inputType = this.layersOrdered.get(0).getOutputType();
        if (inputType != null)
            listBuilder.setInputType(inputType);

        /* Whether to use standard backprop (or BPTT) or truncated BPTT. */
        if (this.useTruncatedBPTT && this.truncatedBPTT > 0)
            listBuilder.backpropType(BackpropType.TruncatedBPTT).tBPTTForwardLength(truncatedBPTT)
                    .tBPTTBackwardLength(truncatedBPTT);
        else
            listBuilder.backpropType(BackpropType.Standard);
        return listBuilder.build();
    }