又是一枚祖国的骚年,阅览做做笔记:http://www.cnblogs.com/neopenx/p/4643705.html

这里只是一些基础知识。帮助理解DL tool的实现。

最新补充:我需要一台DIY的Deep learning workstation.

“这也是深度学习带来的一个全新领域,它要求研究者不仅要理论强,建模强,程序设计能力也要过硬,不能纸上谈兵。”

  • CUDA的广泛应用造就了GPU计算专用Tesla GPU的崛起。
  • 随着显卡的发展,GPU越来越强大,而且GPU为显示图像做了优化。在计算上已经超越了通用的CPU。如此强大的芯片如果只是作为显卡就太浪费了,因此NVidia推出CUDA,让显卡可以用于图像计算以外的目的
  • 目前只有G80、G92、G94、G96、GT200、GF100、GF110、GK100、GK104、GK107平台(即GeForce 8~Gecorce GTX780Ti)的NVidia显卡才能使用CUDA,工具集的核心是一个C语言编译器。G80中拥有128个单独的ALU(Arithmetic Logic Unit,算术逻辑单元),因此非常适合并行计算,而且数值计算的速度远远优于CPU。
 

Tesla GPU

Ref: http://bbs.gpuworld.cn/forum.php?mod=viewthread&tid=199
A. GeForce系列GPU追求“速度”,并不会对“数据正确性”进行“再确认”,因为“显示”就算有1%~2%的错误,也无伤大雅,反正刷屏速度60Hz,肉眼也分辨不出,错就错了也无所谓
B. 但对于“运算”需求,是容不得丝毫错误的,必须达到99.999999999....%正确率的,就有非常高的要求,这也是Tesla GPU必须采用ECC显存,以确保运算正确率的原因,导致价格比GeForce高出很多。

如果,你对“数据正确性”要求不高,那 GeForce 卡绝对会让你很开心。但如果你的计算结果容不下一点点错误,那还是得咬着牙选择 Tesla 专业卡,否则你还要花更多成本去面对难以预期的风险。

最后的caffe性能对比,自觉脑补。

OpenCL

OpenCL(全称Open Computing Language,开放运算语言)是第一个面向异构系统通用目的并行编程的开放式、免费标准,也是一个统一的编程环境,便于软件开发人员为高性能计算服务器、桌面计算系统、手持设备编写高效轻便的代码,而且广泛适用于多核心处理器(CPU)、图形处理器(GPU)、Cell类型架构以及数字信号处理器(DSP)等其他并行处理器,在游戏、娱乐、科研、医疗等各种领域都有广阔的发展前景。


CUDA到底是个什么?

为了泛型编程(C、C++、Fortran多语言)、以及榨取更多的计算力,NVIDIA对OpenCL进行的改装,贴合自己的GPU硬件架构,量身定做出CUDA。

较游戏程序员不同,CUDA程序员主要工作,就是把握硬件架构,在算法理论时间复杂度下,将算法串行执行体系,改组为并行执行体系。(能并行的并行化)

NVIDIA为它在不同成长阶段卖出的产品,规定了计算能力体系:

  1. 1. 计算能力1.0是跑CUDA的最低条件,这一时期的代表作是8800GT家族。
  2. 2. Fermi架构的计算能力是2.0,
  3. 3. Kepler是3.0,
  4. 4. Maxwell是4.0。

GPU会按照负载均衡的原则,将任务平均分至各个SM阵列 <---- Stream Multiprocessors(流多处理器),民间多译为SM计算阵列

对于每个SM阵列,就调度它手下那一伙CUDA核心干活。流处理器(SP)改名为"CUDA核心"。

2.

由于每个SM阵列的CUDA核心有限,NVIDIA规定,Fermi架构,每个SM最多并行执行1024个线程。

