Tensorflow(一)神经网络之MLP

498 阅读19分钟

以下内容是在学习过程中的一些笔记,难免会有错误和纰漏的地方。如果造成任何困扰,很抱歉。

介绍

TensorFlow™是一个基于数据流编程(dataflow programming)的符号数学系统,是一个功能强大的开源软件库,它由Google的布莱恩(Brain)团队开发,被广泛应用于各类机器学习(machine learning)算法的编程实现,其前身是谷歌的神经网络算法库DistBelief。

而它也是使用人数最多的深度学习框架,所谓深度学习就是一个函数集,,通过使用一个函数集来执行多次矩阵相乘的非线性转换运算。

深度学习使用的神经网络叫深度神经网络,其中的隐藏层可能有很多层,其中一届的冠军模型高达150层。基本上,神经网络只需要拥有两层隐藏层,加上输出层和输入层,共计4层,就可以称作深度神经网络,即所谓的深度学习。

而我们常说,深度学习其实是一个数学模型,而对于这种数学模型有几个概念需要了解

  • 向量:也称作矢量,具有大小值和方向性的数学表现,程序中使用一维数组表示。
  • 矩阵:将纯数值排列成二维表格的行和列形状,程序中使用二维数组方式来表示;
  • 张量:不同大小维度,也称为轴的多维数组,如(样本数,特征1,特征2,.....);
  • 微分:目的是求瞬间的变化量,例如照相机的拍照瞬间就是一个变化量;
  • 偏微分:对于多变量的函数,我们可以对多变量进行微分(x,y),这种方式称为偏微分;

总结上述,零维张量就是纯量值;一维张量就是向量,即一个维度的一维数组;二维张量就是矩阵,即维度为2的数组;四维张量就是4个维度的四维数组,例如特征数据图片(样本数,高度,色彩数,宽度)。

接下来聊聊对TensorFlow基础架构组成

对于Estimator来说,它是一个高度封装的API,简化开发者的使用,内有许多封装好的、可以直接使用的分类及回归模型。

而其中高阶API接口Keras是由Python编写的高阶深度学习API,它主要面向与用户快速开发,而Keras作为TensorFlow的前端,屏蔽了底层较为难以理解的算法实现,对用户友好,允许简单而快速的原型设计。

介绍的最后我们对神经网络做一个介绍与分类:

一、API使用方法

API地址
Module: tf | TensorFlow v2.11.0 (google.cn)

打开官网,从API文档中看到许多方法,我们常用的方法参数有:

  • activation - 激活函数,一般用relu;
  • kernel_initializer / bias_initializer - 权重与偏置参数的初始化方法;
  • kernel_regularizer / bias_regularizer - 正则化惩罚项;
  • inputs - 输入,可以自己指定,也可以让网络自动选择;
  • units - 神经元个数;

如数据集的方法:

tf.keras.Sequential线性模型的导入和使用方法

损失函数的方法介绍,开辟新大陆

常用的优化器

所有的API不可能会一个个的介绍完,所以我们将在后续案例,一边学一边翻阅API。

二、多层感知器 - MLP

MLP可用于回归任务,MLP也可以用于分类任务:

  • 如果要预测单个值(房屋的价格,给定其许多特征),则只需要单个输出神经元:其输出就是预测值。对于多元回归(即一次预测多个值),每个输出维度需要一个输出神经元。
  • 对于二进制分类问题,你只需要使用逻辑激活函数的单个输出神经元:输出将是0到1之间的数字,你可以将其解释为正类的估计概率。负类别的估计概率等于一减去该数字。

如果从代码上看

下面这个案例,实际上是一个多元线性回归模型,自变量(输入)有三个

  • TV
  • Radio
  • Newspaper

因变量(输出)则是一个

  • sales

他们之间呈线性关系,接下来看看数据集

代码示例

import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 加载数据
data = pd.read_csv(
    'E:/27_Python_Protect/02_ml/01-识别手写数字/hello02.csv'
)

# 查看是否呈现一种线性关系 图
# plt.scatter(data.TV, data.sales)
# plt.show()

