今回は、前回ダウンロードしてきたMNISTのデータをCSVに変換しました。
今までバイナリデータをちゃんと扱ったことがなかったので、とても勉強になりました。
Pythonによるスクレイピング&機械学習開発テクニック増補改訂 Scrapy、BeautifulSoup、scik [ クジラ飛行机 ]の第4章を参考にさせていただきながら、取り組んでいます。
MNISTのデータのダウンロードまでは、前回の記事をご参照ください。
では、振り返っていきたいと思います。
MNISTからダウンロードしてきたデータは、以下のような構造になっています。 バイナリデータとなっているので、数値で扱うためには、後述のstructモジュールのunpack()メソッドを使って、整数値などに変換してから扱う必要があります。 ラベルファイル (「train-labels-idx1-ubyte」「t10k-labels-idx1-ubyte」) 画像ファイル(「train-images-idx3-ubyte」「t10k-images-idx3-ubyte」) MNIST公式のWebサイトは以下の通りです。 MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges コード全体は以下の通りで、「mnist-to-csv.py」に保存しました。 今回は、「to_csv」という関数を定義して、最後にその関数を使って、CSVに変換するという構造になっています。 import struct def to_csv(name, maxdata): #(4) うまく取り出せたかどうかPGMで保存して確認 #(5) 出力件数を指定して出力 では、コードを順番に見ていきます。 まず、「to_csv」の関数の中身を見ていきます。 最初に、ダウンロードしたMNISTのラベルファイルと、イメージファイルを開きます。 このファイルは、バイナリファイルの読み込みなので、'rb'で開きます。 lbl_f = open('./mnist/'+name+'-labels-idx1-ubyte', 'rb') また、CSVで保存するファイルを開きます。 今度は、テキストファイルの書き込みなので、'w'で開きます。また、エンコーディングには、'utf-8'を指定します。 structモジュールのunpack()メソッドを使って、バイナリデータを読めるデータに変換します。 使い方は、unpack(フォーマット、バイナリデータ)となります。 フォーマットの'>II'は、'>'がビッグエンディアン(データの順番を変えずに読み込む)を表し、'II'が2つ連続したunsined int型(符号無4バイト整数型)を表しています。 全体としてlbl_f.read(8)で読み込んだ8バイトのデータを4バイト、4バイトに分けてそれぞれ、1つずつの整数値としてmag, lbl_countにそれぞれ格納します。 mag, lbl_count = struct.unpack('>II', lbl_f.read(8)) 同様に、img_fから、最初の8バイトを読み込んでmag, img_countにそれぞれ格納します。 mag, img_count = struct.unpack('>II', img_f.read(8)) 次の8バイトを読み込んで、前半4バイトを行数(rows)、後半4バイトを列数(cols)に読み込んで、掛けた値を画素数(pixels)に格納します。(MNISTのデータは、rows=28,cols=28のpixels=784のデータとなります。) rows, cols = struct.unpack('>II', img_f.read(8)) ラベルの数だけ、繰り返します。 for idx in range(lbl_count): 指定したデータの個数(maxdata)を上回ったら処理を終了します。 if idx > maxdata: break lbl_f.read(1)でラベルデータの1バイトを、'B'(整数型の1バイトデータ)としてlabelに格納します。 label = struct.unpack('B', lbl_f.read(1))[0] img_f.read(pixels)で画像データの画素数バイト(784バイト)を、bdataに格納します。 bdata = img_f.read(pixels) bdataを、map関数とlambda式を用いて1バイトづつ文字列に変換した後に、list関数で配列としてsdataに格納します。 sdata = list(map(lambda n: str(n), bdata)) csv_fに出力する際は、先頭1文字目にラベルデータの数字とカンマを出力後、list関数で配列に格納された画像データの値をjoin関数でカンマ区切りにして出力し、最後に改行を出力します。 csv_f.write(str(label)+',') CSVで出力したデータが本当に画像データであるか可視化するためにPGM形式の画像ファイルとして保存してテストします。PGMはテキストファイルで画像を表現する形式です。 全てのデータに実施する必要はないので、取り出した画像データの10個目までについて処理をします。 if idx < 10: まず、画像のヘッダを定義します。'P2'は、グレースケールの画像を、'28 28'は縦28x横28の画像サイズを、'255'は255階調のグレースケールであることを表しています。 s = 'P2 28 28 255\n' あとは画像データ(sdata)をスペース区切りで追加します。 s += ' '.join(sdata) mnistフォルダの配下に、指定した名前と、インデックスと、「0」〜「9」のラベルを作ったファイルを作成して、開いていたファイルを全てクローズします。 iname = './mnist/{0}-{1}-{2}.pgm'.format(name,idx,label) 最後にこれまで作ってきた「to_csv」関数を使って、訓練データ(train)を1,000個とテストデータ(t10k)を500個のデータを、それぞれCSVに変換します。 #(5) 出力件数を指定して出力 先ほど作成したファイルを実行してみます。 python3 mnist-to-csv.py 以下の通り、MNISTのバイナリデータをCSVに変換し、PGMファイルも作成することができました。 作成されたPGMファイルを開いてみると、手書きの数字(図3では、数字の7)の画像ファイルであることが確認できました。 今回は、MNISTの手書き数字画像のバイナリデータを、CSVに変換する処理を確認しました。これまで、バイナリデータをきちんと扱ったことがなかったので、とても勉強になりました。 引き続き、このCSVデータを使って、画像分類の機械学習を実施していきたいと思います。 今後も、Pythonによるスクレイピング&機械学習開発テクニック増補改訂 Scrapy、BeautifulSoup、scik [ クジラ飛行机 ]で、スクレイピングと機械学習開発に取り組んでいきたいと思います。 【過去記事】 2019年8月31日(土)にE資格を受験して、合格しました! E資格対策として勉強の進め方や、参考書などをまとめました。 これから受験される方がいらっしゃいましたらご参考まで。 2019年3月9日(土)にG検定を受験し、見事合格できました! 受験の体験記や勉強法などを別のブログにまとめました。 これから受験される方がいらっしゃいましたらご参考まで。 【E資格対策に使った参考書】 MNISTのデータをCSVに変換する
1.MNISTのデータ構造
2.全体像
#(1)ラベルファイルとイメージファイルを開く
lbl_f = open('./mnist/'+name+'-labels-idx1-ubyte', 'rb')
img_f = open('./mnist/'+name+'-images-idx3-ubyte', 'rb')
csv_f = open('./mnist/'+name+'.csv', 'w', encoding='utf-8')
#(2)ヘッダー情報を読み込む
mag, lbl_count = struct.unpack('>II', lbl_f.read(8))
mag, img_count = struct.unpack('>II', img_f.read(8))
rows, cols = struct.unpack('>II', img_f.read(8))
pixels = rows * cols
#(3) 画像データを読み込んでCSVで保存
res = []
for idx in range(lbl_count):
if idx > maxdata: break
label = struct.unpack('B', lbl_f.read(1))[0]
bdata = img_f.read(pixels)
sdata = list(map(lambda n: str(n), bdata))
csv_f.write(str(label)+',')
csv_f.write(','.join(sdata)+'\r\n')
if idx < 10:
s = 'P2 28 28 255\n'
s += ' '.join(sdata)
iname = './mnist/{0}-{1}-{2}.pgm'.format(name,idx,label)
with open(iname, 'w', encoding='utf-8') as f:
f.write(s)
csv_f.close()
lbl_f.close()
img_f.close()
to_csv('train', 1000)
to_csv('t10k',500)
print('OK')3.ラベルファイルとイメージファイルを開く
img_f = open('./mnist/'+name+'-images-idx3-ubyte', 'rb')
4.ヘッダー情報を読み込む
pixels = rows * cols5.画像データを読み込んでCSVで保存
csv_f.write(','.join(sdata)+'\r\n')6.うまく取り出せたかどうかPGMで保存して確認
with open(iname, 'w', encoding='utf-8') as f:
f.write(s)
csv_f.close()
lbl_f.close()
img_f.close()7.出力件数を指定して出力
to_csv('train', 1000)
to_csv('t10k',500)
print('OK')8.コマンドラインから実行してみる