вводить
адрес проекта:GitHub.com/HiHealthzzz/NEU…
Будучи новичком в области глубокого обучения, многие люди задаются вопросом, как работают такие фреймворки глубокого обучения, как TensorFlow и PyTorch. Все без исключения эти системы используют CUDA для ускорения параллельных вычислений.Здесь я использую CUDA для реализации простой сети CNN, которую каждый может изучить и понять, и достичь точности 99,23% на неискаженном наборе данных MNIST.
Предварительные знания
CUDA
Рекомендуется здесь«Вводный курс по минималистскому программированию на CUDA»
Вывод матрицы
Рекомендовано поделиться Чжиху Бог«Матричное руководство»
дизайн
место хранения
Перед реализацией нейронной сети нам нужно разработать класс хранения для хранения параметров и данных на графическом процессоре. Здесь он называется классом Storage.Для удобства реализации мы напрямую используем тягу::device_vector (похожую на std::vector), предоставляемую CUDA, для управления динамическим массивом в видеопамяти. И добавьте std::vector для сохранения формы Storage, которую можно понимать как форму Tensor в TensorFlow.
умножение матриц
Реализация нейронных сетей использует много операций умножения матриц, поэтому ключом к параллельному ускорению CUDA является достижение эффективного параллельного умножения матриц. Здесь я напрямую использую умножение матриц, ускоренное общей памятью, в «Учебнике по минималистскому программированию CUDA». На самом деле, его можно продолжать оптимизировать, чтобы значительно повысить эффективность.
полносвязный слой
Пусть X будет матрицей входных данных, где каждая строка является выборкой. W — матрица параметров, b — вектор смещения, а L — средние потери выборки. * означает матричное умножение, а не поэлементное умножение, а ^T означает транспонирование:
全连接
前向传播
Y = X * W
反向传播
dL/dX = dL/dY * W^T
dL/dW = X^T * dL/dY
偏置
前向传播
Y = X + b
反向传播
dL/db = sum(dL/dY, 0) 逐样本梯度求和
сверточный слой
Harry.in ria.put в /file/index/…
Чтобы облегчить реализацию свертки с матричным умножением, я ссылаюсь на принцип свертки Caffe, а именно на im2col:
Основная идея состоит в том, чтобы расширить операцию свертки до умножения матриц, чтобы свертка могла быть эффективно реализована с помощью параллельного ускоренного умножения матриц. Пусть F будет параметром ядра свертки, а форма будет следующей:channel_out*channel_in*kernel_width*kernel_height
, X входной образец формыchannel_in*width*height
, b — вектор смещения.
卷积
前向传播
col = im2col(im) 根据im2col展开输入图
Y = F * col
反向传播
dL/dF = dL/dY * col^T
dL/d_col = F^T * dL/dY
dL/d_im = col2im(dL/d_col)
偏置
前向传播
Y = X + b 逐通道相加
反向传播
dL/db = sum(sum(X, 2), 1) 对整个通道进行规约
Maxpool
Обратное распространение Maxpool должно записывать положение элементов перед объединением, а затем передавать обратный градиент прямо обратно.
функция активации
Прямое и обратное распространение функции активации одинаково
ReLU
前向传播
Y = relu(X)
反向传播
dL/dX = relu'(X) element_mul dL/dY 逐元素相乘
其中relu'(x) = 1 if x > 0 else 0
Sigmoid
前向传播
Y = sigmoid(X)
反向传播
dL/dX = sigmoid'(X) element_mul dL/dY 逐元素相乘
其中 sigmoid'(x) = sigmoid(x) * (1 - sigmoid(x))
Softmax
В инженерной реализации: чтобы предотвратить переполнение знаменателя Softmax, вместо него обычно используется LogSoftmax. Установите 1_n как вектор-столбец всех единиц.
Logsoftmax
正向传播
Y = log_softmax(X) = x - log(exp(X) * 1_n) * 1_n^T
由前言中矩阵求导的方法可得
反向传播
dL/dX = dL/dY - (dL/dY * 1_n * exp(x)) / (exp(x) * 1_n)
NLLLoss
NLLLoss — это средняя отрицательная логарифмическая потеря правдоподобия, реализованная для использования с LogSoftmax. Пусть Y будет матрицей меток выборки, по одной выборке на строку. N - количество образцов
前向传播
L = mean(sum(-log_P element_mul Y, 1), 0)
反向传播
用矩阵乘法,L可表示为 L = 1_n^T * ((-log_P element_mul Y) * 1_k) / N
由矩阵求导术可得
dL/d(log_P) = -Y / N
NLLLoss+LogSoftmax为我们常见的Softmax损失
将dL/d(log_P)带入LogSoftmax梯度中可得softmax损失的梯度: softmax(X) - Y
RMSProp
Чтобы реализовать отдельный оптимизатор, нам нужно сохранить градиент во время обратного распространения, а затем использовать алгоритм RMSProp для выполнения единого скользящего среднего для расчета нового градиента. Точно так же можно легко реализовать оптимизаторы, такие как Адам.
выполнить
структура исходного кода
src
cuda CUDA源码
minist MNIST DEMO
test
cuda CUDA源码单元测试
CMakeLists.txt CMake编译脚本
Из-за ограниченного места здесь мы можем видеть только фактический код на GitHub. Каждый уровень инкапсулирован как класс, и для соединения слоев может быть вызвана функция соединения.
Отладка/настройка
Вы можете легко увидеть узкое место в производительности программы с помощью Visual Profiler, предоставляемого CUDA.
В своих экспериментах я обнаружил, что 80% времени выполнения приходится на ожидание операций ввода-вывода графической карты, поэтому эффективность работы была повышена в десятки раз за счет фиксированной памяти и комбинированного выделения памяти и передачи. Во-вторых, остается еще большой простор для оптимизации матричного умножения, но в целом 6-ваттные сэмплы MNIST можно прогонять за десятки секунд на GTX1070, что в принципе достигает моей цели.
Один день программирования и два дня отладки. Отладка — сложная и важная часть разработки. Овладение соответствующими инструментами позволит сделать больше с меньшими затратами. Nsight и cuda-memcheck, предоставляемые CUDA, — все это хорошие инструменты. Конечно, Дафа печати+комментариев также испытан и протестирован.
контрольная работа
网络结构
conv 1 32 5 relu
maxpool 2
conv 32 64 5 relu
maxpool 2
conv 64 128 3 relu
fc 4 * 128 128 relu
fc 128 10 relu
softmax
nllloss
调参
shuffle = true
batch_size = 128
learning_rate = 0.003
L2 = 0.0001
beta = 0.99
准确率
1 epoch 93%
10 epochs 99.12%
30 epochs 99.23%
10s / epoch(GTX1070)
использованная литература
- High Performance Convolutional Neural Networks for Document Processing
- Алгоритм обратного распространения сверточной нейронной сети (CNN)
- вывод матрицы
- Caffe
- CUDA Toolkit Documents