# python的一种范围切割
x = data.iloc[:, 0:-1]
y = data.iloc[:, -1:]

# 导入Sequential模型
model = tf.keras.Sequential(
    [
        # 输出维度10 输入维度3 激活函数relu
        tf.keras.layers.Dense(10, input_shape=(3,), activation='relu'),
        # 最终输出层
        tf.keras.layers.Dense(1)
    ]
)

# 模型详情
# print(model.summary())

# 模型的优化方法 损失函数选择
model.compile(
    optimizer='adam',
    loss='mse'
)

# 记录训练过程 epochs:训练次数
# 训练过程中 loss值会不断下降直到无限逼近
history = model.fit(x, y, epochs=10000)

# 预测范围 前10行前3列
prediction_data_set = data.iloc[:10, 0:-1]

# 进行预测 连续值x 预测y
preTemp = model.predict(prediction_data_set)

print("结果是 = ", preTemp)

2.1 案例:服饰图像分类识别

此Tensorflow官方案例是机器学习中的Hello World,将训练一个神经网络模型,对运动鞋和衬衫等服装图像进行分类,通过Tensorflow及KerasAPI对图像分类识别有一个基本认知。

首先导入相关的类库和数据集

# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

# 数据集导入
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

该数据集包含 10 个类别的 70,000 个灰度图像。这些图像以低分辨率(28x28 像素)展示了单件衣物

加载数据集会返回四个 NumPy 数组:

  • train_imagestrain_labels 数组是训练集,即模型用于学习的数据;
  • 测试集test_imagestest_labels 数组会被用来对模型进行测试;

我们针对这些标签进行一个简单的分类

# 将图像的标签分类
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
标签
0T恤/上衣
1裤子
2套头衫
3连衣裙
4外套
5凉鞋
6衬衫
7运动鞋
8
9短靴
# 浏览数据集
print(train_images.shape)
print(len(train_labels))
print(train_labels)

预处理数据 此时展示的是图像原始像素大小

# 预处理数据 此时展示的是图像原始像素大小
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()

需要将这些值缩小至0到1之间,然后将其馈送到神经网络模型

# 将这些值缩小至0到1之间 然后将其馈送到神经网络模型
train_images = train_images / 255.0
test_images = test_images / 255.0

# 验证数据的格式是否正确
plt.figure(figsize=(10, 10))
for i in range(25):
    plt.subplot(5, 5, i + 1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
plt.show()

然后进行模型构建及训练,构建神经网络前

  1. 配置模型的层;
  2. 编译模型;
# 构建模型 -- 设置层
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10)
])

第一层网络:keras.layers.Flatten,将图像格式从二维数组(28 x 28 像素)转换成一维数组(28 x 28 = 784 像素)。将该层视为图像中未堆叠的像素行并将其排列起来。

第二、三层网络:keras.layers.Dense,两层神经元序列。

# 编译模型
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

# 训练模型
model.fit(train_images, train_labels, epochs=10)

# 评估准确率
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print('\n 评估准确率 Test accuracy:', test_acc)

通过构建模型实现单图预测

probability_model = tf.keras.Sequential([model,
                                         tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)

# 效果查看
predictions[0]
test_labels[0]

注入绘制图像的方法更加直观的展示预测结果

# 图表绘制方法
def plot_image(i, predictions_array, true_label, img):
    predictions_array, true_label, img = predictions_array, true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img, cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'

    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                         100 * np.max(predictions_array),
                                         class_names[true_label]),
               color=color)


def plot_value_array(i, predictions_array, true_label):
    predictions_array, true_label = predictions_array, true_label[i]
    plt.grid(False)
    plt.xticks(range(10))
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1])
    predicted_label = np.argmax(predictions_array)

    thisplot[predicted_label].set_color('red')
    thisplot[true_label].set_color('blue')


# 验证预测结果1
# i = 1
# plt.figure(figsize=(6, 3))
# plt.subplot(1, 2, 1)
# plot_image(i, predictions[i], test_labels, test_images)
# plt.subplot(1, 2, 2)
# plot_value_array(i, predictions[i], test_labels)
# plt.show()

