自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

沒錯,純SQL查詢語句可以實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)

數(shù)據(jù)庫 深度學(xué)習(xí)
在這篇文章中,我們將純粹用SQL實(shí)現(xiàn)含有一個(gè)隱藏層(以及帶 ReLU 和 softmax 激活函數(shù))的神經(jīng)網(wǎng)絡(luò)。這些神經(jīng)網(wǎng)絡(luò)訓(xùn)練的步驟包含前向傳播和反向傳播,將在 BigQuery 的單個(gè)SQL查詢語句中實(shí)現(xiàn)。當(dāng)它在 BigQuery 中運(yùn)行時(shí),實(shí)際上我們正在成百上千臺服務(wù)器上進(jìn)行分布式神經(jīng)網(wǎng)絡(luò)訓(xùn)練。

[[229220]]

我們熟知的SQL是一種數(shù)據(jù)庫查詢語句,它方便了開發(fā)者在大型數(shù)據(jù)中執(zhí)行高效的操作。但本文從另一角度嵌套SQL查詢語句而構(gòu)建了一個(gè)簡單的三層全連接網(wǎng)絡(luò),雖然由于語句的嵌套過深而不能高效計(jì)算,但仍然是一個(gè)非常有意思的實(shí)驗(yàn)。

在這篇文章中,我們將純粹用SQL實(shí)現(xiàn)含有一個(gè)隱藏層(以及帶 ReLU 和 softmax 激活函數(shù))的神經(jīng)網(wǎng)絡(luò)。這些神經(jīng)網(wǎng)絡(luò)訓(xùn)練的步驟包含前向傳播和反向傳播,將在 BigQuery 的單個(gè)SQL查詢語句中實(shí)現(xiàn)。當(dāng)它在 BigQuery 中運(yùn)行時(shí),實(shí)際上我們正在成百上千臺服務(wù)器上進(jìn)行分布式神經(jīng)網(wǎng)絡(luò)訓(xùn)練。聽上去很贊,對吧?

也就是說,這個(gè)有趣的項(xiàng)目用于測試 SQL 和 BigQuery 的限制,同時(shí)從聲明性數(shù)據(jù)的角度看待神經(jīng)網(wǎng)絡(luò)訓(xùn)練。這個(gè)項(xiàng)目沒有考慮任何的實(shí)際應(yīng)用,不過***我將討論一些實(shí)際的研究意義。

我們先從一個(gè)基于神經(jīng)網(wǎng)絡(luò)的簡單分類器開始。它的輸入尺寸為 2,輸出為二分類。我們將有一個(gè)維度為 2 的單隱層和 ReLU 激活函數(shù)。輸出層的二分類將使用 softmax 函數(shù)。我們在實(shí)現(xiàn)網(wǎng)絡(luò)時(shí)遵循的步驟將是在  Karpathy’s CS231n 指南(https://cs231n.github.io/neural-networks-case-study/)中展示的基于 SQL 版本的 Python 示例。

模型

該模型含有以下參數(shù):

輸入到隱藏層

  • W: 2×2 的權(quán)重矩陣(元素: w_00, w_01, w_10, w_11)
  • B: 2×1 的偏置向量(元素:b_0, b_1)

隱藏到輸出層

  • W2: 2×2 的權(quán)重矩陣(元素: w2_00, w2_01, w2_10, w2_11)
  • B2: 2×1 的偏置向量(元素:b2_0, b2_1)

訓(xùn)練數(shù)據(jù)存儲在 BigQuery 表格當(dāng)中,列 x1 和 x2 的輸入和輸出如下所示(表格名稱:example_project.example_dataset.example_table)

如前所述,我們將整個(gè)訓(xùn)練作為單個(gè) SQL 查詢語句來實(shí)現(xiàn)。在訓(xùn)練完成后,通過 SQL 查詢語句將會返回參數(shù)的值。正如你可能猜到的,這將是一個(gè)層層嵌套的查詢,我們將逐步構(gòu)建以準(zhǔn)備這個(gè)查詢語句。我們將會從最內(nèi)層的子查詢開始,然后逐個(gè)增加嵌套的外層。

前向傳播

首先,我們將權(quán)重參數(shù)  W 和 W2 設(shè)為服從正態(tài)分布的隨機(jī)值,將權(quán)重參數(shù) B 和 B2 設(shè)置為 0。 W 和 W2 的隨機(jī)值可以通過 SQL 本身產(chǎn)生。為了簡單起見,我們將從外部生成這些值并在 SQL 查詢中使用。用于初始化參數(shù)的內(nèi)部子查詢?nèi)缦拢?nbsp;

  1. SELECT *,     
  2.                -0.00569693  AS w_00,  
  3.                0.00186517  AS w_01,  
  4.                0.00414431  AS w_10,  
  5.                0.0105101  AS w_11,  
  6.                0.0  AS b_0, 
  7.                0.0  AS b_1, 
  8.                -0.01312284  AS w2_00, 
  9.                - 0.01269512  AS w2_01, 
  10.               0.00379152  AS w2_10,      
  11.               -0.01218354  AS w2_11, 
  12.               0.0  AS b2_0, 
  13.               0.0  AS b2_1 
  14.  FROM  `example_project.example_dataset.example_table` 

