多核程序设计的相关基础知识----以误差扩散算法为例

简介:     本文从基础入手,主要阐述基于桌面电脑的多核程序设计的基础知识,包括一些向量化运算,虚拟机算,多线程等的相关知识总结。 一.计算平台的分类 单指令单数据流机器(SISD) 传统的串行计算机,所有指令都是串行。



    本文从基础入手,主要阐述基于桌面电脑的多核程序设计的基础知识,包括一些向量化运算,虚拟机算,多线程等的相关知识总结。

一.计算平台的分类

单指令单数据流机器(SISD)
传统的串行计算机,所有指令都是串行。

多指令单数据流机器(MISD)
多个指令流同时对一个数据流进行处理。但是大多数情况下,多个指令流处理多个数据才是更加有效的处理方式。

单指令多数据流机器(SIMD)

几乎所有的计算机都实现了SIMD功能,intel处理器中实现的MMX,SSE,SSE2,SSE3等扩展指令集
说到这里,我就多少说几句,最近在做这方面的优化,发现居然知网上面很多研究 ,SIMD编译优化的,其实debug和release下面的程序运行时间差别很大,visual studio默认开启了很多编译优化,如果对c语言的内部函数不是很熟悉,编译成release版本的程序已经是优化的不错了,但是针对SIMD指令优化最好的莫过于Intel自己家的编译器

windows下SIMD编译优化的例子:


多指令多数据流机器(MIMD)

能够同时执行多个指令流,这些指令流分别对不同的数据流进行操作。MIMD是目前最流行的并行计算平台。例如 intel core duo双核处理器。

目前的计算机一般都属于SIMD机器或者MIMD机器,而这两种机器都提供了支持并行执行的硬件特性,因此软件开发人员能够非常方便的利用软件中存在的数据级和任务级并行性来提高程序性能。

如果要在应用程序中使用多线程技术,就必须对操作系统的限制有清楚的了解,也就是对系统的api有充分的了解,然而这对于开发通用高性能计算的程序确是一大障碍,我们不能换一个系统,就掌握一套api。

二. 虚拟环境:虚拟机和虚拟平台

在现在很多平台上运行的多线程环境其实是基于虚拟机的,并且目前计算的一个重要趋势是虚拟化。虚拟化技术主要有两种:

1.运行时虚拟化
典型的如:JAVA virtual machine,jvm,微软的通用语言运行时环境Common language runtime CLR
这些虚拟机都至少创建了三个线程:
执行线程
垃圾回收线程
编译线程(just-in-time 即时编译执行技术,将字节码编译成可执行的二进制代码)

一般来讲,这些虚拟机为任务创建的其他进程会以最优化的方式映射到其他可执行资源上。

2.系统虚拟化




VMM virtual machine monitor 虚拟机监视器对底层的平台进行必要的 虚拟化,从而使得每个虚拟机上的操作系统都感觉自己拥有整个硬件资源。

