Main Content

テキスト符号化器モデル関数の定義

この例では、テキスト符号化器モデル関数の定義方法を示します。

深層学習のコンテキストでは、符号化器は、入力を何らかの潜在空間にマッピングする深層学習ネットワークの一部です。これらのベクトルは、さまざまなタスクに使用できます。次に例を示します。

  • ソフトマックス演算を符号化されたデータに適用し、クロス エントロピー損失を使用する分類。

  • 符号化されたベクトルをコンテキスト ベクトルとして使用する sequence-to-sequence 変換。

データの読み込み

ファイル sonnets.txt には、シェイクスピアのソネット全集が 1 つのテキスト ファイルとして格納されています。

ファイル "sonnets.txt" からシェイクスピアのソネットのデータを読み取ります。

filename = "sonnets.txt";
textData = fileread(filename);

ソネットは、2 つの空白文字でインデントされています。replace を使用してインデントを削除し、関数 split を使用してテキストを個別の行に分割します。最初の 9 つの要素と短いソネット タイトルからヘッダーを削除します。

textData = replace(textData,"  ","");
textData = split(textData,newline);
textData(1:9) = [];
textData(strlength(textData)<5) = [];

データの準備

テキスト データをトークン化および前処理する関数を作成します。例の最後にリストされている関数 preprocessText は以下のステップを実行します。

  1. 各入力ストリングの前後に、指定された開始トークンと停止トークンをそれぞれ付加する。

  2. tokenizedDocument を使用してテキストをトークン化する。

テキスト データを前処理し、開始トークン "<start>" と停止トークン "<stop>" をそれぞれ指定します。

startToken = "<start>";
stopToken = "<stop>";
documents = preprocessText(textData,startToken,stopToken);

トークン化されたドキュメントから単語符号化オブジェクトを作成します。

enc = wordEncoding(documents);

深層学習モデルの学習を行う際には、入力データは固定長のシーケンスを含む数値配列でなければなりません。ドキュメントの長さは異なるため、短いシーケンスはパディング値でパディングしなければなりません。

パディング トークンを含み、そのトークンのインデックスも決定するように、単語符号化を再作成します。

paddingToken = "<pad>";
newVocabulary = [enc.Vocabulary paddingToken];
enc = wordEncoding(newVocabulary);
paddingIdx = word2ind(enc,paddingToken)
paddingIdx = 3595

モデル パラメーターの初期化

符号化器の目的は、単語インデックスのシーケンスを何らかの潜在空間においてベクトルにマッピングすることです。

次のモデルのパラメーターを初期化します。

このモデルでは、次の 3 つの操作を行います。

  • 埋め込みでは、範囲 1 ~ vocabularySize で単語インデックスを次元 embeddingDimension のベクトルにマッピングします。ここで、vocabularySize は符号化ボキャブラリの単語数、embeddingDimension は埋め込みによって学習されたコンポーネントの数です。

  • LSTM 演算では、単語ベクトルのシーケンスを入力として受け取り、1 x numHiddenUnits のベクトルを出力します。ここで、numHiddenUnits は LSTM 演算での隠れユニットの数です。

  • 全結合演算では、入力と、バイアスを加算した重み行列を乗算し、サイズ latentDimension のベクトルを出力します。ここで、latentDimension は潜在空間の次元です。

パラメーターの次元を指定します。

embeddingDimension = 100;
numHiddenUnits = 150;
latentDimension = 50;
vocabularySize = enc.NumWords;

パラメーターの struct を作成します。

parameters = struct;

関数 initializeGaussian を使用し、ガウスで埋め込みの重みを初期化します。この関数は、この例にサポート ファイルとして添付されています。平均値を 0、標準偏差を 0.01 に指定します。詳細については、ガウスによる初期化を参照してください。

mu = 0;
sigma = 0.01;
parameters.emb.Weights = initializeGaussian([embeddingDimension vocabularySize],mu,sigma);

符号化器の LSTM 演算に関する学習可能なパラメーターを初期化します。

  • 関数 initializeGlorot を使用し、Glorot 初期化子で入力の重みを初期化します。この関数は、この例にサポート ファイルとして添付されています。詳細については、Glorot の初期化を参照してください。

  • 関数 initializeOrthogonal を使用し、直交初期化子で再帰重みを初期化します。この関数は、この例にサポート ファイルとして添付されています。詳細については、直交初期化を参照してください。

  • 関数 initializeUnitForgetGate を使用し、ユニット忘却ゲート初期化子でバイアスを初期化します。この関数は、この例にサポート ファイルとして添付されています。詳細については、ユニット忘却ゲートによる初期化を参照してください。

