基于深度学习的多标签文本分类
此示例演示如何对具有多个独立标签的文本数据进行分类。
对于分类任务,对于每个观察都可以有多个独立的标签——例如,一篇科学文章上的标签——您可以训练一个深度学习模型来预测每个独立类别的概率。为了使网络能够学习多标签分类目标,可以使用二进制交叉熵损失来独立优化每个类的损失。
这个例子定义了一个深度学习模型,它根据使用arXiv API[1]收集的数学论文摘要对主题领域进行分类。该模型由单词嵌入和GRU、最大池化操作、完全连接和sigmoid操作组成。
为了衡量多标签分类的性能,可以使用标签f得分[2]。标记f评分通过关注具有部分匹配的文本分类来评估多标签分类。该度量是匹配标签的归一化比例相对于真实和预测标签的总数。
这个例子定义了以下模型:
一种将单词序列映射到数字向量序列的单词嵌入。
学习嵌入向量之间依赖关系的GRU操作。
一种最大池化操作,它将特征向量序列减少为单个特征向量。
将特征映射到二进制输出的完全连接层。
用于学习输出和目标标签之间的二元交叉熵损失的sigmoid运算。
此图显示了通过模型体系结构传播的一段文本,并输出一个概率向量。这些概率是独立的,所以它们的和不一定等于1。
导入文本数据
使用arXiv API从数学论文中导入一组摘要和类别标签。方法指定要导入的记录数importSize
变量。
importSize = 50000;
创建一个使用set查询记录的URL“数学”
和元数据的前缀“arXiv”
.
url =“https://export.arxiv.org/oai2?verb=ListRecords”+...“集=数学”+...“&metadataPrefix = arXiv”;
方法提取查询URL返回的摘要文本、类别标签和恢复令牌parseArXivRecords
函数,该函数作为支持文件附加到本示例中。要访问此文件,请将此示例作为实时脚本打开。注意arXiv API是有速率限制的,需要在多个请求之间等待。
[textData, labelsAll resumptionToken] = parseArXivRecords (url);
迭代地导入更多的记录块,直到达到所需的数量,或者没有更多的记录。要从您停止的地方继续导入记录,请在查询URL中使用前一个结果的恢复令牌。方法执行arXiv API施加的速率限制,在每次查询之前添加20秒延迟暂停
函数。
而元素个数(textData) < importSize如果resumptionToken = =""打破结束url =“https://export.arxiv.org/oai2?verb=ListRecords”+..." &resumptionToken = "+ resumptionToken;pause(20) [textDataNew,labelsNew,resumptionToken] = parseArXivRecords(url);textData = [textData;textDataNew];labelsAll = [labelsAll;labelsNew];结束
预处理文本数据
方法对文本数据进行标记和预处理preprocessText
函数,在示例末尾列出。
documentsAll = preprocessText (textData);documentsAll (1:5)
ans = 5×1 tokenizedDocument: 72 token:描述新算法$(k,\ell)$ pebble游戏颜色获取表征族$(k,\ell)$稀疏图算法解关于树分解图的家族问题特殊实例稀疏图出现刚性理论近年来受到越来越多的关注特殊彩色鹅卵石推广加强先前的结果lee streinu给出新证明tuttenashwilliams表征树性提出新的分解证明稀疏性基$(k,\ell)$ pebble游戏颜色工作暴露连接pebble博弈算法前稀疏图算法gabow gabow westermann hendrickson 22个令牌:显示行列式斯特林循环数计数无标记无环单源自动机证明涉及双射自动机某些标记格点路径信号可逆对合计算计算行列式18个令牌:论文显示计算$\lambda_{\alpha}$ norm alpha并格结果结果描述hardy空间$h^p(r^n)$ term并格特殊原子62个令牌:偏立方等距子图超立方结构图定义平均半立方djokovi winklers关系起重要作用理论偏立方结构本文描述偏立方图偏立方任意维新表征建立新证明知道结果给出运算笛卡尔积粘贴展开收缩过程利用本文构造新的偏立方旧的特等距格维有限偏立方得到平均运算计算29令牌:论文提出算法计算hecke本征系统hilbertsiegel cusp形式实二次域窄类数给出举例二次域$\q(\sqrt{5})$举例识别hilbertsiegel本征形式可能提升Hilbert本征形式
删除标签不属于“数学”
集。
为i = 1:numel(labelsAll) labelsAll{i} = labelsAll{i}(startwith (labelsAll{i},“数学。”));结束
在词云中可视化一些类。找到对应的文档如下:
带有“组合学”标记的摘要和没有标记的摘要
“统计理论”
有“统计理论”标签的摘要和没有标签的摘要
“组合”
带有这两种标记的抽象
“组合”
而且“统计理论”
方法查找每个组的文档索引ismember
函数。
idxCO = cellfun(@(lbls) ismember(“数学。有限公司”lbls) & & ~ ismember (“数学。圣”lbls) labelsAll);idxST = cellfun(@(lbls)“数学。圣”lbls) & & ~ ismember (“数学。有限公司”lbls) labelsAll);= cellfun(@(lbls) ismember(“数学。有限公司”lbls) & & ismember (“数学。圣”lbls) labelsAll);
在字云中可视化每个组的文档。
图次要情节(1、3、1)wordcloud (documentsAll (idxCO));标题(“组合”次要情节(1、3、2)wordcloud (documentsAll (idxST));标题(“统计理论”次要情节(1,3,3)wordcloud (documentsAll (idxCOST));标题(“两个”)
查看类的数量。
一会=独特(猫(labelsAll {:}));numClasses =元素个数(类名)
numClasses = 32
使用直方图可视化每个文档标签的数量。
labelCounts = cellfun (@numel labelsAll);图直方图(labelCounts)包含(“标签”) ylabel (“频率”)标题(”标签项”)
为深度学习准备文本数据
方法将数据划分为训练和验证分区cvpartition
函数。保留10%的数据以进行验证坚持
选择0.1。
本量利= cvpartition(元素个数(documentsAll),坚持= 0.1);documentsTrain = documentsAll(培训(cvp));documentsValidation = documentsAll(测试(cvp));labelsTrain = labelsAll(培训(cvp));labelsValidation = labelsAll(测试(cvp));
创建一个单词编码对象,将训练文档编码为单词索引序列。参数指定5000个单词的词汇表订单
选项“频率”
,MaxNumWords
选项5000
.
内附= wordEncoding (documentsTrain、订单=“频率”MaxNumWords = 5000)
enc = wordcoding with properties: NumWords: 5000词汇:[1×5000 string]
为了改进培训,可以使用以下技巧:
在训练时,将文档截短到可以减少填充量且不会丢弃太多数据的长度。
用按长度升序排序的文档训练一个历元,然后在每个历元打乱数据。这种技术被称为sortagrad.
要选择用于截断的序列长度,请在直方图中可视化文档长度,并选择捕获大部分数据的值。
documentLengths = doclength (documentsTrain);图直方图(documentLengths)包含(“文档长度”) ylabel (“频率”)标题(“文档长度”)
大多数培训文档的令牌少于175个。使用175记号作为截断和填充的目标长度。
maxSequenceLength = 175;
要使用sortagrad技术,请按长度升序对文档进行排序。
[~, idx] = (documentLengths)进行排序;documentsTrain = documentsTrain (idx);labelsTrain = labelsTrain (idx);
定义和初始化模型参数
为每个操作定义参数,并将它们包含在结构中。使用格式parameters.OperationName.ParameterName
,在那里参数
是结构,哦perationName
操作的名称(例如“俱乐部”
),ParameterName
参数的名称(例如,“重量”
).
创建一个结构体参数
包含模型参数。初始偏差为零。对这些操作使用以下权值初始化式:
方法初始化权重
initializeGaussian
函数。对于GRU操作,使用
initializeGlorot
而且initializeZeros
函数,分别。方法初始化权重和偏差
initializeGaussian
而且initializeZeros
函数,分别。
初始化函数initializeGlorot
,initializeGaussian
,initializeZeros
作为支持文件附加到示例中。要访问这些函数,请将示例作为实时脚本打开。
初始化嵌入的可学习参数。
embeddingDimension = 300;numHiddenUnits = 250;inputSize = en . numwords + 1;参数=结构;sz = [embeddingDimension inputSize];μ= 0;σ= 0.01;parameters.emb.Weights = initializeGaussian (sz、μ、σ);
初始化GRU操作的可学习参数。
sz = [3*numHiddenUnits embeddingDimension];numOut = 3 * numHiddenUnits;numIn = embeddingDimension;parameters.gru.InputWeights = initializeGlorot(深圳、numOut numIn);sz = [3*numHiddenUnits];numOut = 3 * numHiddenUnits;numIn = numHiddenUnits;parameters.gru.RecurrentWeights = initializeGlorot(深圳、numOut numIn);sz = [3*numHiddenUnits 1];parameters.gru.Bias = initializeZeros(深圳);
初始化完全连接操作的可学习参数。
sz = [numClasses numHiddenUnits];μ= 0;σ= 0.01;parameters.fc.Weights = initializeGaussian (sz、μ、σ);sz = [numClasses 1];parameters.fc.Bias = initializeZeros(深圳);
查看参数
结构体。
参数
参数=结构体字段:Emb: [1×1 struct] gru: [1×1 struct] fc: [1×1 struct]
查看GRU操作的相关参数。
parameters.gru
ans =结构体字段:InputWeights: [750×300 dlarray] RecurrentWeights: [750×250 dlarray] Bias: [750×1 dlarray]
定义模型函数
创建函数模型
,它计算前面描述的深度学习模型的输出。这个函数模型
将输入数据和模型参数作为输入。网络输出对标签的预测。
定义模型损失函数
创建函数modelLoss
,它以输入数据的小批和相应的目标作为输入,并返回损耗、损耗相对于可学习参数的梯度和网络输出。
指定培训选项
训练5个周期,小批次大小为256。
numEpochs = 5;miniBatchSize = 256;
使用Adam优化器进行训练,学习率为0.01,并指定梯度衰减和梯度衰减因子的平方分别为0.5和0.999。
learnRate = 0.01;gradientDecayFactor = 0.5;squaredGradientDecayFactor = 0.999;
用阈值1 using剪辑渐变 标准梯度剪裁。
gradientThreshold = 1;
若要将概率向量转换为标签,请使用概率高于指定阈值的标签。指定标签阈值为0.5。
labelThreshold = 0.5;
每个时代验证网络。
numObservationsTrain =元素个数(documentsTrain);numIterationsPerEpoch =地板(numObservationsTrain / miniBatchSize);validationFrequency = numIterationsPerEpoch;
火车模型
初始化训练进度图。为f值和损失创建动画线。
图C = colororder;subplot(2,1,1) lineFScoreTrain = animatedline(Color=C(1,:));lineFScoreValidation = animatedline (...线型=”——“,...标志=“o”,...MarkerFaceColor =“黑色”);ylim([0 1])包含(“迭代”) ylabel (“标签f值”网格)在subplot(2,1,2) lineLossTrain = animatedline(Color=C(2,:));lineLossValidation = animatedline (...线型=”——“,...标志=“o”,...MarkerFaceColor =“黑色”);ylim([0正])包含(“迭代”) ylabel (“损失”网格)在
初始化Adam优化器的参数。
trailingAvg = [];trailingAvgSq = [];
准备验证数据。创建一个单热编码矩阵,其中非零项对应每个观察的标签。
numObservationsValidation =元素个数(documentsValidation);TValidation = zero (numClasses, numObservationsValidation,“单身”);为i = 1:numObservationsValidation [~,idx] = ismember(labelsValidation{i},classNames);TValidation (idx,我)= 1;结束
使用自定义训练循环训练模型。
对于每个epoch,循环小批量的数据。在每个历元结束时,打乱数据。在每次迭代结束时,更新训练进度图。
为每个mini-batch:
将文档转换为单词索引序列,并将标签转换为虚拟变量。
将序列转换为
dlarray
对象的基础类型为单一,并指定维度标签“BTC”
(批量、时间、通道)。如果有GPU,请使用GPU进行训练。这需要并行计算工具箱™。使用GPU需要并行计算工具箱™和支持的GPU设备。有关支持的设备的信息,请参见GPU计算的需求(并行计算工具箱).
GPU训练,转换为
gpuArray
对象。评估模型损失和梯度
dlfeval
和modelLoss
函数。剪辑的梯度。
更新网络参数
adamupdate
函数。方法验证网络(如有必要)
modelPredictions
函数,在示例末尾列出。更新训练情节。
迭代= 0;开始=抽搐;循环遍历各个时代。为时代= 1:numEpochs在小批量上循环。为i = 1:numIterationsPerEpoch迭代=迭代+ 1;idx =(张)* miniBatchSize + 1:我* miniBatchSize;读取小批量数据,并将标签转换为虚拟%变量。文件= documentsTrain (idx);标签= labelsTrain (idx);将文档转换为序列。len = min (maxSequenceLength马克斯(doclength(文档)));X = doc2sequence (enc、文档...PaddingValue = inputSize,...长度= len);X =猫(1,X {:});% Dummify标签。T = 0 (numClasses miniBatchSize,“单身”);为j = 1:miniBatchSize [~,idx2] = ismember(labels{j},classNames);T (idx2 j) = 1;结束将小批量数据转换为dlarray。X = dlarray (X,“BTC”);如果在GPU上训练,那么将数据转换为GPU array。如果canUseGPU X = gpuArray(X);结束评估模型损失,梯度和预测使用dlfeval和% modelLoss函数。(损失、渐变Y) = dlfeval (@modelLoss X T参数);%梯度剪裁。gradient = dlupdate(@(g) thresholdL2Norm(g,gradientThreshold),gradient);使用Adam优化器更新网络参数。(参数、trailingAvg trailingAvgSq) = adamupdate(参数、渐变...learnRate trailingAvg trailingAvgSq,迭代,...gradientDecayFactor squaredGradientDecayFactor);显示培训进度。subplot(2,1,1) D = duration(0,0,toc(start),Format=“hh: mm: ss”);标题(”时代:“+时代+”,过去:“+字符串(D))%的损失。=双重损失(损失);addpoints (lineLossTrain、迭代、失去)% f值标签。Y = Y > labelThreshold;分数= labelingFScore (Y, T);addpoints (lineFScoreTrain、迭代、双(收集(分数)))drawnow%显示验证指标。如果迭代== 1 || mod(迭代,validationFrequency) == 0 YValidation = modelprediction (parameters,enc,documentsValidation,miniBatchSize,maxSequenceLength);%的损失。lossValidation = crossentropy (YValidation TValidation,...TargetCategories =“独立”,...DataFormat =“CB”);lossValidation =双(lossValidation);addpoints (lineLossValidation迭代,lossValidation)% f值标签。YValidation = YValidation > labelThreshold;分数= labelingFScore (YValidation TValidation);分数=双(分数);addpoints drawnow (lineFScoreValidation,迭代,分数)结束结束%洗牌数据。idx = randperm (numObservationsTrain);documentsTrain = documentsTrain (idx);labelsTrain = labelsTrain (idx);结束
测试模型
要对一组新数据进行预测,请使用modelPredictions
函数,在示例末尾列出。的modelPredictions
函数将模型参数、字编码和标记文档数组作为输入,并输出与指定的小批大小和最大序列长度对应的模型预测。
YValidation = modelPredictions(参数、内附documentsValidation、miniBatchSize maxSequenceLength);
为评估性能,计算标记f分使用labelingFScore
函数,在示例末尾列出。标记f评分通过关注具有部分匹配的文本分类来评估多标签分类。要将网络输出转换为标签数组,请查找得分高于指定标签阈值的标签。
= labelingFScore(YValidation > labelThreshold,TValidation)
分数=单0.5663
通过尝试阈值的一系列值并比较结果,查看标记阈值对标记f得分的影响。
用力推= linspace (0, 1, 10);分数= 0(大小(刺));为i = 1: numl (thr) YPredValidationThr = YValidation >= thr(i);分数(i) = labelingFScore (YPredValidationThr TValidation);结束图绘制(用力推,得分)参照线(labelThreshold,“r——”);包含(“阈值”) ylabel (“标签f值”)标题(“标签门槛的影响”)
可视化预测
为了可视化分类器的正确预测,计算真阳性的数量。真阳性是一个分类器的实例,它正确地预测了一个观察结果的特定类。
Y = YValidation > labelThreshold;T = TValidation;numtruepositive = sum(T & Y,2);numObservationsPerClass = (T, 2)之和;trueposiverates = numtruepositive ./ numObservationsPerClass;
在直方图中可视化每个类别的真实阳性数字。
figure truePositiveRates = extractdata(truePositiveRates);[~, idx] =排序(truePositiveRates,“下”);直方图(类别(idx) =类名,BinCounts = truePositiveRates (idx))包含(“类别”) ylabel (“真阳性率”)标题(“真正积极的利率”)
通过显示真阳性、假阳性和假阴性的分布,可视化分类器预测错误的实例。假阳性是分类器为观察结果分配一个特定的错误类的实例。假阴性是分类器未能为观察结果分配一个特定的正确类的实例。
创建一个混淆矩阵,显示真阳性、假阳性和假阴性计数:
对于每个类,在对角线上显示真正计数。
对于每一对类(我,j),显示误报的实例数j当实例也为假阴性时我.
即包含以下元素的混淆矩阵:
计算假阴性和假阳性。
falsennegative = T & ~Y;假阳性= ~T & Y;
计算非对角线元素。
falseNegatives = permute(falseNegatives,[3 2 1]);numconditionalfalse阳性= sum(假阴性和假阳性,2);numConditionalFalsePositives =挤压(numConditionalFalsePositives);tpfnMatrix = numConditionalFalsePositives;
将对角线元素设置为真正计数。
idxDiagonal = 1: numClasses + 1: numClasses ^ 2;tpfnMatrix (idxDiagonal) = numTruePositives;
在混淆矩阵中可视化真阳性和假阳性计数confusionchart
函数和排序矩阵,使对角线上的元素按降序排列。
图tpfnMatrix = extractdata(tpfnMatrix);厘米= confusionchart (tpfnMatrix,类名);sortClasses(厘米,“descending-diagonal”);标题(“真阳性,假阳性”)
要更详细地查看矩阵,请将此示例作为实时脚本打开,并在一个新窗口中打开该图。
文本预处理功能
的preprocessText
函数使用以下步骤对输入文本数据进行标记和预处理:
对文本进行标记
tokenizedDocument
函数。方法将数学方程提取为单个标记RegularExpressions
选项,通过指定正则表达式“\ $ * ?。\ $”
,它捕捉出现在两个“$”符号之间的文本。删除标点符号使用
erasePunctuation
函数。方法将文本转换为小写
较低的
函数。删除停止词使用
removeStopWords
函数。用动词来引理课文
normalizeWords
函数与风格
选项设置为“引理”
.
函数文件= preprocessText (textData)标记文本。regularExpressions =表;regularExpressions。模式=“\ $ * ?。\ $”;regularExpressions。类型=“方程”;文件= tokenizedDocument (textData RegularExpressions = RegularExpressions);%擦掉标点符号。= erasePunctuation文件(文档);%转换为小写。文件=低(文件);% Lemmatize。= addPartOfSpeechDetails文件(文档);文件= = normalizeWords(文档、风格“引理”);删除停止词。= removeStopWords文件(文档);删除短单词。文件= removeShortWords(文件,2);结束
模型函数
这个函数模型
接受输入数据作为输入X
和模型参数参数
,并返回标签的预测。
函数(X, Y =模型参数)%嵌入重量= parameters.emb.Weights;X =嵌入(X,重量);%格勒乌inputWeights = parameters.gru.InputWeights;recurrentWeights = parameters.gru.RecurrentWeights;偏见= parameters.gru.Bias;numHiddenUnits =大小(inputWeights, 1) / 3;hiddenState = dlarray(zero ([numHiddenUnits 1]));Y =格勒乌(X, hiddenState inputWeights recurrentWeights,偏差);%最大池化沿时间维度Y = max (Y, [], 3);%完全连接重量= parameters.fc.Weights;偏见= parameters.fc.Bias;Y = fullyconnect (Y,重量,偏差);% s形的Y =乙状结肠(Y);结束
损失函数模型
的modelLoss
函数接受一个小批量输入数据作为输入X
与相应的目标T
包含标签并返回损耗、损耗相对于可学习参数的梯度和网络输出。
函数[loss,gradient,Y] = model loss (X,T,parameters) Y = model(X,parameters);损失= crossentropy (Y, T, TargetCategories =“独立”);梯度= dlgradient(损失、参数);结束
模型的预测函数
的modelPredictions
函数将模型参数、字编码、标记文档数组、小批大小和最大序列长度作为输入,并通过在指定大小的小批上迭代返回模型预测。
函数Y = modelprediction (parameters,enc,documents,miniBatchSize,maxSequenceLength) inputSize = en . numwords + 1;numObservations =元素个数(文件);numIterations = ceil(numObservations / miniBatchSize);numFeatures =大小(parameters.fc.Weights, 1);Y = 0 (numFeatures numObservations,“喜欢”, parameters.fc.Weights);为i = 1:numIterations idx = (i-1)*miniBatchSize+1:min(i*miniBatchSize,numObservations);len = min (maxSequenceLength马克斯(doclength(文档(idx))));X = doc2sequence (enc,文档(idx),...PaddingValue = inputSize,...长度= len);X =猫(1,X {:});X = dlarray (X,“BTC”);Y (:, idx) =模型(X,参数);结束结束
标签f值函数
标记f评分函数[2]通过关注具有部分匹配的每文本分类来评估多标签分类。该度量是匹配标签的归一化比例相对于给出的真实和预测标签的总数
在哪里N而且C分别对应观察数和类数,和Y而且T分别对应预测和目标。
函数score = labelingFScore(Y,T) numObservations = size(T,2);scores = (2 * sum(Y .* T)) ./ sum(Y + T);score = sum(scores) / numObservations;结束
梯度剪切功能
的thresholdL2Norm
函数缩放输入梯度,使其
范数值等于指定的梯度阈值时
可学习参数梯度的范数值大于指定的阈值。
函数gradient = thresholdL2Norm(gradients,gradientThreshold) gradientNorm =根号(sum(gradients(:).^2));如果梯度阈值=梯度*(梯度阈值/梯度norm);结束结束
参考文献
出来了。“arXiv API”。2020年1月15日。https://arxiv.org/help/api
Sokolova, Marina,和Guy Lapalme。分类任务绩效指标的系统分析。信息处理与管理45岁的没有。4(2009): 427 - 437。
另请参阅
tokenizedDocument
(文本分析工具箱)|fullyconnect
|格勒乌
|dlupdate
|adamupdate
|dlarray
|dlfeval
|dlgradient
|wordEncoding
(文本分析工具箱)|doc2sequence
(文本分析工具箱)|extractHTMLText
(文本分析工具箱)|htmlTree
(文本分析工具箱)