最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C/C++實現(xiàn)手寫數(shù)字識別的示例詳解

 更新時間:2023年10月23日 16:28:38   作者:crazybobo1207  
這篇文章主要為大家詳細(xì)介紹了如何使用C/C++實現(xiàn)手寫數(shù)字識別,分別處理 32*32 文本數(shù)據(jù)集和mnist 28*28 png數(shù)據(jù)集,感興趣的小伙伴可以跟隨小編一起了解一下

絕大多數(shù)人都是用python寫,俺就喜歡用C/C++一句一句寫。代碼還未認(rèn)真整理,寫的有點亂,應(yīng)該還有優(yōu)化的余地。

程序主要目的:對測試數(shù)據(jù)集的樣本進(jìn)行預(yù)測,計算預(yù)測準(zhǔn)確率。

數(shù)據(jù)集:分別使用32*32數(shù)據(jù)集和28*28數(shù)據(jù)集(mnist數(shù)據(jù)集)。前者是txt文本,后者是png圖片。

算法:使用最簡單的KNN算法。

加快程序執(zhí)行的主要思路:

1.使用多線程(10個線程)讀取0到9數(shù)字對應(yīng)的樣本文件;

2.使用多線程(10個線程)對0到9數(shù)字對應(yīng)的樣本進(jìn)行預(yù)測;

3.求距離時,使用歐式距離,但是不做開平方運算(開平方運算是多余的,浪費時間);

4.求K個最近距離鄰居(類似于求TOP K),采用C++的push_heap和pop_heap(小根堆)。

對于32*32的數(shù)據(jù)集,由于樣本是txt文件,直接讀取txt文件中的0和1,很容易求出樣本之間的距離。

對于mnist數(shù)據(jù)集,因為原始數(shù)據(jù)是png圖片,所以需要做一些預(yù)處理:可以使用opencv讀取像素數(shù)據(jù),轉(zhuǎn)成類似于32*32的txt數(shù)據(jù)集,方便求距離。另外,方便程序處理,重命名了文件名,文件名分別是0_0.txt,0_1.txt……,轉(zhuǎn)換成txt文件的mnist數(shù)據(jù)集如下:

簡便起見,對樣本個數(shù)做了一些簡化,32*32數(shù)據(jù)集的訓(xùn)練數(shù)據(jù)是180*10=1800個,測試數(shù)據(jù)是80*10=800個,mnist數(shù)據(jù)集的訓(xùn)練數(shù)據(jù)是5000*10=5萬個,測試數(shù)據(jù)是800*10=8千個(原始測試樣本是1萬個,每個數(shù)字的測試樣本個數(shù)不同)。從數(shù)據(jù)量對比來看,后者是前者的280倍(訓(xùn)練數(shù)據(jù)集是28倍,測試數(shù)據(jù)集是10倍),對應(yīng)的程序運行時間(計算測試樣本的預(yù)測準(zhǔn)確率)后者也是前者的200多倍(排序算法很重要,如果不使用小根堆求TOP K,而是使用傳統(tǒng)的整體數(shù)據(jù)排序,估計運行速度會差很多)。

部分代碼如下(代碼還未整理,比較亂,暫時只貼主要代碼,表明整體思路),具體代碼回頭整理好了再貼。

#define TrainingDataNum 50000	
#define TestDataNum 8000		
#define FeatureNum 784    //28*28	
#define ClassNum 10
#define FileMaxCol 40    //大于28
#define K 3
 
//……………………
 
struct DisAndLabel
{
	int distance;
	int classLabel;
};
 
bool Cmp(const DisAndLabel& a, const DisAndLabel& b)
{
	return a.distance < b.distance;
}
 
int FileToTrainingDataArray(int** pTrainingDataFeture, int* pTrainingDataClass, int tid);
int FileToTestDataArray(int** pTestDataFeture, int* pTestDataClass, int tid);
void ClassifyTest(int** pTestDataFeture, int** pTrainingDataFeture, int* pTestDataClass, int* pTrainingDataClass, int tid);
 
//……………………
 
int main()
{
	clock_t t1, t2, t3, t4, t5;
	t1 = clock();
 
	int** pTrainingDataFeture = new int* [TrainingDataNum];
	if (pTrainingDataFeture == NULL)
	{
		exit(-1);
	}
 
	for (int i = 0; i < TrainingDataNum; i++)
	{
		pTrainingDataFeture[i] = new int[FeatureNum + 1];
		if (pTrainingDataFeture[i] == NULL)
		{
			exit(-1);
		}
	}
	
	//……………………
 
	t2 = clock();
	double duration = (double(t2) - double(t1)) / CLOCKS_PER_SEC;
	cout << "分配內(nèi)存:" << duration << "秒" << endl;
	
	//……………………
 
	thread td[10];
 
	for (int tid = 0; tid < 10; tid++)
	{
		td[tid] = thread(&FileToArrayThread, pTrainingDataFeture, pTrainingDataClass, pTestDataFeture, pTestDataClass, tid);
	}
 
	for (int tid = 0; tid < 10; tid++)
	{
		td[tid].join();
	}
	
	//……………………
	
	int errorCountTotal = 0;
 
	for (int i = 0; i < 10; i++)
	{
		errorCountTotal += errorCount[i];
	}
 
	cout << "*********************************************************" << endl;
	cout << "測試集測試結(jié)果:" << endl;
	cout << "k=" << K << endl;
	cout << "測試集樣本個數(shù):" << TestDataNum << endl;
	cout << "預(yù)測錯誤個數(shù):" << errorCountTotal << endl;
	cout << "錯誤率:" << double(errorCountTotal * 100.0 / TestDataNum) << "%" << endl;
	cout << "正確率:" << 100.0 - double(errorCountTotal * 100.0 / TestDataNum) << "%" << endl;
	//cout << "*********************************************************" << endl;
 
	t4 = clock();
	duration = (double(t4) - double(t3)) / CLOCKS_PER_SEC;
	cout << "*********************************************************" << endl;
	cout << "8000個樣本預(yù)測準(zhǔn)確率分析:" << duration << "秒" << endl;
 
	duration = (double(t4) - double(t1)) / CLOCKS_PER_SEC;
	cout << "*********************************************************" << endl;
	cout << "總共用時:" << duration << "秒" << endl;
	
	//……………………
}

