知识图谱(BILSTM+CRF项目完整实现)【第六章】

张开发
2026/4/21 7:26:24 15 分钟阅读

分享文章

知识图谱(BILSTM+CRF项目完整实现)【第六章】
一、代码架构图在data_origin中有两种类型的数据:分别是一般项目和一般项目txtoriginal一般项目中放的是部位、症状、索引列之间用制表符隔开一般项目txtoriginal放的是原始数据二、构建序列标注数据要把原始数据转换为目标数据常用的方式是构建字典,把索引作为键,把标签作为值。可以使用标签类型字典把中文转换为英文然后遍历索引防止中间的索引被标记为O可以判断是否是起始索引若果是起始索引拼接B不是起始索引拼接I难点1获取到所有原始数据通过os.Walk()遍历原始数据所在的文件夹得到所有数据文件2获取原始数据对应的标注数据通过文件名称的特点将原始数据文件名中的.txtoriginal替换成就是对应的标注数据三、BILSTM输入输出计算BILSTM输入有三个元素分别是输入张量、隐藏状态、细胞状态BILSTM输出有三个元素分别是输出张量、最终隐藏状态、最终细胞状态无论是输入张量还是输出张亮默认参数的顺序是L【序列长度】N批次数H张量维度如果参数batch_firstTrue的时候,那么参数顺序是(N批次数,L【序列长度】,H张量维度),这是我们常用的顺序输入参数:输入序列:(batch_size,seq_length,n_dim)[batch_firstTrue]隐藏状态维度:hidden_size隐藏状态:(D*num_lays,batch_size,hidden_size)细胞状态:(D*num_lays,batch_size,hidden_size)输出参数:输出序列:(batch_size,seq_length,D*hidden_size)[batch_firstTrue]隐藏状态:(D*num_lays,batch_size,hidden_size)细胞状态:(D*num_lays,batch_size,hidden_size)如果在输出层上面加一个线性层,那所有的输出参数最后一维的hidden变为线性层的维度小结:输入序列(批次,序列长度,序列维度)输出序列(批次,序列长度,输出维度(隐藏维度/自定义的线性维度))细胞状态(层数*双向/单向,批次数,隐藏状态)细胞状态(层数*双向/单向,批次数,隐藏状态)例如输入序列[8,50,128](batch_firsttrue),隐藏层维度100那么隐藏状态是(D*1,8,100)细胞状态为(D*1,8,100)D的取值是看这个模型是双向模型还是单向模型,如果说是单向模型(比如:LSTM)那么D1,如果是双向模型(比如BILSTM),那么D2num_lays指的是总共有多少个模型,如果整个系统只有一个BILSTM,那么num_lays1,如果整个系统里面有两个BILSTM,那么num_lays2输出序列[8,50,D*100](batch_firstTrue)隐藏状态是(D*1,8,100)细胞状态是(D*1,8,100)四、项目BILSTM应用(基线模型)输入序列的批次和长度:[batch_size,seq_length]向量层对输入序列进行向量化:[batch_size,seq_length,embedding_dim]输入序列到BILSTM里面,BILSTM输出维度:[batch_size,seq_length,hidden_size*2](input_size,hidden_size,bidirectionalTrue,batch_firstTrue)BILSTM输出的维度是:隐藏层*D,所以真正的隐藏层维度是BILSTM输出维度/2随机失活层:只保留有效未知的输出结果,无效部分的值转换为0attention_mask:因为输入序列长短不一,但是神经网络要求同一批次输入序列长度相同.这时候使用attention_mask可以防止神经网络看到这些补齐的padding,让神经网络只关注有用的信息(使用padding补齐序列是在数据预处理的时候完成的)线性层:把输出维度转换为标签类型数维度变换分析:1. 输入层input_ids形状[batch_size, seq_len] [2, 59]含义2 个句子每个句子 59 个词的索引含 padding2. 词嵌入层word_embeds操作nn.Embedding(vocab_size, embedding_dim)把每个词索引映射成 300 维向量形状[batch_size, seq_len, embedding_dim] [2, 59, 300]图中标注[2, 59, 300]✅3. BiLSTM 层参数nn.LSTM(input_size300, hidden_size128, bidirectionalTrue)input_size输入维度 词向量维度 300hidden_size单向隐藏层维度 128bidirectionalTrue双向 LSTM输出会拼接前向 后向的隐藏状态输出形状[batch_size, seq_len, hidden_size*2] [2, 59, 128*2256]图中标注[2, 59, 256]✅4. Dropout 层操作随机让部分神经元失活防止过拟合不改变维度输出形状和输入一样[2, 59, 256]图中标注[2, 59, 256]✅5. 「对位相乘」Attention Mask两个输入Dropout 输出[2, 59, 256]attention_mask形状是[2, 59]0/1 矩阵1 表示有效 token0 表示 padding关键广播机制下的对位相乘attention_mask会被自动扩展为[2, 59, 1]再和[2, 59, 256]逐元素相乘有效位置mask1向量保持不变padding 位置mask0整个 256 维向量全部置 0输出形状还是[2, 59, 256]但 padding 部分的向量全是 06. 线性层linear参数nn.Linear(hidden_dim*2, tag_size)→nn.Linear(256, 12)操作对每个 token 的 256 维特征做线性变换映射到 12 个标签的分数输出形状[batch_size, seq_len, tag_size] [2, 59, 12]图中标注[2, 59, 12]✅总结每一步的维度变化表格层输入形状操作输出形状输入层--[2, 59]词嵌入[2, 59]词索引→300 维向量[2, 59, 300]BiLSTM[2, 59, 300]双向 LSTM隐藏层 128[2, 59, 256]Dropout[2, 59, 256]随机失活[2, 59, 256]对位相乘[2, 59, 256][2, 59]mask广播 逐元素相乘padding 置 0[2, 59, 256]线性层[2, 59, 256]256→12 维线性变换[2, 59, 12]关键补充为什么要做「对位相乘」这一步的核心目的是屏蔽 padding 部分模型对 padding 位置也会输出特征但这些是无效的通过attention_mask的 0 值和这些特征做对位相乘直接把无效位置的特征清 0这样后续计算 loss 或做预测时就不会被 padding 部分干扰五、BILSTM实现NER总共有五个超参需要设置向量化维度、隐藏层维度、随机失活比例、字符数量、标签数量import torch import torch.nn as nn class NERLSTM(nn.Module): def __init__(self, embedding_dim, hidden_dim, dropout, word2id, tag2id): super(NERLSTM, self).__init__() self.name BiLSTM self.embedding_dim embedding_dim self.hidden_dim hidden_dim self.vocab_size len(word2id) self.tag_size len(tag2id) self.word_embeds nn.Embedding(self.vocab_size, self.embedding_dim) self.dropout nn.Dropout(dropout) self.lstm nn.LSTM(self.embedding_dim, self.hidden_dim // 2, bidirectionalTrue, batch_firstTrue) self.hidden2tag nn.Linear(self.hidden_dim, self.tag_size) def forward(self, x, mask): embedding self.word_embeds(x) outputs, hidden self.lstm(embedding) outputs outputs * mask.unsqueeze(-1) # 仅保留有效位置的输出 outputs self.dropout(outputs) outputs self.hidden2tag(outputs) return outputs

更多文章