Binary classification with additional dimension (subclasses)

Viewed 297

Suppose I have an array of 10 observations (belong to class A or B), 5 columns and 2 subclasses (C, D) as an additional dimension and I would like to make a binary classification (to A or B class) in Keras R. What should the network architecture look like in this case?

library("keras")

df = data.frame(class = c(rep("A", 10), rep("B", 10)),
                subclass = rep(c("C", "D"), 10),
                feature1 = rnorm(20),
                feature2 = rnorm(20),
                feature3 = rnorm(20))

df1 = df[df$subclass == "C", ]
df2 = df[df$subclass == "D", ]
df_list = list(df1, df2)

build_model = function() {
  model = keras_model_sequential() 

  model %>%
    # input_shape is 3 features and 2 subclasses
    layer_dense(units = 2, activation = 'sigmoid', input_shape = c(3, 2))

  model %>%
    compile(
      optimizer = "adam",
      loss = "binary_crossentropy",
      metrics = list("accuracy")
    )
}

# one hot encoding to A, B classes
labels = to_categorical(as.integer(df_list[[1]][, "class"]) - 1)

# drop factor columns
data = lapply(df_list, function(x) x[, -(1:2)])

# convert to array
data_array = array(unlist(c(data[[1]], data[[2]])), dim = c(10, 3, 2))

model = build_model()

# error appears in the following function:
history = model %>% fit(
  x = data_array,
  y = labels
)

Error:

Error in py_call_impl(callable, dots$args, dots$keywords):

ValueError: A target array with shape (10, 2) was passed for an output of shape (None, 3, 2) while using as loss binary_crossentropy. This loss expects targets to have the same shape as the output.

That error is related to the difference between dimensions of the input and output data, but I don't know what it should look like correctly. My sample data dimensions are 10 observations, 3 features and 2 subclasses.

Model info:

Model: "sequential"
____________________________________________________________________
Layer (type)                Output Shape               Param #    
====================================================================
dense (Dense)               (None, 3, 2)               6          
====================================================================
Total params: 6
Trainable params: 6
Non-trainable params: 0
____________________________________________________________________
2 Answers

Your error says that your model output shape is (None, 3, 2) but you give him output with shape (10,2) (labels). To fix this you should fix your input shape: Your input shpt is 3, not (3,2) because you have 3 features and you expect to have 2 outputs.

Change this line:

layer_dense(units = 2, activation = 'sigmoid', input_shape = c(3, 2))

to this:

layer_dense(units = 2, activation = 'sigmoid', input_shape = c(3))

I tested it with python, and it seems to work well:

import keras
model = keras.Sequential()
model.add(keras.layers.Dense(units = 2,activation="sigmoid",input_shape=(3,)))
model.summary()


Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_4 (Dense)              (None, 2)                 8         
=================================================================
Total params: 8
Trainable params: 8
Non-trainable params: 0
_________________________________________________________________

Before the sigmoid layer, an flatten layer is required in the neural network architecture. Then the code will work.

model %>%
  # input_shape is 3 features and 2 subclasses
  layer_flatten(input_shape = c(3, 2)) %>%
  layer_dense(units = 2, activation = 'sigmoid')
Related