Проведение эксперимента с различными параметрами, эффективное сохранение результатов

Моя задача:

  • У меня есть программа, написанная на Python, которая принимает набор переменных (A,B,C) в качестве входных данных и выводит два числа (X, Y).
  • Я хочу запустить эту программу на большом диапазоне входов (A,B,C)
    • Я буду называть запуск программы с заданным набором переменных "проведением эксперимента".
  • Я использую кластер для этого (я отправляю свои работы в SLURM)
  • Затем я хочу сохранить результаты экспериментов в одном файле, например, во фрейме данных со столбцами [A|B|C|X|Y], где каждая строка является выходом другого эксперимента.

Моя текущая ситуация:

  • Я написал свою программу в следующем виде:

    import io
    from optparse import OptionParser
    
    parser = OptionParser()
    
     parser.add_option("-f", "--file",action="store", type="string", dest="filename")
     parser.add_option("-a", "--input_a",type="int", dest="a")
     parser.add_option("-b", "--input_b",type="int", dest="b")
     parser.add_option("-c", "--input_c",type="int", dest="c")
    (options, args) = parser.parse_args()
    
     def F(a,b,c):
         return((a+b, b+c))
    
     Alice = options.input_a
     Bob = options.input_b
     Carol = options.input_c
    
      with io.open("results_a_{0}_b_{1}_c_{2}.txt".format(Alice, Bob, Carol), "a") as f:
         (x,y) = F(Alice, Bob, Carol)
         f.write(u"first output = {0}, second output = {1}".format(x,y))
    
  • Это позволяет мне запускать программу один раз и сохранять результаты в одном файле.

  • В принципе, я мог бы затем отправить эту работу для диапазона (A,B,C), получить большое количество текстовых файлов с результатами, а затем попытаться объединить их в один файл.
  • Тем не менее, я предполагаю, что это не лучший способ идти о вещах.

Что я хотел бы знать, это:

  • Есть ли для меня более естественный способ запустить эти эксперименты и сохранить результаты в одном файле, и если да, то что это?
  • Как я должен представить свою коллекцию работ на SLURM, чтобы сделать это?
    • В настоящее время я представляю (эффективно) приведенный ниже скрипт, который на самом деле не работает:

...

      for a in 1 2 3; do
      for b in 10 20 30; do
      for c in 100 200 300; do
      python toy_experiment.py -a $a -b $b -c $c &
      done
      done
      done
      wait

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

1 ответ

TL;DR

Вы должны изучить, как использовать блокировку файлов в вашей системе и использовать ее для безопасного доступа к одному выходному файлу.

Вы также должны отправить свой сценарий с назначением массива заданий и разрешить каждому заданию в массиве запускать один эксперимент.


Здесь много чего происходит.

Один важный вопрос: сколько времени обычно занимает F() для вычисления? Я предполагаю, что вы только что написали пример, но это необходимо, чтобы решить, как лучше всего подойти к проблеме.

Если промежуток времени для каждого вычисления короткий, возможно, вы можете запустить несколько пакетов, агрегируя в одном скрипте несколько вычислений: в этом примере 3 пакета (для ==1, a==2 и a==3), каждый из они вычисляют все возможные эксперименты для b и c и генерируют 3 файла, которые должны быть собраны в конце.

Если временной интервал длинный, то перегрузка создания нескольких тысяч маленьких файлов не имеет большого значения. И объединить их потом будет легко.

Другое дело: при одновременной работе всех заданий в фоновом режиме вы, вероятно, перегружаете одну машину. Я не знаю, как вы запрашиваете у SLURM ресурсы, но наверняка вы будете использовать только один узел. И злоупотребляя этим. Если там есть другие пользователи, они, вероятно, разозлятся. Вы должны контролировать количество одновременных заданий, запущенных на узле, чтобы быть числом процессоров, предоставленных на этом узле. Вероятно, поможет запуск ваших расчетов с помощью srun.

Другим способом было бы создать одну работу для расчета. Вы можете инкапсулировать их в массиве заданий. В этом случае вы будете запускать только один эксперимент на задание, и вам не придется ничего начинать в фоновом режиме.

Наконец, перейдем к вашему основному вопросу: каков наилучший способ эффективно сохранить всю эту информацию на диске.

Создать тысячи файлов легко и возможно, но это не лучший способ для файловой системы. Возможно, у вас есть доступ к некоторому RAM-диску в общем узле. Запись небольшого файла в локальное хранилище вычислительного узла и копирование этого файла на общий диск в памяти было бы намного более эффективным. И когда все эксперименты будут выполнены, вы можете легко агрегировать результаты. Недостатком является то, что пространство обычно очень ограничено (я действительно не знаю реальный размер ваших данных), и это будет диск в памяти: он может быть потерян в случае сбоя питания.

Лучше было бы использовать один файл, но, как отметил Дмитрий Чубаров, вы должны использовать механизмы блокировки файлов. В противном случае вы рискуете получить смешанные результаты.

Наконец, подход, который я считаю наиболее подходящим для вашей проблемы, заключается в использовании какого-то решения, подобного базе данных. Если у вас есть доступ к реляционной БД, которая поддерживает транзакции, просто создайте таблицу с необходимыми полями и позвольте вашему коду подключиться и вставить результаты. Извлечение их в конце будет бризом. БД может быть клиент-серверной (MySQL, PostgreSQL,Oracle...) или встроенной (HSQLDB). Другой вариант - использовать какой-либо формат файла, например NetCDF, который точно предназначен для такого рода научных данных и имеет некоторую поддержку параллельного доступа.

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