当然,实际任务中,每个SM会分到几百万个线程,这时候,就只能小部分并行,然后再串行了。

  • Fermi 1.0架构,官方设计是16组SM,512SP,然而旗舰GTX480最后只弄出了15组,480SP,顺次阉割出GTX470、GTX460。
  • Fermi 2.0架构,旗舰GTX580,总算达到设计图要求,达到了16组,512SP,顺次阉割出了GTX570,GTX560。

3.

Kepler架构最大变化在于, 对每个SM阵列,将SP数量扩大到6倍,达到192SP。谓之曰SMX阵列

每个SMX阵列,包含192个CUDA核心,单次并行吞吐量是2048个线程。

  • Kepler 1.0架构,官方设计是15组SM,2880SP,然而旗舰GTX580最后只弄出了8组,1536SP,顺次阉割出GTX570、GTX560。
  • Kepler 2.0架构,旗舰GTX680,总算达到设计图要求,达到了15组,2880SP,顺次阉割出了GTX670,GTX660。

特别版,GTX Titan Z,直接把两块GK110并在一起,合出了30组,5760SP,同时支持双精度浮点计算。

其阉割掉双精度之后,就是GTX690。

  

值得一提的是,GTX游戏卡直接把双精度阉割掉了,因为只有Tesla做科学计算的时候,才会用双精度浮点运算。

4.

Maxwell架构是老黄的无奈之举。因为台积电把20nm工艺让给了ARM系(Apple和高通)。

还是基于28nm的Maxwell,继续在SM上大刀阔斧闹改革,将192SP降低为128SP,谓之曰SMM阵列

Maxwell 最新架构,官方设计是16组SM,2048SP,为旗舰GTX980,顺次阉割出GTX970,GTX960。

特别版,GTX TitanX,24组SM,3072SP,较之TitanZ,阉掉了双精度浮点数支持。

TitanX是老黄在GTC 2015向DL界主推的一块民用卡,因为DL无需高精度浮点,用Tesla太奢侈。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int deviceCount;
cudaGetDeviceCount(&deviceCount);
int dev;
for (dev = ; dev < deviceCount; dev++)
{
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
if (dev == )
{
if (/*deviceProp.major==9999 && */deviceProp.minor = &&deviceProp.major==)
printf("\n"); }
printf("\nDevice%d:\"%s\"\n", dev, deviceProp.name);
printf("Total amount of global memory %u bytes\n", deviceProp.totalGlobalMem);
printf("Number of mltiprocessors %d\n", deviceProp.multiProcessorCount);
printf("Total amount of constant memory: %u bytes\n", deviceProp.totalConstMem);
printf("Total amount of shared memory per block %u bytes\n", deviceProp.sharedMemPerBlock);
printf("Total number of registers available per block: %d\n", deviceProp.regsPerBlock);
printf("Warp size %d\n", deviceProp.warpSize);
printf("Maximum number of threada per block: %d\n", deviceProp.maxThreadsPerBlock);
printf("Maximum sizes of each dimension of a block: %d x %d x %d\n", deviceProp.maxThreadsDim[],
deviceProp.maxThreadsDim[],
deviceProp.maxThreadsDim[]);
printf("Maximum size of each dimension of a grid: %d x %d x %d\n", deviceProp.maxGridSize[], deviceProp.maxGridSize[], deviceProp.maxGridSize[]);
printf("Maximum memory pitch : %u bytes\n", deviceProp.memPitch);
printf("Texture alignmemt %u bytes\n", deviceProp.texturePitchAlignment);
printf("Clock rate %.2f GHz\n", deviceProp.clockRate*1e-6f);
}
printf("\nTest PASSED\n");
getchar();
}

Comment:

