菜鸟学人工神经网络(C++11实现)零:矩阵类

人工神经网络的主要作用是在我们自己不知道规律的情况下让它自己总结出规律,并且我们给它一个输入时它能给出一个合乎情理的输出。下面先上会用到的一个类 t_matrix(为什么不是CMatrix,这是因为我有时候把代码也放到安卓机上一个叫C4Droid的程序里执行,然后出错了修改,大家知道,手机切换大小写是比较麻烦的,所以我用t_来代替 t的意思就是类型的英文type,以后只要是自定义数据类型的都用t_作前缀)。不错,就是一个矩阵相关的类,从这一步你们就会发现这里面绝对是大量的矩阵运算。这个矩阵代码是通用的所以单独用一个文件来保存以便复用,代码如下(为方便在VS 2013里查看代码,成员的实现直接放在了类了,以后的类也会这么干大笑):

#pragma once
#include"stdlib.h"
#include"math.h"
template<int row, int col>class t_matrix
{
public:
	//row*col矩阵与col*col1矩阵相乘
	template< int col1>t_matrix<row, col1>operator*(const t_matrix<col, col1>&M)const
	{
		t_matrix<row, col1> ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col1; j++)
			{
				ret.data[i][j] = 0;
				for (int k = 0; k < col; k++)
					ret.data[i][j] += data[i][k] * M.data[k][j];
			}
		return ret;
	}
	//
	t_matrix operator+(const t_matrix&M)const
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = data[i][j] + M.data[i][j];
		return ret;
	}
	t_matrix&operator+=(const t_matrix&M)
	{
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				data[i][j] += M.data[i][j];
		return *this;
	}
	t_matrix operator-(const t_matrix&M)const
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = data[i][j] - M.data[i][j];
		return ret;
	}
	t_matrix&operator-=(const t_matrix&M)
	{
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				data[i][j] -= M.data[i][j];
		return *this;
	}
	t_matrix operator*(const double val)const
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = data[i][j] * val;
		return ret;
	}
	friend t_matrix operator*(const double val, const t_matrix&M)
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = M.data[i][j] * val;
		return ret;
	}
	//转置矩阵
	t_matrix<col, row>transpose()const
	{
		t_matrix<col, row>ret;
		for (int i = 0; i < col; i++)
			for (int j = 0; j < row; j++)
				ret.data[i][j] = data[j][i];
		return ret;
	}
	//矩阵的hadamard积
	t_matrix hadamard(const t_matrix&M)
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = data[i][j] * M.data[i][j];
		return ret;
	}
	//矩阵的克罗内克积(张量积)
	template<int r, int c>t_matrix<row*r, col*c>kronecker(const t_matrix<r, c>&M)const
	{
		t_matrix<row*r, col*c>ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				for (int a = 0; a < r; a++)
					for (int b = 0; b < c; b++)
						ret.data[i*r + a][j*c + b] = data[i][j] * M.data[a][b];
		return ret;
	}
	//矩阵的每个元素平方的和
	double square()
	{
		double ret = 0;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret += data[i][j] * data[i][j];
		return ret;
	}
public:
	//常数矩阵
	static t_matrix constant(double val)
	{
		t_matrix ret;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = val;
		return ret;
	}
	//min到max的随机矩阵
	static t_matrix random(double min, double max)
	{
		t_matrix<row, col>ret;
		double len = (max - min) / (double)RAND_MAX;
		for (int i = 0; i < row; i++)
			for (int j = 0; j < col; j++)
				ret.data[i][j] = min + (double)rand() *len;
		return ret;
	}
public:
	double data[row][col];
};

大家是不是发现这居然是个模板类,int类型的row、col分别是矩阵的行数和列数,都要求大于0,本来应该是unsigned int的,但是我用int习惯了就没用。为什么要用模板类呢?这主要是为了让VS2013在我们输入矩阵数据时能及时发现错误,因为矩阵的行和列是不尽相同的,不同行列的矩阵对大多数矩阵运算操作是不适用的,所以用了模板类让编译器来帮我们在输入时就检查,而不是运行后才发现错误。还有另一个原因就是模板类能提高性能,当然在我们的例子代码里性能什么的都是浮云,我们只要效果

大家会看到这个类里重载了许多运算符。如果对矩阵熟悉的话应该能猜出这些重载是干嘛的。下面简单说一下(以下函数都是简写):

operator*(t_matrix):两个矩阵的正常乘积。要求第一个矩阵的列与第二个矩阵的行相等,不然编译器会报错。(看看,这个操作就对行列数有要求)

operator*(double):一个标量与矩阵相乘。满足交换律。

operator+(t_matrix):两个矩阵相加。要求两矩阵的行数、列数分别相等。(又是一个行列数限制)

operator+=(t_matrix):(学过C的不知道这什么意思就先去看看基础吧。)

operator-(t_matrix):两矩阵相减。要求同operator+。

operator-=(t_matrix):(你们知道的)

transpose():返回本矩阵的转置矩阵。(就是把矩阵的行、列元素对换,(row,col)矩阵变成(col,row)矩阵)

hadamard():两矩阵的hadamard积。要求同operator+,计算方式与两矩阵相加相似,只是把里面的加法换成乘法。(我不知道hadamard的同文时什么)

kronecker():两矩阵的克罗内克积(也有称为张量积的)。这是以上这几个矩阵与矩阵操作中唯一一个对行列数没要求的操作。将第一个矩阵(row行col列)中的每一个元素与第二个矩阵(row1行col1列)相乘并摆放在大矩阵中该元素相对的位置,所以返回的大矩阵的行列数是(row*row1行col*col1列)。

下面是几个辅助的操作:

square():返回本矩阵的每个元素平方的和。(可以用矩阵与它的转置矩阵相乘达到同样的效果,但是为了性能(其实是为了偷懒大笑)和理解,给它单独做了一个函数

static constant(double):返回一个矩阵,这个矩阵的每个元素都相同。

static random(double min,double max):返回一个矩阵,这个矩阵的每个元素都是[min,max]间的随机数

唯一的变量

data[row][col]:保存矩阵数据并给外部访问。(本来想重载operato[]来访问的,后来想想算了(因为我代码里都用了好多,懒得去ctrl+H替换大笑))

有了这些操作我们的接下来的工作将会少写很多代码。好了,真正的人工神经网络下一篇blog开始得意


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值