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

转自:https://www.qcloud.com/community/article/598765?fromSource=gwzcw.117333.117333.117333

这是《使用腾讯云 GPU 学习深度学习》系列文章的第二篇,主要介绍了 Tensorflow 的原理,以及如何用最简单的Python代码进行功能实现。本系列文章主要介绍如何使用 腾讯云GPU服务器 进行深度学习运算,前面主要介绍原理部分,后期则以实践为主。

往期内容:

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

1. 神经网络原理

神经网络模型,是上一章节提到的典型的监督学习问题,即我们有一组输入以及对应的目标输出,求最优模型。通过最优模型,当我们有新的输入时,可以得到一个近似真实的预测输出。

我们先看一下如何实现这样一个简单的神经网络:

  • 输入 x = [1,2,3],
  • 目标输出 y = [-0.85, 0.72]
  • 中间使用一个包含四个单元的隐藏层。
  • 结构如图:

求所需参数 w1_0 w2_0 b1_0 b2_0, 使得给定输入 x 下得到的输出 ,和目标输出  之间的平均均方误差 (Mean Square Errors, MSE) 最小化 。

我们首先需要思考,有几个参数?由于是两层神经网络,结构如下图(图片来源http://stackoverflow.com/questions/22054877/backpropagation-training-stuck), 其中输入层为 3,中间层为 4,输出层是 2:

因此,其中总共包含 (3x4+4) + (4*2+2) = 26 个参数需要训练。我们可以如图初始化参数。参数可以随机初始化,也可以随便指定:

# python
import numpy as np
w1_0 = np.array([[ 0.1,  0.2,  0.3,  0.4],
                 [ 0.5,  0.6,  0.7,  0.8],
                 [ 0.9,  1.0,  1.1,  1.2]])
w2_0 = np.array([[ 1.3,  1.4],
                 [ 1.5,  1.6],
                 [ 1.7,  1.8],
                 [ 1.9,  2.0]])

b1_0 = np.array( [-2.0, -6.0, -1.0, -7.0])
b2_0 = np.array( [-2.5, -5.0])

我们进行一次正向传播:

# python

x = [1,2,3]
y = [-0.85, 0.72]

o1 = np.dot(x, w1_0 ) + b1_0
os1 = np.power(1+np.exp(o1*-1), -1)
o2 = np.dot(os1, w2_0) + b2_0
os2 = np.tanh(o2)

再进行一次反向传播:

# python

alpha = 0.1
grad_os2 = (y - os2) * (1-np.power(os2, 2))
grad_os1 = np.dot(w2_0, grad_os2.T).T * (1-os1)*os1
grad_w2 = ...
grad_b2 = ...
...
...
w2_0    = w2_0 + alpha * grad_w2
b2_0    = b2_0 + alpha * grad_b2
...
...

如此反复多次,直到最终误差收敛。进行反向传播时,需要将所有参数的求导结果都写上去,然后根据求导结果更新参数。我这里就没有写全,因为一层一层推导实在是太过麻烦。更重要的是,当我们需要训练新的神经网络结构时,这些都需要重新推导一次,费时费力。

然而仔细想一想,这个推导的过程也并非无规律可循。即上一级的神经网络梯度输出,会被用作下一级计算梯度的输入,同时下一级计算梯度的输出,会被作为上一级神经网络的输入。于是我们就思考能否将这一过程抽象化,做成一个可以自动求导的框架?OK,以 Tensorflow 为代表的一系列深度学习框架,正是根据这一思路诞生的。

2.深度学习框架

近几年最火的深度学习框架是什么?毫无疑问,Tensorflow 高票当选。

但实际上,这些深度学习框架都具有一些普遍特征。Gokula Krishnan Santhanam认为,大部分深度学习框架都包含以下五个核心组件

  1. 张量(Tensor)
  2. 基于张量的各种操作
  3. 计算图(Computation Graph)
  4. 自动微分(Automatic Differentiation)工具
  5. BLAS、cuBLAS、cuDNN等拓展包

其中,张量 Tensor 可以理解为任意维度的数组——比如一维数组被称作向量(Vector),二维的被称作矩阵(Matrix),这些都属于张量。有了张量,就有对应的基本操作,如取某行某列的值,张量乘以常数等。运用拓展包其实就相当于使用底层计算软件加速运算。

我们今天重点介绍的,就是计算图模型,以及自动微分两部分。首先介绍以 Torch 框架为例,谈谈如何实现自动求导,然后再用最简单的方法,实现这两部分。

2.1. 深度学习框架如何实现自动求导

诸如 Tensorflow 这样的深度学习框架的入门,网上有大量的 几行代码、几分钟入门这样的资料,可以快速实现手写数字识别等简单任务。但如果想深入了解 Tensorflow 的背后原理,可能就不是这么容易的事情了。这里我们简单的谈一谈这一部分。

我们知道,当我们拿到数据、训练神经网络时,网络中的所有参数都是 变量。训练模型的过程,就是如何得到一组最佳变量,使预测最准确的过程。这个过程实际上就是,输入数据经过 正向传播,变成预测,然后预测与实际情况的误差 反向传播 误差回来,更新变量。如此反复多次,得到最优的参数。这里就会遇到一个问题,神经网络这么多层,如何保证正向、反向传播都可以正确运行?

值得思考的是,这两种传播方式,都具有 管道传播 的特征。正向传播一层一层算就可以了,上一层网络的结果作为下一层的输入。而反向传播过程可以利用 链式求导法则,从后往前,不断将误差分摊到每一个参数的头上。

图片来源:Colah博客


进过抽象化后,我们发现,深度学习框架中的 每一个模块都需要两个函数,一个连接正向,一个连接反向。这里的正向和反向,如同武侠小说中的 任督二脉。而训练模型的过程,数据通过正向传播生成预测结果,进而将误差反向传回更新参数,就如同让真气通过任督二脉在体内游走,随着训练误差逐渐缩小收敛,深度神经网络也将打通任督二脉。

接下来,我们将首先审视一下 Torch 框架的源码如何实现这两部分内容,其次我们通过 Python 直接编写一个最简单的深度学习框架。

举 Torch 的 nn 项目的例子是因为Torch 的代码文件结构比较简单,Tensorflow 的规律和Torch比较近似,但文件结构相对更加复杂,有兴趣的可以仔细读读相关文章

Torch nn 模块Github 源码 这个目录下的几乎所有 .lua 文件,都有这两个函数:

# lua
function xxx:updateOutput(input)
   input.THNN.xxx_updateOutput(
      input:cdata(),
      self.output:cdata()
   )
   return self.output
end

function xxx:updateGradInput(input, gradOutput)
   input.THNN.xxx_updateGradInput(
      input:cdata(),
      gradOutput:cdata(),
      self.gradInput:cdata(),
      self.output:cdata()
   )
   return self.gradInput
end

这里其实是相当于留了两个方法的定义,没有写具体功能。具体功能的代码,在 ./lib/THNN/generic 目录中用 C 实现实现,具体以 Sigmoid 函数举例。

我们知道 Sigmoid 函数的形式是:

代码实现起来是这样:

# lua
void THNN_(Sigmoid_updateOutput)( THNNState
  *state, THTensor
  *input, THTensor
  *output)
{
  THTensor_(resizeAs)(output, input);

  TH_TENSOR_APPLY2(real, output, real, input,
    *output_data = 1./(1.+ exp(- *input_data));
  );
}

Sigmoid 函数求导变成:

所以这里在实现的时候就是:

// c
void THNN_(Sigmoid_updateGradInput)(
          THNNState *state,
          THTensor *input,
          THTensor *gradOutput,
          THTensor *gradInput,
          THTensor *output)
{
  THNN_CHECK_NELEMENT(input, gradOutput);
  THTensor_(resizeAs)(gradInput, output);
  TH_TENSOR_APPLY3(real, gradInput, real, gradOutput, real, output,
    real z = * output_data;
    *gradInput_data = *gradOutput_data * (1. - z) * z;
  );
}

大家应该注意到了一点, updateOutput 函数, output_data 在等号左边, input_data 在等号右边。 而 updateGradInput 函数, gradInput_data 在等号左边, gradOutput_data 在等号右边。 这里,output = f(input) 对应的是 正向传播 input = f(output) 对应的是 反向传播。

1.2 用 Python 直接编写一个最简单的深度学习框架

这部分内容属于“造轮子”,并且借用了优达学城的一个小型项目 MiniFlow

数据结构部分

首先,我们实现一个父类 Node,然后基于这个父类,依次实现 Input Linear Sigmoid 等模块。这里运用了简单的 Python Class 继承。这些模块中,需要将 forward 和 backward 两个方法针对每个模块分别重写。

代码如下:

# python
class Node(object):
    """
    Base class for nodes in the network.

    Arguments:

        `inbound_nodes`: A list of nodes with edges into this node.
    """
    def __init__(self, inbound_nodes=[]):
        """
        Node‘s constructor (runs when the object is instantiated). Sets
        properties that all nodes need.
        """
        # A list of nodes with edges into this node.
        self.inbound_nodes = inbound_nodes
        # The eventual value of this node. Set by running
        # the forward() method.
        self.value = None
        # A list of nodes that this node outputs to.
        self.outbound_nodes = []
        # New property! Keys are the inputs to this node and
        # their values are the partials of this node with
        # respect to that input.
        self.gradients = {}

        # Sets this node as an outbound node for all of
        # this node‘s inputs.
        for node in inbound_nodes:
            node.outbound_nodes.append(self)

    def forward(self):
        """
        Every node that uses this class as a base class will
        need to define its own `forward` method.
        """
        raise NotImplementedError

    def backward(self):
        """
        Every node that uses this class as a base class will
        need to define its own `backward` method.
        """
        raise NotImplementedError

class Input(Node):
    """
    A generic input into the network.
    """
    def __init__(self):
        Node.__init__(self)

    def forward(self):
        pass

    def backward(self):
        self.gradients = {self: 0}
        for n in self.outbound_nodes:
            self.gradients[self] += n.gradients[self]

class Linear(Node):
    """
    Represents a node that performs a linear transform.
    """
    def __init__(self, X, W, b):
        Node.__init__(self, [X, W, b])

    def forward(self):
        """
        Performs the math behind a linear transform.
        """
        X = self.inbound_nodes[0].value
        W = self.inbound_nodes[1].value
        b = self.inbound_nodes[2].value
        self.value = np.dot(X, W) + b

    def backward(self):
        """
        Calculates the gradient based on the output values.
        """
        self.gradients = {n: np.zeros_like(n.value) for n in self.inbound_nodes}
        for n in self.outbound_nodes:
            grad_cost = n.gradients[self]
            self.gradients[self.inbound_nodes[0]] += np.dot(grad_cost, self.inbound_nodes[1].value.T)
            self.gradients[self.inbound_nodes[1]] += np.dot(self.inbound_nodes[0].value.T, grad_cost)
            self.gradients[self.inbound_nodes[2]] += np.sum(grad_cost, axis=0, keepdims=False)

class Sigmoid(Node):
    """
    Represents a node that performs the sigmoid activation function.
    """
    def __init__(self, node):
        Node.__init__(self, [node])

    def _sigmoid(self, x):
        """
        This method is separate from `forward` because it
        will be used with `backward` as well.

        `x`: A numpy array-like object.
        """
        return 1. / (1. + np.exp(-x))

    def forward(self):
        """
        Perform the sigmoid function and set the value.
        """
        input_value = self.inbound_nodes[0].value
        self.value = self._sigmoid(input_value)

    def backward(self):
        """
        Calculates the gradient using the derivative of
        the sigmoid function.
        """
        self.gradients = {n: np.zeros_like(n.value) for n in self.inbound_nodes}
        for n in self.outbound_nodes:
            grad_cost = n.gradients[self]
            sigmoid = self.value
            self.gradients[self.inbound_nodes[0]] += sigmoid * (1 - sigmoid) * grad_cost

class Tanh(Node):
    def __init__(self, node):
        """
        The tanh cost function.
        Should be used as the last node for a network.
        """
        Node.__init__(self, [node])

    def forward(self):
        """
        Calculates the tanh.
        """
        input_value = self.inbound_nodes[0].value
        self.value  = np.tanh(input_value)

    def backward(self):
        """
        Calculates the gradient of the cost.
        """
        self.gradients = {n: np.zeros_like(n.value) for n in self.inbound_nodes}
        for n in self.outbound_nodes:
            grad_cost = n.gradients[self]
            tanh = self.value
            self.gradients[self.inbound_nodes[0]] += (1 + tanh) * (1 - tanh) * grad_cost.T

class MSE(Node):
    def __init__(self, y, a):
        """
        The mean squared error cost function.
        Should be used as the last node for a network.
        """
        Node.__init__(self, [y, a])

    def forward(self):
        """
        Calculates the mean squared error.
        """
        y = self.inbound_nodes[0].value.reshape(-1, 1)
        a = self.inbound_nodes[1].value.reshape(-1, 1)

        self.m = self.inbound_nodes[0].value.shape[0]
        self.diff = y - a
        self.value = np.mean(self.diff**2)

    def backward(self):
        """
        Calculates the gradient of the cost.
        """
        self.gradients[self.inbound_nodes[0]] = (2 / self.m) * self.diff
        self.gradients[self.inbound_nodes[1]] = (-2 / self.m) * self.diff

调度算法与优化部分

优化部分则会在以后的系列中单独详细说明。这里主要将简单讲一下图计算的算法调度。就是实际上Tensorflow的各个模块会生成一个有向无环图,如下图(来源http://www.geeksforgeeks.org/topological-sorting-indegree-based-solution/):

在计算过程中,几个模块存在着相互依赖关系,比如要计算模块1,就必须完成模块3和模块4,而要完成模块3,就需要在之前顺次完成模块5、2;因此这里可以使用 Kahn 算法作为调度算法(下面的 topological_sort 函数),从计算图中,推导出类似 5->2->3->4->1 的计算顺序。

# python
def topological_sort(feed_dict):
    """
    Sort the nodes in topological order using Kahn‘s Algorithm.

    `feed_dict`: A dictionary where the key is a `Input` Node and the value is the respective value feed to that Node.

    Returns a list of sorted nodes.
    """
    input_nodes = [n for n in feed_dict.keys()]
    G = {}
    nodes = [n for n in input_nodes]
    while len(nodes) > 0:
        n = nodes.pop(0)
        if n not in G:
            G[n] = {‘in‘: set(), ‘out‘: set()}
        for m in n.outbound_nodes:
            if m not in G:
                G[m] = {‘in‘: set(), ‘out‘: set()}
            G[n][‘out‘].add(m)
            G[m][‘in‘].add(n)
            nodes.append(m)

    L = []
    S = set(input_nodes)
    while len(S) > 0:
        n = S.pop()
        if isinstance(n, Input):
            n.value = feed_dict[n]

        L.append(n)
        for m in n.outbound_nodes:
            G[n][‘out‘].remove(m)
            G[m][‘in‘].remove(n)
            if len(G[m][‘in‘]) == 0:
                S.add(m)
    return L

def forward_and_backward(graph):
    """
    Performs a forward pass and a backward pass through a list of sorted Nodes.

    Arguments:

        `graph`: The result of calling `topological_sort`.
    """
    for n in graph:
        n.forward()

    for n in graph[::-1]:
        n.backward()

def sgd_update(trainables, learning_rate=1e-2):
    """
    Updates the value of each trainable with SGD.

    Arguments:

        `trainables`: A list of `Input` Nodes representing weights/biases.
        `learning_rate`: The learning rate.
    """
    for t in trainables:
        t.value = t.value - learning_rate * t.gradients[t]

使用模型

# python

import numpy as np
from sklearn.utils import resample
np.random.seed(0)

w1_0 = np.array([[ 0.1,  0.2,  0.3,  0.4],
                 [ 0.5,  0.6,  0.7,  0.8],
                 [ 0.9,  1.0,  1.1,  1.2]])
w2_0 = np.array([[ 1.3,  1.4],
                 [ 1.5,  1.6],
                 [ 1.7,  1.8],
                 [ 1.9,  2.0]])
b1_0 = np.array( [-2.0, -6.0, -1.0, -7.0])
b2_0 = np.array( [-2.5, -5.0])

X_ = np.array([[1.0, 2.0, 3.0]])
y_ = np.array([[-0.85, 0.75]])
n_features = X_.shape[1]

W1_ = w1_0
b1_ = b1_0
W2_ = w2_0
b2_ = b2_0

X, y = Input(), Input()
W1, b1 = Input(), Input()
W2, b2 = Input(), Input()

l1 = Linear(X, W1, b1)
s1 = Sigmoid(l1)
l2 = Linear(s1, W2, b2)
t1 = Tanh(l2)
cost = MSE(y, t1)

feed_dict = {
    X: X_,   y: y_,
    W1: W1_, b1: b1_,
    W2: W2_, b2: b2_
}

epochs = 10
m = X_.shape[0]
batch_size = 1
steps_per_epoch = m // batch_size

graph = topological_sort(feed_dict)
trainables = [W1, b1, W2, b2]

l_Mat_W1 = [w1_0]
l_Mat_W2 = [w2_0]
l_Mat_out = []

l_val = []
for i in range(epochs):
    loss = 0
    for j in range(steps_per_epoch):
        X_batch, y_batch = resample(X_, y_, n_samples=batch_size)
        X.value = X_batch
        y.value = y_batch
        forward_and_backward(graph)
        sgd_update(trainables, 0.1)
        loss += graph[-1].value

    mat_W1 = []
    mat_W2 = []
    for i in graph:
        try:
            if  (i.value.shape[0] == 3) and (i.value.shape[1] == 4):
                mat_W1 = i.value
            if  (i.value.shape[0] == 4) and (i.value.shape[1] == 2):
                mat_W2 = i.value
        except:
            pass

    l_Mat_W1.append(mat_W1)
    l_Mat_W2.append(mat_W2)
    l_Mat_out.append(graph[9].value)

来观察一下。当然还有更高级的可视化方法:https://jizhi.im/blog/post/v_nn_learn

# python
import matplotlib.pyplot as plt
%matplotlib inline

fig = plt.figure( figsize=(14,10))
ax0 = fig.add_subplot(131)
#aax0 = fig.add_axes([0, 0, 0.3, 0.1])
c0 = ax0.imshow(np.array(l_Mat_out).reshape([-1,2]).T, interpolation=‘nearest‘,aspect=‘auto‘, cmap="Reds", vmax=1, vmin=-1)
ax0.set_title("Output")

cbar = fig.colorbar(c0, ticks=[-1, 0, 1])

ax1 = fig.add_subplot(132)
c1 = ax1.imshow(np.array(l_Mat_W1).reshape(len(l_Mat_W1), 12).T, interpolation=‘nearest‘,aspect=‘auto‘, cmap="Reds")
ax1.set_title("w1")
cbar = fig.colorbar(c1, ticks=[np.min(np.array(l_Mat_W1)), np.max(np.array(l_Mat_W1))])

ax2 = fig.add_subplot(133)
c2 = ax2.imshow(np.array(l_Mat_W2).reshape(len(l_Mat_W2), 8).T, interpolation=‘nearest‘,aspect=‘auto‘, cmap="Reds")
ax2.set_title("w2")
cbar = fig.colorbar(c2, ticks=[np.min(np.array(l_Mat_W2)), np.max(np.array(l_Mat_W2))])

ax0.set_yticks([0,1])
ax0.set_yticklabels(["out0", "out1"])

ax1.set_xlabel("epochs")
#for i in range(len(l_Mat_W1)):

我们注意到,随着训练轮数 Epoch 不断增多, Output 值从最初的 [0.72, -0.88] 不断接近 y = [-0.85, 0.72], 其背后的原因,是模型参数不断的从初始化的值变化、更新,如图中的 w1 w2 两个矩阵。

好了,最简单的轮子已经造好了。 我们的轮子,实现了 Input Linear Sigmoid Tanh 以及 MSE 这几个模块。 接下来的内容,我们将基于现在最火的轮子 Tensorflow,详细介绍一下更多的模块。

最后,本篇只是造了个最基本的轮子,我们集智的知乎专栏上,有一个系列文章,正在介绍如何在Matlab上手写深度学习框架,传送门: matDL框架开发直播:2——全连接层的实现和优化,欢迎大家围观。

目前腾讯云 GPU 服务器还在内测阶段,暂时没有申请到内测资格的读者也可以使用普通的云服务器运行本讲的代码。但从第三讲开始,我们将逐渐开始使用 Tensorflow 框架分析相关数据,对应的计算量大大增加,必须租用 云GPU服务器 才可以快速算出结果。服务器的租用方式,以及 Python 编程环境的搭建,我们将以腾讯云 GPU 为例,在接下来的内容中和大家详细介绍。

时间: 2024-12-19 16:33:34

使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理【转】的相关文章

学习深度学习网址

1.从零开始学习深度学习的网址,包括全连接神经网络.卷积神经网络.循环神经网络等等: https://www.zybuluo.com/hanbingtao/note/485480 2.python 2学习的网址: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000 原文地址:https://www.cnblogs.com/zzm1/p/10445176.html

Guava库学习:学习Guava Files系列(二)

原文地址:Guava库学习:学习Guava Files系列(二) 上一篇,Guava库学习:学习Guava Files系列(一)中,我们简单的学习了使用Files进行文件的读写等常用操作,本篇我们继续进行Guava Files系列的学习.     InputSupplier 和 OutputSupplier Guava提供了 InputSupplier 和 OutputSupplier接口,用于提供InputStreams/Readers 或OutputStreams/Writers的处理.我们

mxnet:结合R与GPU加速深度学习(转)

近年来,深度学习可谓是机器学习方向的明星概念,不同的模型分别在图像处理与自然语言处理等任务中取得了前所未有的好成绩.在实际的应用中,大家除了关心模型的准确度,还常常希望能比较快速地完成模型的训练.一个常用的加速手段便是将模型放在GPU上进行训练.然而由于种种原因,R语言似乎缺少一个能够在GPU上训练深度学习模型的程序包. DMLC(Distributed (Deep) Machine Learning Community)是由一群极客发起的组织,主要目标是提供快速高质量的开源机器学习工具.近来流

deep learning...深入学习深度学习 --工具篇

Caffe( http://caffe.berkeleyvision.org/ )是一个清晰而高效的深度学习框架,其作者是博士毕业于UC Berkeley的贾扬清( http://daggerfs.com/ ),他目前在Google工作.Caffe是纯粹的C++/CUDA架构,支持命令行.Python和MATLAB接口:可以在CPU和GPU直接无缝切换:

机器学习之深度学习---深度学习之我见

今天下午,闲来无事,遂百度翻看下最近关于模式识别,以及目标检测方面的最新进展,还有收获不少! ------------------------------------author:pkf -----------------------------------------------time:2016-1-20 --------------------------------------------------------------qq:1327706646 1.深度学习的本质 2.深度学习对传

系统学习深度学习--GoogLeNetV1,V2,V3 【Incepetion V1-V3】

GoogLeNet Incepetion V1 这是GoogLeNet的最早版本,出现在2014年的<Going deeper with convolutions>.之所以名为"GoogLeNet"而非"GoogleNet",文章说是为了向早期的LeNet致敬. Motivation 深度学习以及神经网络快速发展,人们不再只关注更给力的硬件.更大的数据集.更大的模型,而是更在意新的idea.新的算法以及模型的改进. 一般来说,提升网络性能最直接的办法就是

深度学习“深度学习”-概念篇

Q:什么是"深度学习" 对于"深度学习"这个术语,一个粗浅的定义是"主要使用深度神经网络为工具的机器学习算法".深度学习首先是一类机器学习的方法,因为它和其他机器学习方法一样允许计算机从样本中.从实例中.从数据中使用统计手段"学习"出规律来,而不用像专家系统和其他符号主义的方法一样人工定义规则.其次,深度学习不同于其他机器学习方法的地方,在于它主要的工具,或者说使用到的数学模型是深度神经网络. 虽说深度学习这个词时近几年才后起

低价租用高性能GPU进行深度学习

首先介绍租用网站:https://www.freegpu.com/ B站有位管理员,UP主叫:史开杰,本文是根据up主的视频制作的文字教程 up主推荐的个人微信: 1. 点击机器列表可以查看可用机器,价格都在零点几美元每小时左右 2. 点击我的钱包,创建新的账号 3. 一定要保存好自己的私钥和秘钥 4. 因为需要邮箱接收ssh和jupyter的远程信息,所以需要先充值1分钱绑定邮箱(DBC相当于Q币) 5. 充值完成后,继续绑定邮箱,按照邮箱所要求的数量输入DBC数目 原文地址:https://

Deep Learning(深度学习)学习笔记整理系列(二)——特征

[email protected] http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0  2013-04-08 1)该Deep Learning的学习系列是整理自网上很大牛和机器学习专家所无私奉献的资料的.具体引用的资料请看参考文献.具体的版本声明也参考原文献. 2)本文仅供学术交流,非商用.所以每一部分具体的参考资料并没有详细对应.如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除. 3)本人才疏学浅,整理总结的时候难免出错,还望各位前辈