Другим потенциальным заголовком для этого сообщения может быть "Когда параллельная обработка в r, имеет ли отношение между количеством ядер, размером куска цикла и размером объекта?"
У меня есть corpus. Я выполняю некоторые преобразования при использовании пакета tm. Поскольку корпус большой, я использую параллельную обработку с допараллельным пакетом.
Иногда преобразования выполняют задачу, но иногда они этого не делают. Например, tm::removeNumbers()
. Самый первый документ в корпусе имеет значение содержания "n417". Поэтому, если предварительная обработка выполнена успешно, этот документ будет преобразован в "n".
Образец корпуса ниже для воспроизведения. Вот кодовый блок:
library(tidyverse)
library(qdap)
library(stringr)
library(tm)
library(textstem)
library(stringi)
library(foreach)
library(doParallel)
library(SnowballC)
corpus <- (see below)
n <- 100 # this is the size of each chunk in the loop
# split the corpus into pieces for looping to get around memory issues with transformation
nr <- length(corpus)
pieces <- split(corpus, rep(1:ceiling(nr/n), each=n, length.out=nr))
lenp <- length(pieces)
rm(corpus) # save memory
# save pieces to rds files since not enough RAM
tmpfile <- tempfile()
for (i in seq_len(lenp)) {
saveRDS(pieces[[i]],
paste0(tmpfile, i, ".rds"))
}
rm(pieces) # save memory
# doparallel
registerDoParallel(cores = 12)
pieces <- foreach(i = seq_len(lenp)) %dopar% {
piece <- readRDS(paste0(tmpfile, i, ".rds"))
# regular transformations
piece <- tm_map(piece, content_transformer(removePunctuation), preserve_intra_word_dashes = T)
piece <- tm_map(piece, content_transformer(function(x, ...)
qdap::rm_stopwords(x, stopwords = tm::stopwords("english"), separate = F)))
piece <- tm_map(piece, removeNumbers)
saveRDS(piece, paste0(tmpfile, i, ".rds"))
return(1) # hack to get dopar to forget the piece to save memory since now saved to rds
}
stopImplicitCluster()
# combine the pieces back into one corpus
corpus <- list()
corpus <- foreach(i = seq_len(lenp)) %do% {
corpus[[i]] <- readRDS(paste0(tmpfile, i, ".rds"))
}
corpus_done <- do.call(function(...) c(..., recursive = TRUE), corpus)
И здесь - это ссылка на образцы данных. Мне нужно вставить достаточно большую выборку из 2k docs для воссоздания, и SO не позволит мне вставить это так, поэтому см. Связанный документ для данных.
corpus <- VCorpus(VectorSource([paste the chr vector from link above]))
Если я запустил свой блок кода, как указано выше, с n = до 200, то посмотрите на результаты
Я вижу, что числа остаются там, где они должны были быть удалены с помощью tm::removeNumbers()
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n417"
[1] "disturbance"
[1] "grand theft auto"
Однако, если я изменяю размер блока (значение переменной "n" ) до 100:
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n"
[1] "disturbance"
[1] "grand theft auto"
Номера удалены.
Но это непоследовательно. Я попытался сузить его, проведя тестирование на 150, затем 125... и обнаружил, что он будет/не будет работать от 120 до 125 штук. Затем после итерации функции между 120: 125 она иногда работает, а затем не для того же размера блока.
Я думаю, может быть, есть отношение к этой проблеме между тремя переменными: размером корпуса, размером куска и количеством ядер в registerdoparallel()
. Я просто не знаю, что это такое.
Может ли кто-нибудь протянуть руку или даже воспроизвести со связанным образцом тела? Я обеспокоен тем, что иногда могу воспроизвести ошибку, иногда я не могу. Изменение размера куска дает возможность увидеть ошибку с удалением чисел, но не всегда.
Update Сегодня я возобновил сеанс и не смог воспроизвести ошибку. Я создал Google Doc и экспериментировал с разными значениями размера корпуса, количества ядер и размеров блоков. В каждом случае все было успешным. Итак, я попытался работать с полными данными, и все сработало. Однако, по моему здравомыслию, я попробовал снова запустить полные данные, и это не удалось. Теперь я вернулся туда, где был вчера. Кажется, что запустили функцию на более крупном наборе данных, что-то изменило... Я не знаю, что. Возможно, какая-то переменная сеанса? Итак, новая информация заключается в том, что эта ошибка возникает только после запуска функции на очень большом наборе данных. Перезагрузка моей сессии не решила проблему, но возобновление сеансов после простоя в течение нескольких часов.
Новая информация. Возможно, было бы легче воспроизвести проблему на более крупном корпусе, так как это то, что, похоже, вызывает проблему. corpus <- do.call(c, replicate(250, corpus, simplify = F))
создаст 500-килограммовый корпус документа на основе предоставленного мной примера. Функция может работать в первый раз, когда вы ее вызываете, но для меня она, кажется, не срабатывает второй раз.
Эта проблема сложна, потому что, если я смогу воспроизвести проблему, я, вероятно, смогу ее идентифицировать и исправить.
Новая информация. Поскольку с этой функцией было несколько вещей, было трудно понять, где сосредоточить усилия по отладке. Я смотрел на то, что я использую несколько временных файлов RDS для сохранения памяти, а также тот факт, что я выполняю параллельную обработку. Я написал две альтернативные версии script, которая все еще использует файлы rds и разбивает корпус, но не выполняет параллельную обработку (заменил% dopar% только% do%, а также удалил registerDoParallel line) и тот, который использует параллельные но не использует временные файлы RDS для разделения небольшого массива образцов вверх. Я не смог создать ошибку с одноядерной версией script, только с версией, использующей% dopar%, я смог воссоздать проблему (хотя проблема прерывистая, она не всегда терпит неудачу с dopar),
Таким образом, этот вопрос появляется только при использовании %dopar%
. Тот факт, что я использую временные RDS файлы, как представляется, не является частью проблемы.