請注意,表格 example_project.example_dataset.example_table 已經(jīng)包含了列  x1、 x2 和 y。模型參數(shù)將會被作為上述查詢結(jié)果的附加列添加。

接下來,我們將計(jì)算隱藏層的激活值。我們將使用含有元素 d0 和 d1 的向量 D 表示隱藏層。我們需要執(zhí)行矩陣操作 D = np.maximum(0, np.dot(X, W) + B),其中 X 表示輸入向量(元素 x1 和 x2)。這個(gè)矩陣運(yùn)算包括將權(quán)重 W 和輸入 X 相乘,再加上偏置向量 B。然后,結(jié)果將被傳遞給非線性 ReLU 激活函數(shù),該函數(shù)將會把負(fù)值設(shè)置為 0。SQL 中的等效查詢?yōu)椋?nbsp;

  1. SELECT *,       
  2.            (CASE 
  3.             WHEN ((x1*w_00 + x2*w_10) + b_0) > 0.0 THEN ((x1*w_00 + x2*w_10) + b_0) 
  4.             ELSE 0.0 
  5.         ENDAS d0, 
  6.        (CASE 
  7.             WHEN ((x1*w_01 + x2*w_11) + b_0) > 0.0 THEN ((x1*w_01 + x2*w_11) + b_1) 
  8.             ELSE 0.0 
  9.         ENDAS d1 
  10. FROM {inner subquery} 

上面的查詢將兩個(gè)新列 d0 和 d1 添加到之前內(nèi)部子查詢的結(jié)果當(dāng)中。 上述查詢的輸出如下所示。

這完成了從輸入層到隱藏層的一次轉(zhuǎn)換?,F(xiàn)在,我們可以執(zhí)行從隱藏層到輸出層的轉(zhuǎn)換了。

首先,我們將計(jì)算輸出層的值。公式是:scores = np.dot(D, W2) + B2。然后,我們將對計(jì)算出來的值用 softmax 函數(shù)來獲得每個(gè)類的預(yù)測概率。SQL 內(nèi)部的等價(jià)子查詢?nèi)缦拢?nbsp;

  1. SELECT *, 
  2.        EXP(scores_0)/(EXP(scores_0) + EXP(scores_1)) AS probs_0, 
  3.        EXP(scores_1)/(EXP(scores_0) + EXP(scores_1)) AS probs_1 
  4. FROM   
  5. SELECT *,    
  6.                 ((d0*w2_00 + d1*w2_10) + b2_0) AS scores_0, 
  7.                 ((d0*w2_01 + d1*w2_11) + b2_1) AS scores_1 
  8.    FROM {INNER sub-query}) 

首先,我們將使用交叉熵?fù)p失函數(shù)來計(jì)算當(dāng)前預(yù)測的總損失。首先,計(jì)算每個(gè)樣本中正確類預(yù)測概率對數(shù)的負(fù)值。交叉熵?fù)p失只是這些 X 和 Y 實(shí)例中數(shù)值的平均值。自然對數(shù)是一個(gè)遞增函數(shù),因此,將損失函數(shù)定義為負(fù)的正確類預(yù)測概率對數(shù)很直觀。如果正確類的預(yù)測概率很高,損失函數(shù)將會很低。相反,如果正確類的預(yù)測概率很低,則損失函數(shù)值將很高。

為了減少過擬合的風(fēng)險(xiǎn),我們也將同樣增加 L2 正則化。在整體損失函數(shù)中,我們將包含 0.5*reg*np.sum(W*W) + 0.5*reg*np.sum(W2*W2),其中 reg 是超參數(shù)。在損失函數(shù)中包括這一函數(shù)將會懲罰那些權(quán)重向量中較大的值。

