使用TensorFlow構(gòu)建LSTM模型詳細(xì)教程
目標(biāo)
本文的目標(biāo)是解釋一個(gè)可用于構(gòu)建基本LSTM模型的簡(jiǎn)單代碼。我不會(huì)討論和分析結(jié)果。這只是為了讓您開始編寫代碼。
設(shè)置環(huán)境
我將在本文中使用python編寫LSTM代碼。環(huán)境設(shè)置如下:
我建議您下載pycharm IDE并通過(guò)IDE將Tensorflow和所有其他庫(kù)下載到您的項(xiàng)目中。您可以按照以下步驟設(shè)置環(huán)境。
- 下載PyCharm IDE
- 創(chuàng)建一個(gè)項(xiàng)目
- 將Tensorflow,NumPy,SciPy,scikit-learn和Pandas下載到您的項(xiàng)目中。
- 在項(xiàng)目中創(chuàng)建一個(gè)新的python文件
如果您想手動(dòng)創(chuàng)建環(huán)境,下面列出的是python和Tensorflow的兼容版本以及您需要遵循本文的所有其他庫(kù)。
注意:不要使用與提到的不同版本的python,因?yàn)樗赡芘c給定的Tensorflow版本不兼容。下載scikit-learn時(shí),首先下載NumPy和SciPy軟件包。
- Python: 3.6.5
- Tensorflow: 1.9.0
- scikit-learn: 0.19.1
- Pip: 10.0.1
- NumPy: 1.14.3
- Pandas: 0.23.0
- SciPy: 1.1.0
我們到底下載了什么?
- Tensorflow:這是一個(gè)機(jī)器學(xué)習(xí)框架。
- Pandas:這是一個(gè)有助于分析和輕松完成數(shù)據(jù)準(zhǔn)備的庫(kù)。
- scikit-learn:這是一個(gè)機(jī)器學(xué)習(xí)庫(kù),它具有各種機(jī)器學(xué)習(xí)算法,并且還執(zhí)行必要的輔助函數(shù)。
- NumPy:這是一個(gè)可以在多維數(shù)組和矩陣上執(zhí)行高級(jí)數(shù)學(xué)函數(shù)的庫(kù)。
- SciPy:這是一個(gè)用于科學(xué)計(jì)算和技術(shù)計(jì)算的庫(kù)。
- Pip:這是一個(gè)Python的包管理系統(tǒng),可以安裝和管理用Python編寫的軟件包。
數(shù)據(jù)?
對(duì)于本文,我們將使用在kaggle上發(fā)布的信用卡欺詐數(shù)據(jù)集。我們將使用此數(shù)據(jù)集來(lái)訓(xùn)練我們的LSTM模型,以便對(duì)交易是欺詐性交易還是正常交易進(jìn)行分類。
您可以在此處(https://www.kaggle.com/mlg-ulb/creditcardfraud/version/2)獲取數(shù)據(jù)集表單的csv文件。下載后,將其放入項(xiàng)目中以方便使用。如果您可以在開始使用數(shù)據(jù)之前瀏覽數(shù)據(jù)并閱讀并理解每列數(shù)據(jù)所代表的內(nèi)容,將會(huì)很有幫助。
注意:如果您在機(jī)器學(xué)習(xí)算法(如“隨機(jī)森林分類器”)上測(cè)試,此數(shù)據(jù)集將提供更好的分?jǐn)?shù),但我們可以使用此數(shù)據(jù)集作為構(gòu)建LSTM模型的起點(diǎn)。此外,您應(yīng)該記住,此數(shù)據(jù)集具有非常高的類不平衡。
Python代碼
首先,讓我們導(dǎo)入所需Python庫(kù)。
- import tensorflow as tf
- import pandas as pd
- import numpy as np
- from tensorflow.contrib import rnn
- from sklearn.model_selection import train_test_split
- from sklearn.metrics import f1_score, accuracy_score, recall_score, precision_score
現(xiàn)在,我們必須將所有數(shù)據(jù)加載到我們的程序中。我們可以使用Pandas來(lái)做到這一點(diǎn)
- data = pd.read_csv('creditcard.csv', skiprows=[0], header=None)
上面的Python代碼將加載來(lái)自csv文件的所有數(shù)據(jù),從而省略帶有標(biāo)題的行,因此加載的數(shù)據(jù)現(xiàn)在看起來(lái)像這樣:
前5行數(shù)據(jù)
接下來(lái),我們將加載的數(shù)據(jù)分成標(biāo)簽和特征。
- features = data.iloc[:, 1:30]
- labels = data.iloc[:, -1]
如果您瀏覽了信用卡數(shù)據(jù),您會(huì)注意到其中有31列。第1行代碼將數(shù)據(jù)從第1列(第0列)加載到第30列,作為“特征”。
如kaggle所述,最后一列是指定交易是否存在欺詐行的列。因此,在第二行代碼中,我們將最后一列中的數(shù)據(jù)作為標(biāo)簽加載。
注意:我們正在排除第0列,因?yàn)樗惶峁┯嘘P(guān)交易順序的信息,并沒(méi)有為我們的訓(xùn)練增加實(shí)際價(jià)值。我們可以根據(jù)數(shù)據(jù)的發(fā)生順序來(lái)保留數(shù)據(jù)的順序。
我們現(xiàn)在擁有標(biāo)簽和特征,我們需要將這些標(biāo)簽和特征劃分為訓(xùn)練集和測(cè)試集。我們可以使用scikit-learn的'train test split function'。
- X_train,X_test,y_train,y_test = train_test_split(features, labels, test_size=0.2, shuffle=False, random_state=42)
此功能自動(dòng)將特征和標(biāo)簽分為測(cè)試和訓(xùn)練集。“X_train”和“X_test”是特征的訓(xùn)練和測(cè)試集,“y_test”和“y_train”是標(biāo)簽的訓(xùn)練和測(cè)試集。參數(shù)“test_size”指定測(cè)試集應(yīng)該是整個(gè)數(shù)據(jù)集的20%。“shuffle”參數(shù)指定在將數(shù)據(jù)拆分為測(cè)試和訓(xùn)練集之前是否應(yīng)該對(duì)數(shù)據(jù)進(jìn)行混洗。這里我們將其設(shè)置為false以保留事務(wù)的發(fā)生順序。我們使用“random_state”參數(shù),以便每次運(yùn)行此函數(shù)時(shí)獲得相同的輸出。
我們現(xiàn)在要指定我們的超參數(shù)
- epochs = 8
- n_classes = 1
- n_units = 200
- n_features = 29
- batch_size = 35
- epochs:epochs對(duì)應(yīng)于我們將通過(guò)模型運(yùn)行數(shù)據(jù)集的迭代次數(shù)。
- n_classes:這對(duì)應(yīng)于我們?yōu)榇朔诸愃龅念惖臄?shù)量。在我們的例子中,我們有一個(gè)二元分類,如果它是正常的事務(wù)我們分配0,如果它是欺詐性事務(wù)則分配1。在一個(gè)非?;A(chǔ)的層面,如果我們采用一列,我們可以非常容易地表示0和1的欺詐和正常交易。因此,我們可以將類的數(shù)量設(shè)為1。
- n_units:這對(duì)應(yīng)于LSTM隱藏狀態(tài)的大?。╟和h)。
- n_features:如名稱所指定,這表示數(shù)據(jù)集中的特征數(shù)。
- batch_size:這是指您要輸入模型的每批數(shù)據(jù)的大小。每批次將進(jìn)行一次反向傳播。
- 接下來(lái),我們將為我們將要提供給機(jī)器學(xué)習(xí)模型的批數(shù)據(jù)定義place-holders。
- xplaceholder= tf.placeholder('float',[None,n_features])
- yplaceholder = tf.placeholder('float')
'xplaceholder'占位符包含一批特征數(shù)據(jù),'yplaceholder'包含相應(yīng)批次的標(biāo)簽數(shù)據(jù)。'xplaceholder'的shape 已被指定為(<batch_size>,n_features),因?yàn)?ldquo;None”值允許長(zhǎng)度靈活到插入占位符的長(zhǎng)度,但是fed矩陣應(yīng)該具有代碼中指定的相同數(shù)量的特征。由于沒(méi)有為'yplaceholder'明確指定shape,它將是一個(gè)向量,但它的長(zhǎng)度將取決于送入占位符的內(nèi)容。在我們的例子中,y將是一個(gè)長(zhǎng)度為batch_size的向量。
我們已完成大部分準(zhǔn)備工作,因此,我們現(xiàn)在將設(shè)計(jì),訓(xùn)練和測(cè)試我們的LSTM模型
- def recurrent_neural_network_model():
- layer ={ 'weights': tf.Variable(tf.random_normal([n_units, n_classes])),'bias': tf.Variable(tf.random_normal([n_classes]))}
- x = tf.split(xplaceholder, n_features, 1)
- print(x)
- lstm_cell = rnn.BasicLSTMCell(n_units)
- outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)
- output = tf.matmul(outputs[-1], layer['weights']) + layer['bias']
- return output
讓我們理解代碼。我將首先解釋'recurrent_neural_network_model()'函數(shù)內(nèi)部的代碼正在做什么,逐行解釋Python代碼如下:
- 在這一行中,我們手動(dòng)定義權(quán)重和偏差的shapes。我們分別使用shape[rnn_size,n_classes]和[n_classes]的隨機(jī)值賦予TensorFlow變量'weight'和'bias'。
- 現(xiàn)在我們將數(shù)據(jù)作為序列分配給'x'。為此,我們將特征批處理沿著它的垂直維度(維度:1)分成29個(gè)切片,這是一個(gè)二維張量。每個(gè)切片是作為L(zhǎng)STM層的輸入給出的序列的元素。(序列的一個(gè)元素的形狀將是:(<batch_size>,1))
- 然后我們正在創(chuàng)建LSTM層。該函數(shù)實(shí)例化所有門的變量。
- 'outputs'變量包含每個(gè)時(shí)間步長(zhǎng)的LSTM層的所有輸出,'state'包含兩個(gè)隱藏狀態(tài)(h和c)的最后狀態(tài)的值。
- 這里我們只使用'outputs [-1]'獲取LSTM層的最后一個(gè)輸出,并將它與先前定義的權(quán)重矩陣相乘,并將偏差值添加到它。結(jié)果值是前向傳播的logit值。
- 最后,我們將logit值返回給調(diào)用函數(shù)'train_neural_network()'。
- def train_neural_network():
- #1
- logit = recurrent_neural_network_model()
- logit = tf.reshape(logit, [-1])
- #3
- cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logit, labels=yplaceholder))
- optimizer = tf.train.AdamOptimizer().minimize(cost)
- with tf.Session() as sess:
- #6
- tf.global_variables_initializer().run()
- tf.local_variables_initializer().run()
- #7
- for epoch in range(epochs):
- epoch_loss = 0 #8
- i = 0
- for i in range(int(len(X_train) / batch_size)): #10
- #11
- start = i
- end = i + batch_size
- #13
- batch_x = np.array(X_train[start:end])
- batch_y = np.array(y_train[start:end])
- #15
- _, c = sess.run([optimizer, cost], feed_dict={xplaceholder: batch_x, yplaceholder: batch_y})
- epoch_loss += c
- i += batch_size
- #18
- print('Epoch', epoch, 'completed out of', epochs, 'loss:', epoch_loss)
- pred = tf.round(tf.nn.sigmoid(logit)).eval({xplaceholder: np.array(X_test), yplaceholder: np.array(y_test)})
- #20
- f1 = f1_score(np.array(y_test), pred, average='macro')
- accuracy=accuracy_score(np.array(y_test), pred)
- recall = recall_score(y_true=np.array(y_test), y_pred= pred)
- precision = precision_score(y_true=np.array(y_test), y_pred=pred)
- #24
- print("F1 Score:", f1)
- print("Accuracy Score:",accuracy)
- print("Recall:", recall)
- print("Precision:", precision)
- train_neural_network()
現(xiàn)在讓我們了解'train_neural_network()'函數(shù)中的代碼是做什么的,逐行解釋Python代碼如下:
- 1.這里我們將接收的logit值分配給變量。logit值是激活的倒數(shù)。
- 2.然后我們將矩陣重reshaping 為一個(gè)向量,因?yàn)楫?dāng)將它提供給損失函數(shù)時(shí),標(biāo)簽的shape和logits 應(yīng)該相等。
- 3.我們?cè)谶@里定義了損失函數(shù)。使用“sigmoid_cross_entropy_with_logits”函數(shù)是因?yàn)槲覀冋谶M(jìn)行二元分類。如果這是一個(gè)多類分類,我們應(yīng)該使用像'softmax_cross_entropy_with_logits'這樣的損失函數(shù)。
- 4.我們使用“AdamOptimizer()”優(yōu)化器,因?yàn)樗哂邢喈?dāng)好的性能。
直到這一點(diǎn),我們討論的所有代碼都不在Tensorflow會(huì)話中。從這里開始,所有討論的代碼都將在TensorFlow會(huì)話中。
在調(diào)用“train_neural_network()”以啟動(dòng)程序之后,Tensorflow會(huì)話的起點(diǎn)將是執(zhí)行開始的位置。
我們正在初始化到目前為止我們已聲明的所有全局變量。
- 6.然后我們正在初始化項(xiàng)目中的所有局部變量。
- 7.在這里,我們定義一個(gè)循環(huán),直到滿足我們定義的迭代次數(shù)(epoch)。
- 8.在每個(gè)epoch開始時(shí)將epoch loss重置為0。
- 9.定義變量以在將數(shù)據(jù)拆分為批次時(shí)跟蹤開始和結(jié)束計(jì)算
- 10.在這里,我們?cè)俅味x一個(gè)循環(huán),直到batches 達(dá)到計(jì)算閾值為止。
- 11.和12.我們使用'start'和'end'變量來(lái)跟蹤數(shù)據(jù)在每次迭代中的分割位置。
- 13.和14.在每次迭代中,將分別為“batch_x”和“batch_y”變量分配一批特征和標(biāo)簽。
- 15.在這一行中,我們告訴Tensorflow運(yùn)行必要的子圖來(lái)計(jì)算優(yōu)化器和成本,方法是將'batch_x'和'batch_y'變量中的值提供給前面提到的占位符。結(jié)果,將計(jì)算優(yōu)化器的值和成本,并分別分配給“throw-away”變量和“c”變量。
- 16.當(dāng)前批處理的損失將添加到“epoch_loss”變量中。
- 17.此行有助于遍歷每批數(shù)據(jù)(特征和標(biāo)簽)。
- 18.打印那個(gè)epoch的總損失
到目前為止我們討論的是模型的訓(xùn)練方面。訓(xùn)練將持續(xù)到epochs數(shù)達(dá)到閾值。
接下來(lái)的幾行代碼用于測(cè)試模型。
注意:理想情況下,我們將數(shù)據(jù)集劃分為3組,即訓(xùn)練,驗(yàn)證和測(cè)試。我們將保留測(cè)試集并使用驗(yàn)證集來(lái)查看模型的性能并更改超參數(shù)以實(shí)現(xiàn)更好的性能。當(dāng)我們認(rèn)為模型已經(jīng)足夠改進(jìn)時(shí),我們只會(huì)采用測(cè)試集來(lái)了解模型的表現(xiàn)。對(duì)于本文,我們只使用了兩套訓(xùn)練集和測(cè)試集來(lái)保持簡(jiǎn)單。
- 19.這是我們將測(cè)試數(shù)據(jù)集提供給模型并告訴Tensorflow運(yùn)行計(jì)算logit所需的子圖的地方。然后我們通過(guò)sigmoid激活傳遞logit值來(lái)獲得預(yù)測(cè)。四舍五入該值以刪除預(yù)測(cè)值的小數(shù)位。
- 20.我們?cè)谶@里計(jì)算F1得分。F1 Score是Precision和Recall的加權(quán)平均值。您可以從這里閱讀更多相關(guān)信息。
- 21.然后我們計(jì)算準(zhǔn)確度分?jǐn)?shù)。
- 22.這次召回正在計(jì)算中。召回是正確預(yù)測(cè)的陽(yáng)性觀察與所有陽(yáng)性觀察的比率。
- 23.我們也在計(jì)算精度。精確度是正確預(yù)測(cè)的陽(yáng)性觀察值與總預(yù)測(cè)陽(yáng)性觀察值的比率。
- 24.至27.打印出所有計(jì)算得分。
所以,我們終于完成了代碼。
我希望本文能幫助您了解使用Tensorflow構(gòu)建基本LSTM的過(guò)程。請(qǐng)注意,此模型是一個(gè)非常基本的版本,是構(gòu)建和改進(jìn)的良好起點(diǎn)。