中文NLP with fastai - Fastai Part4
使用fastai进行自然语言处理
在之前的教程中,我们已经了解了如何利用预训练模型并对其进行微调,以执行图像分类任务(MNIST)。应用于图像的迁移学习原理同样也可以应用于NLP任务。在本教程中,我们将使用名为AWD_LSTM的预训练模型来对中文电影评论进行分类。AWD_LSTM是LSTM的一种变体。LSTM是一种循环神经网络(RNN),专为处理长文本序列而设计。我们将在后续教程中详细讨论RNN。
使用fastai进行中文自然语言处理:实用示例
中文语言处理是一项具有挑战性的任务,因为大多数NLP模型都是用英语等西方语言训练的。与英语不同,中文不使用空格来分隔单词,这使得分词更具挑战性。幸运的是,有像jieba这样的库可以进行中文分词。Jieba和pkuseg是两个专为有效处理中文分词而设计的库。只要是在中文语料库上训练的,可以使用预训练的词嵌入,如Word2Vec、Glove或FastText。在本指南的最后,我将向您展示如何使用Google的BERT变体——中文BERT来捕捉中文文本中的上下文。XLM-RoBERTa是另一个在中文文本上表现良好的多语言模型。除了中文BERT外,还有许多本土模型,如百度的ERNIE(Enhanced Representation through kNowledge IntEgration)和PaddleNLP,阿里巴巴的FastBERT和AliceMind,以及腾讯的TecentPretrain和Chinese Word Vectors。
处理流程
广义上讲,NLP任务有两个基本模块:文本预处理和文本分类。
在文本预处理中,我们希望以计算机能够解释的方式准备文本。即使对于RNN来说,解释文本的上下文含义也是一项非常复杂的任务。Transformer和自注意力机制在这一领域取得了突破(因此在最后有transformer的例子)。为了简单起见,我们现在将主要关注分词和词嵌入步骤。
分词
分词是将文本转换为"标记"的操作,这些标记可以是字符(“a”、“b”、“c”,…)或单词(“hello”、“world”,…),甚至是子字符串,取决于模型的粒度。这就是中文语言变得有趣的地方,因为与英语或基于字母的语言不同,即使是中文字符(我,喜,欢,爱,中)本身也带有含义!因此,中文的词分割变成了一项更艰巨的任务,因为与英语不同,英语中的单词是由空格分隔的,中国人必须通过阅读和记忆来学习如何识别词的边界。因此,需要特殊的算法来分割中文文本。此外,中文文本中的外来词、数字和符号需要特殊处理。
词嵌入
词嵌入是一种将单词表示为向量的方法。在上一个教程中,我们看到了如何将MNIST数据集(灰度图像)转换为3D向量(高度、宽度、颜色)。我们在这里做的概念上也很相似。这些向量的特殊之处在于它们是从大量文本中学习的,那些含义相似的词在高维向量空间中彼此接近(物以类聚)。在本教程中,我们将创建一个自定义的fastai DataBlock
,ChineseTextBlock
,用于分词和嵌入中文文本。
文本分类
文本分类是为一段文本分配标签的任务。例如,我们可以将电影评论分类为正面或负面。我们将使用fastai的数据加载器和AWD_LSTM
来构建一个文本分类器。
设置和导入
# 如果需要,安装所需的包
# !pip install fastai jieba
from fastai.text.all import *
import jieba
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
中文文本示例
为了演示目的,我们将创建一个小型中文电影评论数据集。在实际应用中,您将加载自己的数据集。
# 中文电影评论示例(正面和负面)
positive_reviews = ["这部电影非常精彩,演员的表演令人印象深刻。","剧情紧凑,特效惊人,是今年最好看的电影之一。","导演的手法很独特,将故事讲述得引人入胜。","音乐配乐恰到好处,为电影增添了不少气氛。","这是一部让人回味无穷的佳作,值得一看。"
]negative_reviews = ["情节拖沓,演员表演生硬,浪费了我的时间。","特效做得很差,剧情漏洞百出,非常失望。","导演似乎不知道自己想要表达什么,整部电影混乱不堪。","对白尴尬,角色塑造单薄,完全不推荐。","这部电影毫无亮点,是我今年看过最差的一部。"
]# 创建数据框
reviews = positive_reviews + negative_reviews
labels = ['positive'] * len(positive_reviews) + ['negative'] * len(negative_reviews)df = pd.DataFrame({'text': reviews, 'label': labels})
df = df.sample(frac=1).reset_index(drop=True) # 打乱数据df.head()
text | label | |
---|---|---|
0 | 这是一部让人回味无穷的佳作,值得一看。 | positive |
1 | 剧情紧凑,特效惊人,是今年最好看的电影之一。 | positive |
2 | 导演的手法很独特,将故事讲述得引人入胜。 | positive |
3 | 特效做得很差,剧情漏洞百出,非常失望。 | negative |
4 | 音乐配乐恰到好处,为电影增添了不少气氛。 | positive |
中文文本分词
让我们探索中文文本的不同分词方法。
1. 使用Jieba进行词级分词
我们需要区分在中文NLP上下文中"词"的含义。中文词由提供含义的汉字组成。例如,词"中国"由两个汉字"中"和"国"组成。词"中国"与"中国是一个伟大的国家"中的"中国"含义不同(中国是一个伟大的国家)。后一句中的"中国"是一个名词短语,而前一句中的"中国"是一个名词。前一句中的"中国"是一个单词,而后一句中的"中国"是两个词。前一句中的"中国"是一个单独的标记,而后一句中的"中国"是两个标记。
然而在英语中,一个词就是一个词,比如"China"。所以中文NLP中的词在概念上更类似于英语中的"子词"。
def chinese_word_tokenizer(text):"""使用Jieba进行中文词分割"""# 处理Path对象,通过读取文件if hasattr(text, 'read_text'):text = text.read_text(encoding='utf-8')elif hasattr(text, 'open'):text = text.open(encoding='utf-8').read()# 如果有混合的英文文本,转换为小写text = str(text).lower()# 使用Jieba分割词words = jieba.cut(text)return list(words)