В этом примере показано, как обучить сеть долговременной памяти глубокого обучения (LSTM) генерировать текст.
Чтобы обучить сеть глубокого обучения для генерации текста, обучайте сеть LSTM последовательности для прогнозирования следующего символа в последовательности символов. Чтобы обучить сеть предсказывать следующий символ, укажите входные последовательности, сдвинутые на один временной шаг в качестве ответов.
Для ввода последовательности символов в сеть LSTM преобразуйте каждое обучающее наблюдение в последовательность символов, представленную векторами , где D - количество уникальных символов в словаре. Для каждого вектора 1, если x соответствует символу с индексом i в данном словаре, = 0 j≠i.
Извлечение текстовых данных из текстового файла sonnets.txt.
filename = "sonnets.txt";
textData = fileread(filename);Сонеты разделяются двумя символами пробела и двумя символами новой строки. Удалить отступы с помощью replace и разбить текст на отдельные сонеты с помощью split. Удалите основной заголовок из первых трех элементов и заголовки сонета, которые появляются перед каждым сонетом.
textData = replace(textData," ",""); textData = split(textData,[newline newline]); textData = textData(5:2:end);
Просмотрите первые несколько наблюдений.
textData(1:10)
ans = 10×1 cell array
{'From fairest creatures we desire increase,↵That thereby beauty's rose might never die,↵But as the riper should by time decease,↵His tender heir might bear his memory:↵But thou, contracted to thine own bright eyes,↵Feed'st thy light's flame with self-substantial fuel,↵Making a famine where abundance lies,↵Thy self thy foe, to thy sweet self too cruel:↵Thou that art now the world's fresh ornament,↵And only herald to the gaudy spring,↵Within thine own bud buriest thy content,↵And tender churl mak'st waste in niggarding:↵Pity the world, or else this glutton be,↵To eat the world's due, by the grave and thee.' }
{'When forty winters shall besiege thy brow,↵And dig deep trenches in thy beauty's field,↵Thy youth's proud livery so gazed on now,↵Will be a tatter'd weed of small worth held:↵Then being asked, where all thy beauty lies,↵Where all the treasure of thy lusty days;↵To say, within thine own deep sunken eyes,↵Were an all-eating shame, and thriftless praise.↵How much more praise deserv'd thy beauty's use,↵If thou couldst answer 'This fair child of mine↵Shall sum my count, and make my old excuse,'↵Proving his beauty by succession thine!↵This were to be new made when thou art old,↵And see thy blood warm when thou feel'st it cold.' }
{'Look in thy glass and tell the face thou viewest↵Now is the time that face should form another;↵Whose fresh repair if now thou not renewest,↵Thou dost beguile the world, unbless some mother.↵For where is she so fair whose unear'd womb↵Disdains the tillage of thy husbandry?↵Or who is he so fond will be the tomb,↵Of his self-love to stop posterity?↵Thou art thy mother's glass and she in thee↵Calls back the lovely April of her prime;↵So thou through windows of thine age shalt see,↵Despite of wrinkles this thy golden time.↵But if thou live, remember'd not to be,↵Die single and thine image dies with thee.' }
{'Unthrifty loveliness, why dost thou spend↵Upon thy self thy beauty's legacy?↵Nature's bequest gives nothing, but doth lend,↵And being frank she lends to those are free:↵Then, beauteous niggard, why dost thou abuse↵The bounteous largess given thee to give?↵Profitless usurer, why dost thou use↵So great a sum of sums, yet canst not live?↵For having traffic with thy self alone,↵Thou of thy self thy sweet self dost deceive:↵Then how when nature calls thee to be gone,↵What acceptable audit canst thou leave?↵Thy unused beauty must be tombed with thee,↵Which, used, lives th' executor to be.' }
{'Those hours, that with gentle work did frame↵The lovely gaze where every eye doth dwell,↵Will play the tyrants to the very same↵And that unfair which fairly doth excel;↵For never-resting time leads summer on↵To hideous winter, and confounds him there;↵Sap checked with frost, and lusty leaves quite gone,↵Beauty o'er-snowed and bareness every where:↵Then were not summer's distillation left,↵A liquid prisoner pent in walls of glass,↵Beauty's effect with beauty were bereft,↵Nor it, nor no remembrance what it was:↵But flowers distill'd, though they with winter meet,↵Leese but their show; their substance still lives sweet.' }
{'Then let not winter's ragged hand deface,↵In thee thy summer, ere thou be distill'd:↵Make sweet some vial; treasure thou some place↵With beauty's treasure ere it be self-kill'd.↵That use is not forbidden usury,↵Which happies those that pay the willing loan;↵That's for thy self to breed another thee,↵Or ten times happier, be it ten for one;↵Ten times thy self were happier than thou art,↵If ten of thine ten times refigur'd thee:↵Then what could death do if thou shouldst depart,↵Leaving thee living in posterity?↵Be not self-will'd, for thou art much too fair↵To be death's conquest and make worms thine heir.' }
{'Lo! in the orient when the gracious light↵Lifts up his burning head, each under eye↵Doth homage to his new-appearing sight,↵Serving with looks his sacred majesty;↵And having climb'd the steep-up heavenly hill,↵Resembling strong youth in his middle age,↵Yet mortal looks adore his beauty still,↵Attending on his golden pilgrimage:↵But when from highmost pitch, with weary car,↵Like feeble age, he reeleth from the day,↵The eyes, 'fore duteous, now converted are↵From his low tract, and look another way:↵So thou, thyself outgoing in thy noon:↵Unlook'd, on diest unless thou get a son.' }
{'Music to hear, why hear'st thou music sadly?↵Sweets with sweets war not, joy delights in joy:↵Why lov'st thou that which thou receiv'st not gladly,↵Or else receiv'st with pleasure thine annoy?↵If the true concord of well-tuned sounds,↵By unions married, do offend thine ear,↵They do but sweetly chide thee, who confounds↵In singleness the parts that thou shouldst bear.↵Mark how one string, sweet husband to another,↵Strikes each in each by mutual ordering;↵Resembling sire and child and happy mother,↵Who, all in one, one pleasing note do sing:↵Whose speechless song being many, seeming one,↵Sings this to thee: 'Thou single wilt prove none.''}
{'Is it for fear to wet a widow's eye,↵That thou consum'st thy self in single life?↵Ah! if thou issueless shalt hap to die,↵The world will wail thee like a makeless wife;↵The world will be thy widow and still weep↵That thou no form of thee hast left behind,↵When every private widow well may keep↵By children's eyes, her husband's shape in mind:↵Look! what an unthrift in the world doth spend↵Shifts but his place, for still the world enjoys it;↵But beauty's waste hath in the world an end,↵And kept unused the user so destroys it.↵No love toward others in that bosom sits↵That on himself such murd'rous shame commits.' }
{'For shame! deny that thou bear'st love to any,↵Who for thy self art so unprovident.↵Grant, if thou wilt, thou art belov'd of many,↵But that thou none lov'st is most evident:↵For thou art so possess'd with murderous hate,↵That 'gainst thy self thou stick'st not to conspire,↵Seeking that beauteous roof to ruinate↵Which to repair should be thy chief desire.↵O! change thy thought, that I may change my mind:↵Shall hate be fairer lodg'd than gentle love?↵Be, as thy presence is, gracious and kind,↵Or to thyself at least kind-hearted prove:↵Make thee another self for love of me,↵That beauty still may live in thine or thee.' }
Преобразуйте текстовые данные в последовательности векторов для предикторов и категориальные последовательности для ответов.
Создайте специальные символы для обозначения «начала текста», «пробела», «конца текста» и «новой строки». Использовать специальные символы "\x0002" (начало текста), "\x00B7" («·», средняя точка), "\x2403" («␃», конец текста), и "\x00B6" ("¶, "pilcrow) соответственно. Для предотвращения неоднозначности необходимо выбрать специальные символы, которые не отображаются в тексте. Поскольку эти символы не отображаются в данных обучения, их можно использовать для этой цели.
startOfTextCharacter = compose("\x0002"); whitespaceCharacter = compose("\x00B7"); endOfTextCharacter = compose("\x2403"); newlineCharacter = compose("\x00B6");
Для каждого наблюдения вставьте начало текстового символа в начале и замените пробел и новые строки соответствующими символами.
textData = startOfTextCharacter + textData;
textData = replace(textData,[" " newline],[whitespaceCharacter newlineCharacter]);Создайте словарный запас уникальных символов в тексте.
uniqueCharacters = unique([textData{:}]);
numUniqueCharacters = numel(uniqueCharacters);Закольцовывать текстовые данные и создавать последовательность векторов, представляющих символы каждого наблюдения и категориальную последовательность символов для ответов. Чтобы обозначить конец каждого наблюдения, укажите конец текстового символа.
numDocuments = numel(textData); XTrain = cell(1,numDocuments); YTrain = cell(1,numDocuments); for i = 1:numel(textData) characters = textData{i}; sequenceLength = numel(characters); % Get indices of characters. [~,idx] = ismember(characters,uniqueCharacters); % Convert characters to vectors. X = zeros(numUniqueCharacters,sequenceLength); for j = 1:sequenceLength X(idx(j),j) = 1; end % Create vector of categorical responses with end of text character. charactersShifted = [cellstr(characters(2:end)')' endOfTextCharacter]; Y = categorical(charactersShifted); XTrain{i} = X; YTrain{i} = Y; end
Просмотрите первое наблюдение и размер соответствующей последовательности. Последовательность является матрицей D-by-S, где D - количество признаков (количество уникальных символов), а S - длина последовательности (количество символов в тексте).
textData{1}ans = 'From·fairest·creatures·we·desire·increase,¶That·thereby·beauty's·rose·might·never·die,¶But·as·the·riper·should·by·time·decease,¶His·tender·heir·might·bear·his·memory:¶But·thou,·contracted·to·thine·own·bright·eyes,¶Feed'st·thy·light's·flame·with·self-substantial·fuel,¶Making·a·famine·where·abundance·lies,¶Thy·self·thy·foe,·to·thy·sweet·self·too·cruel:¶Thou·that·art·now·the·world's·fresh·ornament,¶And·only·herald·to·the·gaudy·spring,¶Within·thine·own·bud·buriest·thy·content,¶And·tender·churl·mak'st·waste·in·niggarding:¶Pity·the·world,·or·else·this·glutton·be,¶To·eat·the·world's·due,·by·the·grave·and·thee.'
size(XTrain{1})ans = 1×2
62 611
Просмотрите соответствующую последовательность ответов. Последовательность является 1-by-S категориальным вектором ответов.
YTrain{1}ans = 1×611 categorical array
F r o m · f a i r e s t · c r e a t u r e s · w e · d e s i r e · i n c r e a s e , ¶ T h a t · t h e r e b y · b e a u t y ' s · r o s e · m i g h t · n e v e r · d i e , ¶ B u t · a s · t h e · r i p e r · s h o u l d · b y · t i m e · d e c e a s e , ¶ H i s · t e n d e r · h e i r · m i g h t · b e a r · h i s · m e m o r y : ¶ B u t · t h o u , · c o n t r a c t e d · t o · t h i n e · o w n · b r i g h t · e y e s , ¶ F e e d ' s t · t h y · l i g h t ' s · f l a m e · w i t h · s e l f - s u b s t a n t i a l · f u e l , ¶ M a k i n g · a · f a m i n e · w h e r e · a b u n d a n c e · l i e s , ¶ T h y · s e l f · t h y · f o e , · t o · t h y · s w e e t · s e l f · t o o · c r u e l : ¶ T h o u · t h a t · a r t · n o w · t h e · w o r l d ' s · f r e s h · o r n a m e n t , ¶ A n d · o n l y · h e r a l d · t o · t h e · g a u d y · s p r i n g , ¶ W i t h i n · t h i n e · o w n · b u d · b u r i e s t · t h y · c o n t e n t , ¶ A n d · t e n d e r · c h u r l · m a k ' s t · w a s t e · i n · n i g g a r d i n g : ¶ P i t y · t h e · w o r l d , · o r · e l s e · t h i s · g l u t t o n · b e , ¶ T o · e a t · t h e · w o r l d ' s · d u e , · b y · t h e · g r a v e · a n d · t h e e . ␃
Определите архитектуру LSTM. Укажите классификационную сеть последовательности к последовательности LSTM с 200 скрытыми единицами. Задайте размер элемента обучающих данных (количество уникальных символов) в качестве размера ввода и количество категорий в ответах в качестве размера вывода полностью подключенного слоя.
inputSize = size(XTrain{1},1);
numHiddenUnits = 200;
numClasses = numel(categories([YTrain{:}]));
layers = [
sequenceInputLayer(inputSize)
lstmLayer(numHiddenUnits,'OutputMode','sequence')
fullyConnectedLayer(numClasses)
softmaxLayer
classificationLayer];Укажите параметры обучения с помощью trainingOptions функция. Укажите количество периодов обучения как 500, а начальный показатель обучения как 0,01. Для предотвращения разузлования градиентов установите порог градиента равным 2. Укажите, чтобы перетасовать данные каждую эпоху, установив 'Shuffle' опция для 'every-epoch'. Для контроля за ходом обучения установите 'Plots' опция для 'training-progress'. Для подавления подробных выходных данных установите 'Verbose' кому false.
Опция размера мини-пакета определяет количество наблюдений, обрабатываемых в одной итерации. Укажите размер мини-пакета, равномерно разделяющий данные, чтобы убедиться, что функция использует все наблюдения для обучения. В противном случае функция игнорирует наблюдения, которые не завершают мини-пакет. Установите размер мини-партии 77.
options = trainingOptions('adam', ... 'MaxEpochs',500, ... 'InitialLearnRate',0.01, ... 'GradientThreshold',2, ... 'MiniBatchSize',77,... 'Shuffle','every-epoch', ... 'Plots','training-progress', ... 'Verbose',false);
Обучение сети.
net = trainNetwork(XTrain,YTrain,layers,options);

Используйте generateText функция, перечисленная в конце примера, для создания текста с использованием обученной сети.
generateText функция генерирует текст по символам, начиная с начала текста и восстанавливает текст с помощью специальных символов. Функция выполняет выборку каждого символа, используя выходные оценки прогнозирования. Функция прекращает прогнозирование, когда сеть прогнозирует символ конца текста или когда генерируемый текст имеет длину 500 символов.
Создание текста с использованием обученной сети.
generatedText = generateText(net,uniqueCharacters,startOfTextCharacter,newlineCharacter,whitespaceCharacter,endOfTextCharacter)
generatedText =
"Look, that your lepperites of such soous toor men,
Where than proud on your sweetest but lever ill lie.
One of Death a deal doth teal hearts come,
And that which gives did mistress one learn
Made mens of tongue that hands hear,
And all they with me, do I fortune to brief;
And every peinted could with this right ampontion sorend
By genilir'd lime thau hours, and wonder sposing,
And night by day you waster'd then new;
For ailling thuse borrowest vein fulse were of here spent,
Since my heart morey "
generateText функция генерирует текст по символам, начиная с начала текста и восстанавливает текст с помощью специальных символов. Функция выполняет выборку каждого символа, используя выходные оценки прогнозирования. Функция прекращает прогнозирование, когда сеть прогнозирует символ конца текста или когда генерируемый текст имеет длину 500 символов.
function generatedText = generateText(net,uniqueCharacters,startOfTextCharacter,newlineCharacter,whitespaceCharacter,endOfTextCharacter)Создайте вектор начала текстового символа, найдя его индекс.
numUniqueCharacters = numel(uniqueCharacters); X = zeros(numUniqueCharacters,1); idx = strfind(uniqueCharacters,startOfTextCharacter); X(idx) = 1;
Создание текста по символам с использованием обученной сети LSTM с использованием predictAndUpdateState и datasample. Прекратите прогнозирование, когда сеть прогнозирует символ конца текста или когда созданный текст имеет длину 500 символов. datasample для этой функции требуются Toolbox™ статистики и машинного обучения.
Для больших коллекций данных, длинных последовательностей или больших сетей прогнозы на GPU обычно вычисляются быстрее, чем прогнозы на CPU. В противном случае предсказания на CPU обычно вычисляются быстрее. Для прогнозирования одного шага времени используйте CPU. Чтобы использовать CPU для прогнозирования, установите 'ExecutionEnvironment' вариант predictAndUpdateState кому 'cpu'.
generatedText = ""; vocabulary = string(net.Layers(end).Classes); maxLength = 500; while strlength(generatedText) < maxLength % Predict the next character scores. [net,characterScores] = predictAndUpdateState(net,X,'ExecutionEnvironment','cpu'); % Sample the next character. newCharacter = datasample(vocabulary,1,'Weights',characterScores); % Stop predicting at the end of text. if newCharacter == endOfTextCharacter break end % Add the character to the generated text. generatedText = generatedText + newCharacter; % Create a new vector for the next input. X(:) = 0; idx = strfind(uniqueCharacters,newCharacter); X(idx) = 1; end
Восстановите созданный текст путем замены специальных символов соответствующими пробелами и символами новой строки.
generatedText = replace(generatedText,[newlineCharacter whitespaceCharacter],[newline " "]); end
lstmLayer | sequenceInputLayer | trainingOptions | trainNetwork