主要内容

使用注意力的图像字幕

这个例子展示了如何使用注意力训练一个深度学习模型来进行图像配图。

大多数预训练的深度学习网络都被配置为单标签分类。例如,给定一张典型办公桌的图像,网络可能会预测出单一类别的“键盘”或“鼠标”。相比之下,图像字幕模型结合了卷积和循环操作来生成图像中内容的文本描述,而不是单个标签。

本例中训练的模型使用编码器-解码器架构。编码器是一个预先训练好的Inception-v3网络,用作特征提取器。解码器是一个循环神经网络(RNN),它将提取的特征作为输入并生成标题。解码器包含一个注意机制这允许解码器在生成标题时专注于编码输入的部分。

编码器模型是一个预先训练好的Inception-v3模型,它从“mixed10”层,然后是全连接和ReLU操作。

该解码器模型由词嵌入、注意机制、门控循环单元(GRU)和两个全连接操作组成。

负荷预训练网络

加载一个预先训练好的Inception-v3网络。这一步需要深度学习工具箱™模型适用于Inception-v3网络万博1manbetx支持包。如果您没有安装所需的支持包,则该软件提供下载链接。万博1manbetx

Net = inceptionv3;inputSizeNet = net.Layers(1).InputSize;

将网络转换为adlnetwork对象进行特征提取并移除最后四层,留下“mixed10”层作为最后一层。

lgraph = layerGraph(net);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]超参数DataAugmentation: 'none'归一化:'rescale-symmetric' NormalizationDimension: 'auto' Max: 255 Min: 0

自定义训练不支持这种归一化,因此必须在网络中禁用归万博1manbetx一化,而在自定义训练循环中执行归一化。将最小值和最大值保存为双精度变量inputMin而且inputMax,并将输入层替换为不归一化的图像输入层。

inputMin = double(loggraph . layers (1).Min);inputMax = double(lgraph.Layers(1).Max);层= imageInputLayer(inputSizeNet,归一化=“没有”、名称=“输入”);lgraph =替换层(lgraph,“input_1”层);

确定网络的输出大小。使用analyzeNetwork函数查看最后一层的激活大小。若要分析自定义培训循环工作流的网络,请设置TargetUsage选项“dlnetwork”

