自学内容网 自学内容网

四、自然语言处理_01时序信号与文本向量化

1、时序信号

1.1 概述

以往我们做数据处理时,大多数都是处理一维数组、二维表格、三通道图像这些常规类型的数据,这些数据最多是在行/列、宽/高维度上存在顺序,但在时间维度上面没有顺序

时序信号是指包含时序数据(Time Series Data)的信号,时序数据是一种特殊的数据类型,它记录了按时间顺序排列的数据点,包括语音、心电图、金融市场等数据

在处理时序数据时,需要考虑到数据点之间的时间顺序和依赖关系,时间顺序和依赖关系对于理解时序数据的内在规律至关重要(即:除了特征很重要,特征之间的顺序也很重要)

比如:

在上图中,“我打你”和“你打我”虽然都包含“我”、“你”、“打”这三个特征,但由于特征之间的顺序不同,会导致其内涵也不一样

1.2 常用处理方法

对于时序信号,目前常见的处理方法包括卷积、RNN、Transformer等等

  • 一维卷积网络(1D Convolutional Neural Networks, CNNs)

    • 适用于处理时序数据的局部特征,可以捕捉时间序列中的局部模式

    • 通过滑动窗口的方式在时间序列上应用卷积操作

  • 循环神经网络(Recurrent Neural Networks, RNNs)

    • 特别适合处理时序数据,因为它们能够处理任意长度的序列

    • 常见的RNN变体包括长短期记忆网络(LSTM)和门控循环单元(GRU),它们能够更好地处理长序列中的长期依赖问题

  • 自注意力机制(Self-Attention Mechanisms)

    • 允许模型在序列的不同位置之间动态地分配不同的注意力权重

    • 这种机制在Transformer模型中得到了广泛应用,也被用于处理时序数据

2、文本向量化

2.1 概述

在NLP(自然语言处理)领域中,我们经常要和文本打交道(比如一段汉字文章)

然而,人工智能算法只能处理数字,也就是浮点数,并不能处理汉字

因此,我们必须要想办法把汉字转换为浮点数,这就是文本向量化,即:把一段话拆成多个词,再将每个词都转换成一个向量(这个向量也称为词向量)

2.2 embedding

embedding(嵌入)指的是:将离散的高维数据(如文字、语音等)转换为连续的向量进行表示的过程

在PyTorch中,nn.Embedding 就是实现embedding功能的模块,可将离散型数据(通常是整数)映射为连续型向量进行表示,这个模块的输入是索引列表,输出是相应的词嵌入

使用nn.Embedding非常简单,只需要指定嵌入的维度和可选的最大索引即可:

import torch
import torch.nn as nn

# 创建一个嵌入层,嵌入维度为10(0到9),最大索引为20(0到19)
embedding = nn.Embedding(num_embeddings=20, embedding_dim=10)

# 创建一个包含整数的张量
indices = torch.tensor([1, 5, 9, 15])

# 使用嵌入层将整数映射为向量
embeddings = embedding(indices)
print(embeddings)

2.3 常用处理方法

文本向量化通常有以下几种方法:

  • 词袋模型(Bag of Words, BoW):将文本转换为一个长向量,每个维度代表一个词,向量中的元素是该词在文档中出现的次数或二元特征(出现为1,未出现为0)

  • TF-IDF(Term Frequency-Inverse Document Frequency):考虑词频(TF)和逆文档频率(IDF),以反映一个词对于一个文档集或一个语料库中的其中一份文档的重要性

  • 词嵌入(Word Embeddings):通过预训练模型(如Word2Vec、GloVe)将每个词映射到一个高维空间中的向量,这些向量能够捕捉词之间的语义关系

生成词向量通常有以下几种方法:

  • Word2Vec:由Google开发的一种模型,通过预测上下文词来学习词向量

  • GloVe(Global Vectors for Word Representation):利用全局统计信息来学习词向量,捕捉词与词之间的共现关系

  • FastText:由Facebook开发,类似于Word2Vec,但将词分解为字符n-gram,以更好地处理罕见词和词形变化

2.4 处理步骤

将文本转换为词,再将词转换为向量,这个过程通常包括以下几个步骤:

Step1:分词(Tokenization):将句子拆分成单个的词或者符号,这些单个的词或符号被称为tokens,例如:对于句子“我爱北京天安门!”,分词后的结果可能是“我”、“爱”、“北京”、“天安门”、“!”

Step2:构建词汇表(Vocabulary):为所有tokens建立一个唯一的词汇表,并为每个token分配一个唯一的id,例如:词汇表可能是{"我": 3, "爱": 54, "北京": 65, "天安门": 78, "!": 89}

Step3:One-Hot编码:将每个token的id转换为One-Hot编码形式,即一个长度为词汇表大小的向量,其中对应token id的位置为1,其余位置为0,例如:token "3" 的One-Hot编码可能是一个很长的向量,其中第3个位置是1,其余位置是0

