План остановки дракона заставляет его восстанавливать цели, которые он уже построил ранее

Я сейчас пользуюсь drake запустить набор из>1k моделирования. Я подсчитал, что на запуск комплекта уйдет около двух дней, но я также ожидаю, что мой компьютер в любой момент в тот период выйдет из строя, потому что, ну, в общем-то, так и есть.

Очевидно, что остановка плана отменяет все цели, которые уже были построены, так что по сути это означает, что я не могу использовать drake по прямому назначению.

Я полагаю, я мог бы сделать функцию, которая на самом деле редактирует R-файл, где указан план, чтобы сделать drake последовательно добавлять цели в свой кеш, но это кажется совершенно хакерским.

Есть идеи как с этим бороться?

РЕДАКТИРОВАТЬ: реальная проблема, кажется, исходит от использования set.seed внутри моих функций генерации данных. Я знал, что drake уже делает это для пользователя таким образом, чтобы обеспечить воспроизводимость, но я решил, что если я просто оставлю свои функции такими, какими они были, это ничего не изменит, поскольку drake будет гарантировать, что случайное семя, которое я выбрал, всегда будет одинаковым? Не думаю, но, так как я удалил этот шаг, все кэшируется нормально, поэтому проблема решена.

1 ответ

Решение

Чтобы привлечь внимание зрителей, я постараюсь разобрать проблему. @zipzapboing, пожалуйста, поправьте меня, если мое описание не соответствует цели.

Допустим, у вас есть скрипт, который генерирует drake планировать и выполнять его.

library(drake)

simulate_data <- function(seed){
  set.seed(seed)
  rnorm(100)
}

seed_grid <- data.frame(
  id = paste0("target_", 1:3),
  seed = sample.int(1e6, 3)
)

print(seed_grid)
#>         id   seed
#> 1 target_1 581687
#> 2 target_2 700363
#> 3 target_3 914982

plan <- map_plan(seed_grid, simulate_data)

print(plan)
#> # A tibble: 3 x 2
#>   target   command                      
#>   <chr>    <chr>                        
#> 1 target_1 simulate_data(seed = 581687L)
#> 2 target_2 simulate_data(seed = 700363L)
#> 3 target_3 simulate_data(seed = 914982L)

make(plan)
#> target target_1
#> target target_2
#> target target_3
make(plan)
#> All targets are already up to date.

Создано в 2018-11-12 пакетом представлением (v0.2.1)

Второй make() работал просто отлично, верно? Но если бы вы запускали один и тот же сценарий в другом сеансе, у вас был бы другой план. Случайно сгенерированный seed аргументы simulate_data() будет отличаться, поэтому все ваши цели будут строиться с нуля.

library(drake)

simulate_data <- function(seed){
  set.seed(seed)
  rnorm(100)
}

seed_grid <- data.frame(
  id = paste0("target_", 1:3),
  seed = sample.int(1e6, 3)
)

print(seed_grid)
#>         id   seed
#> 1 target_1 654304
#> 2 target_2 252208
#> 3 target_3 781158

plan <- map_plan(seed_grid, simulate_data)

print(plan)
#> # A tibble: 3 x 2
#>   target   command                      
#>   <chr>    <chr>                        
#> 1 target_1 simulate_data(seed = 654304L)
#> 2 target_2 simulate_data(seed = 252208L)
#> 3 target_3 simulate_data(seed = 781158L)

make(plan)
#> target target_1
#> target target_2
#> target target_3

Создано в 2018-11-12 пакетом представлением (v0.2.1)

Одно из решений заключается в том, чтобы быть очень осторожным, чтобы держаться за то же самое plan, Однако есть еще более простой способ: просто drake установить семена для вас. drake автоматически дает каждой цели свое собственное воспроизводимое случайное семя. Эти семена целевого уровня детерминированно генерируются корневым семенем (seed аргумент make()) и названия целей.

library(digest)
library(drake)
library(magrittr) # defines %>%

simulate_data <- function(){
  mean(rnorm(100))
}

plan <- drake_plan(target = simulate_data()) %>%
  expand_plan(values = 1:3)

print(plan)
#> # A tibble: 3 x 2
#>   target   command        
#>   <chr>    <chr>          
#> 1 target_1 simulate_data()
#> 2 target_2 simulate_data()
#> 3 target_3 simulate_data()

tmp <- rnorm(1)
digest(.Random.seed) # Fingerprint of the current seed.
#> [1] "0bbddc33a4afe7cd1c1742223764661c"

make(plan)
#> target target_1
#> target target_2
#> target target_3
make(plan)
#> All targets are already up to date.

# The targets have different seeds and different values.
readd(target_1)
#> [1] -0.05530201
readd(target_2)
#> [1] 0.03698055
readd(target_3)
#> [1] 0.05990671

clean() # Destroy the targets.
tmp <- rnorm(1) # Change the global seed.
digest(.Random.seed) # The seed changed.
#> [1] "5993aa5cff4b72a0e14fa58dc5c5e3bf"

make(plan)
#> target target_1
#> target target_2
#> target target_3

# The targets were regenerated with the same values (same seeds).
readd(target_1)
#> [1] -0.05530201
readd(target_2)
#> [1] 0.03698055
readd(target_3)
#> [1] 0.05990671

# You can recover a target's seed from its metadata.
seed <- diagnose(target_1)$seed
print(seed)
#> [1] 1875584181

# And you can use that seed to reproduce
# the target's value outside make().
set.seed(seed)
mean(rnorm(100))
#> [1] -0.05530201

Создано в 2018-11-12 пакетом представлением (v0.2.1)

Я действительно должен написать больше в руководстве о том, как семена работают в drake и выделите оригинальную ловушку, поднятую в этой теме. Я сомневаюсь, что вы единственный, кто боролся с этой проблемой.

Другие вопросы по тегам