处理器虚拟化技术所带来的一个非常重要的好处就是能够剥离指令集结构(instruction set architecture,ISA)与处理器之间的必然联系。但是特权指令只能由操作系统进行执行。所以需要执行特权指令的时候需要向虚拟机监视器发送请求,得到响应后才能执行,这之中当然降低了效率。因此Intel开发了一系列ISA扩展来支持VMM有效的执行特权指令,这些指令就是大名鼎鼎的Intel虚拟化技术,用来提高VMM的性能(VMware,hamx等技术都依赖这个扩展进行实现,但是似乎和windows 的hyper-x有点冲突,实在是不太明白,还请过来人指点一二:


三.并行程序设计的基本概念

设计并行程序,程序员应该将应用程序看成是众多相互依赖的任务的集合。将应用程序划分成多个独立的任务,并确定这些任务之间的相互依赖关系的过程就称为分解(decomposition),分解问题 的方式主要有三种:
1.任务分解
2.数据分解
3.数据流分解




并行程序需要注意的几个问题:
1.同步(Synchronization)
2.通信
3.负载平衡
4.可扩展行(Scalability)


并行误差扩散算法程序实现如下:
程序主要按照论文和书中的代码实现,但是对于数据要进行一些特殊的处理

讨论帖子:讨论帖

// ERROR-diffusion.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "omp.h"
#include "windows.h"
#include <iostream>

#include <opencv2/core/core.hpp>    
#include <opencv2/highgui/highgui.hpp>  


#pragma comment(lib,"opencv_core2410d.lib")                  
#pragma comment(lib,"opencv_highgui2410d.lib")                  
#pragma comment(lib,"opencv_imgproc2410d.lib")     

using namespace std;  
using namespace cv;  

void error_diffusion(unsigned int width,
					 unsigned int height,
					 unsigned short **InputImage,
					 unsigned short **OutputImage
	)

{

	for (unsigned int i = 0;i < height-1; i++)
	{
		for(unsigned int j = 1;j < width-1; j++)
		{
			//计算输出像素的值
			if (InputImage[i][j]<128)
			{
				OutputImage[i][j] = 0;
			}
			else{ OutputImage[i][j] = 1;}

			//计算误差值
			int err = InputImage[i][j] - 255*OutputImage[i][j];
			//扩散误差
			int v;
			v=(int)InputImage[i  ][j+1];v+=err*7/16;if (v>255) v=255; if (v<0) v=0;InputImage[i  ][j+1]=(unsigned short)v;
			v=(int)InputImage[i+1][j-1];v+=err*3/16;if (v>255) v=255; if (v<0) v=0;InputImage[i+1][j-1]=(unsigned short)v;
			v=(int)InputImage[i+1][j  ];v+=err*5/16;if (v>255) v=255; if (v<0) v=0;InputImage[i+1][j  ]=(unsigned short)v;
			v=(int)InputImage[i+1][j+1];v+=err*1/16;if (v>255) v=255; if (v<0) v=0;InputImage[i+1][j+1]=(unsigned short)v;
		}
	}
}

int row = 288;
//int col = width;

void error_diffusion_omp(unsigned int width,
	unsigned int height,
	unsigned short **InputImage,
	unsigned short **OutputImage
	)

{
	int cpu_num = omp_get_num_procs();//cpu数
	 
	int col = width;
#pragma omp parallel private(row , col)//并行域
	{
		int thread_id = omp_get_num_threads();//每个线程的线程号
		Sleep(20*thread_id);//根据线程短延迟
	
#pragma omp for
		for (int i = 0; i<(height/cpu_num);i++)
		{
			 row  = row*cpu_num + thread_id;

			for ( col = 0;col<width;col++)
			{
				//计算输出像素的值
				if (InputImage[i][col]<128)
				{
					OutputImage[i][col] = 0;
				}
				else{ OutputImage[i][col] = 1;}

				//计算误差值
				int err = InputImage[i][col] - 255*OutputImage[i][col];
				//扩散误差
				InputImage[i][col+1] += err * 7/16;
				InputImage[i+1][col-1] += err * 7/16;
				InputImage[i+1][col] += err * 7/16;
				InputImage[i+1][col+1] += err * 7/16;

			}
		}

	

	}
}



int _tmain(int argc, _TCHAR* argv[])
{
	string str_name = "result.pgm";  
	

	Mat image_src = imread(str_name,0);
	imshow("original image",image_src);

	unsigned short **InputImage = new unsigned short *[image_src.rows];
	for (int i = 0;i<image_src.rows;i++)
	{
		InputImage[i] = new unsigned short [image_src.cols];
	}
	unsigned short **OutputImage = new unsigned short *[image_src.rows];
	for (int i = 0;i<image_src.rows;i++)
	{
		OutputImage[i] = new unsigned short [image_src.cols];
	}

	cout<<image_src.rows;
	cout<<image_src.cols;
	Mat image_dst(image_src.rows,image_src.cols,CV_8U);

	for(int y = 0;y < image_src.rows;y++)  
	{  
		uchar *ptr= image_src.ptr<uchar>(y); 
		
		for(int x = 0;x < image_src.cols;x++)  
		{  
			
			InputImage[y][x] = ptr[x];
			OutputImage[y][x] = 0;
			
		}  
	} 


	error_diffusion(image_src.cols,image_src.rows,InputImage,OutputImage);
	//error_diffusion_omp(image_src.cols,image_src.rows,InputImage,OutputImage);

	for(int y = 0;y < image_src.rows;y++)  
	{  
		uchar *ptr= image_dst.ptr<uchar>(y); 

		for(int x = 0;x < image_src.cols;x++)  
		{  
			if (OutputImage[y][x]==1)
			{
				ptr[x] = 255;
			}
			else
				ptr[x] = 0;

		}  
	} 
	imshow("error diffusion",image_dst);
	imwrite("result.bmp",image_dst);

	waitKey(0);


	return 0;
}



效果图:




参考文献:

SHAMEEM AKHTER(孟). 多核程序设计技术--通过软件多线程提升性能[M]. 电子工业, 2007.
张春柳, 李嘉, 熊琭. 基于OpenMP实现的误差扩散算法[J]. 软件产业与工程, 2015(1):44-48.





相关文章
基于最小二乘正弦拟合算法的信号校正matlab仿真,校正幅度,频率以及时钟误差,输出SNDR,SFDR,ENOB指标
基于最小二乘正弦拟合算法的信号校正matlab仿真,校正幅度,频率以及时钟误差,输出SNDR,SFDR,ENOB指标
|
机器学习/深度学习 算法
扩散模型=进化算法!生物学大佬用数学揭示本质
在机器学习与生物学交叉领域,Tufts和Harvard大学研究人员揭示了扩散模型与进化算法的深刻联系。研究表明,扩散模型本质上是一种进化算法,通过逐步去噪生成数据点,类似于进化中的变异和选择机制。这一发现不仅在理论上具有重要意义,还提出了扩散进化方法,能够高效识别多解、处理高维复杂参数空间,并显著减少计算步骤,为图像生成、视频合成及神经网络优化等应用带来广泛潜力。论文地址:https://arxiv.org/pdf/2410.02543。
457 21
基于梯度流的扩散映射卡尔曼滤波算法的信号预处理matlab仿真
本项目基于梯度流的扩散映射卡尔曼滤波算法(GFDMKF),用于信号预处理的MATLAB仿真。通过设置不同噪声大小,测试滤波效果。核心代码实现数据加载、含噪信号生成、扩散映射构建及DMK滤波器应用,并展示含噪与无噪信号及滤波结果的对比图。GFDMKF结合非线性流形学习与经典卡尔曼滤波,提高对非线性高维信号的滤波和跟踪性能。 **主要步骤:** 1. 加载数据并生成含噪测量值。 2. 使用扩散映射捕捉低维流形结构。 3. 应用DMK滤波器进行状态估计。 4. 绘制不同SNR下的轨迹示例。
|
机器学习/深度学习 人工智能 算法
【CIKM 2023】扩散模型加速采样算法OLSS,大幅提升模型推理速度
近日,阿里云人工智能平台 PAI与华东师范大学陈岑副教授团队合作在深度学习顶级会议 CIKM 2023 上发表 OLSS (Optimal Linear Subspace Search) 算法,这是一种针对扩散模型的采样加速算法。在这篇论文中,扩散模型加速算法的本质被建模成线性子空间的扩张过程,给出了目前方法的统一分析,并基于此设计了新的加速算法,大幅度提升了扩散模型的生成速度。
|
机器学习/深度学习 算法
**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。
【6月更文挑战第28天】**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。数据从输入层流经隐藏层到输出层,计算预测值。接着,比较预测与真实值计算损失。然后,从输出层开始,利用链式法则反向计算误差和梯度,更新权重以减小损失。此过程迭代进行,直到损失收敛或达到训练次数,优化模型性能。反向传播实现了自动微分,使模型能适应训练数据并泛化到新数据。
462 2
|
算法 JavaScript 程序员
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
282 0
|
算法 安全
基于龙格库塔算法的SIR病毒扩散预测matlab仿真
该程序使用龙格库塔算法实现SIR模型预测病毒扩散,输出易感、感染和康复人群曲线。在MATLAB2022a中运行显示预测结果。核心代码设置时间区间、参数,并定义微分方程组,通过Runge-Kutta方法求解。SIR模型描述三类人群动态变化,常微分方程组刻画相互转化。模型用于预测疫情趋势,支持公共卫生决策,但也存在局限性,如忽略空间结构和人口异质性。
|
存储 算法 Python
程序设计的艺术:算法与数据结构的魅力
程序设计的艺术:算法与数据结构的魅力
188 0
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
324 0
|
人工智能 算法
阿里云人工智能平台 PAI 扩散模型加速采样算法论文入选 CIKM 2023
近日CIKM 2023上,阿里云人工智能平台PAI和华东师范大学陈岑副教授团队主导的扩散模型加速采样算法论文《Optimal Linear Subspace Search: Learning to Construct Fast and High-Quality Schedulers for Diffusion Models》入选。此次入选意味着阿里云人工智能平台 PAI自研的扩散模型算法和框架达到了全球业界先进水平,获得了国际学者的认可,展现了中国人工智能技术创新在国际上的竞争力。

热门文章

最新文章