運行結(jié)果如下:

K=3時,8000個測試樣本,預(yù)測錯誤了78個(其實算法沒有問題,很多情況是因為測試樣本里的數(shù)字寫的太奇葩了,數(shù)字X實在不像數(shù)字X),下面把K改為5,準(zhǔn)確率提高了一些。

從運行時間看,8000個樣本的預(yù)測用時是5秒多,如果只預(yù)測一個樣本,用時大概是5.4秒/8000=0.7毫秒,主要是訓(xùn)練數(shù)據(jù)集數(shù)據(jù)有點多(5萬個樣本)。

下面是32*32數(shù)據(jù)集的運行結(jié)果,由于訓(xùn)練樣本和測試樣本的數(shù)據(jù)量比mnist數(shù)據(jù)集少很多,所以程序運行速度快了200倍,平均每個樣本的預(yù)測時間大概是0.03秒/800=0.04毫秒。

程序總共用時不到50毫秒(用python寫,貌似要10秒左右),比python快了200倍。C語言直接操作內(nèi)存+高速緩存+宇宙第一IDE的代碼優(yōu)化+多線程,運行速度比python快2個數(shù)據(jù)級很正常。但是代碼量也比python多很多,一般2到3倍,如果python是直接調(diào)算法庫,比python多10倍以上 -_-。

樣本預(yù)測錯誤的具體原因是什么,可以分析K個最近樣本的距離值,以數(shù)字8(預(yù)測錯誤的重災(zāi)區(qū))為例:

到此這篇關(guān)于C/C++實現(xiàn)手寫數(shù)字識別的示例詳解的文章就介紹到這了,更多相關(guān)C++數(shù)字識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實現(xiàn)數(shù)字雨效果

    C語言實現(xiàn)數(shù)字雨效果

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)數(shù)字雨效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • C++基于LINUX的文件操作

    C++基于LINUX的文件操作

    這篇文章主要為大家介紹了C++基于LINUX的文件操作示例知識擴充,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • C++中map和set的簡介及使用詳解

    C++中map和set的簡介及使用詳解

    本文主要介紹了C++中map和set的簡介及使用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • c語言實現(xiàn)奇偶排序算法

    c語言實現(xiàn)奇偶排序算法

    這篇文章主要介紹了c語言實現(xiàn)奇偶排序算法,有需要的朋友可以參考一下
    2013-12-12
  • 用C語言實現(xiàn)圣誕樹(簡易版+進(jìn)階版)

    用C語言實現(xiàn)圣誕樹(簡易版+進(jìn)階版)

    大家好,本篇文章主要講的是用C語言實現(xiàn)圣誕樹(簡易版+進(jìn)階版),感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 淺析C++中的虛函數(shù)

    淺析C++中的虛函數(shù)

    以下是對C++中的虛函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • C語言 深入淺出講解指針的使用

    C語言 深入淺出講解指針的使用

    指針是C語言中一個非常重要的概念,也是C語言的特色之一。使用指針可以對復(fù)雜數(shù)據(jù)進(jìn)行處理,能對計算機的內(nèi)存分配進(jìn)行控制,在函數(shù)調(diào)用中使用指針還可以返回多個值
    2022-03-03
  • C語言中void類型指針的實現(xiàn)

    C語言中void類型指針的實現(xiàn)

    C語言中void類型指針有著特殊的用途,本文就來一下void類型指針的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • C語言實現(xiàn)桶排序的方法示例

    C語言實現(xiàn)桶排序的方法示例

    這篇文章主要介紹了C語言實現(xiàn)桶排序的方法,簡單描述了桶排序的概念、原理并結(jié)合實例形式分析了C語言實現(xiàn)桶排序算法的具體操作技巧,需要的朋友可以參考下
    2018-01-01
  • C語言結(jié)構(gòu)體內(nèi)存對齊問題小結(jié)

    C語言結(jié)構(gòu)體內(nèi)存對齊問題小結(jié)

    本文主要講解了C語言中結(jié)構(gòu)體的內(nèi)存對齊規(guī)則、計算方法以及影響因素,包括對齊規(guī)則的四個要點、內(nèi)存對齊的原因、如何修改默認(rèn)對齊數(shù)以及結(jié)構(gòu)體傳參時的注意事項,此外,還介紹了結(jié)構(gòu)體位段的概念、內(nèi)存分配和使用注意事項,感興趣的朋友一起看看吧
    2025-02-02

最新評論

乌兰浩特市| 太和县| 汪清县| 集安市| 宜都市| 威远县| 道孚县| 那坡县| 青神县| 峨眉山市| 昭苏县| 东丰县| 高尔夫| 河源市| 建宁县| 津南区| 湘潭县| 武邑县| 修文县| 松溪县| 馆陶县| 平度市| 湾仔区| 崇义县| 英吉沙县| 贵溪市| 宕昌县| 边坝县| 汉源县| 高碑店市| 同仁县| 洞头县| 德保县| 彩票| 江山市| 黑水县| 台东县| 北碚区| 霍城县| 五台县| 三明市|