Main Content

メモリ外のシーケンス データを使用したネットワークの学習

この例では、データストアの変換と組み合わせによってメモリ外のシーケンス データで深層学習ネットワークに学習させる方法を説明します。

変換されたデータストアは、基となるデータストアから読み取ったデータを変換または処理します。変換されたデータストアは、深層学習アプリケーションの学習データ セット、検証データ セット、テスト データ セット、および予測データ セットのソースとして使用できます。変換されたデータストアを使用して、メモリ外のデータを読み取るか、データのバッチを読み取る際に特定の前処理演算を実行します。予測子とラベルを含む個別のデータストアがある場合、これらのデータストアを組み合わせて深層学習ネットワークにデータを入力できます。

ネットワークの学習時に、入力データのパディング、切り捨て、または分割が行われ、同じ長さのシーケンスのミニバッチが作成されます。メモリ内のデータの場合、関数 trainingOptions に入力シーケンスのパディングと切り捨てを自動的に行うオプションが用意されていますが、メモリ外のデータの場合は、シーケンスのパディングと切り捨てを手動で行わなければなりません。

学習データの読み込み

[1] および [2] に記載のある Japanese Vowels データ セットを読み込みます。zip ファイル japaneseVowels.zip には可変長のシーケンスが含まれています。シーケンスは 2 つのフォルダー TrainTest に分割されています。これらのフォルダーには、学習シーケンスとテスト シーケンスがそれぞれ含まれています。これらの各フォルダーでは、シーケンスが 1 から 9 まで番号が付けられたサブフォルダーに分割されています。これらのサブフォルダーの名前はラベル名です。MAT ファイルは各シーケンスを表します。各シーケンスは行列で、行数が 12 (特徴ごとに 1 行) で、列数が可変 (タイム ステップごとに 1 列) です。行数はシーケンス次元で、列数はシーケンス長です。

シーケンス データを解凍します。

filename = "japaneseVowels.zip";
outputFolder = fullfile(tempdir,"japaneseVowels");
unzip(filename,outputFolder);

学習予測子用にファイル データストアを作成し、読み取り関数を関数 load に指定します。関数 load は MAT ファイルから構造体配列にデータを読み込みます。学習フォルダー内のサブフォルダーからファイルを読み取るには、'IncludeSubfolders' オプションを true に設定します。

folderTrain = fullfile(outputFolder,"Train");
fdsPredictorTrain = fileDatastore(folderTrain, ...
    'ReadFcn',@load, ...
    'IncludeSubfolders',true);

データストアをプレビューします。返される struct は、最初のファイルからの単一のシーケンスを含みます。

preview(fdsPredictorTrain)
ans = struct with fields:
    X: [12×20 double]

ラベル用にファイル データストアを作成し、読み取り関数が関数 readLabel (この例の最後に定義) になるように指定します。関数 readLabel は、サブフォルダー名からラベルを抽出します。

classNames = string(1:9);
fdsLabelTrain = fileDatastore(folderTrain, ...
    'ReadFcn',@(filename) readLabel(filename,classNames), ...
    'IncludeSubfolders',true);

データストアをプレビューします。出力は最初のファイルのラベルに対応しています。

preview(fdsLabelTrain)
ans = categorical
     1 

データストアの変換と統合

シーケンス データを予測子のデータストアから深層学習ネットワークに入力するには、シーケンスのミニバッチが同じ長さでなければなりません。シーケンスの長さが 20 になるようにパディングまたは切り捨てを行う関数 padSequence (データストアの最後に定義) を使用して、データストアを変換します。

sequenceLength = 20;
tdsTrain = transform(fdsPredictorTrain,@(data) padSequence(data,sequenceLength));

変換されたデータストアをプレビューします。出力は最初のファイルのパディングされたシーケンスに対応しています。

X = preview(tdsTrain)
X = 1×1 cell array
    {12×20 double}

両方のデータストアの予測子とラベルを深層学習ネットワークに入力するには、関数 combine を使用してこれらを組み合わせます。

cdsTrain = combine(tdsTrain,fdsLabelTrain);

データストアの組み合わせをプレビューします。データストアは 1 行 2 列の cell 配列を返します。最初の要素は予測子に対応しています。2 番目の要素はラベルに対応しています。

preview(cdsTrain)
ans=1×2 cell array
    {12×20 double}    {[1]}

LSTM ネットワーク アーキテクチャの定義

