??keras中SimpleRNN和日常RNN所不同的就是其隱藏層到輸出層之間是沒(méi)有權(quán)重的死姚,即最后時(shí)刻隱藏層的輸出即為最終的輸出。下面以一個(gè)例子來(lái)說(shuō)明運(yùn)算過(guò)程
keras自帶的SimpleRNN進(jìn)行計(jì)算
- 導(dǎo)入所需要的庫(kù)
import tensorflow as tf
import keras
from keras import Sequential
from keras.layers import SimpleRNN
- 搭建神經(jīng)網(wǎng)絡(luò)
model=Sequential()
model.add(SimpleRNN(32,input_shape=(None,20),activation='relu'))
model.summary()
??keras中SimpleRNN 默認(rèn)的激活函數(shù)為tanh色罚,這里為了方便對(duì)比账劲,采用relu激活函數(shù)瀑焦。keras中輸入的形式一般為[batch_size,timestep,num],在上述代碼中榛瓮,20代表的是num 榆芦。time_step是未知的None,一般batch_size在網(wǎng)絡(luò)輸入的時(shí)候不直接輸進(jìn)去吧(好像是在訓(xùn)練的時(shí)候自己可以改)驻右。此處崎淳,我們不訓(xùn)練,直接用生成的初始化參數(shù)作為最后的參數(shù)森爽,因?yàn)橹皇球?yàn)證計(jì)算過(guò)程,只需要對(duì)比網(wǎng)絡(luò)最后的結(jié)果和我自己算出的結(jié)果是否一致就行橘蜜。
- 參數(shù)的提取
??在生成網(wǎng)絡(luò)后付呕,初始化的參數(shù)就已經(jīng)確定了,導(dǎo)出初始化參數(shù)作為自己驗(yàn)證的權(quán)重。
U=model.get_weights()[0] #輸入層和循環(huán)層之間的權(quán)重象颖,維度為(20*32)
W=model.get_weights()[1] #循環(huán)層與循環(huán)層之間的權(quán)重姆钉,維度為(32*32)
bias=model.get_weights()[2] #隱藏層的偏置項(xiàng),32個(gè)
??上述代碼中陶冷,U表示輸入和循環(huán)層之間的權(quán)重(因?yàn)樵诖罱ňW(wǎng)絡(luò)時(shí)固定了輸入的num為20筋讨,循環(huán)層t時(shí)刻的維數(shù)為32),其維度為(2032),W表示循環(huán)層之間的權(quán)重赤屋,因?yàn)閠-1時(shí)刻和t時(shí)刻的都為32壁袄,所以權(quán)重矩陣維度為(3232)嗜逻。這里其實(shí)的計(jì)算沒(méi)有考慮batch_size,如果考慮了batch_size的話,其實(shí)都是矩陣的計(jì)算逆日。(這里想不明白沒(méi)關(guān)系萄凤,后面驗(yàn)證時(shí)候具體的計(jì)算流程,一看就懂了)坪圾。最后的bias表示的是某個(gè)時(shí)刻t的32個(gè)偏置項(xiàng)。
- 測(cè)試數(shù)據(jù)生成
test=np.random.randint(1,20,(10,2,20))
??為方便驗(yàn)證漓概,生成的test的維度為[10,2,20]病梢,10指的是batch_size,2表示的是時(shí)間步time_step , 20指的是輸入的維度堂鲜。
-直接用網(wǎng)絡(luò)進(jìn)行計(jì)算
model_predict=model.predict(test)
model_predict.shape
??輸出的維度為[10,32]护奈,model_predict的具體數(shù)值在后續(xù)的對(duì)比中進(jìn)行展示霉旗。
自己計(jì)算SimpleRNN的輸出
- 自己定義一個(gè)relu激活函數(shù)
def activation_relu(x):
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if x[i,j]<0:
x[i,j]=0
return x
- 矩陣乘法進(jìn)行驗(yàn)證
x_t1=test[:,0,:]
x_t2=test[:,1,:]
# 第一個(gè)循環(huán)層的數(shù)據(jù)
s_t1=activation_relu(np.dot(x_t1,U)+bias)
# 第二個(gè)循環(huán)層的數(shù)據(jù)
s_t2=activation_relu(np.dot(x_t2,U)+np.dot(s_t1,W)+bias)
??在測(cè)試數(shù)據(jù)生成的時(shí)候厌秒,我們已經(jīng)說(shuō)明了測(cè)試數(shù)據(jù)的時(shí)間步為2,第一個(gè)時(shí)間步x_t1的維度為[10,20]擅憔,s_t1的維度為, s_t2的維度為 。此時(shí)s_t2就為最后的輸出蚌讼。
對(duì)比兩個(gè)結(jié)果
?? 從上圖發(fā)現(xiàn)SimpleRNN和我所理解的計(jì)算過(guò)程是一樣的篡石。為更準(zhǔn)確的驗(yàn)證西采,做一個(gè)循環(huán),代碼如下:
def compare_value(a,b):
if len(a.shape)!=len(b.shape):
print("兩者維度不同胖眷,無(wú)法比較")
else:
a_shape=np.array(a.shape) #原始的a.shape的格式為tuple
b_shape=np.array(b.shape)
result=a_shape-b_shape
if sum(result)!=0:
print("維度不同霹崎,無(wú)法比較")
else:
#為防止保留位數(shù)的差異仿畸,統(tǒng)一保留小數(shù)點(diǎn)后6位
a=np.round(a,3)
b=np.round(b,3)
c=a-b
#由于電腦計(jì)算位數(shù)等等一些方式朗和,可能保留的小數(shù)位不同簿晓,會(huì)在小數(shù)點(diǎn)后6,7位有點(diǎn)點(diǎn)誤差
#這個(gè)不是運(yùn)算方式,而是電腦保留位數(shù)導(dǎo)致的
if c.sum()<1e-5:
print("兩者相同")
else:
print("兩者數(shù)據(jù)不同")
compare_value(s_t2,model_predict)
兩者相同
以一張圖來(lái)描述SimpleRNN的計(jì)算過(guò)程