基于 FastAI 文本迁移学习的情感分类(93%+Accuracy)

胶片情感分析

前言

系列专栏:【深度学习:算法项目实战】✨︎
涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记忆、自然语言处理、深度强化学习、大型语言模型和迁移学习。

情感分析是指利用自然语言处理、文本分析、计算语言学和生物统计学,系统地识别、提取、量化和研究情感状态和主观信息。

语言模型通过学习来预测单词序列的概率。但为什么我们需要学习单词的概率呢?让我们通过一个例子来理解。我相信你一定用过谷歌翻译。出于不同的原因,我们都会用它将一种语言翻译成另一种语言。这是一个流行的 NLP 应用的例子,叫做机器翻译。在 “机器翻译 ”中,你需要从一种语言中输入一堆单词,然后将这些单词转换成另一种语言。现在,系统可能会给出许多潜在的翻译,您需要计算每种翻译的概率,以了解哪种翻译最准确。

目录

  • 1. 根据预训练模型训练文本分类器
    • 1.1 使用高级应用程序接口
    • 1.2 使用数据块应用程序接口
  • 2. ULMFiT 方法
    • 2.1 微调 IMDb 上的语言模型
    • 2.2 训练文本分类器

我们将使用《学习词向量进行情感分析》一文中的 IMDb 数据集,该数据集包含数千条电影评论。

1. 根据预训练模型训练文本分类器

我们将尝试使用预训练模型来训练分类器,为了准备好数据,我们将首先使用高级 API:

1.1 使用高级应用程序接口

我们可以使用以下命令下载数据并解压:

