美文网首页一些需要知道的概念
用代码来模拟“神经元”和“条件反射”

用代码来模拟“神经元”和“条件反射”

作者: JiaYe | 来源:发表于2018-02-08 18:32 被阅读0次

    参考巴甫洛夫的经典条件反射。
    在给狗狗喂食时,狗狗嘴里产生唾液。如果在喂食的同时摇响铃铛,并经过多次训练,就会形成条件反射,不喂食摇响铃铛也会产生唾液。下面用一段简单的代码——“神经元”,来模拟一下条件反射过程。
    神经元由树突、细胞、轴突组成,研究发现,相连接神经在同步放电后突触连接增强。我们通过修改树突的权重,来模拟连接增强:
    狗吃东西流口水,属于先天非条件反射。狗听到铃铛流口水,属于后天训练的条件反射。假设有一个神经元,A树突连接到食物,B树突连接到铃铛。那么A树突的权重默认为1.0,代表非条件反射,树突有输入的时候就会激活唾液。B树突默认权重0.0,代表条件反射,树突有输入时不会激活唾液。我们就在两个树突同时有输入时,将其中较低的权重不断增加,来模拟训练过程。

    struct Neuron<T:Axon>{
        dendrite_wieghts: Vec<f32>,
        dendrite_values: Vec<f32>,
        axon: T
    }
    

    以上代码是一个神经元的结构体,其中,dendrite_wieghts是神经元树突,dendrite_values是神经元的树突的输入值。axon是个接口,用来接收神经元输出。

    impl <T:Axon> Neuron<T>{
        fn set_dendrites(&mut self, values: &[f32]){
            self.dendrite_values.copy_from_slice(values);
            self.execute();
        }
    
        fn execute(&mut self){
            let mut total = 0.0;
            let mut max_weight = 0.0;
            //加权求和
            for d in 0..self.dendrite_wieghts.len(){
                total += self.dendrite_values[d]*self.dendrite_wieghts[d];
                if self.dendrite_wieghts[d]>max_weight{
                    max_weight = self.dendrite_wieghts[d];
                }
            }
    
            //调整权重: 如果有N个树突都有输入,那么调整他们的权重,直到同一水平
            for d in 0..self.dendrite_wieghts.len(){
                if self.dendrite_values[d]!=0.0 && self.dendrite_wieghts[d]<max_weight && self.dendrite_wieghts[d]<1.0{
                    self.dendrite_wieghts[d] += 0.1;
                }
            }
            self.axon.output(total);
        }
    }
    

    神经元有两个方法,set_dendrites用来设置所有突触接收到的值。execute方法用来求所有突触的加权和,此方法会在set_dendrites调用之后自动触发,然后通知轴突(axon)回调,这相当于动物神经元树突受到刺激后激活轴突。

    //轴突
    trait Axon{
        fn output(&self, o:f32);
    }
    //实现一个监听是否有唾液的接口
    struct SalivaAxon{}
    impl Axon for SalivaAxon{
        fn output(&self, output:f32){
            //println!("output:{}", output);
            if output >= 1.0{
                println!("有唾液!");
            }else{
                println!("无唾液!!");
            }
        }
    }
    

    以上代码是接口回调。
    下面的main函数开始模拟条件反射:

    fn main() {
        let mut neuron = Neuron{
            //两个突触 连接到食物(舌头)的权重1.0 连接到铃铛(耳朵)的权重0.0
            dendrite_wieghts: vec![1.0, 0.0], 
            dendrite_values: vec![0.0, 0.0],
            axon: SalivaAxon{}
        };
    
        neuron.set_dendrites(&[1.0, 0.0]); //第一次: 吃+不响铃->有唾液
        neuron.set_dendrites(&[1.0, 1.0]); //第二次: 吃+响铃->有唾液
        neuron.set_dendrites(&[0.0, 1.0]); //第三次: 不吃+响铃->无唾液
        //再训练9次就学会条件反射
        for _ in 0..9{
            neuron.set_dendrites(&[1.0, 1.0]);
        }
        //测试训练好的条件反射
        neuron.set_dendrites(&[0.0, 1.0]);  // 不吃+响铃 ***有唾液***
    }
    

    运行结果输出如下:
    有唾液!
    有唾液!
    无唾液!!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!
    有唾液!

    可以发现,经过训练以后,最后一次只输入铃铛,仍然会激发唾液。

    当然大脑的思维和记忆是由千万亿的神经细胞呈现的,这里只是一段有趣的代码来模仿一下。如果将更多的神经元链接到一起,会有什么神奇的结果吗?
    待续。。。

    (原创文章)
    2018年2月8日 上海
    planet2@qq.com

    相关文章

      网友评论

        本文标题:用代码来模拟“神经元”和“条件反射”

        本文链接:https://www.haomeiwen.com/subject/pzgttftx.html