政安晨:【示例演绎机器学习】(二)—— 神经网络的二分类问题示例 (影评分类)

政安晨的个人主页:政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏: 政安晨的机器学习笔记

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正,让小伙伴们一起学习、交流进步!

作者对人工智能领域的机器学习方面的知识,一直是倾向于采用演绎的方式为大家讲解,今后也会继续采用这类方式。


简述

在人工智能机器学习领域中,神经网络是一种模拟人类神经系统的算法模型。它由许多互相连接的人工神经元组成,可以用于分类和回归任务。

神经网络的分类是指将输入数据映射到不同的类别中。在训练过程中,神经网络通过调整连接权重和激活函数的参数,学习如何将输入数据映射到正确的类别。常见的神经网络分类模型包括多层感知机(MLP),卷积神经网络(CNN),循环神经网络(RNN)等。

神经网络的回归是指将输入数据映射到连续的数值或函数。与分类不同,回归任务需要输出连续的数值或函数来拟合数据。在回归任务中,神经网络通过训练来学习数据的非线性模式,并预测出准确的连续数值。常见的神经网络回归模型包括前馈神经网络(Feedforward Neural Network),循环神经网络(RNN),长短期记忆网络(LSTM)等。

总的来说,神经网络在人工智能机器学习中既能用于分类任务,将输入数据映射到不同的类别,也能用于回归任务,将输入数据映射到连续的数值或函数。

通过训练,神经网络可以学习数据的非线性模式,并在未知数据上进行准确的分类或回归预测。

分类和回归术语表

分类和回归都涉及许多专业术语,这些术语在机器学习领域都有确切的定义,你应该熟悉这些定义:

样本(sample)或输入(input)进入模型的数据点。

预测(prediction)或输出(output)模型的输出结果。

目标(target)真实值。对于外部数据源,理想情况下模型应该能够预测出目标。

预测误差(prediction error)或损失值(loss value)模型预测与目标之间的差距。

类别(class)分类问题中可供选择的一组标签。举例来说,对猫狗图片进行分类时,“猫”和“狗”就是两个类别。

标签(label)分类问题中类别标注的具体实例。如果1234号图片被标注为包含类别“狗”,那么“狗”就是1234号图片的标签。

真实值(ground-truth)或标注(annotation)数据集的所有目标,通常由人工收集。

二分类(binary classification)一项分类任务,每个输入样本都应被划分到两个互斥的类别中。

多分类(multiclass classification)一项分类任务,每个输入样本都应被划分到两个以上的类别中,比如手写数字分类。

多标签分类(multilabel classification)一项分类任务,每个输入样本都可以被分配多个标签。举个例子,一张图片中可能既有猫又有狗,那么应该同时被标注“猫”标签和“狗”标签。每张图片的标签个数通常是可变的。

标量回归(scalar regression)目标是一个连续标量值的任务。预测房价就是一个很好的例子,不同的目标价格形成一个连续空间。

向量回归(vector regression)目标是一组连续值(比如一个连续向量)的任务。如果对多个值(比如图像边界框的坐标)进行回归,那就是向量回归。

小批量(mini-batch)或批量(batch)模型同时处理的一小部分样本(样本数通常在8和128之间)。样本数通常取2的幂,这样便于在GPU上分配内存。训练时,小批量用于计算一次梯度下降,以更新模型权重。

影评分类:二分类问题示例

二分类问题是最常见的一类机器学习问题,在本例中,你将学习如何根据影评文本将其划分为正面或负面。

咱们使用某个电影数据库的数据集来进行接下来的演绎。

电影数据集

咱们使用IMDB数据集,它包含来自互联网电影数据库的50 000条严重两极化的评论。

数据集被分为25 000条用于训练的评论与25 000条用于测试的评论,训练集和测试集都包含50%的正面评论与50%的负面评论。

与以前咱们演绎过的MNIST数据集一样,该数据集也已经内置于Keras库中。

它已经过预处理:评论(单词序列)已被转换为整数序列,其中每个整数对应字典中的某个单词。这样一来,我们就可以专注于模型的构建、训练与评估。

咱们准备好环境后,开始接下来的演绎。(Conda虚拟环境、Jupyter Notebook等)

第一次看到这里的小伙伴可以看一下我这个专栏:

政安晨的机器学习笔记icon-default.png?t=N7T8http://t.csdnimg.cn/VYj8N