Step4:Embedding层:在深度学习模型中,通常会使用一个Embedding层来将One-Hot编码的向量转换为低维的密集向量,这个Embedding层是一个可学习的矩阵,它的维度是[词汇表大小, 嵌入维度],例如:如果嵌入维度是512,那么每个token的One-Hot编码将被转换为一个512维的向量

Step5:注意数据结构

  • 原始句子的数据结构通常是[batch_size, seq_len],其中batch_size是批次大小,seq_len是序列长度
  • 经过Embedding层处理后,数据结构变为[batch_size, seq_len, embedding_dim],其中embedding_dim是嵌入维度

3、案例

现有如下三句文本,需要进行文本向量化处理

  • "还会再见吗?燕子,再见的时候你要幸福,好不好,燕子,你要开心,你要幸福,好不好,开心啊,幸福。"

  • "你的世界没有我了,没关系,你要自己幸福。"

  • "燕子!燕子!燕子!没有你我怎么活啊!!!"

代码实现:

Step1: 分词

import jieba
import torch 
from torch import nn

s1 = "还会再见吗?燕子,再见的时候你要幸福,好不好,燕子,你要开心,你要幸福,好不好,开心啊,幸福。"
s2 = "你的世界没有我了,没关系,你要自己幸福。"
s3 = "燕子!燕子!燕子!没有你我怎么活啊!!!"

# 使用jieba对第一句话进行分词
# 输出:['还会', '再见', '吗', '?', '燕子', ',', '再见', '的', '时候', '你', '要', '幸福', ',', '好不好', ',', '燕子', ',', '你', '要', '开心', ',', '你', '要', '幸福', ',', '好不好', ',', '开心', '啊', ',', '幸福', '。']
print(jieba.lcut(s1))

# 使用jieba对第一、二、三句话加起来的内容进行分词并去重
# 输出:{'活', '好不好', '没有', '没关系', '燕子', '幸福', '!', '时候', '了', '自己', '我', '开心', '。', '怎么', '还会', ',', '?', '吗', '世界', '再见', '你', '的', '啊', '要'}
tokens = {token for sentence in [s1, s2, s3] for token in jieba.lcut(sentence)}
print(tokens)

# 因为人工智能模型通常会使用矩阵运算来处理数据,而矩阵的维度必须相互匹配
# 所以,为便于后面对第一、二、三句话进行处理,我们需要将这三局话分词后的结果保持长度一致
# 将长度保持一致的主要方法就是添加中间词,包括:
# (1)<PAD>,代表填充词
# (2)<UNK>,代表未知词
tokens.add("<PAD>")
tokens.add("<UNK>")

Step2: 构建词典

# 构建两个词典
# 1、词--id号
token2idx = {token: idx for idx, token in enumerate(tokens)}
# 2、id号--词
idx2token = {idx: token for idx, token in enumerate(tokens)}

print(token2idx)
print(idx2token)

Step3: 长度对齐

# 要想长度对其,则首先需要设置一个固定的长度值
# 对于固定长度值的选取,通常采用两种方法:
# 1、选取最长的句子
# 2、在所有句子的长度中取平均值
# 这里我们选择第一种方法
import numpy as np
token1 = jieba.lcut(s1)
token2 = jieba.lcut(s2)
token3 = jieba.lcut(s3)
lens = [len(temp) for temp in [token1, token2, token3]]
SEQ_LEN = np.max(lens)

# 定义一个对其长度的方法
def pad_sentence(sentence, seq_len=SEQ_LEN):
    """
        处理句子:按照 SEQ_LEN 的长度来统一句子的长度
    """
    sentence_token = jieba.lcut(sentence)
    # get方法用于从字典中获取与键(这里是token,也就是第一个参数)相关联的值,如果键不存在于字典中,get方法会返回其第二个参数指定的默认值(<UNK>对应的id)
    idx = [token2idx.get(token, token2idx.get("<UNK>")) for token in sentence_token]
    # 长度不够的填充<PAD>
    idx += [token2idx.get("<PAD>")] * (seq_len - len(sentence_token))
    return idx

# 开始对其长度
idx1 = pad_sentence(sentence=s1)
idx2 = pad_sentence(sentence=s2)
idx3 = pad_sentence(sentence=s3)

Step4: embedding处理

# 转张量
X = torch.tensor(data=[idx1, idx2, idx3], dtype=torch.long)

# embeddings处理
embedding = nn.Embedding(num_embeddings=len(token2idx), 
                         embedding_dim=256,
                         padding_idx=idx2token.get("<PAD>"))
embeddings = embedding(X)
print(embeddings)

输出:


原文地址:https://blog.csdn.net/weixin_43767064/article/details/144242888

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!