在查詢當(dāng)中,我們同樣會計(jì)算訓(xùn)練樣本的數(shù)量(num_examples)。這對于后續(xù)我們計(jì)算平均值來說很有用。SQL 查詢中計(jì)算整體損失函數(shù)的語句如下: 

  1. SELECT *,    
  2.     (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 
  3. FROM   
  4.    (SELECT *,   
  5.                     SUM(correct_logprobs)  OVER ()  sum_correct_logprobs, 
  6.                                      COUNT(1)  OVER ()  num_examples 
  7.    FROM    
  8.       (SELECT *,   
  9.                      (CASE 
  10.                           WHEN y = 0 THEN -1*LOG(probs_0) 
  11.                           ELSE -1*LOG(probs_1) 
  12.                     ENDAS correct_logprobs 
  13.       FROM {inner subquery})) 

反向傳播

接下來,對于反向傳播,我們將計(jì)算每個(gè)參數(shù)對于損失函數(shù)的偏導(dǎo)數(shù)。我們使用鏈?zhǔn)椒▌t從***一層開始逐層計(jì)算。首先,我們將通過使用交叉熵和 softmax 函數(shù)的導(dǎo)數(shù)來計(jì)算 score 的梯度。與此相對的查詢是: 

  1. SELECT *,    
  2.               (CASE 
  3.                          WHEN y = 0  THEN (probs_0–1)/num_examples            ELSE probs_0/num_examples 
  4.                END)  AS dscores_0, 
  5.              (CASE 
  6.                         WHEN y = 1 THEN (probs_1–1)/num_examples            ELSE probs_1/num_examples 
  7.               END)  AS dscores_1  
  8. FROM {inner subquery} 

在上文中,我們用  scores = np.dot(D, W2) + B2 算出了分?jǐn)?shù)。因此,基于分?jǐn)?shù)的偏導(dǎo)數(shù),我們可以計(jì)算隱藏層 D 和參數(shù) W2,B2 的梯度。對應(yīng)的查詢語句是: 

  1. SELECT *, 
  2.        SUM(d0*dscores_0) OVER () AS dw2_00, 
  3.        SUM(d0*dscores_1) OVER () AS dw2_01,  
  4.        SUM(d1*dscores_0) OVER () AS dw2_10,  
  5.        SUM(d1*dscores_1) OVER () AS dw2_11,  
  6.        SUM(dscores_0) OVER () AS db2_0,  
  7.        SUM(dscores_1) OVER () AS db2_1,  
  8.        CASE  
  9.           WHEN (d0) <= 0.0  THEN 0.0  
  10.           ELSE (dscores_0*w2_00 + dscores_1*w2_01)  
  11.        END AS dhidden_0,  
  12.       CASE  
  13.           WHEN (d1) <= 0.0 THEN 0.0  
  14.           ELSE (dscores_0*w2_10 + dscores_1*w2_11)  
  15.       END AS dhidden_1  
  16. FROM {inner subquery} 

同理,我們知道  D = np.maximum(0, np.dot(X, W) + B)。因此,通過 D 的偏導(dǎo),我們可以計(jì)算出 W 和 B 的導(dǎo)數(shù)。我們無須計(jì)算 X 的偏導(dǎo),因?yàn)樗皇悄P偷膮?shù),且也不必通過其它模型參數(shù)進(jìn)行計(jì)算。計(jì)算 W 和 B 的偏導(dǎo)的查詢語句如下: 

  1. SELECT *,  
  2.        SUM(x1*dhidden_0) OVER () AS dw_00,  
  3.        SUM(x1*dhidden_1) OVER () AS dw_01,  
  4.        SUM(x2*dhidden_0) OVER () AS dw_10,  
  5.        SUM(x2*dhidden_1) OVER () AS dw_11,  
  6.        SUM(dhidden_0) OVER () AS db_0,  
  7.        SUM(dhidden_1) OVER () AS db_1  
  8. FROM {inner subquery} 

