沒錯,純SQL查詢語句可以實現神經網絡

2021-01-11 機器之心Pro

選自Medium

作者:Harisankar Haridas

機器之心編譯

參與:陳韻竹、思源

我們熟知的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.0 THEN ((x1*w_00 + x2*w_10) + b_0)

ELSE 0.0

END) AS d0,

(CASE

WHEN ((x1*w_01 + x2*w_11) + b_0) > 0.0 THEN ((x1*w_01 + x2*w_11) + b_1)

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 *,

WHEN y = 0 THEN -1*LOG(probs_0)

ELSE -1*LOG(probs_1)

END) AS correct_logprobs

FROM {inner subquery}))

反向傳播

接下來,對於反向傳播,我們將計算每個參數對於損失函數的偏導數。我們使用鏈式法則從最後一層開始逐層計算。首先,我們將通過使用交叉熵和 softmax 函數的導數來計算 score 的梯度。與此相對的查詢是:

SELECT *,

WHEN y = 0 THEN (probs_0–1)/num_examples

ELSE probs_0/num_examples

END) AS dscores_0,

WHEN y = 1 THEN (probs_1–1)/num_examples

END) AS dscores_1

在上文中,我們用 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.0 THEN 0.0

ELSE (dscores_0*w2_00 + dscores_1*w2_01)

END AS dhidden_0,

ELSE (dscores_0*w2_10 + dscores_1*w2_11)

END AS dhidden_1

同理,我們知道 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

最後,我們使用 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

這包含了正向和反向傳播的一整個迭代過程。以上查詢語句將返回更新後的權重和偏置項。部分結果如下所示:

為了進行多次訓練迭代,我們將反覆執行上述過程。用一個簡單 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),該論文對分布式資料庫和分布式深度學習展開了廣泛的研究討論。

希望你如我一般享受其中!請在下方分享你的高見。

