Alex_McAvoy

想要成为渔夫的猎手

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;
}
阅读全文 »

Reference

线程层次结构

核函数在 device 端执行时,会启动若干线程,一个核函数所启动的所有线程被称为一个线程网格(Thread Grid),同一个线程网格上的线程共享相同的全局内存空间,每个线程网格又可分为若干线程块(Thread Block),每个线程块中又包含若干线程

阅读全文 »

Reference

函数执行环境标识符

由于 GPU 是异构模型,所以需要区分 host 端和 device 端上的代码,在 CUDA 中是通过函数类型限定词开区别 host 和 device 上的函数,主要的三个函数类型限定词如下:

阅读全文 »

GPU

在 GPU 出现之前,对于各种绘制计算机图形所需的运算,包括顶点设置、光影、像素操作等,都是由 CPU 配合特定软件实现的

图形处理器(Graphic Processing Unit,GPU)本质上是一组图形函数的集合,专门用于处理绘制计算机图形所需的运算,而这些函数由硬件实现,因此,GPU 从某种意义上讲就是为了在图形处理过程中充当主角而出现的

阅读全文 »

【概述】

概率无向图模型(Probabilistic Undirected Graphical Model)又称马尔可夫随机场(Markov Random Field),其是由无向图 $G=(V,E)$ 来表示的联合概率分布 $P(Y)$,其中 $Y\in\mathcal{Y}$ 是一组随机变量,用结点 $v\in V$ 表示随机变量,边 $e\in E$ 表示随机变量间的依赖关系

直观来看,马尔可夫链是下一结点的状态只与当前结点有关系,与过去的结点没有关系,而马尔可夫随机场,是当前结点只与该结点直接连接的结点有关系,与随机场中其他的结点没有关系

阅读全文 »

Reference:

【概述】

如果概率模型的变量都是观测变量(Observable Variable),又称显变量,即可以直接观测到的变量,那么当给定数据时,可以直接使用极大似然估计,或使用贝叶斯估计来估计模型的参数

阅读全文 »

【概述】

变分推断(Variational Inference)是贝叶斯统计中常用的、含有隐变量模型的推理方法,其与马尔可夫链蒙特卡罗法属于不同的技巧

MCMC 通过随机抽样的方法近似计算后验概率,变分推断通过解析的方法计算后验概率的近似值

阅读全文 »

References:

【概述】

当随机变量 $X$ 服从多维目标分布的情况下,对这个多维目标分布抽样,一种方法是 单分量 Metropolis Hasting 算法 中介绍的单分量 MH 算法

阅读全文 »