2018-07-04 20:08:23 gxc_8311 阅读数 1580
  • 3D游戏引擎之GPU渲染(DX篇)

    本次课程主要是针对3D游戏引擎内部的GPU之Shader渲染处理,告诉大家引擎底层是如何与Shader代码结合的。从基本的灯光渲染,环境渲染到后的Bloom渲染。

    12032 人正在学习 去看看 姜雪伟

最近深度学习十分火爆,作为一个程序员当然要多学习一下深度学习这种酷炫的新技能啦。现在Google的Tensorflow已经把深度学习需要的一些常用计算封装成了函数库,已经成为了事实上的深度计算标准。本来想在自己的电脑上跑一下Tensorflow的mnist手写数字识别demo,折腾了半天装好了Tensorflow之后想着终于可以高高兴兴的跑一下mnist_deep.py了。

但是跑起来之后发现......真是太TM的慢了!!


每迭代一次要花4-5秒的时间,老子的电脑可是带独立显卡GT 750M的MacBook Pro啊!这速度等它训练完收敛我估计我可以读完一本书了......

所以我开始在网上找有没有GPU加速的云主机可以便宜点儿租来跑一下这些深度计算,找了半天发现网上有很多可以跑深度学习的虚拟主机,但每一个我上去都要重新装一下环境。而且只要开机就收我每个小时十几二十块的费用,我这装个环境至少也得十几分钟……这几块钱就白送给人家了......

直到我发现了这个......

极客云

http://www.jikecloud.net/

打开之后就会看到网站对云主机的介绍,感兴趣的可以点击“如何使用”来查看帮助文档。


如果是新用户注册,可以点击“现在注册”进入注册页面。

嗯嗯......这个验证码真TM的炫动......

注册之后就来到了“我的云主机”页面,点创建实例跳转到创建页面。

在“创建实例”页面可以选择你需要的机型来创建虚拟主机,现在无论是注册还是登陆都会送很多的代金券。实际使用价格还是挺低的,经济实惠。

点击“创建”按钮并等待片刻后,会回到“我的云主机”页面,此时可以看到创建的云主机已经显示在列表界面里面了。

在列表界面有Jupyter Notebook的链接。点这个链接就可以进入Jupyter Notebook了,使用起来很方便。

我们跑一下mnist手写数字的训练Demo,点击文件的链接可以显示文件的内容。

在文件内容页面复制好代码以后,点屏幕左上角的那个图标回到Jupyter首页。

回到首页后点右边的New下拉菜单,选择新建一个Python 3的Notebook。

创建好Notebook之后,在图示处粘贴刚刚复制的代码。

复制好代码之后,就可以点击Run运行啦。

可以看到点击Run之后,在页面下方就出现了程序的log,这说明我们的程序已经欢快的运行起来啦~

上面那种方式其实是给大家演示了一下在Jupyter Notebook里面写程序并且运行程序的方法。如果你已经上传好了几个python文件的话,可以在主页点完的New下拉菜单新建一个Python 3的Notebook之后,运行 %run mnist_deep.py 来执行python文件。

看,它这就欢快的跑起来啦~

总结:

新版的极客云深度学习实例,既装好了所有的深度学习框架,又新加入了Jupyter Notebook方便使用。实现了零设置执行深度学习的程序,想了解更多细节可以去访问极客云的网站:http://www.jikecloud.net/


2017-08-21 12:01:14 u010159842 阅读数 1068
  • 3D游戏引擎之GPU渲染(DX篇)

    本次课程主要是针对3D游戏引擎内部的GPU之Shader渲染处理,告诉大家引擎底层是如何与Shader代码结合的。从基本的灯光渲染,环境渲染到后的Bloom渲染。

    12032 人正在学习 去看看 姜雪伟

这是《使用腾讯云GPU学习深度学习》系列文章的第四篇,主要举例介绍了深度学习计算过程中的一些数据预处理方法。本系列文章主要介绍如何使用 腾讯云GPU服务器 进行深度学习运算,前面主要介绍原理部分,后期则以实践为主。

往期内容:
使用腾讯云 GPU 学习深度学习系列之一:传统机器学习的回顾

使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理

使用腾讯云 GPU 学习深度学习系列之三:搭建深度神经网络

上一节,我们基于Keras设计了一个用于 CIFAR-10 数据集的深度学习网络。我们的代码主要包括以下部分:

  • 批量输入模块
  • 各种深度学习零件搭建的深度神经网络
  • 凸优化模块
  • 模型的训练与评估

我们注意到,批量输入模块中,实际上就是运用了一个生成器,用来批量读取图片文件,保存成矩阵,直接用于深度神经网络的训练。由于在训练的过程中,图片的特征,是由卷积神经网络自动获取的,因此深度学习通常被认为是一种 端对端(End to end) 的训练方式,期间不需要人为的过多干预。

但是,在实际的运用过程中,这一条并不总是成立。深度神经网络在某些特定的情况下,是需要使用某些特定方法,在批量输入模块之前,对输入数据进行预处理,并且处理结果会极大的改善。

本讲将主要介绍几种数据预处理方法,并且通过这些预处理方法,进行特征提取,提升模型的准确性。

1. 结合传统数据处理方法的特征提取

这一部分我们举医学影像学的一个例子,以 Kaggle 社区第三届数据科学杯比赛的肺部 CT 扫描结节数据为例,来说明如何进行数据的前处理。以下代码改编自该 kaggle 比赛的官方指导教程,主要是特异性的提取 CT 影像图片在肺部的区域的扫描结果,屏蔽无关区域,进而对屏蔽其他区域后的结果,使用深度学习方法进行进一步分析。

屏蔽的程序本身其实并未用到深度学习相关内容,这里主要使用了skimage库。下面我们详细介绍一下具体方法。