里面有搭建环境的部分。

现在咱们加载数据集,代码如下:

from tensorflow.keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(
    num_words=10000)

演绎:

参数num_words=10000的意思是仅保留训练数据中前10 000个最常出现的单词,低频词将被舍弃。这样一来,我们得到的向量数据不会太大,便于处理。如果没有这个限制,那么我们需要处理训练数据中的88 585个单词。这个数字太大,且没有必要。许多单词只出现在一个样本中,它们对于分类是没有意义的。

train_data和test_data这两个变量都是由评论组成的列表,每条评论又是由单词索引组成的列表(表示单词序列)。train_labels和test_labels都是由0和1组成的列表,其中0代表负面(negative)1代表正面(positive)

 

由于限定为前10 000个最常出现的单词,因此单词索引都不会超过10 000。

下面的代码可以让您将一条评论快速解码为英文单词:

# word_index是一个将单词映射为整数索引的字典
word_index = imdb.get_word_index() 

reverse_word_index = dict(

    # 将字典的键和值交换,将整数索引映射为单词
    [(value, key) for (key, value) in word_index.items()])

decoded_review = " ".join(
    [reverse_word_index.get(i - 3, "?") for i in train_data[0]])
    #  ←----对评论解码。注意,索引减去了3,因为0、1、2分别是为“padding”(填充)、“start of sequence”(序列开始)、“unknown”(未知词)保留的索引

演绎如下:

准备数据

你不能将整数列表直接传入神经网络。

整数列表的长度各不相同,但神经网络处理的是大小相同的数据批量。你需要将列表转换为张量,转换方法有以下两种:

填充列表,使其长度相等,再将列表转换成形状为(samples, max_length)的整数张量,然后在模型第一层使用能处理这种整数张量的层(也就是Embedding层)。

对列表进行multi-hot编码,将其转换为由0和1组成的向量。

举个例子,将序列[8,5]转换成一个10 000维向量,只有索引8和5对应的元素是1,其余元素都是0。然后,模型第一层可以用Dense层,它能够处理浮点数向量数据。

下面我们采用后一种方法将数据向量化。

为尽可能讲清楚,咱们将手动实现这一方法:

如下代码(用multi-hot编码对整数序列进行编码):

import numpy as np
def vectorize_sequences(sequences, dimension=10000):

    # 创建一个形状为(len(sequences), dimension)的零矩阵
    results = np.zeros((len(sequences), dimension))

    for i, sequence in enumerate(sequences):
        for j in sequence:

            # 将results[i]某些索引对应的值设为1
            results[i, j] = 1.

    return results

# 将训练数据向量化
x_train = vectorize_sequences(train_data)

# 将测试数据向量化
x_test = vectorize_sequences(test_data)

你还应该将标签向量化,这很简单:

y_train = np.asarray(train_labels).astype("float32")
y_test = np.asarray(test_labels).astype("float32")

至此,数据可以传入神经网络中了。

构建模型

输入数据是向量,而标签是标量(1和0),这是你会遇到的最简单的一类问题。有一类模型在这种问题上的表现很好,那就是带有relu激活函数的密集连接层(Dense)的简单堆叠。

对于Dense层的这种堆叠,需要做出以下两个关键的架构决策:

神经网络有多少层

每层有多少个单元

架构的选择有很多“讲究”,这个咱们以后细聊,现在您只需要相信我选择的下列架构是合适的即可:

两个中间层,每层16个单元,第三层输出一个标量预测值,代表当前评论的情感类别。

以下是该模型的架构示意图:

模型定义:

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dense(16, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])

传入每个Dense层的第一个参数是该层的单元(unit)个数,即该层表示空间的维数。同时,每个带有relu激活函数的Dense层都实现了下列张量运算:

output = relu(dot(input, W) + b)

16个单元对应的权重矩阵W的形状为(input_dimension, 16),与W做点积相当于把输入数据投影到16维表示空间中(然后再加上偏置向量b并应用relu运算)。

你可以将表示空间的维度直观理解为“模型学习内部表示时所拥有的自由度”。

单元越多(表示空间的维度越高),模型就能学到更加复杂的表示,但模型的计算代价也变得更大,并可能导致学到不必要的模式(这种模式可以提高在训练数据上的性能,但不会提高在测试数据上的性能)。