***,我們使用 W、B、W2 及 B2 各自的導(dǎo)數(shù)進(jìn)行更新操作。計(jì)算公式是 param = learning_rate * d_param ,其中l(wèi)earning_rate 是參數(shù)。為了體現(xiàn) L2 正則化,我們會在計(jì)算 dW 和 dW2 時(shí)加入一個(gè)正則項(xiàng) reg*weight。我們也去掉如  dw_00, correct_logprobs 等緩存的列,它們曾在子查詢時(shí)被創(chuàng)建,用于保存訓(xùn)練數(shù)據(jù)(x1, x2 及 y 列) 和模型參數(shù)(權(quán)重和偏置項(xiàng))。對應(yīng)的查詢語句如下: 

  1. SELECT x1,  
  2.    x2, 
  3.        y,  
  4.        w_00 — (2.0)*(dw_00+(1e-3)*w_00) AS w_00,  
  5.        w_01 — (2.0)*(dw_01+(1e-3)*w_01) AS w_01,  
  6.        w_10 — (2.0)*(dw_10+(1e-3)*w_10) AS w_10,  
  7.        w_11 — (2.0)*(dw_11+(1e-3)*w_11) AS w_11,  
  8.        b_0 — (2.0)*db_0 AS b_0,  
  9.        b_1 — (2.0)*db_1 AS b_1, 
  10.        w2_00 — (2.0)*(dw2_00+(1e-3)*w2_00) AS w2_00,  
  11.        w2_01 — (2.0)*(dw2_01+(1e-3)*w2_01) AS w2_01, 
  12.        w2_10 — (2.0)*(dw2_10+(1e-3)*w2_10) AS w2_10,  
  13.        w2_11 — (2.0)*(dw2_11+(1e-3)*w2_11) AS w2_11,  
  14.        b2_0 — (2.0)*db2_0 AS b2_0,  
  15.        b2_1 — (2.0)*db2_1 AS b2_1  
  16. FROM {inner subquery} 

這包含了正向和反向傳播的一整個(gè)迭代過程。以上查詢語句將返回更新后的權(quán)重和偏置項(xiàng)。部分結(jié)果如下所示:

為了進(jìn)行多次訓(xùn)練迭代,我們將反復(fù)執(zhí)行上述過程。用一個(gè)簡單 Python 函數(shù)足以搞定,代碼鏈接如下:https://github.com/harisankarh/nn-sql-bq/blob/master/training.py。

因?yàn)榈螖?shù)太多,查詢語句嵌套嚴(yán)重。執(zhí)行 10 次訓(xùn)練迭代的查詢語句地址如下:

https://github.com/harisankarh/nn-sql-bq/blob/master/out.txt

因?yàn)椴樵冋Z句的多重嵌套和復(fù)雜度,在 BigQuery 中執(zhí)行查詢時(shí)多項(xiàng)系統(tǒng)資源告急。BigQuery 的標(biāo)準(zhǔn) SQL 擴(kuò)展的縮放性比傳統(tǒng) SQL 語言要好。即使是標(biāo)準(zhǔn) SQL 查詢,對于有 100k 個(gè)實(shí)例的數(shù)據(jù)集,也很難執(zhí)行超過 10 個(gè)迭代。因?yàn)橘Y源的限制,我們將會使用一個(gè)簡單的決策邊界來評估模型,如此一來,我們就可以在少量迭代后得到較好的準(zhǔn)確率。

我們將使用一個(gè)簡單的數(shù)據(jù)集,其輸入 X1、X2 服從標(biāo)準(zhǔn)正態(tài)分布。二進(jìn)制輸出 y 簡單判斷   x1 + x2 是否大于 0。為了更快的訓(xùn)練完 10 個(gè)迭代,我們使用一個(gè)較大的學(xué)習(xí)率 2.0(注意:這么大的學(xué)習(xí)率并不推薦實(shí)際使用,可能會導(dǎo)致發(fā)散)。將上述語句執(zhí)行 10 個(gè)迭代得出的模型參數(shù)如下:

我們將使用 Bigquery 的函數(shù) save to table 把結(jié)果保存到一個(gè)新表。我們現(xiàn)在可以在訓(xùn)練集上執(zhí)行一次推理來比較預(yù)測值和預(yù)期值的差距。查詢語句片段在以下鏈接中:

https://github.com/harisankarh/nn-sql-bq/blob/master/query_for_prediction.sql。

僅通過十個(gè)迭代,我們的準(zhǔn)確率就可達(dá) 93%(測試集上也差不多)。

如果我們把迭代次數(shù)加到 100 次,準(zhǔn)確率高達(dá) 99%。

優(yōu)化

下面是對本項(xiàng)目的總結(jié)。我們由此獲得了哪些啟發(fā)?如你所見,資源瓶頸決定了數(shù)據(jù)集的大小以及迭代執(zhí)行的次數(shù)。除了祈求谷歌開放資源上限,我們還有如下優(yōu)化手段來解決這個(gè)問題。

創(chuàng)建中間表和多個(gè) SQL 語句有助于增加迭代數(shù)。例如,前 10 次迭代的結(jié)果可以存儲在一個(gè)中間表中。同一查詢語句在執(zhí)行下 10 次迭代時(shí)可以基于這個(gè)中間表。如此,我們就執(zhí)行了 20 個(gè)迭代。這個(gè)方法可以反復(fù)使用,以應(yīng)對更大的查詢迭代。

