矩阵并行计算

一、矩阵卷帘存储

串行计算中无需考虑数据在处理中怎样存储,但是在并行计算中需要进行关注,以便进行负载均衡等操作。

卷帘存储:矩阵A,矩阵中的元素为 A i j A_{ij} Aij,处理机阵列 p × q p\times q p×q,小块 A i j A_{ij} Aij存放在处理器 P k l P_{kl} Pkl处(k = i mod p, l = j mod q)。
如下图所示:
在这里插入图片描述

二、矩阵向量并行乘法

y = A x , A ∈ R m n ,   x ∈ R n \quad \quad y=A x, \quad A\in\mathbb{R}^{mn},\ x\in\mathbb{R}^n y=Ax,ARmn, xRn

2.1 串行算法

2.1.1 i-j实现

矩阵A的一行乘以向量x,外层循环i循环一次确定结果y中的一个值,内层循环j负责控制遍历矩阵A的一行,x的每一行(即为每一个元素)。

void matvec_i_j(float *y, float **A, float *x, int m, int n)
{
	float *arr = (float*)calloc(m, sizeof(float));
	memset(arr, 0, m);
	for (int i = 0;i < m;i++)
		for (int j = 0;j < n;j++)
			arr[i] += A[i][j] * x[j];

	printf("Multiply the matrix by the vector: \n");
	for (int i = 0;i < m;i++)
		printf("%f  \n", arr[i]);
}

2.1.2 j-i实现

矩阵A的一列乘向量x的一个值,即为外层循环j循环一次计算出结果y中每个值的第j个分量,再对每次算出的值相加即可

void matvec_j_i(float *y, float **A, float *x, int m, int n)
{
    float *arr = (float *)calloc(m, sizeof(float));
    memset(arr, 0, m);
    for (int j = 0; j<n; j++){
        for (int i = 0; i<m; i++){
            arr[i] += A[i][j] * x[j];
        }
    }
    printf("Multiply the matrix by the vector j-i: \n");
    for (int i = 0; i<m; i++)
        printf("%f  \n", arr[i]);
}

二者运行结果相同,如下图所示:
在这里插入图片描述

2.2 并行算法

2.2.1 行分块划分矩阵

将矩阵 A 按行划分成如下的行块子矩阵
A = [ A 0 T , A 1 T , … , A p − 1 T ] T \quad\quad\quad\quad\quad\quad A=\left[A_{0}^{T}, A_{1}^{T}, \ldots, A_{p-1}^{T}\right]^{T} A=[A0T,A1T,,Ap1T]T
则:
A x = [ A 0 T , A 1 T , … , A p − 1 T ] T x = [ ( A 0 x ) T , ( A 1 x ) T , … , ( A p − 1 x ) T ] \quad\quad \begin{aligned} A x &=\left[A_{0}^{T}, A_{1}^{T}, \ldots, A_{p-1}^{T}\right]^{T} x \\ &=\left[\left(A_{0} x\right)^{T},\left(A_{1} x\right)^{T}, \ldots,\left(A_{p-1} x\right)^{T}\right] \end{aligned} Ax=[A0T,A1T,,Ap1T]Tx=[(A0x)T,(A1x)T,,(Ap1x)T]

A i A_i Ai存放在结点 P i P_i Pi中,每个结点计算 A i x A_ix Aix,最后调用 MPI_GATHER 或 MPI_GATHERV 即可

2.2.2 列分块划分矩阵

将矩阵 A 按列划分,并对 x 也做相应的划分
A = [ A 0 , A 1 , … , A p − 1 ] ,   x = ( x 0 T , x 1 T , … , x p − 1 T ) T \quad\quad A=\left[A_{0}, A_{1}, \ldots, A_{p-1}\right], \ x=\left(x_{0}^{T}, x_{1}^{T}, \ldots, x_{p-1}^{T}\right)^{T} A=[A0,A1,,Ap1], x=(x0T,x1T,,xp1T)T
则有结果为:
A x = ∑ i = 0 p − 1 A i x i T \quad\quad\quad\quad A x=\sum_{i=0}^{p-1} A_{i} x_{i}^{T} Ax=i=0p1AixiT
A i A_i Ai x i x_i xi 存放在结点 P i P_i Pi 中,每个结点计算 A i   x i T A_i\ x_i^T Ai xiT,最后调用 MPI_REDUCE 或 MPI_ALLREDUCE 即可