analyzeNetwork (lgraph TargetUsage =“dlnetwork”

2021 - 06 - 30 - _18 30 - 15. png

创建一个名为outputSizeNet包含网络输出大小。

outputSizeNet = [8 8 2048];

将图层图转换为adlnetwork对象并查看输出层。输出层是“mixed10”v3网络层。

Net = dlnetwork(lgraph)
dlnet = dlnetwork with properties: Layers: [311×1 nnet.cnn.layer.Layer] Connections: [345×2 table] Learnables: [376×3 table] State: [188×3 table] InputNames: {'input'} OutputNames: {'mixed10'}

导入COCO数据集

分别从“2014火车图像”和“2014火车/val注释”数据集中下载图像和注释https://cocodataset.org/#download.将图像和注释提取到一个名为“可可”.COCO 2014数据集由可可财团

从文件中提取标题“captions_train2014.json”使用jsondecode函数。

dataFolder = fullfile(tempdir,“可可”);文件名= fullfile(数据文件夹,“annotations_trainval2014”“注释”“captions_train2014.json”);STR = fileread(文件名);数据= jsondecode(str)
data =带字段的结构:信息:[1×1 struct] images: [82783×1 struct] licenses: [8×1 struct] annotations: [414113×1 struct]

注释结构体的字段包含图像字幕所需的数据。

data.annotations
ans =414113×1包含字段的struct数组:Image_id id标题

数据集包含每个图像的多个标题。为确保相同的图像不会同时出现在训练集和验证集中,请使用独特的方法中的idimage_id字段的注释字段的数据,然后查看唯一图像的数量。

numObservationsAll = numel(data.annotations)
numObservationsAll = 414113
imageIDs = [data.annotations.image_id];imageIDsUnique =唯一的(imageIDs);numUniqueImages = nummel (imageIDsUnique)
numUniqueImages = 82783

每张图片至少有五个标题。创建一个结构annotationsAll使用这些字段:

  • ImageID-图像ID

  • 文件名—镜像的文件名

  • 标题-原始标题的字符串数组

  • CaptionIDs中的对应标题的索引向量data.annotations

为了简化合并,可以根据图像id对注释进行排序。

[~,idx] = sort([data.annotations.image_id]);data.annotations= data.annotations(idx);

遍历注释并在必要时合并多个注释。

I = 0;J = 0;imageIDPrev = 0;I < number (data.annotations) = I + 1;imageID = data.annotations(i).image_id;标题= string(data.annotations(i).caption);如果imageID ~= imageIDPrev创建新条目J = J + 1;annotationsAll (j)。ImageID= imageID; annotationsAll(j).Filename = fullfile(dataFolder,“train2014”“COCO_train2014_”+垫(字符串(imageID) 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%的观测值进行测试。

cvp = cvpartition(nummel (annotationsAll),HoldOut=0.05);idxTrain =训练(cvp);idxTest = test(cvp);annotationsTrain =注解sall (idxTrain);注解stest =注解sall (idxTest);

该结构体包含三个字段:

  • id-标题的唯一标识符

  • 标题-图像标题,指定为字符向量

  • image_id-与标题对应的图像的唯一标识符

要查看图像和相应的标题,请找到具有文件名的图像文件“train2014 \ COCO_train2014_XXXXXXXXXXXX.jpg”,在那里“XXXXXXXXXXXX”对应于左侧填充0的图像ID,长度为12。

imageID = annotationsTrain(1).ImageID;captions = annotationsTrain(1).标题;filename = annotationsTrain(1).Filename;

要查看图像,请使用imread而且imshow功能。

Img = imread(文件名);图imshow(img) title(字幕)

为培训准备数据

为训练和测试准备字幕。方法中提取文本标题包含训练和测试数据的结构的字段(annotationsAll),删除标点符号,并将文本转换为小写。

captionsAll = cat(1,annotationsAll.Captions);captionsAll = eraspunctuation (captionsAll);captionsAll = lower(captionsAll);

为了生成标题,RNN解码器需要特殊的开始和停止令牌来分别指示何时开始和停止生成文本。添加自定义令牌“<开始>”而且“<停止>”分别写在标题的开头和结尾。

captionsAll =“<开始>”+字幕全部+“<停止>”

符号标记标题tokenizedDocument方法指定开始和停止令牌CustomTokens选择。

documentsAll = tokenizedDocument(captionsAll,CustomTokens=[“<开始>”“<停止>”]);

创建一个wordEncoding对象,将单词映射到数值索引并返回。通过指定与训练数据中最常观察到的单词对应的词汇量5000来降低内存需求。为了避免偏见,只使用与训练集相对应的文档。

enc = worddencoding (documentsAll(idxTrain),MaxNumWords=5000,Order=“频率”);

创建一个包含与标题对应的图像的增强图像数据存储。将输出大小设置为与卷积网络的输入大小匹配。要使映像与标题保持同步,可以使用映像ID重新构造文件名,从而为数据存储指定一个文件名表。若要将灰度图像返回为3通道RGB图像,请设置ColorPreprocessing选项“gray2rgb”

tblFilenames = table(cat(1,annotationsTrain.Filename));augimdsTrain = augmentedImageDatastore(inputSizeNet,tblFilenames, color预处理=“gray2rgb”
augimdsTrain = augmentedImageDatastore with properties: NumObservations: 78644 MiniBatchSize: 1 DataAugmentation: 'none' color预处理:'gray2rgb' OutputSize: [299 299] OutputSizeMode: 'resize' DispatchInBackground: 0

初始化模型参数

初始化模型参数。指定512个隐藏单元,字嵌入维数为256。

embeddingDimension = 256;numHiddenUnits = 512;

初始化包含编码器模型参数的结构。

  • 属性指定的Glorot初始化器初始化全连接操作的权重initializeGlorot函数,在示例末尾列出。指定输出大小以匹配解码器的嵌入维度(256),并指定输入大小以匹配预训练网络的输出通道数量。的“mixed10”Inception-v3网络的层输出数据为2048个通道。

numFeatures = outputSizeNet(1) * outputSizeNet(2);inputSizeEncoder = outputsizeet (3);parametersEncoder = struct;%完全连接parametersencode .fc. weights = dlarray(initializeGlorot(embeddingDimension,inputSizeEncoder));parametersencode .fc. bias = dlarray(0 ([embeddingDimension 1],“单身”));

初始化一个包含解码器模型参数的结构。

  • 用嵌入维和词汇表大小加1给出的大小初始化单词嵌入权重,其中额外的条目对应于填充值。

  • 初始化Bahdanau注意机制的权重和偏差,其大小与GRU操作的隐藏单元数量相对应。

  • 初始化GRU操作的权重和偏差。

  • 初始化两个全连接操作的权重和偏差。

对于模型解码器参数,分别使用Glorot初始化器和零初始化每个权重和偏差。

inputSizeDecoder = enc.NumWords + 1;parametersDecoder = struct;%单词嵌入parametersDecoder.emb.Weights = dlarray(initializeGlorot(embeddingDimension,inputSizeDecoder));%的关注parametersDecoder.attention。Weights1 = dlarray(initializeGlorot(numHiddenUnits,embeddingDimension));parametersDecoder.attention。Bias1 = darray (0 ([numHiddenUnits 1],“单身”));parametersDecoder.attention。Weights2 = dlarray(initializeGlorot(numHiddenUnits,numHiddenUnits));parametersDecoder.attention。Bias2 = darray (0 ([numHiddenUnits 1],“单身”));parametersDecoder.attention.WeightsV = dlarray(initializeGlorot(1,numHiddenUnits));parametersDecoder.attention.BiasV = dlarray(0 (1,1,“单身”));%格勒乌parametersdecoder .gru. inputwights = dlarray(initializeGlorot(3*numHiddenUnits,2*embeddingDimension));parametersdecoder .gru. recurrentwights = dlarray(initializeGlorot(3*numHiddenUnits,numHiddenUnits));parametersDecoder.gru.Bias = dlarray(0 (3*numHiddenUnits,1,“单身”));%完全连接parametersDecoder.fc1。Weights = dlarray(initializeGlorot(numHiddenUnits,numHiddenUnits));parametersDecoder.fc1。偏差= darray (0 ([numHiddenUnits 1],“单身”));%完全连接parametersDecoder.fc2。Weights = dlarray(initializeGlorot(c. numwords +1,numHiddenUnits));parametersDecoder.fc2。偏差= dlarray(零([enc。NumWords + 1,“单身”));

定义模型函数

创建函数modelEncoder而且modelDecoder,列在示例末尾,分别计算编码器模型和解码器模型的输出。

modelEncoder函数中列出的编码器模型函数部分,将一个激活数组作为输入X从预训练网络的输出,并将其通过全连接操作和ReLU操作。由于预先训练的网络不需要跟踪自动区分,因此提取编码器模型函数之外的特征在计算上更有效。

modelDecoder函数中列出的解码器模型函数部分,将与输入单词对应的单个输入时间步长、解码器模型参数、编码器的特征和网络状态作为输入,并返回对下一个时间步长的预测、更新的网络状态和注意力权重。

指定培训项目

指定培训选项。训练30个epoch,迷你批量大小为128,并在图中显示训练进度。

miniBatchSize = 128;numEpochs = 30;情节=“训练进步”

如果有GPU,可以在GPU上进行训练。使用GPU需要并行计算工具箱™和受支持的GPU设备。万博1manbetx有关受支持设备的信息,请参见万博1manbetxGPU计算要求(并行计算工具箱)

executionEnvironment =“汽车”

列车网络的

使用自定义训练循环训练网络。

在每个纪元的开始,对输入数据进行洗牌。要保持增强图像数据存储中的图像和标题的同步,可以创建一个索引数组,该数组由打乱的索引组成,索引到这两个数据集。

对于每个小批量:

  • 将图像重新缩放到预训练网络所期望的大小。

  • 对于每个图像,选择一个随机的标题。

  • 将标题转换为单词索引序列。使用与填充令牌索引对应的填充值指定序列的右填充。

  • 将数据转换为dlarray对象。对于图像,指定尺寸标签“SSCB”(空间,空间,通道,批次)。

  • 对于GPU训练,将数据转换为gpuArray对象。

  • 使用预训练的网络提取图像特征,并将其重塑为编码器期望的大小。

  • 评估模型损失和梯度使用dlfeval而且modelLoss功能。

  • 类更新编码器和解码器模型参数adamupdate函数。

  • 以图表形式展示训练进度。

初始化Adam优化器的参数。

trailingAvgEncoder = [];trailingAvgSqEncoder = [];trailingAvgDecoder = [];trailingAvgSqDecoder = [];

初始化培训进度图。创建一条动画线,在相应的迭代中绘制损失。

如果情节= =“训练进步”figure lineLossTrain = animatedline(Color=[0.85 0.325 0.098]);包含(“迭代”) ylabel (“损失”) ylim([0 inf])网格结束

训练模型。

迭代= 0;numObservationsTrain = numel(annotationsTrain);numIterationsPerEpoch = floor(numObservationsTrain / miniBatchSize);开始= tic;%遍历epoch。epoch = 1:numEpochs% Shuffle数据。idxShuffle = randperm(numObservationsTrain);在小批上循环。i = 1:numIterationsPerEpoch迭代=迭代+ 1;确定小批指标。idx = (i-1)*miniBatchSize+1:i*miniBatchSize;idxMiniBatch = idxShuffle(idx);读取小批数据。tbl = readByIndex(augimdsTrain,idxMiniBatch);X = cat(4,tbl.input{:});注解=注解应变(idxMiniBatch);对于每个图像,选择随机标题。idx = cellfun(@(captionIDs) randsample(captionIDs,1),{annotations.CaptionIDs});documents = documentsAll(idx);创建一批数据。[X, T] = createBatch(X,documents,net,inputMin,inputMax,enc,executionEnvironment);计算模型损失和梯度使用dlfeval和% modelLoss函数。[loss, gradientsEncoder, gradientsDecoder] = dlfeval(@modelLoss, parametersEncoder,...parametersDecoder, X, T);使用adamupdate更新编码器。[parametersEncoder, trailingAvgEncoder, trailingAvgSqEncoder] = adamupdate(parametersEncoder, trailingAvgSqEncoder)...gradientsEncoder, trailingAvgEncoder, trailingAvgSqEncoder, iteration);使用adamupdate更新解码器。[parametersDecoder, trailingAvgDecoder, trailingAvgSqDecoder] = adamupdate(parametersDecoder, trailingAvgSqDecoder)...gradientsDecoder, trailingAvgDecoder, trailingAvgSqDecoder, iteration);%显示培训进度。如果情节= =“训练进步”D = duration(0,0,toc(start),Format=“hh: mm: ss”);addpoints (lineLossTrain、迭代、双(损失))标题(”时代:“+ epoch +,消失:"+字符串(D))现在绘制结束结束结束

预测新标题

标题生成的过程不同于训练的过程。在训练过程中,在每个时间步,解码器使用前一个时间步的真值作为输入。这就是所谓的“教师强迫”。在对新数据进行预测时,解码器使用之前的预测值而不是真实值。

为序列中的每一步预测最有可能的单词可能会导致次优结果。例如,如果解码器在给出大象的图像时预测标题的第一个单词是“a”,那么预测下一个单词为“elephant”的概率就变得不太可能,因为短语“a elephant”出现在英语文本中的概率极低。

为了解决这个问题,您可以使用光束搜索算法:而不是对序列中的每个步骤进行最有可能的预测,而是选择顶部k预测(光束指数)和每个后续步骤,保持顶部k目前为止根据总分预测的序列。

通过提取图像特征生成新图像的标题,将它们输入编码器,然后使用beamSearch函数中列出的波束搜索函数部分的示例。

Img = imread(“laika_sitting.jpg”);X = extractImageFeatures(net,img,inputMin,inputMax,executionEnvironment);beamIndex = 3;maxNumWords = 20;[words,attentionScores] = beamSearch(X,beamIndex,parametersEncoder,parametersDecoder,enc,maxNumWords);标题= join(words)
描述= "一只狗站在瓷砖地板上"

显示带有标题的图像。

图imshow(img) title(标题)

预测数据集的标题

要预测图像集合的标题,请遍历数据存储中的小批数据,并使用extractImageFeatures函数。然后,在迷你批处理中的图像上循环,并使用beamSearch函数。

创建一个增强图像数据存储,并将输出大小设置为与卷积网络的输入大小相匹配。若要将灰度图像输出为3通道RGB图像,请设置ColorPreprocessing选项“gray2rgb”

tblFilenamesTest = table(cat(1, annotationste . filename));augimdsTest = augmentedImageDatastore(inputSizeNet,tblFilenamesTest, color预处理=“gray2rgb”
augimdsTest = augmentedImageDatastore与属性:NumObservations: 4139 MiniBatchSize: 1 DataAugmentation: 'none' color预处理:'gray2rgb' OutputSize: [299 299] OutputSizeMode: 'resize' DispatchInBackground: 0

为测试数据生成标题。在大型数据集上预测标题可能需要一些时间。如果您有并行计算工具箱™,那么您可以通过在parfor看。如果您没有并行计算工具箱。然后parfor循环以串行方式运行。

beamIndex = 2;maxNumWords = 20;numObservationsTest = numel(annotationsTest);numIterationsTest = ceil(numObservationsTest/miniBatchSize);captionsTestPred = strings(1,numObservationsTest);documentsTestPred = tokenizedDocument(strings(1,numObservationsTest));i = 1:numIterationsTest%小批指数。idxStart = (i-1)*miniBatchSize+1;idxEnd = min(i*miniBatchSize,numObservationsTest);idx = idxStart:idxEnd;Sz =数字(idx);读取图像。tbl = readByIndex(augimdsTest,idx);提取图像特征。X = cat(4,tbl.input{:});X = extractImageFeatures(net,X,inputMin,inputMax,executionEnvironment);生成标题。captionsPredMiniBatch = strings(1,sz);documentsPredMiniBatch = tokenizedDocument(strings(1,sz));parforj = 1:sz words = beamSearch(X(:,:,j),beamIndex,parametersEncoder,parametersDecoder,enc,maxNumWords);captionsPredMiniBatch(j) = join(words);documentsPredMiniBatch(j) = tokenizedDocument(words,TokenizeMethod=“没有”);结束captionsTestPred(idx) = captionsPredMiniBatch;documentsTestPred(idx) = documentsPredMiniBatch;结束
分析文件并将文件传输给工作人员…完成。

要查看具有相应标题的测试图像,请使用imshow函数并将标题设置为预测的标题。

Idx = 1;tbl = readByIndex(augimdsTest,idx);Img = tbl.input{1};title(captionsTestPred(idx))

评估模型精度

为了使用BLEU分数来评估字幕的准确性,请使用bleuEvaluationScore函数。使用bleuEvaluationScore函数时,可以将单个候选文档与多个引用文档进行比较。

bleuEvaluationScore函数在默认情况下使用长度为1到4的n-grams对相似性进行评分。由于标题很短,这种行为可能导致没有信息的结果,因为大多数分数接近于零。属性将n-gram长度设置为1到2NgramWeights选项为具有相等权重的两元素向量。

ngramWeights = [0.5 0.5];i = 1:numObservationsTest annotation = annotationsTest(i);captionIDs =注解。captionIDs;candidate = documentsTestPred(i);references = documentsAll(标题id);得分= bleuEvaluationScore(候选人,引用,NgramWeights= NgramWeights);分数(i) =分数;结束

查看BLEU平均得分。

scoreMean =平均(分数)
scoreMean = 0.4224

在直方图中可视化分数。

图直方图(分数)“蓝色分数”) ylabel (“频率”

注意函数

注意函数使用Bahdanau注意计算上下文向量和注意权重。

函数[contextVector, attentionWeights] =注意(隐藏,特征,weights1,...bias1、weights2 bias2、weightsV biasV)模型尺寸。[embeddingDimension,numFeatures,miniBatchSize] = size(features);numHiddenUnits = size(weights1,1);%完全连接。Y1 =重塑(features,embeddingDimension, numFeatures*miniBatchSize);Y1 = fulllyconnect (Y1,weights1,bias1,DataFormat=“CB”);Y1 =重塑(Y1,numHiddenUnits,numFeatures,miniBatchSize);%完全连接。Y2 = fulllyconnect (hidden,weights2,bias2,DataFormat=“CB”);Y2 =重塑(Y2,numHiddenUnits,1,miniBatchSize);%加法,tanh。scores = tanh(Y1 + Y2);scores =重塑(scores, numHiddenUnits, numFeatures*miniBatchSize);%完全连接,softmax。attentionWeights = fulllyconnect (scores,weightsV,biasV,DataFormat=“CB”);注意重量=重塑(注意重量,1,numFeatures,miniBatchSize);attentionWeights = softmax(attentionWeights,DataFormat=“渣打银行”);%的上下文。contextVector = attentionWeights .* features;contextVector = squeeze(sum(contextVector,2));结束

嵌入函数

嵌入函数将索引数组映射到嵌入向量序列。

函数Z =嵌入(X,权重)将输入重塑为向量[N, T] = size(X, 1:2);X =重塑(X, N*T, 1);嵌入矩阵的索引Z =权重(:,X);通过分离批次和序列尺寸来重塑输出Z =重塑(Z, [], N, T);结束

特征提取函数

extractImageFeatures函数将一个已训练的对象作为输入dlnetwork对象,一个输入图像、图像重新缩放的统计数据和执行环境,并返回一个dlarray包含从预训练网络中提取的特征。

函数X = extractImageFeatures(net,X,inputMin,inputMax,executionEnvironment)调整大小和缩放。inputSize = net.Layers(1).InputSize(1:2);X = imresize(X,inputSize);X = rescale(X,-1,1,InputMin= InputMin,InputMax= InputMax);%转换为darray。X = dlarray(X,“SSCB”);%转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”X = gpuArray(X);结束提取特征并重塑。X = predict(net,X);sz = size(X);numFeatures = sz(1) * sz(2);inputSizeEncoder = sz(3);miniBatchSize = sz(4);X =重塑(X,[numFeatures inputSizeEncoder miniBatchSize]);结束

批量创建命令功能

createBatch函数以小批量数据、标记化的标题、预训练的网络、用于图像缩放的统计数据、单词编码和执行环境作为输入,并返回与提取的图像特征和标题相对应的小批量数据用于训练。

函数[X, T] = createBatch(X,documents,net,inputMin,inputMax,enc,executionEnvironment) X = extractImageFeatures(net,X,inputMin,inputMax,executionEnvironment);将文档转换为单词索引序列。T = doc2sequence(enc,documents,PaddingDirection=“正确”, PaddingValue = enc.NumWords + 1);T = cat(1,T{:});将小批量数据转换为大数组。T = dlarray(T);如果在GPU上训练,则将数据转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”T = gpuArray(T);结束结束

编码器模型函数

modelEncoder函数接受一个激活数组作为输入X并将其通过全连接操作和ReLU操作传递。对于全连接操作,仅对通道维度进行操作。方法将其他通道平展为一个维度,并将该维度指定为批处理维度DataFormat选项fullyconnect函数。

函数Y = modelEncoder(X,parametersEncoder) [numFeatures,inputSizeEncoder,miniBatchSize] = size(X);%完全连接weights = parametersencode .fc. weights;bias = parametersencode .fc. bias;embeddingDimension = size(weights,1);X = permute(X,[2 1 3]);X =重塑(X,inputSizeEncoder,numFeatures*miniBatchSize);Y = fulllyconnect (X,权重,偏差,DataFormat=“CB”);Y =重塑(Y,embeddingDimension,numFeatures,miniBatchSize);% ReLUY = relu(Y);结束

解码器模型函数

modelDecoder函数以单个时间步长作为输入X,解码器模型参数,编码器的特征和网络状态,并返回对下一个时间步长的预测,更新的网络状态和注意力权重。

函数[Y,state,attentionWeights] = modelDecoder(X,parametersDecoder,features,state) hiddenState = state.gru. hiddenState;%的关注weights1 = parametersDecoder.attention.Weights1;bias1 = parametersdecode .attention. bias1;weights2 = parametersDecoder.attention.Weights2;bias2 = parametersDecoder.attention.Bias2;weightsV = parametersDecoder.attention.WeightsV;biasV = parametersdecode .attention. biasV;[contextVector, attentionWeights] = attention(hiddenState,features,weights1,bias1,weights2,bias2,weightsV,biasV);%嵌入weights = parametersDecoder.emb.Weights;X =嵌入(X,权重);%连接Y = cat(1,contextVector,X);%格勒乌inputwights = parametersdecoder .gru. inputwights;recurrentwights = parametersdecoder .gru. recurrentwights;bias = parametersDecoder.gru.Bias;[Y, hiddenState] = gru(Y, hiddenState, inputwights, recurrentwights, bias, DataFormat=“认知行为治疗”);%更新状态state.gru.HiddenState =隐藏状态;%完全连接weights = parametersDecoder.fc1.Weights;bias = parametersDecoder.fc1.Bias;Y = fulllyconnect (Y,权重,偏差,DataFormat=“CB”);%完全连接weights = parametersDecoder.fc2.Weights;bias = parametersDecoder.fc2.Bias;Y = fulllyconnect (Y,权重,偏差,DataFormat=“CB”);结束

模型的损失

modelLoss函数以编码器和解码器参数作为输入,编码器特征X,和目标标题T,并返回损失、编码器和解码器参数相对于损失的梯度以及预测。

函数(损失、gradientsEncoder gradientsDecoder YPred] =...modelLoss(parametersEncoder,parametersDecoder,X,T) miniBatchSize = size(X,3);sequenceLength = size(T,2) - 1;vocabSize = size(parametersDecoder.emb.Weights,2);型号编码器features = modelEncoder(X,parametersEncoder);初始化状态numHiddenUnits = size(parametersDecoder.attention.Weights1,1);State = struct;state.gru.HiddenState = dlarray(0 ([numHiddenUnits miniBatchSize],“单身”));YPred = dlarray(0 ([vocabSize miniBatchSize sequenceLength],“喜欢”, X));损失= dlarray(single(0));padToken = vocabSize;t = 1:sequenceLength decoderInput = t (:,t);YReal = T(:, T +1);[YPred(:,:,t),state] = modelDecoder(decoderInput,parametersDecoder,features,state);mask = YReal ~= padToken;loss = loss + sparseCrossEntropyAndSoftmax(YPred(:,:,t),YReal,mask);结束计算梯度[gradientsEncoder,gradientsDecoder] = dlgradient(loss, parametersEncoder,parametersDecoder);结束

稀疏交叉熵与软最大损失函数

sparseCrossEntropyAndSoftmax将预测作为输入Y,对应的指标T和序列填充掩码,并应用softmax函数并返回交叉熵损失。

函数loss = sparseCrossEntropyAndSoftmax(Y, T, mask) miniBatchSize = size(Y, 2);% Softmax。Y = softmax(Y,DataFormat=“CB”);查找与目标单词对应的行。idx = sub2ind(size(Y), T', 1:miniBatchSize);Y = Y(idx);%远离0。Y = max(Y, single(1e-8));%掩码损失。loss = log(Y) .* mask';损失= -sum(损失,“所有”) ./ miniBatchSize;结束

波束搜索函数

beamSearch函数以图像特征作为输入X,波束索引,编码器和解码器网络的参数,单词编码和最大序列长度,并使用波束搜索算法返回图像的标题词。

函数[words,attentionScores] = beamSearch(X,beamIndex,parametersEncoder,parametersDecoder,...enc, maxNumWords)%模型尺寸numFeatures = size(X,1);numHiddenUnits = size(parametersDecoder.attention.Weights1,1);提取特征features = modelEncoder(X,parametersEncoder);初始化状态State = struct;state.gru.HiddenState = dlarray(0 ([numHiddenUnits 1],“喜欢”, X));初始化候选候选人= struct;候选人。状态=状态;候选人。话说=“<开始>”;候选人。得分= 0;候选人。注意分数= dlarray(零([numFeatures maxNumWords],“喜欢”, X));候选人。StopFlag= false; t = 0;%循环单词t < maxNumWords t = t + 1;candidatesNew = [];%遍历候选人I = 1:数字(候选人)当预测到停止令牌时停止生成如果候选人(i)。StopFlag继续结束%候选人详细信息状态=候选人(i).状态;words =考生(i).Words;分数=考生(i).分数;注意分数=考生(i).注意分数;%预测下一个令牌decoderInput = word2ind(enc,words(end));[YPred,state,attentionScores(:,t)] = modelDecoder(decoderInput,parametersDecoder,features,state);YPred = softmax(YPred,DataFormat=“CB”);[scoresTop,idxTop] = maxk(extractdata(YPred),beamIndex);idxTop = gather(idxTop);循环顶部的预测j = 1:beamIndex candidate = struct;candidateWord = ind2word(enc,idxTop(j));candidateScore = scoresTop(j);如果candidateWord = =“<停止>”候选人。StopFlag= true; attentionScores(:,t+1:end) = [];其他的候选人。StopFlag= false;结束候选人。状态=状态;候选人。话说=[words candidateWord]; candidate.Score = score + log(candidateScore); candidate.AttentionScores = attentionScores; candidatesNew = [candidatesNew candidate];结束结束%寻找最佳候选人[~,idx] = maxk([candidatesNew.Score],beamIndex);候选人=候选人新(idx);当所有候选对象都有停止令牌时停止预测如果([candidates.StopFlag])打破结束结束%找到最佳候选人words = candidate (1).Words(2:end-1);attentionScores =考生(1).AttentionScores;结束

荣耀权重初始化函数

initializeGlorot函数根据gloot初始化生成一个权重数组。

函数weights = initializeGlorot(numOut, numIn) varWeights = sqrt(6 / (numIn + numOut));权重= varWeights * (2 * rand([numOut, numIn],“单身”) - 1);结束

另请参阅

(文本分析工具箱)|(文本分析工具箱)|(文本分析工具箱)|||||||||(文本分析工具箱)|

相关的话题