使用Spark进行数据清洗,构建用户画像和物品画像,挖掘数据特征,形成数据集存储在HDFS。
使用TensorFlow作为深度学习计算框架,通过Hbox调度深度学习作业,使用集群分布式训练。训练模型使用TF Serving部署,封装成TF-Web对内提供预测接口,线上使用Go Server提供推荐服务。
![d8bd3d9c98cc74850be8fff496295c6e.png](https://i-blog.csdnimg.cn/blog_migrate/305f5911ddf6baed8a5c4d9bfe8f4e47.jpeg)
![f3db3691d338d3b138d59a95d6b27d12.png](https://i-blog.csdnimg.cn/blog_migrate/6e8670e5fe74f1447e6a9da3e18283aa.png)
![578545749c061e01f459871a9067135f.png](https://i-blog.csdnimg.cn/blog_migrate/3c91d3ad3ef7887e545a58cb6b583059.png)
![611c78089dbdcb63624488a8b346ec2f.png](https://i-blog.csdnimg.cn/blog_migrate/f0e24272be58be683ffe73029ee1aa40.jpeg)
![ec516850874cc7b369536004d93d7836.png](https://i-blog.csdnimg.cn/blog_migrate/f724a3b1541b69c823e9982ad7da8560.png)
![e1e9f5474b16995d906b3ad964756d94.png](https://i-blog.csdnimg.cn/blog_migrate/b90a8976f3e210466ac6c4a4d6108d87.png)
class placeholder:
def __init__(self):
self.consumers = []
_default_graph.placeholders.append(self)
Variable节点:计算图中表示模型参数的节点。Variable节点拥有初始值value,将输出传递给它的子节点consumers。
class Variable:
def __init__(self, initial_value = None):
self.value = initial_value
self.consumers = []
_default_graph.variables.append(self)
Operation节点:使用Variable节点或Placeholder节点来组成简单的函数,可以通过复合Operation节点来建立复杂网络。它具有输入和输出,输入由父节点input_nodes传递,输出传递到子节点consumers中。而compute方法需要继承,用来表述Operation节点所表示的函数计算。
class Operation:
def __init__(self, input_nodes=[]):
self.input_nodes = input_nodes
self.consumers = []
for input_node in input_nodes:
input_node.consumers.append(self)
_default_graph.operations.append(self)
def compute(self):
pass
Addition Operation的具体写法:
class add(Operation):
def __init__(self, x, y):
super().__init__([x, y])
def compute(self, x_value, y_value):
self.inputs = [x_value, y_value]
return x_value + y_value
图(Graph)使用一个Graph类来绑定计算图中的所有节点(opeartions、placeholders和varaibles)。当创建新的graph的时候,可以调用asdefault方法来设置为这张图的default_graph,这样不用显式地将节点绑定到图中。
class Graph:
def __init__(self):
"""Construct Graph"""
self.operations = []
self.placeholders = []
self.variables = []
def as_default(self):
global _default_graph
_default_graph = self
会话(Session)完成了图定义,如何执行图?在TensorFlow中,通过定义Session实例,Client将计算图传递给后端,通过Session.run方法传递给master执行。计算图的输出是特定的Operation节点。而输出节点的计算依赖其他中间节点,必须保证operations是按拓扑顺序执行的,计算节点o之前,节点o的所有输入节点已经完成计算。比如,要计算z节点必须先计算出中间节点y。这里通过反向的后序遍历来完成拓扑排序。类似的,Session可以这么定义:
class Session:
def run(self, operation, feed_dict = {}):
"""Computes the output of an operation
"""
...
def traverse_postorder(operation):
nodes_postorder = []
def recurse(node):
if isinstance(node, Operation):
for input_node in node.input_nodes:
recurse(input_node)
nodes_postorder.append(node)
recurse(operation)
return nodes_postorder
session.run方法首先对节点进行拓扑排序,并根据排序结果依次计算节点输出,完成图的执行。
前向传递算法再回顾这张计算图:
![ec516850874cc7b369536004d93d7836.png](https://i-blog.csdnimg.cn/blog_migrate/f724a3b1541b69c823e9982ad7da8560.png)
![18dfd1570e41f5777a47e8f551d7f5be.png](https://i-blog.csdnimg.cn/blog_migrate/29b9251c89cddef9631ebb5c9485f39c.png)
# Create a new graph
Graph().as_default()
# Create variables
A = Variable([[1, 0], [0, -1]])
b = Variable([1, 1])
# Create placeholder
x = placeholder()
# Create hidden node y
y = matmul(A, x)
# Create output node z
z = add(y, b)
session = Session()
output = session.run(z, {x: [1, 2]})
print(output)
可以得到结果:
[ 2 -1]
构建损失函数深度学习中,分类任务通常使用交叉熵作为损失函数,它的公式如下:
![cee40a2cd7e79fc35d2379b7797d14f3.png](https://i-blog.csdnimg.cn/blog_migrate/4c13bf05dfceb5c1f76dac4f4d3fe8a4.png)
![4136f218947916d1e8fcc5c636c6d043.png](https://i-blog.csdnimg.cn/blog_migrate/381c0a3644c2551b55035720574d29c7.png)
# Create a new graph
Graph().as_default()
X = placeholder()
c = placeholder()
W = Variable([[1, -1],
[1, -1]])
b = Variable([0, 0])
p = softmax( add(matmul(X, W), b) )
# Cross-entropy loss
J = negative(reduce_sum(reduce_sum(multiply(c, log(p)), axis=1)))
session = Session()
print(session.run(J, {
X: np.concatenate((blue_points, red_points)),
c:
[[1, 0]] * len(blue_points)
+ [[0, 1]] * len(red_points)}))
梯度下降优化算法通过使用梯度下降方法来最小化代价函数,流程如下:
模型参数W和b设置随机初始值。
计算代价函数J对W和b的梯度。
分别在其负梯度的方向上下降一小步(使用learning_rate控制步长大小)。
回到步骤2,继续执行。
class GradientDescentOptimizer:
def __init__(self, learning_rate):
self.learning_rate = learning_rate
def minimize(self, loss):
learning_rate = self.learning_rate
class MinimizationOperation(Operation):
def compute(self):
# Compute gradients
grad_table = compute_gradients(loss)
for node in grad_table:
if type(node) == Variable:
grad = grad_table[node]
node.value -= learning_rate * grad
return MinimizationOperation()
computegradients函数通过反向传递算法计算梯度,gradtable字典存放了代价函数J节点对计算图中所有variable节点的当前梯度。
反向传递算法链式法则是计算梯度的基本法则。下图和公式显示了e对a的梯度计算:
![3559cf3eddd3986a6c1c1f41a07c443f.png](https://i-blog.csdnimg.cn/blog_migrate/d6e0cc9e5bddbc091f7437b2f3292a44.png)
![b1092e40f9ccb491cc45c243721953c6.png](https://i-blog.csdnimg.cn/blog_migrate/c15848e4e87496fae4e4b41eeeb97da2.png)
J节点自身的梯度为1。
对任意节点z的所有子节点consumer,计算子节点的梯度。
将子节点的梯度乘以节点z本身的梯度得到J节点对任意节点z的梯度。
from queue import Queue
def compute_gradients(loss):
# grad_table[node] will contain the gradient of the loss w.r.t. the node's output
...
return grad_table
节点自身的梯度Operation的自身梯度通过预先定义,使用RegisterGradient注册到全局变量gradientregistry中。以sigmoid函数为例:
@RegisterGradient("sigmoid")
def _sigmoid_gradient(op, grad):
sigmoid = op.output
return grad * sigmoid * (1-sigmoid)
实践:搭建MLP
![ef4059539c5597620ae67b038caccdeb.png](https://i-blog.csdnimg.cn/blog_migrate/eebd9c56978d226c4e2b85fdbeb90f28.jpeg)
# Create a new graph
ts.Graph().as_default()
# Create training input placeholder
X = ts.placeholder()
# Create placeholder for the training classes
c = ts.placeholder()
# Build a hidden layer
W_hidden1 = ts.Variable(np.random.randn(2, 4))
b_hidden1 = ts.Variable(np.random.randn(4))
p_hidden1 = ts.sigmoid(ts.add(ts.matmul(X, W_hidden1), b_hidden1))
# Build a hidden layer
W_hidden2 = ts.Variable(np.random.randn(4, 8))
b_hidden2 = ts.Variable(np.random.randn(8))
p_hidden2 = ts.sigmoid(ts.add(ts.matmul(p_hidden1, W_hidden2), b_hidden2))
# Build a hidden layer
W_hidden3 = ts.Variable(np.random.randn(8, 2))
b_hidden3 = ts.Variable(np.random.randn(2))
p_hidden3 = ts.sigmoid(ts.add(ts.matmul(p_hidden2, W_hidden3), b_hidden3))
# Build the output layer
W_output = ts.Variable(np.random.randn(2, 2))
b_output = ts.Variable(np.random.randn(2))
p_output = ts.softmax(ts.add(ts.matmul(p_hidden3, W_output), b_output))
# Build cross-entropy loss
J = ts.negative(ts.reduce_sum(ts.reduce_sum(ts.multiply(c, ts.log(p_output)), axis=1)))
# Build minimization op
minimization_op = ts.train.GradientDescentOptimizer(learning_rate=0.03).minimize(J)
# Build placeholder inputs
feed_dict = {
X: np.concatenate((blue_points, red_points)),
c:
[[1, 0]] * len(blue_points)
+ [[0, 1]] * len(red_points)
}
# Create session
session = ts.Session()
# Perform 100 gradient descent steps
for step in range(2000):
J_value = session.run(J, feed_dict)
if step % 100 == 0:
print("Step:", step, " Loss:", J_value)
session.run(minimization_op, feed_dict)
通过可视化决策边界,可以发现模型学习到了比较复杂的非线性关系。
![f377c15a4f14aa1da7584649d04c1a3b.png](https://i-blog.csdnimg.cn/blog_migrate/9b8b0b5b2ba4cdb9487a5ea585e42986.png)
TensorSlow简单深刻的展示了深度学习框架底层的一般原理,加深理解生产使用的TensorFlow。
TensorFlow后端使用C++高效实现。
TensroFlow优化了算法过程,比如公共表达式消除,常量折叠。
TensorFlow支持分布式,支持GPU等硬件设备。
TensorFlow提供生产化的一系列工具。
![93d33b87c49a620806bb748b5a1ea856.png](https://i-blog.csdnimg.cn/blog_migrate/c67f228f0ccf50300ef1ffd997252242.jpeg)