在 Scala 中实现 Perceptron 时遇到问题
Trouble implementing Perceptron in Scala
我正在学习 CalTech 在线课程 从数据中学习,我对在 Scala 中创建 Perceptron
感到困惑。我选择 Scala 是因为我正在学习它并想挑战自己。我理解理论,也理解其他人在Python和Ruby中的解决方案。但我想不通为什么我自己的 Scala 代码不起作用。
Perceptron
代码中的背景:Learning_algorithm
我在 OSX 10.10 上 运行 Scala 2.11。
根据算法,我从权重 (0.0, 0.0, 0.0) 开始,其中权重 [2] 是学习偏差分量。我已经在 X-Y 平面上的 space [-1, 1],[-1,1] 中生成了一个测试集。我通过 a) 选择两个随机点并通过它们画一条线,然后 b) 生成一些其他随机点并计算它们是在线的一侧还是另一侧。据我所知,通过在 Python 中绘制它可以生成线性可分数据。
我的下一步是采用我的初始化权重并检查每个点以找到分类错误的点,即未生成正确的 +1 或 -1 结果的点。下面是简单计算权重和向量 x 的点积的代码:
def h(weight:List[Double], p:Point ): Double = if ( (weight(0)*p.x + weight(1)*p.y + weight(2)) > 0) 1 else -1
是初始权重,所以都是误分类。然后我更新权重,如下所示:
def newH(weight:List[Double], p:Point, y:Double): List[Double] = {
val newWt = scala.collection.mutable.ArrayBuffer[Double](0.0, 0.0, 0.0)
newWt(0) = weight(0) + p.x*y
newWt(1) = weight(1) + p.y*y
newWt(2) = weight(2) + 1*y
return newWt.toList
}
然后我根据上面 h() 输出的值检查测试集,再次识别错误分类点,并继续迭代。
这遵循 Yaser 教授在这里展示的算法(或者至少应该遵循):Library
问题是算法永远不会收敛。我的权重——其中的第三个组成部分是偏差——不断变得更负或更正。每次调整后我的权重向量类似于:
Weights: List(16.43341624736786, 11627.122008800507, -34130.0)
Weights: List(15.533397436141968, 11626.464265227318, -34131.0)
Weights: List(14.726969361305237, 11626.837346673012, -34132.0)
Weights: List(14.224745154380798, 11627.646470665932, -34133.0)
Weights: List(14.075232982635498, 11628.026384592056, -34134.0)
我是 Scala 新手,所以我的代码可能很糟糕。但是我在 Scala 中遗漏了什么吗,例如重新分配,这可能会导致我的体重混乱?还是我完全误解了 Perceptron
的运作方式?我的体重更新是错误的吗?
感谢您在这方面给我的任何帮助!
感谢蒂尔。我发现了我的代码的两个问题,我会分享它们,但为了解决你的问题:其他人在 class 的论坛上问过这个问题,看起来 Wiki 公式所做的只是为了改变学习率。可以随机选择 Alpha,y-h(weight, p) 会给你
这样的权重
-1-1 = 2
在y=-1且h()=1的情况下,或者
1-(-1) = 2
在y=1且h()=-1的情况下
My/the class公式取1*p.x
而不是alpha*2
,这似乎是学习率不同的问题。希望这是有道理的。
我的两个问题如下:
- 传入重算公式
newH
的y
值需要是y的目标值,即"correct y"这是在生成测试点时发现的。我传递了通过 h() 生成的 y,这是猜测的函数。这显然是有道理的,因为我们希望通过使用目标 y 而不是不正确的 y 来校正权重。
- 我在 Scala 中对目标
y
和 h()=y
进行了比较,但比较的是通过 .get()
从映射中获得的元素。我的 Scala 映射看起来像 Map[Point,Double]
,其中 Double
值指的是测试集创建期间生成的 y
值。但是做 .get()
给你 Option[Double]
而不是 Double
值。 Scala Map#get and the return of Some() 中对此进行了解释,现在很有意义。我暂时做了 map.get(<some Point>).get()
,因为我专注于调试而不是代码完善,然后我能够准确地比较两个 Double
值。
我正在学习 CalTech 在线课程 从数据中学习,我对在 Scala 中创建 Perceptron
感到困惑。我选择 Scala 是因为我正在学习它并想挑战自己。我理解理论,也理解其他人在Python和Ruby中的解决方案。但我想不通为什么我自己的 Scala 代码不起作用。
Perceptron
代码中的背景:Learning_algorithm
我在 OSX 10.10 上 运行 Scala 2.11。
根据算法,我从权重 (0.0, 0.0, 0.0) 开始,其中权重 [2] 是学习偏差分量。我已经在 X-Y 平面上的 space [-1, 1],[-1,1] 中生成了一个测试集。我通过 a) 选择两个随机点并通过它们画一条线,然后 b) 生成一些其他随机点并计算它们是在线的一侧还是另一侧。据我所知,通过在 Python 中绘制它可以生成线性可分数据。
我的下一步是采用我的初始化权重并检查每个点以找到分类错误的点,即未生成正确的 +1 或 -1 结果的点。下面是简单计算权重和向量 x 的点积的代码:
def h(weight:List[Double], p:Point ): Double = if ( (weight(0)*p.x + weight(1)*p.y + weight(2)) > 0) 1 else -1
是初始权重,所以都是误分类。然后我更新权重,如下所示:
def newH(weight:List[Double], p:Point, y:Double): List[Double] = {
val newWt = scala.collection.mutable.ArrayBuffer[Double](0.0, 0.0, 0.0)
newWt(0) = weight(0) + p.x*y
newWt(1) = weight(1) + p.y*y
newWt(2) = weight(2) + 1*y
return newWt.toList
}
然后我根据上面 h() 输出的值检查测试集,再次识别错误分类点,并继续迭代。
这遵循 Yaser 教授在这里展示的算法(或者至少应该遵循):Library
问题是算法永远不会收敛。我的权重——其中的第三个组成部分是偏差——不断变得更负或更正。每次调整后我的权重向量类似于:
Weights: List(16.43341624736786, 11627.122008800507, -34130.0)
Weights: List(15.533397436141968, 11626.464265227318, -34131.0)
Weights: List(14.726969361305237, 11626.837346673012, -34132.0)
Weights: List(14.224745154380798, 11627.646470665932, -34133.0)
Weights: List(14.075232982635498, 11628.026384592056, -34134.0)
我是 Scala 新手,所以我的代码可能很糟糕。但是我在 Scala 中遗漏了什么吗,例如重新分配,这可能会导致我的体重混乱?还是我完全误解了 Perceptron
的运作方式?我的体重更新是错误的吗?
感谢您在这方面给我的任何帮助!
感谢蒂尔。我发现了我的代码的两个问题,我会分享它们,但为了解决你的问题:其他人在 class 的论坛上问过这个问题,看起来 Wiki 公式所做的只是为了改变学习率。可以随机选择 Alpha,y-h(weight, p) 会给你
这样的权重-1-1 = 2
在y=-1且h()=1的情况下,或者
1-(-1) = 2
在y=1且h()=-1的情况下
My/the class公式取1*p.x
而不是alpha*2
,这似乎是学习率不同的问题。希望这是有道理的。
我的两个问题如下:
- 传入重算公式
newH
的y
值需要是y的目标值,即"correct y"这是在生成测试点时发现的。我传递了通过 h() 生成的 y,这是猜测的函数。这显然是有道理的,因为我们希望通过使用目标 y 而不是不正确的 y 来校正权重。 - 我在 Scala 中对目标
y
和h()=y
进行了比较,但比较的是通过.get()
从映射中获得的元素。我的 Scala 映射看起来像Map[Point,Double]
,其中Double
值指的是测试集创建期间生成的y
值。但是做.get()
给你Option[Double]
而不是Double
值。 Scala Map#get and the return of Some() 中对此进行了解释,现在很有意义。我暂时做了map.get(<some Point>).get()
,因为我专注于调试而不是代码完善,然后我能够准确地比较两个Double
值。