# 用模型的预测绘制几张图像
# Plot the first X test images, their predicted labels, and the true labels.
# Color correct predictions in blue and incorrect predictions in red.
num_rows = 5
num_cols = 3
num_images = num_rows * num_cols
plt.figure(figsize=(2 * 2 * num_cols, 2 * num_rows))
for i in range(num_images):
    plt.subplot(num_rows, 2 * num_cols, 2 * i + 1)
    plot_image(i, predictions[i], test_labels, test_images)
    plt.subplot(num_rows, 2 * num_cols, 2 * i + 2)
    plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

完整代码

# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

# 数据集导入 图像与标签 训练集与测试集
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

# 将图像的标签分类
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

# 将这些值缩小至0到1之间 然后将其馈送到神经网络模型
train_images = train_images / 255.0
test_images = test_images / 255.0

# 构建模型 -- 设置层
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10)
])

# 编译模型
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

# 训练模型
model.fit(train_images, train_labels, epochs=10)

# 评估准确率
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print('\n 评估准确率 Test accuracy:', test_acc)

# 预测
probability_model = tf.keras.Sequential([model,
                                         tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)


# 效果查看
# predictions[0]
# test_labels[0]

# 图表绘制方法
def plot_image(i, predictions_array, true_label, img):
    predictions_array, true_label, img = predictions_array, true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img, cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'

    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                         100 * np.max(predictions_array),
                                         class_names[true_label]),
               color=color)


def plot_value_array(i, predictions_array, true_label):
    predictions_array, true_label = predictions_array, true_label[i]
    plt.grid(False)
    plt.xticks(range(10))
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1])
    predicted_label = np.argmax(predictions_array)

    thisplot[predicted_label].set_color('red')
    thisplot[true_label].set_color('blue')


# 验证预测结果1
# i = 1
# plt.figure(figsize=(6, 3))
# plt.subplot(1, 2, 1)
# plot_image(i, predictions[i], test_labels, test_images)
# plt.subplot(1, 2, 2)
# plot_value_array(i, predictions[i], test_labels)
# plt.show()

# 用模型的预测绘制几张图像
# Plot the first X test images, their predicted labels, and the true labels.
# Color correct predictions in blue and incorrect predictions in red.
num_rows = 5
num_cols = 3
num_images = num_rows * num_cols
plt.figure(figsize=(2 * 2 * num_cols, 2 * num_rows))
for i in range(num_images):
    plt.subplot(num_rows, 2 * num_cols, 2 * i + 1)
    plot_image(i, predictions[i], test_labels, test_images)
    plt.subplot(num_rows, 2 * num_cols, 2 * i + 2)
    plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

2.2 线性不可分问题

什么是线性不可分(XOR)?——不能用一条线将数据分成两类的问题。而多层感知器是如何解决的?通过神经网络,构建层与神经元进行划分。

上述神经网络的每一层神经层,其每一个顶点都会链接下一层的所有顶点,成为全连接。输出的神经元(感知器)数量视结果和解决的问题而定,例如数字识别0-9,就需要输出10个,因为有10个类别。

神经网络的构建最大的问题在于隐藏层,我们需要决定有几个隐藏层以及每一层有多少个神经元,一般情况下会视问题和数据集情况而定,有一些准则可以参考:

  • 每一个隐藏层的神经元数量建议一致;
  • 隐藏层的神经元位于输入层和输出层之间;
  • 隐藏层的神经元数量应该是2/3输入层的神经元数量再加上输出层的神经元数;
  • 隐藏层的神经元数量应该少于2倍的输入层神经元数量;

2.3 神经网络的学习过程

神经网络的学习目标就是找出正确的权重值来缩小损失(Loss,实际值与预测值之前的差距)

神经网络的输入值X,在经过每一层 f(wx+b) 数据转换的计算后,可以得到预测值Y:

  • 通过损失函数(Loss Fun),计算预测值与目标值之间差异的损失分数。
  • 通过优化器(Optimizer),更新权重,以便于缩小预测值与目标值之间的差异。
  • 神经网络会自行使用数据来自我训练,形成训练循环,也叫迭代,直到训练出最优的预测模型为止。

