锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 人工智能 / C#语言LSTM长短期记忆网络实战
政企荣誉
  • 亚马逊语音识别合作亚马逊语音识别合作
    意向种子企业,小语种方向
  • 资本力量1+6融资活动政府推荐参加资本力量
    1+6融资活动
  • 输入法全平台上市公司众为兴
    合作伙伴
  • 中航信飞机票务平台河南职教中心
    成人学历和能力培训合作联盟成员
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

C#语言LSTM长短期记忆网络实战

神经网络技术在机器学习中成为主流,也逐渐发展出来高级版本,LSTM长短期记忆网络就是一种高级版本。神经网络中网络细胞运算处理运算因子,LSTM加入了因子类型,扩展了细胞运算架构,能够有效地提升学习率,识别出好结果。
锐英源软件在kaldi中应用了LSTM,执行了LSTM训练用的一些脚本,对LSTM结合Python经验丰富,本文结合C#语言应用LSTM技术,描述了一个算法实现细节,信息来源于国外网站,锐英源软件进行了翻译和注解,部分信息著作权归属国外专家。
-------------------------翻译开始---------------------
在这篇文章中,我将展示如何在 C# 中实现 CNTK 106 教程。本教程讲座是用 Python 编写的,没有 C# 中的相关示例。出于这个原因,我决定将这个非常好的教程翻译成 C#。该教程可以在CNTK 106: Part A – Time series prediction with LSTM (Basics)中找到,并使用正弦波函数来预测时间序列数据。对于这个问题,使用了 Long Short Term Memory,LSTM,Recurrent Neural Network。

目标

本教程的目标是预测连续函数(正弦波)的模拟数据。根据函数的先前值,其中是在时间观察到的幅度信号,对 的值的预测将预测相应的未来时间点。
本教程的精彩之处在于使用了非常适合此类问题的 LSTM 循环神经网络。你可能知道,LSTM 是一种特殊的循环神经网络,它能够在训练过程中从经验中学习。更多关于这个奇妙版本的循环神经网络的信息可以在这里找到。
博文分为几个小节:

  1. 模拟数据部分
  2. LSTM 网络
  3. 模型训练和评估

由于模拟数据集很大,原始教程有两种运行模式,由变量isFast控制。在快速模式的情况下,变量设置为True,本教程将使用此模式。稍后,读者可能会False为了看到更好的训练模型而将值更改为,但训练时间会更长。此博客文章的演示向用户公开了批量大小和迭代次数的变量,因此用户可以根据需要定义这些数字。

数据生成

为了生成模拟的正弦波数据,我们将实现几个辅助方法。让 和 分别是正弦波的过去值和未来(期望的预测值)的有序集合。两种方法的实现:

生成波数据集()

采用generateWaveDataset周期函数、一组独立值(对应于这种情况下的时间)并通过提供时间步长和时移来生成波函数。该方法与generate_data()原始教程中的 python 方法有关。


static Dictionary<string, (float[][] train, float[][] valid, float[][] test)>
loadWaveDataset(Func<double, double> fun, float[] x0, int timeSteps, int timeShift)
{
////fill data
float[] xsin = new float[x0.Length];//all data
for (int l = 0; l < x0.Length; l++)
xsin[l] = (float)fun(x0[l]);

 

    //split data on training and testing part
var a = new float[xsin.Length - timeShift];
var b = new float[xsin.Length - timeShift];

    for (int l = 0; l < xsin.Length; l++)
{
//
if (l < xsin.Length - timeShift) a[l] = xsin[l]; // if (l >= timeShift)
b[l - timeShift] = xsin[l];
}

    //make arrays of data
var a1 = new List<float[]>();
var b1 = new List<float[]>();
for (int i = 0; i < a.Length - timeSteps + 1; i++)
{
//features
var row = new float[timeSteps];
for (int j = 0; j < timeSteps; j++)
row[j] = a[i + j];
//create features row
a1.Add(row);
//label row
b1.Add(new float[] { b[i + timeSteps - 1] });
}

    //split data into train, validation and test data set
var xxx = splitData(a1.ToArray(), 0.1f, 0.1f);
var yyy = splitData(b1.ToArray(), 0.1f, 0.1f);

 

    var retVal = new Dictionary<string, (float[][] train, float[][] valid, float[][] test)>();
retVal.Add("features", xxx);
retVal.Add("label", yyy);
return retVal;
}

