神经网络最基本形式感知器的入门教程3
一个单一的感知器已经可以学习如何分类,让我们看看编码如何实现?
除了一些标准库,我们只需要一个定制库用来将感知器输出变成一个PNG图片:
package main
import ( "fmt" "math/rand" "time" "github.com/appliedgo/perceptron/draw"
)
现在我们定义感知器,一个新的感知器是使用随机权重和偏差,这两个值会在以后训练中修改,感知器执行两个任务:
- 处理输入信号
- 根据训练调整输入权重
这是感知器的数据结构,带有权重和偏差:
type Perceptron struct { weights []float32 bias float32 }
下面是感知器的Heaviside Step function
func (p *Perceptron) heaviside(f float32) int32 { if f < 0 { return 0 } return 1 }
创建一个带有N个输入的感知器,权重和偏差使用-1和1之间随机数初始化。
func NewPerceptron(n int32) *Perceptron { var i int32 w := make([]float32, n, n) for i = 0; i < n; i++ { w[i] = rand.Float32()*2 - 1 }
return &Perceptron{ weights: w, bias: rand.Float32()*2 - 1, } }
下面的Process函数将实现感知器的核心功能,它对输入加入权重,汇总它们,增加偏差值,然后通过Heaviside Step function运行结果,会返回一个boolean类型但是是int32,我们就可以直接使用这个值来调整感知器。
func (p *Perceptron) Process(inputs []int32) int32 { sum := p.bias for i, input := range inputs { sum += float32(input) * p.weights[i] } return p.heaviside(sum)
}
在学习阶段,感知器基于结果和正确结果偏离程度调整其权重和偏差:
func (p *Perceptron) Adjust(inputs []int32, delta int32, learningRate float32) { for i, input := range inputs { p.weights[i] += float32(input) * float32(delta) * learningRate } p.bias += float32(delta) * learningRate }
训练
我们排除线是垂直的,这样我们就能知道一条线等于一个线性函数:
f(x) = ax + b
参数a指定线的梯度(即这条线有多陡),而b代表偏移。
用这种方式描述线,对于一个给定的点,检查这个点是该在线的上方还是下方,对于点(x,y),如果y值大于f(x)结果,那么(x,y)将在线上方。
a和b指定线性函数,这个函数描述分离线,看下面细节,它们以全局水平定义,因为我们在几个地方需要它们。
var ( a, b int32 )
函数描述下面这条线:
func f(x int32) int32 { return a*x + b }
如果点(x,y)在线y=ax+b上方,上面函数返回1,否则返回0:
func isAboveLine(point []int32, f func(int32) int32) int32 {
x := point[0] y := point[1] if y > f(x) { return 1 } return 0
}
下面函数train是训练老师,老师产生一个随机测试点,然后喂给感知器,老师然后比较输出和正确答案,告诉感知器它离正确答案有多远:
func train(p *Perceptron, iters int, rate float32) {
for i := 0; i < iters; i++ {
产生-100和100之间随机点:
point := []int32{ rand.Int31n(201) - 101, rand.Int31n(201) - 101, }
喂这个点给这个感知器然后评估结果:
actual := p.Process(point) expected := isAboveLine(point, f)
让感知器相应地调整其内部值:
p.Adjust(point, expected-actual, rate)
}
}
运行
现在是时候看看感知器如何完成学习任务。我们扔一些随机点,但是这个时候没有老师的反馈。感知器分类会正确吗?
这是我们的测试函数,返回正确答案个数:
func verify(p *Perceptron) int32 { var correctAnswers int32 = 0
创建一个新的画布,x和y范围是-100到100:
c := draw.NewCanvas() for i := 0; i < 100; i++ {
产生-100和100之间的随机点:
point := []int32{ rand.Int31n(201) - 101, rand.Int31n(201) - 101, }
喂这个点给感知器,然后评估结果:
result := p.Process(point) if result == isAboveLine(point, f) { correctAnswers += 1 }
画这个点,颜色告诉你感知器的回答是“在线上面”还是“下面”:
c.DrawPoint(point[0], point[1], result == 1)
}
画这个线y=ax+b
c.DrawLinearFunction(a, b)
保存图片为./result.png
c.Save() return correctAnswers }
下面是main函数:是入口执行函数,设置 训练和测试感知器:
func main() {
设置线参数,线的梯度从-5和5之间变化,b偏移在-50和50之间:
rand.Seed(time.Now().UnixNano()) a = rand.Int31n(11) - 6 b = rand.Int31n(101) - 51
用两个输入点创建一个新的感知器:
p := NewPerceptron(2)
开始学习:
iterations := 1000
var learningRate float32 = 0.1 // Allowed range: 0 < learning rate <= 1.
真正进行训练:
train(p, iterations, learningRate)
感知器准备好测试:
successRate := verify(p) fmt.Printf("%d%% of the answers were correct.\n", successRate)
}
上面完整代码见: GitHub
你可以通过下面方法获得:
go get -d github.com/appliedgo/perceptron cd $GOPATH/github.com/appliedgo/perceptron go build ./perceptron
打开结果的result.png看看感知器对这些点划分得如何?
深入学习教程:从感知到深度神经网络
Tensorflow简单教程