本示例说明如何使用长短期记忆LSTM网络对序列数据的每个时间步进行分类。
要训练深度神经网络对序列数据的每个时间步进行分类,可以使用序列到序列LSTM网络。序列到序列LSTM网络可以使得对序列数据的每个单独时间步进行不同的预测。
本示例使用了从佩戴在身上的智能手机获得的传感器数据,该示例训练了一个LSTM网络,在给定时间序列数据的情况下识别佩戴者的活动,该时间序列数据表示在三个不同方向上的加速度计的读数。训练数据包含其个人的时间序列数据。每个序列具有三个特征,并且长度不同,数据集包含6个训练观察结果和一个测试观察结果。

加载序列数据

加载人类活动识别数据。数据包含七个时间序列的传感器数据,这些数据是从穿戴在身上的智能手机获得的。每个序列有三个特征,并且特征不同。这三个功能分别对应三个方向上的加速度计数器。

  1. load HumanActivityTrain
  2. XTrain

XTrain=6×1 cell array {3×64480 double} {3×53696 double} {3×56416 double} {3×50688 double} {3×51888 double} {3×54256 double}

画一幅图来可视化一下训练过程,画出第一个训练序列的第一个特征,然后标注出相关的活动。

  1. X = XTrain{1}(1,:);
  2. classes = categories(YTrain{1});
  3. figure
  4. for j = 1:numel(classes)
  5. label = classes(j);
  6. idx = find(YTrain{1} == label);
  7. hold on
  8. plot(idx,X(idx))
  9. end
  10. hold off
  11. xlabel("Time Step")
  12. ylabel("Acceleration")
  13. title("Training Sequence 1, Feature 1")
  14. legend(classes,'Location','northwest')

♠ 使用深度学习进行序列到序列分类 - 图1
图1. 训练过程图

定义LSTM网络架构

定义一下LSTM网络架构,确定LSTM的输入的大小为3(因为这是输入数据的特征个数),确定LSTM的隐藏层个数为200,输出整个序列。最后,通过设定全连接层的个数为5能够分辨出5个类来,然后紧跟着一个softmax层和一个分类层。(大小为3的输入层->大小为200的隐藏层->大小为5的全阶层->softmax层->分类层)。

  1. numFeatures = 3;
  2. numHiddenUnits = 200;
  3. numClasses = 5;
  4. layers = [...
  5. sequenceInputLayer(numFeatures)
  6. lstmLayer(numHiddenUnits, 'OutputMode', 'sequence')
  7. fullyConnectedLayer(numClasses)
  8. softmaxLayer
  9. classificationLayer
  10. ];

确定一下网络层的参数,设定解决方法为 ‘adam’,训练60个epochs。为了防止梯度爆炸,设定梯度阈值为2

  1. options = trainingOptions('adam', ...
  2. 'MaxEpochs',60, ...
  3. 'GradientThreshold',2, ...
  4. 'Verbose',0, ...
  5. 'Plots','training-progress');

使用 trainNetwork函数来训练LSTM网络,每个小批量都包含整个训练集,所以每个epoch都会更新一次,因为序列很长,所以在处理每个批量和更新画图的时候都要花很长时间。

  1. net = trainNetwork(XTrain, YTrain, layers, options);

♠ 使用深度学习进行序列到序列分类 - 图2
图2. 训练过程

测试LSTM网络

加载测试集然后对每个时间步长的活动进行分类。
加载人类活动的测试集,其中XTest包含了3维的序列,YTest包含了序列所对应的步长所属的标签。

  1. load HumanActivityTest
  2. figure
  3. plot(XTest{1}')
  4. xlabel("Time Step")
  5. legend("Feature " + (1:numFeatures))
  6. title("Test Data")

♠ 使用深度学习进行序列到序列分类 - 图3
图3. 验证集
使用classify函数对测试集数据进行分类

  1. YPred = classify(net, XTest{1});

另外,也可以使用函数classifyAndUpdateState然后来一次预测一个时间步长。通常,与一次一次的与预测相比,对全序列预测会更快。
计算预测的准确性

  1. acc = sum(YPred == YTest{1})./numel(YTest{1})

acc = 0.9998

画图来看一下预测数据和真实数据的差别

  1. figure
  2. plot(YPred,'.-')
  3. hold on
  4. plot(YTest{1})
  5. hold off
  6. xlabel("Time Step")
  7. ylabel("Activity")
  8. title("Predicted Activities")
  9. legend(["Predicted" "Test Data"])

♠ 使用深度学习进行序列到序列分类 - 图4
图5. 预测数据和真实数据的差别