深度学习:手写反向传播网络拟合sinx,可设置网络层数

一、全局方法:

  1. rand(a,b):该方法返回在区间(a,b)的任意随机数,且保证每次调用的时候返回的都是与之前不同的随机数
  2. generate_w(m,n):该方法返回生成的m*n的weight矩阵,且通过在该方法中调用rand(a,b)来初始化每个weight的值
  3. generate_b(m):该方法返回生成的m长度的bias值,且通过在该方法中调用rand(a,b)来初始化每个bias的值
  4. fit_function(x,deriv=False):该方法返回拟合函数,如果该方法传入的deriv是True,则返回拟合函数的导数。我试验了两种拟合函数,一种是sigmoid。另一种是tanh函数,在实验数据来看,tanh拟合效果比较好,而sigmoid由于只能输出0-1的正数,只能拟合0-π的一部分,且拟合效果不是很好。

     

random.seed(0)
def rand(a, b):
    return (b-a) * random.random() + a

def generate_w(m, n):
    w = [0.0] *m
    for i in range(m):
        w[i] = [0.0]*n
        for j in range(n):
            w[i][j] =rand(-0.69,1)#rand(-1,1) #
    return w

def generate_b(m):
    b = [0.0]*m
    for i in range(m):
        b[i] =rand(-2.409,0.02)# rand(-1,1)#
    return b

def fit_function(x,deriv=False):
    if deriv==True:
        #return x*(1-x)
        return 1-np.tanh(x) * np.tanh(x) #tanh鍑芥暟鐨勫鏁?
    return np.tanh(x)
    #return 1/(1+np.exp(-x))

二、 定义了BPNetwork类,其内部函数方法说明如下:

  1. __init__(self):定义类中所需要的数据,类中所需要维持的参数名称在此函数中事先定义。这些数据包括:

⑴ self.input_n = 0:表示输入层的神经元个数,拟合sinx需要self.input_n = 2,一个是输入的数据,另一个用来调节bias

⑵ self.input_cells = []:表示输入层的神经元输入的数据,有两个元素,一个是输入的数据;另一个用来调节bias,默认为1

   ⑶ self.output_n = 0:输出层的神经元个数

   ⑷ self.output_cells = []:输出层的神经元的输出值

   ⑸ self.input_w = []:输入层到第一层隐藏层的weight

   ⑹ self.output_w = []:最后一层隐藏层到输出层的weight

   ⑺ self.hidden_ns = []:隐藏层的设置,它的长度是指隐藏层个数,它的每个元素指该层隐藏层的神经元个数

   ⑻ self.hidden_ws = []:隐藏层的weights,其中的每个元素为上一层隐藏层到下一层隐藏层的weight,一共有n-1个weight

   ⑼ self.hidden_bs = []:其中的每个元素self.hidden_bs[i]都是第i层隐藏层的bias设置,其长度为隐藏层的个数

   ⑽ self.output_b = []:输出层的bias

   ⑾ self.hidden_results = []:其中的每个元素是每一层隐藏层的输出值

   ⑿ self.output_deltas = []:指输出层的∂Error/(output_w)

   ⒀ self.hidden_deltases = []:其中的每个元素self.hidden_deltases[i] 指从第i层出发的∂Error/(weight),该weight指从第i层到第i+1层的weight

2. setup(self, input_n, output_n, hidden_set): 初始化类中所需参数,输入的参数中,

input_n是定义输入的参数个数,但并不等于输入层神经元个数,self.input_n等于输入的参数input_n+1,原因是需要新增一个神经元用来调节bias,且这个神经元的输入值记为1,这样就可以通过用output_deltas来调节input_b了

output_n是输出层个数

hidden_set是一个list,里面的每个元素是隐藏层的神经元个数,如[10,10]表示有两层隐藏层,两层隐藏层都有11个神经元,+1的原因同input_cells中增加一个神经元的作用是一样的,是为了调节该隐藏层的bias

通过这些信息就可以初始化类中所需要的数据了。即在__init__方法中的那些数据.

