65.9K
CodeProject 正在变化。 阅读更多。
Home

构建简单人工智能 .NET 库 - 第 1 部分 - 基础优先

starIconstarIconstarIconstarIconstarIcon

5.00/5 (20投票s)

2017年9月9日

CPOL

5分钟阅读

viewsIcon

40352

downloadIcon

1754

一系列文章的第一部分,演示如何从零开始构建.NET AI库

系列介绍

我的目标是创建一个简单的AI库,涵盖一些高级AI主题,例如遗传算法、人工神经网络、模糊逻辑和其他进化算法。完成这个系列文章的唯一挑战是是否有足够的时间编写代码和文章。

拥有代码本身可能不是主要目标,然而,理解这些算法才是。希望有一天能对某些人有所帮助。

这个系列将分几部分发布,具体多少还不确定。无论如何,每一部分将专注于一个关键主题,并力求全面覆盖。

请随时评论并提出任何澄清问题,或者希望提出更好的方法。

文章介绍 - 第一部分 “基础”

这是多部分系列的第一部分,我将它专门用于介绍一个名为“CommonLib”的基础库,其中包含一些基本类,如

  • 一个名为“Canvas”的图形封装类
  • 用于处理“Vector”和“Matrix”运算以及其他数学运算的数学封装类
  • 一个名为“RandomFactory”的随机数生成器类

上述每个类将在下面详细解释。

1. 图形封装类 Canvas

图形将用于测试我们将要构建的AI库,因此,我创建了一个封装类来包含所有常用的图形操作,使其比创建Graphics对象更方便。

Canvas类封装了一些图形操作,如DrawLineDrawBoxSquare)、DrawCircleDrawTextClear

主要地,它包含一个内部图形对象g和一个位图对象bmp

构造函数

''' <summary>
''' Canvas constructor function
''' </summary>
''' <param name="_width">Drawing area - Width</param>
''' <param name="_height">Drawing area - Height</param>
Public Sub New(_width As Integer, _height As Integer)
    Me._Width = _width
    Me._Height = _height
    Me._bmp = New Bitmap(_width, _height)
    g = Graphics.FromImage(_bmp)
    g.SmoothingMode = SmoothingMode.HighQuality
End Sub

WidthHeight是创建Canvas对象的必需整数,它们代表绘制区域。

下面是一个声明canvas对象及其用法的示例。

Imports CommonLib.CommonLib

Public Class Form1
    ' Form-level Canvas object
    Private myCanvas As Canvas

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        myCanvas = New Canvas(PictureBox1.Width, PictureBox1.Height)
        Draw()
    End Sub

    Private Sub Draw()
        With myCanvas
            .DrawBox(50, 25, 25, Color.Black)
            .FillBox(50, 100, 25, Color.Red)
            .DrawCircle(50, 100, 200, Color.Blue)
            .FillCircle(50, 200, 200, Color.Green)
            .DrawText("Test String", 250, 200, Color.Red)
        End With
        ' To draw canvas
        PictureBox1.Image = myCanvas.Image
        ' other code
    End Sub

    Private Sub Clear()
        myCanvas.Clear()
        PictureBox1.Image = myCanvas.Image
    End Sub
End Class

上面代码的结果如下

2. 数学类

MathFunctions

这个类封装了一些有用的数学函数

Constraint Function (约束函数)

''' <summary>
''' Constrains value between min and max values
'''   if less than min, return min
'''   more than max, return max
'''   otherwise return same value
''' </summary>
''' <param name="Value"></param>
''' <param name="min"></param>
''' <param name="max"></param>
''' <returns></returns>
Public Function Constraint(Value As Single, min As Single, max As Single) As Single
    If Value <= min Then
        Return min
    ElseIf Value >= max Then
        Return max
    End If
    Return Value
End Function

Map Function (映射函数)

''' <summary>
''' Re-maps a number from one range to another. In the example above,
''' </summary>
''' <param name="value"> the incoming value to be converted </param>
''' <param name="start1"> lower bound of the value's current range </param>
''' <param name="stop1"> upper bound of the value's current range </param>
''' <param name="start2"> lower bound of the value's target range </param>
''' <param name="stop2"> upper bound of the value's target range </param>
Public Shared Function Map(ByVal value As Single, ByVal start1 As Single, _
  ByVal stop1 As Single, ByVal start2 As Single, ByVal stop2 As Single) As Single
    Dim Output As Single = start2 + (stop2 - start2) * ((value - start1) / _
                           (stop1 - start1))
    Dim errMessage As String = Nothing
    
    If Output <> Output Then
        errMessage = "NaN (not a number)"
        Throw New Exception(errMessage)
    ElseIf Output = Single.NegativeInfinity _
                    OrElse Output = Single.PositiveInfinity Then
        errMessage = "infinity"
        Throw New Exception(errMessage)
    End If
    Return Output
End Function

Norm Function (范数函数)

''' <summary>
''' Normalizes a number from another range into a value between 0 and 1.
''' Identical to map(value, low, high, 0, 1);
''' Numbers outside the range are not clamped to 0 and 1, because
''' out-of-range values are often intentional and useful.
''' </summary>
''' <param name="value"> the incoming value to be converted </param>
''' <param name="start"> lower bound of the value's current range </param>
''' <param name="stop"> upper bound of the value's current range </param>
Public Shared Function Norm(ByVal value As Single, _
                            ByVal start As Single, ByVal [stop] As Single) As Single
    Return (value - start) / ([stop] - start)
