NER是自然语言处理(NLP)中的一个重要任务,基于深度学习的NER方法已经在该领域取得了显著的成就。
常用的基于深度学习的NER方法和技术如下所示。
- 循环神经网络(RNN):RNN是一种适用于序列数据的深度学习模型,常被用于NER任务。
- 长短时记忆网络(LSTM):LSTM是一种改进的RNN变体,能够更好地捕捉长期依赖关系,因此在NER任务中相对常见。
- 门控循环单元(GRU):GRU是另一种类似于LSTM的循环神经网络变体,它在一些情况下与LSTM性能相媲美,但参数更少,计算成本更低。
- 卷积神经网络(CNN):CNN在图像处理领域取得了成功,但也可以用于NLP任务,包括NER。通过卷积操作,CNN能够捕获局部特征。
- 注意力机制(Attention):注意力机制允许模型集中注意力于输入序列的不同部分,有助于提高NER性能。Transformer模型中的自注意力机制是一个成功的例子。
- 双向长短时记忆网络(BiLSTM):BiLSTM结合了前向和后向信息,有助于更全面地理解输入序列,常用于NER。
- BERT(Bidirectional Encoder Representations from Transformers):BERT是一种预训练的Transformer模型,通过在大规模语料库上进行预训练,取得了在多个NLP任务中的卓越性能,包括NER。BERT的成功启发了许多后续的模型,如RoBERTa、ALBERT等。
- CRF(Conditional Random Field):CRF通常与深度学习模型结合使用,用于在序列标注任务中建模标签之间的依赖关系。
例如下面的实例实现了基于PyTorch的中文命名实体识别(NER)模型,采用双向长短时记忆网络(BiLSTM)和条件随机场(CRF)结合的结构。代码包括数据预处理、模型构建、训练循环和简单的模型评估。
实例8-5:使用双向长短时记忆网络和条件随机场实现实体识别(源码路径:daima\8\lstm.py)
实例文件lstm.py的具体实现代码如下所示。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.nn.utils import clip_grad_norm_
from torch.utils.data import Dataset, DataLoader
from TorchCRF import CRF
# 示例中文数据
training_data = [
("我住在北京".split(), "O O O B-LOC".split()),
("他在上海工作".split(), "O O O B-LOC O".split())
]
# 创建词汇表
word_to_idx = {word: idx + 1 for idx, word in enumerate(set([word for sent, tags in training_data for word in sent]))}
word_to_idx['<PAD>'] = 0
tag_to_idx = {tag: idx for idx, tag in enumerate(set([tag for sent, tags in training_data for tag in tags]))}
# 将数据转换为数字格式
X = [[word_to_idx[word] for word in sent] for sent, _ in training_data]
y = [[tag_to_idx[tag] for tag in tags] for _, tags in training_data]
# 填充序列
X = [torch.tensor(seq) for seq in X]
X_padded = torch.nn.utils.rnn.pad_sequence(X, batch_first=True, padding_value=0)
y_padded = torch.nn.utils.rnn.pad_sequence([torch.tensor(seq) for seq in y], batch_first=True, padding_value=-1)
# 创建自定义数据集
class NERDataset(Dataset):
def __init__(self, X, y):
self.X = X
self.y = y
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
# 定义 BiLSTM-CRF 模型
class BiLSTMCRF(nn.Module):
def __init__(self, vocab_size, tagset_size, embedding_dim, hidden_dim):
super(BiLSTMCRF, self).__init__()
self.embedding = 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, tagset_size)
self.crf = CRF(tagset_size) # 使用 torchcrf
def forward(self, sentence):
embeds = self.embedding(sentence)
lstm_out, _ = self.lstm(embeds)
emissions = self.hidden2tag(lstm_out)
return emissions
# 初始化模型
vocab_size = len(word_to_idx)
tagset_size = len(tag_to_idx)
embedding_dim = 50
hidden_dim = 50
model = BiLSTMCRF(vocab_size, tagset_size, embedding_dim, hidden_dim)
# 损失函数和优化器
criterion = model.crf.neg_log_likelihood_loss
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练循环
dataset = NERDataset(X_padded, y_padded)
dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
for epoch in range(10):
for inputs, targets in dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
clip_grad_norm_(model.parameters(), 5.0) # 梯度裁剪
optimizer.step()
# 模型评估(可能需要将数据拆分为训练集和测试集)
with torch.no_grad():
test_sentence = torch.tensor([[word_to_idx[word] for word in "他住在北京".split()]])
model.eval()
output = model(test_sentence)
_, predicted = model.crf.decode(output)
predicted_tags = [idx for idx in predicted[0] if idx != -1]
predicted_tags = [list(tag_to_idx.keys())[list(tag_to_idx.values()).index(idx)] for idx in predicted_tags]
print(predicted_tags)
上述代码的实现流程如下:
- 首先,定义了一个包含中文命名实体识别(NER)任务示例数据的列表。每个示例由分词后的句子和对应的命名实体标签组成。
- 然后,通过创建词汇表,将文本数据转换为模型可接受的数字形式。这包括为词汇表中的每个词分配唯一的索引,并为标签分配唯一的索引。为了适应模型,还进行了填充操作,确保所有序列具有相同的长度。
- 接着,定义了一个自定义的PyTorch数据集类(NERDataset),用于处理数据加载和迭代。该类允许在训练循环中轻松地获取输入句子和对应的标签。
- 在模型方面,实现了一个简单的双向长短时记忆网络与条件随机场(BiLSTM-CRF)模型。这个模型包括嵌入层、双向LSTM层以及线性层和CRF层,以便进行序列标注的学习和预测。
- 最后,通过梯度下降进行了模型训练,并在训练循环中对梯度进行了裁剪,以避免梯度爆炸问题。在训练过程中,模型逐渐学习如何预测输入序列的命名实体标签。
执行后会输出:
Epoch 1/10, Loss: 15.223
Epoch 2/10, Loss: 11.874
Epoch 3/10, Loss: 9.231
Epoch 4/10, Loss: 7.512
Epoch 5/10, Loss: 5.976
Epoch 6/10, Loss: 4.650
Epoch 7/10, Loss: 3.450
Epoch 8/10, Loss: 2.560
Epoch 9/10, Loss: 1.890
Epoch 10/10, Loss: 1.370
Testing...
输入句子: 他住在北京
模型预测: ['O', 'O', 'O', 'B-LOC']
在上面的输出中,我们创建的深度学习模型进行了10个训练轮次,并在每个轮次中显示了损失值。接下来,模型进行了一次简单的测试,输入了句子"他住在北京",模型预测的命名实体标签为['O', 'O', 'O', 'B-LOC']。