需要注意的是在初始化weight的时候使用generate_w方法形成一个由随机数的矩阵,初始化bias的时候使用generate_b形成一个由随机数组成的一维数组

 def __init__(self):
        self.input_n = 0
        self.input_cells = []
        self.output_n = 0
        self.output_cells = []
        self.input_w = []
        self.output_w = []
        self.hidden_ns = []
        self.hidden_ws = []
        self.hidden_bs = []
        self.output_b = []
        self.hidden_results = []
        self.output_deltas = []
        self.hidden_deltases = []

    def setup(self, input_n, output_n, hidden_set):
        #初始化各种参数
        self.input_n = input_n +1
        self.output_n = output_n
        self.hidden_ns = [0.0]*len(hidden_set)
        for i in range(len(hidden_set)):
            self.hidden_ns[i] = hidden_set[i]+1

        self.input_cells = [1.0]*self.input_n
        self.output_cells = [1.0]*self.output_n
        #初始化weights和bias
        self.input_w = generate_w(self.input_n, self.hidden_ns[0])
        self.hidden_ws = [0.0]*(len(self.hidden_ns)-1)
        for i in range(len(self.hidden_ns)-1):
            self.hidden_ws[i] = generate_w(self.hidden_ns[i],self.hidden_ns[i+1])
        self.output_w = generate_w(self.hidden_ns[len(self.hidden_ns)-1], self.output_n)
        self.output_b = generate_b(self.output_n)
        self.hidden_bs = [0.0]*len(self.hidden_ns)
        for i in range(len(self.hidden_ns)):
            self.hidden_bs[i] = generate_b(self.hidden_ns[i])
        self.hidden_results = [0.0]*(len(self.hidden_ns))

3. forward_propagate(self, input):向前传播。

⑴ 将输入的input作为前n-1个输入层神经元的输入值,第n个输入层神经元设为1,然后进行向前传播

⑵ 传播分为三个部分,输入层到隐藏层第一层,在隐藏层之中,然后从最后一层隐藏层到输出层。 传播公式为:

 Output[h]=fit_function((Σi=0输入层神经元个数weight[i][h]*input[i])+bias[h])

   传播的思路就是:前一层的输入的值乘以前一层到后一层的weight,然后得到积的加和,再用这个加和加上下一层的对应的bias,得到后一层的输出。

def forward_propagate(self, input):
        for i in range(len(input)):
            self.input_cells[i] = input[i]
        #输入层
        self.hidden_results[0] = [0.0]* self.hidden_ns[0]
        for h in range(self.hidden_ns[0]):
            total = 0.0
            for i in range(self.input_n):
                total += self.input_w[i][h] * self.input_cells[i]
            self.hidden_results[0][h] = fit_function(total+self.hidden_bs[0][h])
        #隐藏层
        for k in range (len(self.hidden_ns)-1):
            self.hidden_results[k+1] = [0.0]*self.hidden_ns[k+1]
            for h in range(self.hidden_ns[k+1]):
                total = 0.0
                for i in range(self.hidden_ns[k]):
                    total += self.hidden_ws[k][i][h] * self.hidden_results[k][i]
                self.hidden_results[k+1][h] = fit_function(total + self.hidden_bs[k+1][h])
        #输出层
        for h in range(self.output_n):
            total = 0.0
            for i in range(self.hidden_ns[len(self.hidden_ns)-1]):
                total += self.output_w[i][h] * self.hidden_results[len(self.hidden_ns)-1][i]
            self.output_cells[h] = fit_function(total + self.output_b[h])

        return self.output_cells[:]

4. get_deltas(self, label):该函数是得到self.output_deltas和self.hidden_deltases的函数。

self.output_deltas = Error/(output_w):指输出层的deltas公式为

 output_deltas[o]=fit_function(output_cell[o])*(label[o]-output_cells[o])

self.hidden_deltases = Error/(weight) weight是指hidden_ws中的元素。

