深度学习课程--assign3--RNN简单理解

Recurrent Neural Network - RNN

为了更好地理解RNN的框架,我们将会用numpy手写RNN的各种layers。之后再用tensorflow 的keras来直接用函数定义layers。所以首先要理解RNN,RNN的简单结构我们是知道的,如下图所示,可以注意到对于多次隐层的循环,用的权值是一样的。
在这里插入图片描述
下面将会参考这个网站提供的例子来理解 RNN的网络结构:
http://iamtrask.github.io/2015/11/15/anyone-can-code-lstm/

我们将会用python简单的建立 两个input,16个隐藏层,一个output。比如是 加法的运算。a+b = c
比如 a = 12 ,变成二进制 2^3 + 2 ^ 2 ,才用8个数。即[0,0,0,0,1,1,0,0]
b = 4 即 [0,0,0,0,0,1,0,0]
所以c应该为 16 即为[0,0,0,1,0,0,0,0] 作为ground truth。我们将会用RNN来预测 任意的两个二进制数字相加的结果,并跟ground truth做对比。
所以首先是来create 二进制的数据集

我们将会用np.unpackbits来转换十进制整数为二进制。下面便是np.unpackbits的用法

a = np.array([[2], [7], [23]], dtype=np.uint8)
a.shape   #3行1列 
b = np.unpackbits(a, axis=1)
#变成二进制 
b  # 2^1 = 2 ; 2^2+2^1+2^0 = 7 ; 2^4+2^2+2^1+2^0 =16+4+2+1=23

在这里插入图片描述
所以,我们将会创建2^8 = 256个zheng

Data Generation

import copy
import numpy as np
np.random.seed(123)
#创建 二进制的字典 -- 方便随机提取
int2binary = {
    
    }
#定义8个数字  
binary_dim = 8 

largest_num = pow(2,binary_dim)  #2**8 = 256

#把256个数 全部转化为 二进制 即有256个 二进制 
binary = np.unpackbits(np.array([range(largest_num)],dtype=np.uint8).T,axis=1)

#然后把binary放入字典int2binary,方便随机提取 
for i in range(largest_num):
    int2binary[i] = binary[i]

在这里插入图片描述

设置RNN网络参数

#设置网络维度
alpha = 0.1 
input_dim = 2
hidden_dim = 16
output_dim = 1 

#设置网络weights 权重参数
w0 = 2*np.random.random((input_dim,hidden_dim))-1   #随机设置(2,16)的参数
print(w0.shape)
w1 = 2*np.random.random((hidden_dim,output_dim)) - 1
print(w1.shape)
wh = 2*np.random.random((hidden_dim,hidden_dim)) - 1
print(wh.shape)

(2, 16)
(16, 1)
(16, 16)
同时也要准备好 backprop 的数据 ,即delta gradient的值

dw0 = np.zeros_like(w0)

dw1 = np.zeros_like(w1)

dwh = np.zeros_like(wh)

RNN的作用是 根据 两个二进制 a , b 来 predict a + b 的值。

下面是训练的过程 ,重复10000次 ,然后求导更新pred值,到最后的预测已经很准了。

#定义sigmoid函数
def sigmoid(x):
    output = 1/(1+np.exp(-x))
    return output

#定义sigmoid的求导 derivate
def sigmoid_grads(s):
    d = s*(1-s)
    return d 
#定义一个函数 把二进制转换为 十进制 
def bin2dec(b):
    out = 0
    for i, x in enumerate(b[::-1]):
        out += x * pow(2, i)  
    return out
#这部分是为了画图~ 画出 accs和errs via epoch
errs = list()
accs = list()

error = 0
accuracy = 0

对于每次feedward之后预测完,便从后面到前面开始求导~来更新权重values

