RNN 更新全连接层权重 全连接层权重矩阵_全连接


全连接层是MLP的重要组成部分。其前向传播的计算过程为:



其中,


为全连接层第


层的输入,是一个


的矩阵,其中



分别为一个batch的样本个数和上一层的节点数;



为权重和偏置,其中权重为


的矩阵,偏置为一个


的向量,其中


为下一层的节点数。


对于第


层,其反向传播的过程分为求权重与偏置的偏导(误差)和求该层的误差,权重与偏置的偏导即求损失对其的梯度用以进行网络的参数更新,而第


层的误差是为了将误差传给前一层,以进行反向传播。


对于第


层,其权重与偏置的偏导:





其中,


为网络的总层数,


为第


层的输出,因而

为损失对第


层输出的误差。由于全连接网络的层与层之间是串联的结构,因此第


层的输出与第


层的输入相同,即



因此在反向传播中,对于第


层来说,只需要获取第


层传来的误差


,并计算当前层的权重与偏置的偏导即可获得该层参数的梯度了。


由于


,因此





下面是全连接层FullConnectionLayer类的头文件。


#ifndef FULLCONNECTION_LAYER_H_
#define FULLCONNECTION_LAYER_H_

#include "Operator.hpp"

namespace mario
{
	typedef class FullConnectionLayer : public Operator
	{
	private:
		matrix m_w;
		matrix m_b;

		matrix m_dw;
		matrix m_db;
		matrix m_dx;

		matrix m_in;
		matrix m_out;

	public:
		FullConnectionLayer();
		FullConnectionLayer(const int &_lastNeuronNum, const int&_nextNeuronNum);
		~FullConnectionLayer();
	
		const matrix& getW() const;

		const matrix& getB() const;

		const matrix& forward(const matrix&_lastOut);

		const matrix& backward(const matrix &_nextDerr);

		void update(const double &_learningRate = 0.001);

	}Fc;
}

#endif	//FULLCONNECTION_LAYER_H_


FullConnectionLayer类的数据成员包括输入输出m_in、m_out,权重m_w、偏置m_b及其梯度m_dw、m_db,该层的误差m_x。成员函数包括前向传播forward(),反向传播求梯度backward(),更新权重与偏置update(),还可以查看权重和偏置getW()、getB()。

下面重点记录一下前向与反向传播的部分,首先是前向传播forward()。


const matrix& FullConnectionLayer::forward(const matrix&_lastOut)
	{
		if (m_in.cols() != _lastOut.cols())
		{
			cout << "Error in ullConnectionLayer::forward(): m_in.cols() != _lastOut.cols().n";
			return matrix();
		}

		m_in.release();
		m_out.release();
		
		m_in = _lastOut;
		m_out = m_in*m_w + m_b;

		return m_out;
}


接下来是反向传播。


const matrix& FullConnectionLayer::backward(const matrix &_nextDerr)
{
	if (m_in.rows() != _nextDerr.rows())
	{
		cerr << "Error in FullConnectionLayer::backward(): m_in.rows() != _nextDx.rows().n";
		return matrix();
	}

	m_dw.release();
	m_db.release();
	m_dx.release();

	m_dw = m_in.T()*_nextDerr / m_in.rows();
	m_db = _nextDerr.meanByCol();
	m_dx = _nextDerr*m_w.T();

	return m_dx;
}


最后利用求得的梯度更新参数。


void FullConnectionLayer::update(const double &_learningRate)
{
	m_w -= _learningRate*m_dw;
	m_b -= _learningRate*m_db;
}


至此,FullConnectionLayer的主要成员函数记录完毕了 。

接下来是损失函数的介绍和如何利用这些数据和单个的层,连接成一整个网络,并进行前向与反向传播。