title: Keras categorical model
body: <p>I'm trying to create a Keras deep learning algorithm to identify coniferous and leafed trees from a false-colour orthophoto. I have extracted around 4 500 training/validation images which are considered to be correct, such as <a href="https://i.stack.imgur.com/6Xiph.jpg" rel="nofollow noreferrer">here</a> and <a href="https://i.stack.imgur.com/yZtSS.jpg" rel="nofollow noreferrer">here</a>. The pixel size in real-world is 0,5 meters so these are not really high-res images. All images are fixed-size 31x31 px. The following model is a product of googling, especially Keras' own documentation site.</p>
  
  <pre><code>from keras.preprocessing.image import ImageDataGenerator
  from keras.models import Sequential
  from keras.layers import Conv2D, MaxPooling2D
  from keras.layers import Activation, Dropout, Flatten, Dense
  from keras import backend as K
  
  # dimensions of our images.
  img_width, img_height = 30, 30
  
  train_data_dir = 'treedata/train'
  validation_data_dir = 'treedata/validation'
  nb_train_samples = 4000
  nb_validation_samples = 533
  epochs = 50
  batch_size = 16
  
  if K.image_data_format() == 'channels_first':
      input_shape = (3, img_width, img_height)
  else:
      input_shape = (img_width, img_height, 3)
  
  model = Sequential()
  
  model.add(Conv2D(32, (3, 3), input_shape=input_shape))
  model.add(Activation('relu'))
  model.add(MaxPooling2D(pool_size=(2, 2)))
  
  model.add(Flatten())
  model.add(Dense(64))
  model.add(Dropout(0.5))
  
  model.add(Activation('relu'))
  model.add(Dense(2)) # number of classes
  model.add(Activation('softmax'))
  
  model.compile(loss='categorical_crossentropy',
            optimizer='rmsprop',
            metrics=['accuracy'])
  
  # this is the augmentation configuration we will use for training
  train_datagen = ImageDataGenerator(
      rescale=1. / 255,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True)
  
  # this is the augmentation configuration we will use for testing:
  # only rescaling
  test_datagen = ImageDataGenerator(rescale=1. / 255)
  
  train_generator = train_datagen.flow_from_directory(
      train_data_dir,
      target_size=(img_width, img_height),
      batch_size=batch_size,
      class_mode='categorical')
  
  validation_generator = test_datagen.flow_from_directory(
      validation_data_dir,
      target_size=(img_width, img_height),
      batch_size=batch_size,
      class_mode='categorical')
  
  model.fit_generator(
      train_generator,
      steps_per_epoch=nb_train_samples // batch_size,
      epochs=epochs,
      validation_data=validation_generator,
      validation_steps=nb_validation_samples // batch_size)
  
  model.save('treetypes.h5')
  </code></pre>
  
  <p>From epoch 2 onwards, the accuracy claims to be > 0.99 and loss &lt; 0.02, which I find odd. After creating the model, I try to go through an orthophoto and decide if one 30x30 px sub-image contains a tree of given type.</p>
  
  <pre><code>import numpy as np
  import cv2
  from keras.models import load_model
  from keras.preprocessing import image
  
  model = load_model('treetypes.h5') 
  roi = cv2.imread('roi.jpg')
  sy, sx = img.shape[:2]
  px_apart = 10 # start sub-images 10 px apart
  s = 30 # sub-image size
  
  for starty in range(1, sy-img_height, px_apart):
  
      for startx in range(1, sx-img_width, px_apart):
  
          subimg = img[starty:starty+s, startx:startx+s]
          x = image.img_to_array(subimg)
          x = np.expand_dims(x, axis=0)
          is_tree = model.predict(x, batch_size=1, verbose=0) # predict classes
  </code></pre>
  
  <p>This is where I get lost. First and foremost, there seems not to be a choice that a sub-image is neither a coniferous nor leafed tree (all sub-images get predicted either is_tree = [[0, 1]] or is_tree = [[1, 0]]). There are not for example predictions [[0.1, 0.02]], which would suggest that this sub-image is not a tree at all. Thus, two main questions:</p>
  
  <p>1) Have I understood correctly that the model should output probabilities for belonging to class 1 (coniferous) and class 2 (leafed)? Why it does give only "binary" results? I read somewhere that softmax scales sum of probabilities to 1.</p>
  
  <p>2) Is my model anywhere near usable? Or is it even viable to use NN for this, given coarse sample resolution? I suspect some overfitting for my model...</p>
  
  <p>Thanks in advance if anyone has time to take on this!</p>