1. 项目概述
这个教程将带您使用Matlab实现一个结合LSTM和Multihead Attention机制的文本分类模型。作为序列建模的黄金搭档,LSTM擅长捕捉长距离依赖关系,而Attention机制则能自动聚焦关键信息。我们将从原理到代码实现完整走一遍流程,特别适合刚接触深度学习的新手朋友。
文本分类是NLP的基础任务,应用场景非常广泛:
- 电商评论情感分析(正向/负向)
- 新闻稿件自动归类(政治/经济/体育)
- 工单内容分类(技术问题/账单问题/售后服务)
- 邮件自动分拣(重要/推广/垃圾邮件)
传统方法依赖人工特征工程,而LSTM+Attention的组合可以自动学习文本特征和关键信息。Matlab的深度学习工具箱提供了非常友好的接口,即使没有Python基础也能快速上手。
2. 核心组件解析
2.1 LSTM网络原理
长短期记忆网络(LSTM)是RNN的改进版本,通过三个门控机制(输入门、遗忘门、输出门)解决梯度消失问题。其核心公式如下:
code复制遗忘门:f_t = σ(W_f·[h_{t-1}, x_t] + b_f)
输入门:i_t = σ(W_i·[h_{t-1}, x_t] + b_i)
候选记忆:C̃_t = tanh(W_C·[h_{t-1}, x_t] + b_C)
记忆更新:C_t = f_t * C_{t-1} + i_t * C̃_t
输出门:o_t = σ(W_o·[h_{t-1}, x_t] + b_o)
隐状态:h_t = o_t * tanh(C_t)
在Matlab中,我们使用lstmLayer函数创建:
matlab复制numHiddenUnits = 100; % 隐层神经元数量
lstmLayer(numHiddenUnits,'OutputMode','last')
2.2 Multihead Attention机制
Attention机制的核心是计算Query和Key的相似度,然后对Value加权求和。Multihead版本则并行多个Attention头,捕获不同子空间的语义信息。
计算过程分为四步:
- 线性变换得到Q、K、V
- 计算Scaled Dot-Product Attention
- 多头结果拼接
- 最终线性变换
在Matlab中实现时,我们可以使用dlarray和自定义层:
matlab复制function Z = attention(Q, K, V)
d_k = size(K,1);
scores = (Q * K') / sqrt(d_k);
weights = softmax(scores);
Z = weights * V;
end
3. 数据准备与预处理
3.1 数据集加载
我们使用工厂工单报告数据集,包含描述文本和对应的分类标签:
matlab复制filename = "factoryReports.csv";
data = readtable(filename,'TextType','string');
head(data)
典型数据格式:
| Description | Category |
|---|---|
| "Items stuck in scanner" | Mechanical |
| "Loud noises from piston" | Mechanical |
| "Power cuts when starting" | Electronic |
3.2 文本预处理流程
完整的文本预处理管道:
matlab复制function docs = preprocessText(textData)
docs = tokenizedDocument(textData); % 分词
docs = lower(docs); % 转小写
docs = erasePunctuation(docs); % 移除标点
docs = removeStopWords(docs); % 移除停用词
docs = normalizeWords(docs); % 词形归一化
end
3.3 序列填充与截断
为保证输入长度一致,我们需要设置固定序列长度:
matlab复制sequenceLength = 100;
XTrain = doc2sequence(enc,documentsTrain,...
'Length',sequenceLength,...
'PaddingDirection','left',...
'PaddingValue',0);
提示:建议先分析文本长度分布,选择覆盖90%样本的长度值
4. 模型构建与训练
4.1 网络架构设计
完整的模型架构代码:
matlab复制inputSize = 1;
embeddingDim = 128;
numHeads = 4;
numHiddenUnits = 100;
layers = [
sequenceInputLayer(inputSize)
wordEmbeddingLayer(embeddingDim,vocabSize)
% LSTM部分
lstmLayer(numHiddenUnits,'OutputMode','sequence')
% Multihead Attention
functionLayer(@(x) multiheadAttention(x,numHeads),...
'Formattable',true)
% 分类头
globalAveragePooling1dLayer
fullyConnectedLayer(numClasses)
softmaxLayer
classificationLayer];
4.2 自定义Attention层实现
Multihead Attention核心函数:
matlab复制function output = multiheadAttention(input,numHeads)
[d_model, seq_len, batchSize] = size(input);
d_k = d_model / numHeads;
% 初始化权重
persistent Wq Wk Wv Wo;
if isempty(Wq)
Wq = dlarray(randn(d_model,d_model));
Wk = dlarray(randn(d_model,d_model));
Wv = dlarray(randn(d_model,d_model));
Wo = dlarray(randn(d_model,d_model));
end
% 线性变换
Q = pagemtimes(Wq, input);
K = pagemtimes(Wk, input);
V = pagemtimes(Wv, input);
% 分头处理
Q = reshape(Q,[d_k,numHeads,seq_len,batchSize]);
K = reshape(K,[d_k,numHeads,seq_len,batchSize]);
V = reshape(V,[d_k,numHeads,seq_len,batchSize]);
% 计算Attention
scores = pagemtimes(permute(Q,[2 1 3 4]), permute(K,[2 3 1 4])) / sqrt(d_k);
weights = softmax(scores, 'DataFormat', 'SSTUB');
output = pagemtimes(weights, permute(V,[2 3 1 4]));
% 合并多头输出
output = permute(output,[3 1 2 4]);
output = reshape(output,[d_model,seq_len,batchSize]);
output = pagemtimes(Wo, output);
end
4.3 训练配置与执行
训练参数设置建议:
matlab复制options = trainingOptions('adam',...
'MaxEpochs',15,...
'MiniBatchSize',32,...
'Shuffle','every-epoch',...
'ValidationData',{XValidation,YValidation},...
'Plots','training-progress',...
'LearnRateSchedule','piecewise',...
'LearnRateDropFactor',0.5,...
'LearnRateDropPeriod',5);
开始训练:
matlab复制net = trainnet(XTrain,YTrain,layers,"crossentropy",options);
5. 模型评估与优化
5.1 性能评估指标
建议计算以下指标:
matlab复制% 预测结果
YPred = classify(net,XValidation);
% 混淆矩阵
figure
confusionchart(YValidation,YPred)
% 分类报告
metrics = struct(...
'Accuracy', mean(YPred == YValidation),...
'Precision', @(c) sum(YPred==c & YValidation==c)/sum(YPred==c),...
'Recall', @(c) sum(YPred==c & YValidation==c)/sum(YValidation==c),...
'F1', @(c) 2*(metrics.Precision(c)*metrics.Recall(c))/(metrics.Precision(c)+metrics.Recall(c)));
5.2 常见问题排查
-
准确率低
- 检查嵌入维度是否足够(建议128-256)
- 增加LSTM单元数量(100-300)
- 尝试不同的Attention头数(4-8)
-
过拟合
- 添加Dropout层(rate=0.2-0.5)
- 使用L2正则化(lambda=0.001)
- 增加训练数据量
-
训练不稳定
- 减小学习率(初始0.001)
- 使用梯度裁剪('GradientThreshold'=1)
- 尝试不同的优化器(如'rmsprop')
6. 完整代码示例
matlab复制% 数据准备
data = readtable("factoryReports.csv",'TextType','string');
docsTrain = preprocessText(data.Description);
YTrain = categorical(data.Category);
% 创建词编码
enc = wordEncoding(docsTrain);
% 序列化
XTrain = doc2sequence(enc,docsTrain,'Length',100);
% 构建模型
inputSize = 1;
embeddingDim = 128;
numHeads = 4;
numHiddenUnits = 100;
numClasses = numel(categories(YTrain));
layers = [
sequenceInputLayer(inputSize)
wordEmbeddingLayer(embeddingDim,enc.NumWords)
lstmLayer(numHiddenUnits,'OutputMode','sequence')
functionLayer(@(x) multiheadAttention(x,numHeads),'Formattable',true)
globalAveragePooling1dLayer
fullyConnectedLayer(numClasses)
softmaxLayer
classificationLayer];
% 训练配置
options = trainingOptions('adam',...
'MaxEpochs',15,...
'MiniBatchSize',32,...
'ValidationData',{XValidation,YValidation},...
'Plots','training-progress');
% 开始训练
net = trainnet(XTrain,YTrain,layers,"crossentropy",options);
% 测试新数据
newText = "Machine makes grinding noise";
newDoc = preprocessText(newText);
XNew = doc2sequence(enc,newDoc,'Length',100);
label = classify(net,XNew);
disp("Predicted label: " + string(label));
7. 进阶优化建议
-
词嵌入优化
- 使用预训练词向量(如Word2Vec)
- 尝试不同的嵌入维度(50-300)
- 微调嵌入层权重
-
架构改进
- 堆叠多层LSTM(2-3层)
- 添加残差连接
- 使用双向LSTM
-
超参数调优
matlab复制hyperparameters = struct(... 'InitialLearnRate', [1e-4, 1e-3],... 'NumHiddenUnits', [50, 100, 200],... 'EmbeddingDim', [64, 128, 256]); -
部署考虑
- 使用MATLAB Compiler生成独立应用
- 通过MATLAB Production Server部署为API
- 转换为ONNX格式供其他平台使用
这个项目展示了如何将前沿的深度学习技术应用于实际文本分类任务。通过调整模型结构和参数,您可以将其适配到各种不同的应用场景。建议从简单配置开始,逐步增加复杂度,同时密切监控验证集性能。
