什么是Tensorflow?
TensorFlow是谷歌推出的深度学习框架,于2019年发布了第二版。 它是世界上最著名的深度学习框架之一,被行业专家和研究人员广泛使用。
Tensorflow v1难以使用和理解,因为它的Pythonic较少,但是随着Keras发行的v2现在与Tensorflow.keras完全同步,它易于使用,易学且易于理解。
请记住,这不是有关深度学习的文章,所以我希望您了解深度学习的术语及其背后的基本思想。
我们将使用非常著名的数据集IRIS数据集探索深度学习的世界。
废话不多说,我们直接看看代码。
导入和理解数据集
- from sklearn.datasets import load_iris
- iris = load_iris()
现在,这个 iris 是一个字典。 我们可以使用下面的代码查看键值
- >>> iris.keys()
- dict_keys([‘data’, ‘target’, ‘frame’, ‘target_names’, ‘DESCR’, ‘feature_names’, ‘filename’])
因此,我们的数据在 data 键中,目标在 targe 键中,依此类推。 如果要查看此数据集的详细信息,可以使用 iris[ ['DESCR']。
现在,我们必须导入其他重要的库,这将有助于我们创建神经网络。
- from sklearn.model_selection import train_test_split #to split data
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- import tensorflow as tf
- from tensorflow.keras.layers import Dense
- from tensorflow.keras.models import Sequential
在这里,我们从tensorflow中导入了2个主要的东西,分别是Dense和Sequential。 从tensorflow.keras.layers导入的Dense是紧密连接的一种层。 密集连接的层意味着先前层的所有节点都连接到当前层的所有节点。
Sequential是Keras的API,通常称为Sequential API,我们将使用它来构建神经网络。
为了更好地理解数据,我们可以将其转换为数据帧。 我们开始做吧。
- X = pd.DataFrame(data = iris.data, columns = iris.feature_names)
- print(X.head())
- X.head()
请注意,这里我们设置了column = iris.feature_names,其中feature_names是具有所有4个特征名称的键。
同样对于目标,
- y = pd.DataFrame(data=iris.target, columns = [‘irisType’])
- y.head()
要查看目标集合中的类数量,我们可以使用
- y.irisType.value_counts()
这里我们可以看到我们有3个类,每个类都有标签0、1和2。
- iris.target_names #它是iris词典的键值
这些是我们必须预测的类名称。
机器学习的数据预处理
目前,机器学习的第一步就是数据预处理。数据预处理的主要步骤是:
- 填入缺失值
- 将数据分割成为训练集以及验证集
- 对数据进行标准化处理
- 将类别性数据转换成为独热向量
缺失值
为了检查是否存在缺失值,我们可以用pandas.DataFrame.info()来进行检查工作。
- X.info()
这样我们就可以看到我们(很幸运地)没有缺失值,并且所有特征都是float64格式的。
分割为训练集和测试集
为了将数据集分割为训练集和测试集,我们可以使用先前已经引入过的sklearn.model_selection中的train_test_split。
- X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.1)
其中test_size是一种声明,它说明我们希望整个数据集的10%被用来做为测试数据。
数据的标准化
一般情况下,当数据的偏差非常大的时候,我们会对数据进行标准化。为了查看偏差值,我们可以使用pandas.DataFrame中的var()函数来检查所有列的偏差值。
- X_train.var(), X_test.var()
这样我们便可以看到,X_train和X_test的偏差值都非常低,因此无需对数据进行标准化。
将分类数据转换为一个独热向量
因为我们知道我们的输出数据是已经使用iris.target_name检查过的3个类之一,所以好消息是,当我们加载目标时,它们已经是0、1、2格式,其中0=1类,1=2类,依此类推。
这种表示方式的问题在于,我们的模型可能会赋予越高的数字更高的优先级,这可能会导致结果有偏差。 因此,为了解决这个问题,我们将使用单热点表示法。 你可以在这里了解更多关于一个热门载体的信息。 我们可以使用内置的KERS TO_CATEGRICAL,也可以使用skLearn中的OneHotEncoding。 我们将使用to_classical。
- y_train = tf.keras.utils.to_categorical(y_train)
- y_test = tf.keras.utils.to_categorical(y_test)
我们将只检查前5行,以检查它是否已正确转换。
- y_train[:5,:]
是的,我们已经把它转换成了独热的表达方式。
最后一件事
我们可以做的最后一件事是将我们的数据转换回Numpy数组,这样我们就可以使用一些额外的函数,这些函数将在稍后的模型中对我们有所帮助。 要做到这一点,我们可以使用
- X_train = X_train.values
- X_test = X_test.values
让我们看看第一个训练示例的结果是什么。
- X_train[0]
在这里,我们可以看到第一个训练示例中4个特征的值,它的形状是(4),
当我们在它们上使用to_Category时,我们的目标标签已经是数组格式。
机器学习模型
现在,我们终于准备好创建我们的模型并对其进行训练。 我们将从一个简单的模型开始,然后我们将转到复杂的模型结构,在那里我们将介绍Keras中的不同技巧和技术。
让我们对我们的基本模型进行编码
- model1 = Sequential() #Sequential Object
首先,我们必须创建一个Sequential对象。 现在,要创建一个模型,我们所要做的就是根据我们的选择添加不同类型的层。 我们将制作一个10层的Dense层模型,这样我们就可以观察到过拟合,并在以后通过不同的正则化技术来减少它。
- model1.add( Dense( 64, activation = 'relu', input_shape= X_train[0].shape))
- model1.add( Dense (128, activation = 'relu')
- model1.add( Dense (128, activation = 'relu')
- model1.add( Dense (128, activation = 'relu')
- model1.add( Dense (128, activation = 'relu')
- model1.add( Dense (64, activation = 'relu')
- model1.add( Dense (64, activation = 'relu')
- model1.add( Dense (64, activation = 'relu')
- model1.add( Dense (64, activation = 'relu')
- model1.add( Dense (3, activation = 'softmax')
请注意,在我们的第一层中,我们使用了一个额外的参数INPUT_Shape。 此参数指定第一层的尺寸。 在这种情况下,我们不关心训练示例的数量。 相反,我们只关心功能的数量。 因此,我们传入任何训练示例的形状,在我们的示例中,它是(4,)在input_Shape内。
请注意,我们在输出层中使用了Softmax(激活函数),因为它是一个多类分类问题。 如果这是一个二进制分类问题,我们会使用Sigmoid激活函数。
我们可以传入任何我们想要的激活函数,如Sigmoid或linear或tanh,但实验证明relu在这类模型中表现最好。
现在,当我们定义了模型的形状后,下一步是指定它的损耗、优化器和度量。 我们在keras中使用Compile方法指定这些参数。
- model1.compile(optimizer='adam', loss= 'categorical_crossentropy', metrics = ['acc'])
在这里,我们可以使用任何优化器,如随机梯度下降、RMSProp等,但我们将使用Adam。
我们在这里使用CATEGRICAL_CROSENTROPY是因为我们有一个多类分类问题,如果我们有一个二进制分类问题,我们将使用BINARY_CROSENTROPY。
衡量标准对于评估一个人的模型是很重要的。 我们可以根据不同的度量标准来评估我们的模型。 对于分类问题,最重要的衡量标准是准确度,它表明我们的预测有多准确。
我们模型的最后一步是将其匹配到训练数据和训练标签上。 让我们对它进行编码。
- history = model1.fit(X_train, y_train, batch_size = 40, epochs=800, validation_split = 0.1
fit返回一个回调,其中包含我们训练的所有历史记录,我们可以使用它来执行不同的有用任务,如绘图等。
历史回调有一个名为history的属性,我们可以将其作为history.history进行访问,这是一个包含所有损失和指标历史的字典,即,在我们的示例中,它具有Loss、Acc、val_loses和val_acc的历史记录,并且我们可以将每个单独的历史记录作为 history.history.loss 或 history.history['val_acc'] 等进行访问。
我们有一个指定的epoch数为800,batch大小为40,验证拆分为0.1,这意味着我们现在有10%的验证数据,我们将使用这些数据来分析我们的训练。 使用800个epoch将过度拟合数据,这意味着它将在训练数据上执行得非常好,但在测试数据上则不会。
当模型进行训练时,我们可以看到我们在训练集和验证集上的损失和准确性。
在此,我们可以看到,训练集上的准确率是100%,验证集上的准确率则为67%,这对于这样一个模型来说已经很出色了。接下来就让我们画出图像。
- plt.plot(history.history['acc'])
- plt.plot(history.history['val_acc'])
- plt.xlabel('Epochs')
- plt.ylabel('Acc')
- plt.legend(['Training', 'Validation'], loc='upper right')
我们可以很清楚地看到,训练集上的准确率要比验证集上高得多了。
类似地,我们用如下方法画出损失:
- plt.plot(history.history['loss'])
- plt.plot(history.history['val_loss'])
- plt.xlabel('Epochs')
- plt.ylabel('Loss')
- plt.legend(['Training', 'Validation'], loc='upper left')
在此,我们可以很清楚地看到,验证集上的损失比训练集上要大得多了,这是因为数据被过拟合了。
为了看看模型的表现是不是好,我们可以使用model.evaluate来查看。我们要将数据和标签放入评估函数中。
- model1.evaluate(X_test, y_test)
这样,我们就可看到模型的准确率为88%,这对于一个过拟合的模型来说已经很好了。
正则化
让我们通过将正则化添加到我们的模型中来使它变得更好。 正则化将减少我们模型的过度拟合,并将改进我们的模型。
我们将在我们的模型中添加L2正则化。 单击 此处了解有关L2正则化的更多信息。 要在我们的模型中添加L2正则化,我们必须指定要添加正则化的层,并给出一个附加参数kernel_Regularizer,然后传递tf.keras.Regularizers.l2()。
我们还将在我们的模型中实现一些dropout,这将帮助我们更好地减少过拟合,从而获得更好的性能。 要阅读更多关于dropout背后的理论和动机,请参阅这篇文章。
让我们重新定义这个模型吧。
- model2 = Sequential()
- model2.add(Dense(64, activation = 'relu', input_shape= X_train[0].shape))
- model2.add( Dense(128, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add( Dense (128, activation = 'relu',kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add(tf.keras.layers.Dropout(0.5)
- model2.add( Dense (128, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add(Dense(128, activation = 'relu', kernel_regularizer = tf.keras.regularizers.l2(0.001)
- ))
- model2.add( Dense (64, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add( Dense (64, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add(tf.keras.layers.Dropout(0.5)
- model2.add( Dense (64, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add( Dense (64, activation = 'relu', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
- model2.add( Dense (3, activation = 'softmax', kernel_regularizer=tf.keras.regularizers.l2(0.001)
- ))
如果你仔细观察,我们所有的层和参数都是一样的,除了我们在每个dense层中增加了2个dropout层和正则化。
我们将保留所有其他东西(损失、优化器、epoch等)一样。
- model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
- history2 = model2.fit(X_train, y_train, epochs=800, validation_split=0.1, batch_size=40)
现在让我们评估一下模型。
你猜怎么着? 通过加入正则化和dropout层,我们的准确率从88%提高到94%。 如果我们增加了BN层,它将会进一步改善。
让我们把它画出来。
准确率
- plt.plot(history2.history['acc'])
- plt.plot(history2.history['val_acc'])
- plt.title('Accuracy vs. epochs')
- plt.ylabel('Acc')
- plt.xlabel('Epoch')
- plt.legend(['Training', 'Validation'], loc='lower right')
- plt.show()
- plt.plot(history2.history['loss'])
- plt.plot(history2.history['val_loss'])
- plt.title('Loss vs. epochs')
- plt.ylabel('Loss')
- plt.xlabel('Epoch')
- plt.legend(['Training', 'Validation'], loc='upper right')
- plt.show()
洞见
如此一来,我们就非常成功地改善了模型的过拟合,并且将模型准确率提升了几乎6%,这对于一个小数据集来说是很好的改善。
本文转自雷锋网,如需转载请至雷锋网官网申请授权。