LSTM ネットワーク アーキテクチャを定義します。入力データの特徴の数を入力サイズとして指定します。100 個の隠れユニットを持つ LSTM 層を指定して、シーケンスの最後の要素を出力します。最後に、出力サイズがクラスの数に等しい全結合層を指定し、その後にソフトマックス層を配置します。

numFeatures = 12;
numClasses = numel(classNames);
numHiddenUnits = 100;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits,'OutputMode','last')
    fullyConnectedLayer(numClasses)
    softmaxLayer];

学習オプションを指定します。オプションの中から選択するには、経験的解析が必要です。実験を実行してさまざまな学習オプションの構成を調べるには、Experiment Managerアプリを使用できます。

  • Adam オプティマイザーを使用して学習させます。

  • 学習データには、チャネルとタイム ステップにそれぞれ対応する行と列を含むシーケンスがあるため、入力データ形式 "CTB" (チャネル、時間、バッチ) を指定します。

  • エポックの最大数を 75 に設定します。

  • ミニバッチ サイズとして 27 を使用します。

  • 勾配しきい値 2 で学習させます。

  • データストアはシャッフルをサポートしていないため、データをシャッフルしないでください。

  • CPU を使用して学習させます。ネットワークとデータが小さいため、CPU の方がより適しています。GPU が利用できる場合に GPU で学習を行うには、'ExecutionEnvironment' option'auto' (既定値) に設定します。

  • 詳細出力を無効にします。

  • 学習の進行状況をプロットで表示し、精度を監視します。

miniBatchSize = 27;

options = trainingOptions('adam', ...
    'InputDataFormats','CTB', ...
    'MaxEpochs',75, ...
    'MiniBatchSize',miniBatchSize, ...
    'GradientThreshold',2, ...
    'Shuffle','never',...
    'ExecutionEnvironment','cpu', ...
    'Verbose',0, ...
    'Plots','training-progress');

関数trainnetを使用してニューラル ネットワークに学習させます。分類には、クロスエントロピー損失を使用します。

net = trainnet(cdsTrain,layers,"crossentropy",options);

ネットワークのテスト

学習データの場合と同じ手順に従って、ホールドアウトされたテスト データを含む変換されたデータストアを作成します。

folderTest = fullfile(outputFolder,"Test");

fdsPredictorTest = fileDatastore(folderTest, ...
    'ReadFcn',@load, ...
    'IncludeSubfolders',true);
tdsTest = transform(fdsPredictorTest,@(data) padSequence(data,sequenceLength));

関数minibatchpredictを使用して予測を行います。既定では、関数 minibatchpredict は利用可能な GPU がある場合にそれを使用します。GPU を使用するには、Parallel Computing Toolbox™ ライセンスとサポートされている GPU デバイスが必要です。サポートされているデバイスについては、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。そうでない場合、関数は CPU を使用します。実行環境を指定するには、ExecutionEnvironment オプションを使用します。

データには、チャネルとタイム ステップにそれぞれ対応する行と列を含むシーケンスがあるため、入力データ形式 "CTB" (チャネル、時間、バッチ) を指定します。

scores = minibatchpredict(net,tdsTest,MiniBatchSize=miniBatchSize,InputDataFormats="CTB");
YPred = scores2label(scores,classNames);

テスト データに対する分類精度を計算します。テスト セットのラベルを取得するには、読み取り関数 readLabel を使用してファイル データストアを作成し、サブフォルダーを含むように指定します。'UniformRead' オプションを true に設定して、出力が垂直に連結されるように指定します。

fdsLabelTest = fileDatastore(folderTest, ...
    'ReadFcn',@(filename) readLabel(filename,classNames), ...
    'IncludeSubfolders',true, ...
    'UniformRead',true);
YTest = readall(fdsLabelTest);

accuracy = mean(YPred == YTest)
accuracy = 0.9568

関数

関数 readLabel は、classNames のカテゴリで指定されたファイル名からラベルを抽出します。

function label = readLabel(filename,classNames)

filepath = fileparts(filename);
[~,label] = fileparts(filepath);

label = categorical(string(label),classNames);

end

関数 padSequence は、シーケンスが指定された長さになるように data.X でシーケンスのパディングと切り捨てを行い、結果を 1 行 1 列の cell で返します。

function sequence = padSequence(data,sequenceLength)

sequence = data.X;
[C,S] = size(sequence);

if S < sequenceLength
    padding = zeros(C,sequenceLength-S);
    sequence = [sequence padding];
else
    sequence = sequence(:,1:sequenceLength);
end

sequence = {sequence};

end

参考

| | | | | |

関連するトピック