В недавнем соревновании Invasive Species Monitoring удалось опробовать пакет keras, позволяющий использовать в R одноименную библиотеку. Был на 11 месте, затем съехал на 19 (на публичном LB), а итоговые результаты не показывают до сих пор.
Мое лучшее решение представляло собой простое усреднение предсказаний одной модели после двух разных эпох и еще одной модели после лучшей эпохи. Модели отличались форматом изображений: в первой картинки были с правильным соотношением сторон - 300х400 (высота на ширину), а во второй - с неправильным (400х300). Файнтюнил InceptionV3, хотя у участников и с Resnet все очень хорошо получалось.
В топовом решении использовалась перекрестная проверка вместо маленькой проверочной выборки в моем случае, а также картинки значительно большего размера; я остановился на 400х300 ввиду наличия GPU всего c 4Гб памяти, а автор https://www.kaggle.com/jamesrequa/keras-k-fold-inception-v3-1st-place-lb-0-99770 взял 800х800. Размер картинки в данном случае решает: борьба шла за доли процента AUC, а по своим моделям я видел, что самые "сомнительные" предсказания были как раз для тех изображений, где цветочки получились совсем маленького размера. Потенциально качество модели на относительно мелких изображениях можно было бы улучшить, добавив в список преобразований при аугментации еще и увеличение (zoom_range в image_data_generator()).
0.99 with R and Keras (Inception V3 fine-tune)
0.99 with R and Keras (Inception V3 fine-tune)
setwd("G:/KAGGLE/invasive")
library(keras)
# Class labels
labels <- read.table("data/train_labels.csv",
header = TRUE,
sep = ",")
labels$invasive_f <- factor(labels$invasive,
levels = c(0, 1),
labels = c("non_invasive", "invasive"))
# Train data
files <- list.files("data/train")
old_names <- sapply(files,
strsplit,
split = ".",
fixed = TRUE)
max_length <- max(sapply(old_names,
function(x) nchar(x[[1]])))
zeros <- max_length - sapply(old_names,
function(x) nchar(x[[1]]))
zeros <- sapply(zeros,
function(x) paste(rep(0, x), collapse = ""))
new_names <- Map(function(x, y) paste0("data/train/", y, x[1], ".jpg"),
x = old_names,
y = zeros)
files <- list.files("data/train",
full.names = TRUE)
Map(function(x, y) file.rename(from = x, to = y),
files,
new_names)
lapply(as.character(unique(labels$invasive_f)),
function(x) dir.create(path = paste0("./data/train/", x)))
files <- list.files("data/train",
pattern = "*.jpg")
new_names <- paste0("data/train/",
labels$invasive_f,
"/",
files)
files <- list.files("data/train",
full.names = TRUE,
pattern = "*.jpg")
Map(function(x, y) file.rename(from = x, to = y),
files,
new_names)
# Test data
files <- list.files("data/test")
old_names <- sapply(files,
strsplit,
split = ".",
fixed = TRUE)
max_length <- max(sapply(old_names,
function(x) nchar(x[[1]])))
zeros <- max_length - sapply(old_names,
function(x) nchar(x[[1]]))
zeros <- sapply(zeros,
function(x) paste(rep(0, x), collapse = ""))
new_names <- Map(function(x, y) paste0("data/test/", y, x[1], ".jpg"),
x = old_names,
y = zeros)
files <- list.files("data/test",
full.names = TRUE)
Map(function(x, y) file.rename(from = x, to = y),
files,
new_names)
train_directory <- "data/train/"
validation_directory <- "data/validation/"
test_directory <- "data/test/"
img_height <- 300
img_width <- 400
batch_size <- 16
epochs <- 40
train_samples = 2136
validation_samples = 159
test_samples = 1531
datagen <- image_data_generator(
rotation_range = 20,
width_shift_range = 0.2,
height_shift_range = 0.2,
horizontal_flip = TRUE
)
train_generator <- flow_images_from_directory(
train_directory,
generator = datagen,
target_size = c(img_height, img_width),
color_mode = "rgb",
class_mode = "binary",
batch_size = batch_size,
shuffle = TRUE,
seed = 123)
validation_generator <- flow_images_from_directory(
validation_directory,
generator = datagen,
target_size = c(img_height, img_width),
color_mode = "rgb",
classes = NULL,
class_mode = "binary",
batch_size = batch_size,
shuffle = TRUE,
seed = 123)
test_generator <- flow_images_from_directory(
test_directory,
generator = image_data_generator(),
target_size = c(img_height, img_width),
color_mode = "rgb",
class_mode = "binary",
batch_size = 1,
shuffle = FALSE)
base_model <- application_inception_v3(weights = "imagenet",
include_top = FALSE,
input_shape = c(img_height, img_width, 3))
# Custom layers
predictions <- base_model$output %>%
layer_global_average_pooling_2d() %>%
layer_dense(units = 1024, activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model <- keras_model(inputs = base_model$input,
outputs = predictions)
model %>% compile(
loss = "binary_crossentropy",
optimizer = optimizer_sgd(lr = 0.0001,
momentum = 0.9,
decay = 1e-5),
metrics = "accuracy"
)
tensorboard("logs/inception3")
model %>% fit_generator(
train_generator,
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = epochs,
validation_data = validation_generator,
validation_steps = as.integer(validation_samples / batch_size),
verbose = 1,
callbacks = list(
callback_model_checkpoint(
"models/inception3/inception3_{epoch:02d}_{val_acc:.2f}.h5",
save_weights_only = TRUE),
callback_tensorboard("logs/inception3"),
callback_csv_logger("logs/inception3/log_inception3.csv", separator = ";")
)
)
save_model_hdf5(model,
"models/inception3_40epochs.h5")
base_model <- application_inception_v3(weights = "imagenet",
include_top = FALSE,
input_shape = c (img_height, img_width, 3))
predictions <- base_model$output %>%
layer_global_average_pooling_2d() %>%
layer_dense(units = 1024, activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model <- keras_model(inputs = base_model$input,
outputs = predictions)
load_model_weights_hdf5(model,
"models/inception3/XXXXXXX.h5") # use your best epoch here
model %>% compile(
loss = "binary_crossentropy",
optimizer = optimizer_sgd(lr = 0.0001,
momentum = 0.9,
decay = 1e-5),
metrics = "accuracy"
)
preds <- predict_generator(model,
test_generator,
steps = test_samples)
preds <- data.frame(name = 1:test_samples,
invasive = 1 - preds)
write.table(preds,
"submit.csv", sep = ",",
dec = ".",
quote = FALSE,
row.names = FALSE)
Комментариев нет:
Отправить комментарий