CSP-矩阵运算
题目背景
Softmax(Q×KTd)×V 是 Transformer 中注意力模块的核心算式,其中 Q、K 和 V 均是 n 行 d 列的矩阵,KT 表示矩阵 K 的转置,× 表示矩阵乘法。
问题描述
为了方便计算,顿顿同学将 Softmax 简化为了点乘一个大小为 n 的一维向量 W:
(W⋅(Q×KT))×V
点乘即对应位相乘,记 W(i) 为向量 W 的第 i 个元素,即将 (Q×KT) 第 i 行中的每个元素都与 W(i) 相乘。
现给出矩阵 Q、K 和 V 和向量 W,试计算顿顿按简化的算式计算的结果。
输入格式
从标准输入读入数据。
输入的第一行包含空格分隔的两个正整数 n 和 d,表示矩阵的大小。
接下来依次输入矩阵 Q、K 和 V。每个矩阵输入 n 行,每行包含空格分隔的 d 个整数,其中第 i 行的第 j 个数对应矩阵的第 i 行、第 j 列。
最后一行输入 n 个整数,表示向量 W。
输出格式
输出到标准输出中。
输出共 n 行,每行包含空格分隔的 d 个整数,表示计算的结果。
样例输入
3 2
1 2
3 4
5 6
10 10
-20 -20
30 30
6 5
4 3
2 1
4 0 -5
样例输出
480 240
0 0
-2200 -1100
子任务
70 的测试数据满足:n≤100 且 d≤10;输入矩阵、向量中的元素均为整数,且绝对值均不超过 30。
全部的测试数据满足:n≤104 且 d≤20;输入矩阵、向量中的元素均为整数,且绝对值均不超过 1000。
提示
请谨慎评估矩阵乘法运算后的数值范围,并使用适当数据类型存储矩阵中的整数。
注意矩阵乘法行和列的选择,注意转置矩阵的坐标表示
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int hang,lie;
cin>>hang>>lie;
LL tem[lie][lie];
LL ans[hang][lie];
for (int i = 0; i < lie; i++) {
for (int j = 0; j < lie; j++) {
tem[i][j]=0;
}
}
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
ans[i][j]=0;
}
}
int Q[hang][lie],K[hang][lie],V[hang][lie],W[hang];
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
cin>>Q[i][j];
}
}
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
cin>>K[i][j];
}
}
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
cin>>V[i][j];
}
}
for (int i = 0; i < hang; i++) {
cin>>W[i];
}
for (int i = 0; i < lie; i++) {
for (int j = 0; j < lie; j++) {
for (int k = 0; k < hang; k++) {
tem[i][j]+=(K[k][i])*(V[k][j]);
}
}
}
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
for (int k = 0; k < lie; k++) {
ans[i][j]+=tem[k][j]*Q[i][k];
}
ans[i][j]*=W[i];
}
}
for (int i = 0; i < hang; i++) {
for (int j = 0; j < lie; j++) {
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
}