这个例子展示了如何训练一个深度学习模型来使用注意力进行图像字幕。
大多数预训练的深度学习网络配置为单标签分类。例如,给定一张典型的办公桌的图像,网络可能预测单一类别的“键盘”或“鼠标”。相比之下,图像字幕模型结合了卷积和循环操作来生成图像内容的文本描述,而不是单个标签。
本例中训练的模型使用编码器-解码器体系结构。该编码器是一个预先训练的Inception-v3网络,用作特征提取器。该解码器采用递归神经网络(RNN),将提取的特征作为输入,生成标题。解码器包含一个注意机制这允许解码器在生成标题时专注于已编码的输入部分。
编码器模型是一个预先训练的Inception-v3模型,它从“mixed10”
层,然后是完全连接和ReLU操作。
该解码器模型由词嵌入、注意机制、门控循环单元(GRU)和两个完全连接的操作组成。
加载预训练的Inception-v3网络。此步骤需要深度学习工具箱™ 模型对于Inception-v3网络金宝app支持包。如果您没有安装所需的支持包,那么该软件将提供下载链接。金宝app
网= inceptionv3;inputSizeNet = net.Layers (1) .InputSize;
将网络转换为dlnetwork
对象的特征提取和删除最后四层,留下“mixed10”
层作为最后一层。
lgraph = layerGraph(净);lgraph = removeLayers (lgraph, (“avg_pool”“预测”“predictions_softmax”“ClassificationLayer_predictions”]);
查看网络的输入层。Inception-v3网络使用对称缩放归一化,最小值为0,最大值为255。
lgraph.Layers (1)
ans = ImageInputLayer with properties: Name: 'input_1' InputSize: [299 299 3] Hyperparameters DataAugmentation: 'none' Normalization: ' scale-symmetric' NormalizationDimension: 'auto' Max: 255 Min: 0
自定义训练不支持这种归一化,因此必须在网络中禁用归金宝app一化,而在自定义训练循环中执行归一化。将最小值和最大值保存为所命名变量的双精度inputMin
和输入最大值
,将输入层替换为不规格化的图像输入层。
inputMin =双(lgraph.Layers (1) .Min);inputMax =双(lgraph.Layers (1) .Max);层= imageInputLayer (inputSizeNet,“归一化”,“没有”,“名字”,“输入”);lgraph = replaceLayer (lgraph,“input_1”层);
确定网络的输出大小。使用analyzeNetwork
函数查看最后一层的激活大小。深度学习网络分析仪显示了网络的一些问题,这些问题可以在定制培训工作流中安全地忽略。
analyzeNetwork (lgraph)
创建一个名为输出SizeNet
包含网络输出大小。
outputSizeNet = [8 8 2048];
将层图转换为dlnetwork
对象并查看输出层。输出层是“mixed10”
初始化v3网络的一层。
dlnet = dlnetwork (lgraph)
dlnet = dlnetwork with properties: Layers: [311×1 net.cnn.layer. layer] Connections: [345×2 table] Learnables: [376×3 table] State: [188×3 table] InputNames: {'input'} OutputNames: {'mixed10'}
从数据集“2014 Train images”和“2014 Train/val annotation”分别下载图片和注释https://cocodataset.org/#download.将图像和注释提取到一个名为“可可”
.COCO 2014数据集由可可财团.
从文件中提取标题“captions_train2014.json”
使用jsondecode
函数。
dataFolder = fullfile (tempdir,“可可”);文件名= fullfile (dataFolder,“annotations_trainval2014”,“注释”,“captions_train2014.json”);str = fileread(文件名);data = jsondecode (str)
资料=带字段的结构:[1×1 struct] images: [82783×1 struct] licenses: [8×1 struct] annotation: [414113×1 struct]
的注释
结构体的字段包含图像标题所需的数据。
data.annotations
ans =414113×1带有字段的结构数组:image_id id标题
数据集包含每个图像的多个标题。为确保在训练集和验证集中不会出现相同的图像,请使用独特的
函数中的idimage_id
字段,然后查看唯一图像的数量。
numObservationsAll =元素个数(data.annotations)
numObservationsAll = 414113
imageid = [data.annotations.image_id];imageIDsUnique =独特(imageid);numUniqueImages =元素个数(imageIDsUnique)
numUniqueImages = 82783
每张图片至少有5个说明。创建一个结构体annotationsAll
使用以下字段:
ImageID
——形象标识
文件名
-图像的文件名
标题
-原始标题的字符串数组
CaptionIDs
-中相应标题的索引向量data.annotations
为了使合并更容易,可以根据图像id对注释进行排序。
[~, idx] = ([data.annotations.image_id])进行排序;data.annotations= data.annotations(idx);
循环注释并在必要时合并多个注释。
我= 0;j = 0;imageIDPrev = 0;虽然I < numel(data.annotations) I = I + 1;imageID = data.annotations .image_id;标题=字符串(data.annotations(我).caption);如果imageID ~ = imageIDPrev%创建新条目j=j+1;注释所有(j).ImageID=ImageID;注释所有(j).Filename=fullfile(dataFolder,“train2014”,“COCO_train2014_”+pad(字符串(图像ID),12,“左”,' 0 ') +“jpg”);annotationsAll (j)。标题= caption; annotationsAll(j).CaptionIDs = i;其他的%添加标题annotationsAll (j)。标题= [annotationsAll(j).Captions; caption]; annotationsAll(j).CaptionIDs = [annotationsAll(j).CaptionIDs; i];结束imageIDPrev = imageID;结束
将数据划分为训练集和验证集。保留5%的观察值进行测试。
本量利= cvpartition(元素个数(annotationsAll),“坚持”, 0.05);idxTrain =培训(cvp);idxTest =测试(cvp);annotationsTrain = annotationsAll (idxTrain);annotationsTest = annotationsAll (idxTest);
该结构包含三个字段:
id
-标题的唯一标识符
标题
-图像标题,指定为字符向量
image_id
-图像与标题对应的唯一标识符
若要查看图像和相应的标题,请定位带有文件名的图像文件“train2014 \ COCO_train2014_XXXXXXXXXXXX.jpg”
,在那里“XXXXXXXXXXXX”
对应的图像ID左填充为0,长度为12。
imageID = annotationsTrain (1) .ImageID;标题= annotationsTrain (1) .Captions;文件名= annotationsTrain (1) .Filename;
要查看图像,请使用imread
和imshow
功能。
img=imread(文件名);图imshow(img)标题(字幕)
为培训和测试准备标题。从中提取文本标题
包含训练和测试数据的结构体的字段(annotationsAll
),删除标点符号,并将文本转换为小写。
annotationsAll.Captions captionsAll =猫(1);captionsAll = erasePunctuation (captionsAll);captionsAll =低(captionsAll);
为了生成标题,RNN解码器需要特殊的开始和停止标记,分别指示何时开始和停止生成文本。添加自定义令牌“<开始>”
和“<停止>”
分别放在字幕的开头和结尾。
captionsAll =“<开始>”+ captionsAll +“<停止>”;
标记标题使用tokenizedDocument
函数指定开始和停止标记“CustomTokens”
选择。
documentsAll = tokenizedDocument (captionsAll,“CustomTokens”, (“<开始>”“<停止>”]);
创建一个wordEncoding
对象,该对象将单词映射为数字索引并返回。根据训练数据中最常观察到的单词,将词汇量设定为5000,以减少记忆要求。为了避免偏差,只使用与训练集相对应的文档。
内附= wordEncoding (documentsAll (idxTrain),“MaxNumWords”, 5000,“秩序”,“频率”);
创建包含与标题相对应的图像的增强图像数据存储。设置输出大小以匹配卷积网络的输入大小。若要使图像与标题保持同步,请通过使用图像ID重建文件名来指定数据存储的文件名表。若要以3-ch格式返回灰度图像,请退火RGB图像,设置“颜色预处理”
选项“gray2rgb”
.
tblFilenames=表格(cat(1,annotationsTrain.Filename));augimdsTrain=增强图像数据存储(inputSizeNet,tblFilenames,“颜色预处理”,“gray2rgb”)
augimdsTrain = augmentedImageDatastore with properties: NumObservations: 78644 MiniBatchSize: 1 DataAugmentation: 'none' ColorPreprocessing: 'gray2rgb' OutputSize: [299 299] OutputSizeMode: 'resize' DispatchInBackground: 0
初始化模型参数。指定512个隐藏单元,单词嵌入维数为256。
embeddingDimension = 256;numHiddenUnits = 512;
初始化包含编码器模型参数的结构体。
属性指定的gloria初始化器初始化全连接操作的权值initializeGlorot
函数,列在示例的最后。指定输出大小以匹配解码器的嵌入维数(256),以及输入大小以匹配预先训练网络的输出通道数。的“mixed10”
Inception-v3网络的一层有2048个通道输出数据。
numFeatures = outputSizeNet(1) * outputSizeNet(2);inputSizeEncoder = outputSizeNet (3);parametersEncoder =结构;%完全连接parametersEncoder.fc.Weights = dlarray (initializeGlorot (embeddingDimension inputSizeEncoder));parametersEncoder.fc.Bias = dlarray(zeros([embedingdimension 1]),“单一”));
初始化包含解码器模型参数的结构体。
初始化单词嵌入权值,其大小由嵌入维度和词汇表大小加1给出,其中额外的条目对应于填充值。
初始化Bahdanau注意机制的权重和偏差,其大小与GRU操作的隐藏单元数相对应。
初始化GRU操作的权值和偏差。
初始化两个完全连接操作的权值和偏差。
对于模型解码器参数,分别用gloria初始化器和零初始化每个权重和偏差。
inputSizeDecoder = encn . numwords + 1; / /输入一个数字parametersDecoder =结构;%单词嵌入parametersDecoder.emb.Weights = dlarray (initializeGlorot (embeddingDimension inputSizeDecoder));%的关注parametersDecoder.attention。Weights1 = dlarray (initializeGlorot (numHiddenUnits embeddingDimension));parametersDecoder.attention。Bias1 = dlarray(0 ([numHiddenUnits 1],),“单一”));parametersDecoder.attention。Weights2 = dlarray (initializeGlorot (numHiddenUnits numHiddenUnits));parametersDecoder.attention。Bias2 = dlarray(0 ([numHiddenUnits 1],),“单一”));numHiddenUnits parametersDecoder.attention.WeightsV = dlarray (initializeGlorot (1));parametersDecoder.attention.BiasV = dlarray (0 (1, - 1,“单一”));%格勒乌parametersDecoder.gru.InputWeights = dlarray (initializeGlorot (3 * numHiddenUnits, 2 * embeddingDimension));parametersDecoder.gru.RecurrentWeights = dlarray (initializeGlorot (3 * numHiddenUnits numHiddenUnits));parametersDecoder.gru.Bias = dlarray (0 (3 * numHiddenUnits, 1,“单一”));%完全连接parametersDecoder.fc1。重量= dlarray (initializeGlorot (numHiddenUnits numHiddenUnits));parametersDecoder.fc1。Bias = dlarray(0 ([numHiddenUnits 1]),“单一”));%完全连接parametersDecoder.fc2。重量= dlarray (initializeGlorot (enc.NumWords + 1, numHiddenUnits));parametersDecoder.fc2。偏见= dlarray (0 ([enc。NumWords + 1,“单一”));
创建函数modelEncoder
和modelDecoder
,分别计算编码器和解码器模型的输出。
的modelEncoder
函数中列出的编码器模型函数在本例的一节中,将一个激活数组作为输入dlX
从预训练网络的输出,并通过一个完全连接的操作和一个ReLU操作。由于预先训练的网络不需要跟踪自动区分,提取编码器模型函数外的特征更具有计算效率。
的modelDecoder
函数中列出的译码器模型函数在示例的一部分中,将对应于输入字的单个输入时间步长、解码器模型参数、编码器的特征和网络状态作为输入,并返回对下一个时间步长、更新的网络状态和注意力权重的预测。
指定培训选项。训练30个时代,小批量128个,并在一个plot中显示训练进度。
miniBatchSize = 128;numEpochs = 30;情节=“训练进步”;
在可用的GPU上进行训练。使用GPU需要并行计算工具箱™和支持的GPU设备。金宝app有关支持的设备的信息,请参见金宝appGPU支金宝app持情况(并行计算工具箱).
executionEnvironment =“汽车”;
使用自定义训练循环训练网络。
在每个历元开始时,对输入数据进行无序排列。为了使增强图像数据存储中的图像与标题保持同步,请创建一个无序排列的索引数组,将索引放入两个数据集中。
为每个mini-batch:
将图像重新缩放到预先训练的网络所期望的大小。
对于每个图像,选择一个随机的标题。
将标题转换为单词索引序列。使用与填充标记的索引对应的填充值指定序列的右填充。
将数据转换为dlarray
对象。对于图像,指定尺寸标签“SSCB”
(spatial, spatial, channel, batch)。
对于GPU培训,将数据转换为gpuArray
对象。
利用预先训练的网络提取图像特征,并将其重塑到编码器所期望的大小。
评估模型梯度和损失使用dlfeval
和modelGradients
功能。
控件更新编码器和解码器模型参数adamupdate
函数。
在图中显示训练进度。
初始化亚当优化器的参数。
trailingAvgEncoder = [];trailingAvgSqEncoder = [];trailingAvgDecoder = [];trailingAvgSqDecoder = [];
初始化培训进度图。创建一条动画线,根据相应的迭代来绘制损失。
如果阴谋==“训练进步”figure lineosstrain = animatedline(“颜色”[0.85 0.325 0.098]);包含(“迭代”) ylabel (“损失”ylim([0 inf])网格在结束
火车模型。
迭代= 0;numObservationsTrain =元素个数(annotationsTrain);numIterationsPerEpoch = floor(nummobservationstrain / miniBatchSize);开始=抽搐;%循环纪元。为时代= 1:numEpochs%洗牌数据。idxShuffle = randperm (numObservationsTrain);%循环小批。为i=1:numIterationsPerEpoch迭代=迭代+1;确定小批量指数。idx =(张)* miniBatchSize + 1:我* miniBatchSize;idxMiniBatch = idxShuffle (idx);%读取小批数据。台= readByIndex (augimdsTrain idxMiniBatch);猫(X = 4, tbl.input {:});注释= annotationsTrain (idxMiniBatch);%对于每个图像,选择随机标题。idx = cellfun(@(captionIDs) randsample(captionIDs,1),{annotation . captionIDs});文件= documentsAll (idx);%创建一批数据。[dlX, dlT] = createBatch(X,documents,dlnet,inputMin,inputMax,enc,executionEnvironment);使用dlfeval和% modelGradients函数。[gradientsEncoder, gradientsDecoder, loss] = dlfeval(@modelGradients, parametersEncoder,)...parametersDecoder、dlX dlT);%更新编码器使用adamupdate。[参数SENCODER,trailingAvgEncoder,trailingAvgSqEncoder]=数据更新(参数SENCODER,...gradientsEncoder, trailingAvgEncoder, trailingAvgSqEncoder,迭代);%更新解码器使用adamupdate。[parametersDecoder, trailingAvgDecoder, trailingAvgSqDecoder] = adamupdate(parametersDecoder,...gradientsDecoder, trailingAvgDecoder, trailingAvgSqDecoder, iteration);%显示训练进度。如果阴谋==“训练进步”D=持续时间(0,0,toc(开始),“格式”,“hh: mm: ss”);addpoints (lineLossTrain、迭代、双(收集(extractdata(损失))))标题(”时代:“+时代+”,过去:“+字符串(D)现在开始结束结束结束
标题生成过程与训练过程不同。在训练过程中,解码器在每一个时间步长上都使用前一个时间步长的真值作为输入。这就是所谓的“强迫教师”。当对新数据进行预测时,解码器使用以前的预测值而不是真实值。
预测序列中每一步最可能出现的单词可能导致次优结果。例如,如果解码器在给出大象的图像时预测标题的第一个单词是“a”,那么预测下一个单词的“大象”的概率就变得更不可能了,因为短语“大象”出现在英语文本中的概率非常低。
要解决这个问题,您可以使用波束搜索算法:不要对序列中的每个步骤采用最可能的预测,而是采用顶部预测k预测(波束指数)和接下来的每个步骤,保持顶部k预测序列到目前为止根据总分。
通过提取图像特征,将其输入编码器,然后使用beamSearch
函数中列出的束搜索功能这个例子的一部分。
img = imread (“laika_siting.jpg”);dlX = extractImageFeatures (dlnet img, inputMin inputMax, executionEnvironment);beamIndex = 3;maxNumWords = 20;(话说,attentionScores) = beamSearch (dlX、beamIndex parametersEncoder, parametersDecoder, enc, maxNumWords);标题=加入(字)
标题= "一只狗站在瓷砖地上"
显示图像和标题。
图imshow (img)标题(标题)
要预测图像集合的标题,可以对数据存储中的小批量数据进行循环,并使用extractImageFeatures
函数。然后,循环小批处理中的图像并使用beamSearch
函数。
创建一个扩充的图像数据存储,并将输出大小设置为与卷积网络的输入大小匹配。将灰度图像输出为3通道RGB图像,设置“颜色预处理”
选项“gray2rgb”
.
TBLFileNameTest=表格(cat(1,annotationsTest.Filename));AugimdTest=增强图像数据存储(inputSizeNet,TBLFileNameTest,“颜色预处理”,“gray2rgb”)
augimdsTest = augmentedImageDatastore with properties: NumObservations: 4139 MiniBatchSize: 1 DataAugmentation: 'none' ColorPreprocessing: 'gray2rgb' OutputSize: [299 299] OutputSizeMode: 'resize' DispatchInBackground: 0
为测试数据生成标题。在大型数据集上预测标题可能需要一些时间。如果您有并行计算工具箱™, 然后,您可以通过在一个文档中生成标题来并行地进行预测parfor
看。如果您没有“并行计算工具箱”。然后parfor
循环以串行方式运行。
beamIndex=2;maxNumWords=20;numObservationsTest=numel(annotationsTest);NumItemationsTest=ceil(numObservationsTest/miniBatchSize);captionsTestPred=String(1,numObservationsTest);documentsTestPred=tokenizedDocument(String(1,numObservationsTest));为我= 1:numIterationsTest% Mini-batch指数。idxStart =(张)* miniBatchSize + 1;idxEnd = min(我* miniBatchSize numObservationsTest);idx = idxStart: idxEnd;深圳=元素个数(idx);%读取图像。台= readByIndex (augimdsTest idx);%提取图像特征。猫(X = 4, tbl.input {:});dlX = extractImageFeatures (dlnet X, inputMin、inputMax executionEnvironment);%生成标题。captionsPredMiniBatch =字符串(深圳);documentsPredMiniBatch = tokenizedDocument(字符串(深圳));parforj=1:sz words=beamSearch(dlX(:,:,j),beamIndex,parametersEncoder,parametersDecoder,enc,maxNumWords);字幕predminibatch(j)=连接(单词);documentsPredMiniBatch(j)=标记化文档(文字、,“TokenizeMethod”,“没有”);结束captionsTestPred(idx)=captionsPredMiniBatch;documentsTestPred(idx)=documentsPredMiniBatch;结束
分析和传送文件给工人…完成。
要查看带有相应标题的测试图像,请使用imshow
函数,并将标题设置为预测的标题。
idx = 1;台= readByIndex (augimdsTest idx);img = tbl.input {1};图imshow (img)标题(captionsTestPred (idx))
要使用BLEU分数评估字幕的准确性,请使用bleuEvaluationScore
函数。使用bleuEvaluationScore
函数时,可以将单个候选文档与多个引用文档进行比较。
的bleuEvaluationScore
默认情况下,函数使用长度为1到4的n-gram对相似性进行评分。由于标题很短,这种行为可能导致信息不充分的结果,因为大多数分数都接近于零。将n-gram长度设置为1到2,通过设置“NgramWeights”
选择具有相等权重的两个元素向量。
ngramWeights = [0.5 0.5];为i=1:numObservationsTest annotation=annotationsTest(i);captionIDs=annotation.captionIDs;候选者=文件测试(i);参考=文件所有(标题ID);分数=BLUEEvaluationScore(候选人、推荐人、,“NgramWeights”, ngramWeights);分数(i) =分数;结束
查看平均BLEU得分。
scoreMean =意味着(分数)
scoreMean = 0.4224
在直方图中可视化分数。
图直方图(分数)包含(“蓝色分数”) ylabel (“频率”)
的注意
函数利用Bahdanau注意计算上下文向量和注意权重。
作用[contextVector, attentionWeights] =注意(隐藏,特征,权重1,...bias1、weights2 bias2、weightsV biasV)%模型维度。[embeddingDimension, numFeatures miniBatchSize] =大小(特性);numHiddenUnits =大小(weights1, 1);%完全连接。dlY1 =重塑(特征,嵌入尺寸,numFeatures*miniBatchSize);dlY1 = fullyconnect (dlY1 weights1 bias1,“DataFormat”,“CB”);dlY1 =重塑(dlY1 numHiddenUnits、numFeatures miniBatchSize);%完全连接。dlY2 = fullyconnect(隐藏、weights2 bias2,“DataFormat”,“CB”);dlY2 =重塑(dlY2 numHiddenUnits 1, miniBatchSize);%,双曲正切。分数= tanh(dlY1 + dlY2);scores =重塑(scores, numHiddenUnits, numFeatures*miniBatchSize);完全连接,softmax。注意权重=完全连接(分数、权重SV、biasV、,“DataFormat”,“CB”);attentionWeights =重塑(attentionWeights 1 numFeatures miniBatchSize);attentionWeights = softmax (attentionWeights,“DataFormat”,“SCB”);%的上下文。contextVector = attentionWeights .* feature;contextVector =挤压(sum (contextVector, 2));结束
的嵌入
函数将一个索引数组映射到一个嵌入向量序列。
作用Z =嵌入(X,权重)将输入重塑为向量[N, T] = size(X, 1:2);X =重塑(X, N*T, 1);%嵌入矩阵的索引Z = weights(:, X);%通过分离批处理和序列尺寸来重塑输出Z =重塑(Z, [], N, T);结束
的extractImageFeatures
函数以训练过的函数作为输入dlnetwork
对象、输入图像、图像缩放的统计信息和执行环境,并返回dlarray
包含从预先训练的网络中提取的特征。
作用dlX = extractImageFeatures (dlnet X, inputMin、inputMax executionEnvironment)%调整大小和缩放。inputSize = dlnet.Layers (1) .InputSize (1:2);X = imresize (X, inputSize);X =重新调节(X, 1, 1,“InputMin”inputMin,“InputMax”, inputMax);%转换为dlarray。dlX = dlarray (X,“SSCB”);%转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlX = gpuArray (dlX);结束%提取特征并重塑。dlX=预测(dlnet,dlX);sz=大小(dlX);numFeatures=sz(1)*sz(2);inputsizencoder=sz(3);miniBatchSize=sz(4);dlX=重塑(dlX,[numFeatures inputsizencoder miniBatchSize]);结束
的createBatch
函数将一小批数据、标记化的标题、预先训练的网络、图像缩放的统计数据、单词编码和执行环境作为输入,并返回与提取的图像特征和标题对应的一小批数据进行训练。
作用[dlX, dlT] = createBatch(X,documents,dlnet,inputMin,inputMax,enc,executionEnvironment) dlX = extractImageFeatures(dlnet,X,inputMin,inputMax,executionEnvironment);将文档转换为单词索引序列。T = doc2sequence (enc、文档“PaddingDirection”,“对”,“PaddingValue”, enc.NumWords + 1);T =猫(1 T {:});%转换小批数据到美元。dlT = dlarray (T);%如果在GPU上训练,则将数据转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlT = gpuArray (dlT);结束结束
的modelEncoder
函数接受一个激活数组作为输入dlX
并通过一个完全连接的操作和一个ReLU操作传递它。对于全连接操作,只在通道尺寸上操作。要仅在通道维度上应用完全连接操作,请将其他通道扁平化为单个维度,并使用“DataFormat”
选择的fullyconnect
函数。
作用dlY = modelEncoder(dlX,parametersEncoder) [numFeatures,inputSizeEncoder,miniBatchSize] = size(dlX); / /输入参数%完全连接重量= parametersEncoder.fc.Weights;偏见= parametersEncoder.fc.Bias;embeddingDimension =大小(重量、1);dlX = permute(dlX,[2 1 3]);dlX =重塑(dlX、inputSizeEncoder numFeatures * miniBatchSize);海底= fullyconnect (dlX、权重、偏见,“DataFormat”,“CB”);dlY=重塑(dlY,嵌入尺寸,numFeatures,miniBatchSize);% ReLU海底= relu(海底);结束
的modelDecoder
函数以单个时间步长作为输入dlX
、解码器模型参数、编码器的特征和网络状态,并返回下一个时间步骤的预测、更新的网络状态和注意力权重。
作用[dlY,state,attentionWeights] = modelDecoder(dlX,parametersDecoder,features,state) hiddenState = state.gru. hiddenState;%的关注weights1 = parametersDecoder.attention.Weights1;bias1 = parametersDecoder.attention.Bias1;weights2 = parametersDecoder.attention.Weights2;bias2 = parametersDecoder.attention.Bias2;weightsV = parametersDecoder.attention.WeightsV;biasV = parametersDecoder.attention.BiasV;[contextVector, attentionWeights] = attention(hiddenState,features,weights1,bias1,weights2,bias2,weightsV,biasV);%嵌入重量= parametersDecoder.emb.Weights;dlX =嵌入(dlX、重量);%连接海底=猫(1 contextVector dlX);%格勒乌inputWeights = parametersDecoder.gru.InputWeights;recurrentWeights = parametersDecoder.gru.RecurrentWeights;偏见= parametersDecoder.gru.Bias;[dlY, hiddenState] = gru(dlY, hiddenState, inputwights, recurrentwights, bias,)“DataFormat”,“认知行为治疗”);%更新状态state.gru.HiddenState = hiddenState;%完全连接重量= parametersDecoder.fc1.Weights;偏见= parametersDecoder.fc1.Bias;海底= fullyconnect(海底,重量、偏见,“DataFormat”,“CB”);%完全连接权重=参数decoder.fc2.weights;偏差=参数decoder.fc2.bias;Dy=完全连接(Dy,权重,偏差,“DataFormat”,“CB”);结束
的modelGradients
函数将编码器和解码器参数作为输入,编码器的特性dlX
,以及目标标题dlT
,并返回编码器和解码器参数相对于损耗、损耗和预测的梯度。
作用[gradientsEncoder gradientsDecoder,损失,dlYPred] =...modelGradients(parametersEncoder,parametersDecoder,dlX,dlT)miniBatchSize=大小(dlX,3);sequenceLength=大小(dlT,2)-1;vocabSize=大小(parametersDecoder.emb.Weights,2);%模型编码器特点= modelEncoder (dlX parametersEncoder);%初始化状态numHiddenUnits =大小(parametersDecoder.attention.Weights1, 1);状态=结构;state.gru.HiddenState = dlarray(0) ([numHiddenUnits miniBatchSize],“单一”));dlYPred = dlarray(zeros([vocabSize miniBatchSize sequenceLength]),“喜欢”dlX));损失= dlarray(单(0));padToken = vocabSize;为t = 1:sequenceLength decoderInput = dlT(:,t);dlYReal = dlT (:, t + 1);[dlYPred (:,:, t)状态]= modelDecoder (decoderInput, parametersDecoder、特征、状态);mask = dlYReal ~= padToken;loss = loss + sparseCrossEntropyAndSoftmax(dlYPred(:,:,t),dlYReal,mask);结束%计算梯度[gradientsEncoder,gradientsDecoder]=dlgradient(丢失,参数sEncoder,参数sDecoder);结束
的sparseCrossEntropyAndSoftmax
将预测作为输入海底
,相应的目标dlT
,序列填充掩码,并应用softmax
函数并返回交叉熵损失。
作用loss = sparseCrossEntropyAndSoftmax(dlY, dlT, mask) miniBatchSize = size(dlY, 2);%Softmax。海底= softmax(海底,“DataFormat”,“CB”);找到与目标单词对应的行。idx = sub2ind(size(dlY), dlT', 1:miniBatchSize);海底=海底(idx);远离零。d = max(d, 1 -8);%掩饰的损失。损失=对数(DY)。*掩码';损失=-总和(损失,“所有”)。/ miniBatchSize;结束
的beamSearch
函数将图像特征作为输入dlX
,波束索引、编码器和解码器网络的参数、字编码和最大序列长度,并使用波束搜索算法返回图像的标题词。
作用(话说,attentionScores) = beamSearch (dlX、beamIndex parametersEncoder, parametersDecoder,...enc,maxNumWords)%模型尺寸numFeatures=size(dlX,1);numHiddenUnits=size(parameters-coder.attention.weights 1,1);%提取特征特点= modelEncoder (dlX parametersEncoder);%初始化状态状态=结构;state.gru.HiddenState = dlarray(0) ([numHiddenUnits 1],“喜欢”dlX));%初始化的候选人候选者=结构;候选人。州=州;候选人,用词=“<开始>”;候选人。分数= 0;候选人。AttentionScores = dlarray(0 ([numFeatures maxNumWords],“喜欢”dlX));候选人。StopFlag= false; t = 0;%循环字虽然t < maxNumWords t = t + 1;candidatesNew = [];%循环候选人为i = 1:元素个数(候选人)%在预测停止令牌时停止生成如果候选人(i)。StopFlag继续结束%候选人细节状态=(我).State候选人;话说=候选人(我).Words;得分=(我).Score候选人;.AttentionScores attentionScores =候选人(我);%预测下一个标记decoderInput = word2ind (enc,话说(结束));[dlYPred、州attentionScores (:, t)] = modelDecoder (decoderInput, parametersDecoder、特征、状态);dlYPred = softmax (dlYPred,“DataFormat”,“CB”);[scoresTop, idxTop] = maxk (extractdata (dlYPred) beamIndex);idxTop =收集(idxTop);%循环预测为j = 1:beamIndex候选= struct;candidateWord = ind2word (enc, idxTop (j));candidateScore = scoresTop (j);如果candidateWord = =“<停止>”候选人。StopFlag= true; attentionScores(:,t+1:end) = [];其他的候选人。StopFlag= false;结束候选人。=状态;候选人。[单词候选人];候选人。Score = Score + log(candidatscore);候选人。AttentionScores = AttentionScores;[候选人];结束结束找到最优秀的候选人[~, idx] = maxk ([candidatesNew.Score], beamIndex);候选人= candidatesNew (idx);当所有候选人都有停止标记时停止预测如果([candidates.StopFlag])打破结束结束获得最佳候选人话说=候选人(1).Words (2: end-1);attentionScores = (1) .AttentionScores候选人;结束
的initializeGlorot
函数根据gloria初始化生成权重数组。
作用weights = initializeGlorot(numOut, numIn) varWeights = sqrt(6 / (numIn + numOut));= varWeights * (2 * rand([numOut, numIn]),“单一”) - 1);结束
adamupdate
|交叉熵
|dlarray
|dlfeval
|梯度
|dlupdate
|格勒乌
|lstm
|softmax
|DOC2序列
(文本分析工具箱)|tokenizedDocument
(文本分析工具箱)|word2ind
(文本分析工具箱)|wordEncoding
(文本分析工具箱)