Alex_McAvoy

想要成为渔夫的猎手

【局部最优问题】

在求解最优化问题时,凸优化问题有全局最优解与局部最优解的区别

全局最优是指求一个问题在全值域范围内最优,局部最优是指一个问题的解在一定范围或区域内最优,或者说解决问题或达成目标的手段在一定范围或限制内最优

阅读全文 »

【概述】

由于在训练神经网络期间前一层的参数发生了变化,这导致了每层输入的分布不同,难以通过较低的学习率和参数初始化来减慢训练速度,同时要训练的具有饱和非线性模型也十分困难,这种现象被称为内部协变量偏移(Internal Covariate Shift)

论文 Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift 中提出了批量归一化(Batch Normalization,BN)这种数据归一化方法来解决该问题

阅读全文 »

【梯度爆炸与梯度消失】

目前优化神经网络的方法基本都是基于反向传播的思想,即根据损失函数计算的误差通过反向传播的方式,逆向对网络权值进行更新

梯度消失和梯度爆炸是最常见的两个问题,它们会影响模型的收敛速度和性能

阅读全文 »

【概述】

反向传播(Error Back Propagation,BP)算法,是迄今为止最成功的神经网络训练算法,其不仅可用于多层前馈神经网络中,还可用于其他神经网络,但通常说到 BP 神经网络时,一般是指用 BP 算法所训练的多层前馈神经网络,此外,在实际应用中,当使用神经网络建模时,大多使用 BP 算法进行训练

BP 算法是一种迭代学习算法,在迭代的每一轮中采用感知机学习算法对参数进行更新,其仍是基于梯度下降法,以目标的负梯度方向对参数进行调整

阅读全文 »

原子操作

CUDA 编程的基本思想利用 GPU 来尽可能地并行执行相同的核函数,对于大多数并行任务,线程间不需要合作或使用其他线程的资源,只需要保证自己能够正常执行即可

但对于某些需要同步执行的操作,例如多个核函数需要对同一个变量进行读取-修改-写入,由于核函数之间是异步的,当试图同时执行时,就会导致出现问题

阅读全文 »

Reference

计算与传输重叠

CPU 与 GPU 间交互时涉及两个引擎:内存复制引擎核函数执行引擎,内存复制引擎负责 CPU 与 GPU 间的数据传输,核函数执行引擎负责 CPU 向 GPU 部署核函数任务

阅读全文 »

1D Grid, 1D Block 向量加法

普通实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdio.h>
#include <math.h>
#define N 100
const double EPS = 1E-6;

void __global__ add(const double *x, const double *y, double *z, int n) {
// 获取全局索引
const int index = blockDim.x * blockIdx.x + threadIdx.x;

// 步长
int stride = blockDim.x * gridDim.x;
for (int i = index; i < n; i += stride) {
z[i] = x[i] + y[i];
}
}

// 误差检测
void check(const double *z, const int n) {
bool error = false;
double maxError = 0;

for (int i = 0; i < n; i++) {
maxError = fmax(maxError, fabs(z[i]-70));
if (fabs(z[i] - 70) > EPS) {
error = true;
}
}

printf("%s\n", error ? "Errors" : "Pass");
printf("最大误差: %lf\n", maxError);
}

int main() {
const int arraySize = sizeof(double) * N;

// 申请host锁定内存
double *h_x, *h_y, *h_z;
cudaMallocHost(&h_x, arraySize);
cudaMallocHost(&h_y, arraySize);
cudaMallocHost(&h_z, arraySize);

// 初始化数据
for (int i = 0; i < N; i++) {
h_x[i] = 50;
h_y[i] = 20;
}

// 申请device显存
double *d_x, *d_y, *d_z;
cudaMalloc((void **)&d_x, arraySize);
cudaMalloc((void **)&d_y, arraySize);
cudaMalloc((void **)&d_z, arraySize);

// host数据传输到device
cudaMemcpy(d_x, h_x, arraySize, cudaMemcpyHostToDevice);
cudaMemcpy(d_y, h_y, arraySize, cudaMemcpyHostToDevice);

// 核函数执行配置
dim3 blockSize(128);
dim3 gridSize((N + blockSize.x - 1) / blockSize.x);

// 执行核函数
add<<<gridSize, blockSize>>>(d_x, d_y, d_z, N);

// 将device得到的结果传输到host
cudaMemcpy(h_z, d_z, arraySize, cudaMemcpyDeviceToHost);

// 检查执行结果
check(h_z, N);

// 释放host锁定内存
cudaFreeHost(h_x);
cudaFreeHost(h_y);
cudaFreeHost(h_z);

// 释放device显存
cudaFree(d_x);
cudaFree(d_y);
cudaFree(d_z);

return 0;
}
阅读全文 »