Многопоточность в машинном обучении — различия между версиями
Skozelko (обсуждение | вклад) (Переделан пункт про broadcast операции) |
Skozelko (обсуждение | вклад) (Ссылки и оформление) |
||
Строка 1: | Строка 1: | ||
Следует выделить следующие виды параллелизма: | Следует выделить следующие виды параллелизма: | ||
− | * Параллелизм на уровне инструкций (ILP): несколько инструкций исполняются одновременно. | + | * Параллелизм на уровне инструкций ([https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D0%B8%D0%B7%D0%BC_%D0%BD%D0%B0_%D1%83%D1%80%D0%BE%D0%B2%D0%BD%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4 ILP]): несколько инструкций исполняются одновременно. |
− | * Параллелизм типа одна инструкция множество данных (SIMD): одна операция применяется к множеству данных | + | * Параллелизм типа одна инструкция множество данных ([https://ru.wikipedia.org/wiki/SIMD SIMD]): одна операция применяется к множеству данных |
* Многопоточный параллелизм: несколько независимых рабочих потоков взаимодействуют через абстракцию совместно используемой памяти. | * Многопоточный параллелизм: несколько независимых рабочих потоков взаимодействуют через абстракцию совместно используемой памяти. | ||
− | * Распределенные вычисления: несколько независимых рабочих компьютеров взаимодействуют по сети. (MLlib на Spark, Mahout на Hadoop) | + | * Распределенные вычисления: несколько независимых рабочих компьютеров взаимодействуют по сети. ([https://spark.apache.org/mllib/ MLlib] на Spark, [https://mahout.apache.org/ Mahout] на Hadoop) |
== Идеи используемые для ускорения вычислений в ML == | == Идеи используемые для ускорения вычислений в ML == | ||
Строка 21: | Строка 21: | ||
Такая оптимизации часто встречаются в библиотеках машинного обучения. | Такая оптимизации часто встречаются в библиотеках машинного обучения. | ||
− | === Параллелизм | + | === Параллелизм кросс-валидации === |
− | Полная кросс-валидация, k-fold, t×k-fold, Leave-One-Out легко распараллеливаются на несколько потоков, каждый из которых работает на своем разбиении данных | + | Полная [[Кросс-валидация | кросс-валидация]], k-fold, t×k-fold, Leave-One-Out легко распараллеливаются на несколько потоков, каждый из которых работает на своем разбиении данных |
[[Файл:ParallelCrossValidation.png|500px]] | [[Файл:ParallelCrossValidation.png|500px]] | ||
Строка 30: | Строка 30: | ||
Фреймворки машинного обучения, такие как TensorFlow, PyTorch и MxNet используют эти возможности через библиотеки от компаний производителей графических ускорителей и открытые фреймворки: | Фреймворки машинного обучения, такие как TensorFlow, PyTorch и MxNet используют эти возможности через библиотеки от компаний производителей графических ускорителей и открытые фреймворки: | ||
− | * [https://developer.nvidia.com/cuda-toolkit CUDA] | + | * [https://developer.nvidia.com/cuda-toolkit CUDA] — язык параллельного программирования/вычислительная платформа для вычислений общего назначения на графическом процессоре |
− | * [https://developer.nvidia.com/cublas cuBLAS] | + | * [https://developer.nvidia.com/cublas cuBLAS] — библиотека представляет собой реализацию BLAS (базовых подпрограмм линейной алгебры) поверх среды выполнения CUDA. |
− | * [https://www.khronos.org/opencl/ OpenCL] | + | * [https://www.khronos.org/opencl/ OpenCL] — фреймворк для написания компьютерных программ, связанных с параллельными вычислениями на различных графических и центральных процессорах, а также FPGA |
Пример перемножения матриц на cuBLAS | Пример перемножения матриц на cuBLAS | ||
Строка 87: | Строка 87: | ||
Можно запустить внешний цикл [[Стохастический градиентный спуск|стохастического градиентного спуска (SGD)]] параллельно в пуле потоков и использовать конструкции синхронизации, такие как блокировки, чтобы предотвратить состояние гонки. Однако из-за накладных расходов на синхронизацию ускорение может получиться маленьким. | Можно запустить внешний цикл [[Стохастический градиентный спуск|стохастического градиентного спуска (SGD)]] параллельно в пуле потоков и использовать конструкции синхронизации, такие как блокировки, чтобы предотвратить состояние гонки. Однако из-за накладных расходов на синхронизацию ускорение может получиться маленьким. | ||
− | Еще более интересная идея называется асинхронным SGD или Hogwild. SGD запускается параллельно в несколько потоков без какой-либо синхронизации. Теперь состояния гонки могут возникнуть, но во многих случаях это хорошо, потому что они просто немного изменяют шум и ошибки уже присутствующие из-за случайного выбора градиента. | + | Еще более интересная идея называется асинхронным SGD или Hogwild<ref>[https://arxiv.org/abs/1106.5730 HOGWILD!: A Lock-Free Approach to Parallelizing Stochastic Gradient Descent]</ref>. |
+ | SGD запускается параллельно в несколько потоков без какой-либо синхронизации. Теперь состояния гонки могут возникнуть, но во многих случаях это хорошо, потому что они просто немного изменяют шум и ошибки уже присутствующие из-за случайного выбора градиента. | ||
=== Параллелизм в методе k ближайших соседей === | === Параллелизм в методе k ближайших соседей === | ||
− | Основное время работы метода k ближайших соседей составляет поиск ближайших соседей. Так как расстояния до разных объектов независимы, то можно разбить объекты на группы, параллельно решить задачу во всех группах, а потом объединить результат<ref>[http://ceres-journal.eu/download.php?file=2019_01_01.pdf Implementation of a Parallel K-Nearest Neighbor Algorithm Using MPI]</ref>. Альтернативный подход | + | Основное время работы метода k ближайших соседей составляет поиск ближайших соседей. |
+ | Так как расстояния до разных объектов независимы, то можно разбить объекты на группы, параллельно решить задачу во всех группах, а потом объединить результат<ref>[http://ceres-journal.eu/download.php?file=2019_01_01.pdf Implementation of a Parallel K-Nearest Neighbor Algorithm Using MPI]</ref>. | ||
+ | Альтернативный подход — параллельная сортировка всех объектов, например, с использованием битонной сортировки<ref>[https://users.cs.duke.edu/~nikos/reprints/knn-TR-CS-2012-03.pdf Parallel Search of k-Nearest Neighbors with Synchronous Operations]</ref>. | ||
=== Параллелизм в методе опорных веторов === | === Параллелизм в методе опорных веторов === | ||
− | Вычислительная сложность метода опорных векторов заключается в минимизации квадратичной функции. Первый вариант распараллеливания задачи | + | Вычислительная сложность метода опорных векторов заключается в минимизации квадратичной функции. |
+ | Первый вариант распараллеливания задачи — добавление параллелизма в алгоритм в явном виде, например, параллельная оптимизация большего количества переменных в SMO<ref>[https://publikationen.uni-tuebingen.de/xmlui/bitstream/handle/10900/49015/pdf/tech_21.pdf Parallel Support Vector Machines]</ref>. | ||
+ | Второй подход — запись алгоритма через матричные операции, которые легко параллелизируемы<ref>[https://www.researchgate.net/publication/6265163_Multiplicative_Updates_for_Nonnegative_Quadratic_Programming Multiplicative Updates for Nonnegative Quadratic Programming]</ref>. | ||
== Источники информации == | == Источники информации == |
Версия 07:57, 28 декабря 2020
Следует выделить следующие виды параллелизма:
- Параллелизм на уровне инструкций (ILP): несколько инструкций исполняются одновременно.
- Параллелизм типа одна инструкция множество данных (SIMD): одна операция применяется к множеству данных
- Многопоточный параллелизм: несколько независимых рабочих потоков взаимодействуют через абстракцию совместно используемой памяти.
- Распределенные вычисления: несколько независимых рабочих компьютеров взаимодействуют по сети. (MLlib на Spark, Mahout на Hadoop)
Идеи используемые для ускорения вычислений в ML
Параллелизм для ускорения линейной алгебры.
Многие операции линейной алгебры, например, векторное сложение, произведение матриц и вычисление нормы состоят из большого количества независимых операций. Поэтому можно сильно повысить их производительность как за счёт ILP и SIMD параллелизма для маленьких данных, так и за счёт многопоточности для больших данных. От ускорения линейной алгебры особенно выигрывают нейронные сети, так как большую часть времени их работы занимает умножение матриц.
Иногда необходимо выполнить операцию с объектам имеющими разнаю размерность, но которые можно привести к одной размерности повторением одного из объектов вдоль одной или нескольких осей. Например, если нужно прибавить к каждой строке матрицы вектор или домножить вектор на число. В таком случае можно не писать цикл в явном виде, а использовать broadcast операции. При этом задача оптимизации переходит к разработчику библиотеки, который может обеспечить лучший параллелизм операций за счет доступа к внутренностям библиотеки.
Примеры оптимизаций:
- Высоко оптимизированные тензорные библиотеки для арифметики.
- Алгоритмы в терминах матричных операций, а не векторных операций, насколько это возможно.
- Broadcast операции вместо циклов.
- Распараллеленные реализации некоторых специальных операций (таких как свертки для CNN).
Параллелизм в оптимизации гиперпараметров
Для параллельной оптимизации гиперпараметров можно использовать поиск по решётке или случайный поиск в которых мы можем оценить параметры независимо. Такая оптимизации часто встречаются в библиотеках машинного обучения.
Параллелизм кросс-валидации
Полная кросс-валидация, k-fold, t×k-fold, Leave-One-Out легко распараллеливаются на несколько потоков, каждый из которых работает на своем разбиении данных
Параллелизм GPU
Графические процессоры позволяют применять одну и ту же операцию параллельно к десяткам тысяч элементов за счет большого числа потоков.
Фреймворки машинного обучения, такие как TensorFlow, PyTorch и MxNet используют эти возможности через библиотеки от компаний производителей графических ускорителей и открытые фреймворки:
- CUDA — язык параллельного программирования/вычислительная платформа для вычислений общего назначения на графическом процессоре
- cuBLAS — библиотека представляет собой реализацию BLAS (базовых подпрограмм линейной алгебры) поверх среды выполнения CUDA.
- OpenCL — фреймворк для написания компьютерных программ, связанных с параллельными вычислениями на различных графических и центральных процессорах, а также FPGA
Пример перемножения матриц на cuBLAS
void gpu_blas_mmul(cublasHandle_t &handle, const float *A, const float *B, float *C, const int m, const int k, const int n) { int lda = m, ldb = k, ldc = m; const float alf = 1; const float bet = 0; const float *alpha = &alf; const float *beta = &bet; // Do the actual multiplication cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc); }
Пример перемножения матриц на PyCUDA
import pycuda.gpuarray as gpuarray import numpy as np import skcuda.linalg as linalg # --- Initializations import pycuda.autoinit linalg.init() A = np.array(([1, 2, 3], [4, 5, 6])).astype(np.float64) B = np.array(([7, 8, 1, 5], [9, 10, 0, 9], [11, 12, 5, 5])).astype(np.float64) A_gpu = gpuarray.to_gpu(A) B_gpu = gpuarray.to_gpu(B) C_gpu = linalg.dot(A_gpu, B_gpu) print(np.dot(A, B)) print(C_gpu)
Наивная реализация перемножения матриц на OpenCL
// First naive implementation __kernel void myGEMM1(const int M, const int N, const int K, const __global float *A, const __global float *B, __global float *C) { // Thread identifiers const int globalRow = get_global_id(0); // Row ID of C (0..M) const int globalCol = get_global_id(1); // Col ID of C (0..N) // Compute a single element (loop over K) float acc = 0.0f; for (int k = 0; k < K; k++) { acc += A[k * M + globalRow] * B[globalCol * K + k]; } // Store the result C[globalCol * M + globalRow] = acc; }
Параллелизм в стохастическом градиентном спуске
Можно запустить внешний цикл стохастического градиентного спуска (SGD) параллельно в пуле потоков и использовать конструкции синхронизации, такие как блокировки, чтобы предотвратить состояние гонки. Однако из-за накладных расходов на синхронизацию ускорение может получиться маленьким.
Еще более интересная идея называется асинхронным SGD или Hogwild[1]. SGD запускается параллельно в несколько потоков без какой-либо синхронизации. Теперь состояния гонки могут возникнуть, но во многих случаях это хорошо, потому что они просто немного изменяют шум и ошибки уже присутствующие из-за случайного выбора градиента.
Параллелизм в методе k ближайших соседей
Основное время работы метода k ближайших соседей составляет поиск ближайших соседей. Так как расстояния до разных объектов независимы, то можно разбить объекты на группы, параллельно решить задачу во всех группах, а потом объединить результат[2]. Альтернативный подход — параллельная сортировка всех объектов, например, с использованием битонной сортировки[3].
Параллелизм в методе опорных веторов
Вычислительная сложность метода опорных векторов заключается в минимизации квадратичной функции. Первый вариант распараллеливания задачи — добавление параллелизма в алгоритм в явном виде, например, параллельная оптимизация большего количества переменных в SMO[4]. Второй подход — запись алгоритма через матричные операции, которые легко параллелизируемы[5].
Источники информации
- Principles of Large-Scale Machine Learning
- cuBLAS library user guide
- Matrix multiplication on GPU using CUDA with CUBLAS
- A short notice on performing matrix multiplications in PyCUDA
- CUDA C++ Programming Guide
- OpenCL SGEMM tuning for Kepler
- ↑ HOGWILD!: A Lock-Free Approach to Parallelizing Stochastic Gradient Descent
- ↑ Implementation of a Parallel K-Nearest Neighbor Algorithm Using MPI
- ↑ Parallel Search of k-Nearest Neighbors with Synchronous Operations
- ↑ Parallel Support Vector Machines
- ↑ Multiplicative Updates for Nonnegative Quadratic Programming