本章我们将学习以下内容:

l  什么是微基准测试

l  如何将它应用到代码中

l  什么是激活函数

l  如何绘制和基准测试激活函数

每个开发人员都需要有一个好的基准测试工具。质量基准无处不在;你们每天都能听到,这个减少了10%那个增加了25%还记得那句老话吗,当你听到一个数字被抛出时,98.4%的情况下这个数字是假的。顺便说一下,这个数字也是我编的。当你听到这样的话,让那个人证明一下,你会得到什么?我们不需要定性的结果;我们需要能够被证明和持续复制的量化结果。可重复的结果是非常重要的,不仅对一致性,而且对可信度和准确性。这就是微基准测试发挥作用的地方。

我们将使用BenchmarkDotNet库,您可以在这里找到:https://github.com/dotnet/BenchmarkDotNet。我认为它是您可以使用的最不可替代的框架之一,我认为它的重要性不亚于单元测试和集成测试

为了展示这个工具的价值,我们将绘制几个激活函数并比较它们的运行时。作为其中的一部分,我们将考虑预热、遗留和RyuJIT、冷启动以及程序执行的更多方面。最后,我们会得到一组定量的结果来证明函数的精确度量。如果在2.0版本中,我们看到某些东西运行得比较慢,我们可以重新运行基准并进行比较。

我强烈建议将其集成到您的持续集成/持续构建过程中,以便在每个版本中都可以比较基准数据。

在本章中,我们将有两个样本。第一个是激活函数查看器;它将绘制每个激活函数,以便我们可以看到它的外观。可以在Colin Green的SharpNEAT中找到它,它是开源的。这个包绝对是不可思议的。我在它的基础上创建了新的ui以及高级版本来满足我的需求,它是目前能找到的最灵活的工具。第一个示例应用程序带有最新的SharpNEAT包,可以在https://github.com/colgreen/sharpneat找到它。

使用视觉绘图方法

下面是一个局部和全局最小值的图,它是由SharpNEAT的自定义版本绘制的。

如前所述,我们将绘制并测试几个激活函数。我们到处都听到激活函数这个词,但我们真的知道它的意思吗?让我们从一个快速的解释开始。

一个激活函数用来决定一个神经元是否被激活。有些人喜欢用fired来代替activated。不管怎样,它最终决定了某个东西是开还是关,是被触发还是没有,是被激活还是没有。

.让我们首先看一个单个激活函数的图:

这是逻辑陡峭近似和Swish激活函数单独绘制时的样子,因为有很多类型的激活函数,这是我们所有的激活函数一起绘制时的样子:

在这一点上,你可能会想,我们为什么还要关心情节是什么样的呢?好问题。我们关心这些,因为一旦你进入神经网络或其他领域,你会经常用到这些。这是非常方便的,能够知道你的激活函数是否将你的神经元的值在开或关的状态,以及它将保持或需要的值在什么范围内。毫无疑问,你将在作为机器学习开发人员的职业生涯中遇到和/或使用激活函数,了解TanH和LeakyReLU激活函数之间的区别非常重要。

绘制所有函数

所有激活函数的绘图都是在一个函数内完成的,这个函数名为PlotAllFunctions:

private void PlotAllFunctions()
{
// 首先,从母版窗格中清除所有旧的GraphPane
collection MasterPane master = zed.MasterPane;
master.PaneList.Clear();
// 显示母版窗格标题,并设置
outer margin to points
master.Title.IsVisible = true;
master.Margin.All = ;
// 在主窗格上绘制多个函数.
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 = ;
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=; 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 = , WarmupCount = ,
  TargetCount = , 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 = , WarmupCount = ,
      TargetCount = , 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 = , WarmupCount = , TargetCount = ,
        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=; i<__loops; i++)
  {
    a = Functions.LogisticFunctionSteep(_x[i % _x.Length]);
  }
  return a;
}

此处使用了[Benchmark]属性。这向BenchmarkDotNet表明,这将是一个需要进行基准测试的测试。在内部调用如下函数:

对于logisticfunction陡峭函数,其实现与大多数激活函数一样简单(假设你知道公式)。在这种情况下不是绘制激活函数,而是对其进行基准测试。

你将注意到函数接受并返回double。我们也通过使用和返回浮点变量对相同的函数进行基准测试,因此我们使用double对函数之间的差异进行基准测试和浮动。因此,人们可以看到,有时性能影响比他们想象的要大:

总结