第一步,读取医学影像图像。这里以 LUNA16数据集 中的1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636438705059720603192 这张CT 影像数据为例,这张片子可以在这里下载,然后解压缩,用下面的代码分析。其他片子请在 LUNA16 数据集)下载:

from __future__ import print_function, division

import numpy as np
import os
import csv
from glob import glob
import pandas as pd
import numpy as np
import SimpleITK as sitk

from skimage import measure,morphology
from sklearn.cluster import KMeans
from skimage.transform import resize
import matplotlib.pyplot as plt
import seaborn as sns

from glob import glob

try:
    from tqdm import tqdm # long waits are not fun
except:
    print('TQDM does make much nicer wait bars...')
    tqdm = lambda x: x

def make_mask(center,diam,z,width,height,spacing,origin):
    '''
    Center : centers of circles px -- list of coordinates x,y,z
    diam : diameters of circles px -- diameter
    widthXheight : pixel dim of image
    spacing = mm/px conversion rate np array x,y,z
    origin = x,y,z mm np.array
    z = z position of slice in world coordinates mm
    '''
    mask = np.zeros([height,width]) # 0's everywhere except nodule swapping x,y to match img
    #convert to nodule space from world coordinates

    # Defining the voxel range in which the nodule falls
    v_center = (center-origin)/spacing
    v_diam = int(diam/spacing[0]+5)
    v_xmin = np.max([0,int(v_center[0]-v_diam)-5])
    v_xmax = np.min([width-1,int(v_center[0]+v_diam)+5])
    v_ymin = np.max([0,int(v_center[1]-v_diam)-5])
    v_ymax = np.min([height-1,int(v_center[1]+v_diam)+5])

    v_xrange = range(v_xmin,v_xmax+1)
    v_yrange = range(v_ymin,v_ymax+1)

    # Convert back to world coordinates for distance calculation
    x_data = [x*spacing[0]+origin[0] for x in range(width)]
    y_data = [x*spacing[1]+origin[1] for x in range(height)]

    # Fill in 1 within sphere around nodule
    for v_x in v_xrange:
        for v_y in v_yrange:
            p_x = spacing[0]*v_x + origin[0]
            p_y = spacing[1]*v_y + origin[1]
            if np.linalg.norm(center-np.array([p_x,p_y,z]))<=diam:
                mask[int((p_y-origin[1])/spacing[1]),int((p_x-origin[0])/spacing[0])] = 1.0
    return(mask)

def matrix2int16(matrix):
    '''
    matrix must be a numpy array NXN
    Returns uint16 version
    '''
    m_min= np.min(matrix)
    m_max= np.max(matrix)
    matrix = matrix-m_min
    return(np.array(np.rint( (matrix-m_min)/float(m_max-m_min) * 65535.0),dtype=np.uint16))

df_node = pd.read_csv('./annotation.csv')
for fcount, img_file in enumerate(tqdm(df_node['seriesuid'])):
    mini_df = df_node[df_node["seriesuid"]==img_file] #get all nodules associate with file
    if mini_df.shape[0]>0: # some files may not have a nodule--skipping those
        # load the data once
        itk_img = sitk.ReadImage("%s.mhd" % img_file)
        img_array = sitk.GetArrayFromImage(itk_img) # indexes are z,y,x (notice the ordering)
        num_z, height, width = img_array.shape        #heightXwidth constitute the transverse plane
        origin = np.array(itk_img.GetOrigin())      # x,y,z  Origin in world coordinates (mm)
        spacing = np.array(itk_img.GetSpacing())    # spacing of voxels in world coor. (mm)
        # go through all nodes (why just the biggest?)
        for node_idx, cur_row in mini_df.iterrows():       
            node_x = cur_row["coordX"]
            node_y = cur_row["coordY"]
            node_z = cur_row["coordZ"]
            diam = cur_row["diameter_mm"]
            # just keep 3 slices
            imgs = np.ndarray([3,height,width],dtype=np.float32)
            masks = np.ndarray([3,height,width],dtype=np.uint8)
            center = np.array([node_x, node_y, node_z])   # nodule center
            v_center = np.rint((center-origin)/spacing)  # nodule center in voxel space (still x,y,z ordering)
            for i, i_z in enumerate(np.arange(int(v_center[2])-1,
                             int(v_center[2])+2).clip(0, num_z-1)): # clip prevents going out of bounds in Z
                mask = make_mask(center, diam, i_z*spacing[2]+origin[2],
                                     width, height, spacing, origin)
                masks[i] = mask
                imgs[i] = img_array[i_z]
            np.save(os.path.join("./images_%04d_%04d.npy" % (fcount,node_idx)),imgs)
            np.save(os.path.join("./masks_%04d_%04d.npy"  % (fcount,node_idx)),masks)

简单解释下,首先,CT 影像是一个三维的图像,以三维矩阵的形式保存在1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636438705059720603192.raw 这个文件中,.mhd文件则保存了影像文件的基本信息。具体而言,annotation.csv 文件中,图像中结节的坐标是:

x seriesuid coordX coordY coordZ diameter_mm
0 1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636... 56.208405 86.343413 -115.867579 23.350644

这里结节坐标的 coordX~Z 都是物理坐标, .mhd文件保存的,就是从这些物理坐标到 .raw文件中矩阵坐标的映射。于是上面整个函数,其实就是在从 CT 影像仪器的原始文件读取信息,转换物理坐标为矩阵坐标,并且 将结节附近的CT 切片存储成对应的 python 矩阵,用来进行进一步的分析。

然后,我们看一下读取的结果。可见输入文件中标注的结节就在右下方。