deviceProp.name为GPU名字,如果没有GPU则会输出 Device Emulation 
deviceProp.totalGlobalMem返回的是全局储存器的大小,对大数据或一些大模型计算时显存大小必须大于数据大小,如图返回的是2GB的存储大小, 
deviceProp.multiProcessorCount返回的是设备中流多处理器(SM)的个数,流处理器(SP)的个数SM数×每个SM包含的SP数,其中帕斯卡为每个SM,64个SP,麦克斯韦为128个,开普勒为192个,费米为32个, 
deviceProp.totalConstMem返回的是常数储存器的大小,如同为64kB 
deviceProp.sharedMemPerBlock返回共享储存器的大小,共享存储器速度比全局储存器快, 
deviceProp.regsPerBlock返回寄存器的数目; 
deviceProp.warpSize返回线程束中线程多少; 
deviceProp.maxThreadsPerBlock返回一个block中最多可以有的线程数; 
deviceProp.maxThreadsDim[]返回block内3维度中各维度的最大值 
deviceProp.maxGridSize[]返回Grid内三维度中各维度的最大值; 
deviceProp.memPitch返回对显存访问时对齐时的pitch的最大值; 
deviceProp.texturePitchAlignment返回对纹理单元访问时对其参数的最大值; 
deviceProp.clockRate返回显存的频率;


附另一个可能是不错的链接,关于cuda programming:http://blog.csdn.net/augusdi/article/details/12833235

只看一些基础概念:

2.1 线程网格(Grid)、线程块(Block)、线程(Thread)、线程束(Warp)

2.1.1 内核函数

内核函数是并行计算中最基本的单元函数,其特点是:

统一的处理逻辑代码,分布并行掌控不同区域的数据,以此达到多区域数据联动并行执行。

NVIDIA为了CPU在逻辑上能调度GPU计算的函数,规定了统一的格式。

以__global__限定符为始,声明:__global__ void helloworld()。

__global__意思为,GPU执行,CPU调用

调用时,需要分配  <<<线程块,块内线程数>>>。

如执行helloword,使用1个线程块,块内使用256个线程,则

helloworld<<<,>>>

2.1.2 线程网格(Grid)

线程网格在编程时并不存在,它只是抽象上的并行网格体系。

不同种类的内核函数,每种内核函数调度数个的线程块,这数个线程块逻辑上被判为一个Grid。

2.1.3 线程块(Block)

线程块是一个3D结构,强调3D坐标系时,需要以dim3类型声明三维大小。

dim3是个结构体, 成员x、y、z,代表方向轴尺度。

如helloworld<<<dim3(1,1,1), 256>>>。

当然,大部分操作基本使用的是1D坐标系,线程块默认全部扩展到X轴上。

一般写成helloworld<<<1,256>>>。

通常在内核函数内,需要获取线程块编号,以便对数据集的不同区域处理,四大重要属性:

☻dim3 gridDim(不是指有多少Grid,而是指一个Grid有多少Block)

☻dim3 blockDim(不是指有多少Block,而是指一个Block有多少Thread)

☻dim3 blockIdx

☻dim3 threadIdx

对于1D坐标系,有int tid= (blockDim.x*blockIdx.x) + threadIdx.x;

tid指明当前线程的编号,是内核函数里最基本的控制变量。

int step=(blockDim.x * gridDim.x);

由于CUDA限制每个Block的线程数(2.0以上通常使用1024,以下通常使用512)

所以在常规元素分解模型中,通常把每个Block的线程数设置为常量(固定不动)

这时,有两个策略:

① 其一,不固定Block:

这种方法最为常用,由于CUDA对每个任务而言,对Block数量的限制很松,

如图:

这时候,可以采取为每个线程分配一个元素的方法,用

BLOCKS=(N+THREADS−1)/THREADSBLOCKS=(N+THREADS−1)/THREADS

算出一个动态的Block数量的需求,这时候,for(i=tid;i<N;i+=step)等效于for(i=tid;i<N;i+=1)

因为这个循环根本不会执行第二次。

① 其二,固定Block数量:

这时,这时候,为了跑完全部的N个元素,有些Thread会启动人工循环。

