菜鳥學人工神經網絡(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開始得意


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章