在神经网络的训练循环中分为正向传播评诂损失反向传播三个阶段,此时我们可以看一段代码:

model.fit(train_images, train_labels, epochs=10)

其中Tensorflow的epochs代表着训练迭代次数,不断地重复执行下面的这张图上的操作

但是,也并不是越多次的训练循环就能训练出最佳的预测模型,其中会发生以下几种情况

泛化性是指预测模型对于未知而且从来没有看过的数据也能够有很好的预测性。

2.4 激活函数

从激活一词看出,这个函数在某个特定条件下才会被激活使用,通过设置单独的激活层实现,也可以在构造层对象时通过传递 activation 参数实现。

# 导入Sequential模型
model = tf.keras.Sequential(
    [
        # 输出维度10 输入维度3 激活函数relu
        tf.keras.layers.Dense(10, input_shape=(3,), activation='relu'),
        # 最终输出层
        tf.keras.layers.Dense(1)
    ]
)

对神经网络的神经元使用激活函数,是为了让神经元可以执行非线性的数据转换,例如,年龄和体重可能是线性关系,但是收入和体重并不是线性关系。

常用的激活函数如下:

  • 隐藏层:ReLU()
  • 输出层:Sigmoid()--二元分类、Tanh()--二元分类、Softmax()--多元分类

接下来简单描述常用的激活函数

  1. ReLU - 输入小于0啧输出0,输入大于0则为线性函数直接输出输入值;
  2. Sigmoid - 将数据转换为0-1的概率;
  3. Tanh - 三角函数,输出范围是-1到1;
  4. Softmax - 将输入值转换为0-1的实数;

2.5 损失函数

地址
机器学习算法中的7个损失函数的详细指南 (baidu.com)

损失函数(或称目标函数、优化评分函数)是编译模型时所需的两个参数之一,损失函数越小,表示预测的模型越好。

# 可以这样
model.compile(
    optimizer='adam',
    loss='mse'
)

# 还可以这样
model.compile(loss='mean_squared_error', optimizer='sgd')

# 还能这样
from keras import losses
model.compile(loss=losses.mean_squared_error, optimizer='sgd')

一般回归问题经常使用均方误差(MSE),分类问题使用交叉熵(Cross-Entropy)。

2.6 Keras深度学习模型

Keras是由Python编写的高阶深度学习API,它主要面向与用户快速开发,而Keras作为TensorFlow的前端,屏蔽了底层较为难以理解的算法实现,对用户友好,允许简单而快速的原型设计。

模型是Keras函数库的核心数据结构,其中支持的两种模型:

  • Sequential

    线性堆栈模型,单一输入与输出,每一层接着下一层,不允许跨层,调用add()新增神经层。

  • Functional API

    如果是复杂的多输入和多输出,或者拥有共享神经层的深度学习模型,则使用这个。Sequential模型就是Functional API的一种特殊情况。

Keras的Sequential模型是一个容器,将各种Keras预建神经层类型依次新增到模型里:

  1. 多层感知器 - MLP,新增一个或多个Dense;
  2. 卷积神经网络 - CNN,新增一或多组Conv2D和Pooling层后,即可新增Dropout\Flatten\Dense层来创建卷积神经网络;
  3. 循环神经网络 - RNN,使用SimpleRNN\LSTM\GRU创建神经网络;

2.7 案例:糖尿病预测(一)

查看数据集

上述有9个字段,前面8个是对病情属性的描述,最后一个字段是得出的结论,1是有病,0是没病。

先上源代码

import numpy as np
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense

# 载入糖尿病数据集
df = pd.read_csv("./diabetes.csv")
dataset = df.values

# 分割成输入的训练数据和标签数据
X = dataset[:, 0:8]
Y = dataset[:, 8]

