用深度學習技術預測虛擬貨幣價格
如果要選幾個 2017 年最火的流行詞,絕對有人工智慧和虛擬貨幣。英國程序員 David Sheehan 就被比特幣這種顛覆性的技術以及過山車式的價格漲跌留下了深刻印象,雖然他自己一個幣也沒有,但還是想用機器學習技術預測一下比特幣這種虛擬貨幣的價格。
提醒:不應將本文視為投資建議,也希望大家不要輕易靠這種方法投資虛擬貨幣,本文只是分享我自己對於如何用深度學習技術預測虛擬貨幣價格的一個思路。理財有風險,投資需謹慎,有漲就有跌,請量力而行。
在我(作者David Sheeran——譯者注)寫這篇文章之前,我到網上搜了搜,發現之前有人寫過怎樣用深度學習技術預測比特幣價格,於是我想了想,決定除了比特幣外,也預測另一種近來比較火的虛擬貨幣價格——以太坊,也叫以太幣。
我們會使用一個長短期記憶模型(LSTM),它是深度學習模型的一種,很適合處理時序數據,或者任何有暫時性、空間性和結構性順序的數據,比如電影、語句等等。如果你對這種模型不是很熟悉,我推薦讀一下這篇博客
Exploring LSTMs因為我也想讓不太懂機器學習的讀者願意看下去,所以我會盡量不放大段大段的代碼,請理解一下。要是你也想這麼操作一波,我把數據和代碼放在了 GitHub上,點擊這裡獲取即可
dashee87/blogScripts好了,廢話不說,我們開始吧!
獲取數據
在我們搭建模型之前,我們需要獲取一些數據讓模型學習。在 Kaggle 上有個數據集,詳細記錄了過去幾年比特幣每分鐘的價格以及其他方面的數據(我之前看的那篇預測比特幣價格的教程用的也是這個數據集)。但按照每分鐘的時間尺度,會有很多雜訊數據,所以我們選擇每天的價格。這樣就會產生一個問題:我們可能收集不到足夠的數據(不過我們需要幾百行而不是幾百萬行數據)。
需要強調的是:深度學習中,在嚴重缺乏數據的情況下,沒有模型能取得成功。
我也不想依靠靜態文件,因為在將來用新數據更新模型時它們會讓更新過程無比複雜。相反,我們會從虛擬貨幣網站和 API 中獲取數據。
因為我們會將兩種虛擬貨幣的價格混合在一個模型中,所以從一個數據源中提取數據可能是個好主意。我們會用到網站 coinmarketcap.com 當前我們只考慮比特幣和以太坊的數據,但用這種方法再添加別的幣種也不會太難。在我們導入數據前,我們必須載入一些 Python 包,讓工作更容易些。
import pandas as pdimport timeimport seaborn as snsimport matplotlib.pyplot as pltimport datetimeimport numpy as np# get market info for bitcoin from the start of 2016 to the current daybitcoin_market_info = pd.read_html("https://coinmarketcap.com/currencies/bitcoin/historical-data/?start=20130428&end="+time.strftime("%Y%m%d"))[0]# convert the date string to the correct date formatbitcoin_market_info = bitcoin_market_info.assign(Date=pd.to_datetime(bitcoin_market_info[Date]))# when Volume is equal to - convert it to 0bitcoin_market_info.loc[bitcoin_market_info[Volume]=="-",Volume]=0# convert to intbitcoin_market_info[Volume] = bitcoin_market_info[Volume].astype(int64)# look at the first few rowsbitcoin_market_info.head()
剛剛發生了什麼呢?我們載入了一些 Python 包,然後導入了 coinmarketcap.com 上如上所示的這種數據表格。稍微清洗一下數據後,我們就會獲得上面這個比特幣價格表格。在 URL 里將 bitcoin 換成 ethereum 也能得到以太坊的價格數據。
要想證明數據是準確的,我們可以繪製出兩種貨幣價格和容量隨著時間推移的變化情況:
訓練,測試和隨機遊走
我們已經獲取了一些數據,那麼我們先在需要一個模型。在深度學習中,數據通常被分為訓練集和測試集兩部分。我們用訓練集讓模型進行學習,然後用測試集評估模型的性能。對於時間序列模型,我們一般對一個時間序列進行預測,然後對另一個時間序列進行測試。比如,我把截止日期設為 2017 年 6 月 1 日,那麼就會用在這個日期之前的時間訓練模型,用這個日期之後的數據評估模型。
你可以看到訓練時間大部分包含虛擬貨幣價格較低的時期。這樣,訓練數據或許無法代表測試數據,會損害模型泛化不可見數據的能力(你可以試著讓數據更平穩些)。但幹嘛讓負面情況礙手礙腳呢?在使用我們的機器學習模型前,有必要討論一個更簡單些的模型。最基本的模型就是設定明天的價格等於今天的價格(我們稱之為滯後模型)。我們在數學上以如下方式定義該模型:
在互聯網鏈接分析和金融股票市場中,當擴展一下這個簡單的模型時,通常將價格當做隨機遊走(概念接近於布朗運動,是布朗運動的理想數學狀態。指任何無規則行走者所帶的守恆量都各自對應著一個擴散運輸定律),那麼在數學上可以將其進行如下定義:
我們會從訓練集中確定 μ 和 σ,將隨機遊走模型應用在比特幣和以太坊的測試集上。
哇哦!看看這些預測線。除了少許部分扭曲,基本上緊貼每個虛擬貨幣的實際價格變動情況。模型甚至捕捉到了 6 月中旬和 8 月下旬的暴漲狀況。
然而正如另一篇預測比特幣價格的博客中所說,只在某個點預測未來的模型常常會讓人誤以為它很準確,因為在接下來的預測中模型沒有將誤差因素考慮在內。不管誤差大小如何,它在每個時間點本質上會被重置,因為輸入模型的是真實價格。比特幣的隨機遊走尤其具有誤導性,因為 y 軸的值可以很大,這讓預測線看起來很平滑。
不幸的是,單點預測在評估時序模型中相當普遍。所以通過多點預測衡量模型準確度是個更好的做法。這樣以來,之前預測的誤差不會被重置,而是會被計算入接下來的預測中。這樣,我們在數學上這樣定義:
我們來獲取我們的隨機遊走模型,預測整個測試集的收盤價格。
模型的預測對隨機種子極其敏感。對於以太坊的預測,我選了一個完整的看起來正常的區間隨機遊走(如下gif圖)。你也可以在 Jupyter Notebook 中處理下面這些隨機種子值,看看情況有多糟糕。
注意單點隨機遊走會一直看似十分準確,即便背後並無真實實體。因此,希望你對任何博客中預測出的貨幣價格都保持懷疑態度。想買虛擬貨幣的朋友別被市場預測報告給輕易忽悠了。
長短期記憶模型(LSTM)
在前文說過,我們會用到長短期記憶模型。但我們沒必要從頭開始自己搭建一個模型,現在有不少應用了多種深度學習演算法的開源框架可供我們使用(比如 TensorFlow,Keras,PyTorch等)。我選的是 Keras,因為我發現它很適合像我這種水平不牛的人。
如果你對 Keras 不熟悉,可以看看我寫的這篇教程,或者其他人的教程都行。
Another Keras Tutorial For Neural Network Beginners我創建了一個新的數據框架叫做 model_data。我將移出了之前的一些列(開盤價,每日最高價和最低價),重新表示了一些新列。Close_off_high 代表了當天收盤價和最高價之間的差額,其中值 -1 和 1 表示當天收盤價分別等於最低價和最高價。volatility 列是指被開盤價分開的最低價和最高價的不同。你可能也注意到 model_data 是按照最早時間到最近時間的順序排列的。我們實際上並不需要日期列了,因為不需要再向模型中輸入這項信息。
model_data.head()
我們的長短期記憶模型會使用之前的數據(比特幣和以太坊的都有)預測每種貨幣第二天的收盤價。我們必須決定模型需要獲取之前多少天的數據。
這個隨意,我選擇的是 10 天,因為 10 ....... 是個很好的整數。我們創建一個小型數據框架,包含連續 10 天的數據(稱為窗口),所以第一個窗口會包含訓練集的第 0-9 行(Python 是零索引),第二個窗口是 1-10 行,以此類推。選擇一個小型窗口意味著我們可以將更多的窗口輸入到模型中。下降趨勢是指模型可能沒有足夠的信息來檢測複雜的長期行為(如果出現這種情況)。
深度學習模型不喜歡輸入數據大幅變動。仔細看這些數據列,一些值介乎 -1 和 1 之間,而其它值則是百萬規模。我們需要將數據正常化,所以我們的輸入數據比較一致。通常,你會想讓值在 -1 和 1 之間。Off_high 列和 volatility 列和之前一樣好。對於剩餘的列,和其它人的做法一樣,我們會將輸入數據正常化為窗口中的第一個值。
這個表格表示我們的長短期記憶模型輸入的一個例子(我們實際上有幾百個類似的表格)。我們已經將一些列正常化,因此它們的值在第一個時間點都等於 0,所以我們的目標是預測在該時間點的價格變化情況。我們現在準備好搭建 LSTM 模型了。用 Keras 搭建模型非常快速,將幾個部件放在一起就行。我曾詳細寫了篇教程,可以參考
Another Keras Tutorial For Neural Network Beginners# import the relevant Keras modulesfrom keras.models import Sequentialfrom keras.layers import Activation, Densefrom keras.layers import LSTMfrom keras.layers import Dropoutdef build_model(inputs, output_size, neurons, activ_func = "linear", dropout =0.25, loss="mae", optimizer="adam"): model = Sequential() model.add(LSTM(neurons, input_shape=(inputs.shape[1], inputs.shape[2]))) model.add(Dropout(dropout)) model.add(Dense(units=output_size)) model.add(Activation(activ_func)) model.compile(loss=loss, optimizer=optimizer) return model
因而,build_model 函數構建了一個空的模型(model = Sequential),添加了一個 LSTM 層。為了適應我們的輸入(n x m 表格,其中 n 和 m 表示時間點/行和列的數值),該 LSTM 層經過了調整。函數還包含神經網路的一些特徵,如 dropout 和激活函數等。現在,我們只需指明放入 LSTM 層中的神經元的數量(我選擇的是 20 個),以及訓練模型用的數據數量。
# random seed for reproducibilitynp.random.seed(202)# initialise model architectureeth_model = build_model(LSTM_training_inputs, output_size=1, neurons = 20)# model output is next price normalised to 10th previous closing priceLSTM_training_outputs = (training_set[eth_Close][window_len:].values/training_set[eth_Close][:-window_len].values)-1# train model on data# note: eth_history contains information on the training error per epocheth_history = eth_model.fit(LSTM_training_inputs, LSTM_training_outputs, epochs=50, batch_size=1, verbose=2, shuffle=True)#eth_preds = np.loadtxt(eth_preds.txt)
Epoch 50/506s - loss: 0.0625
現在我們已經搭建好了一個可以預測第二天以太坊收盤價的 LSTM 模型。我們看看它性能如何。我們首先用訓練集檢測它的性能(即 2017 年 6 月之前的數據)。代碼下方的數字表示在第 50 次訓練迭代(或 epoch)後,模型在訓練集上的平均絕對誤差。我們不看其中的變化了,我們可以看看模型輸出的每天收盤價。
對於模型如此高的準確率,我們不應感到太驚訝。模型能獲取其誤差的來源,然後自行修正。實際上,要想實現幾乎零誤差訓練也不是很難。只需添加幾百個神經元訓練上幾千個 epoch 就行。我們更感興趣的是模型在測試集上的表現,因為這代表了模型面臨新數據時的預測效果。
撇開我們上文說的單點預測的誤導性不談,我們搭建的這個 LSTM 模型好像在新數據上表現的還不錯。最明顯的錯誤之處是它沒能檢測出價格突然增高後不可避免的要下降的情況(比如 6 月中旬和 10 月)。實際上,這是個持續性的錯誤,只是在這些峰值處更加明顯。預測的價格和第二天的價格基本上一致(例如 7 月中旬的價格下降)。另外,模型似乎系統性地高估了以太坊的未來價格,因為預測線始終在實際價格線的上方。我懷疑這是因為訓練集代表的時間段正值以太坊價格飛漲,因此模型預估這個趨勢會一直持續。我們也可以針對比特幣的測試集,搭建一個相同的 LSTM 模型預測比特幣的價格,如下圖所示:
點擊這裡獲取全部代碼
dashee87/blogScripts
我前面強調過,單點預測具有誤導性。那麼在仔細看看,你會注意到預測值有規律地反應了之前的值(如 10 月份)。我們的深度學習 LSTM 模型在部分地方再生了一個順序為 p 的自回歸模型,在這些地方,未來的值就是之前 p 值的加權和。我們可以在數學上將自回歸模型進行如下定義:
好消息是,時序任務通常都會用到自回歸模型(比如股票預測),因此我們搭建的 LSTM 模型存在的這個問題可以有合理的解決方案。壞消息是 LSTM 能力的一種浪費,我們本可以用更少的時間搭建一個更簡單的自回歸模型,而且或許能達到同樣的效果。模型更複雜並不等於有更高的準確率。
這樣以來模型的預測很明顯不如單點預測那麼令人滿意(如上圖所示)。但是,我很高興這個模型返回了一些很細微的舉動(例如以太坊這張圖的第二條線)。模型沒有簡單地預測價格朝同一個方向發展,所以我們有理由對模型持樂觀態度。
再回到單點預測部分,我們的深度學習神經網路看起來還不錯,但是無聊的隨機遊走模型也很棒。和隨機遊走模型一樣,LSTM 模型對選擇的隨機種子非常敏感(模型權重開始時隨機設置)。所以,如果我們想比較這兩個模型的話,我們可以讓每個模型運行多次,比如 25 次,對模型誤差有個估計。這個誤差可以計算為測試集中實際收盤價和預測收盤價之間的差額。
或許 AI 還是值得誇獎一番的!!這些圖標顯示了每個模型迭代 25 次後,在測試集上的誤差。LSTM 模型對比特幣和以太坊的預測誤差分別為4%和5%,徹底碾壓隨機遊走模型。
只想打敗隨機遊走模型太 low 了。我們可以將 LSTM 模型和更多的時序模型進行比較。比如自回歸模型,ARIMA,加權平均法等。這個任務我們留給以後再做,你也可以自己試試。
再說一下,希望談到用深度學習預測虛擬貨幣價格時,大家都能保持一個懷疑的態度,因為技術並不是完美的。
總結
我們收集了一些虛擬貨幣的數據,將其輸入一個超酷的長短期記憶模型中。不幸的是,模型的預測幾乎只是重複之前的值。我們怎樣能讓模型更完善些呢?
- 改變損失函數:平均絕對誤差並不真的鼓勵我們去冒險。例如,在絕對平方誤差情況下,LSTM 模型會被迫將檢測峰值視為更重要的事情。而且,更適合模型的損失函數會讓模型不再那麼保守。
- 抑制過於保守的自回歸模型:這能激勵深度學習演算法去探索更有趣或更冒險的模型。這一步說起來容易,做起來難!
- 獲取更多更好的數據:即便靠單單過去的價格就能很好地預測未來價格,我們還可以添加其它一些能提升模型預測能力的數據特徵。這樣,LSTM 模型就不必只依賴過去的價格數據了,可能還能解鎖更複雜的功能的。這一步可能是最值得嘗試但也最難的部分。
如果你想自己從頭創建一個 LSTM 模型,可這裡獲取所有 Python 代碼
dashee87/blogScripts推薦閱讀:
※馬斯克出局OpenAI董事會
※ETC價格突破20美元,市值已超越辣條
※十年了,區塊鏈革命失敗了嗎?
※百萬用戶級DApp - 介紹應用程序特定側鏈
※墨客簡介
TAG:深度學習DeepLearning | 以太坊 | 景略集智 |