利用注意的顺序对顺序的翻译
这个例子展示了如何使用循环序列到序列的编码器-解码器模型将十进制字符串转换为罗马数字。
循环编码器-解码器模型在抽象文本摘要和神经机器翻译等任务中已被证明是成功的。该模型由一个编码器它通常使用循环层(如LSTM)和译码器它将编码的输入映射到所需的输出,通常使用第二个循环层。模型包含注意机制进入模型允许解码器在生成翻译时专注于编码输入的部分。
对于编码器模型,本示例使用一个简单的网络,它由一个嵌入和一个LSTM操作组成。嵌入是一种将类别标记转换为数值向量的方法。
对于解码器模型,本例使用了一个包含LSTM操作和注意机制的网络。注意机制允许解码器参加对编码器的特定部分进行输出。
负荷训练数据
下载十进制罗马数字对“romanNumerals.csv”
.
文件名= fullfile(“romanNumerals.csv”);options = detectImportOptions(文件名,...TextType =“字符串”,...ReadVariableNames = false);选项。变量名= [“源”“目标”];选项。变量类型= [“字符串”“字符串”];Data = readtable(filename,options);
将数据分割为训练和测试分区,每个分区包含50%的数据。
Idx = randperm(size(data,1),500);dataTrain = data(idx,:);dataTest =数据;dataTest(idx,:) = [];
查看一些十进制罗马数字对。
头(dataTrain)
源目标 ______ ____________ " 437年”“CDXXXVII”“431”“CDXXXI”“102年”“人民共和国”“862年”“DCCCLXII”“738年”“DCCXXXVIII”“527年”“DXXVII”“401年”“CDI”“184年”“CLXXXIV”
数据进行预处理
方法对文本数据进行预处理transformText
函数,在示例末尾列出。的transformText
函数对输入文本进行预处理和标记化以进行翻译,方法是将文本分割为字符并添加开始和停止标记。要通过将文本拆分为单词而不是字符来翻译文本,请跳过第一步。
startToken =“<开始>”;stopToken =“<停止>”;strSource = dataTrain.Source;documentsSource = transformText(strSource,startToken,stopToken);
创建一个wordEncoding
对象,该对象使用词汇表将标记映射到数值索引,反之亦然。
encSource = wordEncoding(documentsSource);
使用单词编码,将源文本数据转换为数字序列。
sequencesSource = doc2sequence(encSource,documentsSource,PaddingDirection=“没有”);
使用相同的步骤将目标数据转换为序列。
strTarget = dataTrain.Target;documentsTarget = transformText(strTarget,startToken,stopToken);encTarget = wordcoding (documentsTarget);sequencesTarget = doc2sequence(encTarget,documentsTarget,PaddingDirection=“没有”);
按长度对序列排序。用增加序列长度排序的序列进行训练,会得到序列长度大致相同的批次,并确保在较长序列批次之前使用较小的序列批次更新模型。
sequenceLengths = cellfun(@(序列)size(序列,2),sequencesSource);[~,idx] = sort(sequenceLengths);sequencesSource = sequencesSource(idx);sequencesTarget = sequencesTarget(idx);
创建arrayDatastore
对象中包含源数据和目标数据,并使用结合
函数。
sequencesSourceDs = arrayDatastore(sequencesSource,OutputType=“相同”);sequencesTargetDs = arrayDatastore(sequencesTarget,OutputType=“相同”);sequencesDs = combine(sequencesSourceDs,sequencesTargetDs);
初始化模型参数
初始化模型参数。对于编码器和解码器,都指定一个128的嵌入维数,一个包含100个隐藏单元的LSTM层,以及随机dropout层(概率为0.05)。
embeddingDimension = 128;numHiddenUnits = 100;辍学率= 0.05;
初始化编码器模型参数
函数初始化编码嵌入的权值initializeGaussian
函数,该函数作为支持文件附加到本示例中。金宝app指定平均值为0,标准差为0.01。要了解更多,请参见高斯函数初始化(深度学习工具箱).
inputSize = encSource。NumWords + 1;sz = [embeddingDimension inputSize];Mu = 0;σ = 0.01;parameters.encode .emb. weights = initializgaaussian (sz,mu,sigma);
初始化编码器LSTM操作的可学习参数:
初始化编码器LSTM操作的可学习参数。
sz = [4*numHiddenUnits embeddingDimension];numOut = 4*numHiddenUnits;numIn = embeddingDimension;parameters.encode .lstm. inputweights = initializeGlorot(sz,numOut,numIn);parameters.encode .lstm. recurrentweights = initializeOrthogonal([4*numHiddenUnits numHiddenUnits]);parameters.encode .lstm. bias = initializeUnitForgetGate(numHiddenUnits);
初始化解码器模型参数
函数初始化编码嵌入的权值initializeGaussian
函数。指定平均值为0,标准差为0.01。
outputSize = encTarget。NumWords + 1;sz = [embeddingDimension outputSize];Mu = 0;σ = 0.01;parameters.decoder.emb.Weights = initializgaaussian (sz,mu,sigma);
方法使用gloot初始化器初始化注意机制的权重initializeGlorot
函数。
sz = [numHiddenUnits];numOut = numHiddenUnits;numIn = numHiddenUnits;parameters.decoder.attention.Weights = initializeGlorot(sz,numOut,numIn);
初始化解码器LSTM操作的可学习参数:
方法使用gloot初始化式初始化输入权重
initializeGlorot
函数。方法使用正交初始化式初始化递归权值
initializeOrthogonal
函数。使用单元忘记门初始化器初始化偏置
initializeUnitForgetGate
函数。
初始化解码器LSTM操作的可学习参数。
sz = [4*numHiddenUnits embeddingDimension+numHiddenUnits];numOut = 4*numHiddenUnits;numIn = embeddingDimension + numHiddenUnits;parameters.decoder.lstm.InputWeights = initializeGlorot(sz,numOut,numIn);parameters. decoders .lstm. recurrentweights = initializeOrthogonal([4*numHiddenUnits numHiddenUnits]);parameters.decoder.lstm.Bias = initializeUnitForgetGate(numHiddenUnits);
初始化解码器全连接操作的可学习参数:
使用gloot初始化器初始化权值。
方法初始化带有零的偏置
initializeZeros
函数,该函数作为支持文件附加到本示例中。金宝app要了解更多,请参见零初始化(深度学习工具箱).
sz = [outputSize 2*numHiddenUnits];numOut = outputSize;numIn = 2*numHiddenUnits;parameters.decoder.fc.Weights = initializeGlorot(sz,numOut,numIn);parameters. decoer .fc. bias = initializeZeros([outputSize 1]);
定义模型函数
创建函数modelEncoder
而且modelDecoder
,分别计算编码器和解码器模型的输出。
的modelEncoder
函数中列出的编码器模型函数部分,接受输入数据、模型参数、用于确定训练的正确输出的可选掩码,并返回模型输出和LSTM隐藏状态。
的modelDecoder
函数中列出的解码器模型函数部分,取输入数据、模型参数、上下文向量、LSTM初始隐藏状态、编码器输出和辍学概率,输出解码器输出、更新的上下文向量、更新的LSTM状态和注意评分。
定义模型损失函数
创建函数modelLoss
,列于模型损失函数示例的部分,该部分采用编码器和解码器模型参数、一小批输入数据和与输入数据对应的填充掩码,以及退出概率,并返回损失和损失相对于模型中可学习参数的梯度。
指定培训选项
训练小批次大小为32,100课时,学习率为0.001。
miniBatchSize = 32;numEpochs = 100;learnRate = 0.001;
初始化Adam的选项。
gradientDecayFactor = 0.9;squaredGradientDecayFactor = 0.999;
火车模型
使用自定义训练循环训练模型。使用minibatchqueue
处理和管理培训期间的小批量图像。对于每个小批次:
使用自定义的小批量预处理功能
preprocessMiniBatch
(在本例末尾定义)来查找小批处理中所有序列的长度,并分别为源序列和目标序列将序列填充到与最长序列相同的长度。排列填充序列的第二个和第三个维度。
返回未格式化的小批处理变量
dlarray
具有基础数据类型的对象单
.所有其他输出都是数据类型的数组单
.如果有GPU,请使用GPU进行训练。返回GPU上的所有小批处理变量(如果有的话)。使用GPU需要并行计算工具箱™和支持的GPU设备。金宝app有关支持的设备的信息,请参见GPU按版金宝app本支持。
的minibatchqueue
对象为每个迷你批处理返回四个输出参数:源序列、目标序列、迷你批处理中所有源序列的长度以及目标序列的序列掩码。
numMiniBatchOutputs = 4;mbq = minibatchqueue(sequencesDs,numMiniBatchOutputs,...MiniBatchSize = MiniBatchSize,...MiniBatchFcn = @ (x, t) preprocessMiniBatch (x, t, inputSize outputSize));
的值初始化adamupdate
函数。
trailingAvg = [];trailingAvgSq = [];
计算训练进度监视器的总迭代次数
numObservationsTrain = numel(sequencsource);numIterationsPerEpoch = ceil(numObservationsTrain / miniBatchSize);numIterations = numEpochs * numIterationsPerEpoch;
初始化训练进度监视器。因为计时器在创建监视器对象时开始,所以要确保创建的对象接近训练循环。
(培训进度)...指标=“损失”,...信息=“时代”,...包含=“迭代”);
训练模型。对于每个小批次:
阅读一小批填充序列。
计算损耗和梯度。
方法更新编码器和解码器模型参数
adamupdate
函数。更新培训进度监测器。
停止训练
停止
训练进度监视器的属性为真正的
.的停止
属性更改为1
当你点击停止按钮时。
纪元= 0;迭代= 0;循环遍历各个时代。而epoch < numEpochs && ~monitor。停止epoch = epoch + 1;重置(兆贝可);在小批量上循环。而Hasdata (mbq) && ~monitor。停止iteration = iteration + 1; [X,T,sequenceLengthsSource,maskSequenceTarget] = next(mbq);%计算损失和梯度。[loss,gradient] = dlfeval(@modelLoss,parameters,X,T,sequenceLengthsSource,...maskSequenceTarget,辍学);使用adamupdate更新参数。[parameters,trailingAvg,trailingAvgSq] = adamupdate(参数,gradient,trailingAvg,trailingAvgSq,...迭代,learnRate、gradientDecayFactor squaredGradientDecayFactor);按序列长度归一化损失。loss = loss ./ size(T,3);更新培训进度监视器。recordMetrics(监控、迭代损失=损失);updateInfo(监视、时代=时代+"的"+ numEpochs);班长。进度= 100*迭代/numIterations;结束结束
生成翻译
要使用训练过的模型为新数据生成翻译,请使用与训练时相同的步骤将文本数据转换为数字序列,并将序列输入编码器-解码器模型,并使用令牌索引将结果序列转换回文本。
使用与训练时相同的步骤对文本数据进行预处理。使用transformText
函数将文本拆分为字符并添加开始和停止标记。
strSource = dataTest.Source;strTarget = dataTest.Target;
翻译文本使用modelPredictions
函数。
maxSequenceLength = 10;分隔符="";strTranslated = translateText(参数,strSource,maxSequenceLength,miniBatchSize,...encSource、encTarget startToken stopToken,分隔符);
创建一个包含测试源文本、目标文本和翻译的表。
TBL =表;资源描述。Source = strSource;资源描述。Target = strTarget;资源描述。翻译了= strTranslated;
查看翻译的随机选择。
idx = randperm(size(dataTest,1),miniBatchSize);台(idx:)
ans =32×3表来源目标翻译______ ___________ ____________“996”“CMXCVI”“CMMXCVI”“576”“DLXXVI”“DCLXXVI”“86”“LXXXVI”“DCCCLXV”“23”“XXIII”“CCCCXIII”“99”“XCIX”“CMMXIX”“478”“CDLXXVIII”“dccclxiii”“313”“CCCXIII”“CCCXIII”“60”“LX”“DLX”“864”“DCCCLXIV”“DCCCLIV”“280”“CCLXXX”“dccclxii”“DCCCLIV”“959”“CMLIX”“CMLXI”“283”“ccclxiii”“CCCCVI”“534”“DCCXXIV”“721”“DCCXXI”“DCCCII”等
文本转换功能
的transformText
函数对输入文本进行预处理和标记化以进行翻译,方法是将文本分割为字符并添加开始和停止标记。要通过将文本拆分为单词而不是字符来翻译文本,请跳过第一步。
函数documents = transformText(str,startToken,stopToken) str = strip(replace(str, stopToken))"",”“));str = startToken + str + stopToken;documents = tokenizedDocument(str,CustomTokens=[startToken stopToken]);结束
小批量预处理功能
的preprocessMiniBatch
函数对数据进行预处理以进行训练,该函数在本例的训练模型部分中进行了描述。该函数使用以下步骤对数据进行预处理:
确定小批处理中所有源序列和目标序列的长度
方法将序列填充到与迷你批处理中最长序列相同的长度
padsequences
函数。排列序列的最后两个维度
函数[X,T,sequenceLengthsSource,maskTarget] = preprocessMiniBatch(sequencesSource,sequencesTarget,inputSize,outputSize) sequenceLengthsSource = cellfun(@(X) size(X, 2),sequencesSource);X = padsequences(sequencesSource,2,PaddingValue=inputSize);X = permute(X,[1 3 2]);[T,maskTarget] = padsequences(sequencesTarget,2,PaddingValue=outputSize);T = permute(T,[1 3 2]);maskTarget = permute(maskTarget,[1 3 2]);结束
模型损失函数
的modelLoss
函数获取编码器和解码器模型参数、一小批输入数据和与输入数据相对应的填充掩码,以及退出概率,并返回损失和损失相对于模型中可学习参数的梯度。
函数[loss,gradient] = modelLoss(参数,X,T,...sequenceLengthsSource maskTarget,辍学)%通过编码器前进。[Z,hiddenState] = modelEncoder(parameters.encoder,X,sequenceLengthsSource);%解码器输出。doteacherforced = rand < 0.5;序列长度= size(T,3);Y = decoderprediction (parameters.decoder,Z,T,hiddenState,dropout,...doTeacherForcing sequenceLength);隐藏损失。Y = Y(:,:,1:end-1);T = extractdata(gather(T(:,:,2:结束)));T = onehotencode(T,1,ClassNames=1:size(Y,1));maskTarget = maskTarget(:,:,2:end);maskTarget = repmat(maskTarget,[size(Y,1),1,1]);loss = crossentropy(Y,T,Mask=maskTarget,Dataformat=“认知行为治疗”);%更新渐变。gradient = dlgradient(损失,参数);结束
编码器模型函数
这个函数modelEncoder
获取输入数据、模型参数、用于确定训练的正确输出的可选掩码,并返回模型输出和LSTM隐藏状态。
如果sequenceLengths
为空,则函数不屏蔽输出。指定并为空值sequenceLengths
当使用modelEncoder
预测函数。
函数[Z,hiddenState] = modelEncoder(parameters,X,sequenceLengths)%嵌入。weights = parameters.emb.Weights;Z = embed(X,weights,DataFormat=“认知行为治疗”);% LSTM。inputWeights = parameters.lstm.InputWeights;recurrentWeights = parameters.lstm.RecurrentWeights;bias = parameters.lstm.Bias;numHiddenUnits = size(recurrentWeights, 2);initialHiddenState = dlarray(0 ([numHiddenUnits 1]));initialCellState = dlarray(0 ([numHiddenUnits 1]));[Z,hiddenState] = lstm(Z,initialHiddenState,initialCellState,inputWeights,...recurrentWeights,偏见,DataFormat =“认知行为治疗”);%掩蔽训练。如果~isempty(sequenceLengths) miniBatchSize = size(Z,2);为n = 1:miniBatchSize hiddenState(:,n) = Z(:,n,sequenceLengths(n));结束结束结束
解码器模型函数
这个函数modelDecoder
取输入数据、模型参数、上下文向量、LSTM初始隐藏状态、编码器输出、dropout概率,输出解码器输出、更新的上下文向量、更新的LSTM状态、注意评分。
函数[Y,context,hiddenState,attentionScores] = modelDecoder(参数,X,context,...hiddenState, Z,辍学)%嵌入。weights = parameters.emb.Weights;X = embed(X,weights,DataFormat=“认知行为治疗”);% RNN输入。sequenceLength = size(X,3);Y = cat(1, X, repmat(context,[1 1 sequenceLength]));% LSTM。inputWeights = parameters.lstm.InputWeights;recurrentWeights = parameters.lstm.RecurrentWeights;bias = parameters.lstm.Bias;initialCellState = dlarray(0 (size(hiddenState)));[Y,hiddenState] = lstm(Y,hiddenState,initialCellState,...inputWeights recurrentWeights,偏见,DataFormat =“认知行为治疗”);%的辍学生。mask = rand(size(Y),“喜欢”,Y) >辍学;Y = Y *掩模;%的注意。weights = parameters.attention.Weights;[context,attentionScores] = luongAttention(hiddenState,Z,weights);%连接。Y = cat(1, Y, repmat(context,[1 1 sequenceLength]));%完全连接。weights = parameters.fc.Weights;bias = parameters.fc.Bias;Y =完全连接(Y,权重,偏差,DataFormat=“认知行为治疗”);% Softmax。Y = softmax(Y,DataFormat=“认知行为治疗”);结束
梁注意函数
的luongAttention
函数根据Luong“一般”评分[1]返回上下文向量和注意评分。这相当于分别将查询、键和值指定为隐藏状态、加权潜在表示和潜在表示的点积注意。
函数[context,attentionScores] = luongAttention(hiddenState,Z,weights) numHeads = 1;queries = hiddenState;keys = pagemtimes(weights,Z);values = Z;[context,attentionScores] = attention(查询,键,值,numHeads,...规模= 1,...DataFormat =“认知行为治疗”);结束
解码器模型预测函数
的decoderModelPredictions
函数返回预测的序列Y
给定输入序列、目标序列、隐藏状态、退出概率、启用教师强制的标志和序列长度。
函数Y = decoderprediction(参数,Z,T,hiddenState,dropout,...doTeacherForcing sequenceLength)%转换为dlarray。T = dlarray(T);初始化上下文。miniBatchSize = size(T,2);numHiddenUnits = size(Z,1);context = zero ([numHiddenUnits miniBatchSize],“喜欢”, Z);如果doTeacherForcing%通过解码器转发。Y = modelDecoder(参数,T,上下文,hiddenState,Z,dropout);其他的获得解码器的第一步。decoderInput = T(:,:,1);初始化输出。numClasses = numel(parameters.fc.Bias);Y = 0 ([numClasses miniBatchSize sequenceLength],“喜欢”, decoderInput);%循环时间步骤。为t = 1:sequence elength%通过解码器转发。[Y(:,:,t), context, hiddenState] = modelDecoder(parameters,decoderInput,context,...hiddenState, Z,辍学);%更新解码器输入。[~, decoderInput] = max(Y(:,:,t),[],1);结束结束结束
文本翻译功能
的translateText
函数通过在小批量上迭代转换文本数组。该函数将模型参数、输入字符串数组、最大序列长度、小批处理大小、源和目标字编码对象、开始和停止标记以及用于组装输出的分隔符作为输入。
函数strTranslated = translateText(参数,strSource,maxSequenceLength,miniBatchSize,...encSource、encTarget startToken stopToken,分隔符)转换文本。documentsSource = transformText(strSource,startToken,stopToken);sequencesSource = doc2sequence(encSource,documentsSource, doc2sequence)...PaddingDirection =“正确”,...PaddingValue = encSource。NumWords + 1);%转换为dlarray。X = cat(3,sequencesSource{:});X = permute(X,[1 3 2]);X = dlarray(X);初始化输出。numObservations = numel(strSource);strTranslated = strings(numObservations,1);在小批量上循环。numIterations = ceil(numObservations / miniBatchSize);为i = 1:numIterations idxMiniBatch = (i-1)*miniBatchSize+1:min(i*miniBatchSize,numObservations);miniBatchSize = numel(idxMiniBatch);%使用模型编码器编码。sequenceLengths = [];[Z, hiddenState] = modelEncoder(parameters.encoder,X(:,idxMiniBatch,:),sequenceLengths);解码器预测。doteacherforced = false;Dropout = 0;decoderInput = repmat(word2ind(encTarget,startToken),[1 miniBatchSize]);decoderInput = dlarray(decoderInput);Y = decoderprediction (parameters.decoder,Z,decoderInput,hiddenState,dropout,...doTeacherForcing maxSequenceLength);[~, idxPred] = max(extractdata(Y),[],1);继续翻译国旗。idxStop = word2ind(encTarget,stopToken);keeptranslated = idxPred ~= idxStop;%循环时间步骤。T = 1;而t <= maxSequenceLength && any(keeptranslations (:,:,t))%更新输出。newWords = ind2word(encTarget, idxPred(:,:,t))';idxUpdate = idxMiniBatch(keeptranslation (:,:,t));strTranslated(idxUpdate) = strTranslated(idxUpdate) + delimiter + newWords(keeptranslations (:,:,t));T = T + 1;结束结束结束
参考书目
[1] Luong, Minh-Thang, Hieu Pham, Christopher D. Manning。“基于注意力的神经网络机器翻译的有效方法。”arXiv预打印arXiv:1508.04025(2015)。
另请参阅
word2ind
|tokenizedDocument
|wordEncoding
|dlarray
(深度学习工具箱)|adamupdate
(深度学习工具箱)|dlupdate
(深度学习工具箱)|dlfeval
(深度学习工具箱)|dlgradient
(深度学习工具箱)|crossentropy
(深度学习工具箱)|softmax
(深度学习工具箱)|lstm
(深度学习工具箱)|doc2sequence