如何在R中使用Keras避免使用预训练/外部模型进行图像分类

4
我有以下代码。可以在这里这里下载数据集,数据集包含被分类为的图像。
此代码的任务是训练猫和狗的图像数据。 因此,给出一张图片,它可以告诉你它是猫还是狗。 它的灵感来自于这个页面。下面是完整的运行代码:
library(keras)


# Organize dataset --------------------------------------------------------
options(warn = -1)

# Ths input
original_dataset_dir <- "data/kaggle_cats_dogs/original/"


# Create new organized dataset directory ----------------------------------

base_dir <- "data/kaggle_cats_dogs_small/"
dir.create(base_dir)

train_dir <- file.path(base_dir, "train")
dir.create(train_dir)

validation_dir <- file.path(base_dir, "validation")
dir.create(validation_dir)

test_dir <- file.path(base_dir, "test")
dir.create(test_dir)

train_cats_dir <- file.path(train_dir, "cats")
dir.create(train_cats_dir)

train_dogs_dir <- file.path(train_dir, "dogs")
dir.create(train_dogs_dir)

validation_cats_dir <- file.path(validation_dir, "cats")
dir.create(validation_cats_dir)

validation_dogs_dir <- file.path(validation_dir, "dogs")
dir.create(validation_dogs_dir)

test_cats_dir <- file.path(test_dir, "cats")
dir.create(test_cats_dir)

test_dogs_dir <- file.path(test_dir, "dogs")
dir.create(test_dogs_dir)

# Copying files from original dataset to newly created directory
fnames <- paste0("cat.", 1:1000, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames), 
          file.path(train_cats_dir)) 


fnames <- paste0("cat.", 1001:1500, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames), 
          file.path(validation_cats_dir))

fnames <- paste0("cat.", 1501:2000, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames),
          file.path(test_cats_dir))

fnames <- paste0("dog.", 1:1000, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames),
          file.path(train_dogs_dir))

fnames <- paste0("dog.", 1001:1500, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames),
          file.path(validation_dogs_dir)) 

fnames <- paste0("dog.", 1501:2000, ".jpg")
dum <- file.copy(file.path(original_dataset_dir, fnames),
          file.path(test_dogs_dir))

options(warn = -1)

# Making model ------------------------------------------------------------


conv_base <- application_vgg16(
  weights = "imagenet",
  include_top = FALSE,
  input_shape = c(150, 150, 3)
)


model <- keras_model_sequential() %>% 
  conv_base %>%
  layer_flatten() %>% 
  layer_dense(units = 256, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")

summary(model)

length(model$trainable_weights)
freeze_weights(conv_base)
length(model$trainable_weights)



# Train model -------------------------------------------------------------

train_datagen = image_data_generator(
  rescale = 1/255,
  rotation_range = 40,
  width_shift_range = 0.2,
  height_shift_range = 0.2,
  shear_range = 0.2,
  zoom_range = 0.2,
  horizontal_flip = TRUE,
  fill_mode = "nearest"
)

# Note that the validation data shouldn't be augmented!
test_datagen <- image_data_generator(rescale = 1/255)  

train_generator <- flow_images_from_directory(
  train_dir,                  # Target directory  
  train_datagen,              # Data generator
  target_size = c(150, 150),  # Resizes all images to 150 × 150
  batch_size = 20,
  class_mode = "binary"       # binary_crossentropy loss for binary labels
)

validation_generator <- flow_images_from_directory(
  validation_dir,
  test_datagen,
  target_size = c(150, 150),
  batch_size = 20,
  class_mode = "binary"
)


# Compile model -----------------------------------------------------------

model %>% compile(
  loss = "binary_crossentropy",
  optimizer = optimizer_rmsprop(lr = 2e-5),
  metrics = c("accuracy")
)


# Evaluate  ---------------------------------------------------------------

history <- model %>% fit_generator(
  train_generator,
  steps_per_epoch = 100,
  epochs = 30,
  validation_data = validation_generator,
  validation_steps = 50
)


# Plot --------------------------------------------------------------------
plot(history)

上面的示例需要下载一个外部模型(convnet trained ImageNet)数据集以及VGG16架构,才能完全运行。
conv_base <- application_vgg16(
  weights = "imagenet",
  include_top = FALSE,
  input_shape = c(150, 150, 3)
)


model <- keras_model_sequential() %>% 
  conv_base %>%
  layer_flatten() %>% 
  layer_dense(units = 256, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")

对于猫/狗数据集,这是可以接受的。因为VGG16也包含了猫和狗。

实际上,我正在执行与两种动物不同的任务,即对两种生物细胞进行分类。因此,代码是适合的,除了模型选择,似乎不能使用VGG16,因为内容不同。

如果我想编写没有conv_base的代码(合理的模型),该怎么办?如果我仍然需要使用外部模型,有哪些合理的替代方案呢?


你为什么认为你不能使用VGG16? - Dr. Snoopy
据我所知,ImageNet是来自通用图像的数据集。并不是非常特定于生物学数据,例如细胞。 - pdubois
2
不,这并不重要,学习到的特征应该仍然是有用的,有出版物在实验中展示了这一点。你应该进行实验,只有在得到负面结果后,再尝试其他模型或预训练。 - Dr. Snoopy
2个回答

4

嗯……一个合理的模型可以是一个非常广泛和开放的问题。

你应该首先遵循@Matias Valdenegro的评论,如果你的结果不好,那么你可以尝试这些解决方案。

VGG16解决方案

首先,最简单的方法是使用VGG16模型,而不冻结其权重,只需不调用 freeze_weights() 即可。

这将使VGG16模型重新训练以满足您的需求。但另一方面,由于需要训练的权重更多,您的训练时间将会更长。

在此选项中,您还可以选择不下载预训练的VGG16权重,只需用 weights = "imagenet" 替换为 weights = None (或R版本的“None”,我认为是 NULL )。这将创建一个完全未经训练的VGG16模型。

创建自定义模型

现在,这真的是一个可能性的世界。无论您使用卷积层、密集层、它们的混合、选择多少个过滤器、单元等等。

一些建议是:访问VGG16代码并查看其结构。这是一个用于图像分类的好模型。您可以复制其代码,如果需要,进行一些更改,例如减少过滤器和/或层数(因为分类两种类型的细胞可能比仅对任何类型的图像进行分类要容易得多)。
您可以看到它有五个Conv2D + Conv2D + MaxPooling2D块。您可以尝试在您的模型中使用2或3个块,并查看是否足以对细胞进行分类。
Python代码在此处,但您可能可以理解如何在R中执行此操作,您只需查看使用了哪些层。其他模型可在应用程序文件夹中找到。

1
如果你的两类细胞可以被人眼很好地区分,那么使用预训练模型VGG-16将会对你有极大的帮助,因为它学习的特征与人类用于区分物体的方式非常相似。唯一不同的是将特征空间映射到你的新对象集合上,例如,如果你将其应用于生物细胞,则所有圆形细胞可能属于一类,椭圆形细胞则属于另一类(如果我的例子没有生物意义,请原谅我),因此你只需要重新训练最后一个全连接层,或者如果结果仍然不可接受,则冻结顶部层并重新训练一些底部层,就像你引用的博客所示。你可以尝试使用其他预训练权重网络,如Inceptionv3等。使用预训练权重可以大大减少训练时间和所需的标签数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接