主要内容

使用自动编码器生成文本

这个例子展示了如何使用自动编码器生成文本数据。

AutoEncoder是一种培训以复制其输入的深层学习网络。AutoEncoder由两个较小的网络组成:和编码器和解码器。编码器将输入数据映射到一些潜在空间中的特征向量。解码器使用该潜在空间中的向量重建数据。

培训过程无人监督。换句话说,该模型不需要标记数据。要生成文本,可以使用解码器从任意输入重建文本。

这个例子训练一个自动编码器来生成文本。编码器使用单词嵌入和LSTM操作将输入文本映射到潜在向量。解码器使用LSTM操作和相同的嵌入来从潜在向量重建文本。

加载数据

该文件sonnets.txt.包含单个文本文件中的所有莎士比亚的十四赛。

从文件中阅读莎士比亚的十四赛数据“sonnets.txt”

文件名=“sonnets.txt”;textdata = fileread(filename);

十四行诗用两个空格缩进。使用删除缩进代替将文本分割成单独的行分裂函数。从前九个元素和短十四圈标题中删除标题。

textData =取代(textData,"");textData =分裂(textData、换行符);textData (1:9) = [];textData (strlength (textData) < 5) = [];

准备数据

创建一个用于标记和预处理文本数据的函数。这个函数preprocessText,执行以下步骤:

  1. 分别用指定的开始标记和停止标记添加和附加每个输入字符串。

  2. 使用授权文本tokenizedDocument

预处理文本数据并指定start和stop令牌“<开始>”“<停止>”,分别。

startToken =“<开始>”;stopToken =“<停止>”;文件= preprocessText (textData startToken stopToken);

从标记化的文档创建单词编码对象。

内附= wordEncoding(文件);

在培训深度学习模型时,输入数据必须是包含固定长度序列的数字阵列。由于文档具有不同的长度,因此必须使用填充值填充较短的序列。

重新创建单词编码以包括填充令牌并确定该令牌的索引。

paddingtoken =“<垫>”;(内附newVocabulary =。词汇paddingToken];内附= wordEncoding (newVocabulary);paddingToken paddingIdx = word2ind (enc)
paddingIdx = 3595

初始化模型参数

初始化以下模型的参数。

在这里, T 为序列长度, x 1 x T 输入序列是字索引,和 y 1 y T 为重建序列。

编码器将单词索引序列映射到潜在向量,通过嵌入将输入转换为单词向量序列,将单词向量序列输入到LSTM操作中,并对LSTM输出的最后一个时间步进行全连接操作。解码器使用初始化编码器输出的LSTM重新构造输入。对于每个时间步长,解码器预测下一个时间步长,并使用下一个时间步长预测的输出。编码器和解码器都使用相同的嵌入。

指定参数的尺寸。

EmbeddingDimension = 100;numhidandunits = 150;LatentDimension = 75;vocabularySize = enc.NumWords;

为参数创建一个结构体。

参数=结构;

使用高斯函数初始化嵌入的权值initializeGaussian函数,该函数作为支持文件附加到本示例中。金宝app指定0的平均值和0.01的标准偏差。想要了解更多,请看高斯函数初始化

μ= 0;σ= 0.01;parameters.em . weights = initializeGaussian([embedingdimension vocabularySize],mu,sigma);

初始化编码器LSTM操作的可学习参数:

  • 属性使用gloria初始化器初始化输入权重initializeGlorot函数,该函数作为支持文件附加到本示例中。金宝app想要了解更多,请看Glorot初始化

  • 用正交初始化器初始化递归权值initializeOrthogonal函数,该函数作为支持文件附加到本示例中。金宝app想要了解更多,请看正交初始化

  • 使用单元遗忘门初始化器初始化偏差initializeUnitForgetGate函数,该函数作为支持文件附加到本示例中。金宝app想要了解更多,请看单元遗忘门初始化

sz = [4*numHiddenUnits embedingdimension]; / /隐藏尺寸numOut = 4 * numHiddenUnits;numIn = embeddingDimension;parameters.lstmEncoder.InputWeights = initializeGlorot(深圳、numOut numIn);parameters. lstmencoder . recurrentwights = initialize正交([4*numHiddenUnits numHiddenUnits]);parameters.lstmEncoder.Bias = initializeUnitForgetGate (numHiddenUnits);

初始化编码器完全连接操作的可读参数:

  • 用gloria初始化器初始化权重。

  • 属性用零初始化偏差initializeZeros函数,该函数作为支持文件附加到本示例中。金宝app想要了解更多,请看零初始化

sz = [latentDimension numHiddenUnits];numOut = latentDimension;numIn = numHiddenUnits;parameters.fcEncoder.Weights = initializeGlorot(深圳、numOut numIn);parameters.fcEncoder.Bias = initializeZeros([latentDimension 1]);