相比于在每一步增加外查詢,我們應(yīng)該盡可能的使用函數(shù)的嵌套。例如,在一個(gè)子查詢中,我們可以同時(shí)計(jì)算 scores 和 probs,而不應(yīng)使用 2 層嵌套查詢。

在上例中,所有的中間項(xiàng)都被保留直到***一個(gè)外查詢執(zhí)行。其中有些項(xiàng)如 correct_logprobs 可以早些刪除(盡管 SQL 引擎可能會自動的執(zhí)行這類優(yōu)化)。

多嘗試應(yīng)用用戶自定義的函數(shù)。如果感興趣,你可以看看這個(gè) BigQuery 的用戶自定義函數(shù)的服務(wù)模型的項(xiàng)目(但是,無法使用 SQL 或者 UDFs 進(jìn)行訓(xùn)練)。

意義

現(xiàn)在,讓我們來看看基于深度學(xué)習(xí)的分布式 SQL 引擎的深層含義。 BigQuery、Presto  這類 SQL 倉庫引擎的一個(gè)局限性在于,查詢操作是在 CPU 而不是 GPU 上執(zhí)行的。研究 blazingdb 和 mapd 等基于 GPU 加速的數(shù)據(jù)庫查詢結(jié)果想必十分有趣。一個(gè)簡單的研究方法就是使用分布式 SQL 引擎執(zhí)行查詢和數(shù)據(jù)分布,并用 GPU 加速數(shù)據(jù)庫執(zhí)行本地計(jì)算。

退一步來看,我們已經(jīng)知道執(zhí)行分布式深度學(xué)習(xí)很難。分布式 SQL 引擎在數(shù)十年內(nèi)已經(jīng)有了大量的研究工作,并產(chǎn)出如今的查詢規(guī)劃、數(shù)據(jù)分區(qū)、操作歸置、檢查點(diǎn)設(shè)置、多查詢調(diào)度等技術(shù)。其中有些可以與分布式深度學(xué)習(xí)相結(jié)合。如果你對這些感興趣,請看看這篇論文(https://sigmodrecord.org/publications/sigmodRecord/1606/pdfs/04_vision_Wang.pdf),該論文對分布式數(shù)據(jù)庫和分布式深度學(xué)習(xí)展開了廣泛的研究討論。 

原文鏈接:https://towardsdatascience.com/deep-neural-network-implemented-in-pure-sql-over-bigquery-f3ed245814d3 

責(zé)任編輯:龐桂玉 來源: 數(shù)據(jù)與算法之美
相關(guān)推薦

2018-07-03 16:10:04

神經(jīng)網(wǎng)絡(luò)生物神經(jīng)網(wǎng)絡(luò)人工神經(jīng)網(wǎng)絡(luò)

2025-02-25 14:13:31

2021-12-20 09:00:00

深度學(xué)習(xí)神經(jīng)元網(wǎng)絡(luò)安全

2017-04-26 08:31:10

神經(jīng)網(wǎng)絡(luò)自然語言PyTorch

2010-10-21 10:28:13

SQL Server查

2018-10-18 10:27:15

機(jī)器學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)python

2020-07-22 18:11:07

神經(jīng)網(wǎng)絡(luò)函數(shù)代碼

2019-07-25 08:20:37

代碼開發(fā)神經(jīng)網(wǎng)絡(luò)

2022-02-15 23:38:22

Python機(jī)器學(xué)習(xí)算法

2023-10-09 08:00:00

ChatGPT人工智能

2019-12-17 10:16:34

MySQLSQL優(yōu)化數(shù)據(jù)庫

2022-04-07 09:01:52

神經(jīng)網(wǎng)絡(luò)人工智能

2017-05-04 18:30:34

大數(shù)據(jù)卷積神經(jīng)網(wǎng)絡(luò)

2019-05-07 19:12:28

機(jī)器學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)Python

2020-09-22 07:46:03

人工神經(jīng)網(wǎng)絡(luò)人工智能AI

2017-09-10 07:07:32

神經(jīng)網(wǎng)絡(luò)數(shù)據(jù)集可視化

2010-09-26 17:09:05

SQL語句

2017-07-18 10:20:30

Python神經(jīng)網(wǎng)絡(luò)

2017-03-13 14:45:51

Python神經(jīng)網(wǎng)絡(luò)基礎(chǔ)

2020-12-19 11:05:57

循環(huán)神經(jīng)網(wǎng)絡(luò)PyTorch神經(jīng)網(wǎng)絡(luò)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號