i+=step会将元素坐标继续跳转,因为N必然大于step,你不能用+1来取剩余的元素吧?

这两种方法本质上是等效的,由于在物理执行时,同时并行线程最多大概是3072,

几百万、甚至几千万的Block会被CUDA扔到等待队列里,由CUDA自己安排自动循环,

有时甚至比你的人工循环更高效,所以,通常用①的方法,为了保持写法一致,step也会作为默认跳转量。

2.1.4 线程(Thread)

CUDA逻辑体系里最基本的执行单位,等效于CPU的线程。

内核函数一旦被指明了线程块大小,线程大小后,每个线程就分配到了一个内核函数的副本。

区别这些的线程的唯一方法就是线程编号tid,通过tid,让不同线程窥视数据集的不同部分。

用相同的逻辑代码,执行数据空间的不同子集。

2.1.5 线程束(Warp)

线程束对用户透明,它是NVIDIA强行规定的。目前显卡都固定为32。

逻辑上,线程束将32个线程编为一组。

一般微机系统,如8086,它的访存模式是串行的。每一个总线周期,吞一个字节进来。

NVIDIA的GPU在一个总线周期内,能够最大吞32*4=128字节。

前提是当个线程束内的线程,逐序访问显存,这特别需要设计数据存储形式。

使用线程束的目的是掩盖单个总线周期过长的问题,通常要跑500~600个T周期。


一般来说,一个CUDA程序必然少不了以下三步:

cudaMalloc:创建新的动态显存堆

cudaMemcpy:将主机(Host)内存复制到设备(Device)显存

☻显存处理完之后,cudaMemcpy:设备(Device)显存复制回主机(Host)内存,释放显存cudaFree

其中第三步最容易遗忘。要知道,CPU最后是无法使用显存中的数据的。

一个例子:

/* GPU版HelloWorld,主要目的是演示CUDA基本程序框架:
*☻ 将HelloWorld复制进显存
*☻ 让GPU完成strcpy函数
*☻ 将显存中的HelloWorld转回内存,并且打印
*/ /****kernel.cu****/
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
__global__ void cudaStrcpy(char *des, char *src) /*内核函数*/
{
while ((*src) != '\0') *des++ = *src++;
*des = '\0';
} /****gpu_helloworld.cu****/
#include "device.cu"
#include "kernel.cu"
#include "cstring"
void helloworld(char *str1, char *str2)
{
InitCUDA();
char *dev_str1=, *dev_str2=;
int size = strlen(str1) + ;
cudaMalloc((void**)&dev_str1, size); /*cuda系函数必须放在cu文件里*/
cudaMalloc
((void**)&dev_str2, size);
cudaMemcpy(dev_str1, str1, size,cudaMemcpyHostToDevice);
cudaStrcpy<<<,>>>(dev_str2, dev_str1); /*单线程块、单线程*/
cudaMemcpy
(str2, dev_str1, size, cudaMemcpyDeviceToHost);
} /****main.cpp****/
#include "cstdio"
#include "cstring"
extern void helloworld(char *str1, char *str2);
int main()
{
char src[] = "HelloWorld with CUDA";
char *des = new char[strlen(src)+];
helloworld(src, des);
printf("%s\n", des);
}

另一个例子:

/* 向量加法是CUDA 7.0在VS中提供的样例模板,演示了并行算法的经典trick:循环消除。
*利用单个线程块中,多个线程并发执行,来消除循环。
*时间复杂度估计,不能简单从O(n)迁移到O(1),因为GPU同时并行量存在限制。
*即便是Kepler架构中拥有192SP的SM阵列,理论同时并行量也不过是2048。
*/ /****kernel.cu****/
__global__ void kernel_plus(int *a, int *b, int *c)
{
int x = threadIdx.x;
c[x] = a[x] + b[x];
} /****gpu_vectoradd.cu****/
void vectorAdd(int *a, int *b, int *c,int size)
{
if (!InitCUDA()) return;
int *dev_a = , *dev_b = , *dev_c = ;
cudaMalloc((void**)&dev_a, size*sizeof(int));
cudaMalloc((void**)&dev_b, size*sizeof(int));
cudaMalloc((void**)&dev_c, size*sizeof(int));
cudaMemcpy(dev_a, a, size*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, size*sizeof(int), cudaMemcpyHostToDevice);
kernel_plus << <, size >> >(dev_a, dev_b, dev_c);
cudaMemcpy(c, dev_c, size*sizeof(int), cudaMemcpyDeviceToHost);
} /****main.cpp****/
extern void vectorAdd(int *a, int *b, int *c, int size);
int main()
{
int a[] = { , , , , }, b[] = { , , , , }, c[] = { };
vectorAdd(a, b, c,);
printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",
c[], c[], c[], c[], c[]);
}

Ref: http://blog.csdn.net/qiexingqieying/article/details/51734347

首先对这些框架进行总览。

库名称

开发语言

速度

灵活性

文档

适合模型

平台

上手难易

Caffe

c++/cuda

一般

全面

CNN

所有系统

中等

TensorFlow

c++/cuda/Python

中等

中等

CNN/RNN

Linux, OSX

MXNet

c++/cuda

全面

CNN

所有系统

中等

Torch

c/lua/cuda

全面

CNN/RNN

Linux, OSX

中等

Theano

python/c++/cuda

中等

中等

CNN/RNN

Linux, OSX

接下来将对这些框架进行分别介绍。

Caffe

第一个主流的工业级深度学习工具。
它开始于2013年底,由UC Berkely的Yangqing Jia老师编写和维护的具有出色的卷积神经网络实现。在计算机视觉领域Caffe依然是最流行的工具包。
它有很多扩展,但是由于一些遗留的架构问题,不够灵活且对递归网络和语言建模的支持很差。
 

TensorFlow

Google开源的其第二代深度学习技术——被使用在Google搜索、图像识别以及邮箱的深度学习框架。
是一个理想的RNN(递归神经网络)API和实现,TensorFlow使用了向量运算的符号图方法,使得新网络的指定变得相当容易,支持快速开发。
缺点是速度慢,内存占用较大。(比如相对于Torch)
 

MXNet

是李沐和陈天奇等各路英雄豪杰打造的开源深度学习框架,是分布式机器学习通用工具包DMLC 的重要组成部分。
它注重灵活性和效率,文档也非常的详细,同时强调提高内存使用的效率,甚至能在智能手机上运行诸如图像识别等任务。
 
Torch
Facebook力推的深度学习框架,主要开发语言是C和Lua。
有较好的灵活性和速度。
它实现并且优化了基本的计算单元,使用者可以很简单地在此基础上实现自己的算法,不用浪费精力在计算优化上面。核心的计算单元使用C或者cuda做了很好的优化。在此基础之上,使用lua构建了常见的模型。
缺点是接口为lua语言,需要一点时间来学习。
 
Theano
2008年诞生于蒙特利尔理工学院,主要开发语言是Python。
Theano派生出了大量深度学习Python软件包,最著名的包括BlocksKeras
Theano的最大特点是非常的灵活,适合做学术研究的实验,且对递归网络和语言建模有较好的支持,缺点是速度较慢。
 
Finally, 到此位置,应该对DL TOOL有了一定的理解。
 

我需要一台DIY的Deep Learning Workstation.

Goto: [GPU] DIY for Deep Learning Workstation