img_file = "./images_0000_0000.npy"
imgs_to_process = np.load(img_file).astype(np.float64)

fig = plt.figure(figsize=(12,4))
for i in range(3):
    ax = fig.add_subplot(1,3,i+1)
    ax.imshow(imgs_to_process[i,:,:], 'bone')
    ax.set_axis_off()

可见图中,除了中间亮度较低的肺部,还有亮度较高的脊柱、肋骨,以及肌肉、脂肪等组织。我们的一个思路,就是 留下暗的区域,去掉亮的区域。当然这里,亮度多高才算亮?这个我们可以对一张图中所有像素点的亮度做概率密度分布,然后用 Kmeans 算法,找出这个明暗分解的阈值(下文图中左上角):

i = 0
img = imgs_to_process[i]

#Standardize the pixel values
mean = np.mean(img)
std = np.std(img)
img = img-mean
img = img/std

# Find the average pixel value near the lungs
#         to renormalize washed out images
middle = img[100:400,100:400]
mean = np.mean(middle)  
max = np.max(img)
min = np.min(img)

# To improve threshold finding, I'm moving the
#         underflow and overflow on the pixel spectrum
img[img==max]=mean
img[img==min]=mean


# Using Kmeans to separate foreground (radio-opaque tissue)
#     and background (radio transparent tissue ie lungs)
# Doing this only on the center of the image to avoid
#     the non-tissue parts of the image as much as possible
kmeans = KMeans(n_clusters=2).fit(np.reshape(middle,[np.prod(middle.shape),1]))
centers = sorted(kmeans.cluster_centers_.flatten())
threshold = np.mean(centers)
thresh_img = np.where(img<threshold,1.0,0.0)  # threshold the image

然后使用 skimage 工具包。 skimage 是python一种传统图像处理的工具,我们这里,主要使用这个工具包,增强图像的轮廓,去除图像的细节,进而根据图像的轮廓信息,进行图像的分割,得到目标区域(Region of Interests, ROI)。

# 对一张图中所有像素点的亮度做概率密度分布, 用竖线标注阈值所在
fig = plt.figure(figsize=(8,12))
ax1 = fig.add_subplot(321)
sns.distplot(middle.ravel(), ax=ax1)
ax1.vlines(x=threshold, ymax=10, ymin=0)
ax1.set_title('Threshold: %1.2F' % threshold)
ax1.set_xticklabels([])

# 展示阈值对图像切割的结果。小于阈值的点标注为1,白色。大于阈值的点标注为0,黑色。
ax2 = fig.add_subplot(322)
ax2.imshow(thresh_img, "gray")
ax2.set_axis_off()
ax2.set_title('Step1, using threshold as cutoff')

# 增大黑色部分(非ROI)的区域,使之尽可能的连在一起
eroded = morphology.erosion(thresh_img,np.ones([4,4]))
ax3 = fig.add_subplot(323)
ax3.imshow(eroded, "gray")
ax3.set_axis_off()
ax3.set_title('Step2,  erosion shrinks bright\nregions and enlarges dark regions.')

# 增大白色部分(ROI)的区域,尽可能的消除面积较小的黑色区域
dilation = morphology.dilation(eroded,np.ones([10,10]))
ax4 = fig.add_subplot(324)
ax4.imshow(dilation, "gray")
ax4.set_axis_off()
ax4.set_title('Step3,  dilation shrinks dark\nregions and enlarges bright regions.')

# 上一张图中共有三片连续区域,即最外层的体外区域,内部的肺部区域,以及二者之间的身体轮廓区域。这里将其分别标出
labels = measure.label(dilation)
ax5 = fig.add_subplot(325)
ax5.imshow(labels, "gray")
#ax5.set_axis_off()
ax5.set_title('Step4, label connected regions\n of an integer array.')


# 提取regions 信息,这张图片的 region的 bbox位置分别在 [[0,0,512,512],[141, 86, 396, 404]],
#   分别对应 体外+轮廓 以及 肺部区域的左上角、右下角坐标。
#   于是这里通过区域的宽度 B[2]-B[0]、高度 B[3]-B[1]
#   以及距离图片上下的距离  B[0]>40 and B[2]<472,
#   最终保留需要的区域。
regions = measure.regionprops(labels)
good_labels = []
for prop in regions:
    B = prop.bbox
    if B[2]-B[0]<475 and B[3]-B[1]<475 and B[0]>40 and B[2]<472:
        good_labels.append(prop.label)

mask = np.zeros_like(labels)
for N in good_labels:
    mask = mask + np.where(labels==N,1,0)

mask = morphology.dilation(mask,np.ones([10,10])) # one last dilation

ax6 = fig.add_subplot(326)
ax6.imshow(mask, "gray")
ax6.set_axis_off()
ax6.set_title('Step5, remain the region of interests.')

最后再看一下提取的效果如何:

fig = plt.figure(figsize=(8,4))

ax1 = fig.add_subplot(1,2,1)
ax1.imshow(imgs_to_process[0,:,:], 'bone')
ax1.set_axis_off()
ax1.set_title("Raw CT image")

ax2 = fig.add_subplot(1,2,2)
ax2.imshow(imgs_to_process[0,:,:]*mask, 'bone')
ax2.set_axis_off()
ax2.set_title("Pre-processed Images with\nregion of interest in lung")

右图将进一步的放入深度学习模型,进行肺部结节的进一步检测。

2. 结合深度学习技术的特征提取增强

除了通过传统手段进行数据预先处理,我们同样可以使用深度学习技术进行这一步骤。

可能大家对手写数字识别数据集(MNIST)非常熟悉,Tensorflow 官网就有教程,指导如何搭建卷积神经网络,训练一个准确率高达 99.2% 的模型。

png