三、矩阵乘并行计算

本节要考虑的计算问题为:
C = A × B C = A\times B C=A×B

3.1 串行矩阵乘法

3.1.1i-j-k实现

矩阵A的行和矩阵B的列相乘相加即可。

for (int i = 0;i < m;i++){
	for (int j = 0;j < n;j++){
		for (int r=0;r<k;r++)
			arr[i][j] += A[i][r] * B[r][j];
	}
}

3.2 矩阵并行分块乘法

3.2.1 行列分块

矩阵A按行进行划分,矩阵B按列进行划分。
A = [ A 0 T A 1 T ⋯ A p − 1 T ] T , B = [ B 0 B 1 ⋯ B p − 1 ] A=\left[\begin{array}{llll}A_{0}^{T} & A_{1}^{T} & \cdots & A_{p-1}^{T}\end{array}\right]^{T}, \quad B=\left[\begin{array}{llll}B_{0} & B_{1} & \cdots & B_{p-1}\end{array}\right] A=[A0TA1TAp1T]T,B=[B0B1Bp1]
第一轮计算后得到
C i j = A i × B j C_{ij}=A_i\times B_j Cij=Ai×Bj
然后第i号处理器将其所有的矩阵B的列块传递至第i-1号处理器中,再次进行计算。B的列块循环传送p-1次后得到C的最终结果。此时编号为i的处理器中存储有子矩阵 C i 0 , C i 1 , . . . , C i ( p − 1 ) C_{i0},C_{i1},...,C_{i(p-1)} Ci0,Ci1,...,Ci(p1)
循环过程如下图所示,第一次计算时为图(a),传递后为图(b)。
在这里插入图片描述
其实整个计算的过程是从对角线开始斜向上进行计算的,计算过程如下图所示:
在这里插入图片描述

for i=0 to p-1
	j=(i+myid) mod p
	Cj=A*B
	src = (myid+1) mod p
	dest = (myid-1+p) mod p
	if (i!=p-1) 
		send(B,dest)
		recv(B,src)
	end if
end for

本算法中,Cj = Cmyid, j ,A = Amyid ,B 在处理器中每次循环向前移动一个处理器,即每次交换一个子矩阵数据块,共交换 p-1 次。

3.2.2 行行分块算法

将矩阵A、B均按行进行划分,如下:
A = [ A 0 T , A 1 T , … , A p − 1 T ] T , B = [ B 0 T , B 1 T , … , B p − 1 T ] A=\left[A_{0}^{T}, A_{1}^{T}, \ldots, A_{p-1}^{T}\right]^{T}, \quad B=\left[B_{0}^{T}, B_{1}^{T}, \ldots, B_{p-1}^{T}\right] A=[A0T,A1T,,Ap1T]T,B=[B0T,B1T,,Bp1T]
再对矩阵A的每一行再次划分,划分为单个元素:
A i = [ A i 0 , A i 1 , … , A i , p − 1 ] , i = 0 , 1 , … , p − 1 A_{i}=\left[A_{i 0}, A_{i 1}, \ldots, A_{i, p-1}\right], \quad i=0,1, \ldots, p-1 Ai=[Ai0,Ai1,,Ai,p1],i=0,1,,p1
要计算出矩阵C的第一行,需要用矩阵A中的第一行去乘矩阵B的每一列,也就是
C i = A i × B C_i = A_i\times B Ci=Ai×B
此时真正需要相乘的是矩阵A的第一行的第j个元素和矩阵B的第j行,每次相乘会得到矩阵 C i j C_{ij} Cij的一部分,j++依次计算即可得到矩阵C的第i行的值,即为 :
C i = ∑ j = 0 p − 1 A i j × B j C_i=\sum_{j=0}^{p-1} A_{ij} \times B_{j} Ci=j=0p1Aij×Bj

