【发布时间】:2021-07-13 21:15:47
【问题描述】:
我正在尝试使用 OpenMP 并行我的 C++ 神经网络训练过程。但这行不通。
然后我使用带有嵌套循环的简单 C++ 代码来测试 OpenMP。
但是 OpenMP 多线程比单线程慢得多。
我做错了什么让它变慢了吗?还是我错过了什么?
系统
MacOS 4 核
语言
C++
时间函数
我同时使用了 high_resolution_clock::now() 和 omp_get_wtime()。
std::chrono::high_resolution_clock::now();
单线程花费时间:0.00000000000000
2 个线程花费时间:0.00010013580322
4 个线程花费时间:0.00016403198242
6 个线程花费时间:0.00017309188843
8 个线程花费时间:0.00112605094910
10 个线程花费时间:0.00013613700867
12个线程花费时间:0.00082898139954
omp_get_wtime();
单线程花费时间:0.00000005900000
2 个线程花费时间:0.00009907600000
4 个线程花费时间:0.00018207300000
6 个线程花费时间:0.00014479500000
8 个线程花费时间:0.00070604400000
10 个线程花费时间:0.00057277700000
12个线程花费时间:0.00074358000000
代码
#include <iostream>
#include <omp.h>
#include <chrono>
#include <iomanip>
using namespace std;
void test() {
int j = 0;
for (int i = 0; i < 100000; i++) {
// do something to kill time...
j++;
}
};
int main()
{
auto startTime = chrono::high_resolution_clock::now();
auto endTime = chrono::high_resolution_clock::now();
// without openMp
startTime = chrono::high_resolution_clock::now();
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
chrono::duration<double> diff = endTime - startTime;
cout << setprecision(14) << fixed;
cout << "single thread cost time: " << diff.count() << endl;
// 2 threads
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(2)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "2 threads cost time: " << diff.count() << endl;
// 4 threads
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(4)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "4 threads cost time: " << diff.count() << endl;
// 6 threads
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(6)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "6 threads cost time: " << diff.count() << endl;
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(8)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "8 threads cost time: " << diff.count() << endl;
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(10)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "10 threads cost time: " << diff.count() << endl;
startTime = chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(12)
for (int i = 0; i < 100000; i++) {
test();
}
endTime = chrono::high_resolution_clock::now();
diff = endTime - startTime;
cout << "12 threads cost time: " << diff.count() << endl;
// system("pause");
return 0;
}
我如何编译代码
clang++ -std=c++11 -Xpreprocessor -fopenmp parallel.cpp -O3 -o parallel -lomp
更新
大家好,前面的问题已经解决了,我想我不应该使用NUM_THREAD。
但是当我使用 OpenMP 来加速我的神经网络时,需要更长的时间。
数据大小
MNIST 数据集,每个 epoch 60000
时间函数
omp_get_wtime()
单线程结果
***** 训练纪元 1.
批数:6000。
批量大小:10。
进度:5999/6000。
火车时间是... 64.7082。
准确度:97.72% 9772/10000。
预测时间是... 3.51836。
发布数据样本...
释放神经网络...
OpenMP 的结果
***** 训练纪元 1.
批数:6000。
批量大小:10。
进度:5999/6000。
火车时间是:247.615.
准确度:97.72% 9772/10000。
预测时间为:30.739。
使用并行的代码
#pragma omp parallel for
for (int k = 0; k < size; k++) {
layer->map[i].data[k] = activation_func::tan_h(layer->map_common[k] + layer->map[i].b);
// cout << "current thread: " << omp_get_thread_num() << endl;
}
使用 parallel for 和 omp critical 的代码
for (int k = 0; k < layer->map_count; k++) {
for (int i = 0; i < map_h; i++) {
for (int j = 0; j < map_w; j++) {
double max_value = prev_layer->map[k].data[2*i*upmap_w + 2*j];
for (int n = 2*i; n < 2*(i + 1); n++) {
#pragma omp parallel for
for (int m = 2*j; m < 2*(j + 1); m++) {
#pragma omp critical
max_value = MAX(max_value, prev_layer->map[k].data[n*upmap_w + m]);
}
}
layer->map[k].data[i*map_w + j] = activation_func::tan_h(max_value);
}
}
}
【问题讨论】:
-
您的测试循环实际上并没有做任何事情,因此编译器可能正在删除它。那么你得到的时间主要是花在创建线程上的时间。
-
测试函数应该返回值并且你的代码应该在某处打印它。正如@1201ProgramAlarm 所说,编译器可能会检测到您只是在浪费计算时间并删除循环。
-
9个女人一个月不能生孩子!您的计算时间太小,因此多线程很有用。创建/结束线程需要时间。此外,请使用环境变量
OMP_NUM_THREADS而不是num_threads(...)。 -
@JérômeRichard 关于最后一句话,不确定它是否会起作用,因为 OP 有多个具有不同线程数的并行区域
-
@dreamcrash 是的,但我认为最好在专用脚本(例如 bash)中移除(基于复制过去的)基准测试代码。无论如何,这在这里并不重要,因为该程序是一个基准。
标签: c++ multithreading macos parallel-processing openmp