Моя программа нейроэволюции (C ++) в настоящее время ограничена небольшими наборами данных, и у меня есть проекты для нее, которые (на моей нынешней рабочей станции / облачной компоновке) будут выполняться месяцами. Самым большим узким местом является НЕ оценка сети или эволюционных процессов; это размер наборов данных. Чтобы получить пригодность сети-кандидата, она должна быть оценена для КАЖДОЙ записи в наборе.
В идеальном мире у меня был бы доступ к облачному экземпляру виртуальной машины с 1 ядром для каждой записи в наборе данных Cover Type из 15 120 записей. Однако самые большие виртуальные машины, которые я обнаружил, — 112-ядерные. В настоящее время моя программа использует OpenMP для распараллеливания цикла for, реализующего оценку всех записей. Ускорение равно количеству ядер. Кроссовер / мутация является последовательной, но ее можно легко распараллелить для оценки каждого человека (100–10000 из них).
Самая большая проблема заключается в том, как сеть должна была быть реализована. Обращение к сети напрямую из этой структуры.
struct DNA {
vector<int> sizes;
vector<Function> types;
vector<vector<double>> biases;
vector<vector<vector<double>>> weights;
};
Ускорение GPU оказывается невозможным. Структуры программы должны состоять из многомерных типов данных, размеры которых могут различаться (не каждый слой имеет одинаковый размер). Я выбрал векторы STL … ПОТОМ понял, что ядра не могут быть переданы или обратиться к ним. Стандартные операции (вектор / матрица) потребуют преобразования данных, передачи, выполнения и обратного преобразования. Это просто не жизнеспособно.
MPI. В последнее время я размышлял над этим, и, по-видимому, он пригоден для оценки пригодности каждого человека. Если оценка каждого из них занимает более пары секунд (что является почти достоверным), я могу представить, что этот подход является наилучшим способом продвижения вперед. Тем не менее, я рассматриваю 3 варианта того, как это сделать:
Глядя на то, что вы описали, я не думаю, что ускорение GPU невозможно. Мой любимый подход — OpenCL, но даже если вы используете CUDA, вы не можете легко использовать C ++ STL для этой цели. Но если вы преодолеете препятствие на пути преобразования вашего кода C ++ в структуры данных C (т.е. float
, double
, или же int
и их массивы, а не vector<>
типы, и переопределить ваш vector<Function>
в более примитивные типы), использование GPU должно быть легким, особенно если ваша программа в основном выполняет матричные операции. Но вы можете знать, что архитектура GPU отличается от CPU. Если ваша логика имеет много ветвлений (то есть, структуры if-then-else), производительность в GPU не будет хорошей.
GPU гораздо более способный, чем вы думали. Вся память в GPU распределяется динамически, что означает, что вы можете выделить столько памяти, сколько захотите. Если вы хотите указать разный размер для каждого потока, просто сохраните их в массиве и используйте идентификатор потока для индексации. Более того, вы даже можете хранить сеть в разделяемой памяти и оценивать записи по потокам для ускорения доступа к памяти. Как вы упомянули, наиболее удобный способ — использовать библиотеку тяги. Вам не нужно понимать, как это реализовано, если ваша цель не изучать GPU. Вам также не нужно беспокоиться о производительности, потому что она оптимизирована профессиональными экспертами по GPU (многие из Nvidia, которые создают GPU). Конструкция Thrust очень похожа на STL, поэтому ее легко освоить, если вы знакомы с C ++.