注:注意代码里的()元组形式,这和python类似了。另外var动态变量类型也和python类似了。
生成数据后,要创建三个数据集: train、validate 和test,test是上述方法生成的数据拆分而来。下面的splitData方法将原dataset分成三个datasets:


static (float[][] train, float[][] valid, float[][] test) splitData(float[][] data,
float valSize = 0.1f, float testSize = 0.1f)
{
//calculate
var posTest = (int)(data.Length * (1 - testSize));
var posVal = (int)(posTest * (1 - valSize));

    return (data.Skip(0).Take(posVal).ToArray(),
data.Skip(posVal).Take(posTest - posVal).ToArray(), data.Skip(posTest).ToArray());
}

为了可视化数据,创建了 Windows 窗体项目。此外,使用 ZedGraph .NET 类库来可视化数据。下图显示了生成的数据。

网络建模

如博客文章开头所述,我们将创建 LSTM 循环神经网络,每个输入有 1 个 LSTM 单元。我们有 N 个输入,每个输入都是连续函数中的一个值。LSTM 的 N 个输出是产生单个输出的密集层的输入。在 LSTM 和密集层之间,我们插入了一个 dropout 层,该层随机丢弃来自 LSTM 的 20% 的值,以防止模型过度拟合训练数据集。我们想在训练期间使用 dropout 层,但是在使用模型进行预测时,我们不想丢弃值。
LSTM 的实现可以用一种方法进行总结,但真正的实现可以在本文随附的演示示例中查看。
以下方法实现了上图所示的 LSTM 网络。该方法的参数已经定义。


public static Function CreateModel(Variable input, int outDim, int LSTMDim,
int cellDim, DeviceDescriptor device, string outputName)
{

    Func<Variable, Function> pastValueRecurrenceHook = (x) => CNTKLib.PastValue(x);

    //creating LSTM cell for each input variable
Function LSTMFunction = LSTMPComponentWithSelfStabilization<float>(
input,
new int[] { LSTMDim },
new int[] { cellDim },
pastValueRecurrenceHook,
pastValueRecurrenceHook,
device).Item1;

    //after the LSTM sequence is created return the last cell in order to
//continue generating the network
Function lastCell = CNTKLib.SequenceLast(LSTMFunction);

    //implement drop out for 10%
var dropOut = CNTKLib.Dropout(lastCell,0.2, 1);

    //create last dense layer before output
var outputLayer =  FullyConnectedLinearLayer(dropOut, outDim, device, outputName);

    return outputLayer;
}

注:Func<Variable, Function> pastValueRecurrenceHook = (x) => CNTKLib.PastValue(x);Func委托,结果是Function函数,x是参数,实际函数代码是CNTKLib.PastValue(x)。

训练网络

为了训练模型,nextBatch()实施了产生以提供训练功能的批次方法。请注意,由于 CNTK 支持可变序列长度,我们必须将批次作为序列列表提供。这是生成小批量数据的便利功能,通常称为小批量。


private static IEnumerable<(float[] X, float[] Y)> nextBatch(float[][] X, float[][] Y, int mMSize)
{

    float[] asBatch(float[][] data, int start, int count)
{
var lst = new List<float>();
for (int i = start; i < start + count; i++) { if (i >= data.Length)
break;

            lst.AddRange(data[i]);
}
return lst.ToArray();
}

    for (int i = 0; i <= X.Length - 1; i += mMSize)
{ var size = X.Length - i; if (size > 0 && size > mMSize)
size = mMSize;

        var x = asBatch(X, i, size);
var y = asBatch(Y, i, size);

        yield return (x, y);
}
}

