機器學(xué)習(xí)的當(dāng)前趨勢 機器學(xué)習(xí)目前有三大趨勢:概率編程,深度學(xué)習(xí)和“大數(shù)據(jù)”。在PP內(nèi)部,許多創(chuàng)新都在使用變分推理來進行規(guī)模擴展。在本文中,我將展示如何在PyMC3中使用變分推理來擬合簡單的貝葉斯神經(jīng)網(wǎng)絡(luò)。我還將討論如何在概率編程和深度學(xué)習(xí)之間架起橋梁,為將來的研究開辟非常有趣的途徑。 概率性編程規(guī)劃 概率編程允許非常靈活地創(chuàng)建自定義概率模型,主要關(guān)注從數(shù)據(jù)中洞察和學(xué)習(xí)。該方法本質(zhì)上是貝葉斯方法,因此我們可以指定先驗來告知和約束我們的模型,并以后驗分布的形式得到不確定性估計。使用MCMC采樣算法,我們可以從這個后驗中抽取樣本,非常靈活地估計這些模型。PyMC3和Stan是目前用于構(gòu)建和評估這些模型的最先進工具。然而,采樣的一個主要缺點是它通常非常慢,特別是對于高維模型。這就是為什么最近開發(fā)出的變分推理算法幾乎和MCMC一樣靈活,但速度要快得多。這些算法不是從后驗中抽取樣本,而是將后驗的分布(如正態(tài)分布)擬合到樣本上,將樣本問題轉(zhuǎn)化為優(yōu)化問題。 不幸的是,當(dāng)涉及到傳統(tǒng)的ML問題,如分類或(非線性)回歸時,概率編程常常處于第二位(在準(zhǔn)確性和可擴展性方面),而不是像集成學(xué)習(xí)這樣的算法方法(例如隨機森林或梯度增強回歸樹) 。 深度學(xué)習(xí) 現(xiàn)在正處于第三次文藝復(fù)興時期,深度學(xué)習(xí)一直成為頭條新聞,它主宰了幾乎所有的物體識別基準(zhǔn),在雅達利游戲(Atari games)中大出風(fēng)頭,在圍棋(Go)中擊敗了世界冠軍李世石(Lee Sedol)。從統(tǒng)計學(xué)角度來看,神經(jīng)網(wǎng)絡(luò)是非常好的非線性函數(shù)近似和表示學(xué)習(xí)者表現(xiàn)。雖然主要用于分類,但它們已經(jīng)擴展到使用自編碼器進行無監(jiān)督學(xué)習(xí)以及各種其他有趣的方式(例如,遞歸網(wǎng)絡(luò)或MDN來估計多模態(tài)分布)。為什么他們這么好用?沒有人真正知道,因為統(tǒng)計特性仍未被完全理解。 深度學(xué)習(xí)的一大創(chuàng)新之處在于能夠訓(xùn)練這些極其復(fù)雜的模型。這取決于幾個支柱:
彌合深度學(xué)習(xí)和概率編程 一方面,我們有概率編程,它允許我們以非常有原則和易于理解的方式構(gòu)建相當(dāng)小的模型,以深入了解我們的數(shù)據(jù); 另一方面,我們有深度學(xué)習(xí),它使用許多啟發(fā)式方法來訓(xùn)練巨大且高度復(fù)雜的模型,這些模型在預(yù)測方面令人驚嘆。變分推理的最新創(chuàng)新允許概率編程來擴展模型復(fù)雜性以及數(shù)據(jù)大小。因此,我們正處于能夠?qū)⑦@兩種方法結(jié)合起來以幫助解開機器學(xué)習(xí)的新創(chuàng)新的風(fēng)口浪尖。 雖然這將允許概率編程應(yīng)用于更廣泛的有趣問題,但我相信,這種橋梁也為深度學(xué)習(xí)的創(chuàng)新帶來了巨大的希望。
PyMC3中的貝葉斯神經(jīng)網(wǎng)絡(luò) 生成數(shù)據(jù) 首先,讓我們生成一些玩具數(shù)據(jù) - 一個簡單的二元分類問題,它不是線性可分的。 %matplotlib inlineimport theanoimport pymc3 as pmimport sklearnimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom warnings import filterwarningsfilterwarnings('ignore')sns.set_style('white')from sklearn import datasetsfrom sklearn.preprocessing import scalefrom sklearn.model_selection import train_test_splitfrom sklearn.datasets import make_moonsX, Y = make_moons(noise=0.2, random_state=0, n_samples=1000)X = scale(X)X = X.astype(float)Y = Y.astype(float)X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=.5)fig, ax = plt.subplots(figsize=(12, 8))ax.scatter(X[Y==0, 0], X[Y==0, 1], label='Class 0')ax.scatter(X[Y==1, 0], X[Y==1, 1], color='r', label='Class 1')sns.despine(); ax.legend()ax.set(xlabel='X', ylabel='Y', title='Toy binary classification data set'); 模型規(guī)格 神經(jīng)網(wǎng)絡(luò)非常簡單?;締卧且粋€感知器,它只不過是邏輯回歸。我們并行使用其中許多,然后將它們疊加起來以獲得隱藏層。在這里,我們將使用2個隱藏層,每個隱藏層有5個神經(jīng)元,足以解決這個簡單問題。 def construct_nn(ann_input, ann_output): n_hidden = 5 # Initialize random weights between each layer init_1 = np.random.randn(X.shape[1], n_hidden).astype(float) init_2 = np.random.randn(n_hidden, n_hidden).astype(float) init_out = np.random.randn(n_hidden).astype(float) with pm.Model() as neural_network: # Weights from input to hidden layer weights_in_1 = pm.Normal('w_in_1', 0, sd=1, shape=(X.shape[1], n_hidden), testval=init_1) # Weights from 1st to 2nd layer weights_1_2 = pm.Normal('w_1_2', 0, sd=1, shape=(n_hidden, n_hidden), testval=init_2) # Weights from hidden layer to output weights_2_out = pm.Normal('w_2_out', 0, sd=1, shape=(n_hidden,), testval=init_out) # Build neural-network using tanh activation function act_1 = pm.math.tanh(pm.math.dot(ann_input, weights_in_1)) act_2 = pm.math.tanh(pm.math.dot(act_1, weights_1_2)) act_out = pm.math.sigmoid(pm.math.dot(act_2, weights_2_out)) # Binary classification -> Bernoulli likelihood out = pm.Bernoulli('out', act_out, observed=ann_output, total_size=Y_train.shape[0] # IMPORTANT for minibatches ) return neural_network# Trick: Turn inputs and outputs into shared variables. ann_input = theano.shared(X_train)ann_output = theano.shared(Y_train)neural_network = construct_nn(ann_input, ann_output) Normal先驗有助于調(diào)整權(quán)重。通常我們會在輸入中添加一個常量b,但是為了保持代碼的整潔,我在這里省略了它。 變分推理:縮放模型復(fù)雜度 我們現(xiàn)在可以運行像NUTS這樣的MCMC采樣器,在這種情況下工作得非常好,但正如我已經(jīng)提到的,當(dāng)我們將模型擴展到具有更多層的更深層架構(gòu)時,這將變得非常緩慢。 相反,我們將使用ADVI變分推理算法,這是最近添加到PyMC3,并更新使用運算符變分推理(OPVI)框架。這樣做速度更快,并且可以更好地擴展。 from pymc3.theanof import set_tt_rng, MRG_RandomStreamsset_tt_rng(MRG_RandomStreams(42))%%timewith neural_network: inference = pm.ADVI() approx = pm.fit(n=50000, method=inference) 在性能方面,考慮到NUTS確實不是太好。接下來我們使它更快一些。為了讓它真正運行起來,我們可能需要在GPU上運行神經(jīng)網(wǎng)絡(luò)。 由于使用樣本更方便,我們可以使用sample方法快速地從變分近似中提取樣本(這只是從正態(tài)分布中采樣,所以與MCMC完全不同): trace = approx.sample(draws=5000) 繪制目標(biāo)函數(shù)(ELBO)我們可以看到優(yōu)化會逐漸改善擬合。 plt.plot(-inference.hist)plt.ylabel('ELBO')plt.xlabel('iteration'); 現(xiàn)在我們訓(xùn)練了模型,讓我們使用后驗預(yù)測檢查(PPC)來預(yù)測保留集。 # Replace arrays our NN references with the test dataann_input.set_value(X_test)ann_output.set_value(Y_test)with neural_network: ppc = pm.sample_ppc(trace, samples=500, progressbar=False)# Use probability of > 0.5 to assume prediction of class 1pred = ppc['out'].mean(axis=0) > 0.5 讓我們來看看我們的預(yù)測: fig, ax = plt.subplots()ax.scatter(X_test[pred==0, 0], X_test[pred==0, 1])ax.scatter(X_test[pred==1, 0], X_test[pred==1, 1], color='r')sns.despine()ax.set(title='Predicted labels in testing set', xlabel='X', ylabel='Y');print('Accuracy = {}%'.format((Y_test == pred).mean() * 100)) Accuracy = 95.0% 我們的神經(jīng)網(wǎng)絡(luò)已經(jīng)做得很好了。 讓我們看看分類器學(xué)到了什么 這樣,我們在整個輸入空間的網(wǎng)格上評估類概率預(yù)測。 grid = pm.floatX(np.mgrid[-3:3:100j,-3:3:100j])grid_2d = grid.reshape(2, -1).Tdummy_out = np.ones(grid.shape[1], dtype=np.int8)ann_input.set_value(grid_2d)ann_output.set_value(dummy_out)with neural_network: ppc = pm.sample_ppc(trace, samples=500, progressbar=False) 概率面 cmap = sns.diverging_palette(250, 12, s=85, l=25, as_cmap=True)fig, ax = plt.subplots(figsize=(14, 8))contour = ax.contourf(grid[0], grid[1], ppc['out'].mean(axis=0).reshape(100, 100), cmap=cmap)ax.scatter(X_test[pred==0, 0], X_test[pred==0, 1])ax.scatter(X_test[pred==1, 0], X_test[pred==1, 1], color='r')cbar = plt.colorbar(contour, ax=ax)_ = ax.set(xlim=(-3, 3), ylim=(-3, 3), xlabel='X', ylabel='Y');cbar.ax.set_ylabel('Posterior predictive mean probability of class label = 0'); 預(yù)測值的不確定性 到目前為止,我展示的一切都可以用非貝葉斯神經(jīng)網(wǎng)絡(luò)完成。每個類標(biāo)簽的后驗預(yù)測均值應(yīng)與最大似然預(yù)測值相同。不過,我們也可以通過后驗預(yù)測的標(biāo)準(zhǔn)差來了解我們預(yù)測中的不確定性。這是看起來像: cmap = sns.cubehelix_palette(light=1, as_cmap=True)fig, ax = plt.subplots(figsize=(14, 8))contour = ax.contourf(grid[0], grid[1], ppc['out'].std(axis=0).reshape(100, 100), cmap=cmap)ax.scatter(X_test[pred==0, 0], X_test[pred==0, 1])ax.scatter(X_test[pred==1, 0], X_test[pred==1, 1], color='r')cbar = plt.colorbar(contour, ax=ax)_ = ax.set(xlim=(-3, 3), ylim=(-3, 3), xlabel='X', ylabel='Y');cbar.ax.set_ylabel('Uncertainty (posterior predictive standard deviation)'); 我們可以看到非常接近決策邊界的地方,我們對于預(yù)測哪個標(biāo)簽的不確定性是最高的。您可以想象,將預(yù)測與不確定性聯(lián)系起來是許多應(yīng)用(如醫(yī)療保健)的關(guān)鍵屬性。為了進一步提高精度,我們可能希望主要根據(jù)來自高不確定區(qū)域的樣本來進行模型訓(xùn)練。 Mini-batch ADVI 到目前為止,我們已經(jīng)對所有數(shù)據(jù)進行了模型訓(xùn)練。顯然,這不會像ImageNet那樣擴展。此外,對mini-batch數(shù)據(jù)(隨機梯度下降)的訓(xùn)練避免了局部最小值,并且可以加快收斂速度。 幸運的是,ADVI也可以在mini-batch上運行。它只需要一些設(shè)置: minibatch_x = pm.Minibatch(X_train, batch_size=32)minibatch_y = pm.Minibatch(Y_train, batch_size=32)neural_network_minibatch = construct_nn(minibatch_x, minibatch_y)with neural_network_minibatch: inference = pm.ADVI() approx = pm.fit(40000, method=inference)plt.plot(-inference.hist)plt.ylabel('ELBO')plt.xlabel('iteration'); 如您所見,mini-batch ADVI的運行時間要低得多。它似乎收斂的更快。 總結(jié) 希望本文演示了PyMC3: ADVI中可用的一個非常強大的新推理算法。我還認為,如前所述,彌合概率編程和深度學(xué)習(xí)之間的差距可以為這一領(lǐng)域的創(chuàng)新開辟許多新途徑。 |
|
來自: taotao_2016 > 《AI》