# 定义模型 因为最终的结果是二元分类问题 所以使用sigmoid函数
model = Sequential()
# 这个10是输出维度
# (8,)代表输入形状 使用x个样本数、8个特征数
model.add(Dense(10, input_shape=(8,), activation="relu"))
model.add(Dense(8, activation="relu"))
model.add(Dense(1, activation="sigmoid"))

# 显示模型摘要信息
if (1 == 1):
    model.summary()
    exit(0)

# 编译模型
model.compile(loss="binary_crossentropy", optimizer="sgd",
              metrics=["accuracy"])
# 训练模型
history = model.fit(X, Y, epochs=1500, batch_size=100)

# 评估模型
loss, accuracy = model.evaluate(X, Y)
print("准确度 = {:.2f}".format(accuracy))

在模型编译阶段,有一套激活函数对应损失函数的基本标准,并且其中还有优化器和评估标准,关于这些的描述在“神经网络的学习过程“章节有进行描述。

问题种类输出层激活函数损失函数
二分类sigmoidbinary_crossentropy
单标签多分类softmaxcategorical_crossentropy
多标签多分类sigmoidbinary_crossentropy
回归分析不需要mse
回归值为0-1sigmoidmse 或 binary_crossentropy

2.8 案例:糖尿病预测(二)

我们对上一节的内容进行优化,步骤总结如下

  1. 特征标准化

    # 分割成输入的训练数据和标签数据
    X = dataset[:, 0:8]
    Y = dataset[:, 8]
    
    # 特征标准化 - 数据集各字段值的范围差距过大故进行的调整
    # 将数据减掉mean函数的平均之后 再除以std函数的标准差 最后得到特征数据值平均值为0且标准差为1的数据分布
    X -= X.mean(axis=0)
    X /= X.std(axis=0)
    
  2. 输出层替换激活函数

    1之前的输出层只有一个神经元,所以用sigmoid函数,现在改成两个神经元,标签数据也需要执行One-hot编码

    # One-hot编码
    Y = to_categorical(Y)
    
    model.add(Dense(10, input_shape=(8,), activation="relu"))
    model.add(Dense(8, activation="relu"))
    # model.add(Dense(1, activation="sigmoid"))
    model.add(Dense(2, activation="softmax"))
    
  3. 训练循环开始时神经层使用权重初始化

    • kernel_initializer:初始化神经层的权重矩阵
    • bias_initializer:初始化偏移量的值
    model = Sequential()
    model.add(Dense(10, input_shape=(8,),
                    kernel_initializer="random_uniform",
                    bias_initializer="ones",
                    activation="relu"))
    model.add(Dense(8, kernel_initializer="random_uniform",
                    bias_initializer="ones",
                    activation="relu"))
    model.add(Dense(2, kernel_initializer="random_uniform",
                    bias_initializer="ones",
                    activation="softmax"))
    

    接下来对其中的参数进行说明

    初始化参数说明
    zeros全部初始为0
    ones全部初始为1
    XXXX_normal正态分布的随机数,可以是random_normal或其它
    XXXX_uniform均匀分布的随机数,可以是random_uniform或其它
  4. 编译模型替换优化器

    优化器实际上就是各种改良版的梯度下降法,现在将optimizer="sgd"修改为更好的optimizer="adam",如下

    model.compile(loss="binary_crossentropy", optimizer="adam",
                  metrics=["accuracy"])
    

    除了上述的两种优化器,还有一种rmsprop优化器,是循环神经网络的最佳选择之一。

  5. 减少神经网络参数量

    说白了就是减少了神经元的个数,因为数据不多。

    model = Sequential()
    model.add(Dense(10, input_shape=(8,), activation="relu"))
    model.add(Dense(6, activation="relu"))
    model.add(Dense(2, activation="softmax"))
    
  6. 数据集的自动分割 - validation_split

2.9 模型的存储与载入

完成神经网络训练以后,我们可以存储神经网络的模型和权重,其中包含了后面要学习的两个概念:

  • 迁移学习
  • 预训练模型库

程序可以直接载入神经网络模型与权重来进行预测,不用每次花时间重新训练模型。

模型存储

