2022.10.12,今天没打游戏

import numpy

import funcSet


def get_d_loss_o(errOut, corOut):
    return (errOut - corOut) / len(errOut[0])


def getCost(errOut, corOut):
    return numpy.sum(1 / 2 * (errOut - corOut) ** 2) / len(errOut) / len(errOut[0])


class NeuralLine:
    def __init__(self, inputLen, hiddenLen, activeFunc, studyRate):
        self.matrix = numpy.random.rand(inputLen, hiddenLen)
        self.outputs = None
        self.bias = numpy.zeros((1, hiddenLen))
        self.activeFunc = activeFunc
        self.studyRate = studyRate
        self.next = None
        self.pre = None
        self.d_loss_h = None
        # 以下用于实现adam优化算法
        self.vDw = numpy.zeros((inputLen, hiddenLen))
        self.sDw = numpy.zeros((inputLen, hiddenLen))
        self.vDb = numpy.zeros((1, hiddenLen))
        self.sDb = numpy.zeros((1, hiddenLen))

    def input(self, inputs):
        self.outputs = numpy.dot(inputs, self.matrix)
        self.outputs += self.bias
        self.outputs = self.activeFunc.func(self.outputs)

    def adamUpdate(self, inputs, step):
        db = numpy.sum(self.d_loss_h, axis=0, keepdims=True)
        self.vDb = 0.9 * self.vDb + 0.1 * db
        self.sDb = 0.9 * self.sDb + 0.1 * db ** 2

        cor = 1 / numpy.sqrt(1 - 0.9 ** step)

        self.bias -= self.studyRate * cor * self.vDb / numpy.sqrt(self.sDb + 1e-10)

        # 这里比较烦,不过相乘后矩阵行列数对了,正好就对了
        dw = numpy.dot(inputs.T, self.d_loss_h)

        self.vDw = 0.9 * self.vDw + 0.1 * dw
        self.sDw = 0.9 * self.sDw + 0.1 * dw ** 2

        self.matrix -= self.studyRate * cor * self.vDw / numpy.sqrt(self.sDw + 1e-10)

    def update(self, inputs, step, optimize='adam'):
        if optimize == 'adam':
            return self.adamUpdate(inputs, step)
        db = numpy.sum(self.d_loss_h, axis=0, keepdims=True)

        self.bias -= self.studyRate * db

        # 这里比较烦,不过相乘后矩阵行列数对了,正好就对了
        dw = numpy.dot(inputs.T, self.d_loss_h)

        self.matrix -= self.studyRate * dw

    def backpropagation(self, d_loss_ho):
        d_ho_h = self.activeFunc.derivativeFunc(self.outputs)

        self.d_loss_h = d_loss_ho * d_ho_h

        # 这里也很烦,不过相乘后矩阵行列数对了,正好就对了
        # 我的妈,两种return都可以训练出结果!!!!而且效果差不多!!!
        return numpy.dot(self.d_loss_h, self.matrix.T)
        # return numpy.dot(d_loss_ho, self.matrix.T)


class NeuralNet:
    def __init__(self, inputLen, neuralLenArray, funcArray, studyRateArray):
        self.netHead = NeuralLine(inputLen, neuralLenArray[0], funcArray[0], studyRateArray[0])
        self.netEnd = self.netHead
        self.step = 0
        for i in range(1, len(neuralLenArray)):
            self.netEnd.next = NeuralLine(neuralLenArray[i - 1], neuralLenArray[i], funcArray[i], studyRateArray[i])
            self.netEnd.next.pre = self.netEnd
            self.netEnd = self.netEnd.next

    def input(self, inputs):
        temp = self.netHead
        temp.input(inputs)
        temp = temp.next
        while temp is not None:
            temp.input(temp.pre.outputs)
            temp = temp.next

    def updateStudyRate(self, rate):
        temp = self.netHead
        while temp is not None:
            temp.studyRate *= rate
            temp = temp.next

    def train(self, inputs, outputs):
        oldCost = 0
        while self.step < 10000:
            self.step += 1
            self.setTrain(inputs, outputs)
            cost = getCost(self.netEnd.outputs, outputs)
            if cost < 1e-10:
                break
            if 0 < oldCost < cost:
                # 说明神经网络结构不对,学习速度不对,激活函数不对
                self.updateStudyRate(0.8)
                print('oldCost < cost!!!', oldCost, ': ', cost, '  step: ', self.step, '  studyRate: ', self.netHead.studyRate)
                # break
            oldCost = cost
        print('self.step = %d, cost = ' % self.step + str(cost))

    def setTrain(self, inputs, outputs):
        self.input(inputs)
        d_loss_o = get_d_loss_o(self.netEnd.outputs, outputs)
        temp = self.netEnd
        d_loss_o = temp.backpropagation(d_loss_o)
        temp = temp.pre
        while temp is not None:
            d_loss_o = temp.backpropagation(d_loss_o)
            temp = temp.pre
        temp = self.netHead
        temp.update(inputs, self.step)
        temp = temp.next
        while temp is not None:
            temp.update(temp.pre.outputs, self.step)
            temp = temp.next

    def test(self, inputs):
        self.input(inputs)
        print(self.netEnd.outputs)


