TensorFlow基本使用

Posted love the future

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TensorFlow基本使用相关的知识,希望对你有一定的参考价值。

文章目录

TensorFlow中的keras

到目前为止,Keras已经与TensorFlow完全整合。Keras团队不再更新或维护Keras的独立版本。所以现在所讨论的Keras,是一个集成在Tensor Flow中的API,而不是一个单独的独立库。

传入网络的数据类型

在准备数据时,我们首先需要了解数据的格式,希望数据的格式能够传递给神经网络模型。Sequential模型在训练期间接收数据,这发生在我们对模型调用fit()函数时(训练)。因此,我们需要检查这个函数期望的数据类型。
fit()函数接收的参数如下:

fit(
    x=None,
    y=None,
    batch_size=None,
    epochs=1,
    verbose='auto',
    callbacks=None,
    validation_split=0.0,
    validation_data=None,
    shuffle=True,
    class_weight=None,
    sample_weight=None,
    initial_epoch=0,
    steps_per_epoch=None,
    validation_steps=None,
    validation_batch_size=None,
    validation_freq=1,
    max_queue_size=10,
    workers=1,
    use_multiprocessing=False
)

对其中一些常见的参数进行解释:

  • x:输入的特征值,可以作为x的数据类型如下:
    • 1.numpy中的数组,或者数组列表
    • 2.TensorFlow中的张量,或者张量列表
    • 3.tf.data 中的数据集,输入形式因该是(inputs,targets)或者是(inputs,targets,sample_weights)
    • 4.tf.keras.utils.experimental.DatasetCreator中的数据,它封装了一个可调用函数,该函数只接受一个 tf.distribute.InputContext类型的参数
  • y: 输入特征值对应的标签,与输入数据X一样,是numpy数组或者是张量,应该与x一致,如果x是一个数据集(dataset),生成器(generator),或者是 keras.utils.Sequence的实例,不应该指定y,因为x中就直接包含了y。
  • batch_size:整数值,表示的每次更新的样本数,如果没有指定的话,批次大小是默认32,如果x是一个数据集(dataset),生成器(generator),或者是 keras.utils.Sequence的实例,不应该指定batch_size,因为x中会生成批次。
  • epochs:整数值,训练模型的次数。epoch是对所提供的整个x和y数据的迭代
  • validation_split:0-1之间的一个数值,表示的是在数据中分离出来的验证集的比例,不在该验证集上进行训练,只是在每次epoch中对其进行验证,如果x是一个数据集(dataset),生成器(generator),或者是 keras.utils.Sequence的实例,不应该指定validation_split,
  • validation_data:表示具体的训练集数据,通过元组(V_sample,V_label)的形式.
  • shuffle:True和False。以batch_size的大小进行洗牌。
  • verbose:指定了我们希望在每个训练阶段看到的控制台输出量。详细程度从0到2不等,因此我们得到的是最详细的输出。0表示是什么都不输出。

更多的细节可以查看:https://tensorflow.google.cn/api_docs/python/tf/keras/Sequential#fit
除了格式化数据以使其符合模型所需的格式之外,格式化或处理数据的另一个原因是以这样的方式对其进行转换,从而使网络更容易、更快或更高效地学习

数据处理

深度学习的数据处理将因我们处理的数据类型和我们将使用网络执行的任务类型而有很大不同。
我们将从一个非常简单的分类任务开始,使用一个简单的数字数据集。
我们首先需要导入我们将要使用的库。接下来,我们创建两个空列表。一个保存输入数据,另一个保存目标数据。

import numpy as np
from random import randint
from sklearn.utils import shuffle
from sklearn.preprocessing import MinMaxScaler
train_labels = []
train_samples = []

创建数据集:一个简单的数据集,用于一个简单的任务
我们假设在一项临床试验中,一种实验药物在13岁到100岁的人身上进行了测试。该试验有2100名参与者。一半参与者年龄在65岁以下,另一半参与者年龄在65岁或以上。该试验显示,约95%的65岁或以上患者出现药物副作用,约95%的65岁以下患者没有副作用,这通常表明老年人更有可能出现副作用。