hidden_deltases[k][o]=fit_function_deriv(hidden_result[k][o])*(deltas[i]*weight[o][i]

这里的deltas是指的上一层神经元的deltas

 def get_deltas(self, label):
        self.output_deltas = [0.0] * self.output_n
        #输出层 deltas
        for o in range(self.output_n):
            error = label[o] - self.output_cells[o]
            self.output_deltas[o] = fit_function(self.output_cells[o],True) * error
        #隐藏层deltas
        tmp_deltas = self.output_deltas
        tmp_w = self.output_w
        self.hidden_deltases = [0.0]*(len(self.hidden_ns))
        k = len(self.hidden_ns) - 1
        while k >= 0:
            self.hidden_deltases[k] = [0.0] * (self.hidden_ns[k])
            for o in range(self.hidden_ns[k]):
                error = 0.0
                for i in range(len(tmp_deltas)):
                    error += tmp_deltas[i] * tmp_w[o][i]
                self.hidden_deltases[k][o] = fit_function(self.hidden_results[k][o],True) * error
            k = k - 1
            if k>=0:
                tmp_w = self.hidden_ws[k]
                tmp_deltas = self.hidden_deltases[k+1]
            else:
                break

5. renew_w(self,learn): 更新weight的函数,仍然分成三个部分,先更新最后一层隐藏层到输出层的权重,再是隐藏层之间的权重,然后再更新第一层隐藏层到输入层的权重。更新weight的公式为:

Weight[i][o] += deltas[o]*input[i]*learn,其中的o是输出层神经元的index,i是输入层的神经元的index,input是指输入层的输入,learn是学习率。

 def renew_w(self, learn):
        #更新隐藏层→输出层的权重
        k = len(self.hidden_ns)-1
        for i in range(self.hidden_ns[k]):
            for o in range(self.output_n):
                change = self.output_deltas[o] * self.hidden_results[k][i]
                self.output_w[i][o] += change * learn

        #更新隐藏层的权重
        while k > 0 :
            for i in range(self.hidden_ns[k-1]):
                for o in range(self.hidden_ns[k]):
                    change = self.hidden_deltases[k][o] * self.hidden_results[k-1][i]
                    self.hidden_ws[k-1][i][o] += change * learn
            k = k - 1

         #更新输入层→隐藏层权重
        for i in range(self.input_n):
            for o in range(self.hidden_ns[0]):
                change = self.hidden_deltases[0][o] * self.input_cells[i]
                self.input_w[i][o] += change * learn

6. renew_b(self,learn): 更新bias的函数,分成两个部分,第一部分是隐藏层的bias,第二部分是输出层的bias。更新bias的公式为:

bias[i]+= deltas[i]*learn

 def renew_b(self,learn):
        #更新隐藏层bias
        k = len(self.hidden_bs)-1
        while k>=0:
            for i in range(self.hidden_ns[k]):
                self.hidden_bs[k][i] = self.hidden_bs[k][i] + learn * self.hidden_deltases[k][i]
            k = k - 1
        #更新输出层bias
        for o in range(self.output_n):
            self.output_b[o] += self.output_deltas[o] * learn

7. back_propagate(self, input, label, learn):先进行前向传播,再进行反向传播,然后获取deltas,更新weight和bias,之后再计算此次正向传播得到的损失值,并返回。这个函数的每一行都在调用其他的函数,是一次完整的反向传播。

 def back_propagate(self, input, label, learn):
        self.forward_propagate(input)
        self.get_deltas(label)
        self.renew_w(learn)
        self.renew_b(learn)
        return self.get_loss(label,self.output_cells)

8. get_loss(self,label,output_cell):用损失函数获取损失值,公式为

Σo输出值的个数=0((label[o]-output_cell[o])**2) *0.5

  #计算损失值
    def get_loss(self,label,output_cell):
        error = 0.0
        for o in range (len(output_cell)):
            error += 0.5 * (label[o] - output_cell[o]) ** 2
        return error

9. test(self):设置bp网的结构,然后得到20组数据进行训练,然后再用200组数据进行测试。直接调用test()方法就可以测试。

  #测试
    def test(self):
        input_datas,labels = self.get_train()
        self.setup(1,1,[10,10])
        self.train(input_datas,labels,0.05,3000)

        test,test_label = self.get_test()
        error = self.get_average_loss(test,test_label)
        print(error)
        '''ylabels = []
        error = 0
        for i in range(len(test)):
            ylabels.append(self.forward_propagate(test[i]))
            error += self.get_loss (test_label[i], self.output_cells)

        print("---测试误差---")
        error = error/200
        print(error)

猜你喜欢

转载自blog.csdn.net/dulingmo/article/details/83862436
今日推荐