这个例子展示了如何训练深度学习LSTM网络来使用字符嵌入生成文本。
为了训练用于文本生成的深度学习网络,训练一个序列到序列的LSTM网络来预测字符序列中的下一个字符。为了训练网络预测下一个字符,指定响应为移动一个时间步长的输入序列。
要使用字符嵌入,请将每个训练观察值转换为整数序列,其中整数索引为字符词汇表。在网络中包括一个单词嵌入层,该层学习字符嵌入并将整数映射到向量。
读取HTML代码《傲慢与偏见古登堡计划》电子书,简·奥斯汀著并使用webread
和htmlTree
.
url =“https://www.gutenberg.org/files/1342/1342-h/1342-h.htm”;代码= webread (url);树= htmlTree(代码);
提取段落,找到p
元素。指定用class忽略段落元素“目录”
使用CSS选择器”:不(.toc)”
.
段落=findElement(树,“p: not (.toc)”);
从使用的段落中提取文本数据extractHTMLText
.并删除空字符串。
textData = extractHTMLText(段落);textData (textData = ="") = [];
删除小于20个字符的字符串。
idx = strlength(textData) < 20;textData (idx) = [];
在词云中可视化文本数据。
图wordcloud (textData);标题(《傲慢与偏见》)
将文本数据转换为预测器的字符索引序列和响应的分类序列。
Category函数将换行符和空白项视为未定义。若要为这些字符创建分类元素,请将它们替换为特殊字符“¶
”(pilcrow,“\x00B6”
)和“·”(中间点,“\ x00B7”
分别)。为防止歧义,必须选择文本中不出现的特殊字符。这些字符不会出现在训练数据中,因此可以用于此目的。
newlineCharacter =组成(“\x00B6”); whitespaceCharacter=compose(“\ x00B7”);textData =取代(textData,[换行符”“]、[newlineCharacter whitespaceCharacter]);
对文本数据进行循环,并创建一个字符索引序列,该序列表示每个观察到的字符,并为响应创建一个分类字符序列。要表示每个观察的结束,包括特殊字符“␃”(文本结束,“\ x2403”
).
endOfTextCharacter =组成(“\ x2403”);numDocuments=numel(textData);为i = 1:numDocuments字符= textData{i};X =双(字符);%创建带有文本结束字符的分类响应向量。charactersShifted=[cellstr(字符(2:end)'endOfTextCharacter];Y=分类(字符移位);XTrain{i}=X;YTrain{i}=Y;结束
在训练期间,默认情况下,软件将训练数据分成小批,并填充序列,使它们具有相同的长度。过多的填充会对网络性能产生负面影响。
为了防止训练过程添加太多的填充,可以按序列长度对训练数据进行排序,并选择一个迷你批大小,以便迷你批中的序列具有相似的长度。
获取每个观察的序列长度。
numObservations =元素个数(XTrain);为i=1:numObservations序列=XTrain{i};SequenceLength(i)=大小(序列,2);结束
按序列长度对数据排序。
[~, idx] = (sequenceLengths)进行排序;XTrain = XTrain (idx);YTrain = YTrain (idx);
定义LSTM体系结构。指定一个包含400个隐藏单元的序列到序列LSTM分类网络。设置输入大小为训练数据的特征维数。对于字符索引序列,特征维数为1。指定一个维度为200的单词嵌入层,并指定单词的数量(对应于字符)作为输入数据中的最高字符值。将完全连接层的输出大小设置为响应中的类别数量。为了防止过拟合,在LSTM层之后加入一个dropout层。
单词嵌入层学习字符的嵌入,并将每个字符映射到一个200维向量。
inputSize =大小(XTrain {1}, 1);numClasses =元素个数(类别([YTrain {:})));(textData numCharacters = max ({}):);layer = [sequenceInputLayer(inputSize) wordEmbeddingLayer(200,numCharacters) lstmLayer(400,“OutputMode”,“序列”) dropoutLayer (0.2);fullyConnectedLayer (numClasses) softmaxLayer classificationLayer];
指定培训选项。指定训练的小批量大小为32,初始学习率为0.01。为了防止渐变发生爆炸,设置渐变阈值为1。为了确保数据保持排序,设置“洗牌”
来“永远”
。若要监控培训进度,请设置“阴谋”
选择“训练进步”
.要抑制verbose输出,请设置“详细”
来假
.
选择= trainingOptions (“亚当”,...“MiniBatchSize”32岁的...“InitialLearnRate”, 0.01,...“GradientThreshold”,1,...“洗牌”,“永远”,...“阴谋”,“训练进步”,...“详细”,假);
培训网络。
net=列车网络(XTrain、YTrain、图层、选项);
根据训练数据中文本的第一个字符,从概率分布中抽样一个字符,生成文本的第一个字符。使用训练好的LSTM网络生成剩余字符,利用生成文本的当前序列预测下一个序列。一个接一个地生成字符,直到网络预测到“文本结束”字符。
根据第一个字符在训练数据中的分布情况对第一个字符进行采样。
initialCharacters=extractBefore(textData,2);firstCharacter=datasample(initialCharacters,1);generatedText=第一个字符;
将第一个字符转换为数字索引。
X =双(char (firstCharacter));
对于剩下的预测,根据网络的预测分数对下一个字符进行抽样。预测分数代表下一个字符的概率分布。从网络输出层的类名给出的字符词汇表中抽取字符样本。从网络的分类层获取词汇。
词汇=字符串(net.Layers(结束).ClassNames);
一个字一个字地使用预测predictAndUpdateState
.对于每个预测,输入前一个字符的索引。停止预测网络何时预测到文本字符的结束,或者生成的文本何时有500个字符长。对于大量数据、长序列或大型网络,GPU上的预测通常比CPU上的预测更快。否则,对CPU的预测通常计算得更快。对于单时间步长预测,使用CPU。要使用CPU进行预测,请设置“ExecutionEnvironment”
选择predictAndUpdateState
来“cpu”
.
最大长度= 500;而strlength (generatedText) <最大长度预测下一个角色得分。[净,characterScores] = predictAndUpdateState(净,X,“ExecutionEnvironment”,“cpu”);%对下一个字符进行采样。newCharacter = datasample(词汇,1,“重量”, characterScores);停止预测文本的结尾。如果newCharacter = = endOfTextCharacter打破结束将字符添加到生成的文本中。generatedText = generatedText + newCharacter;%获取字符的数字索引。X=双精度(字符(新字符));结束
通过将特殊字符替换为它们相应的空格和换行符,重新构建生成的文本。
generatedText=replace(generatedText,[newlineCharacter空白字符],[newline”“])
“我希望达西先生跟我一样,诚心诚意地选择了亲戚关系。我们本来是要去找卢卡斯家的。她们是象韦翰爵士那样嫁给他的,因为这两个人认识他,就有可能做现在的事,而且机会就像她们和我读到的那样;丽萃也没有,因为她在思念着香气;看了几次,我从来没有走到有利的情况下;强迫自己。她们可怜又活泼地相信,她是要请客的,因为我太过份了。”
若要生成多段文本,请使用重置状态
.
网= resetState(净);
wordEmbeddingLayer
|doc2sequence
|标记化文档
|lstmLayer
(深度学习工具箱)|trainNetwork
(深度学习工具箱)|培训选项
(深度学习工具箱)|sequenceInputLayer
(深度学习工具箱)|wordcloud
|extractHTMLText
|findElement
|htmlTree