cmdstan กับ opencl

หลังจากที่ลง opencl sdk แล้วก็ให้เพิ่มไฟล์ local ในโฟลเดอร์ make ของ cmdstan โดยที่ใน local พิมพ์ตามนี้ครับ

STAN_OPENCL=true
OPENCL_DEVICE_ID=0
OPENCL_PLATFORM_ID=0 

CC = g++
CXXFLAGS += -fpermissive
LDFLAGS_OPENCL= -L"$(AMDAPPSDKROOT)lib\x86_64" -lOpenCL

จากนั้นก็ให้ make ตามปกติครับ

จาก Stan Math Library: OpenCL CPU/GPU Support (mc-stan.org)

OpenCL ในภาษา Wolfram

มีคนถามมาว่าช่วยทำตัวอย่างให้ดูหน่อยในการใช้ OpenCL ใน Mathematica ซึ่งผมก็บอกไปแล้วว่ามันตัวอย่างเยอะเลยในhelp Mathematica เอง 🙂 แต่ก็ยังอยากให้ผมทำให้ดู ตัวอย่างที่ทำให้ดูก็เป็นการประมาณค่า Pi โดยอาศัยที่เรียกว่า Monte carlo โดยประมาณจากการสุ่มจุดลงในสี่เหลี่ยมจัตุรัสที่มีวงกลมรัศมีครึ่งหนึ่งของความยาวด้านสี่เหลี่ยมจัตุรัส แล้วดูว่ามีกี่จุดที่อยู่ในวงกลม ซึ่งค่า Pi จะสามรถประมาณได้จาก

Pi = 4 * จำนวนจุดในวงกลม / จำนวนจุดที่สุ่มมาทั้งหมด

อันนี้เป็น code ที่ผมเขียนโดยใช้ OpenCL ใน Mathematica เพื่อหาดูว่าจุดไหนบ้างที่อยู่ในวงกลมซึ่งมีจุดศูนย์กลาง (0.5,0.5) ในสี่เหลี่ยนจัตุรัส

<< OpenCLLink`

scr = "
  __kernel void myPie( __global double *X, __global double *Y, 
__global mint *inC, mint np) {
      int indx = get_global_id(0);
      double d; //distance
  	if (indx < np) {
  		d = sqrt((X[indx]-0.5)*(X[indx]-0.5)+(Y[indx]-0.5)*(Y[indx]-0.5));
          if(d <= 0.5)
inC[indx] = 1;   
  	}
  }
  ";

fn = OpenCLFunctionLoad[scr, 
  "myPie", {{_Real, _, "Input"}, {_Real, _, "Input"}, {_Integer, _, 
    "Output"}, _Integer}, 16 ];

np = 10^6;
x = OpenCLMemoryLoad[RandomReal[1, np]];
y = OpenCLMemoryLoad[RandomReal[1, np]];
inc = OpenCLMemoryLoad[ConstantArray[0, np]];
Print["my Pi : ", (OpenCLMemoryGet@(fn[x, y, inc, np] // First) // 
    Total)*4.0/np]

OpenCLMemoryUnload[x, y, inc]

ทดลองรันดูสัก 100 ครั้ง โดยที่แต่ล่ะครั้งสุ่มมา 10^7 จุด แล้วดูว่ามันให้ค่าประมาณแตกต่างเท่าไหร่เมื่อเทียบกับค่าจริง (จาก Mathematica) จากรูปด้านล่าง เส้นประสีดำคือที่ได้จากการประมาณ สีแดงคือเส้นค่า Pi จาก Mathematica

ส่วนอีกอันก็เป็นการหมุนภาพ โดยที่มีจุดหมุนอยู่ที่กลางภาพครับ

scr = "
  __kernel void test1( __global float * mat1, __global float * mat2, 
float theta, mint width, mint height) {
      int xIndex = get_global_id(0);
  	int yIndex = get_global_id(1);
  	int indx = xIndex + yIndex*width;
  
  	 if (xIndex >= width || yIndex >= height)
  		return ;
  
  	//image centre
  	float x0 = width/2;
  	float y0 = height/2;
  
  	//relative position
  	int xprime = xIndex-x0;
  	int yprime = yIndex-y0;
  
  	float sinTheta = sin(theta);
  	float cosTheta = cos(theta);
  
  	int nx =(xprime*cosTheta - yprime*sinTheta + x0);
  	int ny =(xprime*sinTheta + yprime*cosTheta + y0);
  	mat2[indx] = mat1[nx + width*ny];
  }
  
  ";

Clear[test];
test = OpenCLFunctionLoad[scr, 
  "test1", {{"Float", _, "Input"}, {"Float", _, "Output"}, 
   "Float", _Integer, _Integer}, {16, 16}, 
  "ShellOutputFunction" -> Print];

CUDAFunctionLoad

หลังจากที่ลองเขียนโปรแกรมเล่น(ด้วยภาษา C)โดยใช้ CUDA สักพักแล้วเกิดของขึ้นร้อนวิชาอยากจะลองเอาไปใช้งานจริงแต่มันก็ติดว่างานส่วนใหญ่ที่ทำจะใช้ Mathematica เป็นหลัก หลายคำสั่งหรือfunction ที่เขียนขึ้นเองนั้นก็อยู่ใน Mathematica หมด ก็เลยคิดว่าแล้วจะเอาfunction ที่เขียนด้วย CUDA ไปใช้ใน Mathematica ยังไง

หลังจากงมอยู่พักใหญ่ก็พบว่า Mathematica ตั้งแต่เวอร์ชั่น 8 เป็นต้นมาสามารถที่จะใช้ความสามารถของ CUDA ได้โดย package ที่ชื่อ CUDALink ซึ่งมีมาด้วยกับตัว Mathematica แล้ว วิธีการก็เพียงโหลดpackage นี้

<<CUDALink`

