笔者邀请您,先思考:
1 您使用过哪些深度学习框架?
2 您用过Keras吗?您用Keras解决什么问题?
在本文中,我们将使用Keras构建一个简单的神经网络。我们假设您对机器学习包(如scikit-learn)和其他科学包(如panda和Numpy)有一定的了解。
训练一个人工神经网络
训练一个人工神经网络包括以下步骤:
- 权值被随机初始化为接近零但不是零的数。
- 将数据集的观察喂给输入层。
- 正向传播(从左到右):激活神经元,得到预测值。
- 将预测结果与实际值进行比较并计算误差。
- 反向传播(从右到左):调整权重。
- 重复步骤1 - 5
- 当整个训练集通过神经网络时,就完成了一个epoch。
业务问题
现在让我们继续解决一个真正的业务问题。一家保险公司向你提供了他们客户先前索赔的数据。保险公司希望你开发一个模型来帮助他们预测哪些索赔看起来是欺诈的。通过这样做,你希望每年为公司节省数百万美元。这是一个分类问题。这些是数据集中的列。
编者按:问题驱动和索赔欺诈,通过帮助公司省钱,以实现数据变现,体现数据,模型和策略的价值。
数据预处理
与许多业务问题一样,所提供的数据没有为我们处理。因此,我们必须以我们的算法能够接受的方式来准备它。我们从数据集中看到我们有一些分类列。我们需要将这些转换成0和1,以便我们的深度学习模型能够理解它们。另一件需要注意的事情是,我们必须将数据集作为numpy数组提供给模型。下面我们导入必要的包,然后加载到数据集中。
代码语言:javascript复制编者按:通过数据预处理的方法和手段,完成好数据的准备工作。
1import pandas as pd
2import numpy as np
3df = pd.read_csv('raw_data/insurance_claims.csv')
然后我们将分类列转换为哑变量。
代码语言:javascript复制1feats = ['policy_state', 'insured_sex', 'insured_education_level', 'insured_occupation', 'insured_hobbies', 'insured_relationship', 'collision_type', 'incident_severity', 'authorities_contacted', 'incident_state', 'incident_city', 'incident_location', 'property_damage', 'police_report_available', 'auto_make', 'auto_model', 'fraud_reported', 'incident_type']
2
3df_final = pd.get_dummies(df, columns=feats, drop_first=True)
在本例中,我们使用drop_first=True来避免虚拟变量陷阱。例如,如果你有ab c d作为类别那么你可以把d作为哑变量。这是因为如果某物不属于a b c,那么它肯定属于d,这被称为多重共线性。
我们使用sklearn的train_test_split将数据拆分为训练集和测试集。
代码语言:javascript复制1from sklearn.model_selection import train_test_split
接下来,我们要确保删除我们预测的列,以防止它泄漏到训练集和测试集。我们必须避免使用相同的数据集来训练和测试模型。我们在数据集的末尾设置.values,以便获得numpy数组。这是我们的深度学习模型接受数据的方式。这一步很重要,因为我们的机器学习模型需要数组形式的数据。
代码语言:javascript复制1X = df_final.drop(['fraud_reported_Y', 'policy_csl', 'policy_bind_date', 'incident_date'],axis=1).values
2y = df_final['fraud_reported_Y'].values
然后我们将数据分割成训练和测试集。我们使用70%的数据进行训练,30%的数据进行测试。
代码语言:javascript复制1X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
接下来,我们必须使用Sklearn的StandardScaler对数据集进行缩放。由于在深度学习中需要进行大量的计算,特性缩放是必须的。特征缩放标准化了自变量的范围。
代码语言:javascript复制1from sklearn.preprocessing import StandardScaler
2sc = StandardScaler()
3X_train = sc.fit_transform(X_train)
4X_test = sc.transform(X_test)
构建人工神经网络(ANN)
我们需要做的第一件事是导入Keras。默认情况下,Keras将使用TensorFlow作为其后端。
代码语言:javascript复制1import keras
接下来,我们需要从Keras导入一些模块。Sequential模块用于初始化ANN,Dense模块用于构建ANN的层。
代码语言:javascript复制1from keras.models import Sequential
2from keras.layers import Dense
接下来,我们需要通过创建一个sequence实例来初始化ANN。sequence函数初始化一个层级的线性堆栈。这允许我们在以后使用Dense模块添加更多的层。
代码语言:javascript复制1classifier = Sequential()
添加输入层(第一隐藏层)
我们使用add方法向ANN添加不同的层。第一个参数是要添加到该层的节点数。对于应该添加多少个节点没有经验法则,但是一个常见的策略是选择节点的数量是输入层节点的和输出层节点的数量的平均值。
比如说你有五个自变量和一个输出。然后把它们加起来除以2,也就是3。您还可以决定试验一种称为参数调优的技术。第二个参数kernel_initializer将用于初始化权重。在这种情况下,它将使用均匀分布来确保权重是接近于零的小数字。下一个参数是激活函数。我们用整流器函数,简称relu。我们主要使用这个函数在ANN中隐藏层。最后一个参数是input_dim,它是输入层中的节点数。它表示自变量的数量。
代码语言:javascript复制1classifier.add(
2 Dense(3, kernel_initializer = ‘uniform’,
3 activation = ‘relu’, input_dim=5))
添加第二个隐藏层
添加第二个隐藏层类似于添加第一个隐藏层。
代码语言:javascript复制1classifier.add(
2 Dense(3, kernel_initializer = ‘uniform’,
3 activation = ‘relu’))
我们不需要指定input_dim参数,因为我们已经在第一个隐藏层中指定了它。在第一个隐藏层中,我们指定了这个,以便让层知道需要多少输入节点。在第二个隐藏层中,ANN已经知道需要多少输入节点,所以我们不需要重复。
添加输出层
代码语言:javascript复制1classifier.add(
2 Dense(1, kernel_initializer = ‘uniform’,
3 activation = ‘sigmoid’))
我们改变第一个参数,因为在输出节点中我们需要一个节点。这是因为我们只关心一项索赔是否具有欺骗性。我们改变激活函数因为我们想要得到索赔是欺诈的概率。我们通过使用Sigmoid激活函数来做到这一点。如果您要处理的分类问题有两个以上的类(例如,分类猫、狗和猴子),我们需要改变两件事。我们将第一个参数改为3,激活函数改为softmax。Softmax是一个应用于两个以上类别的自变量的sigmoid函数。
编译ANN
代码语言:javascript复制1classifier.compile(optimizer= ‘adam’,
2 loss = ‘binary_crossentropy’,
3 metrics = [‘accuracy’])
编译基本上是将随机梯度下降法应用于整个神经网络。第一个参数是你想要用来在神经网络中得到最优权重集的算法。这里使用的算法是一个随机梯度算法。这有很多变体。一个非常有效的方法是adam。第二个参数是随机梯度算法中的损失函数。由于我们的分类是二进制的,我们使用binary_crossentropy 损失函数。否则我们就会使用categorical_crossentopy。
训练集上拟合ANN
代码语言:javascript复制1classifier.fit(X_train, y_train, batch_size = 10, epochs = 100)
X_train表示我们用来训练ANN的自变量,y_train表示我们预测的列。Epochs表示通过ANN传递完整数据集的次数。Batch_size是权重将被更新的观察值的数量。
使用训练集进行预测
代码语言:javascript复制1y_pred = classifier.predict(X_test)
这将向我们显示索赔欺诈的可能性。然后,我们为将索赔归类为欺诈设定阈值为50%。这意味着任何概率为0.5或以上的索赔都将被归类为欺诈。
代码语言:javascript复制1y_pred = (y_pred > 0.5)
通过这种方式,保险公司可以首先追踪那些没有可疑的索赔,然后花更多时间评估那些被标记为欺诈的索赔。
核查混淆矩阵
代码语言:javascript复制1from sklearn.metrics import confusion_matrix
2cm = confusion_matrix(y_test, y_pred)
混淆矩阵的解释如下。在2000个观测中,1550 175观测被正确预测,230 45观测被错误预测。你可以用正确预测的次数除以总预测次数来计算准确率。在这种情况下(1550 175)/ 2000,也就是86%
做一个预测
假设保险公司只给你一次索赔。他们想知道索赔是否具有欺骗性。你会怎么做才能知道呢?
代码语言:javascript复制1new_pred = classifier.predict(sc.transform(np.array([[a,b,c,d]])))
其中a b c d代表你的特征。
代码语言:javascript复制1new_pred = (new_prediction > 0.5)
由于我们的分类器需要numpy数组,所以我们必须将单个观察值转换为numpy数组,并使用变量标准化进行缩放。
评价ANN
在对模型进行一到两次训练之后,您会注意到您会得到不同的准确度。所以你不确定哪个是正确的。这就引入了偏差方差权衡。从本质上讲,我们正在尝试训练一个模型,它将是准确的,并且在训练几次后,它的准确性不会有太多的差异。为了解决这个问题,我们使用K-fold交叉验证,K = 10。这将把训练集分成10份。然后我们将在9个flods上训练我们的模型,并在剩下的flod上测试它。因为我们有10个flods,我们将通过10个组合迭代来做这个。
每次迭代都会给我们提供它的准确性。然后我们会找到所有准确度的平均值并将其作为模型的准确度。我们还计算了方差,以确保它是最小的。
Keras有一个scikit学习包装器(KerasClassifier),它允许我们在Keras代码中包含K-fold交叉验证。
代码语言:javascript复制1from keras.wrappers.scikit_learn import KerasClassifier
接下来,我们从scikit_learn导入k-fold交叉验证函数。
代码语言:javascript复制1from sklearn.model_selection import cross_val_score
KerasClassifier希望它的一个参数是一个函数,因此我们需要构建这个函数。这个函数的目的是构建我们的ANN的架构。
代码语言:javascript复制1def make_classifier():
2 classifier = Sequential()
3 classiifier.add(Dense(3, kernel_initializer = ‘uniform’, activation = ‘relu’, input_dim=5))
4 classiifier.add(Dense(3, kernel_initializer = ‘uniform’, activation = ‘relu’))
5 classifier.add(Dense(1, kernel_initializer = ‘uniform’, activation = ‘sigmoid’))
6 classifier.compile(optimizer= ‘adam’,loss = ‘binary_crossentropy’,metrics = [‘accuracy’])
7 return classifier
这个函数将构建分类器并返回它以供下一步使用。我们在这里做的唯一一件事就是将前面的ANN体系结构包装在一个函数中并返回分类器。
然后,我们使用K-fold交叉验证创建一个新的分类器,并将参数build_fn作为前面创建的函数传递。接下来,我们传递batch的大小和epoch的数量,就像我们在前面的分类器中所做的一样。
代码语言:javascript复制1classiifier = KerasClassifier(build_fn = make_classifier,
2 batch_size=10, nb_epoch=100)
要应用k-fold交叉验证函数,我们可以使用scikit-learn的cross_val_score函数。估计器就是我们用make_classifier构建的分类器,n_jobs=-1将利用所有可用的cpu。cv是折叠数,10是一个典型的选择。cross_val_score将返回计算中使用的十个测试fold的十个准确度。
代码语言:javascript复制1accuracies = cross_val_score(estimator = classifier,
2 X = X_train,
3 y = y_train,
4 cv = 10,
5 n_jobs = -1)
为了得到相对准确度,我们得到了准确度的均值。
代码语言:javascript复制1mean = accuracies.mean()
所得方差如下:
代码语言:javascript复制1variance = accuracies.var()
目标是在准确度之间有一个小的差异。
克服过拟合
机器学习中的过度拟合是指当模型在训练集中学习细节和噪声,以致在测试集中表现不佳时发生的情况。当我们在测试集和训练集的准确度之间存在巨大差异时,或者当你在应用k-fold交叉验证时观察到高方差时,就可以观察到过拟合。在人工神经网络中,我们使用了一种叫做“dropout regularization”的技术来解决这个问题。dropout regularization通过在训练的每次迭代中随机禁用一些神经元,以防止它们彼此过于依赖。
代码语言:javascript复制 1from keras.layers import Dropout
2
3classifier = Sequential()
4classiifier.add(Dense(3, kernel_initializer = ‘uniform’, activation = ‘relu’, input_dim=5))
5
6# Notice the dropouts
7classifier.add(Dropout(rate = 0.1))
8classiifier.add(Dense(6, kernel_initializer = ‘uniform’, activation = ‘relu’))
9classifier.add(Dropout(rate = 0.1))
10
11classifier.add(Dense(1, kernel_initializer = ‘uniform’, activation = ‘sigmoid’))
12classifier.compile(optimizer= ‘adam’,loss = ‘binary_crossentropy’,metrics = [‘accuracy’])
在这种情况下,我们在第一隐藏层和第二隐藏层之后应用drop。使用0.1的比率意味着10%的神经元将在每次迭代中被禁用。建议从0.1开始。然而,你不应该超过0.4,因为你现在开始变得欠拟合。
参数调整
一旦您获得了您的准确度,您就可以调整参数以获得更高的准确度。网格搜索使我们能够测试不同的参数,以获得最佳的参数。
第一步是从sklearn导入GridSearchCV模块。
代码语言:javascript复制1from sklearn.model_selection import GridSearchCV
我们还需要修改make_classifier函数,如下所示。我们创建了一个名为optimizer的新变量,它允许我们在params变量中添加多个优化器。
代码语言:javascript复制1def make_classifier(optimizer):
2 classifier = Sequential()
3 classiifier.add(Dense(6, kernel_initializer = ‘uniform’, activation = ‘relu’, input_dim=11))
4 classiifier.add(Dense(6, kernel_initializer = ‘uniform’, activation = ‘relu’))
5 classifier.add(Dense(1, kernel_initializer = ‘uniform’, activation = ‘sigmoid’))
6 classifier.compile(optimizer= optimizer,loss = ‘binary_crossentropy’,metrics = [‘accuracy’])
7 return classifier
我们仍然会使用KerasClassifier,但是我们不会传递批处理大小和epoch的数量,因为这些是我们想要调优的参数。
代码语言:javascript复制1classifier = KerasClassifier(build_fn = make_classifier)
下一步是创建一个字典,其中包含我们想要调优的参数——在本例中是批处理大小、epoch的数量和优化器函数。我们仍然使用adam作为优化器,并添加了一个名为rmsprop的新优化器。Keras文档在处理循环神经网络时推荐使用rmsprop。然而,我们可以尝试为这个ANN看看它是否给我们一个更好的结果。
代码语言:javascript复制1params = {
2 'batch_size':[20,35],
3 'nb_epoch':[150,500],
4 'Optimizer':['adam','rmsprop']
5}
然后我们使用网格搜索来测试这些参数。网格搜索函数需要我们的估计器,我们刚刚定义的参数,评分指标和k-fold的数量。
代码语言:javascript复制1grid_search = GridSearchCV(estimator=classifier,
2 param_grid=params,
3 scoring=’accuracy’,
4 cv=10)
和前面的对象一样,我们需要拟合我们的训练集。
代码语言:javascript复制1grid_search = grid_search.fit(X_train,y_train)
我们可以使用best_params从网格搜索对象中获得最佳的参数选择。同样,我们使用best_score_来获得最好的分数。
代码语言:javascript复制1best_param = grid_search.best_params_
2best_accuracy = grid_search.best_score_
需要注意的是,在寻找最佳参数时,这个过程需要一段时间。
总结
人工神经网络只是一种深层神经网络。还有其他一些网络,如递归神经网络(RNN)、卷积神经网络(CNN)和玻尔兹曼机。RNNs可以预测股票的价格在未来是否会上涨或下跌。CNNs用于计算机视觉——在一组图像中识别猫和狗,或在大脑图像中识别癌细胞的存在。玻尔兹曼机用于设计推荐系统。也许我们可以在未来介绍其中一个神经网络。
Cheers.
作者:Derrick Mwiti 原文链接: https://heartbeat.fritz.ai/introduction-to-deep-learning-with-keras-c7c3d14e1527
您有什么想法或者见解,请留言。
数据人网是数据人学习,交流和分享的平台,诚邀您创造和分享数据知识,共建和共享数据智库。