目标
本文的目标是解释一个可用于构建基本LSTM模型的简单代码。我不会讨论和分析结果。这只是为了让您开始编写代码。
设置环境
我将在本文中使用python编写LSTM代码。环境设置如下:
我建议您下载pycharm IDE并通过IDE将Tensorflow和所有其他库下载到您的项目中。您可以按照以下步骤设置环境。
- 下载PyCharm IDE
- 创建一个项目
- 将Tensorflow,NumPy,SciPy,scikit-learn和Pandas下载到您的项目中。
- 在项目中创建一个新的python文件
如果您想手动创建环境,下面列出的是python和Tensorflow的兼容版本以及您需要遵循本文的所有其他库。
注意:不要使用与提到的不同版本的python,因为它可能与给定的Tensorflow版本不兼容。下载scikit-learn时,首先下载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:这是一个机器学习框架。
- Pandas:这是一个有助于分析和轻松完成数据准备的库。
- scikit-learn:这是一个机器学习库,它具有各种机器学习算法,并且还执行必要的辅助函数。
- NumPy:这是一个可以在多维数组和矩阵上执行高级数学函数的库。
- SciPy:这是一个用于科学计算和技术计算的库。
- Pip:这是一个Python的包管理系统,可以安装和管理用Python编写的软件包。
数据?
对于本文,我们将使用在kaggle上发布的信用卡欺诈数据集。我们将使用此数据集来训练我们的LSTM模型,以便对交易是欺诈性交易还是正常交易进行分类。
您可以在此处(https://www.kaggle.com/mlg-ulb/creditcardfraud/version/2)获取数据集表单的csv文件。下载后,将其放入项目中以方便使用。如果您可以在开始使用数据之前浏览数据并阅读并理解每列数据所代表的内容,将会很有帮助。
注意:如果您在机器学习算法(如“随机森林分类器”)上测试,此数据集将提供更好的分数,但我们可以使用此数据集作为构建LSTM模型的起点。此外,您应该记住,此数据集具有非常高的类不平衡。
Python代码
首先,让我们导入所需Python库。
- 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
现在,我们必须将所有数据加载到我们的程序中。我们可以使用Pandas来做到这一点
- data = pd.read_csv('creditcard.csv', skiprows=[0], header=None)
上面的Python代码将加载来自csv文件的所有数据,从而省略带有标题的行,因此加载的数据现在看起来像这样:
接下来,我们将加载的数据分成标签和特征。
- features = data.iloc[:, 1:30]
- labels = data.iloc[:, -1]
如果您浏览了信用卡数据,您会注意到其中有31列。第1行代码将数据从第1列(第0列)加载到第30列,作为“特征”。
如kaggle所述,最后一列是指定交易是否存在欺诈行的列。因此,在第二行代码中,我们将最后一列中的数据作为标签加载。
注意:我们正在排除第0列,因为它只提供有关交易顺序的信息,并没有为我们的训练增加实际价值。我们可以根据数据的发生顺序来保留数据的顺序。
我们现在拥有标签和特征,我们需要将这些标签和特征划分为训练集和测试集。我们可以使用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)
此功能自动将特征和标签分为测试和训练集。“X_train”和“X_test”是特征的训练和测试集,“y_test”和“y_train”是标签的训练和测试集。参数“test_size”指定测试集应该是整个数据集的20%。“shuffle”参数指定在将数据拆分为测试和训练集之前是否应该对数据进行混洗。这里我们将其设置为false以保留事务的发生顺序。我们使用“random_state”参数,以便每次运行此函数时获得相同的输出。
我们现在要指定我们的超参数
- epochs = 8
- n_classes = 1
- n_units = 200
- n_features = 29
- batch_size = 35
- epochs:epochs对应于我们将通过模型运行数据集的迭代次数。
- n_classes:这对应于我们为此分类所做的类的数量。在我们的例子中,我们有一个二元分类,如果它是正常的事务我们分配0,如果它是欺诈性事务则分配1。在一个非常基础的层面,如果我们采用一列,我们可以非常容易地表示0和1的欺诈和正常交易。因此,我们可以将类的数量设为1。
- n_units:这对应于LSTM隐藏状态的大小(c和h)。
- n_features:如名称所指定,这表示数据集中的特征数。
- batch_size:这是指您要输入模型的每批数据的大小。每批次将进行一次反向传播。
- 接下来,我们将为我们将要提供给机器学习模型的批数据定义place-holders。
- xplaceholder= tf.placeholder('float',[None,n_features])
- yplaceholder = tf.placeholder('float')
'xplaceholder'占位符包含一批特征数据,'yplaceholder'包含相应批次的标签数据。'xplaceholder'的shape 已被指定为(<batch_size>,n_features),因为“None”值允许长度灵活到插入占位符的长度,但是fed矩阵应该具有代码中指定的相同数量的特征。由于没有为'yplaceholder'明确指定shape,它将是一个向量,但它的长度将取决于送入占位符的内容。在我们的例子中,y将是一个长度为batch_size的向量。
我们已完成大部分准备工作,因此,我们现在将设计,训练和测试我们的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()'函数内部的代码正在做什么,逐行解释Python代码如下:
- 在这一行中,我们手动定义权重和偏差的shapes。我们分别使用shape[rnn_size,n_classes]和[n_classes]的随机值赋予TensorFlow变量'weight'和'bias'。
- 现在我们将数据作为序列分配给'x'。为此,我们将特征批处理沿着它的垂直维度(维度:1)分成29个切片,这是一个二维张量。每个切片是作为LSTM层的输入给出的序列的元素。(序列的一个元素的形状将是:(<batch_size>,1))
- 然后我们正在创建LSTM层。该函数实例化所有门的变量。
- 'outputs'变量包含每个时间步长的LSTM层的所有输出,'state'包含两个隐藏状态(h和c)的最后状态的值。
- 这里我们只使用'outputs [-1]'获取LSTM层的最后一个输出,并将它与先前定义的权重矩阵相乘,并将偏差值添加到它。结果值是前向传播的logit值。
- 最后,我们将logit值返回给调用函数'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()
现在让我们了解'train_neural_network()'函数中的代码是做什么的,逐行解释Python代码如下:
- 1.这里我们将接收的logit值分配给变量。logit值是激活的倒数。
- 2.然后我们将矩阵重reshaping 为一个向量,因为当将它提供给损失函数时,标签的shape和logits 应该相等。
- 3.我们在这里定义了损失函数。使用“sigmoid_cross_entropy_with_logits”函数是因为我们正在进行二元分类。如果这是一个多类分类,我们应该使用像'softmax_cross_entropy_with_logits'这样的损失函数。
- 4.我们使用“AdamOptimizer()”优化器,因为它具有相当好的性能。
直到这一点,我们讨论的所有代码都不在Tensorflow会话中。从这里开始,所有讨论的代码都将在TensorFlow会话中。
在调用“train_neural_network()”以启动程序之后,Tensorflow会话的起点将是执行开始的位置。
我们正在初始化到目前为止我们已声明的所有全局变量。
- 6.然后我们正在初始化项目中的所有局部变量。
- 7.在这里,我们定义一个循环,直到满足我们定义的迭代次数(epoch)。
- 8.在每个epoch开始时将epoch loss重置为0。
- 9.定义变量以在将数据拆分为批次时跟踪开始和结束计算
- 10.在这里,我们再次定义一个循环,直到batches 达到计算阈值为止。
- 11.和12.我们使用'start'和'end'变量来跟踪数据在每次迭代中的分割位置。
- 13.和14.在每次迭代中,将分别为“batch_x”和“batch_y”变量分配一批特征和标签。
- 15.在这一行中,我们告诉Tensorflow运行必要的子图来计算优化器和成本,方法是将'batch_x'和'batch_y'变量中的值提供给前面提到的占位符。结果,将计算优化器的值和成本,并分别分配给“throw-away”变量和“c”变量。
- 16.当前批处理的损失将添加到“epoch_loss”变量中。
- 17.此行有助于遍历每批数据(特征和标签)。
- 18.打印那个epoch的总损失
到目前为止我们讨论的是模型的训练方面。训练将持续到epochs数达到阈值。
接下来的几行代码用于测试模型。
注意:理想情况下,我们将数据集划分为3组,即训练,验证和测试。我们将保留测试集并使用验证集来查看模型的性能并更改超参数以实现更好的性能。当我们认为模型已经足够改进时,我们只会采用测试集来了解模型的表现。对于本文,我们只使用了两套训练集和测试集来保持简单。
- 19.这是我们将测试数据集提供给模型并告诉Tensorflow运行计算logit所需的子图的地方。然后我们通过sigmoid激活传递logit值来获得预测。四舍五入该值以删除预测值的小数位。
- 20.我们在这里计算F1得分。F1 Score是Precision和Recall的加权平均值。您可以从这里阅读更多相关信息。
- 21.然后我们计算准确度分数。
- 22.这次召回正在计算中。召回是正确预测的阳性观察与所有阳性观察的比率。
- 23.我们也在计算精度。精确度是正确预测的阳性观察值与总预测阳性观察值的比率。
- 24.至27.打印出所有计算得分。
所以,我们终于完成了代码。
我希望本文能帮助您了解使用Tensorflow构建基本LSTM的过程。请注意,此模型是一个非常基本的版本,是构建和改进的良好起点。