在本章中,我们学习了如何将微基准测试应用到代码中。我们还了解了如何绘制和基准测试激活函数,以及如何使用微基准测试。现在,您有了一个最强大的基准测试库,可以将其添加到所有代码中。在下一章中,我们将深入探讨直观的深度学习,并向您展示c#开发人员可以使用的最强大的机器学习测试框架之一。

基于C#的机器学习--微基准测试和激活功能的更多相关文章

  1. 基于C#的机器学习--目录

    转载请注明出处:https://www.cnblogs.com/wangzhenyao1994/p/10223666.html 文章发表的另一个地址:https://blog.csdn.net/wyz ...

  2. 基于C#的机器学习--深层信念网络

    我们都听说过深度学习,但是有多少人知道深度信念网络是什么?让我们从本章开始回答这个问题.深度信念网络是一种非常先进的机器学习形式,其意义正在迅速演变.作为一名机器学习开发人员,对这个概念有一定的了解是 ...

  3. Java12新特性 -- 微基准测试套件

    JMH,即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件.何谓Micro Benchmark呢?简单的来说就是基于方法层面的基准测试,精度可以达到微秒级.当 ...

  4. [译]使用JMH进行微基准测试:不要猜,要测试!

    英文原文:Micro Benchmarking with JMH: Measure, don't guess!翻译地址:使用JMH进行微基准测试:不要猜,要测试!原文作者:Antonio翻译作者:Ho ...

  5. Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试

    本文是本人前一段时间做一个简单Java监控工具调研总结,主要包括VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,以及对Java微基准测试的简单介绍, ...

  6. 基于Spring Cloud的微服务入门教程

    (本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...

  7. 基于Python的机器学习实战:KNN

    1.KNN原理: 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系.输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应 ...

  8. 干货|基于 Spring Cloud 的微服务落地

    转自 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的 ...

  9. 基于Spring Cloud的微服务落地

    微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务 ...

随机推荐

  1. 《Microsoft编写优质无错C程序秘诀》提纲

    第1章 假想的编译程序1.使用编译程序所有的可选警告设施2.使用lint来查出编译程序漏掉的错误3.如果有单元测试,就进行单元测试第2章 自己设计并使用断言1.既要维护程序的交付版本,又要维护程序的调 ...

  2. 浅析在QtWidget中自定义Model(beginInsertRows()和endInsertRows()是空架子,类似于一种信号,用来通知底层)

    Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...

  3. 数据库连接池之_Druid简单使用

    数据库连接池: 连接池是创建和管理一个连接的缓冲池的技术,这些连接真备好被任何需要他们的线程使用,可以对传统的JDBCjava数据库连接()进行优化 在实际开发中,我们需要频繁的操作数据库,这就意味着 ...

  4. 为新项目添彩的 10+ 超有用 JavaScript 库

    快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中.   <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...

  5. C#每天进步一点--引用类型和值类型

    在刚参加工作面试时,我们经常会遇到有关值类型和引用类型的问题,你回答的怎么样直接影响你在别人心目中的印象,你回答的不好说明你对C#没有深入的了解学习,今天我带大家回顾下C#中的引用类型和值类型. CL ...

  6. java中Array和ArrayList区别

    1)精辟阐述:可以将 ArrayList想象成一种“会自动扩增容量的Array”. 2)Array([]):最高效:但是其容量固定且无法动态改变:     ArrayList:  容量可动态增长:但牺 ...

  7. Hexo+NexT(一):在Windows下安装Hexo+NexT及搭建博客

    阅读本篇之前,假定读者已经有了Node.js的基础,如需要补充Node.js知识的,请自行百度. Hexo是在Node.js框架下的一个项目,利用Node.js提供的强大功能,完成从Markdown到 ...

  8. vue history 模式打包部署在域名的二级目录的配置指南

    最近在做项目,需要把项目部署在域名下的二级目录,并且是在用vue-router的history 模式. 我们都知道vue-router 的两种前端基本访问模式 hash 和history .hash ...

  9. python trojan development 2nd —— use python to send mail and listen to the key board then combine them

    请勿用于非法用途!!!!!本人概不负责!!!原创作品,转载说明出处!!!!! from pynput.keyboard import Key,Listener import logging impor ...

  10. 【简单脚本】Linux查看配置信息

    命令比较多,统一整合了一下: 1.新建文件touch getComputerConf.sh 2.vim getComputerConf.sh 3.按i键插入,右键粘贴如下内容: #!/bin/sh e ...