初始化解码器LSTM操作的可读参数:

  • 使用gloria初始化器初始化输入权重。

  • 用正交初始化器初始化循环权值。

  • 用单元遗忘门初始化器初始化偏差。

Sz = [4 * LatentDimension EmbeddingDimensile];numout = 4 * latentdimension;numIn = embeddingDimension;参数.lstmdecoder.inputwights = initializeglorot(sz,numout,numin);参数.lstmdecoder.recurrentweights = initialize正常([4 * latentdimension latentdimension]);参数.lstmdecoder.bias = nigentizezeros([4 * latentdimension 1]);

初始化解码器全连接操作的可学习参数:

  • 用gloria初始化器初始化权重。

  • 用零初始化偏差。

sz = [vocabularySize latentDimension];numOut = vocabularySize;numIn = latentDimension;parameters.fcDecoder.Weights = initializeGlorot(深圳、numOut numIn);parameters.fcDecoder.Bias = initializeZeros([vocabularySize 1]);

要了解有关体重初始化的更多信息,请参阅初始化模型函数的可学习参数

定义模型编码器功能

创建函数modelEncoder,列于编码器模型函数计算编码器模型的输出。的modelEncoder函数,将单词索引、模型参数和序列长度作为输入序列,并返回相应的潜在特征向量。要了解有关定义模型编码器函数的更多信息,请参见定义文本编码器模型函数

定义模型解码器功能

创建函数Modeldecoder.,列于译码器模型函数计算解码器模型的输出。的Modeldecoder.函数,将单词索引、模型参数和序列长度作为输入序列,并返回相应的潜在特征向量。要了解有关定义模型解码器函数的更多信息,请参见定义文本解码器模型函数

定义模型梯度函数

modelGradients功能,列出模型梯度函数示例的一部分,将模型的可学习参数,即输入数据作为输入dlX,以及用于掩蔽的序列长度向量,并返回损耗相对于可学习参数和相应损耗的梯度。要了解关于定义模型梯度函数的更多信息,请参见为自定义训练循环定义模型梯度函数

指定培训选项

指定培训选项。

火车100个时级批次大小为128。

miniBatchSize = 128;numEpochs = 100;

以0.01的学习率训练。

learnRate = 0.01;

在图中显示训练进度。

情节=“训练进步”

在可用的GPU上进行训练。使用GPU需要并行计算工具箱™和支持的GPU设备。金宝app有关支持的设备的信息,请参见金宝appGPU通金宝app过发布支持(并行计算工具箱)

executionEnvironment =“汽车”

列车网络的

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

初始化ADAM Optimizer的参数。

trailingAvg = [];trailingAvgSq = [];

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

