我目前正在尝试根据本文paper中的描述实现新版本的储层神经网络(类似于循环神经网络,但仅训练输出层权重)。
此过程的一部分描述了如何从线性特征向量 构造非线性特征向量 。例如,要构造二次非线性特征向量,请遵循以下过程:
在论文中,他们给这个操作赋予了符号:
作为示例,以下线性特征向量:
1
2
3
4
与自身计算外积后变为,
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
根据我的理解,非线性特征向量是,
1
2
3
4
4
6
8
9
12
16
理想情况下,我正在寻找一个使用 Eigen 的程序,它允许我做到这一点?
例如,我尝试过这样的事情:
// You'll need to have the Eigen library
#include "Eigen/Dense"
#include <iostream>
#include <format>
int main() {
Eigen::Vector<double, 4> o_lin;
o_lin << 1, 2, 3, 4;
const auto outer_prod{ o_lin * o_lin.transpose() };
const auto upper_tri{ outer_prod.template triangularView<Eigen::Upper>() };
Eigen::Vector<double, 16> upper_tri_vec;
std::cout << outer_prod << "\n\n";
std::cout << std::format( "upper_tri ({}, {}), size: {}\n",
upper_tri.rows(), upper_tri.cols(),
upper_tri.size() );
std::cout << std::format( "upper_tri_vec ({}, {}), size: {}\n",
upper_tri_vec.rows(), upper_tri_vec.cols(),
upper_tri_vec.size() );
// This fails @ runtime for me
upper_tri.evalTo( upper_tri_vec );
std::cout << upper_tri_vec << std::endl;
// This won't compile as the triangularView doesn't have a .reshaped() method
// Eigen::Vector<double, 10> o_nonlin{ upper_tri.reshaped() };
}
给出输出:
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
upper_tri (4, 4), size: 16
upper_tri_vec (16, 1), size: 16
Assertion failed: ((!(RowsAtCompileTime!=Dynamic) || (rows==RowsAtCompileTime)) && (!(ColsAtCompileTime!=Dynamic) || (cols==ColsAtCompileTime)) && (!(Rows
AtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic) || (rows<=MaxRowsAtCompileTime)) && (!(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynami
c) || (cols<=MaxColsAtCompileTime)) && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."), function resize, file PlainObjectBase.h, l
ine 273.
zsh: abort ./main
有什么方法可以解决这个问题吗?
--- 编辑 ---
虽然我一直在尝试实现这个特定的上三角元素 - >向量映射操作,但在尝试这样的事情时遇到了不同的问题:
// Shorter name for std::ptrdiff_t == Eigen::Index
using Index = std::ptrdiff_t;
template <Weight T, Index R, Index C, Index N>
constexpr inline Eigen::Vector<T, N>
get_u_tri( const Eigen::Ref<Eigen::Matrix<T, R, C>> m ) {
Vec<T, N> result;
Index pos{ 0 };
for ( Index i{ 0 }; i < R; ++i ) {
Index m_block_width{ std::max( C - i, Index{ 1 } ) };
Index m_block_pos{ std::min( i, C - 1 ) };
result.template segment( pos, m_block_width ) =
m.template block( i, m_block_pos, 1, m_block_width );
// result.template block( pos, 0, C - i, 1 ) =
// m.template block( i, m_block_pos, 1, m_block_width );
pos += std::max( C - i, Index{ 1 } );
}
return result;
}
但是,这会产生以下运行时错误:
Assertion failed: (rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."), function resize, file DenseB
ase.h, line 261.
我会使用
Map
(文档在这里)基本上将triangularView
复制到Vector
。
#include <Eigen/Dense>
#include <iostream>
int main(int argc, char *argv[]) {
Eigen::Matrix<double, 4, 1> olin;
olin << 1,2,3,4;
Eigen::Matrix4d outer_product;
outer_product = olin * olin.transpose();
Eigen::Vector<double, 16> triview_vec;
Eigen::Matrix<double, 4, 4>::Map(triview_vec.data(), 16, 1) = outer_product.triangularView<Eigen::Upper>();
std::cout << triview_vec << std::endl;
return 0;
}
此时
triview_vec
将如下所示:
1
0
0
0
2
4
0
0
3
6
9
0
4
8
12
16
然后你可以使用任何你最喜欢的方法来提取你关心的值。我不擅长对
Eigen
向量进行索引,所以这是我的蛮力方法。
Eigen::Vector<int, 16> down = (triview_vec.array() > 0.0).select(Eigen::Vector<int, 16>::Ones(),0);
Eigen::Vector<double, Eigen::Dynamic> nonlin;
int size_nonlin = down.sum();
nonlin.resize(size_nonlin);
size_t tracker = 0;
for (size_t i = 0; i < 16; ++i){
if (down(i)){
nonlin(tracker) = triview_vec(i);
tracker++;
}
}
最终结果是:
1
2
4
3
6
9
4
8
12
16