但实际运用过程中,我们会发现其实 MNIST 数据集其实书写的比较工整,于是我们就考虑到,对于比较潦草的书写,直接训练卷积神经网络,是否是最好的选择?是否可以将“草书”字体的数字,变得正规一点,然后放进卷积神经网络训练?于是我们利用一个“草书”版的 MNIST 数据集,来介绍一下spatial_transform 模块:

首先需要下载这个“草书”版的手写数字集:

wget https://github.com/daviddao/spatial-transformer-tensorflow/raw/master/data/mnist_sequence1_sample_5distortions5x5.npz

画风如下,明显凌乱了许多,但其实人还是可以看懂,所以我们可以尝试使用深度神经网络来解决。
png

我们开始分析数据。首先读数据:

import tensorflow as tf
# https://github.com/tensorflow/models/tree/master/transformer
from spatial_transformer import transformer  
import numpy as np
from tf_utils import weight_variable, bias_variable, dense_to_one_hot
import matplotlib.pyplot as plt
from keras.backend.tensorflow_backend import set_session

np.random.seed(0)
tf.set_random_seed(0)

config = tf.ConfigProto()
config.gpu_options.allow_growth=True
set_session(tf.Session(config=config))
%matplotlib inline

mnist_cluttered = np.load('./mnist_sequence1_sample_5distortions5x5.npz')

X_train = mnist_cluttered['X_train']
y_train = mnist_cluttered['y_train']
X_valid = mnist_cluttered['X_valid']
y_valid = mnist_cluttered['y_valid']
X_test = mnist_cluttered['X_test']
y_test = mnist_cluttered['y_test']

Y_train = dense_to_one_hot(y_train, n_classes=10)
Y_valid = dense_to_one_hot(y_valid, n_classes=10)
Y_test = dense_to_one_hot(y_test, n_classes=10)

初始化参数,然后直接得到一批原始数据,放入xout

x = tf.placeholder(tf.float32, [None, 1600])
keep_prob = tf.placeholder(tf.float32)

iter_per_epoch = 100
n_epochs = 500
train_size = 10000
indices = np.linspace(0, 10000 - 1, iter_per_epoch)
indices = indices.astype('int')
iter_i = 0

batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
x_tensor = tf.reshape(x, [-1, 40, 40, 1])

sess = tf.Session()
sess.run(tf.global_variables_initializer())
xout = sess.run(x_tensor, feed_dict={x: batch_xs})

然后搭建一个 spatial_transform 网络。网络结构如下图:

png

x = tf.placeholder(tf.float32, [None, 1600])
y = tf.placeholder(tf.float32, [None, 10])

x_tensor = tf.reshape(x, [-1, 40, 40, 1])
W_fc_loc1 = weight_variable([1600, 20])
b_fc_loc1 = bias_variable([20])

W_fc_loc2 = weight_variable([20, 6])
initial = np.array([[1., 0, 0], [0, 1., 0]])
initial = initial.astype('float32')
initial = initial.flatten()
b_fc_loc2 = tf.Variable(initial_value=initial, name='b_fc_loc2')

# %% Define the two layer localisation network
h_fc_loc1 = tf.nn.tanh(tf.matmul(x, W_fc_loc1) + b_fc_loc1)

# %% We can add dropout for regularizing and to reduce overfitting like so:
keep_prob = tf.placeholder(tf.float32)
h_fc_loc1_drop = tf.nn.dropout(h_fc_loc1, keep_prob)

# %% Second layer
h_fc_loc2 = tf.nn.tanh(tf.matmul(h_fc_loc1_drop, W_fc_loc2) + b_fc_loc2)

# %% We'll create a spatial transformer module to identify discriminative
# %% patches
out_size = (40, 40)
h_trans = transformer(x_tensor, h_fc_loc2, out_size)

再得到一批经过变换后的数据,放入xtransOut

iter_i = 0
batch_xs = X_train[0:101]
batch_ys = Y_train[0:101]

sess = tf.Session()
sess.run(tf.global_variables_initializer())

xtransOut = sess.run(h_trans,
                            feed_dict={
                                x: batch_xs,
                                y: batch_ys,
                                keep_prob: 1.0
})

展示两批数据。上面一行是原始数据,下面一行是变换后的数据。可见数字在局部被放大,有的数字写的歪的被自动正了过来:

fig = plt.figure(figsize=(10,2))

for idx in range(10):
    ax1 = fig.add_subplot(2,10,idx+1)
    ax2 = fig.add_subplot(2,10,idx+11)

    ax1.imshow(xout[idx,:,:,0], "gray")
    ax2.imshow(xtransOut[idx,:,:,0], "gray")
    ax1.set_axis_off()
    ax2.set_axis_off()
    ax1.set_title(np.argmax(batch_ys, axis=1)[idx])
    ax2.set_title(np.argmax(batch_ys, axis=1)[idx])

也就是说,通过 spatial_transform 层,对同一批输入数据的参数学习,我们最后实际上得到了一个坐标的映射 Grid generator
$T_{\theta(G)}$ ,可以将一个倾斜的、“草书”书写的数字,变得更正一点。

png

接下来,我们构建一个卷积神经网络:

x = tf.placeholder(tf.float32, [None, 1600])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)

