如何将三维数组序列输入到LSTM模型中?
问题解答:韩语文本形态素拆分后输入LSTM的实现方案
可行性说明
完全可行。韩语作为黏着语,将单词拆分为形态素(如나는拆为['나','는'])的预处理方式,能让模型捕捉更细粒度的语言特征,而LSTM天生适配序列数据,只要将三维数组调整为符合PyTorch LSTM的输入格式即可。
原代码问题与修改方案
基础错误修正
原代码中类定义为Tagger,但super调用时写的是WordTagger,这会导致运行报错,需修正为super(Tagger, self).__init__()。
输入维度适配与代码修改
PyTorch的nn.LSTM支持两种输入格式:
- 默认格式:
(seq_len, batch_size, input_size) - 开启
batch_first=True时:(batch_size, seq_len, input_size)
针对你的三维输入数组(num_word_groups, num_morphemes_per_group, embedding_dim),提供两种处理思路的代码实现:
思路1:先编码词素组内部序列,再处理词素组序列
适合以单词为单位的任务(如词性标注、文本分类),先对每个词素组内的形态素序列编码,得到单词级表示后再输入上层LSTM:
import torch import torch.nn as nn import torch.nn.functional as F class Tagger(nn.Module): def __init__(self, embedding_dim=43, n_layers=4, dropout=0.2, output_dim=11, bidirectional=False): super(Tagger, self).__init__() # 修正类名不一致问题 # 编码词素组内部的形态素序列 self.morph_lstm = nn.LSTM(embedding_dim, embedding_dim, num_layers=1, bidirectional=bidirectional, batch_first=True) # 编码词素组构成的单词序列 self.word_lstm = nn.LSTM( embedding_dim * 2 if bidirectional else embedding_dim, embedding_dim * 2 if bidirectional else embedding_dim, num_layers=n_layers-1, bidirectional=bidirectional, batch_first=True ) self.hidden_dim = (embedding_dim * 2) if bidirectional else embedding_dim self.linear = nn.Linear(self.hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, embedded): # embedded输入维度: (batch_size, 词素组数量, 每组词素数, embedding_dim) batch_size, num_groups, num_morphemes, emb_dim = embedded.shape # 重塑为批量处理每个词素组的格式 morph_embedded = embedded.view(-1, num_morphemes, emb_dim) # 获取词素组的最后一个时间步输出作为单词表示 morph_out, _ = self.morph_lstm(morph_embedded) group_rep = morph_out[:, -1, :] # 重塑回词素组序列格式 group_rep = group_rep.view(batch_size, num_groups, -1) # 处理词素组序列并输出结果 lstmed, _ = self.word_lstm(self.dropout(group_rep)) outputs = self.linear(self.dropout(lstmed)) scores = F.log_softmax(outputs, dim=-1) return scores
思路2:将所有词素展开为一维序列输入
适合以形态素为单位的任务(如形态素标注),直接将所有词素按顺序展开为长序列输入LSTM:
import torch import torch.nn as nn import torch.nn.functional as F class Tagger(nn.Module): def __init__(self, embedding_dim=43, n_layers=4, dropout=0.2, output_dim=11, bidirectional=False): super(Tagger, self).__init__() # 修正类名错误 self.lstm = nn.LSTM(embedding_dim, embedding_dim, num_layers=n_layers, bidirectional=bidirectional, batch_first=True) self.hidden_dim = (embedding_dim * 2) if bidirectional else embedding_dim self.linear = nn.Linear(self.hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, embedded): # embedded输入维度: (batch_size, 词素组数量, 每组词素数, embedding_dim) batch_size, num_groups, num_morphemes, emb_dim = embedded.shape # 展开为一维形态素序列 flat_embedded = embedded.view(batch_size, -1, emb_dim) # 处理序列并输出结果 lstmed, _ = self.lstm(self.dropout(flat_embedded)) outputs = self.linear(self.dropout(lstmed)) scores = F.log_softmax(outputs, dim=-1) return scores
补充说明
- 若为单样本输入(无batch维度),需先用
embedded.unsqueeze(0)添加batch维度,将(词素组数量, 每组词素数, embedding_dim)转换为(1, 词素组数量, 每组词素数, embedding_dim)。 - 针对变长词素组(如有的组2个词素、有的组4个词素),建议使用
torch.nn.utils.rnn.pack_padded_sequence处理,避免padding引入噪声。
内容的提问来源于stack exchange,提问作者HanGoil
相关产品推荐
相关产品推荐

