第57章 词卷积

使用字符卷积对文本分类是可以实现的,但是相对于词来说,字符包含的信息并没有词多,即使卷积神经网络能够较好地对数据信息进行学习,但是由于包含的内容关系不多而导致其最终效果差强人意。

在字符卷积的基础上,研究人员尝试使用以词为基础数据对文本进行处理。比如,下图为使用卷积神经网络CNN做词卷积模型。


图1 使用卷积神经网络CNN做词卷积模型

图2 使用卷积神经网络CNN做词卷积模型

在实际读写中,一般用短文本表达较为集中的思想,文本长度有限、结构紧凑、能够独立表达意思,因此可以使用基于词卷积的神经网络对数据进行处理。

单词的文本处理

使用卷积神经网络对单词进行处理的最基本要求是将文本转换成计算机可以识别的数据。上一章中,使用了卷积神经网络对字符的独热编码矩阵进行了处理,能不能将文本中的单词进行独热编码后再进行处理处理?

图3 单词进行独热编码

图4 单词进行独热编码

使用独热编码表示单词从理论上说是可行的,但是实际上并不可行。对于基于字符的独热编码方案来说,所有的字符会在一个相对合适的字符库(比如26个字母或者一些常用的字符)中选取,那么总量不会太多(一般不出超过128个),因此组成的矩阵也不会太大。

对于单词来说,常用的英文单词或者中文词语一般在5000个左右,因此建立一个稀疏、庞大的独热编码矩阵是不可实际的想法。

目前来说,一般较好的解决方法就是使用word2vec的词嵌入方法,这样可以通过学习将字库中的词转换成维度一定的向量,作为卷积神经网络的计算依据。这里继续使用前几章准备好的AG News新闻数据集,并以标题作为处理的目标。单词的词向量建立步骤如下,

分词处理

首先对数据进行分词处理,与采用独热编码的数据读取类似,首先对文本进行清洗,不使用停用词以及标准化文本。需要注意的是,对于word2vec训练模型来说,需要输入若干词列表,因此要将读取的文本进行分词,转换成数组的形式。 代码如下,


import csv
import re
import jax
import numpy

def setup():
    
    with open("../../Shares/ag_news_csv/train.csv", "r") as handler:
        
        train_labels = []
        train_texts = []
        
        trains = csv.reader(handler)
        trains = list(trains)
        
        for i in range(len(trains)):
            
            line = trains[I]
            
            train_labels.append(jax.numpy.int32(line[0]))
            train_texts.append(purify(line[1], split = True))
            
    return train_labels, train_texts

def purify(string: str, pattern: str = r"[^a-z]", replacement: str = " ", split = False):
    
    string = string.lower()
    
    string = re.sub(pattern = pattern, repl = replacement, string = string)
    # Replace the consucutive spaces with single space
    string = re.sub(pattern = r" +",  repl = replacement, string = string)
    # string = re.sub(pattern = " ", repl = "", string = string)
    
    # Trim the string
    string = string.strip()
    string = string + " eos"
    
    if split:
        
        string = string.split(" ")
    
    return string

模型训练与载入

下一步是对分词模型的训练和载入,基于已有的分词数据,对不同维度的矩阵分别处理。 需要注意的书,对于word2vec词向量来说,简单地将待补全矩阵全部用0矩阵补全是不合适的,一个好的办法就是将0矩阵修改为一个非常小的常数矩阵,代码如下,


def one_hot_numbers(numbers):
    
    array = numpy.array(numbers)
    maximum = numpy.max(array) + 1
    
    eyes = numpy.eye(maximum)[array]
    
    return eyes
    
def make_words_matrix(maximum_length = 12):
    
    train_labels, train_texts = setup()
    
    import gensim.models
        
    model = gensim.models.word2vec.Word2Vec(train_titles, vector_size = 64, min_count = 0, window = 5)
    
    matrixes = []
    
    for line in train_texts:
        
        length = len(line)
        
        if length > maximum_length:
            
            line = line[: maximum_length]
            matrix = model.wv[line]
            
            matrixes.append(matrix)
            
        else:
            
            matrix = model.wv[line]
            padding_length = maximum_length - length
            padding_matrix = numpy.zeros([padding_length, 64]) + 1e-10
            
            matrix = jax.numpy.concatenate([matrix, padding_matrix], axis = 0)
            
            matrixes.append(matrix)
            
    train_texts = numpy.expand_dims(matrixes, axis = 3)
    train_labels = one_hot_numbers(train_labels)
    
    return train_texts, train_labels