def test():
    inputs = numpy.array([[0, 1], [1, 0], [0, 0], [1, 1], [0, 2], [2, 0], [-2, -2], [2, 2]])
    outputs = numpy.array([[1], [1], [0], [0], [1], [1], [0], [0]])
    neuralLenArray = [4, len(outputs[0])]
    funcArray = [funcSet.tanhSet, funcSet.straightSet]
    studyRateArray = [0.2, 0.1]
    nnet = NeuralNet(len(inputs[0]), neuralLenArray, funcArray, studyRateArray)
    print(nnet.netHead.matrix)
    nnet.train(inputs, outputs)
    print(nnet.netHead.matrix)
    print(nnet.netEnd.outputs)


# tanh是记忆随机数映射关系之神,可能是因为输入和输出都在-1到1之间
# tanh表现比sigmoid好4倍

# 通过计算得知,学习速率要和inputs范围成反比,和outputs范围没啥关系!!!

# 我认为我很少有机会看这些注释,它们越来越多了,所以我还是记在脑子里吧。。。?
# 学习速度,激活函数,应当是每一个神经元自己学习还是每一层神经元自己学习??
# 反向传播可以认为是激励,改变某个参数使得误差减小,就像从不同角度思考问题一样?调用不同参数就像猜测,找规律。。
# dropout,训练时,对于节点数多的层,随机去除某个节点(输出乘以0),包括输入,就像看到猫的一部分,听到一个音调,我们就大概判断出是哪只猫??
# dropout是防止过拟合的手段,即防止过分学习少数特例
# 归一化输入?对于不同分辨率的图片归一化为相同分辨率,对于1000到1001之间的输入线性转化为-1到1之间的输入,同理对每一层的输出都归一化?
# 指数爆炸是否说明爆炸是指数形式的化学反应,
# 将每层权重控制在1/n附近,因为input在(-1,1),这样input*matrix得到的output也在(-1,1),也取决于activeFunc(output)
# x -= 1/m * sum(x), e2 = 1/m * sum(x^2), x /= e2. 记住1/m*sum(x) 和 e2,对output作同样处理

# momentum算法,或称为指数加权平均算法
# 每次更新权值的偏导数d_cost_w = 0.9 * pre_d_cost_w + 0.1 * cur_d_cost_w,只需要记住上一次偏导数即可
# 当然最开始没有上一次的偏导数,可以最开始的1次让d_cost_w = cur_d_cost_w,或者也没必要,因为迭代10次以后,最开始的偏导数已经不重要,
# 对于动辄更新上千次,上万次的bp算法来说,没区别,这样做的好处是防止更新过头,平均更新方向,
# 比如一次朝东北,一次朝东南,平均后,朝北和朝南的部分被平均了,假如之前10次的平均偏导数和这次的差不多,则这个平均算法相当于没影响

# 只有激活函数和潜在规律同级别才能通过实数集上的测试,比如指数模拟指数,平方模拟平方,如果激活函数不对,无论如何训练只是记住训练集范围内的映射关系
# 这时就要尝试新的激活函数。。
# 学习速率衰减,随着接近目标矩阵,过大的学习速度会使成果在目标附近摆动,而开始时较为远离,稍大的学习速度可以快速接近目标

# 初始参数就像我们对事物的偏见,尝试不同的初始参数,比较优劣,留优去劣,就像别人和你说一个人怎么样,一件事怎么样,顺着别人的思路是否能得到更好的结果??

if __name__ == '__main__':
    test()

# 一个重要的事情是,让程序尝试不同的超参数,尤其是激活函数的选择,甚至激活函数本身也可以用训练好的神经网络,
# 当然最好是线性函数,矩阵乘法可以模拟线性函数,已经证实,激活函数是二次函数,则一定可以模拟二次函数??
# 其实多层神经网络就是把神经网络当作激活函数,第4层把第3层当作第二层的输出的激活函数
# 我们做数学题时,也需要训练,然后记忆特征,下次遇到同类型题目则调用训练好的神经网络作为激活函数。。。
# 多会一种题型,或多会一个激活函数是不是代表更聪明一点?
# 参数太多,必须让神经网络自己调整自己的参数,

# 人找规律都是线性的,人对看起来非线性的数据很反感
# 找规律本质是找某个抽象层的线性关系
# 抽象是个固定的,偏见的算法,因为人讨厌随机的算法,经过迭代,在某一层,数据呈现线性关系,则认为找到规律了
# 对特定的数据模式只有几个待选的偏见算法,如果确定数据是有规律的,但已有的算法无法找到规律,可以认为这个数据就是一种规律?
# 而所谓线性又是什么?是我们倒背如流的一二三四五吗,我想一二三四五也不是天生的,也是学习来的规律吧?因为经常出现
# 人脑本身也自然随机进化而来,随机尝试的算法如果表现更优秀则可以留存下来,否则淘汰,就像模拟生命的起源和发展。。那有点慢
# 但最终,一定比现在的人类的思维方法更好,因为没有理由随机到完美的思维方法吧?即使是人也有笨的,或对某些问题笨。。
# 现在想来,超脑的科幻电影非常真实。。。几十年前就已经想到这个问题了,那么超脑有可能灭绝人类吗?如果从更广意义考虑灭绝和不灭绝没什么区别
# 所以应当给超脑一个欲望,即帮助人类进化和发展,进化是不是算是灭绝人类呢??好像人类和几亿年前的鱼完全不是同一个物种了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值