写一个会学习的神经元
介绍
周末看了个视频,说是人的神经元怎么怎么传脉冲就能进行思考,我不知道这是真的还是假的,但听起来有些道理。这让我想到了之前很火的人工智能,突然觉得理解了点什么,于是就弄了段看起来能学习的代码。
这段程序的功能很简单,就是模仿一个拥有四个「树突」中的神经元,它会对「树突」上的各个输入进行抑制或放大,然后合起来得到一个值,如果合起来的值大于某个阈值,它的「突触」就输出1(激活),否则输出0(继续睡觉)。
它的样子大概如此,是不是很像(抽象)一个神经元?
我们思路是这样的:
-
先用代码实现这个神经元
-
然后呢,就开始给这个神经元一些学习资料,当它学习得足够刻苦后,就会变得聪明起来,成为一个Smart Boy,也就是SB~。 为了简单起见,学习资料就是4个0/1构成的列表,例如(1,0,1,0),答案就是1或0。
-
接着,我们就开始对它进行一些测试,看它是不是真的学会了。也就是给它一些(1, 0, 1, 0)看它能不能按学习资料中的规律给出0或1的答案。
实现
首先是实现神经元,我们使用四个参数Wi来表现树突对上面输入的抑制或放大作用。这几个参数分别作用在input的各个分量上
class SmartBoy:
def __init__(self):
self.w1 = 1
self.w2 = 1
self.w3 = 1
self.w4 = 1
def brain(self, input):
r = self.w1*input[0] + self.w2*input[1] + self.w3*input[2] + self.w4*input[3]
if r > 0.5:
return 1
else:
return 0
按现在这样,这个神经元只会把四个输入全部加起来,然后看是不是大于0.5,决定是激活(1)或是继续睡觉(0)。这不够智能,我们还需要它能学习文化知识,改变自己的认知。
于是加入这样一串规则,就是给个exercise自己想,然后看答案,偏大就随机把各个W缩小,不然就放大。这样学一阵子之后,它对各个树突的态度就变化了,神经元也就成长了,它懂得了应该接受哪个树突,又该拒绝哪个。
def learn(self, exer, key):
ans = self.brain(exer)
if ans == key:
return
else:
if ans > key:
self.w1 = self.w1 * random.random()
self.w2 = self.w2 * random.random()
self.w3 = self.w3 * random.random()
self.w4 = self.w4 * random.random()
else:
self.w1 = self.w1 * random.random() + 1
self.w2 = self.w2 * random.random() + 1
self.w3 = self.w3 * random.random() + 1
self.w4 = self.w4 * random.random() + 1
现在,我们需要准备一本好的教材,一本告诉神经元exer开头是1,就应该输出1的教材
book = [
[(1,1,0,0), 1],
[(1,1,0,1), 1],
[(1,0,1,0), 1],
[(0,0,1,1), 0],
[(1,0,1,1), 1],
[(1,1,0,1), 1],
[(1,1,1,1), 1],
[(0,1,1,1), 0],
[(1,1,1,0), 1],
[(0,1,1,0), 0],
[(1,1,0,1), 1],
[(1,0,1,1), 1],
]
现在我们召唤一个神经元sb,让它开始学习我们的教材300遍,读书三百遍,其义自现。
sb = SmartBoy()
for i in range(300):
for exer, key in book:
sb.learn(exer, key)
接着我们出一套试题
tests = [
(1,0,1,1),
(1,1,1,1),
(0,0,1,1),
(1,0,1,0),
(1,0,0,0),
(1,1,0,0),
(1,1,1,0),
(0,0,1,0),
(0,0,0,0),
(1,1,0,1),
]
考试开始
for test in tests:
ans = sb.brain(test)
print(test, ans)
print(f"brain is {sb.w1} {sb.w2} {sb.w3} {sb.w4}")
那么,它给出的答案是什么呢?(exer开头是1,就应该输出1)
(1, 0, 1, 1) 1
(1, 1, 1, 1) 1
(0, 0, 1, 1) 0
(1, 0, 1, 0) 1
(1, 0, 0, 0) 1
(1, 1, 0, 0) 1
(1, 1, 1, 0) 1
(0, 0, 1, 0) 0
(0, 0, 0, 0) 0
(1, 1, 0, 1) 1
brain is 0.6200796171156872 0.11142487074770839 0.17477170033243886 0.002014989461413244
没错,全对了
换本教材
既然说了这个神经元可以学习,那么我们给它换本教材再学300遍,应该就能学会新的东西了。那到底是不是呢,我们试试看。
现在给出一本新书,表达的规律是,中间是两个1就给出1
book = [
[(1,1,0,0), 0],
[(1,1,0,1), 0],
[(1,0,1,0), 0],
[(0,0,1,1), 0],
[(1,0,1,1), 0],
[(1,1,0,1), 0],
[(1,1,1,1), 1],
[(0,1,1,1), 1],
[(1,1,1,0), 1],
[(0,1,1,0), 1],
[(1,1,0,1), 0],
[(1,0,1,1), 0],
]
依然学习300遍,然后用之前的试题来测测看,它给的答案如下
(1, 0, 1, 1) 0
(1, 1, 1, 1) 1
(0, 0, 1, 1) 0
(1, 0, 1, 0) 0
(1, 0, 0, 0) 0
(1, 1, 0, 0) 0
(1, 1, 1, 0) 1
(0, 0, 1, 0) 0
(0, 0, 0, 0) 0
(1, 1, 0, 1) 0
brain is 0.08391736481954896 0.211282837293934 0.31411813879982625 0.033044625275163504
没错,它学会了!
再换一本
这次我们的教材是,末尾的1就输出1
book = [
[(1,1,0,0), 0],
[(1,1,0,1), 1],
[(1,0,1,0), 0],
[(0,0,1,1), 1],
[(1,0,1,1), 1],
[(1,1,0,1), 1],
[(1,1,1,1), 1],
[(0,1,1,1), 1],
[(1,1,1,0), 0],
[(0,1,1,0), 0],
[(1,1,0,1), 1],
[(1,0,1,1), 1],
]
测试结果如下
(1, 0, 1, 1) 1
(1, 1, 1, 1) 1
(0, 0, 1, 1) 1
(1, 0, 1, 0) 0
(1, 0, 0, 0) 0
(1, 1, 0, 0) 0
(1, 1, 1, 0) 0
(0, 0, 1, 0) 0
(0, 0, 0, 0) 0
(1, 1, 0, 1) 1
brain is 0.05803250548287294 0.030302330140830957 0.09168660880948953 0.5004478665614163
没错!sb它又学会了!
它很行吗
从上面可以看出,只要我们给它一本新的教材,然后学个300遍,它就能掌握其中的规律,并顺利通过测试。
但是,当教材不够好时,它还是学不会的。例如,教材给出的例子太少,或者,教程给出的例子不够典型,它的学习效果就会很差。 教材真的很重要。
或者,需要学习的规律太复杂时,它也是学不会的,毕竟,它太简单了,也就四个树突。
当然,由于我们使用的是随机数,所以有时候即使学习300遍,也还是学不会,这时就可以重造了。
如果我们实现更多的神经元,那这一堆神经元应该能实现更复杂的功能。
完整的代码
import random
class SmartBoy:
def __init__(self):
self.w1 = 1
self.w2 = 1
self.w3 = 1
self.w4 = 1
def brain(self, input):
r = self.w1*input[0] + self.w2*input[1] + self.w3*input[2] + self.w4*input[3]
if r > 0.5:
return 1
else:
return 0
def learn(self, exer, key):
ans = self.brain(exer)
if ans == key:
return
else:
if ans > key:
self.w1 = self.w1 * random.random()
self.w2 = self.w2 * random.random()
self.w3 = self.w3 * random.random()
self.w4 = self.w4 * random.random()
else:
self.w1 = self.w1 * random.random() + 1
self.w2 = self.w2 * random.random() + 1
self.w3 = self.w3 * random.random() + 1
self.w4 = self.w4 * random.random() + 1
if __name__=="__main__":
book = [
[(1,1,0,0), 0],
[(1,1,0,1), 1],
[(1,0,1,0), 0],
[(0,0,1,1), 1],
[(1,0,1,1), 1],
[(1,1,0,1), 1],
[(1,1,1,1), 1],
[(0,1,1,1), 1],
[(1,1,1,0), 0],
[(0,1,1,0), 0],
[(1,1,0,1), 1],
[(1,0,1,1), 1],
]
tests = [
(1,0,1,1),
(1,1,1,1),
(0,0,1,1),
(1,0,1,0),
(1,0,0,0),
(1,1,0,0),
(1,1,1,0),
(0,0,1,0),
(0,0,0,0),
(1,1,0,1),
]
sb = SmartBoy()
for i in range(300):
for exer, key in book:
sb.learn(exer, key)
for test in tests:
ans = sb.brain(test)
print(test, ans)
print(f"brain is {sb.w1} {sb.w2} {sb.w3} {sb.w4}")