中间层使用relu作为激活函数,最后一层使用sigmoid激活函数,以便输出一个介于0和1之间的概率值(表示样本目标值等于“1”的可能性,即评论为正面的可能性)。

relu函数将所有负值归零(见下图):

sigmoid函数则将任意值“压缩”到[0, 1]区间内(见下图),其输出可以看作概率值:

什么是激活函数?为什么要使用激活函数?

如果没有像relu这样的激活函数(也叫非线性激活函数),Dense层就只包含两个线性运算,即点积与加法:

output = dot(input, W) + b

这样的层只能学习输入数据的线性变换(仿射变换)该层的假设空间是从输入数据到16维空间所有可能的线性变换集合。这种假设空间非常受限,无法利用多个表示层的优势,因为多个线性层堆叠实现的仍是线性运算,增加层数并不会扩展假设空间。

为了得到更丰富的假设空间,从而充分利用多层表示的优势,需要引入非线性,也就是添加激活函数。relu是深度学习中最常用的激活函数,但还有许多其他函数可选,它们都有类似的奇怪名称,比如prelu、elu等。

最后,需要选择损失函数和优化器。

你面对的是一个二分类问题,模型输出是一个概率值(模型最后一层只有一个单元并使用sigmoid激活函数),所以最好使用binary_crossentropy(二元交叉熵)损失函数。这并不是唯一可行的选择,比如你还可以使用mean_squared_error(均方误差)

但对于输出概率值的模型,交叉熵(crossentropy)通常是最佳选择。交叉熵是一个来自于信息论领域的概念,用于衡量概率分布之间的距离,在这个例子中就是真实分布与预测值之间的距离。

至于优化器,我们将使用rmsprop。对于几乎所有问题,它通常都是很好的默认选择。

接下来的步骤是用rmsprop优化器和binary_crossentropy损失函数来配置模型,另外注意,咱们还在训练过程中监控精度

编译模型

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

模型编译完毕:

验证方法

深度学习模型不应该在训练数据上进行评估

标准做法是使用验证集来监控训练过程中的模型精度。下面我们将从原始训练数据中留出10 000个样本作为验证集,如下代码所示(留出验证集)

x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]

现在我们将使用由512个样本组成的小批量,对模型训练20轮,即对训练数据的所有样本进行20次迭代。与此同时,我们还要监控在留出的10 000个样本上的损失和精度。

可以通过validation_data参数传入验证数据,如下代码所示:

训练模型

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val))

演绎如下:

如果在CPU上运行,那么每轮的时间不到2秒(政安晨用的是CPU版本的TensorFlow,用了好多秒),整个训练过程将在20秒内完成。

每轮结束时会有短暂的停顿,因为模型需要计算在验证集的10 000个样本上的损失和精度。

注意,调用model.fit()返回了一个History对象。这个对象有一个名为history的成员,它是一个字典,包含训练过程中的全部数据。

咱们现在来看一下:

history_dict = history.history
history_dict.keys()

这个字典包含4个条目,分别对应训练过程和验证过程中监控的指标。

咱们将通过Matplotlib进行绘图展示。

下面代码在同一张图上绘制训练损失和验证损失图

import matplotlib.pyplot as plt

history_dict = history.history
loss_values = history_dict["loss"]
val_loss_values = history_dict["val_loss"]
epochs = range(1, len(loss_values) + 1)

# "bo"表示“蓝色圆点”
plt.plot(epochs, loss_values, "bo", label="Training loss")

# "b"表示“蓝色实线”
plt.plot(epochs, val_loss_values, "b", label="Validation loss")