End Function

GetBitArray Function (获取位数组函数)

''' <summary>
''' Generates 8 bit array of an integer, value from 0 to 255
''' </summary>
''' <param name="Value"></param>
''' <returns></returns>
Public Function GetBitArray(Value As Integer) As Integer()
    Dim Result(7) As Integer
    Dim sValue As String
    Dim cValue() As Char
    
    Value = Constraint(Value, 0, 255)
    sValue = Convert.ToString(Value, 2).PadLeft(8, "0"c)
    cValue = sValue.ToArray
    For i As Integer = 0 To cValue.Count - 1
        If cValue(i) = "1"c Then
            Result(i) = 1
        Else
            Result(i) = 0
        End If
    Next
    Return Result
End Function

Matrix Operations (矩阵运算)

矩阵运算非常重要(尤其对于后续的人工神经网络),因此创建单独的类来处理不同情况下的矩阵函数是值得的,即VectorMatrix1D

有很多资源可以描述矩阵及其函数,因此我不会在这上面花费太多时间。

只需提及,在CommonLib中目前只考虑了两种特殊矩阵:Matrix1DVector

Matrix1D

是单列矩阵

稍后,此类将有助于简化神经网络的创建。此类实现了IMatrix接口。

  • Size - 矩阵的大小或容量 - 简单来说就是Values数组中存储的元素数量
  • Product - 实现两个矩阵m1m2之间的矩阵乘法,或矩阵与标量的乘法
  • Add - 实现两个矩阵m1m2之间的矩阵加法,或矩阵与标量的加法
  • Sub - 实现两个矩阵m1m2之间的矩阵减法,或矩阵与标量的减法
  • Divide - 实现矩阵与标量之间的矩阵除法
  • Sum - 矩阵所有元素的和 a1+a2+a3+...........+an
  • RandomizeValues - 将矩阵元素随机化到最小和最大值之间
  • Copy - 将一个矩阵的内容复制到对象中,从给定的起始索引开始
  • ForceValues - 将矩阵的所有元素强制设置为ForcedValue
  • GetValue - 返回矩阵中索引为Index的元素,索引从0开始
  • SetValue - 设置矩阵元素在位置Index的值,索引从0开始

向量

Vector是一个特殊的矩阵,具有1行多列(在本例中,只考虑2列和3列,不考虑更高的维度)。这是思考向量的一种方式,然而最有效的方式是将vector视为“大小加上方向”的对象。这是一个非常强大但又非常简单的对象;只需给出两个数字,我们就可以提取大小和方向。

向量在数学和物理学中扮演着非常重要的角色,也许我将另开一篇文章专门介绍向量。现在,您可以访问此链接 获取更多关于向量和向量运算的信息。

注意CommonLib仅考虑二维和三维向量,对于更高维度的向量,将使用矩阵。

CommonLib中实现了许多向量运算,例如

  • Randomize - 将向量的XYZ分量随机化到01之间
  • Magnitude - 计算向量的欧几里得范数(长度),并返回结果 = SQRT (X2+Y2+Z2)
  • Add - 将xyz分量添加到向量,将一个向量加到另一个向量,或将两个独立向量相加。以下是来自维基百科的向量加法的图形表示。

  • Sub - 执行向量与向量或标量值的减法运算

  • Mult - 实现向量标量乘法
  • Div - 是标量除法实现
  • Distance - 计算两个向量之间的欧几里得距离 = SQRT (dX2+dY2+dZ2)
  • Dot - 实现向量的点积。更多信息请访问此链接
  • Cross - 实现向量的叉积。以下是链接解释其背后的数学原理。
  • Normalize - 将向量归一化为长度为1(使其成为单位向量)。
  • Limit - 将此向量的幅度限制为由max参数传递的值。
  • SetMag - 将此向量的幅度设置为由len参数传递的值。
  • Heading - 计算此向量的旋转角度。
  • Rotate - 按角度旋转向量,幅度保持不变。
  • AngleBetween - 计算并返回两个向量之间的角度(以弧度为单位)。

3. RandomFactory

这个类对于初始化各种AI对象和进行测试目的都非常重要。它扩展了.NET的Random类并添加了更多方法。

除了数字(integerSingleDouble)之外,它还可以提供不同的随机函数,如随机颜色、随机字符、随机布尔值。

此外,它通过Box-Muller变换实现了Gaussian(高斯)随机函数。

''' <summary>
'''   Generates normally distributed numbers using Box-Muller transform by 
'''   generating 2 random doubles
'''   Gaussian noise is statistical noise having a probability density function (PDF) 
'''   equal to that of the normal distribution, 
'''   which is also known as the Gaussian distribution.
'''   In other words, the values that the noise can take on are Gaussian-distributed.
''' </summary>
''' <param name = "Mean">Mean of the distribution, default = 0</param>
''' <param name = "StdDeviation">Standard deviation, default = 1</param>
''' <returns></returns>
Public Function NextGaussian(Optional ByVal Mean As Double = 0, _
                             Optional ByVal StdDeviation As Double = 1) As Double
    Dim X1 = _Gen.NextDouble()
    Dim X2 = _Gen.NextDouble()
    Dim StdDistribution = Math.Sqrt(-2.0 * Math.Log(X1)) * Math.Sin(2.0 * Math.PI * X2)
    Dim GaussianRnd = Mean + StdDeviation * StdDistribution
    
    Return GaussianRnd
