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

## 1. 神经网络原理

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

``````# 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))
...
...
w2_0    = w2_0 + alpha * grad_w2
b2_0    = b2_0 + alpha * grad_b2
...
...
``````

## 2.深度学习框架

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

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

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

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

input:cdata(),
self.output:cdata()
)
end
``````

``````# 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
THNNState *state,
THTensor *input,
THTensor *output)
{
real z = * output_data;
*gradInput_data = *gradOutput_data * (1. - z) * z;
);
}
``````

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

#### 数据结构部分

``````# 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.

# 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:

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:

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:
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:
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
``````

#### 调度算法与优化部分

``````# 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()}
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:
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)
``````

``````# python
import matplotlib.pyplot as plt
%matplotlib inline

fig = plt.figure( figsize=(14,10))
#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])

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))])

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)):
``````

0 条评论

• ### 使用腾讯云 GPU 学习深度学习系列之四：深度学习的特征工程

本系列文章主要介绍如何使用 腾讯云GPU服务器 进行深度学习运算，前面主要介绍原理部分，后期则以实践为主。

• ### 使用腾讯云 GPU 学习深度学习系列之六：物体的识别与定位

本文以如何识别马路上的行人、车辆为主题，介绍了基于 Tensorflow 的 SSD 模型如何应用在物体识别定位项目中。

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

本文主要回顾了传统机器学习的主要思想，并基于传统机器学习的内容引入了深度学习部分。

• ### Python 中 \x00 和空字符串的区别，以及在 Django 中的坑

事情是这样的，我有一个守护进程，不停地从 RabbitMQ 消费数据，然后保存到 MySQL。操作数据库使用的是 Django 的 ORM 语法。

• ### Python运算符重载

在Python语言中提供了类似于C++的运算符重在功能： 一下为Python运算符重在调用的方法如下： Method        Overloads   ...

• ### 关于python类的组合

关于python类的组合，绞尽脑汁之后，写了一个生活中的简单例子，有需要的童鞋可以理解下，水平有限，不对的地方望指正

• ### python codis集群客户端(二) - 基于zookeeper对实例创建与摘除

在这一篇中我们实现了不通过zk来编写codis集群proxys的api， 如果codis集群暴露zk给你的话，那么就方便了，探活和故障摘除与恢复codis集群...

• ### 【python实现卷积神经网络】激活函数的实现（sigmoid、softmax、tanh、relu、leakyrelu、elu、selu、softplus）

代码来源：https://github.com/eriklindernoren/ML-From-Scratch

• ### 如何用 Python 打飞机 ？

前言：python 除了生孩子 ，啥都会 。包括打飞机 ！今天小詹的一位读者就来教你如何用 python 打飞机 ！

• ### jenkins python 接口封装

self.server = Jenkins(self.url)