学習可能なパラメーターのサイズは、入力のサイズによって異なります。LSTM 演算への入力は埋め込み演算からの単語ベクトルのシーケンスであるため、入力チャネルの数は embeddingDimension になります。

  • 入力重み行列のサイズは 4*numHiddenUnits x inputSize です。ここで、inputSize は入力データの次元です。

  • 再帰重み行列のサイズは 4*numHiddenUnits x numHiddenUnits です。

  • バイアス ベクトルのサイズは 4*numHiddenUnits x 1 です。

sz = [4*numHiddenUnits embeddingDimension];
numOut = 4*numHiddenUnits;
numIn = embeddingDimension;

parameters.lstmEncoder.InputWeights = initializeGlorot(sz,numOut,numIn);
parameters.lstmEncoder.RecurrentWeights = initializeOrthogonal([4*numHiddenUnits numHiddenUnits]);
parameters.lstmEncoder.Bias = initializeUnitForgetGate(numHiddenUnits);

符号化器の全結合演算に関する学習可能なパラメーターを初期化します。

  • Glorot 初期化子を使用して重みを初期化します。

  • 関数 initializeZeros を使用し、ゼロでバイアスを初期化します。この関数は、この例にサポート ファイルとして添付されています。詳細については、ゼロでの初期化を参照してください。

学習可能なパラメーターのサイズは、入力のサイズによって異なります。全結合演算への入力は LSTM 演算の出力であるため、入力チャネルの数は numHiddenUnits になります。全結合演算でサイズ latentDimension のベクトルを出力するには、出力サイズを latentDimension に指定します。

  • 重み行列のサイズは outputSize x inputSize です。ここで、outputSizeinputSize は、出力と入力の次元にそれぞれ対応します。

  • バイアス ベクトルのサイズは outputSize x 1 です。

sz = [latentDimension numHiddenUnits];
numOut = latentDimension;
numIn = numHiddenUnits;

parameters.fcEncoder.Weights = initializeGlorot(sz,numOut,numIn);
parameters.fcEncoder.Bias = initializeZeros([latentDimension 1]);

モデル符号化器関数の定義

この例の符号化器モデル関数の節にリストされている関数 modelEncoder を作成し、符号化器モデルの出力を計算します。関数 modelEncoder は、モデル パラメーターおよびシーケンス長を単語インデックスの入力シーケンスとして受け取り、対応する潜在特徴ベクトルを返します。

データのミニバッチの準備

カスタム学習ループを使用してモデルの学習を行うには、データのミニバッチを反復処理し、それを符号化器モデル関数およびモデル勾配関数に必要な形式に変換しなければなりません。この例のこの節では、カスタム学習ループ内でデータのミニバッチを準備するのに必要な手順について説明します。

データのミニバッチ例を準備します。documents から、32 件のドキュメントで構成されるミニバッチを選択します。これは、カスタム学習ループの反復処理で使用されるデータのミニバッチを表します。

miniBatchSize = 32;
idx = 1:miniBatchSize;
documentsBatch = documents(idx);

関数 doc2sequence を使用してドキュメントをシーケンスに変換します。また、パディング トークンに対応する単語インデックスを使用し、そのシーケンスの右側をパディングするように指定します。

X = doc2sequence(enc,documentsBatch, ...
    PaddingDirection="right", ...
    PaddingValue=paddingIdx);

関数 doc2sequence の出力は cell 配列です。ここで、その各要素は単語インデックスの行ベクトルです。符号化器モデル関数は数値入力を必要とするため、関数 cat を使用してデータの行を連結し、最初の次元と連結するように指定します。出力のサイズは miniBatchSize x sequenceLength です。ここで、sequenceLength はミニバッチ内の最長シーケンスの長さです。

X = cat(1,X{:});
size(X)
ans = 1×2

    32    14

形式 "BTC" (batch、time、channel) をもつ dlarray にデータを変換します。ソフトウェアは、形式 "CTB" に従って出力を自動的に再配置します。これにより、出力のサイズは 1×miniBatchSize×sequenceLength になります。

X = dlarray(X,'BTC');
size(X)
ans = 1×3

     1    32    14

マスクについては、ドキュメントのミニバッチを入力としてもつ関数 doclength を使用し、パディングを削除した入力データのシーケンス長を計算します。

sequenceLengths = doclength(documentsBatch);

このコードの抜粋は、カスタム学習ループにおけるミニバッチの準備の例を示しています。

