我们熟知的SQL是一种数据库查询语句,它方便了开发者在大型数据中执行高效的操作。但本文从另一角度嵌套SQL查询语句而构建了一个简单的三层全连接网络,虽然由于语句的嵌套过深而不能高效计算,但仍然是一个非常有意思的实验。
在这篇文章中,我们将纯粹用SQL实现含有一个隐藏层(以及带
ReLU 和 softmax 激活函数)的神经网络。这些神经网络训练的步骤包含前向传播和反向传播,将在 BigQuery
的单个SQL查询语句中实现。当它在 BigQuery 中运行时,实际上我们正在成百上千台服务器上进行分布式神经网络训练。听上去很赞,对吧?
也就是说,这个有趣的项目用于测试 SQL 和 BigQuery 的限制,同时从声明性数据的角度看待神经网络训练。这个项目没有考虑任何的实际应用,不过最后我将讨论一些实际的研究意义。
我们先从一个基于神经网络的简单分类器开始。它的输入尺寸为 2,输出为二分类。我们将有一个维度为 2 的单隐层和 ReLU 激活函数。输出层的二分类将使用 softmax 函数。我们在实现网络时遵循的步骤将是在 Karpathy’s CS231n 指南(https://cs231n.github.io/neural-networks-case-study/)中展示的基于 SQL 版本的 Python 示例。
模型
该模型含有以下参数:
输入到隐藏层
W: 2×2 的权重矩阵(元素: w_00, w_01, w_10, w_11)
B: 2×1 的偏置向量(元素:b_0, b_1)
隐藏到输出层
W2: 2×2 的权重矩阵(元素: w2_00, w2_01, w2_10, w2_11)
B2: 2×1 的偏置向量(元素:b2_0, b2_1)
训练数据存储在 BigQuery 表格当中,列 x1 和 x2 的输入和输出如下所示(表格名称:example_project.example_dataset.example_table)
如前所述,我们将整个训练作为单个 SQL 查询语句来实现。在训练完成后,通过 SQL 查询语句将会返回参数的值。正如你可能猜到的,这将是一个层层嵌套的查询,我们将逐步构建以准备这个查询语句。我们将会从最内层的子查询开始,然后逐个增加嵌套的外层。
前向传播
首先,我们将权重参数 W 和 W2 设为服从正态分布的随机值,将权重参数 B 和 B2 设置为 0。 W 和 W2 的随机值可以通过 SQL 本身产生。为了简单起见,我们将从外部生成这些值并在 SQL 查询中使用。用于初始化参数的内部子查询如下:
SELECT *,
-0.00569693 AS w_00,
0.00186517 AS w_01,
0.00414431 AS w_10,
0.0105101 AS w_11,
0.0 AS b_0,
0.0 AS b_1,
-0.01312284 AS w2_00,
-0.01269512 AS w2_01,
0.00379152 AS w2_10,
-0.01218354 AS w2_11,
0.0 AS b2_0,
0.0 AS b2_1
FROM `example_project.example_dataset.example_table`
请注意,表格 example_project.example_dataset.example_table 已经包含了列 x1、 x2 和 y。模型参数将会被作为上述查询结果的附加列添加。
接下来,我们将计算隐藏层的激活值。我们将使用含有元素 d0 和 d1 的向量 D 表示隐藏层。我们需要执行矩阵操作 D = np.maximum(0, np.dot(X, W) + B),其中 X 表示输入向量(元素 x1 和 x2)。这个矩阵运算包括将权重 W 和输入 X 相乘,再加上偏置向量 B。然后,结果将被传递给非线性 ReLU 激活函数,该函数将会把负值设置为 0。SQL 中的等效查询为:
SELECT *,
(CASE
WHEN ((x1*w_00 + x2*w_10) + b_0) >0.0THEN ((x1*w_00 + x2*w_10) + b_0)
ELSE0.0
END) AS d0,
(CASE
WHEN ((x1*w_01 + x2*w_11) + b_0) >0.0THEN ((x1*w_01 + x2*w_11) + b_1)
ELSE0.0
END) AS d1
FROM {inner subquery}
上面的查询将两个新列 d0 和 d1 添加到之前内部子查询的结果当中。 上述查询的输出如下所示。
这完成了从输入层到隐藏层的一次转换。现在,我们可以执行从隐藏层到输出层的转换了。
首先,我们将计算输出层的值。公式是:scores = np.dot(D, W2) + B2。然后,我们将对计算出来的值用 softmax 函数来获得每个类的预测概率。SQL 内部的等价子查询如下:
SELECT *,
EXP(scores_0)/(EXP(scores_0) + EXP(scores_1)) AS probs_0,
EXP(scores_1)/(EXP(scores_0) + EXP(scores_1)) AS probs_1
FROM
( SELECT *,
((d0*w2_00 + d1*w2_10) + b2_0) AS scores_0,
((d0*w2_01 + d1*w2_11) + b2_1) AS scores_1
FROM {INNER sub-query})
首先,我们将使用交叉熵损失函数来计算当前预测的总损失。首先,计算每个样本中正确类预测概率对数的负值。交叉熵损失只是这些 X 和 Y 实例中数值的平均值。自然对数是一个递增函数,因此,将损失函数定义为负的正确类预测概率对数很直观。如果正确类的预测概率很高,损失函数将会很低。相反,如果正确类的预测概率很低,则损失函数值将很高。
为了减少过拟合的风险,我们也将同样增加 L2 正则化。在整体损失函数中,我们将包含 0.5*reg*np.sum(W*W) + 0.5*reg*np.sum(W2*W2),其中 reg 是超参数。在损失函数中包括这一函数将会惩罚那些权重向量中较大的值。
在查询当中,我们同样会计算训练样本的数量(num_examples)。这对于后续我们计算平均值来说很有用。SQL 查询中计算整体损失函数的语句如下:
SELECT *,
(sum_correct_logprobs/num_examples) +1e-3*(0.5*(w_00*w_00 + w_01*w_01 + w_10*w_10 + w_11*w_11) +0.5*(w2_00*w2_00 + w2_01*w2_01 + w2_10*w2_10 + w2_11*w2_11)) AS loss
FROM
(SELECT *,
SUM(correct_logprobs) OVER () sum_correct_logprobs,
COUNT(1) OVER () num_examples
FROM
(SELECT *,
(CASE
WHEN y =0THEN -1*LOG(probs_0)
ELSE -1*LOG(probs_1)
END) AS correct_logprobs
FROM {inner subquery}))
反向传播
接下来,对于反向传播,我们将计算每个参数对于损失函数的偏导数。我们使用链式法则从最后一层开始逐层计算。首先,我们将通过使用交叉熵和 softmax 函数的导数来计算 score 的梯度。与此相对的查询是:
SELECT *,
(CASE
WHEN y =0THEN (probs_0–1)/num_examples
ELSE probs_0/num_examples
END) AS dscores_0,
(CASE
WHEN y =1THEN (probs_1–1)/num_examples
ELSE probs_1/num_examples
END) AS dscores_1
FROM {inner subquery}
在上文中,我们用 scores = np.dot(D, W2) + B2 算出了分数。因此,基于分数的偏导数,我们可以计算隐藏层 D 和参数 W2,B2 的梯度。对应的查询语句是:
SELECT *,
SUM(d0*dscores_0) OVER () AS dw2_00,
SUM(d0*dscores_1) OVER () AS dw2_01,
SUM(d1*dscores_0) OVER () AS dw2_10,
SUM(d1*dscores_1) OVER () AS dw2_11,
SUM(dscores_0) OVER () AS db2_0,
SUM(dscores_1) OVER () AS db2_1,
CASE
WHEN (d0) <=0.0THEN0.0
ELSE (dscores_0*w2_00 + dscores_1*w2_01)
END AS dhidden_0,
CASE
WHEN (d1) <=0.0THEN0.0
ELSE (dscores_0*w2_10 + dscores_1*w2_11)
END AS dhidden_1
FROM {inner subquery}
同理,我们知道 D = np.maximum(0, np.dot(X, W) + B)。因此,通过 D 的偏导,我们可以计算出 W 和 B 的导数。我们无须计算 X 的偏导,因为它不是模型的参数,且也不必通过其它模型参数进行计算。计算 W 和 B 的偏导的查询语句如下:
SELECT *,
SUM(x1*dhidden_0) OVER () AS dw_00,
SUM(x1*dhidden_1) OVER () AS dw_01,
SUM(x2*dhidden_0) OVER () AS dw_10,
SUM(x2*dhidden_1) OVER () AS dw_11,
SUM(dhidden_0) OVER () AS db_0,
SUM(dhidden_1) OVER () AS db_1
FROM {inner subquery}
最后,我们使用 W、B、W2 及 B2 各自的导数进行更新操作。计算公式是 param = learning_rate * d_param ,其中learning_rate 是参数。为了体现 L2 正则化,我们会在计算 dW 和 dW2 时加入一个正则项 reg*weight。我们也去掉如 dw_00, correct_logprobs 等缓存的列,它们曾在子查询时被创建,用于保存训练数据(x1, x2 及 y 列) 和模型参数(权重和偏置项)。对应的查询语句如下:
SELECT x1,
x2,
y,
w_00 — (2.0)*(dw_00+(1e-3)*w_00) AS w_00,
w_01 — (2.0)*(dw_01+(1e-3)*w_01) AS w_01,
w_10 — (2.0)*(dw_10+(1e-3)*w_10) AS w_10,
w_11 — (2.0)*(dw_11+(1e-3)*w_11) AS w_11,
b_0 — (2.0)*db_0 AS b_0,
b_1 — (2.0)*db_1 AS b_1,
w2_00 — (2.0)*(dw2_00+(1e-3)*w2_00) AS w2_00,
w2_01 — (2.0)*(dw2_01+(1e-3)*w2_01) AS w2_01,
w2_10 — (2.0)*(dw2_10+(1e-3)*w2_10) AS w2_10,
w2_11 — (2.0)*(dw2_11+(1e-3)*w2_11) AS w2_11,
b2_0 — (2.0)*db2_0 AS b2_0,
b2_1 — (2.0)*db2_1 AS b2_1
FROM {inner subquery}
这包含了正向和反向传播的一整个迭代过程。以上查询语句将返回更新后的权重和偏置项。部分结果如下所示:
为了进行多次训练迭代,我们将反复执行上述过程。用一个简单 Python 函数足以搞定,代码链接如下:https://github.com/harisankarh/nn-sql-bq/blob/master/training.py。
因为迭代次数太多,查询语句嵌套严重。执行 10 次训练迭代的查询语句地址如下:
https://github.com/harisankarh/nn-sql-bq/blob/master/out.txt
因为查询语句的多重嵌套和复杂度,在 BigQuery 中执行查询时多项系统资源告急。BigQuery 的标准 SQL 扩展的缩放性比传统 SQL 语言要好。即使是标准 SQL 查询,对于有 100k 个实例的数据集,也很难执行超过 10 个迭代。因为资源的限制,我们将会使用一个简单的决策边界来评估模型,如此一来,我们就可以在少量迭代后得到较好的准确率。
我们将使用一个简单的数据集,其输入 X1、X2 服从标准正态分布。二进制输出 y 简单判断 x1 + x2 是否大于 0。为了更快的训练完 10 个迭代,我们使用一个较大的学习率 2.0(注意:这么大的学习率并不推荐实际使用,可能会导致发散)。将上述语句执行 10 个迭代得出的模型参数如下:
我们将使用 Bigquery 的函数 save to table 把结果保存到一个新表。我们现在可以在训练集上执行一次推理来比较预测值和预期值的差距。查询语句片段在以下链接中:
https://github.com/harisankarh/nn-sql-bq/blob/master/query_for_prediction.sql。
仅通过十个迭代,我们的准确率就可达 93%(测试集上也差不多)。
如果我们把迭代次数加到 100 次,准确率高达 99%。
优化
下面是对本项目的总结。我们由此获得了哪些启发?如你所见,资源瓶颈决定了数据集的大小以及迭代执行的次数。除了祈求谷歌开放资源上限,我们还有如下优化手段来解决这个问题。
创建中间表和多个 SQL 语句有助于增加迭代数。例如,前 10 次迭代的结果可以存储在一个中间表中。同一查询语句在执行下 10 次迭代时可以基于这个中间表。如此,我们就执行了 20 个迭代。这个方法可以反复使用,以应对更大的查询迭代。
相比于在每一步增加外查询,我们应该尽可能的使用函数的嵌套。例如,在一个子查询中,我们可以同时计算 scores 和 probs,而不应使用 2 层嵌套查询。
在上例中,所有的中间项都被保留直到最后一个外查询执行。其中有些项如 correct_logprobs 可以早些删除(尽管 SQL 引擎可能会自动的执行这类优化)。
多尝试应用用户自定义的函数。如果感兴趣,你可以看看这个 BigQuery 的用户自定义函数的服务模型的项目(但是,无法使用 SQL 或者 UDFs 进行训练)。
意义
现在,让我们来看看基于深度学习的分布式 SQL 引擎的深层含义。 BigQuery、Presto 这类 SQL 仓库引擎的一个局限性在于,查询操作是在 CPU 而不是 GPU 上执行的。研究 blazingdb 和 mapd 等基于 GPU 加速的数据库查询结果想必十分有趣。一个简单的研究方法就是使用分布式 SQL 引擎执行查询和数据分布,并用 GPU 加速数据库执行本地计算。
退一步来看,我们已经知道执行分布式深度学习很难。分布式 SQL 引擎在数十年内已经有了大量的研究工作,并产出如今的查询规划、数据分区、操作归置、检查点设置、多查询调度等技术。其中有些可以与分布式深度学习相结合。如果你对这些感兴趣,请看看这篇论文(https://sigmodrecord.org/publications/sigmodRecord/1606/pdfs/04_vision_Wang.pdf),该论文对分布式数据库和分布式深度学习展开了广泛的研究讨论。
数据分析咨询请扫描二维码
在准备数据分析师面试时,掌握高频考题及其解答是应对面试的关键。为了帮助大家轻松上岸,以下是10个高频考题及其详细解析,外加 ...
2024-12-20互联网数据分析师是一个热门且综合性的职业,他们通过数据挖掘和分析,为企业的业务决策和运营优化提供强有力的支持。尤其在如今 ...
2024-12-20在现代商业环境中,数据分析师是不可或缺的角色。他们的工作不仅仅是对数据进行深入分析,更是协助企业从复杂的数据信息中提炼出 ...
2024-12-20随着大数据时代的到来,数据驱动的决策方式开始受到越来越多企业的青睐。近年来,数据分析在人力资源管理中正在扮演着至关重要的 ...
2024-12-20在数据分析的世界里,表面上的技术操作只是“入门票”,而真正的高手则需要打破一些“看不见的墙”。这些“隐形天花板”限制了数 ...
2024-12-19在数据分析领域,尽管行业前景广阔、岗位需求旺盛,但实际的工作难度却远超很多人的想象。很多新手初入数据分析岗位时,常常被各 ...
2024-12-19入门数据分析,许多人都会感到“难”,但这“难”究竟难在哪儿?对于新手而言,往往不是技术不行,而是思维方式、业务理解和实践 ...
2024-12-19在如今的行业动荡背景下,数据分析师的职业前景虽然面临一些挑战,但也充满了许多新的机会。随着技术的不断发展和多领域需求的提 ...
2024-12-19在信息爆炸的时代,数据分析师如同探险家,在浩瀚的数据海洋中寻觅有价值的宝藏。这不仅需要技术上的过硬实力,还需要一种艺术家 ...
2024-12-19在当今信息化社会,大数据已成为各行各业不可或缺的宝贵资源。大数据专业应运而生,旨在培养具备扎实理论基础和实践能力,能够应 ...
2024-12-19阿里P8、P9失业都找不到工作?是我们孤陋寡闻还是世界真的已经“癫”成这样了? 案例一:本硕都是 985,所学的专业也是当红专业 ...
2024-12-19CDA持证人Louis CDA持证人基本情况 我大学是在一个二线城市的一所普通二本院校读的,专业是旅游管理,非计算机非统计学。毕业之 ...
2024-12-18最近,知乎上有个很火的话题:“一个人为何会陷入社会底层”? 有人说,这个世界上只有一个分水岭,就是“羊水”;还有人说,一 ...
2024-12-18在这个数据驱动的时代,数据分析师的技能需求快速增长。掌握适当的编程语言不仅能增强分析能力,还能帮助分析师从海量数据中提取 ...
2024-12-17在当今信息爆炸的时代,数据分析已经成为许多行业中不可或缺的一部分。想要在这个领域脱颖而出,除了热情和毅力外,你还需要掌握 ...
2024-12-17数据分析,是一项通过科学方法处理数据以获取洞察并支持决策的艺术。无论是在商业环境中提升业绩,还是在科研领域推动创新,数据 ...
2024-12-17在数据分析领域,图表是我们表达数据故事的重要工具。它们不仅让数据变得更加直观,也帮助我们更好地理解数据中的趋势和模式。相 ...
2024-12-16在当今社会,我们身处着一个飞速发展、变化迅猛的时代。不同行业在科技进步、市场需求和政策支持的推动下蓬勃发展,呈现出令人瞩 ...
2024-12-16在现代商业世界中,数据分析师扮演着至关重要的角色。他们通过解析海量数据,为企业战略决策提供有力支持。要有效完成这项任务, ...
2024-12-16在当今数据爆炸的时代,数据分析师是组织中不可或缺的导航者。他们通过从大量数据中提取可操作的洞察力,帮助企业在竞争激烈的市 ...
2024-12-16