cpp简单实现一下RNN神经网络

RNN的结构

在这里插入图片描述
用之前的输出和当前的输入作为新的输入输入带神经网络

t a n h ( x ) = e x − e − x e x + e − x tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} tanh(x)=ex+exexex
S o f t m a x ( X ) = e X ∑ i e x i Softmax(X)=\frac{e^X}{\sum_i{e^{x_i}}} Softmax(X)=iexieX
t a n h ( x ) tanh(x) tanh(x)是非线性函数,使用非线性函数增强神经网络表达力,(。・∀・)ノ゙
S o f t m a x ( x ) Softmax(x) Softmax(x)来处理最后的处理结果,计算每种结果的概率,在反向传播时的效果比最小二乘法更好┗|`O′|┛

前向传播

X i = t a n h ( U i X i − 1 + V i H i + B i ) X_i=tanh\left( U_i X_{i-1} + V_i H_i + B_i \right) Xi=tanh(UiXi1+ViHi+Bi)
H i = X i H_i=X_i Hi=Xi

  • X i X_i Xi 是第i层的输出向量
  • H i H_i Hi 是第i层的上个时刻输出向量
  • U i , V i U_i,V_i Ui,Vi分别是对输入数据处理的权重矩阵
  • B i B_i Bi是偏置
  • 每层神经网络按照这个公式递推就可以了
  • 用Softmax对最后一层处理

反向传播

对于每次的计算,求取其梯度,然后用梯度更新参数
∂ ε ( t ) ∂ U i = ∂ ε ( t ) ∂ X n ( t ) ∏ k = i + 1 n ∂ X k ( t ) ∂ X k − 1 ( t ) ( ∑ k = 1 t + 1 ( ∂ X k − 1 ∂ U i ∏ T = k t ∂ X i ( T ) ∂ X i ( T − 1 ) ) ) \frac{\partial \varepsilon\left(t\right)}{\partial U_i}=\frac{\partial \varepsilon\left(t\right)}{\partial X_n\left(t\right)} \prod_{k=i+1}^{n}\frac{\partial X_{k}\left(t\right)}{\partial X_{k-1}\left(t\right)} \left( \sum_{k=1}^{t+1} \left( \frac{\partial X_{k-1}}{\partial U_i} \prod_{T=k}^{t}\frac{\partial X_i\left(T\right)}{\partial X_i\left(T-1\right)}\right) \right) Uiε(t)=Xn(t)ε(t)k=i+1nXk1(t)Xk(t)(k=1t+1(UiXk1T=ktXi(T1)Xi(T)))
∂ ε ( t ) ∂ U i = ∂ ε ( t ) ∂ X n ( t ) ∏ k = i + 1 n ∂ X k ( t ) ∂ X k − 1 ( t ) ( ∑ k = 1 t + 1 ( ∂ X k − 1 ∂ V i ∏ T = k t ∂ X i ( T ) ∂ X i ( T − 1 ) ) ) \frac{\partial \varepsilon\left(t\right)}{\partial U_i}=\frac{\partial \varepsilon\left(t\right)}{\partial X_n\left(t\right)} \prod_{k=i+1}^{n}\frac{\partial X_{k}\left(t\right)}{\partial X_{k-1}\left(t\right)} \left( \sum_{k=1}^{t+1} \left( \frac{\partial X_{k-1}}{\partial V_i} \prod_{T=k}^{t}\frac{\partial X_i\left(T\right)}{\partial X_i\left(T-1\right)} \right) \right) Uiε(t)=Xn(t)ε(t)k=i+1nXk1(t)Xk(t)(k=1t+1(ViXk1T=ktXi(T1)Xi(T)))
∂ ε ( t ) ∂ U i = ∂ ε ( t ) ∂ X n ( t ) ∏ k = i + 1 n ∂ X k ( t ) ∂ X k − 1 ( t ) ( ∑ k = 1 t + 1 ( ∂ X k − 1 ∂ B i ∏ T = k t ∂ X i ( T ) ∂ X i ( T − 1 ) ) ) \frac{\partial \varepsilon\left(t\right)}{\partial U_i}=\frac{\partial \varepsilon\left(t\right)}{\partial X_n\left(t\right)} \prod_{k=i+1}^{n}\frac{\partial X_{k}\left(t\right)}{\partial X_{k-1}\left(t\right)} \left( \sum_{k=1}^{t+1} \left( \frac{\partial X_{k-1}}{\partial B_i} \prod_{T=k}^{t}\frac{\partial X_i\left(T\right)}{\partial X_i\left(T-1\right)} \right) \right) Uiε(t)=Xn(t)ε(t)k=i+1nXk1(t)Xk(t)(k=1t+1(BiXk1T=ktXi(T1)Xi(T)))
求其梯度的式子很长,需要追溯到上层神经网络的输出和其他时刻的时候神经网络的输出,所也要用递推的方法求梯度

代码实现

#include<bits/stdc++.h>
struct Matrix
{
    int rows,colums;
    float **val;
    void init(int _rows,int _colums)
    {
        rows=_rows,colums=_colums;
        val=new float*[rows];
        for(int i=0; i<rows; i++)
        {
            val[i]=new float[colums];
            for(int j=0; j<colums; j++)
                val[i][j]=(rand()%200-100)/100.0;
        }
    }
};
float tanh(float x){
    x=exp(x);x=x*x;
    return  (x-1)/(x+1);
}
struct NerualNetwork
{
    int layoutNum;
    float factor=0.02;
    Matrix *X,*U,*V,*H,*B;
    Matrix *D,*dU,*dV,*dB,*TU,*TV,*TB;
    Matrix Softmax;
    std::vector<int>layout;
    void addLayout(int number)
    {
        layout.push_back(number);
        layoutNum++;
    }
    void bulid(){
        X=new Matrix[layoutNum];
        H=new Matrix[layoutNum];
        D=new Matrix[layoutNum];


        U =new Matrix[layoutNum];
        dU=new Matrix[layoutNum];
        TU=new Matrix[layoutNum];
        V =new Matrix[layoutNum];
        dV=new Matrix[layoutNum];
        TV=new Matrix[layoutNum];
        B =new Matrix[layoutNum];
        dB=new Matrix[layoutNum];
        TB=new Matrix[layoutNum];

        srand(time(NULL));
        X[0].init(layout[0],1);
        D[0].init(layout[0],1);
        for(int i=1;i<layoutNum;i++){
            X[i].init(layout[i],1);
            H[i].init(layout[i],1);
            D[i].init(layout[i],1);

             U[i].init(layout[i],layout[i-1]);
            dU[i].init(layout[i],layout[i-1]);
            TU[i].init(layout[i],layout[i-1]);
             V[i].init(layout[i],layout[i]);
            dV[i].init(layout[i],layout[i]);
            TV[i].init(layout[i],layout[i]);
             B[i].init(layout[i],1);
            dB[i].init(layout[i],1);
            TB[i].init(layout[i],1);
        }
        Softmax.init(layout[layoutNum-1],1);
    }
    void clearMenory(){
        for(int k=1;k<layoutNum;k++)
            for(int i=0;i<H[k].rows;i++)
                X[k].val[i][0]=0;
    }
    void InitTrainMenory(){
        for(int k=1;k<layoutNum;k++){
            for(int i=0;i<B[k].rows;i++)dB[k].val[i][0]=TB[k].val[i][0]=0;
            for(int i=0;i<U[k].rows;i++){
                memset(dU[k].val[i],0,dU[k].colums*4);
                memset(TU[k].val[i],0,TU[k].colums*4);
            }
            for(int i=0;i<V[k].rows;i++){
                memset(dV[k].val[i],0,dV[k].colums*4);
                memset(TV[k].val[i],0,TV[k].colums*4);
            }
        }
    }
    int updateSoftmax(){
        float sum=0;
        Matrix M=X[layoutNum-1];
        for(int i=0;i<M.rows;i++){
            Softmax.val[i][0]=exp(M.val[i][0]);
            sum+=Softmax.val[i][0];
        }
        int k=0;
        for(int i=0;i<M.rows;i++){
            Softmax.val[i][0]/=sum;
            if(Softmax.val[i][0]>Softmax.val[k][0])k=i;
        }
        return k;
    }
    Matrix run(int input){
        for(int i=0;i<X[0].rows;i++)X[0].val[i][0]=0;
        X[0].val[input][0]=1;
        for(int k=1;k<layoutNum;k++)
        {
            for(int i=0;i<H[k].rows;i++)H[k].val[i][0]=X[k].val[i][0];
            for(int i=0;i<X[k].rows;i++){
                X[k].val[i][0]=B[k].val[i][0];
                for(int j=0;j<U[k].colums;j++)
                    X[k].val[i][0]+=U[k].val[i][j]*X[k-1].val[j][0];

                for(int j=0;j<X[k].rows;j++)
                    X[k].val[i][0]+=V[k].val[i][j]*H[k].val[j][0];
                X[k].val[i][0]=tanh(X[k].val[i][0]);
            }
        }
        return X[layoutNum-1];
    }
    void Partial(int label){
        if(label==-1){
            for(int i=0;i<D[layoutNum-1].rows;i++)
                D[layoutNum-1].val[i][0]=0;
        }else{
            updateSoftmax();
            for(int i=0;i<D[layoutNum-1].rows;i++)
                D[layoutNum-1].val[i][0]=Softmax.val[i][0];
            D[layoutNum-1].val[label][0]-=1;
        }
        for(int k=layoutNum-1;k>0;k--){

            for(int i=0;i<V[k].colums;i++){
                float sum=0;
                for(int j=0;j<V[k].rows;j++)sum+=V[k].val[j][i];
                for(int j=0;j<TU[k].colums;j++)TU[k].val[i][j]*=sum;
                for(int j=0;j<TV[k].colums;j++)TV[k].val[i][j]*=sum;
                TB[k].val[i][0]*=sum;
            }
            for(int i=0;i<TU[k].rows;i++)
            for(int j=0;j<TU[k].colums;j++){
                TU[k].val[i][j]=(TU[k].val[i][j]+X[k-1].val[j][0])*(1-X[k].val[i][0]*X[k].val[i][0]);
                dU[k].val[i][j]+=TU[k].val[i][j]*D[k].val[i][0];
            }

            for(int i=0;i<TV[k].rows;i++)
            for(int j=0;j<TV[k].colums;j++){
                TV[k].val[i][j]=(TV[k].val[i][j]+H[k].val[j][0])*(1-X[k].val[i][0]*X[k].val[i][0]);
                dV[k].val[i][j]+=TV[k].val[i][j]*D[k].val[i][0];
            }
            for(int i=0;i<TB[k].rows;i++){
                TB[k].val[i][0]=(TB[k].val[i][0]+1)*(1-X[k].val[i][0]*X[k].val[i][0]);
                dB[k].val[i][0]+=TB[k].val[i][0]*D[k].val[i][0];
            }
            for(int i=0;i<U[k].colums;i++){
                D[k-1].val[i][0]=0;
                for(int j=0;j<U[k].rows;j++)
                    D[k-1].val[i][0]+=U[k].val[j][i]*(1-X[k].val[j][0]*X[k].val[j][0])*D[k].val[j][0];
            }
        }
    }
    void UpdateTrain(){
        for(int k=1;k<layoutNum;k++){
            for(int i=0;i<B[k].rows;i++)B[k].val[i][0]-=dB[k].val[i][0]*factor;
            for(int i=0;i<U[k].rows;i++)
                for(int j=0;j<U[k].colums;j++)
                    U[k].val[i][j]-=dU[k].val[i][j]*factor;
            for(int i=0;i<V[k].rows;i++)
                for(int j=0;j<V[k].colums;j++){
                    V[k].val[i][j]-=dV[k].val[i][j]*factor;

                }
        }
    }
}RNN;
int main()
{
    RNN.addLayout(5);
    RNN.addLayout(5);
    RNN.addLayout(5);
    RNN.bulid();
    for(int i=0;i<10000;i++){
        for(int j=0;j<5;j++)
        {
            RNN.InitTrainMenory();
            RNN.clearMenory();
            for(int k=0;k<4;k++){
                RNN.run((k+j)%5);
                if(k==3)RNN.Partial((4+j)%5);
                else RNN.Partial(-1);
            }
            RNN.UpdateTrain();
        }
    }
    for(int j=0;j<5;j++)
    {
        RNN.clearMenory();
        for(int k=0;k<4;k++)RNN.run((k+j)%5),printf("%c ",'a'+(k+j)%5);
        int ans=RNN.updateSoftmax();
        printf(" -->%c\n",'a'+(ans));
    }

    return 0;
}

用 a b c d e 训练RNN

输入四个字母 预测第五个字母是啥
在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Python代码示例,用于实现基本的循环神经网络(RNN): ``` import numpy as np # 定义sigmoid函数 def sigmoid(x): return 1 / (1 + np.exp(-x)) # 定义RNN类 class RNN: def __init__(self, input_size, hidden_size, output_size): # 初始化权重矩阵 self.Wxh = np.random.randn(hidden_size, input_size) * 0.01 self.Whh = np.random.randn(hidden_size, hidden_size) * 0.01 self.Why = np.random.randn(output_size, hidden_size) * 0.01 # 初始化偏置向量 self.bh = np.zeros((hidden_size, 1)) self.by = np.zeros((output_size, 1)) def forward(self, x): # 初始化隐藏状态和输出 h = np.zeros((self.Whh.shape[0], 1)) y = np.zeros((self.Why.shape[0], 1)) # 循环计算 for i in range(len(x)): # 更新隐藏状态 h = sigmoid(np.dot(self.Wxh, x[i]) + np.dot(self.Whh, h) + self.bh) # 更新输出 y = np.dot(self.Why, h) + self.by return y # 测试 x = [np.array([[0], [1]]), np.array([[1], [0]]), np.array([[1], [1]]), np.array([[0], [0]])] y = [np.array([[1]]), np.array([[1]]), np.array([[0]]), np.array([[0]])] model = RNN(2, 16, 1) for i in range(1000): for j in range(len(x)): y_pred = model.forward(x[j]) loss = np.sum((y_pred - y[j])**2) # 反向传播 dL_dy = 2 * (y_pred - y[j]) dWhy = np.dot(dL_dy, model.h.T) dL_dh = np.dot(model.Why.T, dL_dy) + model.dh_next dh_raw = model.h * (1 - model.h) dh = dL_dh * dh_raw dbh = dh dWxh = np.dot(dh, x[j].T) dWhh = np.dot(dh, model.h.T) # 更新参数 model.Wxh -= 0.1 * dWxh model.Whh -= 0.1 * dWhh model.Why -= 0.1 * dWhy model.bh -= 0.1 * dbh model.by -= 0.1 * dL_dy model.dh_next = np.dot(model.Whh.T, dh) if i % 100 == 0: print("Epoch: {}, Loss: {}".format(i, loss)) ``` 这个代码示例实现了一个简单RNN,用于二进制加法。它有2个输入神经元,16个隐藏神经元和1个输出神经元。它使用sigmoid作为激活函数,并使用反向传播算法进行训练。在训练过程中,它将输入序列通过RNN,计算输出并计算损失。然后,它使用反向传播算法计算梯度,并使用梯度下降算法更新权重矩阵和偏置向量。在每个epoch结束时,它会打印出损失值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值