def Networks(x,keep_prob, SpatialTrans=True):
    x_tensor = tf.reshape(x, [-1, 40, 40, 1])
    W_fc_loc1 = weight_variable([1600, 20])
    b_fc_loc1 = bias_variable([20])

    W_fc_loc2 = weight_variable([20, 6])
    initial = np.array([[1., 0, 0], [0, 1., 0]])
    initial = initial.astype('float32')
    initial = initial.flatten()
    b_fc_loc2 = tf.Variable(initial_value=initial, name='b_fc_loc2')

    # %% Define the two layer localisation network
    h_fc_loc1 = tf.nn.tanh(tf.matmul(x, W_fc_loc1) + b_fc_loc1)
    # %% We can add dropout for regularizing and to reduce overfitting like so:

    h_fc_loc1_drop = tf.nn.dropout(h_fc_loc1, keep_prob)
    # %% Second layer
    h_fc_loc2 = tf.nn.tanh(tf.matmul(h_fc_loc1_drop, W_fc_loc2) + b_fc_loc2)

    # %% We'll create a spatial transformer module to identify discriminative
    # %% patches
    out_size = (40, 40)
    h_trans = transformer(x_tensor, h_fc_loc2, out_size)

    # %% We'll setup the first convolutional layer
    # Weight matrix is [height x width x input_channels x output_channels]
    filter_size = 3
    n_filters_1 = 16
    W_conv1 = weight_variable([filter_size, filter_size, 1, n_filters_1])

    # %% Bias is [output_channels]
    b_conv1 = bias_variable([n_filters_1])

    # %% Now we can build a graph which does the first layer of convolution:
    # we define our stride as batch x height x width x channels
    # instead of pooling, we use strides of 2 and more layers
    # with smaller filters.
    if SpatialTrans:
        h_conv1 = tf.nn.relu(
            tf.nn.conv2d(input=h_trans,
                         filter=W_conv1,
                         strides=[1, 2, 2, 1],
                         padding='SAME') +
            b_conv1)
    else:
        h_conv1 = tf.nn.relu(
            tf.nn.conv2d(input=x_tensor,
                         filter=W_conv1,
                         strides=[1, 2, 2, 1],
                         padding='SAME') +
            b_conv1)

    # %% And just like the first layer, add additional layers to create
    # a deep net
    n_filters_2 = 16
    W_conv2 = weight_variable([filter_size, filter_size, n_filters_1, n_filters_2])
    b_conv2 = bias_variable([n_filters_2])
    h_conv2 = tf.nn.relu(
        tf.nn.conv2d(input=h_conv1,
                     filter=W_conv2,
                     strides=[1, 2, 2, 1],
                     padding='SAME') +
        b_conv2)

    # %% We'll now reshape so we can connect to a fully-connected layer:
    h_conv2_flat = tf.reshape(h_conv2, [-1, 10 * 10 * n_filters_2])

    # %% Create a fully-connected layer:
    n_fc = 1024
    W_fc1 = weight_variable([10 * 10 * n_filters_2, n_fc])
    b_fc1 = bias_variable([n_fc])
    h_fc1 = tf.nn.relu(tf.matmul(h_conv2_flat, W_fc1) + b_fc1)

    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    # %% And finally our softmax layer:
    W_fc2 = weight_variable([n_fc, 10])
    b_fc2 = bias_variable([10])
    y_logits = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
    return y_logits


# %% We'll now train in minibatches and report accuracy, loss:
iter_per_epoch = 100
n_epochs = 100
train_size = 10000

indices = np.linspace(0, 10000 - 1, iter_per_epoch)
indices = indices.astype('int')

首先训练一个未经过变换的:

y_logits_F = Networks(x, keep_prob, SpatialTrans=False)
cross_entropy_F = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_logits_F, labels=y))
opt = tf.train.AdamOptimizer()
optimizer_F = opt.minimize(cross_entropy_F)
grads_F = opt.compute_gradients(cross_entropy_F, [b_fc_loc2])
correct_prediction_F = tf.equal(tf.argmax(y_logits_F, 1), tf.argmax(y, 1))
accuracy_F = tf.reduce_mean(tf.cast(correct_prediction_F, 'float'))

sessF = tf.Session()
sessF.run(tf.global_variables_initializer())

l_acc_F = []
for epoch_i in range(n_epochs):
    for iter_i in range(iter_per_epoch - 1):
        batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
        batch_ys = Y_train[indices[iter_i]:indices[iter_i+1]]
        sessF.run(optimizer_F, feed_dict={
            x: batch_xs, y: batch_ys, keep_prob: 0.8})

    acc = sessF.run(accuracy_F,
                                                     feed_dict={
                                                         x: X_valid,
                                                         y: Y_valid,
                                                         keep_prob: 1.0
                                                     })
    l_acc_F.append(acc)
    if epoch_i % 10 == 0:
        print('Accuracy (%d): ' % epoch_i + str(acc))
Accuracy (0): 0.151
Accuracy (10): 0.813
Accuracy (20): 0.832
Accuracy (30): 0.825
Accuracy (40): 0.833
Accuracy (50): 0.837
Accuracy (60): 0.832
Accuracy (70): 0.837
Accuracy (80): 0.833
Accuracy (90): 0.843

可见这个神经网络对直接输入变形数据效果不好。我们再训练一个进过变换的:

y_logits = Networks(x, keep_prob)
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_logits, labels=y))
opt = tf.train.AdamOptimizer()
optimizer = opt.minimize(cross_entropy)
grads = opt.compute_gradients(cross_entropy, [b_fc_loc2])
correct_prediction = tf.equal(tf.argmax(y_logits, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))

sess = tf.Session()
sess.run(tf.global_variables_initializer())

l_acc = []
for epoch_i in range(n_epochs):
    for iter_i in range(iter_per_epoch - 1):
        batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
        batch_ys = Y_train[indices[iter_i]:indices[iter_i+1]]
        sess.run(optimizer, feed_dict={
            x: batch_xs, y: batch_ys, keep_prob: 0.8})

    acc = sess.run(accuracy,
                                                     feed_dict={
                                                         x: X_valid,
                                                         y: Y_valid,
                                                         keep_prob: 1.0
                                                     })
    l_acc.append(acc)
    if epoch_i % 10 == 0:
        print('Accuracy (%d): ' % epoch_i + str(acc))