两种方式

  1. 分开存储模型与权重

    # 分开存储模型结构与权重
    json_str = model.to_json()
    with open("model_c.config", "w") as text_file:
        # 存储结构
        text_file.write(json_str)
    
    # 存储权重
    model.save_weights("model_w.weight")
    

    此时会产生三个文件:

    ​ model_w.weight.data-00000-of-00001

    ​ model_w.weight.index

    ​ model_c.config

  2. 同时存储模型与权重

    # 同时存储模型结构与权重
    model.save("model_file_all.h5")
    

    此时会生成一个文件:model_file_all.h5

模型载入

依旧是两种方式

  1. 分开载入模型与权重

    from keras.saving.model_config import model_from_json
    
    model = Sequential()
    
    with open("model_c.config", "r") as text_file:
        json_str = text_file.read()
    model = model_from_json(json_str)
    model.load_weights("model_w.weight", by_name=False)
    
    # 显示模型摘要信息
    model.summary()
    
  2. 同时载入模型与权重

    from keras.saving.save import load_model
    
    model = Sequential()
    model = load_model("model_file_all.h5")
    # 显示模型摘要信息
    model.summary()
    

载入后,都需要调用model.compile函数编译模型,才可以评估模型和计算预测值。

2.10 案例:波士顿房价预测

载入数据,查看特征及数量

import pandas as pd

dataset = pd.read_csv("boston_housing.csv")
# print(dataset.head()) # 显示前5条记录
# print(dataset.shape)  # 显示数据集中有多少条记录以及多少列字段

数据量少的时候,可以对数据集采用交叉验证的思路。

什么是K-fold交叉验证?

先将数据集划分为K个大小相似的互斥子集,每个子集尽可能保证数据分布的一致性,每次使用 k-1 个子集的并集作为训练集,剩下的子集作为测试集。

k最常用的取值是10,上述成为10折交叉验证。

首先是第一次的代码建设

import numpy as np
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense

#  载入波士顿房屋数据集
df = pd.read_csv("./boston_housing.csv")
dataset = df.values

np.random.seed(7)  # 指定乱数种子
np.random.shuffle(dataset)  # 用乱数打乱数据

# 分割成特征数据和标签数据
X = dataset[:, 0:13]
Y = dataset[:, 13]

#  特征标准化
X -= X.mean(axis=0)
X /= X.std(axis=0)

# 分割训练和测试数据集
X_train, Y_train = X[:404], Y[:404]  # 训练数据前404条
X_test, Y_test = X[404:], Y[404:]  # 测试数据后 102条


# 定义模型
def build_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
    model.add(Dense(1))
    # 编译模型
    model.compile(loss="mse", optimizer="adam",
                  metrics=["mae"])
    return model


# K-fold交叉验证
k = 4
nb_val_samples = len(X_train) // k
nb_epochs = 8000
mse_scores = []
mae_scores = []
for i in range(k):
    print("Processing Fold #" + str(i))
    # 取出验证数据集
    X_val = X_train[i * nb_val_samples: (i + 1) * nb_val_samples]
    Y_val = Y_train[i * nb_val_samples: (i + 1) * nb_val_samples]
    # 结合出训练数据集
    X_train_p = np.concatenate(
        [X_train[:i * nb_val_samples],
         X_train[(i + 1) * nb_val_samples:]], axis=0)
    Y_train_p = np.concatenate(
        [Y_train[:i * nb_val_samples],
         Y_train[(i + 1) * nb_val_samples:]], axis=0)
    model = build_model()
    # 训练模型
    model.fit(X_train_p, Y_train_p, epochs=nb_epochs,
              batch_size=16, verbose=0)
    # 评估模型
    mse, mae = model.evaluate(X_val, Y_val)
    mse_scores.append(mse)
    mae_scores.append(mae)

print("MSE_val: ", np.mean(mse_scores))
print("MAE_val: ", np.mean(mae_scores))

# 使用测试数据评估模型
mse, mae = model.evaluate(X_test, Y_test)
print("MSE_test: ", mse)
print("MAE_test: ", mae)

