CNN Input Shape

I am having difficulty when it comes to loading a model, and then finding the required input shape for it.

I can create, train and infer from a CNN model whenI know what the input shape is by using this line.

imageNative = imageNative.reshape(1, modelChannels, modelHeight, modelWidth);

But this is because I know what the input shape is beforehand. However, I am writing a GUI that allows you to select a model and it will infer from it and show the output. The models it will load will have different input shapes, and I don’t want the user to have to know and type in the input shape for the program to know the expected dimensions. So after loading a model

ComputationGraph m = ModelSerializer.restoreComputationGraph(modelFile);

How do I determine the input shape? When I created the model I specified:

graph.addInputs("input").setInputTypes(InputType.convolutional(inputShape[2], inputShape[1], inputShape[0]));

But I can’t find the similar get commands. Was hoping to find a:

graph.getInputTypes().

and then if the input type matched convolutional, to be able to call, getShape();

Also, am I thinking about this wrong? I have seen posts where people talk about CNNs should be able to work on any size image without needing to specify shape, providing it fits into memory. Is this true? If so why do I get errors if my input shapes don’t match

@bugzyUK JFYI There are 2 apis ComputationGraph and MultiLayerNetwork.
I guess you are mainly using computation graph? Mainly asking in case the conversation goes further on something that could work for you. Below I offer an alternative:

Unlike keras there isn’t an input “layer” I’d be happy to help answer if you could be more specific though. Usually the user should know that already. Is your GUI using pretrained models? If so maybe name them?
You’d have to do some sort of resource management anyways. I would recommend a config file that gets loaded (allows workarounds) + named models as an alternative.

@agibsonccc Thank you for your response.

So my program is intended to be used by users who don’t write code. Here is a snippet.

All they should have to do is select the model from the load Model dropdown. That dropdown is populated from a models folder in the root of the program directory, and then this feeds into an inference node which should spit out the predictions.

These models are built and trained in the program

This all currently works fine, except for I have hard coded in the code the model input width, hight and channels.

public static ImgPlus[] inferImg(ComputationGraph model, ImgPlus image) throws IOException {
                
        log.info("Call to infer image" + image.getName());
		
		ImagePlus imp = ImageJFunctions.wrap(image, image.getName());
		
		System.out.println("wrapping Image");

		int imageWidth = (int) image.dimension(0);
		int imageHeight = (int) image.dimension(1);
		
		int modelWidth = 512;
		int modelHeight = 512;
		long modelChannels = 1;
		
		int classes = 3;

		if(modelWidth >= imageWidth && modelHeight >= imageHeight) {
			
			System.out.println("Standard Inference");
		
			NativeImageLoader loader = new NativeImageLoader(modelHeight, modelWidth, modelChannels);
			ImageType imgType = new ImageType();

			BufferedImage bufferedBGR = imgType.getBGRBufferedImage(imp.getProcessor().getBufferedImage());

			INDArray imageNative = loader.asMatrix(bufferedBGR);
			
			System.out.println("Loading Image");
			
			imageNative = imageNative.reshape(1, modelChannels, modelHeight, modelWidth);
			imageNative = imageNative.divi(255f);
			System.out.println("About to call Model Output.... ");
			try {
				INDArray[] output = model.output(imageNative);
			}catch (Exception ex) {
				ex.printStackTrace();
			}
			INDArray[] output = model.output(imageNative);
			System.out.println("Getting Model Output.... ");
			ImagePlus imp2 = IJ.createImage(image.getName(), "32-bit", modelWidth, modelHeight, classes,1,1);
			
			for (INDArray out : output) {
				
				out = out.reshape(classes,modelHeight, modelWidth);
				
				for(int c = 0; c < classes; c++) {
					ImageProcessor ip = imp2.getStack().getProcessor(c+1);
					
					for (int i = 0; i < modelWidth; i++) {
						for (int j = 0; j < modelHeight; j++) {						
							float f = out.getFloat(new int[] {c, i, j });
							ip.putPixelValue(j, i, f*255);
						}
					}

				}
				
			
				Img probImg =  ImageJFunctions.wrap(imp2);
				
				AxisType[] axisTypes = new AxisType[] {Axes.X, Axes.Y, Axes.CHANNEL};
				
				ImgPlus probabilityImgPlus = new ImgPlus(probImg, image.getName(), axisTypes);
				System.out.println("About to return images");
				return new ImgPlus[] {probabilityImgPlus};
			}
		}else{
              <Code here just handles breaking the input image up into chunks to process and stich back together.
        }
}

At the moment I am just typing these modelWidth, modelHeight, modelChannels in when in debug mode. I was hoping there was a way of gettting this from the ComputationGraph object, so i didn’t need to pass it in during the method call. The users of this program might not know stuff about the model, just that they have to pick a model for “Organoids” or “Phase Segmentation”. The builder part of the program I am also hoping will allow non-coding users to build up new models by dragging in layers, so the range of models this should be able to infer from would be quite large, and not known at compile time.

It seems like my config file per model should still stand. Especially when you have a dropdown. The user wouldn’t have to know how to code if you had a config file that stored these values for each input.

Since DL4J’s older api doesn’t really have that concept (and we expected users to have this information anyways in order to feed data to models)

it’d be more straightforward to just trigger an automatic load of those values using the GUI dropdown.