发现变换后正确率还可以接受:

Accuracy (0): 0.25
Accuracy (10): 0.92
Accuracy (20): 0.94
Accuracy (30): 0.955
Accuracy (40): 0.943
Accuracy (50): 0.944
Accuracy (60): 0.957
Accuracy (70): 0.948
Accuracy (80): 0.941
Accuracy (90): 0.948

画图比较正确率与训练次数

plt.plot(l_acc, label="Using Spatial Transform")
plt.plot(l_acc_F, label="Raw input")
plt.legend(loc=8)

可见 Spatial Transform 确实可以提升分类的正确率。

最后,我们专门提出来直接分类分错、Spatial Transform 后分类正确的数字。上面一行是直接预测的结果(错误),下面一行是转换后分类的结果:

通过 Spatial Transform,我们确实可以强化数据的特征,增加数据分类的准确性。

此外,Spatial Transform 除了可以识别“草书”字体的手写数字,同样在交通标志分类中表现优异,通过Spatial Transform 元件与 LeNet-5 网络的组合,Yann LeCun团队实现了42种交通标志分类99.1%准确性(笔者直接用LeNet-5发现准确率只有87%左右),文章地址Traffic Sign Recognition with Multi-Scale Convolutional Networks

png

目前腾讯云 GPU 服务器已经在5月27日盛大公测,本章代码也可以用较小的数据量、较低的nb_epoch在普通云服务器上尝试一下,但是随着处理运算量越来越大,必须租用 云GPU服务器 才可以快速算出结果。服务器的租用方式、价格,详情请见 腾讯云 GPU 云服务器今日全量上线!

2020-04-03 01:45:27 weixin_42588541 阅读数 9
  • 3D游戏引擎之GPU渲染(DX篇)

    本次课程主要是针对3D游戏引擎内部的GPU之Shader渲染处理,告诉大家引擎底层是如何与Shader代码结合的。从基本的灯光渲染,环境渲染到后的Bloom渲染。

    12032 人正在学习 去看看 姜雪伟

前言

  最近参加计算机视觉相关的比赛,发现笔记本的GPU已经无法承受庞大数据集的摧残,转而使用云GPU来跑代码,由于对Linux系统的不熟悉反复出了很多问题,至今终于配制好环境代码可以正常运行了,特此记录:

配置记录

  在查找资料时常常会找到很多过时或者不符合自己情况的代码,在自己写文的时候就把这些内容标清楚了,如果配置不同可以先弄清楚是否可迁移再运行

配置 版本
操作系统 Ubuntu 16.04.6 LTS 4.13.0-36-generic GNU/Linux
python 3.6.3
cuda 10.0

详细步骤

  我需求的环境为python == 3.6,pytorch == 1.1.0,缝缝补补,在看了很多网站之后,以下操作已经能够满足我的需求配置好环境,下面会将所有的信息来源和代码标示出来,需求不同的朋友可以做个借鉴,调整自己的设置

一、安装依赖

来源:https://www.jianshu.com/p/553f9237576c

sudo apt-get install python-dev
sudo apt-get install libffi-dev
sudo apt-get install libssl-dev
sudo apt-get install libxml2-dev
sudo apt-get install libxslt-dev
sudo apt-get install libsqlite3-dev
sudo apt-get install zlib1g-dev
sudo apt-get install libbz2-dev

二、安装python 3.6.3包

来源1:https://pylist.com/t/1576042471
来源2:https://cloud.tencent.com/developer/article/1146946

cd /opt
wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz
tar -xvf Python-3.6.3.tgz
cd Python-3.6.3
./configure
make
make install
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.6 2
update-alternatives --config python3
mv /usr/bin/python /usr/bin/python.bak
ln -s /usr/local/bin/python3 /usr/bin/python

三、安装pip

来源1:https://blog.csdn.net/little_stupid_child/article/details/82747227
来源2:https://blog.csdn.net/wangweiwells/article/details/88374070

sudo rm /usr/bin/lsb_release
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py --force-reinstall

四、更新jupyterlab内核

来源:https://blog.csdn.net/u012151283/article/details/54565467

pip3 install ipykernel
python -m ipykernel install

五、总结

  环境配置比较繁琐,但接下来要学习的东西还有更多更多,写下这些作为记录,也希望能帮到正在苦苦debug的你

2018-04-26 11:40:38 yunqiinsight 阅读数 610
  • 3D游戏引擎之GPU渲染(DX篇)

    本次课程主要是针对3D游戏引擎内部的GPU之Shader渲染处理,告诉大家引擎底层是如何与Shader代码结合的。从基本的灯光渲染,环境渲染到后的Bloom渲染。

    12032 人正在学习 去看看 姜雪伟

摘要: 本文根据实测数据,初步探讨了在弹性GPU云服务器上深度学习的性能模型,可帮助科学选择GPU实例的规格。

1 背景


  得益于GPU强大的计算能力,深度学习近年来在图像处理、语音识别、自然语言处理等领域取得了重大突破,GPU服务器几乎成了深度学习加速的标配。
  阿里云GPU云服务器在公有云上提供的弹性GPU服务,可以帮助用户快速用上GPU加速服务,并大大简化部署和运维的复杂度。如何提供一个合适的实例规格,从而以最高的性价比提供给深度学习客户,是我们需要考虑的一个问题,本文试图从CPU、内存、磁盘这三个角度对单机GPU云服务器的深度学习训练和预测的性能模型做了初步的分析,希望能对实例规格的选择提供一个科学的设计模型。
  下面是我们使用主流的几个开源深度学习框架在NVIDIA GPU上做的一些深度学习的测试。涉及NVCaffe、MXNet主流深度学习框架,测试了多个经典CNN网络在图像分类领域的训练和推理以及RNN网络在自然语言处理领域的训练。

