在我的Web应用程序中,我成功地将<canvas>
连接到了PHP5的人工神经网络(http://ann.thwien.de/index.php/Main_Page)。我这样训练它:
<?phprequire_once 'ANN/Loader.php';$data = $_POST['data'];$data = array_map('floatval', $data);use ANN\Network;use ANN\Values;try{ $objNetwork = Network::loadFromFile('xor.dat');}catch(Exception $e){ print 'Creating a new one...'; $objNetwork = new Network; $objValues = new Values; $objValues->train(); call_user_func_array(array($objValues, 'input'), $data); $objValues->output(1); $objValues->saveToFile('values_xor.dat'); unset($objValues);}try{ $objValues = Values::loadFromFile('values_xor.dat');}catch(Exception $e){ die('Loading of values failed');}$objNetwork->setValues($objValues); // to be called as of version 2.0.6$boolTrained = $objNetwork->train();print ($boolTrained) ? 'Network trained' : 'Network not trained completely. Please re-run the script';$objNetwork->saveToFile('xor.dat');$objNetwork->printNetwork();
如果我需要使用神经网络检查数据,我可以这样做:
<?phprequire_once 'ANN/Loader.php';$data = $_POST['data'];$data = array_map('floatval', $data);use ANN\Network;use ANN\Values;try{ $objNetwork = Network::loadFromFile('xor.dat');}catch(Exception $e){ die('Network not found');}try{ $objValues = Values::loadFromFile('values_xor.dat');}catch(Exception $e){ die('Loading of values failed');}call_user_func_array(array($objValues, 'input'), $data);$objNetwork->setValues($objValues);print_r($objNetwork->getOutputs());
然而,我最终想要的是,如果神经网络识别到一个手势,它会用这些数据进行训练。这样,它会随着时间的推移变得更加准确。我已经为此绞尽脑汁好几天了,但毫无进展。
回答:
观察
大多数经典的ANN架构遵循以下程序:
- 操作两种模式:训练和映射
在训练后,权重(因此网络的记忆)是固定的。
有一些模型试图向现有数据集添加新知识。可以看看自适应共振理论(ART)神经网络。然而,它们不一定能同化新知识。它们可能会添加一个新的输出或一组神经元来分类新项目。
用于模式识别的常用ANN是前馈网络/多层感知器,通过反向传播(BP)进行训练。你的问题似乎属于这一类。
我查看了你的链接,似乎它使用的是“多层感知器”,所以你可能被限制在这个架构上。
问题
你的问题是,如果你的网络已经在(N)个模式上训练并产生了(O)个输出,当它遇到一个新模式(p)时。它将(P)分类为属于产生输出(o)的相同模式(n)或模式组(ns)。
我不知道你的训练数据是添加一个训练模式=一个输出,还是几个训练模式=一个输出。
解决方案
蛮力方法是将(p)添加到你的训练数据中,然后完全重新训练你的网络。
还有其他选项。
BP遵循梯度下降,所以在每个训练周期结束时,你会得到一个错误。BP通常在错误低于选择的水平error_t时停止(见末尾的注释)。这不是一个很好的方法,会导致猜测和过度/不足训练。假设它实际上达到了目标水平,而不是陷入局部最小值。
最初你的错误会很高,当它接近你的error_t时,你可以保存一份权重的副本。这些代表你的网络处于部分训练状态(error_p)。
当你想要引入一个模式(p)时,你可以用这些部分训练的权重重新开始训练,而不是使用初始或新的随机权重。错误应该从(error_p)开始上升,然后开始下降。当它再次达到error_p时,保存新的部分训练权重。让它完成训练,然后重新投入使用。
另一种方法是(1)当你想要包含(p)时。仅使用(p)或你想要添加(p)的训练模式组重新训练你的网络。这将改变你所有其他模式-输出对的识别。
请注意,你的训练网络最初接受了新模式p,并且对它的错误足够低,以至于它说“我认识你”。这意味着当你将训练权重和p呈现给你的训练算法时,它可能已经低于你的目标错误,你只会得到1个训练周期。
所以我建议只进行(1)中提到的1个训练周期。然后在所有你的训练数据+p上进行测试。如果错误低于error_t,则认为它已训练,如果没有,则让它继续运行直到再次降到error_t。
末尾的注释
在任意错误处停止BP是训练的基本方法。这样做可能会导致网络训练不足,以至于它无法识别你想要的,或者“过度拟合”,以至于它只识别你的训练模式而拒绝你的现实世界模式。
另一种方法是拥有一个训练模式集和一个验证集。你用训练数据训练网络,但不将错误作为停止标志。相反,在每个训练周期之后,你向网络展示验证模式,如果它识别它们,你就停止训练。这是你的验证错误_v。
情况变得更糟。
假设你有N个训练模式。在每个训练周期开始时,你向网络展示模式[1]。网络产生一个错误(期望输出 – 实际输出),你将这个错误反向传播到网络中,这意味着下次它看到模式[1]时,错误应该更低。这里它所做的是稍微修改权重。
现在你对模式[2]做同样的事情,依此类推,直到模式[N]。
每次网络为模式[n]调整其权重时,它都会影响对之前模式[1到n-1]的识别。所以当你到达模式[N]时,之前的学习可能已经受到了很多损害。理论上,对模式[1]的学习应该受到了最严重的损害,但实际上这取决于模式之间的共享相似性以及模式变量与输出变量的数学关系。
我告诉你这些是因为如果你要向一个训练过的网络展示一个新模式,你就是在进行这种操作的一部分。
你可以通过在每个训练周期中以随机顺序(或分步顺序)展示你的训练模式来修复/缓解这个问题,这样模式[1]不总是先被看到,模式[N]不总是最后被看到。