from fastai.text.all import *
path = untar_data(URLs.IMDB)
path.ls()
(#5) [Path('/home/sgugger/.fastai/data/imdb/unsup'),Path('/home/sgugger/.fastai/data/imdb/models'),Path('/home/sgugger/.fastai/data/imdb/train'),Path('/home/sgugger/.fastai/data/imdb/test'),Path('/home/sgugger/.fastai/data/imdb/README')]
(path/'train').ls()
(#4) [Path('/home/sgugger/.fastai/data/imdb/train/pos'),Path('/home/sgugger/.fastai/data/imdb/train/unsupBow.feat'),Path('/home/sgugger/.fastai/data/imdb/train/labeledBow.feat'),Path('/home/sgugger/.fastai/data/imdb/train/neg')]

数据按照 ImageNet 风格组织,在 train 文件夹中,我们有两个子文件夹:pos 和 neg(分别用于正面评论和负面评论)。我们可以使用 TextDataLoaders.from_folder 方法收集数据。我们唯一需要指定的是验证文件夹的名称,即 “test”(而不是默认的 “valid”)。

dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test')

然后,我们可以使用 show_batch 方法查看数据:

dls.show_batch()

在这里插入图片描述
文本数据
我们可以看到,该程序库自动处理了所有文本,然后将其拆分成标记符,并添加了一些特殊标记符,如

  • xxbos 表示文本开始
  • xxmaj 表示下一个词被大写

这样,我们就可以在一行中定义一个适合文本分类的学习器:

learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)

我们使用 AWD LSTM 架构,drop_mult 是一个参数,用于控制该模型中所有 dropout 的大小,我们使用准确率来跟踪我们模型效果。然后,我们就可以对预训练模型进行微调:

learn.fine_tune(4, 1e-2)

学习

learn.fine_tune(4, 1e-2)

模型训练
还不错!我们可以使用 show_results 方法来查看模型的运行情况:

learn.show_results()

文本分类模型评估
我们可以很容易地预测新文本:

learn.predict("I really liked that movie!")
('pos', tensor(1), tensor([0.0092, 0.9908]))

在这里,我们可以看到模型认为该评论是正面的。结果的第二部分是 “pos ”在我们的数据词汇表中的索引,最后一部分是每个类别的概率(“pos ”为 99.1%,“neg ”为 0.9%)。

1.2 使用数据块应用程序接口

我们还可以使用数据块 API 在 DataLoaders 中获取数据。这部分比较高深,如果你还不习惯学习新的 API,可以跳过这部分。

数据库块是通过向 fastai 库提供大量信息而建立的:
通过一个名为 “块”(block)的参数来确定所使用的类型:这里我们有文本和类别,因此我们传递 TextBlock 和 CategoryBlock。为了通知库我们的文本是文件夹中的文件,我们使用了 from_folder 类方法。

  • 如何获取原始项目,这里使用函数 get_text_files
  • 如何标注这些项目,这里使用父文件夹。
  • 如何分割这些项目,此处使用祖文件夹。
imdb = DataBlock(blocks=(TextBlock.from_folder(path), CategoryBlock),get_items=get_text_files,get_y=parent_label,splitter=GrandparentSplitter(valid_name='test'))

这只是提供了一个如何组合数据的蓝图。要实际创建数据,我们需要使用 dataloaders 方法:

dls = imdb.dataloaders(path)

2. ULMFiT 方法

我们在上一节中使用的预训练模型被称为语言模型。它是在维基百科上进行预训练的,任务是在阅读了前面所有单词后猜测下一个单词。我们将这个语言模型直接微调为电影评论分类器,取得了很好的效果,但只要多做一步,我们就能做得更好:维基百科的英语与 IMDb 的英语略有不同。因此,我们可以根据 IMDb 语料库微调预训练的语言模型,然后以此为基础建立分类器,而不是直接跳转到分类器。

当然,其中一个原因是,了解你正在使用的模型的基础是很有帮助的。但还有一个非常实用的原因,那就是如果在微调分类模型之前微调(基于序列的)语言模型,就能获得更好的结果。例如,在 IMDb 情感分析任务中,数据集包含了 50,000 条额外的电影评论,这些评论在 unsup 文件夹中没有附加任何正面或负面标签。我们可以使用所有这些影评来微调预训练的语言模型–这将产生一个特别擅长预测影评下一个单词的语言模型。相比之下,预训练模型只在维基百科文章中进行训练。

这幅图概括了整个过程:请添加图片描述

2.1 微调 IMDb 上的语言模型

我们可以很容易地将文本放入适合语言建模的 DataLoaders 中:

dls_lm = TextDataLoaders.from_folder(path, is_lm=True, valid_pct=0.1)

我们需要为 valid_pct 传递一些信息,否则该方法将尝试使用祖文件夹名称来分割数据。通过传递 valid_pct=0.1,我们可以告诉它随机获取其中 10%的评论作为验证集。

我们可以使用 show_batch 查看数据。这里的任务是猜测下一个单词,因此我们可以看到目标都向右移动了一个单词。

dls_lm.show_batch(max_n=5)

在这里插入图片描述
然后,我们有一个方便的方法,可以像以前一样使用 AWD_LSTM 架构直接从中抓取一个学习器。我们使用准确率和困惑度作为衡量指标(困惑度是损失的指数),并将默认权重衰减设为 0.1。

learn = language_model_learner(dls_lm, AWD_LSTM, metrics=[accuracy, Perplexity()], path=path, wd=0.1).to_fp16()

默认情况下,预训练的学习器处于冻结状态,这意味着只有模型的头部会进行训练,而主体则保持冻结。在这里,我们将向你展示 fine_tune 方法背后的内容,并使用 fit_one_cycle 方法来拟合模型:

learn.fit_one_cycle(1, 1e-2)

训练模型
这个模型的训练需要一段时间,所以这是一个很好的机会来讨论保存中间结果的问题。

您可以像这样轻松保存模型的状态:

learn.save('1epoch')

它会在 learn.path/models/ 中创建一个名为 “1epoch.pth ”的文件。如果您想在以同样方式创建学习器后在另一台机器上加载模型,或稍后继续训练,您可以通过以下方式加载该文件的内容:

learn = learn.load('1epoch')

我们可以在解冻后对模型进行微调:

learn.unfreeze()
learn.fit_one_cycle(10, 1e-3)

在这里插入图片描述
完成后,我们就可以保存模型的全部内容,但最后一层除外,该层将激活度转换为选取词汇表中每个标记的概率。不包括最后一层的模型称为编码器。我们可以用 save_encoder 保存它:

learn.save_encoder('finetuned')

术语:Encoder(编码器): 不包括特定任务最终层的模型。在应用于视觉 CNN 时,其含义与 body 大致相同,但更多用于 NLP 和生成模型。

在利用这一点对评论分类器进行微调之前,我们可以使用我们的模型来生成随机评论:因为它经过训练可以猜测句子的下一个单词是什么,所以我们可以用它来编写新的评论:

TEXT = "I liked this movie because"
N_WORDS = 40
N_SENTENCES = 2
preds = [learn.predict(TEXT, N_WORDS, temperature=0.75) for _ in range(N_SENTENCES)]
print("\n".join(preds))
i liked this movie because of its story and characters . The story line was very strong , very good for a sci - fi film . The main character , Alucard , was very well developed and brought the whole story
i liked this movie because i like the idea of the premise of the movie , the ( very ) convenient virus ( which , when you have to kill a few people , the " evil " machine has to be used to protect

2.2 训练文本分类器

我们几乎可以像以前一样收集数据进行文本分类:

dls_clas = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test', text_vocab=dls_lm.vocab)

主要区别在于,我们必须使用与微调语言模型时完全相同的词汇,否则学习到的权重将毫无意义。我们用 text_vocab 传递这个词汇。

然后,我们就可以像之前一样定义文本分类器了:

learn = text_classifier_learner(dls_clas, AWD_LSTM, drop_mult=0.5, metrics=accuracy)

所不同的是,在训练之前,我们先加载之前的编码器:

learn = learn.load_encoder('finetuned')

最后一步是使用辨别学习率和渐进解冻进行训练。在计算机视觉中,我们通常会一次性解冻模型,但对于 NLP 分类器,我们发现每次解冻几层会带来真正的不同。

learn.fit_one_cycle(1, 2e-2)

在这里插入图片描述
只用了一个历元,我们就得到了与第一节中的训练相同的结果,不算太差!我们可以向 freeze_to 传递 -2 以冻结除最后两个参数组之外的所有参数:

learn.freeze_to(-2)
learn.fit_one_cycle(1, slice(1e-2/(2.6**4),1e-2))

训练
然后我们可以再解冻一些,继续训练:

learn.freeze_to(-3)
learn.fit_one_cycle(1, slice(5e-3/(2.6**4),5e-3))

训练
最后是整个模型!

learn.unfreeze()
learn.fit_one_cycle(2, slice(1e-3/(2.6**4),1e-3))

训练整个模型

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[vue3后台管理二]首页和登录测试

[vue3后台管理二]首页和登录测试 1 修改main.js import ./assets/main.cssimport { createApp } from vue import App from ./App.vue import router from ./router createApp(App).use(router).mount(#app)2 路由创建 import {createRouter, createWebHistory} from vue-ro…

计算机网络学习笔记——运输层(b站)

目录 一、 运输层概述 二、运输层端口号、复用与分用的概念 三、UDP和TCP的对比 四、TCP的流量控制 五、TCP的拥塞控制 六、TCP超时重传时间的选择 七、TCP可靠传输的实现 八、TCP报文段的首部格式 一、 运输层概述 物理层、数据链路层、网络层实现了主机到主机的通信…

剪映网页版

https://www.capcut.cn/web 免费,免安装,跨平台,视频云合成,简直太好用了!

echarts-事件

echarts部分事件 添加点击事件 添加点击事件: let options {tooltip: {},xAxis: {type: "category",data: ["d1", "d2", "d3", "d4"],},yAxis: {},series: [{type: "line",data: d1,},{type: &qu…

Codeforces Round 948 (Div. 2) E. Tensor(思维题-交互)

题目 n(3<n<100)个点的有向图&#xff0c; 图的边的关系未知&#xff0c;但保证以下两点&#xff1a; 1. 只存在j->i&#xff08;i<j&#xff09;的边 2. 对于任意三个点i、j、k&#xff08;i<j<k&#xff09;&#xff0c;要么k可以到达i&#xff0c;要么…

知识付费小程序源码系统 界面支持万能DIY装修,一站式运营 附带完整的源代码以及搭建教程

系统概述 这是一款功能强大的知识付费小程序源码系统&#xff0c;它为用户提供了一个全面的平台&#xff0c;能够满足各种知识付费场景的需求。其界面支持万能 DIY 装修&#xff0c;让用户可以根据自己的品牌形象和风格进行个性化定制&#xff0c;打造出独具特色的小程序界面。…

【云原生】Kubernetes----PersistentVolume(PV)与PersistentVolumeClaim(PVC)详解

目录 引言 一、存储卷 &#xff08;一&#xff09;存储卷定义 &#xff08;二&#xff09;存储卷的作用 1.数据持久化 2.数据共享 3.解耦 4.灵活性 &#xff08;三&#xff09;存储卷的分类 1.emptyDir存储卷 1.1 定义 1.2 特点 1.3 示例 2.hostPath存储卷 2.1 …

postman教程-6-发送delete请求

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了postman发送put请求的方法&#xff0c;本小节我们讲解一下postman发送delete请求的方法。 HTTP DELETE 请求是一种用于删除指定资源的请求方法。在RESTful API 设计中&#xff0c;DELETE 请求…

GPT-4o:重塑人机交互的未来

一个愿意伫立在巨人肩膀上的农民...... 一、推出 在人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直被视为连接人类与机器的桥梁。近年来&#xff0c;随着深度学习技术的快速发展&#xff0c;NLP领域迎来了前所未有的变革…

ARM-V9 RME(Realm Management Extension)系统架构之系统能力的执行隔离

安全之安全(security)博客目录导读 目录 一、执行隔离 1、安全状态 2、安全模型 本博客探讨 RME 所需的系统能力&#xff0c;以保证 Arm CCA 对于 Realms 的安全性和隔离特性。 一、执行隔离 1、安全状态 RME 系统支持以下安全状态&#xff1a; 非安全 (Non-secure)安全…

Orange Pi Kunpeng Pro测评

#创作灵感# 参加树莓派鲲鹏开发版的测评活动&#xff0c;也想体验一下该开发版&#xff0c;之前有做过树莓派和香橙派的开发&#xff0c;刚好借此机会了解一下鲲鹏&#xff0c;所以就有了这篇测评文章。 #正文# 引言 说是测评&#xff0c;其实也没有多少测评方面的内容&…

代码随想录算法训练营Day22|235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

二叉搜索树的最近公共祖先 不考虑二叉搜索树这一条件的话&#xff0c;普通的二叉搜索树搜索最近的公共祖先就是昨日的做法&#xff0c;这种做法也能解决二叉搜索树的最近公共祖先。 class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, Tr…

STM32读写内部FLASH读取芯片id

文章目录 读写内部Flash接线程序编写测试效果补充 读取芯片id代码编写 读写内部Flash 接线 程序编写 首先使用ThisFlash.c来写入flash的基本操作&#xff0c;写入、读取、擦除&#xff0c;然后使用Store.c配合数组来进行主存与flash的交互 ThisFlash.c #include "stm32…

为什么工控现场会用到Profinet转Modbus网关设备

一、背景&#xff1a; 工控现场之所以需要使用Profinet转Modbus网关&#xff0c;是因为工控系统中常常存在不同厂家设备之间通讯协议不一致的问题。而Modbus和Profinet分别代表着两种不同的通信协议&#xff0c;Profinet通常用于较新的设备&#xff0c;而Modbus则是比较老的通…

ch2应用层--计算机网络期末复习

2.1应用层协议原理 网络应用程序位于应用层 开发网络应用程序: 写出能够在不同的端系统上通过网络彼此通信的程序 2.1.1网络应用程序体系结构分类: 客户机/服务器结构 服务器: 总是打开(always-on)具有固定的、众所周知的IP地址 主机群集常被用于创建强大的虚拟服务器 客…

基于51单片机的温控风扇的设计–仿真设计

可实现通过DS18B20测量当前环境温度 可实现通过温度自动控制风扇转速 可实现通过按键设置不同风速对应的温度 可实现通过按键切换自动、手动模式 可实现在手动模式下通过按键调整风扇转速 可实现通过LCD1602显示温度、风扇转速挡位、自动/手动模式

【C++】模拟实现string类

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 一.了解项目功能 二.逐步实现项目功能模块及其逻辑详解 &#x1f38f;构建成员变量 &#x1f38f;实现string类默认成员函数 &#x1f4cc;构造函数 &#x1f4cc;析构函数…

k8s 全面掌控日志系统

概述 为了提高系统运维和故障排查的效率&#xff0c; 日志系统采用 ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;技术栈&#xff0c;通过 FileBeats 作为日志收集器&#xff0c;将来自不同节点的日志数据汇总并存储在 Elasticsearch 中&#xff0c;最终通过 K…

创建一个新的Spring Security应用程序,并使用JDBC连接数据库

创建一个新的Spring Security应用程序&#xff0c;并使用JDBC连接数据库 在这个教程中&#xff0c;我们将学习如何创建一个新的Spring Security应用程序&#xff0c;使用JDBC连接数据库以获取用户信息并进行认证。我们还将学习如何配置Spring Security以从数据库中获取用户和权…

Vue3使用Composition API实现响应式

title: Vue3使用Composition API实现响应式 date: 2024/5/29 下午8:10:24 updated: 2024/5/29 下午8:10:24 categories: 前端开发 tags: Vue3CompositionRefsReactiveWatchLifecycleDebugging 1. 介绍 Composition API是Vue.js 3中新增的一组API&#xff0c;用于在组件中组…