I am trying to run a neural network model in R, using Keras library. The idea is very simple, and a neural network model for this problem is overkill, but I need this for testing. I know I could reach my results in other ways, but the problem I am facing is not that simple. The coordinates are not so nicely distributed and there are also other categorical features. I need this test such that I can generalize it to this other problem I have.
In this case, I generate some samples. I generate 100 samples, with a maximum number of points of 1k. In the first 100 the x_coordinate is generated using: rnorm(a_num, 10, 4) and the y_coordinate using: rnorm(a_num, 20, 8) Each sample has a variable number of points. Using zero padding I add zeros until we reach 1k points total.
num_points=1000
all_data=NULL
for(i in 1:100){
a_num=sample(num_points, 1)
adf=data.frame(
ID=i,
x_coord=rnorm(a_num, 10, 4),
y_coord=rnorm(a_num, 20, 8)
)
### zero padding until we reach 1k points
adf=rbind(adf, data.frame(ID=i, x_coord=rep(0, num_points-a_num), y_coord=rep(0, num_points-a_num)))
adf=adf[sample(1:nrow(adf)), ]
all_data=rbind(all_data, adf)
}
I then generate another set of samples. These with coordinates rnorm(a_num, -4, 4), and rnorm(a_num, -8, 8). Also in this case I use zero padding until they reach 1k points.
for(i in 101:200){
a_num=sample(num_points, 1)
adf=data.frame(
ID=i,
x_coord=rnorm(a_num, -4, 4),
y_coord=rnorm(a_num, -8, 8)
)
### zero padding until we reach 1k points
adf=rbind(adf, data.frame(ID=i, x_coord=rep(0, num_points-a_num), y_coord=rep(0, num_points-a_num)))
adf=adf[sample(1:nrow(adf)), ]
all_data=rbind(all_data, adf)
}
The first hundred samples are in the category "1" and the second hundred in the category "0".
the_category=data.frame(ID=1:200, cat=c(rep(1, 100), rep(0, 100)))
I convert each sample from columns to rows. Now, in each row, we have all the x coordinates and all the y coordinates for each sample.
df=as.data.table(all_data)[, dcast(.SD, ID ~ rowid(ID), value.var = names(all_data)[-1])]
df <- as.data.frame(df)
After I build my model. I generate the list "indexes" to split the dataset in training set and test set. I also generate the labels for the training and the test set.
# split the dataset into train and test sets
indexes <- sample(1:nrow(df), size = 0.7*nrow(df))
train_df_x <- df[indexes, 2:ncol(df)]
label_train= the_category$cat[match( df[indexes, "ID"], the_category$ID)]
test_df_x <- df[-indexes, 2:ncol(df)]
label_test=the_category$cat[match(df[-indexes, "ID"], the_category$ID)]
library(keras)
# Define the model architecture
{
model <- keras_model_sequential()
model %>% layer_dense(units = 128, activation = "relu", input_shape = ncol(test_df_x))
model %>% layer_dropout(rate = 0.3)
model %>% layer_dense(units = 64, activation = "relu")
model %>% layer_dropout(rate = 0.3)
model %>% layer_dense(units = 32, activation = "relu")
model %>% layer_dropout(rate = 0.3)
model %>% layer_dense(units = 1, activation = "sigmoid")
}
# Compile the model
model %>% compile(
optimizer = "adam",
loss = "binary_crossentropy",
metrics = c("accuracy") )
# Fit the model on the training data
model %>% fit(
train_df_x,
label_train,
epochs = 100,
batch_size = 1,
validation_split = 0.1 )
Unfortunately, I never reach this final part since I get this error:
Error in py_call_impl(callable, dots$args, dots$keywords) :
ValueError: in user code:
<... omitted ...>4', 'y_coord_945', 'y_coord_946', 'y_coord_947', 'y_coord_948', 'y_coord_949', 'y_coord_950', 'y_coord_951', 'y_coord_952', 'y_coord_953', 'y_coord_954', 'y_coord_955', 'y_coord_956', 'y_coord_957', 'y_coord_958', 'y_coord_959', 'y_coord_960', 'y_coord_961', 'y_coord_962', 'y_coord_963', 'y_coord_964', 'y_coord_965', 'y_coord_966', 'y_coord_967', 'y_coord_968', 'y_coord_969', 'y_coord_970', 'y_coord_971', 'y_coord_972', 'y_coord_973', 'y_coord_974', 'y_coord_975', 'y_coord_976', 'y_coord_977', 'y_coord_978', 'y_coord_979', 'y_coord_980', 'y_coord_981', 'y_coord_982', 'y_coord_983', 'y_coord_984', 'y_coord_985', 'y_coord_986', 'y_coord_987', 'y_coord_988', 'y_coord_989', 'y_coord_990', 'y_coord_991', 'y_coord_992', 'y_coord_993', 'y_coord_994', 'y_coord_995', 'y_coord_996', 'y_coord_997', 'y_coord_998', 'y_coord_999', 'y_coord_1000']. Expected the following keys: ['dense_input']
See `reticulate::py_last_error()` for details
And calling py_last_error() gives:
> reticulate::py_last_error()
Traceback (most recent call last):
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
raise e.with_traceback(filtered_tb) from None
File "C:\Users\fa9028\AppData\Local\Temp\__autograph_generated_filezof6pwaa.py", line 15, in tf__train_function
retval_ = ag__.converted_call(ag__.ld(step_function), (ag__.ld(self), ag__.ld(iterator)), None, fscope)
ValueError: in user code:
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\engine\training.py", line 1160, in train_function *
return step_function(self, iterator)
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\engine\training.py", line 1146, in step_function **
outputs = model.distribute_strategy.run(run_step, args=(data,))
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\engine\training.py", line 1135, in run_step **
outputs = model.train_step(data)
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\engine\training.py", line 993, in train_step
y_pred = self(x, training=True)
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
raise e.with_traceback(filtered_tb) from None
File "C:\PROGRA~3\ANACON~1\lib\site-packages\keras\engine\input_spec.py", line 197, in assert_input_compatibility
raise ValueError(
ValueError: Missing data for input "dense_input". You passed a data dictionary with keys ['x_coord_1', ...A_LOT_OF_COLUMN_NAMES..., 'y_coord_1000']. Expected the following keys: ['dense_input']
Following some posts, here in STACK, I tried to change "input_shape" with "input_shape = NULL", or "input_shape = c(1, ncol(test_df_x)" but it didn't help. What am I doing wrong?
This would be the testing part:
# Evaluate the model on the test data
results <- model %>% evaluate(test_df_x, label_test)
# Make predictions on new data
predictions <- model %>% predict(new_data)
It turns out that the function
model %>% fit(
train_df_x,
label_train,
epochs = 100,
batch_size = 1,
validation_split = 0.1
)
Is not compatible with data frames. The train set (and the test set when doing predictions) must be converted to a matrix.
The fix is simple, one needs to do the following:
train_df_x <- as.matrix(train_df_x)
test_df_x <- as.matrix(test_df_x)
For this simple example, after 100 epoch we have:
Epoch 100/100
126/126 [==============================] - 1s 6ms/step - loss: 1.6427e-34 - accuracy: 1.0000 - val_loss: 0.0000e+00 - val_accuracy: 1.0000