NLP-RNN-LSTM浅析
目录
双向 LSTM(Bi - LSTM)
双向 LSTM(Bi - LSTM)原理深入讲解
代码示例(基于 PyTorch)
LSTM 应用到双向 RNN 中
代码示例(基于 PyTorch)
双向 LSTM - CRF(Conditional Random Field,条件随机场)
双向 LSTM - CRF 原理深入讲解
双向 LSTM 部分
CRF 部分
代码示例(基于 PyTorch)
双向 LSTM - CNNs(Convolutional Neural Networks,卷积神经网络)
双向 LSTM - CNNs 原理深入讲解
CNN 部分
双向 LSTM 部分
整体架构
代码示例(基于 PyTorch)
双向 LSTM - CNNS - CRF
原理深入讲解
代码示例(基于 PyTorch)
双向 LSTM(Bi - LSTM)
- 结构原理:从图片中可以看到,双向 LSTM 由两个方向相反的 LSTM 组成,一个是正向 LSTM(forward),一个是反向 LSTM(backward)。正向 LSTM 按正常顺序处理输入序列(如),反向 LSTM 按逆序处理输入序列(如)。每个时刻的输出由正向和反向 LSTM 在该时刻的隐藏状态共同决定。这使得模型能够同时利用过去和未来的信息,相比单向 LSTM,在处理序列数据时具有更强的上下文理解能力。
- 应用场景:常用于自然语言处理中的词性标注、命名实体识别等任务,因为在这些任务中,单词的语义不仅依赖于前面的单词,还可能依赖于后面的单词。
双向 LSTM(Bi - LSTM)原理深入讲解
双向 LSTM 由两个方向相反的 LSTM 单元组成,即前向 LSTM 和后向 LSTM。以自然语言处理中的句子处理为例,在处理一个单词时,前向 LSTM 可以利用该单词之前的上下文信息,而后向 LSTM 可以利用该单词之后的上下文信息。这样,每个时刻的输出就综合了来自过去和未来的信息,使得模型对序列的理解更加全面。
代码示例(基于 PyTorch)
import torch
import torch.nn as nnclass BiLSTM(nn.Module):def __init__(self, input_size, hidden_size, num_layers, output_size):super(BiLSTM, self).__init__()self.hidden_size = hidden_sizeself.num_layers = num_layersself.bilstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True)self.fc = nn.Linear(2 * hidden_size, output_size)def forward(self, x):# 初始化隐藏状态和细胞状态h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(x.device)c0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(x.device)out, _ = self.bilstm(x, (h0, c0))# out的形状为(batch_size, seq_length, 2 * hidden_size)out = self.fc(out[:, -1, :]) # 取最后一个时间步的输出return out
使用示例
# 示例参数
input_size = 10
hidden_size = 20
num_layers = 2
output_size = 5
batch_size = 3
seq_length = 8# 创建输入数据
x = torch.randn(batch_size, seq_length, input_size)
# 实例化BiLSTM模型
model = BiLSTM(input_size, hidden_size, num_layers, output_size)
# 前向传播
output = model(x)
print(output.shape)
上述代码:
- 在
BiLSTM
类的构造函数中,通过nn.LSTM
并设置bidirectional=True
来创建双向 LSTM 层。由于双向 LSTM 在每个时间步的输出是前向和后向隐藏状态的拼接,所以其维度是2 * hidden_size
,因此全连接层self.fc
的输入维度设置为2 * hidden_size
。 - 在
forward
方法中,首先初始化隐藏状态h0
和细胞状态c0
,这里因为是双向 LSTM,层数变为原来的 2 倍(self.num_layers * 2
)。然后将输入x
和初始化的状态传入双向 LSTM 层得到输出out
,最后取out
中最后一个时间步的输出传入全连接层得到最终结果。
LSTM 应用到双向 RNN 中
- 结构原理:本质上就是双向 LSTM。双向 RNN 是一种允许信息在两个方向流动的循环神经网络结构,将 LSTM 这种能够有效处理长序列依赖问题的单元应用到双向 RNN 中,就形成了双向 LSTM。它结合了 LSTM 处理长序列的优势和双向 RNN 利用双向信息的特点。如图片中所示,两个 LSTM 单元分别从序列的开头和结尾向中间处理数据,在每个时间步上,将两个 LSTM 的隐藏状态进行融合(如拼接等操作),以获得包含更多上下文信息的表示。
- 应用场景:在语音识别中,双向 LSTM 可以更好地理解语音序列的前后信息,提高识别准确率。
双向 RNN(Bidirectional RNN)是一种能够在序列数据中同时利用过去和未来信息的神经网络结构。将 LSTM(长短期记忆网络)应用到双向 RNN 中,就形成了双向 LSTM(Bi - LSTM),它结合了 LSTM 处理长序列依赖问题的优势以及双向 RNN 的双向信息利用能力。
在双向 LSTM 中,存在两个独立的 LSTM 单元,一个按正常顺序(从序列开头向结尾)处理输入序列,称为前向 LSTM;另一个按逆序(从序列结尾向开头)处理输入序列,称为后向 LSTM。
代码示例(基于 PyTorch)
import torch
import torch.nn as nnclass BiLSTMInBRNN(nn.Module):def __init__(self, input_size, hidden_size, num_layers, output_size):super(BiLSTMInBRNN, self).__init__()self.hidden_size = hidden_sizeself.num_layers = num_layersself.bilstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True)self.fc = nn.Linear(2 * hidden_size, output_size)def forward(self, x):batch_size = x.size(0)# 初始化隐藏状态和细胞状态,因为是双向LSTM,层数翻倍h0 = torch.zeros(self.num_layers * 2, batch_size, self.hidden_size).to(x.device)c0 = torch.zeros(self.num_layers * 2, batch_size, self.hidden_size).to(x.device)out, _ = self.bilstm(x, (h0, c0))# out的形状是(batch_size, seq_length, 2 * hidden_size)# 这里简单地取最后一个时间步的输出作为最终特征表示,也可以根据任务选择其他方式out = self.fc(out[:, -1, :])return out
使用示例:
# 示例参数
input_size = 10 # 输入特征维度
hidden_size = 20 # 隐藏层维度
num_layers = 2 # LSTM层数
output_size = 5 # 输出维度
batch_size = 3 # 批量大小
seq_length = 8 # 序列长度# 创建输入数据
x = torch.randn(batch_size, seq_length, input_size)
# 实例化模型
model = BiLSTMInBRNN(input_size, hidden_size, num_layers, output_size)
# 前向传播
output = model(x)
print(output.shape)
上述代码:
- 在
BiLSTMInBRNN
类的构造函数中,通过nn.LSTM
并设置bidirectional=True
来构建双向 LSTM 层。由于双向 LSTM 每个时间步的输出是前向和后向隐藏状态的拼接,所以维度变为2 * hidden_size
,因此全连接层self.fc
的输入维度设置为2 * hidden_size
。 - 在
forward
方法中,先根据批量大小初始化隐藏状态h0
和细胞状态c0
,这里因为是双向 LSTM,层数变为原来的 2 倍(self.num_layers * 2
)。将输入x
和初始化状态传入双向 LSTM 层得到输出out
,然后取out
中最后一个时间步的输出传入全连接层得到最终结果。这种方式常用于序列分类任务,将序列最后一个时间步的特征表示用于预测类别。
双向 LSTM - CRF(Conditional Random Field,条件随机场)
- 结构原理:在双向 LSTM 的基础上,添加了 CRF 层。双向 LSTM 对输入序列进行特征提取和编码,得到每个位置的标签得分。CRF 层则根据这些得分以及标签之间的转移概率,对整个序列的标签进行联合预测。例如在命名实体识别任务中,CRF 层可以考虑标签之间的依赖关系(如 B - ORG 后面更可能是 I - ORG,而不是 O),从而得到更合理的标签序列。
- 应用场景:广泛应用于自然语言处理中的序列标注任务,如命名实体识别、词性标注等,通过 CRF 层对标签序列的约束,提高标注的准确性和一致性。
双向 LSTM - CRF 原理深入讲解
双向 LSTM - CRF 是一种在自然语言处理等序列标注任务中表现优异的模型架构,它结合了双向 LSTM 和条件随机场(CRF)的优势。
双向 LSTM 部分
CRF 部分
代码示例(基于 PyTorch)
实现一个简单的双向 LSTM - CRF 模型用于命名实体识别任务
import torch
import torch.nn as nn
import numpy as np# 定义标签集合
tag_to_ix = {"B - ORG": 0, "I - ORG": 1, "O": 2}
# 转移矩阵,行表示当前标签,列表示下一个标签
START_TAG = "<START>"
STOP_TAG = "<STOP>"
tag_to_ix[START_TAG] = len(tag_to_ix)
tag_to_ix[STOP_TAG] = len(tag_to_ix)
transition_matrix = torch.tensor([[np.log(0.7), np.log(0.3), np.log(0.0)], # B - ORG -> B - ORG, I - ORG, O[np.log(0.0), np.log(0.9), np.log(0.1)], # I - ORG -> B - ORG, I - ORG, O[np.log(0.2), np.log(0.4), np.log(0.4)], # O -> B - ORG, I - ORG, O[0.0] * len(tag_to_ix), # START_TAG -> 所有标签[0.0] * len(tag_to_ix) # 所有标签 -> STOP_TAG
])# BiLSTM_CRF网络
class BiLSTM_CRF(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, tag_to_ix):super(BiLSTM_CRF, self).__init__()self.embedding_dim = embedding_dimself.hidden_dim = hidden_dimself.vocab_size = vocab_sizeself.tag_to_ix = tag_to_ixself.tagset_size = len(tag_to_ix)self.word_embeds = nn.Embedding(vocab_size, embedding_dim)self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True, batch_first=True)self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)self.transition_matrix = transition_matrixdef _get_lstm_features(self, sentence):embeds = self.word_embeds(sentence).unsqueeze(0)lstm_out, _ = self.lstm(embeds)lstm_out = lstm_out.view(len(sentence), self.hidden_dim)lstm_feats = self.hidden2tag(lstm_out)return lstm_featsdef _forward_alg(self, feats):init_alphas = torch.full((1, self.tagset_size), -10000.)init_alphas[0][tag_to_ix[START_TAG]] = 0.forward_var = init_alphasfor feat in feats:alphas_t = []for next_tag in range(self.tagset_size):emit_score = feat[next_tag].view(1, -1).expand(1, self.tagset_size)trans_score = self.transition_matrix[next_tag].view(1, -1)next_tag_var = forward_var + trans_score + emit_scorebest_tag_score, best_tag_id = torch.max(next_tag_var, 1)alphas_t.append(best_tag_score)forward_var = torch.cat(alphas_t).view(1, -1)terminal_var = forward_var + self.transition_matrix[tag_to_ix[STOP_TAG]]alpha = torch.max(terminal_var)return alphadef _viterbi_decode(self, feats):backpointers = []init_vvars = torch.full((1, self.tagset_size), -10000.)init_vvars[0][tag_to_ix[START_TAG]] = 0forward_var = init_vvarsfor feat in feats:bptrs_t = []viterbivars_t = []for next_tag in range(self.tagset_size):next_tag_var = forward_var + self.transition_matrix[next_tag]best_tag_score, best_tag_id = torch.max(next_tag_var, 1)viterbivars_t.append(best_tag_score + feat[next_tag])bptrs_t.append(best_tag_id)forward_var = torch.cat(viterbivars_t).view(1, -1)backpointers.append(bptrs_t)terminal_var = forward_var + self.transition_matrix[tag_to_ix[STOP_TAG]]best_tag_id = torch.argmax(terminal_var)path_score = terminal_var[0][best_tag_id]best_path = [best_tag_id]for bptrs_t in reversed(backpointers):best_tag_id = bptrs_t[best_tag_id][0]best_path.append(best_tag_id)start = best_path.pop()assert start == tag_to_ix[START_TAG]best_path.reverse()return path_score, best_pathdef neg_log_likelihood(self, sentence, tags):feats = self._get_lstm_features(sentence)forward_score = self._forward_alg(feats)gold_score = self._score_sentence(feats, tags)return forward_score - gold_scoredef _score_sentence(self, feats, tags):score = torch.zeros(1)tags = torch.cat([torch.tensor([tag_to_ix[START_TAG]], dtype=torch.long), tags])for i, feat in enumerate(feats):score = score + self.transition_matrix[tags[i + 1], tags[i]] + feat[tags[i + 1]]score = score + self.transition_matrix[tag_to_ix[STOP_TAG], tags[-1]]return scoredef forward(self, sentence):lstm_feats = self._get_lstm_features(sentence)score, tag_seq = self._viterbi_decode(lstm_feats)return score, tag_seq
使用示例:
# 假设词汇表大小为100,词嵌入维度为50,隐藏层维度为100
vocab_size = 100
embedding_dim = 50
hidden_dim = 100
# 模拟一个句子,这里是单词索引列表
sentence = torch.tensor([10, 20, 30], dtype=torch.long)
# 模拟对应的标签
tags = torch.tensor([tag_to_ix["B - ORG"], tag_to_ix["I - ORG"], tag_to_ix["O"]], dtype=torch.long)
model = BiLSTM_CRF(vocab_size, embedding_dim, hidden_dim, tag_to_ix)
loss = model.neg_log_likelihood(sentence, tags)
print("Loss:", loss.item())
_, predicted_tags = model(sentence)
print("Predicted tags:", [list(tag_to_ix.keys())[tag] for tag in predicted_tags])
上述代码:
BiLSTM_CRF
类的构造函数初始化了词嵌入层、双向 LSTM 层、全连接层以及转移矩阵。_get_lstm_features
方法获取双向 LSTM 对输入句子的特征表示。_forward_alg
方法实现了前向算法,用于计算所有可能标签序列的得分。_viterbi_decode
方法使用维特比算法找到概率最大的标签序列。neg_log_likelihood
方法计算模型的负对数似然损失。_score_sentence
方法计算给定标签序列的得分。forward
方法用于预测标签序列。(前向传播)
双向 LSTM - CNNs(Convolutional Neural Networks,卷积神经网络)
- 结构原理:结合了双向 LSTM 和 CNN 的优点。在输入层,可能会使用 CNN 对字符级别的信息进行特征提取,例如提取单词中字符的局部特征。然后将这些特征与词嵌入等其他特征一起输入到双向 LSTM 中,双向 LSTM 进一步处理序列信息,捕捉上下文依赖关系。这种结构可以同时利用 CNN 的局部特征提取能力和双向 LSTM 的上下文建模能力。
- 应用场景:在自然语言处理中,对于一些需要同时考虑字符级和词级信息的任务,如文本分类、情感分析等,双向 LSTM - CNNs 可以取得较好的效果。
双向 LSTM - CNNs 原理深入讲解
双向 LSTM - CNNs 是一种融合了卷积神经网络(CNN)和双向长短期记忆网络(Bi - LSTM)的架构,在处理序列数据尤其是自然语言处理和时间序列分析任务中表现出色,其原理如下:
CNN 部分
CNN 主要负责提取局部特征。以自然语言处理中的文本数据为例,输入的文本通常先被转换为词嵌入(word embeddings)形式,每个词对应一个低维稠密向量。接着,CNN 通过不同大小的卷积核在词嵌入矩阵上滑动进行卷积操作。例如,大小为 3 的卷积核可以捕捉连续 3 个词的局部特征,类似于在文本中提取 n - gram 特征。这些卷积操作能够自动学习到文本中单词之间的局部关联模式,如短语结构等。通过池化操作(如最大池化、平均池化)可以进一步降低数据维度,同时保留重要的特征信息。
双向 LSTM 部分
双向 LSTM 由两个方向相反的 LSTM 组成,分别从序列的开头和结尾向中间处理数据。在每个时间步,前向 LSTM 利用当前及之前的信息计算隐藏状态,后向 LSTM 利用当前及之后的信息计算隐藏状态。然后将这两个方向的隐藏状态进行拼接或其他融合操作,使得模型能够同时利用过去和未来的上下文信息,从而对序列有更全面的理解。例如在情感分析任务中,双向 LSTM 可以结合一个单词前后的所有信息来判断其情感倾向。
整体架构
将 CNN 提取的局部特征输入到双向 LSTM 中。双向 LSTM 基于这些局部特征,进一步捕捉序列的全局依赖关系和长期依赖信息。最后,通过全连接层等结构将双向 LSTM 的输出映射到任务所需的输出空间,如文本分类任务中的类别概率、命名实体识别任务中的标签等。
代码示例(基于 PyTorch)
简单的双向 LSTM - CNNs 用于文本分类的代码示例:
import torch
import torch.nn as nn
import torch.nn.functional as Fclass BiLSTM_CNN(nn.Module):def __init__(self, vocab_size, embedding_dim, num_filters, filter_sizes, hidden_size, num_layers, num_classes):super(BiLSTM_CNN, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim)self.convs = nn.ModuleList([nn.Conv2d(1, num_filters, (fs, embedding_dim)) for fs in filter_sizes])self.lstm = nn.LSTM(num_filters * len(filter_sizes), hidden_size, num_layers, batch_first=True,bidirectional=True)self.fc = nn.Linear(hidden_size * 2, num_classes)def forward(self, x):embedded = self.embedding(x)embedded = embedded.unsqueeze(1)conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs]pooled = [F.max_pool1d(conv, conv.size(2)).squeeze(2) for conv in conved]cat = torch.cat(pooled, dim=1)out, _ = self.lstm(cat.unsqueeze(1))out = out[:, -1, :]out = self.fc(out)return out
使用示例:
# 示例参数
vocab_size = 10000 # 词汇表大小
embedding_dim = 100 # 词嵌入维度
num_filters = 100 # 卷积核数量
filter_sizes = [3, 4, 5] # 卷积核大小
hidden_size = 128 # LSTM隐藏层维度
num_layers = 2 # LSTM层数
num_classes = 2 # 类别数
batch_size = 32
seq_length = 50# 创建输入数据
x = torch.randint(0, vocab_size, (batch_size, seq_length))
# 实例化模型
model = BiLSTM_CNN(vocab_size, embedding_dim, num_filters, filter_sizes, hidden_size, num_layers, num_classes)
# 前向传播
output = model(x)
print(output.shape)
上述代码:
BiLSTM_CNN
类的构造函数初始化了词嵌入层、卷积层、双向 LSTM 层和全连接层。forward
方法中,首先对输入进行词嵌入,然后经过卷积和池化操作提取局部特征,将这些特征拼接后输入到双向 LSTM 中,最后通过全连接层得到分类结果。
双向 LSTM - CNNS - CRF
- 结构原理:是在双向 LSTM - CNNs 的基础上再添加 CRF 层。首先通过 CNN 提取字符级别的局部特征,然后双向 LSTM 对序列信息进行上下文建模,最后 CRF 层根据双向 LSTM 的输出对标签序列进行联合预测,考虑标签之间的依赖关系。这种复杂的结构综合了 CNN 的局部特征提取、双向 LSTM 的上下文建模和 CRF 的序列标注优化能力。
- 应用场景:在复杂的自然语言处理序列标注任务中表现出色,如在医疗文本的实体识别和关系抽取任务中,能够更准确地识别和标注相关的实体和关系。
双向 LSTM - CNNS - CRF 是一种集成了卷积神经网络(CNNs)、双向长短期记忆网络(Bi - LSTM)和条件随机场(CRF)优势的复杂模型架构,在自然语言处理的序列标注任务中表现卓越。
原理深入讲解
- CNNs 部分:在自然语言处理中,文本通常以词向量的形式输入。CNNs 通过卷积核在词向量矩阵上滑动卷积,捕捉局部特征,比如相邻几个词组成的短语特征。例如,3x3 的卷积核可以分析连续 3 个词的关系。池化操作进一步筛选关键特征并降低数据维度,减少计算量,同时保留重要信息,为后续处理提供更具代表性的局部特征。
- 双向 LSTM 部分:双向 LSTM 由前向和后向的 LSTM 组成。前向 LSTM 从序列起始向末尾处理数据,后向 LSTM 则相反。在每个时间步,它们分别整合过去和未来的上下文信息,将两个方向的隐藏状态拼接,能更全面地理解序列信息。比如在命名实体识别中,判断一个词是否属于某个实体,不仅要依据前文,后文信息也至关重要,双向 LSTM 能有效捕捉这些依赖关系。
- CRF 部分:CRF 考虑了标签之间的依赖关系。在序列标注任务里,标签并非独立存在,如 “B - ORG”(组织实体开始标签)后通常接 “I - ORG”(组织实体内标签)。CRF 通过学习转移矩阵来建模这种依赖,转移矩阵中的元素表示从一个标签转移到另一个标签的概率。在预测时,基于双向 LSTM 的输出和转移矩阵,使用维特比算法找出概率最大的标签序列,提升标注准确性。
代码示例(基于 PyTorch)
import torch
import torch.nn as nn
import torch.nn.functional as Fclass BiLSTMCNNsCRF(nn.Module):def __init__(self, vocab_size, embedding_dim, num_filters, filter_sizes, hidden_size, num_layers, num_tags):super(BiLSTMCNNsCRF, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim)self.convs = nn.ModuleList([nn.Conv2d(1, num_filters, (fs, embedding_dim)) for fs in filter_sizes])self.lstm = nn.LSTM(num_filters * len(filter_sizes), hidden_size, num_layers, batch_first=True, bidirectional=True)self.fc = nn.Linear(hidden_size * 2, num_tags)self.transitions = nn.Parameter(torch.randn(num_tags, num_tags))self.transitions.data[torch.arange(num_tags), torch.arange(num_tags)] = -10000self.start_tag = num_tags - 2self.end_tag = num_tags - 1def _get_lstm_features(self, x):embedded = self.embedding(x).unsqueeze(1)conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs]pooled = [F.max_pool1d(conv, conv.size(2)).squeeze(2) for conv in conved]cat = torch.cat(pooled, dim=1)out, _ = self.lstm(cat.unsqueeze(1))return self.fc(out.squeeze(1))def _forward_alg(self, feats):init_alphas = torch.full((1, self.transitions.size(0)), -10000.).to(feats.device)init_alphas[0][self.start_tag] = 0forward_var = init_alphasfor feat in feats:alphas_t = []for next_tag in range(self.transitions.size(0)):emit_score = feat[next_tag].view(1, -1).expand(1, self.transitions.size(0))trans_score = self.transitions[next_tag].view(1, -1)next_tag_var = forward_var + trans_score + emit_scorebest_tag_score, _ = torch.max(next_tag_var, 1)alphas_t.append(best_tag_score)forward_var = torch.cat(alphas_t).view(1, -1)terminal_var = forward_var + self.transitions[self.end_tag]alpha = torch.max(terminal_var)return alphadef _viterbi_decode(self, feats):backpointers = []init_vvars = torch.full((1, self.transitions.size(0)), -10000.).to(feats.device)init_vvars[0][self.start_tag] = 0forward_var = init_vvarsfor feat in feats:bptrs_t = []viterbivars_t = []for next_tag in range(self.transitions.size(0)):next_tag_var = forward_var + self.transitions[next_tag]best_tag_score, best_tag_id = torch.max(next_tag_var, 1)viterbivars_t.append(best_tag_score + feat[next_tag])bptrs_t.append(best_tag_id)forward_var = torch.cat(viterbivars_t).view(1, -1)backpointers.append(bptrs_t)terminal_var = forward_var + self.transitions[self.end_tag]best_tag_id = torch.argmax(terminal_var)best_path = [best_tag_id]for bptrs_t in reversed(backpointers):best_tag_id = bptrs_t[best_tag_id][0]best_path.append(best_tag_id)start = best_path.pop()assert start == self.start_tagbest_path.reverse()return best_pathdef neg_log_likelihood(self, x, tags):feats = self._get_lstm_features(x)forward_score = self._forward_alg(feats)gold_score = self._score_sentence(feats, tags)return forward_score - gold_scoredef _score_sentence(self, feats, tags):score = torch.zeros(1).to(feats.device)tags = torch.cat([torch.tensor([self.start_tag], dtype=torch.long).to(feats.device), tags])for i, feat in enumerate(feats):score = score + self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]]score = score + self.transitions[self.end_tag, tags[-1]]return scoredef forward(self, x):feats = self._get_lstm_features(x)return self._viterbi_decode(feats)
使用示例:
# 示例参数
vocab_size = 10000
embedding_dim = 100
num_filters = 128
filter_sizes = [3, 4, 5]
hidden_size = 256
num_layers = 2
num_tags = 5
batch_size = 16
seq_length = 30# 创建输入数据
x = torch.randint(0, vocab_size, (batch_size, seq_length))
# 模拟标签
tags = torch.randint(0, num_tags, (batch_size, seq_length))
model = BiLSTMCNNsCRF(vocab_size, embedding_dim, num_filters, filter_sizes, hidden_size, num_layers, num_tags)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for epoch in range(10):model.train()optimizer.zero_grad()loss = model.neg_log_likelihood(x, tags)loss.backward()optimizer.step()print(f'Epoch {epoch + 1}, Loss: {loss.item()}')
model.eval()
predicted_tags = model(x)
print(predicted_tags)
BiLSTMCNNsCRF
类构建了完整的双向 LSTM - CNNS - CRF 模型。_get_lstm_features
方法实现了 CNNs 和双向 LSTM 的特征提取过程;_forward_alg
和_viterbi_decode
分别实现了 CRF 的前向算法和维特比解码算法;neg_log_likelihood
计算负对数似然损失用于训练;forward
方法用于预测标签序列 。
相关文章:
NLP-RNN-LSTM浅析
目录 双向 LSTM(Bi - LSTM) 双向 LSTM(Bi - LSTM)原理深入讲解 代码示例(基于 PyTorch) LSTM 应用到双向 RNN 中 代码示例(基于 PyTorch) 双向 LSTM - CRF(Conditio…...
深入解析 iText 7:从 PDF 文档中提取文本和图像
在现代开发中,PDF 文件的操作是不可避免的一部分。无论是生成报告、解析文档,还是从文件中提取信息,我们常常需要处理 PDF 文件。iText 是一个非常强大的库,广泛应用于 PDF 文件的创建、修改和解析。自 iText 7 发布以来ÿ…...
【AI】GitHub Copilot
GitHub Copilot 是一款由 GitHub 和 OpenAI 合作开发的 AI 编程助手,它可以在多种开发工具中使用。以下是 GitHub Copilot 支持的主要开发工具和平台: 1. Visual Studio Code (VS Code) 官方支持:GitHub Copilot 在 VS Code 中拥有最完整的集…...
深入理解 MySQL 8 C++ 源码:SELECT MOD(MONTH(NOW()), 2) 的函数执行过程
MySQL 作为最流行的关系型数据库之一,其内部实现机制一直是开发者探索的热点。本文将以一条简单的 SQL 查询 SELECT MOD(MONTH(NOW()), 2) 为例,深入分析 MySQL 8 源码中内置函数 MOD、MONTH 和 NOW 的执行过程,揭示其底层实现逻辑。 一、SQL…...
基于深度学习进行呼吸音检测的详细示例
以下是一个基于深度学习进行呼吸音检测的详细示例,我们将使用Python语言以及一些常见的深度学习库(如TensorFlow、Keras)和数据处理库(如numpy、pandas),同时会用到音频处理库librosa。整个流程包括数据加载…...
Python 正则表达式的非捕获组介绍
在 Python 正则表达式中,非捕获组 ((?:...)) 是一种用于分组但不保存匹配结果的结构。它与普通的捕获组 (...) 语法类似,但在匹配时不会创建编号或命名的组,常用于简化正则表达式和提高性能。 1. 语法 (?:pattern)?: 表示非捕获标记。pat…...
用大内存主机下载Visual Studio
用一台内存达到128G的主机下载Visual Studio 2022,用的是公司网络。下载速度让我吃了一惊,没人用网络了?还是网站提速了?以前最大只能达到5MB/秒。记录这段经历,是用来分析公司网络用的.........
快速入门——Vue框架快速上手
学习自哔哩哔哩上的“刘老师教编程”,具体学习的网站为:8.Vue框架快速上手_哔哩哔哩_bilibili,以下是看课后做的笔记,仅供参考。 第一节:前端环境准备 编码工具VSCode【www.code.visualstudio.com】/WebStorm也可&am…...
zero自动化框架搭建---Git安装详解
一、Git下载 下载安装包 官网下载 下载的地址就是官网即可:Git - Downloads 进来直接选择windows的安装包下载 选择安装位置 双击安装包安装,选择安装地址后点击next 选择安装的组件,默认即可 也可按照需要自行选择 Windows Explorer i…...
适用于复杂背景的YOLOv8改进:基于DCN的特征提取能力提升研究
文章目录 1. YOLOv8的性能瓶颈与改进需求1.1 YOLOv8的优势与局限性1.2 可变形卷积(DCN)的优势 2. DCN在YOLOv8中的应用2.1 DCN的演变与YOLOv8的结合2.2 将DCN嵌入YOLOv8的结构中2.2.1 DCNv1在YOLOv8中的应用2.2.2 DCNv2与DCNv3的优化 2.3 实验与性能对比…...
Java 大视界 -- 深度洞察 Java 大数据安全多方计算的前沿趋势与应用革新(52)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
Flutter:动态表单(在不确定字段的情况下,生成动态表单)
关于数据模型:模型就是一种规范约束,便于维护管理,在不确定表单内会出现什么数据时,就没有模型一说。 这时就要用到动态表单(根据接口返回的字段,生成动态表单) 1、观察数据格式,定义…...
Redis存在线程安全问题吗?
Redis本身在其单线程模型下是线程安全的,但在特定应用场景下,仍可能面临线程安全相关的挑战。以下是对Redis线程安全性的详细讲解: Redis线程安全的基础 单线程模型: Redis采用单线程模型来处理客户端的请求。这意味着࿰…...
Maven 与 Kubernetes 部署:构建和部署到 Kubernetes 环境中
在现代的 DevOps 实践中,Kubernetes 被广泛用于容器化应用的自动化部署、扩展和管理。而 Maven 是 Java 项目中常用的构建工具,通常用于依赖管理、构建、打包等任务。在许多项目中,Maven 和 Kubernetes 可以结合起来,完成 容器化构…...
与本地电脑PDF文档对话的PDF问答程序
文章目录 PDF问答程序程序流程处理PDF文档创建问答链 在探索和学习新技术时,了解LangChain框架的理论知识固然重要,但实际的案例分析与实践尝试能为你提供更加直观的认识和更深人的理解。本文主要以解析案例代码为主。通过具体的实践操作,你可…...
什么是uniapi
“UniAPI”有两种不同的含义,具体取决于上下文: 1. uni-app 的 API uni-app 是一个基于 Vue.js 的跨平台应用开发框架,允许开发者编写一套代码并发布到 iOS、Android、Web、以及各种小程序等多个平台。uni-app 的 API 是其核心功能之一&…...
网络运维学习笔记 012网工初级(HCIA-Datacom与CCNA-EI)某机构新增:GRE隧道与EBGP实施
文章目录 GRE隧道(通用路由封装,Generic Routing Encapsulation)协议号47实验:思科:开始实施: 华为:开始实施: eBGP实施思科:华为: GRE隧道(通用路…...
Spring MVC 的核心以及执行流程
Spring MVC的核心 Spring MVC是Spring框架中的一个重要模块,它采用了经典的MVC(Model-View-Controller)设计模式。 MVC是一种软件架构的思想,它将软件按照模型(Model)、视图(View)…...
vue单据打印 一维码、二维码实现
编码规则与 JavaScript 代码实现 编码规则数组:定义了 Code 128 条形码编码规则数组 BARS,其中每个数字对应一种条形码的线条组合模式。 const BARS [212222,222122,222221,121223,121322,131222,122213,122312,132212,221213,221312,231212,112232,12…...
01数据准备 抓取图片 通过爬虫方式获取bing的关键词搜索图片
为了获取训练所需的图片,我们最常用的手段就是自己去写一个爬虫去获取相关图片。本文将重点围绕如何采用爬虫的方式获取训练所需的图片素材进行讲解,为了大家能够够直观的掌握相关技术,参考本文的相关过程和代码获取自己的数据图片素材,笔者将详细介绍实现过程。 1、确定图…...
智能马达保护器:为工业电机安全运行保驾护航
在工业生产中,电动机作为核心动力设备,其稳定运行直接关系到生产效率与安全性。然而,复杂的工况环境、频繁启停和突发负载变化,常导致电机面临过载、缺相、短路等故障风险。安科瑞智能马达保护器凭借其智能化、高精度、多功能的设…...
Wireshark使用介绍
文章目录 Wireshark介绍Wireshark使用工作模式介绍1. 混杂模式(Promiscuous Mode)2. 普通模式(Normal Mode)3. 监视模式(Monitor Mode) 界面分区捕获过滤器语法基本语法逻辑运算符高级语法使用示例捕获过滤…...
DeepSeek操作Excel,实现图表自动化生成
案例 让DeepSeek操作Excel,实现图表自动化生成。我们只要用自然语言输入我们的需求(根据哪块单元格区域做什么图表),就可以直接在Excel中自动生成图表。 操作主界面和图表效果 设置接入方式 这里提供了多种接入方式将DeepSeek接…...
【分布式理论13】分布式存储:数据存储难题与解决之道
文章目录 一、数据存储面临的问题二、RAID磁盘阵列的解决方案1. RAID概述2. RAID使用的技术3. RAID的代表性等级 三、分布式存储的新思路1. 分布式存储背景与特点2. 分布式存储的组成要素 一、数据存储面临的问题 在单机系统时代,当数据量不断增加、硬盘空间不够时…...
C++笔记之标准库中的std::copy 和 std::assign 作用于 std::vector
C++笔记之标准库中的std::copy 和 std::assign 作用于 std::vector code review! 文章目录 C++笔记之标准库中的std::copy 和 std::assign 作用于 std::vector1. `std::copy`1.1.用法1.2.示例2.`std::vector::assign`2.1.用法2.2.示例3.区别总结4.支持assign的容器和不支持ass…...
AWS云从业者认证题库 AWS Cloud Practitioner
题库持续更新,上方二维码查看完整题库! 在分担责任模型下,客户对以下哪项负责? A:确保在使用后擦除磁盘驱动器 B:确保在硬件设备上更新固件 C:确保静态数据已加密 D:确保网线为六类或更高类…...
ubuntu20.04重启后不显示共享文件夹
ubuntu20.04重启后不显示共享文件夹 主要参见这两篇博客 Ubuntu重启后不显示共享文件夹_ubuntu 20.04 共享目录无法使用-CSDN博客 ubuntu22.04 配置共享文件夹 找不到/mnt/hgfs_ubuntu安装tools 后mnt文件夹在哪-CSDN博客 重启Ubuntu20.04后,发现共享文件夹进不去…...
C++ 课程设计 汇总(含源码)
C 课程设计 [C课程设计 个人账务管理系统(含源码)](https://arv000.blog.csdn.net/article/details/145601695)[C课程设计 运动会分数统计(含源码)](https://arv000.blog.csdn.net/article/details/145601819)[C 课程设计打印万年历(含源码&a…...
STC 51单片机63——关于STC8H的ADC通道切换问题
使用STC8H时,发现在ADC中断中只能使用一个通道,即使切换了通道,那么数据要不为0,要不就是原先通道的电压。查阅手册,内容并不多,没有发现专门提到的问题。只能去试试,最后发现在ADC中断中&#…...
【前端框架】Vue3 面试题深度解析
本文详细讲解了VUE3相关的面试题,从基础到进阶到高级,分别都有涉及,希望对你有所帮助! 基础题目 1. 简述 Vue3 与 Vue2 相比有哪些主要变化? 答案: 响应式系统:Vue2 使用 Object.definePrope…...
数据结构——模拟栈例题B3619
B3619 10 进制转 x 进制 - 洛谷 #include <bits/stdc.h>using namespace std; #define fs first #define sc second #define endl \n #define all(x) x.begin(), x.end() typedef long long ll; typedef pair<int, int> PII;char a[40];void solve(){int n,x;cin&g…...
Web自动化之Selenium 超详细教程(python)
Selenium是一个开源的基于WebDriver实现的自动化测试工具。WebDriver提供了一套完整的API来控制浏览器,模拟用户的各种操作,如点击、输入文本、获取页面元素等。通过Selenium,我们可以编写自动化脚本,实现网页的自动化测试、数据采…...
物联网简介集合
物联网(IoT)指的是物理设备(如电器和车辆)之间的互联互通。这些设备嵌入了软件、传感器和连接功能,使其能够相互连接并交换数据。这项技术实现了从庞大的设备网络中收集和共享数据,为打造更高效、自动化的系…...
【设计模式精讲】结构型模式之代理模式(静态代理、JDK动态代理、cglib动态代理)
文章目录 第五章 结构型模式5.1 代理模式5.1.1 代理模式介绍5.1.2 代理模式原理5.1.3 静态代理实现5.1.4 JDK动态代理5.1.4.1 JDK动态代理实现5.1.4.2 类是如何动态生成的5.1.4.3 代理类的调用过程 5.1.5 cglib动态代理5.1.5.1 cglib动态代理实现5.1.5.2 cglib代理流程 5.1.6 代…...
node 使用 Redis 缓存
缓存是什么? 高并发下,一个项目最先出问题的,并不是程序本身,而是数据库最先承受不住。 在数据库上我们可以做很多优化,例如优化 SQL 语句,优化索引,如果数据量大了,还可以分库、分表…...
nginx反向代理负载均衡
反向代理原理: 反向代理服务器架设在服务器端,通过缓冲经常被请求的页面来缓解服务器的工作量,将客户机请求 转发给内部网络上的目标服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此 时代理服务…...
国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容
1 监视剪贴板 1.1 应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。 1.2 使用方法 新建一个空文档(重要:防止扰乱…...
AI全栈开发_人工智能AI大模型 Prompt提示词工程详解(全方位介绍及运用)
AI引领的第四次工业革命正席卷而来,如何精准把握这一历史性的机遇,将成为我们这一代人不容忽视且需深入思考与积极行动的重要课题。未来几年AI将会像计算机一样快速普及,面对这一历史性的第一波红利,你是否已准备好把握机遇&#…...
PHP图书借阅小程序源码
📚 图书借阅小程序:一键开启智慧阅读新篇章 🌟 这是一款由ThinkPHP与UniApp两大技术巨擘强强联手精心打造的图书借阅微信小程序,它犹如一座随身携带的移动图书馆,让您无论身处何地都能轻松畅游知识的海洋。创新的多书…...
sourcetree gitee 详细使用
SSH 公钥设置 | Gitee 帮助中心 先配置公钥,输入gitee密码完成验证 gitee仓库创建完成 打开sourcetree 如果你本地有项目(vite )需要 git init 在设置中完成远程仓库的添加 (ssh ,https) 直接提交推送,完成后…...
Hive JOIN过滤条件位置玄学:ON vs WHERE的量子纠缠
Hive JOIN过滤条件位置玄学:ON vs WHERE的量子纠缠 作为数据工程师,Hive JOIN就像吃火锅选蘸料——放错位置味道全变!今天带你破解字节/阿里等大厂高频面试题:ON和WHERE后的过滤条件究竟有什么不同? 一、核心差异对比表 特性ON子句WHERE子句执行时机JOIN操作时JOIN完成后…...
破局与重构:水务企业数字化转型路径探索
随着数字化技术的发展和智慧城市建设进程的推进,水务行业正经历以数据为驱动的深刻变革。本文深入探讨水务行业数字化发展的趋势、水务企业数字化转型的痛点、水务行业标杆企业数字化转型实践以及水务企业数字化转型的方向和路径,为水务企业十五五期间把…...
stm32hal库寻迹+蓝牙智能车(STM32F103C8T6)
简介: 这个小车的芯片是STM32F103C8T6,其他的芯片也可以照猫画虎,基本配置差不多,要注意的就是,管脚复用,管脚的特殊功能,(这点不用担心,hal库每个管脚的功能都会给你罗列,很方便的.)由于我做的比较简单,只是用到了几个简单外设.主要是由带霍尔编码器电机的车模,电机…...
云服务中的“高可用性架构”是怎样的?
在云计算中,“高可用性架构”(High Availability Architecture,简称HA架构)是指通过设计和配置,使得系统、服务或应用能够在发生硬件故障、软件故障、网络问题等情况下,依然保持正常运行,最大程…...
StableDiffusion+ComfyUI
一、AI、AIGC、AIAgent基本概念 图形生成大模型:StableDiffusion(逼真,开源)、Midjourney(艺术性,商业)、FLUX(复杂场景,开源商业)工作流程构建工具:ComfyUI智能体:COZE、Dify、FastGPTAI视频编辑工具&…...
MATLAB基础学习相关知识
MATLAB安装参考:抖音-记录美好生活 MATLAB基础知识学习参考:【1小时Matlab速成教程-哔哩哔哩】 https://b23.tv/CnvHtO3 第1部分:变量定义和基本运算 生成矩阵: % 生成矩阵% 直接法% ,表示行 ;表示列 a [1,2,3;4,5,6;7,8,9];%…...
设计模式 之 工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)(C++)
文章目录 C 工厂模式引言一、简单工厂模式概念实现步骤示例代码优缺点 二、工厂方法模式概念实现步骤示例代码优缺点 三、抽象工厂模式概念实现步骤示例代码优缺点 C 工厂模式 引言 在 C 编程中,对象的创建是一个常见且基础的操作。然而,当项目规模逐渐…...
windows下docker使用笔记
目录 镜像的配置 镜像的拉取 推荐镜像源列表(截至2025年2月测试有效) 配置方法 修改容器名字 如何使用卷 创建不同的容器,每个容器中有不同的mysql和java版本(不推荐) 1. 安装 Docker Desktop(Win…...
SQLMesh 系列教程6- 详解 Python 模型
本文将介绍 SQLMesh 的 Python 模型,探讨其定义、优势及在企业业务场景中的应用。SQLMesh 不仅支持 SQL 模型,还允许通过 Python 编写数据模型,提供更高的灵活性和可编程性。我们将通过一个电商平台的实例,展示如何使用 Python 模…...
【时时三省】(C语言基础)用N-S流程图表示算法
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 N-S流程图 既然用基本结构的顺序组合可以表示任何复杂的算法结构,那么,基本结构之间的流程线就是多余的了。1973年,美国学者I.Nassi和B .Shneiderman提出…...