机器学习之递归神经网络RNN实现二进制加法

1.循环递归,并且当前的结果受前段时间的结果影响,不同样本间是有联系的
这里写图片描述
以下是反向传播时对权重进行调整的推倒公式
这里写图片描述

#coding:utf-8
'''
Created on 2017年3月18日
#本项利用RNN递归神经网络实现二进制加法
@author: qiujiahao
'''
import numpy as np
import copy
#激活函数
def sigmoid(x):
    output = 1/(1+np.exp(-x))
    return output
#sigmoid函数的倒数值
def sigmoid_output_to_derivative(output):
    return output*(1-output)

int2binary = {}
binary_dim = 8

largest_number = pow(2, binary_dim)

#建立一个hash表把0-255每个数的二进制码建立映射
binary = np.unpackbits(
    np.array([range(largest_number)],dtype=np.uint8).T,axis=1)

for i in range(largest_number):
    #将对应的10进制数转化为二进制
    int2binary[i]=binary[i]

#输入参数
#学习速率
alpha = 0.1
#输入的维度:2个2进制的数
input_dim = 2
#中间层
hidden_dim = 16
output_dim = 1

#初始化权重,h代表中间层的循环结构
synapse_0 = 2*np.random.random((input_dim,hidden_dim))  -1
synapse_1 = 2*np.random.random((hidden_dim,output_dim)) -1
synapse_h = 2*np.random.random((hidden_dim,hidden_dim)) -1

#反向传播完了,要去更新参数,这里定义一个和权重一样维度的矩阵
#用来存储更新参数
synapse_0_update = np.zeros_like(synapse_0)
synapse_1_update = np.zeros_like(synapse_1)
synapse_h_update = np.zeros_like(synapse_h)

#开始进行前向传播
for j in range(10000):

    #随机的找一个整数值,除以2是方便c不要超过largest_number
    a_int = np.random.randint(largest_number/2)
    a = int2binary[a_int]

    b_int = np.random.randint(largest_number/2)
    b = int2binary[b_int]  

    #真实的值
    c_int = a_int + b_int 
    c = int2binary[c_int]

    #d用来装预测值
    d = np.zeros_like(c)

    overallError = 0

    layer_2_deltas = list()
    layer_1_values = list()
    #为了第一次迭代的时候能取到前一次的结果,此处加一个全0的值
    layer_1_values.append(np.zeros(hidden_dim))

    #本二进制数一共有8位,依次计算
    for position in range(binary_dim):
        x = np.array([[a[binary_dim-position-1],b[binary_dim-position-1]]])
        y = np.array([[c[binary_dim-position-1]]]).T

        #当前阶段的值乘以权重synapse_0,并加上上一阶段的值乘以synapse_h
        layer_1 = sigmoid(np.dot(x,synapse_0)+np.dot(layer_1_values[-1],synapse_h))

        #输出层并没有循环
        layer_2 = sigmoid(np.dot(layer_1,synapse_1))

        #误差
        layer_2_error = y - layer_2
        #计算L2层的权重对输出的影响,sigmoid_output_to_derivative是计算sigmod函数的倒数值
        layer_2_deltas.append((layer_2_error)*sigmoid_output_to_derivative(layer_2))
        overallError +=np.abs(layer_2_error[0])

        #实际输出
        d[binary_dim-position-1] = np.round(layer_2[0][0])
        #复制保存l1层的输出
        layer_1_values.append(copy.deepcopy(layer_1))

    #用于将来保存循环权重的影响
    future_layer_1_delta=np.zeros(hidden_dim) 

    #进行反向传播计算
    for position in range(binary_dim):
        x = np.array([[a[position],b[position]]])
        #取出前向传播时保存的值
        layer_1 = layer_1_values[-position-1]
        #取出前一阶段的值
        prev_layer_1 = layer_1_values[-position-2]
        #l2层的误差
        layer_2_delta = layer_2_deltas[-position-1]

        #l1层的误差,注意future_layer_1_delta.dot(synapse_h.T)计算的是循环部分的影响
        layer_1_delta = (future_layer_1_delta.dot(synapse_h.T) + layer_2_delta.dot(synapse_1.T)) * sigmoid_output_to_derivative(layer_1) 

        #w1是前一层传下来的delta值乘以当前层的输出值得到w1所需要更新的大小
        synapse_1_update += np.atleast_2d(layer_1).T.dot(layer_2_delta)
        #prev_layer_1是隐层计算出来的值
        synapse_h_update += np.atleast_2d(prev_layer_1).T.dot(layer_1_delta)

        synapse_0_update += x.T.dot(layer_1_delta)

        future_layer_1_delta = layer_1_delta

    # 我们已经完成了所有的反向传播,可以更新几个转换矩阵了。并把更新矩阵变量清零
    #alpha代表更新的力度
    synapse_0 += synapse_0_update * alpha
    synapse_1 += synapse_1_update * alpha
    synapse_h += synapse_h_update * alpha

    synapse_0_update *= 0
    synapse_1_update *= 0
    synapse_h_update *= 0

    # print out progress
    if(j % 1000 == 0):
        print("Error:" + str(overallError))
        print("Pred:" + str(d))
        print("True:" + str(c))
        out = 0
        for index,x in enumerate(reversed(d)):
            out += x*pow(2,index)
        print(str(a_int) + " + " + str(b_int) + " = " + str(out))
        print("------------")  
Error:[ 4.32476103]
Pred:[1 1 1 1 1 1 1 1]
True:[1 0 1 0 1 0 0 0]
100 + 68 = 255
------------
Error:[ 3.79252319]
Pred:[1 1 1 1 1 1 1 1]
True:[1 1 1 1 1 0 1 0]
125 + 125 = 255
------------
Error:[ 4.12765176]
Pred:[1 0 1 1 1 1 0 0]
True:[1 1 0 0 0 0 0 1]
122 + 71 = 188
------------
Error:[ 3.89832429]
Pred:[0 1 1 1 1 1 0 1]
True:[0 1 1 0 0 1 0 1]
78 + 23 = 125
------------
Error:[ 2.74232096]
Pred:[1 1 0 1 1 1 1 0]
True:[1 1 0 1 1 1 1 0]
96 + 126 = 222
------------
Error:[ 1.20789252]
Pred:[1 0 0 1 1 1 0 0]
True:[1 0 0 1 1 1 0 0]
32 + 124 = 156
------------
Error:[ 0.94402244]
Pred:[1 0 0 0 0 0 1 1]
True:[1 0 0 0 0 0 1 1]
107 + 24 = 131
------------
Error:[ 0.388379]
Pred:[0 1 1 1 1 0 1 0]
True:[0 1 1 1 1 0 1 0]
91 + 31 = 122
------------
Error:[ 0.45148266]
Pred:[0 0 1 0 1 1 0 1]
True:[0 0 1 0 1 1 0 1]
18 + 27 = 45
------------
Error:[ 0.25285549]
Pred:[0 1 1 1 1 1 0 0]
True:[0 1 1 1 1 1 0 0]
13 + 111 = 124
------------
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值