2 训练测试


  我们使用NVCaffe、MXNet主流深度学习框架测试了图像分类领域和自然语言处理领域的训练模型。

2.1 图像分类
  我们使用NVCaffe、MXNet测试了图像分类领域的CNN网络的单GPU模型训练。
  NVCaffe和MXNet测试使用ImageNet ILSVRC2012数据集,训练图片1281167张,包含1000个分类,每个分类包含1000张左右的图片。

2.1.1 CPU+Memory

2.1.1.1 NVCaffe
  

NVCaffe是NVIDIA基于BVLC-Caffe针对NVIDIA GPU尤其是多GPU加速的开源深度学习框架。LMDB格式的ImageNet训练集大小为240GB ,验证集大小为9.4GB。
  我们使用NVcaffe对AlexNet、GoogLeNet、ResNet50、Vgg16四种经典卷积神经网络做了图像分类任务的模型训练测试。分别对比了不同vCPU和Memory配置下的训练性能。性能数据单位是Images/Second(每秒处理的图像张数)。图中标注为10000指的是迭代次数10000次,其它都是测试迭代次数为1000次。





2.1.1.2 MXNet
  MXNet的数据集使用RecordIO格式,ImageNet训练集 93GB ,验证集 3.7GB。
  我们使用网络Inception-v3(GoogLeNet的升级版)做了图像分类的训练测试。分别对比了不同vCPU和Memory配置下的训练性能。数据单位是Samples/Second(每秒处理的图像张数)。

2.1.2 磁盘IO
  我们在阿里云GN5(P100)实例上使用NVCaffe测试了GoogLeNet网络模型在NVMe SSD本地盘、SSD云盘和高效云盘上的训练性能,测试结果如下(性能数据单位是Images/Second):

2.2 自然语言处理
  我们使用MXNet测试了RNN网络的LSTM模型的训练,使用PennTreeBank自然语言数据集。PennTreeBank数据集的文本语料库包含近100万个单词,单词表被限定在10000个单词。分别对比了不同vCPU和Memory配置下的训练性能:

3 推理测试


3.1 图像分类
  

我们使用NVCaffe测试了图像分类领域的CNN网络的模型推理。
测试使用ImageNet ILSVRC2012数据集,验证测试图片 50000张。

3.1.1 CPU+Memory
  我们使用NVcaffe对AlexNet、GoogLeNet、ResNet50、VGG16四种经典卷积神经网络做了图像分类的推理测试。分别对比了不同vCPU和Memory配置下的训练性能。数据单位是Images/Second(每秒处理的图像张数)。

3.1.2 磁盘IO
  我们使用NVCaffe测试了GoogLeNet网络在NVMe SSD本地盘、SSD云盘和高效云盘上的图像分类推理性能,测试结果如下(数据单位是Images/Second):

4 数据预处理测试


  在训练模型之前,往往要对训练数据集做数据预处理,统一数据格式,并做一定的归一化处理。
  我们使用NVCaffe对ImageNet ILSVRC2012数据集做了数据预处理的测试,分别对比了NVMe SSD本地盘、SSD云盘和高效云盘的数据预处理时间,数据单位是秒,数据如下:

5 数据分析


5.1 训练


5.1.1 图像分类
  从NVCaffe和MXNet的测试结果来看,图像分类场景单纯的训练阶段对CPU要求不高,单GPU 只需要4vCPU就可以。而内存需求则取决于深度学习框架、神经网络类型和训练数据集的大小:测试中发现NVCaffe随着迭代次数的增多,内存是不断增大的,但是内存需求增大到一定程度,对性能就不会有什么提升了,其中NVCaffe AlexNet网络的训练,相比其它网络对于内存的消耗要大得多。相比之下MXNet的内存占用则要小的多(这也是MXNet的一大优势),93G预处理过的训练数据集训练过程中内存占用不到5G。
对于磁盘IO性能,测试显示训练阶段NVMe SSD本地盘、SSD云盘性能基本接近,高效云盘上的性能略差1%。因此训练阶段对IO性能的要求不高。

5.1.2 自然语言处理
  从MXNet的测试结果来看,对于PennTreeBank这样规模的数据集,2vCPU 1GB Mem就能满足训练需求。由于自然语言处理的原始数据不像图像分类一样是大量高清图片,自然语言处理的原始数据以文本文件为主,因此自然语言处理对内存和显存的要求都不高,从我们的测试来看,4vCPU 30GB 1GPU规格基本满足训练阶段需求。

5.2 推理


5.2.1 图像分类
  从NVCaffe的图像分类推理测试来看,除AlexNet 2vCPU刚刚够用外,其它网络2vCPU对性能没有影响,而9.4GB的验证数据集推理过程中内存占用大概是7GB左右,因此对大部分模型来看,2vCPU 30GB 1GPU规格基本满足图像分类推理的性能需求。
  对于磁盘IO性能,推理性能NVMe SSD本地盘、SSD云盘很接近,但高效云盘差15%。因此推理阶段至少应该使用SSD云盘保证性能。
5.2.2 自然语言处理
  对于自然语言处理,参考训练性能需求,我们应该可以推测2vCPU 30GB 1GPU规格应该也能满足需求。

5.3 数据预处理


  从NVCaffe对ImageNet ILSVRC2012数据集做数据预处理的测试来看,数据预处理阶段是IO密集型,NVMe SSD本地盘比SSD云盘快25%,而SSD云盘比高效云盘快10%。