注意:由于本教程是作为 WinForms C# 项目实现的,它可以可视化训练和测试数据集,并且可以在训练过程中显示最佳找到的模型,所以还有很多其他实现的方法,这里没有提到,但是可以可以在此博客文章所附的演示源代码中找到。

关键见解

使用 LSTM 时,用户应注意以下几点:
由于 LSTM 必须使用未知维度的轴,因此应该以不同的方式定义变量,就像我们在之前的博客文章中看到的那样。因此,输入和输出变量使用以下代码清单进行初始化:


// build the model
var feature = Variable.InputVariable(new int[] { inDim },
DataType.Float, featuresName, null, false /*isSparse*/);
var label = Variable.InputVariable(new int[] { ouDim },
DataType.Float, labelsName, new List<CNTK.Axis>() { CNTK.Axis.DefaultBatchAxis() }, false);

如原始教程中所述:“指定动态轴使递归引擎能够以预期的顺序处理时间序列数据。请花点时间了解如何在 CNTK 中同时使用静态和动态轴,如此处所述动态轴是 LSTM 中的关键点。
现在继续执行定义学习率、动量、学习者和训练者。


var lstmModel = LSTMHelper.CreateModel(feature, ouDim, hiDim, cellDim, device, "timeSeriesOutput");

Function trainingLoss = CNTKLib.SquaredError(lstmModel, label, "squarederrorLoss");
Function prediction = CNTKLib.SquaredError(lstmModel, label, "squarederrorEval");

// prepare for training
TrainingParameterScheduleDouble learningRatePerSample =
new TrainingParameterScheduleDouble(0.0005, 1);
TrainingParameterScheduleDouble momentumTimeConstant = CNTKLib.MomentumAsTimeConstantSchedule(256);

IList<Learner> parameterLearners = new List<Learner>() {
Learner.MomentumSGDLearner(lstmModel.Parameters(),
learningRatePerSample, momentumTimeConstant, /*unitGainMomentum = */true)  };

//create trainer
var trainer = Trainer.CreateTrainer(lstmModel, trainingLoss, prediction, parameterLearners);

现在代码已经准备好了,这 10 个 epoch 应该会返回可接受的结果:


// train the model
for (int i = 1; i <= iteration; i++)
{
//get the next minibatch amount of data
foreach (var miniBatchData in nextBatch(featureSet.train, labelSet.train, batchSize))
{
var xValues = Value.CreateBatch<float>(new NDShape(1, inDim), miniBatchData.X, device);
var yValues = Value.CreateBatch<float>(new NDShape(1, ouDim), miniBatchData.Y, device);

        //Combine variables and data in to Dictionary for the training
var batchData = new Dictionary<Variable, Value>();
batchData.Add(feature, xValues);
batchData.Add(label, yValues);

        //train minibatch data
trainer.TrainMinibatch(batchData, device);
}

    if (this.InvokeRequired)
{
// Execute the same method, but this time on the GUI thread
this.Invoke(
new Action(() =>
{
//output training process
progressReport(trainer, lstmModel.Clone(), i, device);
}
));
}
else
{
//output training process
progressReport(trainer, lstmModel.Clone(), i, device);
}            
}

模型评估

模型评估在训练过程中实施。通过这种方式,我们可以看到学习过程以及模型是如何变得越来越好的。
对于每个小批量,progress都会调用该方法来更新训练和测试数据集的图表。


void progressReport(Trainer trainer, Function model, int iteration, DeviceDescriptor device)
{
textBox3.Text = iteration.ToString();
textBox4.Text = trainer.PreviousMinibatchLossAverage().ToString();
progressBar1.Value = iteration;

    reportOnGraphs(trainer, model, iteration, device);
}

private void reportOnGraphs(Trainer trainer, Function model, int i, DeviceDescriptor device)
{
currentModelEvaluation(trainer, model, i, device);
currentModelTest(trainer, model, i, device);
}

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内