mp1 ≡ (myid+1) mod p, mm1 ≡ (myid−1 + p) mod p
for i = 0 to p − 1 do
	l ≡ (i+myid) mod p
	C = C + Al × B
	if i ≠ p − 1, send(B, mm1), recv(B, mp1)
end{for}

数据交换方式与3.2.1相同,不同的只是计算C的方式。

3.2.3 列列分块

矩阵A和矩阵B均按列进行分块,C也按列进行划分。
与3.2.2类似此处对B的一列再次进行划分,划分为单个元素与A相乘,计算方法如下:
C j = A ∗ B j = ∑ i = 0 p − 1 A i B i j C_{j}=A * B_{j}=\sum_{i=0}^{p-1} A_{i} B_{i j} Cj=ABj=i=0p1AiBij
此时唯一不同在于要进行交换的是A矩阵,不是B矩阵。A矩阵在每次循环后,发送 A j A_j Aj至上一个处理器。

mp1 ≡ (myid+1) mod p, mm1 ≡ (myid−1 + p) mod p
for i = 0 to p − 1 do
	l ≡ (i+myid) mod p
	C = C + A × Bl
	if i ≠ p − 1, send(A, mm1), recv(A, mp1)
end{for}

3.2.4 列行分块

矩阵A按列分块,矩阵B按行进行分块.
A = [ A 0 A 1 ⋯ A p − 1 ] , B i = [ B i 0 B i 1 … B i , p − 1 ] A=\left[\begin{array}{llll}A_{0} & A_{1} & \cdots & A_{p-1}\end{array}\right], \quad B_{i}=\left[\begin{array}{llll}B_{i 0} & B_{i 1} & \ldots & B_{i, p-1}\end{array}\right] A=[A0A1Ap1],Bi=[Bi0Bi1Bi,p1]
此时计算C时按照下式进行:
C = A ∗ B = ∑ i = 0 p − 1 A i B i C=A * B=\sum_{i=0}^{p-1} A_{i} B_{i} C=AB=i=0p1AiBi
每次计算都可以算出C的一个子矩阵,一共算出P个与C相同大小的子矩阵,再进行相加即可得到C。
假设C也是按列存放在处理器中的则有将B的一行再次进行了划分(按行存放与3.2.2类似):
C j = ∑ i = 0 p − 1 A i B i j C_{j}=\sum_{i=0}^{p-1} A_{i} B_{i j} Cj=i=0p1AiBij

C = A × Bmyid
for i = 1 to p − 1 do
	l ≡ (i+myid) mod p, k ≡ (p − i+myid) mod p
	T = A × Bl
	send(T, l), recv(T, k)
	C = C + T
end{for}

3.3 Cannon乘法

Cannon乘法和并行分块乘法不同,不是仅仅让 B 矩阵的各列块循环移动,而是有目的地让 A 的各行块以及 B 的各列块皆施行循环移位,从而实现对 C 的子块的计算
将矩阵 A 和 B 分成 p 个方块 A i j A_{ij} Aij B i j B_{ij} Bij ( 0 ≤ i , j ≤ p − 1 ) (0 \leq i, j \leq \sqrt{p}-1) (0i,jp 1),每块大小为 ⌈ n / p ⌉ × ⌈ n / p ⌉ \lceil n / \sqrt{p}\rceil \times\lceil n / \sqrt{p}\rceil n/p ×n/p ,并将它们分配给 p × p \sqrt{p}\times \sqrt{p} p ×p 个处理器 ( P 00 , P 01 , … , P p − 1 p − 1 ) \left(P_{00}, P_{01}, \ldots, P \sqrt{p}-1 \sqrt{p}-1\right) (P00,P01,,Pp 1p 1)

算法执行分三步:
在这里插入图片描述
整个计算过程如下:
在这里插入图片描述

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值