[GPU] CUDA for Deep Learning, why?的更多相关文章

  1. [GPU] DIY for Deep Learning Workstation

    Link: jcjohnson/cnn-benchmarks Ref: Build a super fast deep learning machine for under $1,000 Graphi ...

  2. TVM优化Deep Learning GPU算子

    TVM优化Deep Learning GPU算子 高效的深度学习算子是深度学习系统的核心.通常,这些算子很难优化,需要HPC专家付出巨大的努力. 端到端张量IR / DSL堆栈TVM使这一过程变得更加 ...

  3. Google Colab 免费的谷歌GPU for deep learning

    Who wants to use a free GPU for deep learning?Google Colab is a free cloud service and now it suppor ...

  4. 【深度学习Deep Learning】资料大全

    最近在学深度学习相关的东西,在网上搜集到了一些不错的资料,现在汇总一下: Free Online Books  by Yoshua Bengio, Ian Goodfellow and Aaron C ...

  5. (转) Deep Learning Resources

    转自:http://www.jeremydjacksonphd.com/category/deep-learning/ Deep Learning Resources Posted on May 13 ...

  6. Top Deep Learning Projects in github

    Top Deep Learning Projects A list of popular github projects related to deep learning (ranked by sta ...

  7. (转)分布式深度学习系统构建 简介 Distributed Deep Learning

    HOME ABOUT CONTACT SUBSCRIBE VIA RSS   DEEP LEARNING FOR ENTERPRISE Distributed Deep Learning, Part ...

  8. Deep Learning and Shallow Learning

    Deep Learning and Shallow Learning 由于 Deep Learning 现在如火如荼的势头,在各种领域逐渐占据 state-of-the-art 的地位,上个学期在一门 ...

  9. A Full Hardware Guide to Deep Learning

    A Full Hardware Guide to Deep Learning Deep Learning is very computationally intensive, so you will ...

随机推荐

  1. sql sever读取写入Excel总结

    主要用到openrowset,opendatasource系统函数,这两个函数任意一个都能完成任务 用这种方法可以实现Excel和sqlserver表之间的相互导入导出. 如果使用openrowset ...

  2. [转]css选择器优先级深入理解

    转载自:http://www.jb51.net/css/67029.html 一.基础选择器 css基础选择器有标签选择器.类选择器.id选择器.通用选择器 1.标签选择器 每个html页面都由很多个 ...

  3. 【转】c#的逆向工程-IL指令集

    转载自:http://www.cnblogs.com/davyjiang/articles/1337400.html 一些 IL 语言解释: 跳转指令集合Beq 如果两个值相等,则将控制转移到目标指令 ...

  4. 手动释放linux内存cache

    总有很多朋友对于Linux的内存管理有疑问,之前一篇linux下的内存管理方式似乎也没能清除大家的疑虑.而在新版核心中,似乎对这个问题提供了新的解决方法,特转出来给大家参考一下.最后,还附上我对这方法 ...

  5. 批量设置ssh无密码登陆脚本

    最近要给集群设置ssh无密码登陆,如果需要手动设置这个无密码登陆,所以在网上找了几个脚本,亲测下面这个好使,并且设置比较简单. 需要用root账户执行,我也是要给root账户设置无密码登陆. 首先我们 ...

  6. java replaceall 使用正则表达式替换单等号,不替换其他相关的等号。

    写项目需要将公式配置到数据库中,取出后根据公式规则进行比较,由于公式的等于是用单等号,在java中无法直接使用,故需要将单等号替换成双等号,单又不能影响大于等于以及其他形式.故果断选择正则表达式替换. ...

  7. 百度地图Api进阶教程-实例高级操作8.html

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. java对mongoDB的基本操作 ,游标使用

    package com.mongodb.text; import java.net.UnknownHostException; import java.util.List; import org.bs ...

  9. Html5學習重點清單

    SVG webSQL 數據庫 SSE 服務推送 MathML 基於xml語法 Web 存储 webSockets通信 canvas 畫布操作 音頻和視頻 地理位置 Geolocation API We ...

  10. thinkphp中memcache的用法实例

    本文实例讲述了thinkphp中memcache的用法.分享给大家供大家参考.具体分析如下: 1.下载并安装memcache ① window下安装memcache. 下载memcached.exe ...