如果情节= =“训练进步”figure lineosstrain = animatedline('颜色',[0.85 0.325 0.098]);Xlabel(“迭代”) ylabel (“损失”ylim([0 inf])网格结束

火车模型。对于第一个纪元,洗牌数据并在小批数据上循环。

为每个mini-batch:

  • 将文本数据转换为单词索引序列。

  • 将数据转换为dlarray

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

  • 计算损失和梯度。

  • 属性更新可学习参数adamupdate函数。

  • 更新培训进度图。

跑步训练可能需要一些时间。

numObservations =元素个数(文件);numIterationsPerEpoch = floor(nummobations / miniBatchSize);迭代= 0;开始=抽搐;时代= 1:numEpochs%洗牌。idx = randperm (numObservations);文档(文档(idx);i = 1:numIterationsPerEpoch iteration = iteration + 1;%读取迷你批处理。idx =(张)* miniBatchSize + 1:我* miniBatchSize;documentsBatch =文档(idx);%转换为序列。X = doc2sequence (enc documentsBatch,...“PaddingDirection”“对”...“PaddingValue”, paddingIdx);X =猫(1,X {:});%转换为美元。dlX = dlarray (X,“BTC”);如果在GPU上培训,则%将数据转换为GPUArray。如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlX = gpuArray (dlX);结束%计算序列长度。sequencelengths = doclength(DocuidetBatch);%评估模型梯度。[gradient,loss] = dlfeval(@modelGradients, parameters, dlX, sequenceLengths);%更新可学习参数。[参数,trailingavg,trailingavgsq] = adamupdate(参数,渐变,...trailighavg,trailingavgsq,迭代,学习);%显示训练进度。如果情节= =“训练进步”D =持续时间(0,0,toc(开始),“格式”“hh: mm: ss”);Addpoints(LineLoStrain,迭代,Double(收集(提取数据(丢失))))标题(”时代:“+时代+”,过去:“+ drawnow字符串(D))结束结束结束

生成文本

用不同的随机状态初始化解码器,使用闭环生成生成文本。闭环生成是指模型每次生成一个时间步长的数据,并使用前一个预测作为下一个预测的输入。

指定生成长度为16的3个序列。

numGenerations = 3;sequenceLength = 16;

创建一个随机值数组来初始化解码器状态。

dlz = dlarray(Randn(Latentdimension,Numgenerations),“CB”);

如果预测GPU,则将数据转换为gpuArray

如果(execultenvironment ==.“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray (dlZ);结束

使用模特预分规函数,列在示例的最后。的模特预分规函数返回给定模型参数、解码器初始状态、最大序列长度、字编码、开始令牌和迷你批大小的解码器的输出分数。

海底= modelDecoderPredictions(参数,dlZ sequenceLength, enc、startToken miniBatchSize);

找到分数最高的单词索引。

[~, idx] = max(海底,[],1);idx =挤压(idx);

将数字索引转换为单词并使用加入函数。

strGenerated =加入(enc.Vocabulary (idx));

方法提取第一个停止令牌之前的文本extractBefore函数。为了防止函数在没有停止标记时返回丢失,请在每个序列的末尾附加一个停止标记。

斯特尔根酸盐=提取物(Strgenerated + StopToken,StopToken);

删除填充令牌。

strGenerated =擦掉(strGenerated paddingToken);

生成过程在每个预测之间引入空白字符,这意味着一些标点字符出现时前后带有不必要的空格。通过删除适当的标点字符前后的空格来重建生成的文本。

删除出现在指定标点字符前的空格。

punctuationCharacters = [“。””、““”“)””:“”;““?”“!”];strGenerated =取代(strGenerated,+ punctuationCharacters punctuationCharacters);

删除指定标点字符后出现的空格。

punctuationCharacters = [”(““”];strGenerated = replace(strGenerated,punctuationCharacters + .,点击特征);

使用。删除前导和尾随空格函数并查看生成的文本。

斯特林=条状(酸分)
strGenerated =3×1的字符串"爱,你安息的轻,最好别让我看见你越走越远" "就像在他弯曲的镰刀的罗盘之前来找吧。"“夏天的了?真理一旦被领导,

编码器模型函数

modelEncoder函数,将模型参数、词索引序列和序列长度作为输入,返回相应的潜在特征向量。

由于输入数据包含不同长度的填充序列,填充可能对损失计算产生不利影响。对于LSTM操作,不是返回序列的最后一个时间步骤的输出(很可能对应于处理大量填充值后的LSTM状态),而是确定由sequenceLengths输入。

函数dlZ = modelEncoder(参数、dlX sequenceLengths)%嵌入。重量= parameters.emb.Weights;dlZ =嵌入(dlX、重量);% LSTM。Inputweights = parameters.lstmencoder.Inputweights;refurrentweights = parameters.lstmencoder.recurrentweights;bias = parameters.lstmencoder.bias;numhidendunits =尺寸(复制重量,2);hiddenstate = zeros(numhidendunits,1,'像'dlX);cellState = 0 (numHiddenUnits 1'像'dlX);dlZ1 = lstm (dlZ hiddenState、cellState inputWeights, recurrentWeights,偏见,'datomformat'“认知行为治疗”);%输出模式'last'与掩蔽。miniBatchSize =大小(dlZ1, 2);miniBatchSize, dlZ = 0 (numHiddenUnits'像'dlZ1);n = 1:miniBatchSize t = sequenceLengths(n);dlZ (:, n) = dlZ1 (:, n, t);结束%完全连接。重量= parameters.fcEncoder.Weights;偏见= parameters.fcEncoder.Bias;dlZ = fullyconnect(重量,dlZ偏见,'datomformat'“CB”);结束

译码器模型函数

Modeldecoder.函数,将模型参数、字索引序列和网络状态作为输入,并返回解码后的序列。

因为lstm函数是有状态(当给定一个时间序列作为输入时,函数会在每个时间步骤之间传播和更新状态)嵌入fullyconnect函数在默认情况下是时间分布的(当给定一个时间序列作为输入时,函数对每个时间步骤独立操作)Modeldecoder.函数支持序列和单时金宝app间步进输入。

函数(海底、州)= modelDecoder(参数、dlX状态)%嵌入。重量= parameters.emb.Weights;dlX =嵌入(dlX、重量);% LSTM。Inputweights = parameters.lstmdecoder.Inputweights;reachrentweights = parameters.lstmdecoder.recurrentweights;bias = parameters.lstmdecoder.bias;hiddenstate = state.hiddentstate;cellstate = state.cellstate;[dly,hiddenstate,cellstate] = lstm(dlx,hiddenstate,cellstate,...输入重量,复制重量,偏见,'datomformat'“认知行为治疗”);状态。HiddenState = HiddenState;状态。CellState = CellState;%完全连接。重量= parameters.fcDecoder.Weights;偏见= parameters.fcDecoder.Bias;海底= fullyconnect(海底,重量、偏见,'datomformat'“认知行为治疗”);% Softmax。海底= softmax(海底,'datomformat'“认知行为治疗”);结束

模型梯度函数

modelGradients用作输入模型学习参数的功能,输入数据dlX,以及用于掩蔽的序列长度向量,并返回损耗相对于可学习参数和相应损耗的梯度。

要计算屏蔽丢失,模型渐变功能使用maskedCrossEntropy损失函数,列在示例的最后。为训练解码器预测序列的下一个时间步长,指定目标为移动一个时间步长的输入序列。

要了解关于定义模型梯度函数的更多信息,请参见为自定义训练循环定义模型梯度函数

函数[gradient, loss] = modelGradients(parameters,dlX,sequenceLengths)%编码器模型。dlZ = modelEncoder(参数、dlX sequenceLengths);%初始化LSTM状态。状态=结构;状态。HiddenState = dlZ;状态。CellState = 0(大小(dlZ),'像', dlZ);%教师强迫。海底= modelDecoder(参数、dlX状态);%的损失。Dlypry = Dly(:,:,1:结束-1);DLT = DLX(:,:,2:结束);损失=平均值(MaskedCrossentropy(Dlyprow,DLT,Sequencelengs));%梯度。梯度= Dlgradient(损失,参数);%标准化绘制损耗。sequenceLength =大小(dlX, 3);loss = loss / sequenceLength;结束

模型的预测函数

模特预分规函数返回给定模型参数、解码器初始状态、最大序列长度、字编码、开始令牌和迷你批大小的解码器的输出分数。

函数dlY = modelDecoderPredictions(parameters,dlZ,maxLength,enc,startToken,miniBatchSize) numObservations = size(dlZ,2);numIterations = cell (nummobations / miniBatchSize);startToken startTokenIdx = word2ind (enc);vocabularySize = enc.NumWords;海底= 0 (vocabularySize numObservations,最大长度,'像', dlZ);%循环在迷你批次。i = 1:numiterations idxminibatch =(i-1)* minibatchsize + 1:min(i * minibatchsize,numobservations);minibatchsize = numel(idxminibatch);%初始化状态。状态=结构;状态。HiddenState = dlZ (:, idxMiniBatch);状态。CellState = 0(大小(dlZ (:, idxMiniBatch)),'像', dlZ);%初始化解码器输入。DecoderInput = DlArray(Repmat(StartTokeNiDX,[1 MiniBatchsize]),“认知行为治疗”);%循环时间步骤。t = 1:最大长度%预测下一个时间步骤。[dlY(:,idxMiniBatch,t), state] = modelDecoder(parameters,decoderInput,state);%闭环生成。[~, idx] = max(海底(:,idxMiniBatch t));decoderInput = idx;结束结束结束

屏蔽跨熵损耗功能

maskedCrossEntropy函数使用指定的序列长度向量计算指定输入序列与目标序列之间的损失,忽略包含填充的任何时间步骤。

函数maskedLoss = maskedcrosssentropy (dlY,T,sequenceLengths) numClasses = size(dlY,1);miniBatchSize =大小(海底,2);sequenceLength =大小(海底,3);maskedLoss = 0 (sequenceLength miniBatchSize,'像'、海底);t = 1:sequenceLength T1 = single(oneHot(t(:,:,t),numClasses));掩码= (t < = sequenceLengths) ';maskedLoss (t):) =面具。* crossentropy(海底(:,:,t), T1,'datomformat'“认知行为治疗”);结束maskedLoss = (maskedLoss, 1)之和;结束

文本预处理功能

这个函数preprocessText执行以下步骤:

  1. 分别用指定的开始标记和停止标记添加和附加每个输入字符串。

  2. 使用授权文本tokenizedDocument

函数文件= preprocessText (textData startToken stopToken)%添加开始和停止标记。textData = startToken + textData + stopToken;标记文本。文件= tokenizedDocument (textData,“CustomTokens”, (startToken stopToken]);结束

嵌入功能

嵌入函数使用给定的权重将索引序列映射到向量。

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

一个炎热的编码功能

otth.函数将数字索引数组转换为单热编码的向量。

函数哦= oneHot(idx, outputSize) miniBatchSize = numel(idx);哦= 0 (outputSize miniBatchSize);n = 1:miniBatchSize c = idx(n)哦(c, n) = 1;结束结束

另请参阅

||

相关的话题