C++元编程——深度双向RNN实验

使用C++的标准库实现了双向RNN的功能。最近对DRNN做了一些改进,同时进行了实验,首先DRNN的代码如下:

#ifndef _RNN_HPP_
#define _RNN_HPP_
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "mat.hpp"
#include "bp.hpp"
#include "activate_function.hpp"
/*
* 									     X<k> 
* 										  ^ 
* 										  | 
* 									     afV 
*										  ^
*							              |
*                                        +bv  
* 										  ^ 
* 										  | 
* 							 bw 		  V 
* 							 |  		  ^
*  							 v  		  | 
*	S<t-1> ------> W ------> + --------> afW ------> S<t>
*							 ^
*							 |
*							 U
*							 ^
*							 |
*							 X<k-1>      	
* */
template<typename val_t, template<typename> class update_method_templ, template<typename> class activate_func>
struct rnn_unite 
{using target_t = typename std::template vector<val_t>;val_t W;				//* 用于对层内加权val_t U;				//* 用于对上层加权val_t V;				//* 用于对激活值加权val_t bv;				//* 激活值的偏移量val_t bw;				//* 层内加权偏移量val_t S;update_method_templ<val_t> umW, umU, umV, umBv, umBw, umS;activate_func<val_t> afW;activate_func<val_t> afV;	//* 对下层的计划函数target_t	pre_input;target_t	pre_S;			//* 上一层进来的Svoid print() const{printf("W:%.4lf U:%.4lf V:%.4lf bv:%.4lf bw:%.4lf S:%.4lf\r\n", W, U, V, bv, bw, S);}rnn_unite():S(0.) {static std::default_random_engine e;std::uniform_real_distribution<double> ud(0, 1);W = ud(e);						//* 随机初始化U = ud(e);V = ud(e);bv = ud(e);bw = ud(e);}inline val_t do_forward(const int& i, val_t& cur_S){cur_S = afW.forward(U * pre_input[i] + W * cur_S + bw);pre_S[i] = cur_S;return afV.forward(V * cur_S + bv);}inline val_t do_backward(const int& i, const target_t& mt_delta, val_t& S_delta, const val_t& Wbak, const val_t& Ubak, const val_t& Vbak, val_t& Vdelta, val_t& bVdelta, val_t& Wdelta, val_t& bWdelta, val_t& Udelta){auto delta_before_afV = mt_delta[i] * afV.backward();Vdelta = Vdelta + pre_S[i] * delta_before_afV;bVdelta = bVdelta + delta_before_afV;//V = umV.update(V, pre_S[i] * delta_before_afV);//bv = umBv.update(bv, delta_before_afV);auto layer_back = (delta_before_afV * Vbak + S_delta) * afW.backward();Wdelta = Wdelta + pre_S[i - 1] * layer_back;bWdelta = bWdelta + layer_back;Udelta = Udelta + pre_input[i] * layer_back;//W = umW.update(W, pre_S[i - 1] * layer_back);//bw = umBw.update(bw, layer_back);//U = umU.update(U, pre_input[i]);S_delta = layer_back * Wbak;return layer_back * Ubak;}//* 升序遍历数组,正向通过网络,返回值为层间正向输出target_t asc_forward(const target_t& mt_in){pre_S.resize(mt_in.size(), 0.);pre_input = mt_in;target_t vec_ret(mt_in.size(), 0.);val_t cur_S = S;						//* 层内计算的值for (int i = 0; i < pre_input.size(); ++i){vec_ret[i] = do_forward(i, cur_S);}return vec_ret;}//* 反向遍历数组反馈误差,返回值为层间反向传播的误差target_t desc_backward(const target_t& mt_delta){val_t Wbak = W, Ubak = U, Vbak = V;target_t ret(mt_delta.size(), 0.);val_t S_delta = 0., Vdelta = 0., bVdelta = 0., Wdelta = 0., bWdelta = 0., Udelta = 0.;for (int i = mt_delta.size()-1; i >= 0; --i){ret[i] = do_backward(i, mt_delta, S_delta, Wbak, Ubak, Vbak, Vdelta, bVdelta, Wdelta, bWdelta, Udelta);}V = umV.update(V, Vdelta);bv = umBv.update(bv, bVdelta);W = umW.update(W, Wdelta);bw = umBw.update(bw, bWdelta);U = umU.update(U, Udelta);S = umS.update(S, S_delta);return ret;}//* 反向遍历数组,正向通过网络target_t desc_forward(const target_t& mt_in){pre_S.resize(mt_in.size(), 0.);pre_input = mt_in;target_t vec_ret(mt_in.size(), 0.);val_t cur_S = S;						//* 层内计算的值for (int i = mt_in.size()-1; i >= 0; --i){vec_ret[i] = do_forward(i, cur_S);}return vec_ret;}//* 正向遍历数组,反向通过网络target_t asc_backward(const target_t& mt_delta){val_t Wbak = W, Ubak = U, Vbak = V, bvbak = bv, bwbak = bw, Sbak = S;target_t ret(mt_delta.size(), 0.);val_t S_delta = 0., Vdelta = 0., bVdelta = 0., Wdelta = 0., bWdelta = 0., Udelta = 0.;for (int i = 0; i < mt_delta.size(); ++i){ret[i] = do_backward(i, mt_delta, S_delta, Wbak, Ubak, Vbak, Vdelta, bVdelta, Wdelta, bWdelta, Udelta);}V = umV.update(V, Vdelta);bv = umBv.update(bv, bVdelta);W = umW.update(W, Wdelta);bw = umBw.update(bw, bWdelta);U = umU.update(U, Udelta);S = umS.update(S, S_delta);return ret;}};template<typename val_t, template<typename> class update_method_templ, template<typename> class activate_func>
struct rnn_dup
{using target_t = typename std::template vector<val_t>;rnn_unite<val_t, update_method_templ, activate_func> rnn_forward, rnn_backward;using weight_type = bp<val_t, 1, gd, no_activate, XavierGaussian, 2, 1>;weight_type w;rnn_dup():rnn_forward(), rnn_backward(){}target_t forward(const target_t& mt_in){target_t mt_forward = rnn_forward.asc_forward(mt_in);target_t mt_backward = rnn_backward.desc_forward(mt_in);target_t ret(mt_in.size(), 0.);for (int i = 0; i < mt_in.size(); ++i){mat<2, 1, val_t> mt;mt[0] = mt_forward[i];mt[1] = mt_backward[i];ret[i] = w.forward(mt)[0];}return ret;}target_t backward(const target_t& mt_delta) {target_t mt_forward(mt_delta.size(), 0.);target_t mt_backward(mt_delta.size(), 0.);for (int i = 0; i < mt_delta.size(); ++i){mat<1, 1, val_t> mt(mt_delta[i]);auto mt_out = w.backward(mt);mt_forward[i] = mt_out[0];mt_backward[i] = mt_out[1];}target_t mt_forward_out = rnn_forward.desc_backward(mt_forward);target_t mt_backward_out = rnn_backward.asc_backward(mt_backward);target_t mt_ret(mt_delta.size(), 0.);for (int i = 0; i < mt_delta.size(); ++i){mt_ret[i] = mt_forward_out[i] + mt_backward_out[i];}return mt_ret;}void print() const {printf("bp weight:\r\n");w.print();printf("forward:\r\n");rnn_forward.print();printf("backward:\r\n");rnn_backward.print();}
};template<typename val_t, template<typename> class update_method_templ, template<typename> class activate_func>
struct rnn_flow 
{using target_t = typename std::template vector<val_t>;using rnn_type = rnn_dup<val_t, update_method_templ, activate_func>;rnn_type* p_layers;int layer_num;rnn_flow(const int& i_layer_num) :layer_num(i_layer_num) {p_layers = new rnn_type[layer_num];}virtual ~rnn_flow() {delete[] p_layers;}target_t forward(const target_t& mt_in) {auto mt = mt_in;for (int i = 0; i < layer_num; ++i) {mt = p_layers[i].forward(mt);}return mt;}target_t backward(const target_t& mt_in) {auto ret = mt_in;for (int i = layer_num-1; i >= 0; --i) {ret = p_layers[i].backward(ret);}return ret;}void print() const{for (int i = 0; i < layer_num; ++i){p_layers[i].print();}}
};#endif

接着使用nadam进行DRNN权值更新,然后输入了两个数组1,2,3和2,3,4进行训练,最后使用各种数组进行训练结果测试,代码如下:

#include "rnn.hpp"
#include "activate_function.hpp"
#include <math.h>const double ln2 = log(2);template<int row_num, int col_num>
mat<row_num, col_num, double> cross_entropy_grad(const mat<row_num, col_num, double>& expect, const mat<row_num, col_num, double>& real)
{mat<row_num, col_num, double> one(1.);return (expect / real - (one - expect)/(one - real))/ln2;
}int main(int argc, char** argv)
{using tgt_mat = std::vector<double>;rnn_flow<double, nadam, Tanh> rnn(2);//* 生成随机矩阵,根据矩阵计算出int train_num = 600000;for (int i = 0; i < train_num; ++i){{tgt_mat in = {.1, .2, .3};auto ret = rnn.forward(in);tgt_mat expect = {.3, .3, .3};mat<1, 3, double> mt_ret(ret.begin(), ret.end());mat<1, 3, double> mt_exp(expect.begin(), expect.end());mat<1, 3, double> mt_delta = cross_entropy_grad(mt_ret, mt_exp);std::vector<double> vec_delta = mt_delta.to_vector();mat<1, 3, double> backdelta = rnn.backward(vec_delta);if (i %(train_num/10) == 0){printf("output:");mt_ret.print();}}{tgt_mat in = {.2, .3, .4};auto ret = rnn.forward(in);tgt_mat expect = {.45, .45, .45};mat<1, 3, double> mt_ret(ret.begin(), ret.end());mat<1, 3, double> mt_exp(expect.begin(), expect.end());mat<1, 3, double> mt_delta = cross_entropy_grad(mt_ret, mt_exp);std::vector<double> vec_delta = mt_delta.to_vector();mat<1, 3, double> backdelta = rnn.backward(vec_delta);if (i %(train_num/10) == 0){printf("output:");mt_ret.print();}}if (i %(train_num/10) == 0){printf("--------------------------\r\n");}}printf("out\r\n");mat<1, 3, double>(rnn.forward({.1, .2, .0})).print();mat<1, 3, double>(rnn.forward({.2, .3, .0})).print();mat<1, 3, double>(rnn.forward({.3, .4, .0})).print();return 0;
}

训练结果如下:

 

第一个按顺序输入.1,.2,.0结果显示输入第2个的结果就是0.3228和我们训练使用的0.3有一点差距,不过差距比较小。第二个按照顺序输入.2,.3,.0,我们训练用的是.2,.3,.4;结果显示是0.456,和我们训练的输出0.45几乎一样。第三个是一个程序没有见过的输入.3,.4,.0;输出没有什么参考意义。总之,可见这个DRNN具备一定的学习能力的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/110469.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jmeter+ant+jenkins接口自动化测试框架

大致思路&#xff1a;Jmeter可以做接口测试&#xff0c;也能做压力测试&#xff0c;而且是开源软件&#xff1b;Ant是基于Java的构建工具&#xff0c;完成脚本执行并收集结果生成报告&#xff0c;可以跨平台&#xff0c;Jenkins是持续集成工具。将这三者结合起来可以搭建一套We…

IET独立出版 | EI检索 | 2023年第三届机械、航空航天与汽车工程国际会议

会议简介 Brief Introduction 2023年第三届机械、航空航天与汽车工程国际会议&#xff08;CMAAE 2023&#xff09; 会议时间&#xff1a;2023年12月8 -10日 召开地点&#xff1a;中国南京 大会官网&#xff1a;www.cmaae.org 航天是当今世界最具挑战性和广泛带动性的高技术领域…

Lua基础知识

文章目录 1. Lua简介1.1 设计目的&#xff1a;1.2 特性1.3 应用场景 2. Lua脚本学习2.1 安装2.2 lua操作2.3 lua案例 学习lua主要是为了后续做高性能缓存架构所准备的基础技术。可以先了解下基础&#xff0c;在实际使用时&#xff0c;再查缺补漏。 1. Lua简介 Lua 是一种轻量小…

八路参考文献:[八一新书]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑工业出版社,2022.

八路参考文献&#xff1a;&#xff3b;八一新书&#xff3d;许少辉&#xff0e;乡村振兴战略下传统村落文化旅游设计&#xff3b;&#xff2d;&#xff3d;北京&#xff1a;中国建筑工业出版社&#xff0c;&#xff12;&#xff10;&#xff12;&#xff12;&#xff0e;

Python直接变快五倍?最新的优化解释器和内存管理

来自公众号&#xff1a;OSC开源社区 2020 年秋&#xff0c;CPython 核心开发者 Mark Shannon 提出了关于 Python 的几个性能改进&#xff0c;这个提议被称为 “香农计划” (Shannon Plan)。 Shannon 随后创建了 Faster Cpython 项目&#xff0c;他希望在 4 年的时间里&#xff…

Spring boot如何工作

越来越方便了 java技术生态发展近25年&#xff0c;框架也越来越方便使用了&#xff0c;简直so easy&#xff01;&#xff01;&#xff01;我就以Spring衍生出的Spring boot做演示&#xff0c;Spring boot会让你开发应用更快速。 快速启动spring boot 请参照官网 Spring | Quic…

银河麒麟V10(Tercel)服务器版安装 Docker

一、服务器环境 ## 查看系统版本&#xff0c;确认版本 cat /etc/kylin-release Kylin Linux Advanced Server release V10 (Tercel)## 操作系统 uname -p aarch64## 内核版本&#xff08;≥ 3.10&#xff09; uname -r 4.19.90-21.2.ky10.aarch64## iptables 版本&#xff08;…

Mysql--技术文档--B树-数据结构的认知

阿丹解读&#xff1a; B树&#xff08;B tree&#xff09;和B树&#xff08;B-tree&#xff09;都是常见的自平衡搜索树数据结构&#xff0c;用于在存储和检索大量数据时提供高效的操作。 基本概念-B树/B树 B树&#xff08;B-tree&#xff09;和B树&#xff08;B tree&#x…

checkstyle检查Java编程样式:final参数

checkstyle可以利用FinalParameters检查方法、构造器、catch和for-each块的参数是final的&#xff1a; https://checkstyle.sourceforge.io/checks/misc/finalparameters.html 背后的原理&#xff1a;程序执行期间修改参数的值会引起混乱&#xff0c;所以应该避免。 要配置使…

MybatisPlus核心功能

文章目录 一、前言二、核心功能2.1、条件构造器2.1.1、基础查询条件2.1.2、复杂查询条件2.1.3、动态查询条件2.1.4、查询结果排序2.1.5、执行查询 2.2、主键策略2.2.1、自增主键策略2.2.2、UUID 主键策略2.2.3、雪花算法主键策略2.2.4、自定义 ID 生成策略 三、总结 一、前言 …

Vscode画流程图

1.下载插件 Draw.id Integration 2.桌面新建文件&#xff0c;后缀名改为XXX.drawio 在vscode打开此文件 &#xff0c;就可以进行绘制流程图啦

智能工厂移动式作业轻薄加固三防平板数据采集终端

在这个高度自动化和数字化的环境中&#xff0c;数据采集变得尤为重要。为了满足这个需求&#xff0c;工业三防平板数据采集终端应运而生。工业三防平板数据采集终端采用了轻量级高强度镁合金材质&#xff0c;这使得它在保持轻薄的同时具有更强的坚固性。这种材质还具有耐磨防损…

Ubuntu20.04配置mysql配置主从复制

ubuntu20.04&#xff1a;mysql主库 sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf # 修改完毕重启 sudo service mysql stop sudo service mysql start主库mysqld.cnf配置 [mysqld] ... # bind-address>->--- 127.0.0.1 # 注释掉&#xff0c;允许外部连接 # mysqlx-b…

【Android】TextView适配文本大小并保证中英文内容均在指定的UI 组件内部

问题 现在有一个需求&#xff0c;在中文环境下textView没有超过底层的组件限制&#xff0c;但是一切换到英文环境就超出了&#xff0c;这个如何解决呢&#xff1f;有啥例子吗&#xff1f; 就像这样子的。 解决 全部代码如下&#xff1a; <?xml version"1.0"…

rust交叉编译 在mac下编译linux和windows

系统版本macbook proVentura 13.5linux ubuntu22.04.3 LTS/18.04.6 LTSwindowswindows 10 专业版 20H2mac下rustc --versionrustc 1.74.0-nightly (58eefc33a 2023-08-24)查看当前系统支持的交叉编译指定系统版本列表 rustup target list如果已经安装这里会显示(installed)。…

Elasticsearch中倒排索引、分词器、DSL语法使用介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Spring Cloud Nacos 和 Eureka区别,包含实战代码

目录 一、Spring Cloud Eureka详解二、Spring Cloud Nacos详解三、Spring Cloud Nacos和Eureka区别 Spring Cloud Nacos 和 Spring Cloud Eureka 都是 Spring Cloud 微服务框架中的服务注册和发现组件&#xff0c;用于帮助开发者轻松地构建和管理微服务应用。它们之间的主要区别…

pytestx容器化执行引擎

系统架构 前端、后端、pytest均以Docker容器运行服务&#xff0c;单独的容器化执行引擎&#xff0c;项目环境隔离&#xff0c;即用即取&#xff0c;用完即齐&#xff0c;简单&#xff0c;高效。 前端容器&#xff1a;页面交互&#xff0c;请求后端&#xff0c;展示HTML报告 后…

RHCE——十一、NFS服务器

NFS服务器 一、简介1、NFS背景介绍2、生产应用场景 二、NFS工作原理1、示例图2、流程 三、NFS的使用1、安装2、配置文件3、主配置文件分析3.1 实验1 4、NFS账户映射4.1 实验24.2 实验3 四、autofs自动挂载服务1、产生原因2、安装3、配置文件分析4、实验45、实验5 一、简介 1、…

归一化的作用,sklearn 安装

目录 归一化的作用&#xff1a; 应用场景说明 sklearn 准备工作 sklearn 安装 sklearn 上手 线性回归实战 归一化的作用&#xff1a; 归一化后加快了梯度下降求最优解的速度; 归一化有可能提高精度(如KNN) 应用场景说明 1&#xff09;概率模型不需要归一化&#xff…