You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中读取图像并用于VGG16预训练模型训练?

问题解决:修复图像形状与标签格式以适配VGG16训练

核心问题分析

  1. 图像维度错误:手动读取图像时将每个图像转为一维向量,拼接后得到单一维度数组,无法识别为「样本数-宽-高-通道」的标准输入格式。
  2. 标签格式不兼容:使用字符串标签直接训练,而categorical_crossentropy损失函数要求输入独热编码的数值标签。
  3. 通道数不匹配:VGG16预训练模型要求输入3通道图像,但当前数据集为单通道灰度图。

分步解决方案

1. 修复图像读取函数

调整read_img,保留图像的三维结构(宽、高、通道),避免转为一维向量:

library(tensorflow)
library(keras)
library(magick)

read_img <- function(file) {
  img <- image_read(file)
  # 强制调整为48x48固定尺寸
  img_resized <- image_resize(img, "48x48!")
  # 将图像转为数组,确保形状为(48,48,1)(灰度图单通道)
  img_array <- as.array(image_data(img_resized))
  dim(img_array) <- c(48, 48, 1)
  return(img_array)
}

2. 修正数据集加载函数

将所有图像数组组合成「(样本数, 48, 48, 1)」的四维数组,同时将字符串标签转为整数编码:

library(abind)

read_emotions_dataset <- function(directory) {
  emotions <- c("anger", "contempt", "disgust", "fear", "happy", "sadness", "surprise")
  # 为每个情绪分配0-6的整数标签(适配keras索引规则)
  emotion_labels <- seq_along(emotions) - 1
  
  image_list <- list()
  labels <- c()
  
  for (i in seq_along(emotions)) {
    emotion <- emotions[i]
    emotion_dir <- file.path(directory, emotion)
    emotion_files <- list.files(path = emotion_dir, full.names = TRUE)
    
    # 读取当前情绪下的所有图像
    current_images <- lapply(emotion_files, read_img)
    image_list <- c(image_list, current_images)
    # 添加对应整数标签
    labels <- c(labels, rep(emotion_labels[i], length(emotion_files)))
  }
  
  # 将图像列表转为四维数组:(样本数, 48, 48, 1)
  images <- abind(image_list, along = 0)
  list(images = images, labels = labels, image_files = unlist(image_list))
}

3. 加载并预处理数据集

加载数据后,将单通道图像转为3通道(复制灰度通道三次),并对标签进行独热编码:

# 加载训练、测试、验证集
emotions_train <- read_emotions_dataset("../data/emotions/work/train")
emotions_test <- read_emotions_dataset("../data/emotions/work/test")
emotions_val <- read_emotions_dataset("../data/emotions/work/validation")

# 提取图像与标签
train_images <- emotions_train$images
train_labels <- emotions_train$labels
val_images <- emotions_val$images
val_labels <- emotions_val$labels
test_images <- emotions_test$images
test_labels <- emotions_test$labels

# 单通道转3通道:复制灰度通道三次以适配VGG16输入要求
train_images_3ch <- train_images %>% abind(., ., ., along = 3)
val_images_3ch <- val_images %>% abind(., ., ., along = 3)
test_images_3ch <- test_images %>% abind(., ., ., along = 3)

# 归一化像素值到0-1区间
train_images_3ch <- train_images_3ch / 255
val_images_3ch <- val_images_3ch / 255
test_images_3ch <- test_images_3ch / 255

# 将整数标签转为独热编码格式
train_labels_onehot <- to_categorical(train_labels, num_classes = 7)
val_labels_onehot <- to_categorical(val_labels, num_classes = 7)
test_labels_onehot <- to_categorical(test_labels, num_classes = 7)

4. 修正模型训练代码

确保输入形状与数据匹配,使用正确的标签格式进行训练:

# 加载VGG16预训练模型,指定输入形状为(48,48,3)
vgg16 <- application_vgg16(weights = "imagenet", include_top = FALSE, input_shape = c(48, 48, 3))

# 冻结预训练层,避免训练时覆盖权重
for (layer in vgg16$layers) layer$trainable <- FALSE

# 添加自定义分类顶层
x <- layer_flatten(vgg16$output)
x <- layer_dense(x, 128, activation = "relu")
x <- layer_dropout(x, 0.5)
predictions <- layer_dense(x, 7, activation = "softmax")

# 构建完整模型
model <- keras_model(inputs = vgg16$input, outputs = predictions)

# 编译模型(使用独热标签对应categorical_crossentropy)
model %>% compile(
  optimizer = optimizer_adam(),
  loss = "categorical_crossentropy",
  metrics = c("accuracy")
)

# 启动训练
history <- model %>% fit(
  x = train_images_3ch,
  y = train_labels_onehot,
  epochs = 10,
  batch_size = 128,
  validation_data = list(val_images_3ch, val_labels_onehot)
)

# 评估模型在测试集上的性能
model %>% evaluate(test_images_3ch, test_labels_onehot)

关键说明

  • 手动读取图像时必须保留空间维度,再按样本维度拼接,避免一维化导致的形状错误。
  • VGG16预训练模型针对RGB图像训练,因此需要将单通道灰度图复制为3通道以匹配输入格式。
  • 使用categorical_crossentropy时,标签必须转换为独热编码,不能直接使用字符串或原始整数。

内容的提问来源于stack exchange,提问作者Haidepzai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:30:54