У меня есть набор данных, аналогичный MNIST (200 000 строк 784 пикселя + 1 категориальный вывод (785 столбцов)), и я хочу обучить MLP и CNN, используя библиотеку Keras
в R (в RStudio). В настоящее время я использую компьютер с 32 ГБ оперативной памяти с процессором Intel i7-8700 @ 3,2 ГГц, и у меня нет проблем при обучении этой нейронной сети с использованием функции fit()
от Keras (время обучения ~ 4 минуты). Тем не менее, когда я выполняю тот же сценарий на своем ноутбуке (8 ГБ ОЗУ с Intel i5-6300 @ 2,3 ГГц), он не может сделать эпоху менее чем за 10 минут.
Я работаю профессором лаборатории в университете, и я беспокоюсь, что мои студенты не смогли запустить сценарий с этой базой данных на своих ноутбуках из-за недостатка вычислительных мощностей. Моя идея состояла в том, чтобы установить те же модели, используя генератор с функцией fit_generator()
, и загружать часть набора данных вместо всего набора данных при каждом вызове функции генератора (чтобы использовать меньше памяти, чем при загрузке всего набора данных и в результате в более быстрой тренировке). Однако это приводит к неожиданным результатам. Точность, достигнутая функцией fit()
, составляет ~ 98,8% на тренировке (120 000 строк) и ~ 98,4% на тесте (80 000 строк), но использование функции fit_generator()
составляет ~ 1,05% на той же тренировке и ~ 1,01% на тот же тест. Я нашел связанные проблемы здесь , здесь , здесь и здесь , и кажется, что проблема в том, что fit_generator()
не перетасовывает обучающие данные, и это приводит к тому, что сеть всегда обучается с одинаковыми пакетами (например, с одним и тем же градиентом при вычислении обратного распространения) и плохо представляет весь набор данных, что приводит к низкой точности. Я обучил модель, используя fit()
, но установив для аргумента shuffle
значение FALSE
, и точность упала до 0,1%, что подтверждает, что перетасовка данных обучения имеет решающее значение для обучения модели.
Мои вопросы:
- Является ли хорошей идеей использовать генератор, чтобы избежать проблем / сократить время обучения при использовании компьютера с более низкими характеристиками, или есть лучшее решение?
- Я тренирую модели, используя весь набор данных, устанавливая аргумент
steps_per_epoch
равным ceil(nrow(train_dataset)/batch_size)
, поэтому он должен использовать те же данные при использовании fit()
и fit_generator()
, за исключением "перетасовки" part right? - В случае, если использование генератора, загружающего часть набора данных, является хорошим решением для обучения моделей с компьютерами с низкой скоростью c, как я могу эффективно перетасовать тренировочные данные, используя генератор?
Все генераторы, которые я видел, берут весь набор данных и производят серию выборок в каждом вызове или не перемешивают данные. Я создал генератор с кодом ниже. В качестве аргументов он принимает datafile
файл с данными (данные обучения или тестовые данные), batch_size
размер пакета, который будет производиться при каждом вызове, mlp
для обработки данных для обучения MLP или CNN. , val
для того, чтобы начать производить пакеты с другим индексом для данных проверки, и shuffle
, чтобы указать, хотим ли мы переставлять данные или нет. Моя идея перетасовать данные состояла в том, чтобы создать случайный индекс и прочитать только одну строку файла для каждого числа в индексе (используя аргументы skip
и nrow
в read.table()
). Это крайне неэффективно из-за нескольких вызовов read.table()
:
data_generator <- function(datafile, batch_size = 128, mlp = TRUE, val = TRUE, shuffle = TRUE) {
nrow_file <- R.utils::countLines(datafile) - 1
if (!val) {
skip <- 0
} else {
skip <- nrow_file / 2
}
function() {
# Calculate the rows to read in this epoch
rows_to_read <- batch_size
if (skip + batch_size > nrow_file) {
rows_to_read <- nrow_file - skip
}
if (shuffle) {
index <- sample (c(1:nrow_file), size=batch_size, replace =F)
} else {
index <- (skip + 1):(skip + rows_to_read)
}
# Load only the rows that we want to use in training
trData <- as.list(numeric(batch_size))
for(i in index) {
ii <- i - 1
trData[[which(i == index)]] <- read.table(datafile, sep = ";", header = TRUE,
skip = ii, nrows = 1)
}
trData <- do.call("rbind",trData)
# Upload the rows to train
skip <<- skip + batch_size
if (skip >= nrow_file) {
skip <<- 0
}
# Build inputs and output
y_train <- trData[,1]
x_train <- trData[,-1]
if (mlp) {
# Return data as is for mlp
list(data.matrix(x_train), data.matrix(y_train))
} else {
# Return data reshaped for CNN
list(array_reshape(data.matrix(x_train), c(nrow(x_train), 28, 28, 1)),
data.matrix(y_train))
}
}
}
Код, который я использовал для обучения модели MLP (аналог CNN):
Без генератора
MLP_model <- keras_model_sequential()
MLP_model %>%
layer_dense(units = 500, activation = 'relu', input_shape = c(784),
kernel_regularizer = regularizer_l2(l = 0.0001),
bias_regularizer = regularizer_l2(l = 0.0001)) %>%
layer_dropout(rate = 0.4, seed = 150) %>%
layer_batch_normalization() %>%
layer_dense(units = 300, activation = 'relu',
kernel_regularizer = regularizer_l2(l = 0.001),
bias_regularizer = regularizer_l2(l = 0.001)) %>%
layer_dropout(rate = 0.3, seed = 150) %>%
layer_batch_normalization() %>%
layer_dense(units = 10, activation = 'softmax',
kernel_regularizer = regularizer_l2(l = 0.001),
bias_regularizer = regularizer_l2(l = 0.001))
MLP_model %>% compile(
loss = loss_categorical_crossentropy,
optimizer = optimizer_adam(),
metrics = c('accuracy')
)
history <- MLP_model %>% fit(
x_train_mlp, y_train,
epochs = 20, batch_size = 124,
validation_split = 0.2,
shuffle = TRUE
)
С генератором:
MLP_model <- keras_model_sequential()
MLP_model %>%
layer_dense(units = 500, activation = 'relu', input_shape = c(784),
kernel_regularizer = regularizer_l2(l = 0.0001),
bias_regularizer = regularizer_l2(l = 0.0001)) %>%
layer_dropout(rate = 0.4, seed = 150) %>%
layer_batch_normalization() %>%
layer_dense(units = 300, activation = 'relu',
kernel_regularizer = regularizer_l2(l = 0.001),
bias_regularizer = regularizer_l2(l = 0.001)) %>%
layer_dropout(rate = 0.3, seed = 150) %>%
layer_batch_normalization() %>%
layer_dense(units = 10, activation = 'softmax',
kernel_regularizer = regularizer_l2(l = 0.001),
bias_regularizer = regularizer_l2(l = 0.001))
MLP_model %>% compile(
loss = loss_categorical_crossentropy,
optimizer = optimizer_adam(),
metrics = c('accuracy')
)
history <- MLP_model %>% fit_generator(
data_generator(traindatafile,
batch_size = 128, mlp = TRUE, val = FALSE),
steps_per_epoch = round((R.utils::countLines(traindatafile)-1) / (128)),
epochs = 10)
Заранее спасибо!