最终,我们想要建立一个模型,告诉我们患者是否会仅仅根据患者的年龄而经历副作用。模型的判断将基于训练数据。

年龄数量情况
13-64105095%没有副作用,5%出现副作用
65及以上105095%出现副作用,5%没有副作用

该代码创建2100个样本,并在train_samples列表中存储个体的年龄,并在train_labels列表中存储个体是否经历过副作用。

for i in range(50):
    # The ~5% of younger individuals who did experience side effects
    random_younger = randint(13,64)
    train_samples.append(random_younger)
    train_labels.append(1)

    # The ~5% of older individuals who did not experience side effects
    random_older = randint(65,100)
    train_samples.append(random_older)
    train_labels.append(0)

for i in range(1000):
    # The ~95% of younger individuals who did not experience side effects
    random_younger = randint(13,64)
    train_samples.append(random_younger)
    train_labels.append(0)

    # The ~95% of older individuals who did experience side effects
    random_older = randint(65,100)
    train_samples.append(random_older)
    train_labels.append(1)

由于fit()函数的预测,我们现在将这两个列表转换为numpy数组,然后对数组进行shuffle,以删除创建过程中强加给数据的任何顺序。

train_labels = np.array(train_labels)
train_samples = np.array(train_samples)
train_labels, train_samples = shuffle(train_labels, train_samples)

在这种形式下,我们现在能够将数据传递给模型,因为它现在是所需的格式,然而,在这样做之前,我们首先将数据缩小到0到1的范围。
我们将使用scikit learn的MinMaxScaler类将所有数据从13到100的范围缩小到0到1的范围。

scaler = MinMaxScaler(feature_range=(0,1))
scaled_train_samples = scaler.fit_transform(train_samples.reshape(-1,1))

上面的reshape是因为fit_transform()不接受一维数据,所以进行维度的扩增。

模型建立

先导入TensorFlow相关的包

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Activation, Dense
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.metrics import categorical_crossentropy

接下来是通过Sequential()创建模型的各层次结构,model是Sequential对象的一个实例,tf.kreas.Sequential模型是一个层的线性堆栈,它接受一个列表,列表中的每一元素都是一个层

model = Sequential([
    Dense(units=16, input_shape=(1,), activation='relu'),
    Dense(units=32, activation='relu'),
    Dense(units=2, activation='softmax')
])

我们的第一层是Dense层。这种类型的层是我们标准的完全连接的神经网络层。Dense层需要的第一个参数是该层拥有的神经元或单位的数量,我们任意将其设置为16。
此外,模型需要知道输入数据的形状(也就是输入特征)。因此,我们在模型的第一个隐藏层中指定输入数据的形状(仅此层),其他的层会自动从上一层获得输入数据的形状。名为input_shape的参数就是我们指定它的方式。
如前所述,我们将根据我们在上一集中生成和处理的数据来训练我们的网络,train_samples是一维的。input_shape参数需要一个匹配输入数据形状的整数元组,因此我们相应地指定(1,)作为一维数据的input_shape。

你可以把我们在这里指定input_shape的方式想象成一个隐式输入层。神经网络的输入层是底层原始数据本身,因此我们不创建明确的输入层。我们现在处理的第一个Dense层实际上是第一个隐藏层。
最后,我们将为密集层设置的可选参数是在该层之后使用的激活函数。我们将使用流行的relu选项。注意,如果没有明确设置激活函数,那么Keras将使用linear激活函数。

我们的下一层也将是Dense层,这一层将有32个节点。这个节点有多少神经元的选择也是任意的,因为其想法是创建一个简单的模型,然后用它进行测试和实验。如果我们注意到这是不够的,那么在那个时候,我们可以解决这个问题,并开始尝试改变参数,如层数、节点数等。这个Dense层还将使用relu作为其激活函数。
最后,我们指定输出层。这一层也是一个Dense层,它将有2个神经元。这是因为我们有两种可能的输出:**要么患者出现副作用,要么患者没有出现副作用。**这一次,我们将使用的激活函数是softmax,它将为我们提供可能输出之间的概率分布。
我们可以在模型上调用summary()来快速可视化该模型。