จากนั้นเราก็สามารถที่จะเรียกfunction ที่เราเขียนเข้าไปได้ด้วยคำสั่ง CUDAFunctionLoad ครับเช่น

CUDAFunctionLoad example
จะว่าไปแล้ว CUDAFunctionLoad นี่มันก็เจ๋งดีครับทำให้ทุกอย่างง่ายไปหมด แต่ก็ยังมีเรื่องที่ต้องปวดหัวหรือระวังเกี่ยวกับชนิดของตัวแปรครับ

ดูรายละเอียดเพิ่มเติมได้ที่ http://reference.wolfram.com/mathematica/CUDALink/ref/CUDAFunctionLoad.html

CUDA ใน Mathematica ทำให้การคำนวณเร็วขึ้น

ทดลองเปรียบเทียบว่าถ้าใช้ GPU คำนวณใน Mathematica จะเร็วขึ้นจากที่ใช้ CPU มากน้อยเท่าใด  เครื่องที่ใช้ทดสอบคือ Dell Precision T5500 , CPU Xeon 2.66 GHz X5650  RAM 12GB, Windows 7  64-Bit, NVIDIA Quadro 4000, Mathematica 8.0.4

คำสั่งที่ใช้ครับ
a=RandomReal[{0,1},{2048,2048}];
b=RandomReal[{0,1},{2048,2048}];
AbsoluteTiming[Do[CUDADot[a,b];,{100}];]
AbsoluteTiming[Do[Dot[a,b];,{100}];]

c=RandomReal[{0,1},{512,512}];
AbsoluteTiming[Do[CUDAFourier[c];,{100}]]
AbsoluteTiming[Do[Fourier[c];,{100}]]

ปัญหา vcvars64.bat กับ NVCCCompiler

เครื่องที่ผมใช้งานลง Windows 7 64 bits พร้อมกับ Visual C++ Express 2010 กับ Windows SDK 7.1 และ NVIDIA SDKs Toolkit แล้วมีปัญหาในการ compile library ใน Mathematica ด้วย CreateLibrary หรือ CreateExecuteable กับ NVCCCompiler ใน Mathematica ซึ่งมันจะขึ้น $Failed

หลังจากที่งมหาคำตอบนี้อยู่นานก็พบว่า ไฟล์ C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat” จะมีการเรียก ไฟล์ C:\Program Files (x86)\Microsoft Visual Studio 10.0\vc\bin\amd64\vcvars64.bat ซึ่งมันไม่ได้ติดตั้งมาด้วยกับตัว compiler ดังนั้นผมเลยสร้างไฟล์ vcvars64.bat มาใหม่โดยใส่บรรทัดนี้ลงไปครับ

CALL “C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd” /x64

จากนั้นก็ลงรันคำสั่งCreateLibrary ด้วยNVCCCompiler  แต่ก็ยังไม่สามารถแก้ปัญหาได้ ยังขึ้น $Failed อยู่ แต่ก็ได้ลองเพิ่ม option  “ShellOutputFunction”->Print ดูเพื่อจะได้รู้ว่ามันเกิดปัญหาอะไร  ซึ่งก็พบว่า Mathematica มีการเรียกใช้ files พวก library จาก folder ของ NVIDIA SDKs Toolkit แต่ดันเรียก nvcc.exe จากตัวของ Mathematica เอง ผมเลย uninstall NVIDIA SDKs Toolkit ออกไป แต่ก็ได้เพิ่มตัวแปร Path ด้วย   C:\Users\SLPHYX\AppData\Roaming\Mathematica\Paclets\Repository\CUDAResources-­Win64-8.0.4.1\CUDAToolkit\bin;  C:\Users\SLPHYX\AppData\Roaming\Mathematica\Paclets\Repository\CUDAResources-­Win64-8.0.4.1\CUDAToolkit\open64\bin

(SLPHYX นี่เป็นชื่อ login ของผมครับ)

หลังจากนั้นก็ปิดแล้วเปิด Mathematica ใหม่ แล้วลองใช้ CreateLibrary กับ NVCCCompiler ก็ปรากกฏว่าใช้ได้แล้ว 🙂