for n in range(10000):
	#随机产生数字 a 和 b 
	############################################################
	#256/2 在1-128内中随机找一个参数 
	a_int = np.random.randint(largest_num/2) 
	#然后用随机产生的num在字典那里提取相应的二进制数字 
	a = int2binary[a_int]  
	
	#同理,用随机产生的num 来提取二进制的数值
	b_int = np.random.randint(largest_num/2)
	b = int2binary[b_int]
	
	#然后同理产生 ground true c 
	c_int = a_int + b_int
	c = int2binary[c_int]
	############################################################
	#现在开始RNN网络的建立  来pred a和b相加
	#开始预测 c ,于是创建 d的形状 
	d = np.zeros_like(c)
	#创建error
	total_error = 0 
	#创建forward的时候 layer1的values 值,然后初始化为0 ,有hidden_dim=16个0,作为隐藏层 
	H = list()
	H.append(np.zeros(hidden_dim))
	#创建layer2 往后的求导 
	layer2_grads = list()
	
	############################################################
	#现在往前计算 feedward
	for i in range(binary_dim):
		#往前的公式是 
		#layer1 = sigmoid(x * w0+ h0 * wh) 这里暂时忽略bias 
		#layer2 = sigmoid(layer1 * h1),这里也暂时忽略 bias
		 
		#首先提取a,b和c的8个数 的每一个 数字 
		X = np.array([[a[binary_dim - i - 1],b[binary_dim - i - 1]]])
		y = np.array([[c[binary_dim - i - 1]]]).T
		
		#开始计算feedward,layer1_values[-1]代表最后一层layer1
		layer1 = sigmoid(np.dot(X,w0)+np.dot(H[-1],wh)) 
		#layer1的shape是 (1,16)
		#放入隐藏层H
		H.append(copy.deepcopy(layer1))	
		layer2 = sigmoid(np.dot(layer1,w1))
		#layer2的shape是 (1)
		d[binary_dim - i - 1] = np.round(layer2[0][0])
		#feedward之后,需要计算error值,跟c相对比 这里即y和layer2对比。
		layer2_error = y - layer2   #目标函数
		total_error += np.abs(layer2_err[0])
		
		#然后对目标函数 往后面求导 即 layer2_error * derivate 
		#求导 求到 w1 那里 的整体 后面需要乘 layer1
		grad = layer2_error * sigmoid_derivative(layer2) 
		layer2_grads.append(grad)
	future_layer1_grad = np.zeros(hidden_dim)
	############################################################

    ############################################################
	#现在往后计算 backward
	for j in range(binary_dim):
		#从二进制的前头开始求导~
		X = np.array([[a[j],b[j]]])
		layer1 = =H[-j - 1]  #提取最后的隐藏层 
		prev_layer1 =H[-j-2] ##再往前提取一层 算数
		#从layer2的导数list提取最后一个 来计算 这是为了计算dw1  = layer1* grads(layers)
		layer2_grad = layer2_grads[-(j+1)]
        dw1 += np.atleast_2d(layer1).T.dot(layer2_grad)

		#开始backprop计算 dw0,dwh  这里的backprop也是有关系 前者的back会影响后面的backward
		layer1_grad = (future_layer1_grad.dot(wh.T) + layer2_grad.dot(w1.T)) * sigmoid_grads(layer1)
        dwh += np.atleast_2d(prev_layer1).T.dot(layer1_grad)
        dw0 += X.T.dot(layer1_grad)
        
        future_layer1_grad = layer1_grad
	w0 += dw0 * alpha
	w1 += dw1 * alpha
	wh += dwh * alpha
	dw0 *= 0
	dw1 *= 0
	dwh *= 0
	#更新结束 
    ############################################################
    
	############################################################
	#这部分是为了画图 
	error += total_error
	if (bin2dec(d) == c_int):
		accuracy += 1
    if (n % 20 == 0):
        errs.append(error / 20)
        accs.append(accuracy / 20)
        error = 0
        accuracy = 0
	############################################################
    if(n % 1000 == 0):
    	print('Iter', n)
        print('Error is: ', str(total_err))
        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("------------")
        #end 
	############################################################
	

在这里插入图片描述

可视化部分

import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(errs, label='error')
plt.plot(accs, label='accuracy')
plt.legend()

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Jiana_Feng/article/details/110154014