この章では次のことを学びます。
Lマイクロベンチマークは何ですか
コードにそれを適用する方法リットル
lの活性化関数とは何ですか
描画する方法リットルとベンチマーク活性化機能
各開発者は、優れたベンチマークツールを持っている必要があります。どこでも品質基準;あなたは、毎日あなたは古い諺に覚えて25%増加し10%削減、あなたは数がスローされたと聞くと、例98.4%で、この数字がfalseを聞くことができますA。ちなみに、この数字は私が作っています。あなたはその人がそれを証明しましょう、のようなものを聞くとき、あなたは結果をどのように取得します我々は連続レプリケーションおよび定量的な結果を証明できるようにする必要があります;?定性的な必要はありません。再現性のある結果は一貫性が、また、信頼性と精度のためだけでなく、非常に重要です。これは遊びにマイクロベンチマークです。
ます。https://github.com/dotnet/BenchmarkDotNet私たちは、あなたが見つけることができるBenchmarkDotNetライブラリを使用します。私はそれはあなたが使用できる最もかけがえのないフレームワークの一つだと思い、私はそれはユニットテストと統合テストとして重要だと思います
このツールの価値を実証するために、我々はいくつかの活性化関数を描画し、その実行を比較します。その一環として、我々は、プログラム実行のウォームアップ、左とRyuJIT、コールドスタートとより多くの側面を考慮します。最後に、私たちは、正確な測定機能を証明する定量的な結果のセットを取得します。バージョン2.0ならば、我々はベンチマークを再実行して比較することができ、何かがもっとゆっくり実行します参照してください。
私は強く、各バージョンの参照データを比較するために、引き続きご継続的インテグレーション/ビルドプロセスに統合することをお勧めします。
この章では、我々は二つのサンプルを持っています。最初の関数は、ビューアを活性化することである。我々はそれがどのように見えるかを確認できるように、それは、それぞれの活性化関数を描画します。これはオープンソースであるSharpNEATコリン・グリーン、で見つけることができます。このパッケージには絶対に信じられないです。私は自分のニーズを満たすために新しいUIと高度なバージョンに基づいてそれを作成し、それが現在見つけることができる最も柔軟なツールです。最新SharpNEATパッケージと最初のサンプルアプリケーションでは、あなたはhttps://github.com/colgreen/sharpneatでそれを見つけることができます。
視覚的な描画方法を使用して、
次はSharpNEATのカスタムバージョンによって描かれる世界最小とローカルマップ、です。
前述したように、我々はいくつかの活性化関数を描画し、テストします。どこでも、私たちは言葉の活性化関数を聞くが、私たちは本当にそれが何を意味するのか知っていますか?私たちは迅速な説明から始めましょう。
活性化関数は、ニューロンが活性化されるかどうかを決定するために使用されます。一部の人々は解雇有効を置き換えるために使用したいです。いずれにせよ、それは最終的に何かがオンまたはオフ、トリガされているかどうか、起動したりしていないと判断します。
私たちは最初の単一活性化関数のビューを見てみましょう:
それは私たちが一緒にすべてのロジック急な活性化関数近似を描き、ある活性化関数、多くの種類があるので、一人で関数としてプロットした場合のようにパッアクティブにしたときのようなものです:
この時点で、あなたは、なぜ我々は気にする必要があり、考えるかもしれないプロットのどのようなことがある?良い質問。あなたは、ニューラルネットワークまたは他のエリアに入ると、あなたは多くの場合、これらを使用しますので、私たちは、それらを気に。それはあなたの状態のニューロンオンまたはオフの活性化関数の値かどうかを知ることができ、非常に便利であり、それは必要な値を維持するか、またはどの程度になります。あなたがマシンとして学習開発者のキャリアの中で遭遇する、および/または活性化関数を使用して、およびTANH LeakyReLU活性化機能の違いを理解する疑いが非常に重要です。
すべての機能を描きます
すべての図面は、関数内で関数名PlotAllFunctionsを活性化機能を行われています。
private void PlotAllFunctions() { // 首先,从母版窗格中清除所有旧的GraphPane collection MasterPane master = zed.MasterPane; master.PaneList.Clear(); // 显示母版窗格标题,并设置 outer margin to 10 points master.Title.IsVisible = true; master.Margin.All = 10; // 在主窗格上绘制多个函数. PlotOnMasterPane(Functions.LogisticApproximantSteep,"Logistic Steep (Approximant)"); PlotOnMasterPane(Functions.LogisticFunctionSteep,"Logistic Steep (Function)"); PlotOnMasterPane(Functions.SoftSign, "Soft Sign"); PlotOnMasterPane(Functions.PolynomialApproximant,"Polynomial Approximant"); PlotOnMasterPane(Functions.QuadraticSigmoid,"Quadratic Sigmoid"); PlotOnMasterPane(Functions.ReLU, "ReLU"); PlotOnMasterPane(Functions.LeakyReLU, "Leaky ReLU"); PlotOnMasterPane(Functions.LeakyReLUShifted,"Leaky ReLU (Shifted)"); PlotOnMasterPane(Functions.SReLU, "S-Shaped ReLU"); PlotOnMasterPane(Functions.SReLUShifted,"S-Shaped ReLU (Shifted)"); PlotOnMasterPane(Functions.ArcTan, "ArcTan"); PlotOnMasterPane(Functions.TanH, "TanH"); PlotOnMasterPane(Functions.ArcSinH, "ArcSinH"); PlotOnMasterPane(Functions.ScaledELU,"Scaled Exponential Linear Unit"); // 重新设置GraphPanes的轴范围。 zed.AxisChange(); // 使用默认窗格布局布局GraphPanes. using (Graphics g = this.CreateGraphics()) { master.SetLayout(g, PaneLayout.SquareColPreferred); }
主绘制函数
在后台,Plot函数负责执行和绘制每个函数:
private void Plot(Func<double, double> fn, string fnName,Color graphColor, GraphPane gpane = null) { const double xmin = -2.0; const double xmax = 2.0; const int resolution = 2000; zed.IsShowPointValues = true; zed.PointValueFormat = "e"; var pane = gpane ?? zed.GraphPane; pane.XAxis.MajorGrid.IsVisible = true; pane.YAxis.MajorGrid.IsVisible = true; pane.Title.Text = fnName; pane.YAxis.Title.Text = string.Empty; pane.XAxis.Title.Text = string.Empty; double[] xarr = new double[resolution]; double[] yarr = new double[resolution]; double incr = (xmax - xmin) / resolution; double x = xmin; for(int i=0; i < resolution; i++, x+=incr) { xarr[i] = x; yarr[i] = fn(x); } PointPairList list1 = new PointPairList(xarr, yarr); LineItem li=pane.AddCurve(string.Empty,list1,graphColor,SymbolType.None); li.Symbol.Fill = new Fill(Color.White); pane.Chart.Fill = new Fill(Color.White, Color.LightGoldenrodYellow, 45.0F); }
这是执行我们传入的激活函数的地方,它的值用于y轴标绘值。著名的ZedGraph开源绘图包用于所有图形绘制。一旦执行了每个函数,就会生成相应的图。
确定基准点
BenchmarkDotNet生成了几个报告,其中一个是HTML报告,类似于在这里看到的:
Excel报告提供了运行程序时使用的每个参数的详细信息,是最广泛的信息来源。在很多情况下,这些参数中的大多数都使用默认值,超出了我们的需要,但至少我们可以选择删除我们需要删除的内容:
我们将在下一节中描述其中的一些参数,当我们回顾创建之前看到的内容的源代码时:
static void Main(string[] args) { var config = ManualConfig.Create(DefaultConfig.Instance); // 建立一个结果导出器。 // 请注意。默认情况下,结果文件将位于.BenchmarkDotNet.Artifactsresults目录 config.Add(new CsvExporter
(CsvSeparator.CurrentCulture,
new BenchmarkDotNet.Reports.SummaryStyle { PrintUnitsInHeader = true, PrintUnitsInContent = false, TimeUnit = TimeUnit.Microsecond, SizeUnit = BenchmarkDotNet.Columns.SizeUnit.KB }
)
); // 遗留JITter 测试. config.Add(new Job(EnvMode.LegacyJitX64,EnvMode.Clr, RunMode.Short) { Env = { Runtime = Runtime.Clr, Platform = Platform.X64 }, Run = { LaunchCount = 1, WarmupCount = 1, TargetCount = 1, RunStrategy = BenchmarkDotNet.Engines.RunStrategy.Throughput }, Accuracy = { RemoveOutliers = true } }.WithGcAllowVeryLargeObjects(true)
); // RyuJIT测试。 config.Add(new Job(EnvMode.RyuJitX64, EnvMode.Clr,RunMode.Short) { Env = { Runtime = Runtime.Clr, Platform = Platform.X64 }, Run = { LaunchCount = 1, WarmupCount = 1, TargetCount = 1, RunStrategy = BenchmarkDotNet.Engines.RunStrategy.Throughput }, Accuracy = { RemoveOutliers = true } }.WithGcAllowVeryLargeObjects(true)
); // 取消注释以允许对未优化的程序集进行基准测试。 //config.Add(JitOptimizationsValidator.DontFailOnError); // 运行基准测试。 var summary = BenchmarkRunner.Run<FunctionBenchmarks>(config); }
让我们进一步分析这段代码:
首先,我们将创建一个手动配置对象,其中包含用于基准测试的配置参数:
var config = ManualConfig.Create(DefaultConfig.Instance);
接下来,我们将设置一个导出器来保存用于导出结果的参数。我们将使用微秒计时和千字节大小将结果导出到.csv文件:
config.Add(new CsvExporter
(CsvSeparator.CurrentCulture,
new BenchmarkDotNet.Reports.SummaryStyle { PrintUnitsInHeader = true, PrintUnitsInContent = false, TimeUnit = TimeUnit.Microsecond, SizeUnit = BenchmarkDotNet.Columns.SizeUnit.KB }
)
);
接下来,我们将创建一个基准作业,它将处理x64体系结构上LegacyJitX64的度量。您可以随意更改此参数和任何其他参数,以进行实验,或者包含测试场景所需或需要的任何结果。在我们的例子中,我们将使用x64平台;启动计数、预热计数和目标计数为1;以及吞吐量的运行策略。我们也会对RyuJIT做同样的事情,但是我们不会在这里显示代码:
config.Add(new Job(EnvMode.LegacyJitX64, EnvMode.Clr,RunMode.Short) { Env = { Runtime = Runtime.Clr, Platform = Platform.X64 }, Run = { LaunchCount = 1, WarmupCount = 1, TargetCount = 1, RunStrategy = Throughput }, Accuracy = { RemoveOutliers = true } }.WithGcAllowVeryLargeObjects(true)
);
最后,我们将运行BenchmarkRunner来执行我们的测试:
var summary = BenchmarkRunner.Run<FunctionBenchmarks>(config);
BenchmarkDotNet将作为DOS命令行应用程序运行,下面是执行上述代码的一个例子:
让我们来看一个被绘制的激活函数的例子:
[Benchmark] public double LogisticFunctionSteepDouble() { double a = 0.0; for(int i=0; i<__loops; i++) { a = Functions.LogisticFunctionSteep(_x[i % _x.Length]); }
return a; }
此处使用了[Benchmark]属性。这向BenchmarkDotNet表明,这将是一个需要进行基准测试的测试。在内部调用如下函数:
对于logisticfunction陡峭函数,其实现与大多数激活函数一样简单(假设你知道公式)。在这种情况下不是绘制激活函数,而是对其进行基准测试。
你将注意到函数接受并返回double。我们也通过使用和返回浮点变量对相同的函数进行基准测试,因此我们使用double对函数之间的差异进行基准测试和浮动。因此,人们可以看到,有时性能影响比他们想象的要大:
总结
在本章中,我们学习了如何将微基准测试应用到代码中。我们还了解了如何绘制和基准测试激活函数,以及如何使用微基准测试。现在,您有了一个最强大的基准测试库,可以将其添加到所有代码中。在下一章中,我们将深入探讨直观的深度学习,并向您展示c#开发人员可以使用的最强大的机器学习测试框架之一。