iteration = 0;

% Loop over epochs.
for epoch = 1:numEpochs

    % Loop over mini-batches.
    for i = 1:numIterationsPerEpoch

        iteration = iteration + 1;

        % Read mini-batch.
        idx = (i-1)*miniBatchSize+1:i*miniBatchSize;
        documentsBatch = documents(idx);

        % Convert to sequences.
        X = doc2sequence(enc,documentsBatch, ...
            PaddingDirection="right", ...
            PaddingValue=paddingIdx);
        X = cat(1,X{:});

        % Convert to dlarray.
        X = dlarray(X,"BTC");

        % Calculate sequence lengths.
        sequenceLengths = doclength(documentsBatch);

        % Evaluate model gradients.
        % ...

        % Update learnable parameters.
        % ...
    end
end

モデル損失関数でのモデル関数の使用

カスタム学習ループを使用して深層学習モデルの学習を行う場合、学習可能なパラメーターについての損失および損失の勾配を計算しなければなりません。この計算は、モデル関数のフォワード パスの出力によって異なります。

符号化器のフォワード パスを実行するには、関数 modelEncoder を、パラメーター、データ、シーケンス長を入力として直接使用します。出力は latentDimensionminiBatchSize 列の行列です。

Z = modelEncoder(parameters,X,sequenceLengths);
size(Z)
ans = 1×2

    50    32

このコードの抜粋は、モデル勾配関数内でモデル符号化器関数を使用する例を示しています。

function [loss,gradients] = modelLoss(parameters,X,sequenceLengths)
    
    Z = modelEncoder(parameters,X,sequenceLengths);

    % Calculate loss.
    % ...

    % Calculate gradients.
    % ...

end

このコードの抜粋は、カスタム学習ループにおけるモデル勾配の評価の例を示しています。

iteration = 0;

% Loop over epochs.
for epoch = 1:numEpochs

    % Loop over mini-batches.
    for i = 1:numIterationsPerEpoch
        iteration = iteration + 1;

        % Prepare mini-batch.
        % ...

        % Evaluate model gradients.
        [loss,gradients] = dlfeval(@modelLoss, parameters, X, sequenceLengths);

        % Update learnable parameters.
        [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ...
            trailingAvg,trailingAvgSq,iteration);
    end
end

符号化器モデル関数

関数 modelEncoder は、モデル パラメーター、単語インデックスのシーケンス、シーケンス長を入力として受け取り、対応する潜在特徴ベクトルを返します。

入力データには長さの異なるパディング済みシーケンスが含まれるため、パディングによって損失計算に悪影響の及ぶ可能性があります。LSTM 演算について、シーケンスの最後のタイム ステップの出力 (多数のパディング値を処理した後の LSTM 状態に相当する可能性が高い) を返す代わりに、sequenceLengths 入力によって与えられた実際の最後のタイム ステップを決定します。

function Z = modelEncoder(parameters,X,sequenceLengths)

% Embedding.
weights = parameters.emb.Weights;
Z = embed(X,weights);

% LSTM.
inputWeights = parameters.lstmEncoder.InputWeights;
recurrentWeights = parameters.lstmEncoder.RecurrentWeights;
bias = parameters.lstmEncoder.Bias;

numHiddenUnits = size(recurrentWeights,2);
hiddenState = zeros(numHiddenUnits,1,"like",X);
cellState = zeros(numHiddenUnits,1,"like",X);

Z1 = lstm(Z,hiddenState,cellState,inputWeights,recurrentWeights,bias);

% Output mode "last" with masking.
miniBatchSize = size(Z1,2);
Z = zeros(numHiddenUnits,miniBatchSize,"like",Z1);
Z = dlarray(Z,"CB");

for n = 1:miniBatchSize
    t = sequenceLengths(n);
    Z(:,n) = Z1(:,n,t);
end

% Fully connect.
weights = parameters.fcEncoder.Weights;
bias = parameters.fcEncoder.Bias;
Z = fullyconnect(Z,weights,bias);

end

前処理関数

関数 preprocessText は以下のステップを実行します。

  1. 各入力ストリングの前後に、指定された開始トークンと停止トークンをそれぞれ付加する。

  2. tokenizedDocument を使用してテキストをトークン化する。

function documents = preprocessText(textData,startToken,stopToken)

% Add start and stop tokens.
textData = startToken + textData + stopToken;

% Tokenize the text.
documents = tokenizedDocument(textData,'CustomTokens',[startToken stopToken]);

end

参考

| |

関連するトピック