model.summary()

模型训练

首先我们需要将模型需要的数据准备好,compile()函数就是将模型训练时所需要的所有数据都准备好,等着模型进行训练即可。

model.compile(optimizer=Adam(learning_rate=0.0001), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
  • optimizer:训练网络使用的优化器,参数为学习率
  • loss:使用的多分类分类交叉熵损失函数,二分类也可以使用二进制交叉熵binary_crossentropy,最后一层需要使用sigmoid而不是softmax作为其激活函数。
  • metrics:该参数需要一个指标列表,我们希望模型在培训和测试期间对这些指标进行评估。我们将其设置为包含字符串“accurity”的列表。表示该模型的准确率。
model.fit(x=scaled_train_samples, y=train_labels, batch_size=10, epochs=30, verbose=2)

  • verbose=2:指定了我们希望在每个训练阶段看到的控制台输出量。详细程度从0到2不等,因此我们得到的是最详细的输出。0表示是什么都不输出。

验证集的作用

回想一下,我们之前构建了一个训练集,在此基础上训练我们的模型。随着我们的模型被训练的每一个阶段,模型将继续学习这个训练集中数据的特征和特征。我们的希望是,以后我们可以利用这个模型,将其应用到新数据中,并让该模型仅根据从训练集中学到的知识,准确地预测以前从未见过的数据。
这就是验证集的作用。在训练开始之前,我们可以选择删除培训集的一部分,并将其放入验证集中。然后,在训练期间,模型将只在训练集中训练,并通过评估验证集中的数据进行验证。本质上,该模型是在训练集中学习数据的特征,从这些数据中学习到什么,然后在验证集上进行预测。在每个阶段,我们不仅会看到训练集的损失和准确性结果,还会看到验证集的损失和准确性结果。这让我们能够看到模型在未经训练的数据上的泛化程度,因为回想起来,验证数据不应该是训练数据的一部分。
这也有助于我们了解模型是否过度拟合。当模型只了解训练数据的细节,无法很好地概括未训练的数据时,就会发生过度拟合。
通常情况下,我们的训练集准确率如果大于验证集的准确率,表示发生了过拟合

创建验证集的方式一:

可以和创建数据集那样创建符合要求的验证集数据,valid_set = (x_val, y_val),然后直接将该验证集数据传入fit中进行训练即可。

model.fit(
      x=scaled_train_samples
    , y=train_labels
    , validation_data=valid_set
    , batch_size=10
    , epochs=30
    , verbose=2
)

创建验证集的方式二:

直接使用 validation_split参数在训练集中进行分割。
指定此参数后,Keras将分离训练数据的一部分(本例中为10%)用作验证数据。该模型将分离训练数据的这一部分,不在其上进行训练,并将在每个epoch结束时评估该数据的损失和任何模型度量。
请注意,默认情况下,fit()函数会在每个epoch之前洗牌数据。但是,在指定validation_split参数时,会从洗牌前x和y数据中的最后一个样本中选择验证数据。因此,在我们以这种方式使用validation_split来创建验证数据的情况下,我们需要确保我们的数据已经提前被shuffle。

model.fit(
      x=scaled_train_samples
    , y=train_labels
    , validation_split=0.1
    , batch_size=10
    , epochs=30
    , verbose=2
)

不仅可以看到训练数据集的准确性信息,还可以看到验证集中的信息。

模型预测

首先需要创建与训练数据类似的测试数据,该数据是模型从没有见过的,因此可以测试模型的训练结果。
创建测试集的方法与训练集的创建很类似。

test_labels =  []
test_samples = []

for i in range(10):
    # The 5% of younger individuals who did experience side effects
    random_younger = randint(13,64)
    test_samples.append(random_younger)
    test_labels.append(1)

    # The 5% of older individuals who did not experience side effects
    random_older = randint(65,100)
    test_samples.append(random_older)
    test_labels.append(0)

for i in range(200):
    # The 95% of younger individuals who did not experience side effects
    random_younger = randint(13,64)
    test_samples.append(random_younger)
    test_labels.append(0)

    # The 95% of older individuals who did experience side effects
    random_older = randint(65,100)
    test_samples.append(random_older)
    test_labels.append(1)

test_labels = np.array(test_labels)
test_samples = np.array(test_samples)
test_labels, test_samples = shuffle(test_labels, test_samples)

scaled_test_samples = scaler.fit_transform(test_samples.reshape(-1,1))

最后利用model.predict()进行预测。在进行测试的时候,是不需要对数据的label值进行输入的,只是为了测试数据的结果,最后我们通过绘制一个混淆矩阵进行效果的分析。
对于这个函数,我们传入测试样本x,指定批处理大小,并指定在预测生成期间希望日志消息的详细程度。预测的输出与我们无关,因此我们将verbose设置为0表示无输出。请注意,与训练集和验证集不同,我们在推理阶段不会将测试集的标签传递给模型。
首先看一下打印的结果,可以知道是一个数组,每一个元素表示的是预测为0,和1的概率是多少。概率大的即为我们预测的结果。

for i in predictions:
    print(i)

预测结果的分析

我们通过绘制混淆矩阵对最后的预测结果进行分析。
首先我们将预测的概率值转化为我们最后的结果,也就是是否有副作用,用0和1表示。

rounded_predictions = np.argmax(predictions, axis=-1)   #返回预测结果更大的那个所在下标,即为我们所需要的预测结果
#引入混淆矩阵需要的包
%matplotlib inline
from sklearn.metrics import confusion_matrix
import itertools
import matplotlib.pyplot as plt
#构造混淆矩阵
cm = confusion_matrix(y_true=test_labels, y_pred=rounded_predictions)
# 绘制混淆矩阵的函数
def plot_confusion_matrix(cm, classes,
                        normalize=False,
                        title='Confusion matrix',
                        cmap=plt.cm.Blues):
    """
    This function prints and plots the confusion matrix.
    Normalization can be applied by setting `normalize=True`.
    """
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
            horizontalalignment="center",
            color="white" if cm[i, j] > thresh else "black")
        
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
#进行绘制
cm_plot_labels = ['no_side_effects','had_side_effects']
plot_confusion_matrix(cm=cm, classes=cm_plot_labels, title='Confusion Matrix')