相關焦點

  • 請確保你查詢mysql資料庫時,sql語句沒有這麼寫_手機網易網
    2020-11-23 19:20:11 來源: 小燕愛生活 舉報   資料庫索引,可以讓查詢
  • MyBatis Dynamic SQL 1.0.0,生成動態 SQL 語句的框架
    MyBatis Dynamic SQL 1.0.0 發布了,這個庫是生成動態 SQL 語句的框架。
  • SQL語句性能調整之ORACLE的執行計劃
    如何產生執行計劃  要為一個語句生成執行計劃,可以有3種方法:  1).最簡單的辦法  Sql> set autotrace on  Sql> select * from dual;  執行完語句後,會顯示explain
  • PandaSQL:一個讓你能夠通過SQL語句進行pandas的操作的python包
    我們可以通過聯接項目列以及聯接條件(TransactionDt≥StartDt和TransactionDt≤EndDt)來實現這一點。因為現在我們的連接條件也有大於號和小於號,這樣的連接稱為不等連接。在繼續之前,一定要考慮如何在pandas中做這樣的事情。pandas的解決方案那麼在pandas身上該怎麼做呢?
  • sqltoy-orm-4.16.11 發版,部分功能優化
    的十四個關鍵特點:1、最簡最直觀的sql編寫方式(不僅僅是查詢語句),採用條件參數前置處理規整法,讓sql語句部分跟客戶端保持高度一致2、sql中支持注釋(規避了對hint特性的影響,知道hint嗎?搜oracle hint),和動態更新加載,便於開發和後期維護整個過程的管理3、支持緩存翻譯和反向緩存條件檢索(通過緩存將名稱匹配成精確的key),實現sql簡化和性能大幅提升4、支持快速分頁和分頁優化功能,實現分頁最高級別的優化,同時還考慮到了cte多個with as情況下的優化支持5、支持並行查詢6、根本杜絕sql注入問題,以後不需要討論這個話題7、支持行列轉換
  • 工作中,我們經常用到哪些SQL語句呢?
    工作中我們基本上每天都要與資料庫打交道,資料庫的知識點呢也特別多,全部記住呢也是不可能的,也沒必要把所有的記住(有些語句命令可能我們一輩子都用不到)。所以呢在工作之餘,把工作中經常用到的一些語句整理出來,忘記的時候可以當做字典來查。個人在工作中用Oracle資料庫比較多,就以關係型資料庫Oracle為例進行整理,後面可能會整理一些非關係型資料庫,如mogodb之類的。
  • 多表組合查詢——Python操作Mysql資料庫
    =、like等)進行查詢條件的比較,sql語句的寫法是:select A..* from A,B where A.主鍵=B.外鍵 and 其他查詢條件;假如我們想要查詢學生名字叫陳偉的學生的成績,在Python中舉例如下:進行等值連接查詢的sql語句編寫時,要明確指出數據源來源於哪幾張表,並且要很清楚的知道哪幾個欄位是相互關聯的,然後再添加其他的查詢條件。
  • MyBatis dynamic SQL 1.1.4 發布,生成動態 SQL 的框架
    MyBatis dynamic SQL 1.1.4 已發布,MyBatis Dynamic SQL 是生成動態 SQL 語句的框架,可把它看作是一個類型安全的 SQL 模板庫,它還支持 MyBatis3
  • 春眠不覺曉,SQL 知多少?|原力計劃
    (現在的 Oracle 公司)發現了關係模型的潛力,開發出了第一個商用 SQL 實現:Oracle V2(Version2)。隨著收購開源資料庫 MySQL,Oracle 公司已經牢牢佔據了資料庫市場的領先地位,同時也導致了 MariaDB 分支的出現。SQL 是關係模式的第一個商業實現,同時也是最成功的一個實現。SQL 是使用最廣泛的資料庫查詢語言。
  • sql查詢語句學習,多表查詢和子查詢以及連接查詢
    交叉連接查詢這種查詢方式基本不會使用,原因就是這種查詢方式得到的是兩個表的乘積(笛卡兒集)語法就是select * from a,b;內連接查詢,可以有效的去除笛卡爾集現象內連接查詢分為兩類:隱式內連接 select * from A,B where 條件隱式連接使用別名:select * from A 別名1,B 別名2 where 別名1.xx=別名2.xx;顯示內連接 select * from A inner join B on 條件 (inner可以省略)顯示連接使用別名: select
  • Oracle分組查詢group by的用法及講解
    group by是sql中比較強大的功能,是在對數據分組統計時必不可少的用法。但是,對於很多經驗不足的同學,經常會寫錯。今天我們就以Oracle為例,來講解下分組查詢group by的用法。我們接下來使用下聚合函數SELECT SSEX,MAX(SAGE) FROM STUDENT GROUP BY SSEX;注意這條sql語句,select子句中聚合函數使用了SAGE(年齡)這個欄位,那會不會違背了前面所說的 「select子句後的欄位必須來自group by後的分組欄位」這個規律呢,我們來執行一下:能正常執行,成功地按照了性別分組,並且查詢出了性別對應年齡最大的學生
  • Java最新SQL注入原因以及預防方案(易理解)
    我們在查詢用戶名和密碼是否正確的時候,本來執行的sql語句是:select * from user where username = '' and password = ''.這樣的sql語句,現在我們輸入密碼是如上這樣的,然後我們會通過參數進行拼接,拼接後的sql語句就是:select * from user where username = '' and password = ' ' or '123' = '123 ';這樣的了,那麼會有一個or語句,只要這兩個有一個是正確的話,就條件成立,因此 123 = 123 是成立的。因此驗證就會被跳過。
  • 數據自動化第三篇(上):三種方法實現數據入庫功能
    上一節我們已經實現了資料庫連接池,視頻版和文字版的內容都已更新,這節我們將要連接資料庫,實現數據的增刪改查。但還有一點需要注意,在數據自動化當中很少有刪除操作,一般只涉及更新(新增)和查詢,所以,外面我們主要實現這兩個方法。
  • 讓機器自動寫SQL語言,首屆中文NL2SQL挑戰賽等你來戰
    我們可以將如上詢問手動寫成相應的 SQL 表達式:「SELECT SUM(銷量) FROM TABLE WHERE 品牌=="寶馬";」,從而得到答案「8」。但這種方式要求我們會 SQL 語句,且一種查詢就要寫一條表達式。而 NL2SQL 做的,就是希望能自動化這一過程,希望結合用戶想要查詢的表格,將用戶的問句轉化為相應的 SQL 語句。
  • SQL Server2008引擎組件和CPU性能監控
    命令解析器通過T-SQL哈希值向位於緩衝池中的Plan Cache發出匹配要求,以檢查是否存在該執行計劃;如果不存在則把T-SQL翻譯成可以執行的內部格式,即查詢樹。  查詢優化器(Optimizer)  查詢優化器從命令解析器中獲取查詢樹,並為它的實際執行做準備。
  • 這個函數讓SQL效率提升99%
    簡介窗口函數(window function), 也可以被稱為 OLAP函數 或 分析函數。窗口函數是在 ISO SQL 標準中定義的。窗口是用戶指定的一組行。窗口函數計算從窗口派生的結果集中各行的值。可以在單個查詢中將多個排名或聚合窗口函數與單個 FROM 子句一起使用。
  • 關係代數與SQL查詢優化的研究
    但是一個資料庫應用系統的查詢性能直接影響到系統的推廣和應用,因此資料庫系統性能和查詢優化成為資料庫應用領域備受關注的熱點問題。 影響資料庫系統性能的因素很多,包括資料庫連接方式、應用系統架構、資料庫設計、管理等。其中最本質又至關重要的是資料庫管理系統本身的查詢優化技術。
  • 30種SQL語句優化方法
    30種SQL語句優化方法 CSDN-青春微涼不離 發表於 2020-11-19 16:05:58 在SQL查詢中為了提高查詢效率,我們常常會採取一些措施對查詢語句進行
  • 一條查詢SQL在MySQL中是怎麼執行的
    這樣在我們以後遇到MySQL的一些異常或者問題的時候,就可以快速定位問題並解決問題。下邊通過一張圖來看一下SQL的執行流程,從中可以清楚的看到SQL語句在MySQL的各個功能模塊中執行的過程。從上圖來看,MySQL大體上可以分為Server層和存儲引擎層兩部分。