我们对上述产生的误差还是不能满足,接下来是模型调优,将上述的神经网络增加到4层的深度

# 定义模型
def build_deep_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
    model.add(Dense(16, activation="relu"))
    model.add(Dense(1))
    #  编译模型
    model.compile(loss="mse", optimizer="adam", 
                  metrics=["mae"])
    return model

查看结果,误差得到了改善,接下来将数据集(不存在数据集分割)全部投入训练,首先改变隐藏层的神经元数量

# 定义模型
def build_deep_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
    model.add(Dense(32, activation="relu"))
    model.add(Dense(1))
    #  编译模型
    model.compile(loss="mse", optimizer="adam", 
                  metrics=["mae"])
    return model

省略代码:所有数据集投入训练

2.11 案例:鸢尾花多元分类

首先查看数据集

从结果看,输出的结果有三种,多元分类问题实锤,上代码

import numpy as np
import pandas as pd
from keras.layers import Dense
from keras.models import Sequential
from keras.utils import to_categorical
from keras.models import load_model

# 对target做一个键值对映射
target_mapping = {"setosa": 0,
                  "versicolor": 1,
                  "virginica": 2}

# 载入数据集
df = pd.read_csv("./iris_data.csv")
df["target"] = df["target"].map(target_mapping)
dataset = df.values

np.random.seed(7)  # 指定乱数种子
np.random.shuffle(dataset)  # 使用乱数打乱资料

# 分割成特征数据和标签数据
X = dataset[:, 0:4].astype(float)
Y = to_categorical(dataset[:, 4])

# 特征标准化
X -= X.mean(axis=0)
X /= X.std(axis=0)

# 分割成训练和测试数据集
X_train, Y_train = X[:120], Y[:120]  # 训练数据前120条
X_test, Y_test = X[120:], Y[120:]  # 测试数据后30条

# 建立Keras的Sequential模型
model = Sequential()
model.add(Dense(6, input_shape=(4,), activation="relu"))
model.add(Dense(6, activation="relu"))
model.add(Dense(3, activation="softmax"))
model.summary()  # 显示模型摘要

# 编译模型
model.compile(loss="categorical_crossentropy", optimizer="adam",
              metrics=["accuracy"])

# 模型训练
model.fit(X_train, Y_train, epochs=1000,
          batch_size=100, verbose=0)

# 评估模型
print("\n Testing ...")
loss, accuracy = model.evaluate(X_test, Y_test)
print("测试数据集的准确度  = {:.2f}".format(accuracy))

# 计算分类的预测值
print("\n 计算分类的预测值 Predicting ...")
# Y_pred = model.predict_classes(X_test)
# Tensorflow 2.6 版本 删除了predict_classes() 这个函数
predict_x = model.predict(X_test)
Y_pred = np.argmax(predict_x, axis=1)
print("Y_pred = ",Y_pred)

Y_target = dataset[:, 4][120:].astype(int)
print("Y_target = ",Y_target)

# 显示混淆矩阵
# 第一个参数为真实标签值,第二个参数是预测值,rownames参数是行名称,colnames是列名称
print("\n 显示混淆矩阵:")
tb = pd.crosstab(Y_target, Y_pred, rownames=["label"], colnames=["predict"])
print(tb)

所谓混淆矩阵,是一个二维矩阵,可以用来评估分类结果的分析表,上述案例中得到的矩阵结果为:

label012
0900
10120
2018

另外对于Keras中predict()方法和predict_classes()方法,由于上述案例使用的Tensorflow版本过高,所以使用了model.predict()做转换, 当使用predict()方法进行预测时,返回值是数值,表示样本属于每一个类别的概率,我们可以使用numpy.argmax()方法找到样本以最大概率所属的类别作为样本的预测标签。

三、One-hot编码

地址
one-hot编码_躺平yyds的博客-CSDN博客_one-hot编码

结尾:

地址
主页 - Keras 中文文档 (keras-zh.readthedocs.io)
关于TensorFlow | TensorFlow中文官网 (google.cn)