End Function

它还实现了Triangle(三角形)分布随机数生成(您可以查看此维基百科文章)。

''' <summary>
'''   Generates values from a triangular distribution
'''   Triangular distribution is a continuous probability distribution with:
'''       lower limit a
'''       upper limit b 
'''       mode c
'''   where a less than b 
'''   c is higher than or equal a but less than or equal b
''' </summary>
''' <param name = "min">Minimum</param>
''' <param name = "max">Maximum</param>
''' <param name = "mode">Mode (most frequent value)</param>
''' <returns></returns>
Public Function NextTriangular(ByVal min As Double, ByVal max As Double, _
                               ByVal mode As Double) As Double
    Dim u = _Gen.NextDouble()
    
    If (u < (mode - min) / (max - min)) Then
        Return min + Math.Sqrt(u * (max - min) * (mode - min))
    Else
        Return max - Math.Sqrt((1 - u) * (max - min) * (max - mode))
    End If
End Function

Shuffle方法提供了使用Fisher-Yates/Knuth算法的列表随机排序实现。

''' <summary>
'''   Shuffles a list in O(n) time by using the Fisher-Yates/Knuth algorithm
''' </summary>
''' <param name = "list"></param>
Public Sub Shuffle(ByVal list As IList)
    For i = 0 To list.Count - 1
        Dim j = _Gen.Next(0, i + 1)
        
        Dim temp = list(j)
        list(j) = list(i)
        list(i) = temp
    Next i
End Sub

为了获得RandomFactory类的有效结果,应创建一个全局或窗体级别的对象,并在整个代码中使用。

下一步是什么

下一篇文章将是关于遗传算法(可能是模糊控制器!),取决于哪个代码会先准备好。

待办事项列表

  1. 添加二维矩阵运算实现。一维矩阵目前还可以,但扩展库以包含二维矩阵将增加更多效率或实用性。我希望在开始人工神经网络库之前完成这项任务。

历史

  • CommonLib已构建为作为不同项目的支持类库,因此应将其保留为一个单独的解决方案,并仅添加引用。

该库的第一版已于2017年8月完成,预计后续版本将继续推出。

© . All rights reserved.