【C/C++】MNISTの手書き数字の画像/ラベルデータをサクっと読み込む

機械学習で定番の数字認識では、サンプルデータとしてMNISTの手書き数字画像を使用する事が多いですね。PythonではMNIST画像を読み書きするライブラリがあるため手間いらずですが、C/C++では自力で読み書きする必要があるため、サンプルを紹介します。

なお、MNIST画像データの詳細な仕様は下記ブログが参考になります。
MNIST データの仕様を理解しよう

 

        #define MNIST_TRAINING_IMG_PATH     "train-images-idx3-ubyte"
        #define MNIST_TRAINING_LABEL_PATH   "train-labels-idx1-ubyte" 
        #define MNIST_TRANING_IMG_CNT	(60000)

        // MNISTの教師画像/ラベルを開く
        FILE *fpImg = fopen(MNIST_TRAINING_IMG_PATH, "rb");
        FILE *fpLabel = fopen(MNIST_TRAINING_LABEL_PATH, "rb");
        if(!fpImg || !fpLabel){
            printf("Mnist Load Err\n");
            return -1;
        }

        // 教師データの読み込み
        for(int iCnt = 0; iCnt < MNIST_TRANING_IMG_CNT; iCnt++){

            // 画像データ読み込み(16バイト目から開始)
            unsigned char szImg[MNIST_IMG_SIZE];
            fseek(fpImg, 16 + iCnt * MNIST_IMG_SIZE, SEEK_SET);
            fread(szImg, sizeof(char),  MNIST_IMG_SIZE, fpImg);

            // ラベルデータ読み込み(8バイト目から開始)
            char cLabel;
            fseek(fpLabel, 8 + iCnt, SEEK_SET);
            fread(&cLabel, sizeof(char), sizeof(char), fpLabel);

            // TODO:学習処理
        }

        // ファイルを閉じる
        fclose(fpImg);
        fclose(fpLabel);

for文内で1データ毎に画像とラベルをszImgとcLabelに読み込んでいます。
szImgは0-255の生の値のため必要に応じて0-1.0に正規化して下さい。
なお、画像の幅/高さやデータ数の情報は固定情報なので、ファイルからロードせずに定数定義としています。