def main():
    
    train_texts, train_labels = make_words_matrix()
    
    print(f"train_texts.shape = {train_texts.shape}, train_labels.shape = {train_labels.shape}")
        
if __name__ == "__main__":
    
    main()

运行结果打印输出如下,


train_titles.shape = (120000, 12, 64, 1), train_labels.shape = (120000, 5)

上面代码中,numpy.expand_dims()函数的作用是对生成的数据列表中的数据进行扩展,将原始的三位矩阵扩展成四维,在不改变具体数值大小的前提下扩展了矩阵的维度,这是为下一步使用二维卷积神经网络对文本进行分类任务做数据准备。

卷积神经网络文本分类模型实现

类似于上一章字符卷积的模型设计,使用二维卷积进行文本分类任务。模型的算法很简单,根据输入的已转换成词嵌入形式的词矩阵,通过不同的卷积提取不同的长度进行二维卷积计算,将最终的计算值进行链接,之后经过池化层获取不同矩阵均值,之后通过一个全连接层对其进行分类。

完整代码如下所示,


import csv
import re
import jax
import numpy
import jax.example_libraries.stax
import jax.example_libraries.optimizers

def setup():
    
    with open("../../Shares/ag_news_csv/train.csv", "r") as handler:
        
        train_labels = []
        train_texts = []
        
        trains = csv.reader(handler)
        trains = list(trains)
        
        for i in range(len(trains)):
            
            line = trains[I]
            
            train_labels.append(jax.numpy.int32(line[0]))
            train_texts.append(purify(line[1], split = True))
            
    return train_labels, train_texts

def purify(string: str, pattern: str = r"[^a-z]", replacement: str = " ", split = False):
    
    string = string.lower()
    
    string = re.sub(pattern = pattern, repl = replacement, string = string)
    # Replace the consucutive spaces with single space
    string = re.sub(pattern = r" +",  repl = replacement, string = string)
    # string = re.sub(pattern = " ", repl = "", string = string)
    
    # Trim the string
    string = string.strip()
    string = string + " eos"
    
    if split:
        
        string = string.split(" ")
    
    return string

def one_hot_numbers(numbers):
    
    array = numpy.array(numbers)
    maximum = numpy.max(array) + 1
    
    eyes = numpy.eye(maximum)[array]
    
    return eyes

def make_words_matrix(maximum_length = 12):
    
    train_labels, train_texts = setup()
    
    import gensim.models
        
    model = gensim.models.word2vec.Word2Vec(train_titles, vector_size = 64, min_count = 0, window = 5)
    
    matrixes = []
    
    for line in train_texts:
        
        length = len(line)
        
        if length > maximum_length:
            
            line = line[: maximum_length]
            matrix = model.wv[line]
            
            matrixes.append(matrix)
            
        else:
            
            matrix = model.wv[line]
            padding_length = maximum_length - length
            padding_matrix = numpy.zeros([padding_length, 64]) + 1e-10
            
            matrix = jax.numpy.concatenate([matrix, padding_matrix], axis = 0)
            
            matrixes.append(matrix)
            
    train_texts = numpy.expand_dims(matrixes, axis = 3)
    train_labels = one_hot_numbers(train_labels)
    
    return train_texts, train_labels

def cnn(number_classes):
    
    return jax.example_libraries.stax.serial(
        
        jax.example_libraries.stax.Conv(1, (3, 3)),
        jax.example_libraries.stax.Relu,
        
        jax.example_libraries.stax.Conv(1, (5, 5)),
        jax.example_libraries.stax.Relu,
        
        jax.example_libraries.stax.Flatten,
        
        jax.example_libraries.stax.Dense(32),
        jax.example_libraries.stax.Relu,
        
        jax.example_libraries.stax.Dense(number_classes),
        
        jax.example_libraries.stax.LogSoftmax
        
        )

结论

本章基于前几章介绍过的内容,在学习了字符卷积的前提下,介绍了词卷积,并通过一个例子讲解了使用卷积神经网络进行词卷积的基本操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359

推荐阅读更多精彩内容