plt.title("Training and validation loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

演绎如下(您的演绎有可能和我的不同):

下面代码在同一张图上绘制训练精度和验证精度图:

# 清空图像
plt.clf()

acc = history_dict["accuracy"]
val_acc = history_dict["val_accuracy"]
plt.plot(epochs, acc, "bo", label="Training acc")
plt.plot(epochs, val_acc, "b", label="Validation acc")
plt.title("Training and validation accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

演绎如下:

如你所见,训练损失每轮都在减小,训练精度每轮都在提高。

这正是梯度下降优化的预期结果——我们想要最小化的量随着每次迭代变得越来越小。

但验证损失和验证精度并非如此,它们似乎在第4轮达到峰值。这正是我之前警告过的一种情况:模型在训练数据上的表现越来越好,但在前所未见的数据上不一定表现得越来越好。准确地说,这种现象叫作过拟合(overfit):在第4轮之后,你对训练数据过度优化,最终学到的表示仅针对于训练数据,无法泛化到训练集之外的数据。

在这种情况下,为防止过拟合,你可以在4轮之后停止训练。一般来说,你可以用多种方法来降低过拟合(咱们以后有机会介绍

我们从头开始训练一个新模型,训练4轮,然后在测试数据上评估模型

代码如下:

model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dense(16, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
model.fit(x_train, y_train, epochs=4, batch_size=512)
results = model.evaluate(x_test, y_test)

演绎与结果如下:

数字 1 指向显示的数字为测试损失,数字 2 指向显示的是测试精度。

小伙伴们可以看到,这种相当简单的方法得到了约88%的精度,利用最先进的方法,您应该可以得到接近95%的精度。

利用训练好的模型对新数据进行预测

训练好一个模型之后,最好用于实践,可以用predict方法来计算评论为正面的可能性。

如你所见,模型对某些样本的结果非常确信。

(某些样本 大于等于0.99,或小于等于0.01)

结论

通过上面的演绎,可以确信前面选择的神经网络架构是非常合理的,但可能仍旧有空间。

比如,我们在最后的分类层之前使用了两个表示层,可以尝试使用一个或三个表示层,然后观察这么做对验证精度和测试精度的影响。尝试使用更多或更少的单元,比如32个或64个。尝试使用mse损失函数代替binary_crossentropy。尝试使用tanh激活函数(这种激活函数在神经网络早期非常流行)代替relu。

这样咱们知道:

通常需要对原始数据进行大量预处理,以便将其转换为张量输入到神经网络中。

单词序列可以被编码为二进制向量,但也有其他编码方式。

带有relu激活函数的Dense层堆叠,可以解决很多问题(包括情感分类)。

你可能会经常用到这种模型。对于二分类问题(两个输出类别),模型的最后一层应该是只有一个单元并使用sigmoid激活函数的Dense层,模型输出应该是一个0到1的标量,表示概率值。

对于二分类问题的sigmoid标量输出,应该使用binary_crossentropy损失函数。

无论你的问题是什么,rmsprop优化器通常都是一个足够好的选择。

随着神经网络在训练数据上的表现越来越好,模型最终会过拟合,并在前所未见的数据上得到越来越差的结果,一定要一直监控模型在训练集之外的数据上的性能。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400783.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BTC系列-系统学习铭文(一)-比特币上的NFT

Ordinals协议概况 开源项目: https://github.com/ordinals/ord铭文浏览器: https://Ordinals.com关于Ordinals的BIP: https://github.com/ordinals/ord/blob/master/bip.mediawiki序数理论手册: https://docs.ordinals.com/overview.html 所需的技术积累 Ordinals NFTs 是基…

SQL注入:网鼎杯2018-unfinish

目录 使用dirmap扫描 使用dirsearch扫描 使用acunetix扫描 爆破后端过滤的字符 绕过限制获取数据 这次的进行SQL注入的靶机是:BUUCTF在线评测 进入到主页面后发现是可以进行登录的,那么我们作为一个安全人员,那肯定不会按照常规的方式来…

达梦数据库--DM8两节点DSC集群安装部署(达梦数据库DSC集群搭建)

1 前期规划 系统规划 本地磁盘规划 共享存储规划 DMDSC 集群为了实现多实例同时访问和修改数据,需要数据文件、控制文件和日志文件都放到共享存储上。DM 支持两种共享存储,裸设备和 DMASM,裸设备是未经过格式化的特殊字符设备,…

【MATLAB】 MODWT信号分解+FFT傅里叶频谱变换组合算法

有意向获取代码,请转文末观看代码获取方式~ 展示出图效果 1 MODWT分解算法 MODWT分解算法是一种基于小波变换的信号分解算法,与EWT分解算法类似,它也可以将信号分解为一系列具有不同频率特性的小波分量。但是,MODWT分解算法在小…

2.21学习总结

1.【模板】ST 表 2.Balanced Lineup G 3.景区导游 4.最近公共祖先(LCA) 倍增思想:主要用于LCA问题,RMQ问题。在进行 递推 时,如果 状态空间很大,通常的 线性递推 无法满足 时间 与 空间复杂度 的要求&…

Web基础②nginx搭建与配置

目录 一.Nginx概述 1.定义 2.Nginx模块作用 (1)main模块 (2)stream服务模块 (3)邮件服务模块 (4)第三方模块 (5)events模块 (6&#xff…

程序媛的mac修炼手册-- 如何彻底卸载Python

啊,前段时间因为想尝试chatgpt的API,需要先创建一个python虚拟环境来安装OpenAI Python library. 结果,不出意外的出意外了,安装好OpenAI Python library后,因为身份认证问题,根本就没有获取API key的权限…

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求,总是能越过缓存,调用数据库,就是缓存穿透。 比如当请求一…

新版Java面试专题视频教程——多线程篇②

新版Java面试专题视频教程——多线程篇② 0. 问题汇总0.1 线程的基础知识0.2 线程中并发安全0.3 线程池0.4 使用场景 1.线程的基础知识2.线程中并发锁3.线程池3.1 说一下线程池的核心参数(线程池的执行原理知道嘛)3.2 线程池中有哪些常见的阻塞队列Array…

Java Web演化史:从Servlet到SpringBoot的技术进程及未来趋势

引言 在快速演进的IT世界里,Java Web开发始终屹立不倒,它不仅承担着历史的厚重,也始终面向未来。 自诞生之日起,Java Web技术就在不断地进化,以适应不同时代的需求。 本文将回顾Java Web开发的重要里程碑,…

django rest framework 学习笔记-实战商城2

01收货地址模型类和视图定义_哔哩哔哩_bilibili 本博客借鉴至大佬的视频学习笔记 地址信息的管理:增删改查的实现 # 序列化器配置 class AddrSerializer(serializers.ModelSerializer):"""收货地址的模型序列化器"""class Meta:mo…

喀秋莎画中画怎么设置 喀秋莎画中画视频怎么导出 喀秋莎什么意思 camtasia studio下载

画中画视频,顾名思义,就是在一个视频中有两个画面,游戏解说、微课等类型的视频常常就以画中画的形式出现。作为一款专业的视频编辑软件,使用camtasia可以轻松地制作画中画视频并导出。接下来我将为大家介绍:喀秋莎画中…

HEVC视频编解码标准学习笔记-1

视频编解码标准H.265/HEVC(High Efficiency Video Coding)通过将视频数据编码为更高效格式,大幅改善了视频流的压缩效率。这里主要介绍Tile、Slice和CTU的定义,以及介绍这些技术组件之间的相互关系。 CTU(编码树单元&…

Chrome插件精选 — 缓存清理

Chrome实现同一功能的插件往往有多款产品,逐一去安装试用耗时又费力,在此为某一类型插件挑选出比较好用的一款或几款,尽量满足界面精致、功能齐全、设置选项丰富的使用要求,便于节省一个个去尝试的时间和精力。 1. Chrome清理大师…

基于深度学习的红肉新鲜过期判决系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 系统构成与流程 4.2 模型训练与优化 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...............................................…

phar反序列化原理及利用

phar是什么? phar 是 PHP 的一种归档文件格式,类似于 ZIP 或 TAR 文件,它可以包含多个文件和目录,并且可以像访问普通文件系统一样在 PHP 中进行访问。在php 5.3 或更高版本中默认开启 在php.ini中配置如下时,才能生成…

线性代数:线性方程组解的结构

目录 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3

docker容器常见操作

目录 一、认识容器 1.1、docker用到的内核技术 1.2、namespace 1.3、Control Group 1.4、LXC与docker区别 二、docker环境准备 2.1、安装docker 2.2、docker daemon环境管理 三、镜像、容器和仓库 3.1、镜像常见操作 3.2、配置镜像加速器 命名空间 3.3、非官方镜像仓…

亿道丨防爆工业平板哪家好丨防爆平板电脑pad:防什么?

在爆炸性环境中,工作安全是至关重要的。防爆工业平板作为一种特殊设计的设备,不仅能够抵御爆炸风险,还提供高效的工作性能。本文将介绍防爆工业平板的防护功能以及其在各个行业中的应用。 在许多行业,如石油、化工、矿山和制药等领…

【RT-DETR有效改进】Best Paper | DAttention (DAT)可变形注意力机制和动态采样点

一、本文介绍 本文给大家带来的是RT-DETR改进DAT(Vision Transformer with Deformable Attention)的教程,其发布于2022年CVPR2022上同时被评选为Best Paper,由此可以证明其是一种十分有效的改进机制,其主要的核心思想是:引入可变…