6 总结


  深度学习框架众多,神经网络类型也是种类繁多,我们选取了主流的框架和神经网络类型,尝试对单机GPU云服务器的深度学习性能模型做了初步的分析,结论是:

  1. 深度学习训练阶段是GPU运算密集型,对于CPU占用不大,而内存的需求取决于深度学习框架、神经网络类型和训练数据集的大小;对磁盘IO性能不敏感,云盘基本能够满足需求。
  2. 深度学习推理阶段对于CPU的占用更小,但是对于磁盘IO性能相对较敏感,因为推理阶段对于延迟有一定的要求,更高的磁盘IO性能对于降低数据读取的延时进而降低整体延迟有很大的帮助。
  3. 深度学习数据预处理阶段是IO密集型阶段,更高的磁盘IO性能能够大大缩短数据预处理的时间。

原文链接

阅读更多干货好文,请关注扫描以下二维码:



2020-03-02 00:17:07 CZW199418 阅读数 240
  • 3D游戏引擎之GPU渲染(DX篇)

    本次课程主要是针对3D游戏引擎内部的GPU之Shader渲染处理,告诉大家引擎底层是如何与Shader代码结合的。从基本的灯光渲染,环境渲染到后的Bloom渲染。

    12032 人正在学习 去看看 姜雪伟

1.创建云服务器

1.1注册滴滴云

首先注册滴滴云,并进行实名认证,否则无法创建云服务器。点击“控制台”,进入控制台页面。

1.2选择配置

点击快速创建云服务器(DC2),显示出云服务器配置列表。

云服务器配置选择:

付费方式:按时长。包月价格过高。

可用区:广东1区。理论上北京区更好,但是北京区GPU服务器太差。

服务器类型:GPU云服务器,通用型P100。

镜像:标准镜像,这里我选择已经安装好CUDA的版本。

配置:根据需要选择,一般选择第一个单GPU即可。

系统盘和数据盘根据自己需要调整。

网络按照默认即可,宽带选择10M,基本上够用,安全组按照默认。

登陆方式选择密码,其他按照默认即可,添加标签,也可以不添加。

创建成功,一定要记住下图中的公网IP,下面会用到。

 

2.远程连接

2.1安装WinSCP

下载WinSCP并安装。打开WinSCP,界面如下。输入上图中的公网IP地址、用户名(默认为dc2-user)和密码登陆。

为了方便以后使用,可以点击保存,即新建一个站点。然后继续登陆。

点击“是”,然后会要求输入密码,以后每次只要输入密码即可。 

 右击文件,可以对文件进行操作。由于上传到服务器较慢,建议将数据集等文件压缩后再上传。

2.2安装PuTTY

下载并安装putty,可以单独使用,也可以结合WinSCP使用。单独使用需要输入公网IP如下图所示。

或者使用 WinSCP打开,如下图所示。

这两种方法打开后界面一致,均需要输入密码。注意,密码在输入过程中无显示且界面无变化。

输入密码,按Enter后,进入云服务器终端界面。

下面的操作与我们平时使用的终端界面一致,输入“nvidia-smi”查看驱动和cuda信息,发现均已安装好。

 安装Anaconda,运行以下命令即可。滴滴云网速很快,但是有时会不稳定。然后就可以创建虚拟环境,安装各种包了。

wget https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
chmod 777 Anaconda3-2019.10-Linux-x86_64.sh
sh Anaconda3-2019.10-Linux-x86_64.sh

安装过程一路yes,安装完成后运行

source ~/.barshrc

2.3 screen命令 

为什么需要使用screen命令呢?因为我们在使用PuTTY时,一旦使用ctrl+d或者关闭窗口,我们的所有操作命令在云服务器都会终止。比如你在训练卷积神经网络,假如此时的电脑意外断网,云服务器就会停止训练,这是sighub信号的原因,此处不再解释。我们可以使用nohub或screen解决这个问题,screen更全面方便,所以记录screen使用流程。

在PuTTY打开的终端页面输入“screen”。

出现以下界面,单击空格键继续。

 然后,我们就打开了screen窗口。

输入screen -ls,可以查看当前screen窗口的代号。

先“ Ctrl+a”,然后单击“d”,即可退出screen的窗口。注意,此时仅仅是暂时退出,该screen窗口依然在运行程序。如果现在关闭PuTTY则不会影响screen里运行的程序。输入“screen -r 代号”可以重新进入screen。

 先“ Ctrl+a”,然后单击“k”,即可杀死screen的窗口,真正关闭该窗口。

 下面是screen的常用键组合。

Ctrl-a ? 显示所有键绑定信息
Ctrl-a w 显示所有窗口列表
Ctrl-a Ctrl-a 切换到之前显示的窗口
Ctrl-a c 创建一个新的运行shell的窗口并切换到该窗口
Ctrl-a n 切换到下一个窗口
Ctrl-a p 切换到前一个窗口(与C-a n相对)
Ctrl-a 0..9 切换到窗口0..9
Ctrl-a a 发送 C-a到当前窗口
Ctrl-a d 暂时断开screen会话
Ctrl-a k 杀掉当前窗口
Ctrl-a [ 进入拷贝/回滚模式

3.快照教程

3.1创建快照

为什么要创建快照?因为我们不运行云服务器,云服务器也在收费,我们必须删掉实例才会停止扣费,但是我们的云服务器全都会被删除。快照相当于一个镜像,可以还原我们之前的所有工作。首先,在控制台中找到需要创建快照的云服务器,在右侧单击。

3.2删除云服务器

创建快照后,我们就可以高枕无忧的删除云服务器了。

3.3使用快照

有两种使用快照还原云服务器的方法。一种是在创建云服务器时选择快照镜像,另一种是在控制台的快照列表中找到快照新建云服务器。

没有更多推荐了,返回首页