模型的加载和保存

#将模型保存至在当前目录下的model/下。
model.save('models/medical_trial_model.h5')

模型的加载需要导入TensorFlow中的load_model

from tensorflow.keras.models import load_model
new_model = load_model('models/medical_trial_model.h5')

最后获得的新模型new_model 与原来的模型一样的结构。还包含模型中使用的优化器,模型的损失函数,以及模型的权值。这种保存模型的方式是保存信息最全面的一种方式。
仅保存模型的结构信息
我们只保存模型的架构。这不会保存模型权重、配置、优化器、损失或其他任何内容。这只会保存模型的体系结构。我们可以通过调用model.to_json()来实现这一点。这将把模型的架构保存为JSON字符串。如果我们把字符串打印出来,我们就能确切地看到它是什么样子。

json_string = model.to_json()
json_string


现在我们已经保存了它,我们可以从中创建一个新模型。首先,我们将从model_from_json函数导入所需的模型,然后我们可以加载模型架构。

from tensorflow.keras.models import model_from_json
model_architecture = model_from_json(json_string)

保存模型结构的另外一种方法是使用to_yaml()函数,然后通过model_from_yaml()加载保存到饿模型。使用的方式和上面的方法一样。
保存模型的权重

model.save_weights('models/my_model_weights.h5')

如果要加载模型的权值,就需要我新建立的模型与原来的模型的结构一样。

model2 = Sequential([
    Dense(units=16, input_shape=(1,), activation='relu'),
    Dense(units=32, activation='relu'),
    Dense(units=2, activation='softmax')
])

model2.load_weights('models/my_model_weights.h5')

以上是关于TensorFlow基本使用的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow:简单的循环神经网络

吴裕雄 python 神经网络——TensorFlow 数据集基本使用方法

tensorflow搭建神经网络基本流程

tensorflow 基础: 神经网络基本框架

带你使用 TensorFlow 进行机器学习研究

MNIST实例-Tensorflow 初体验