--12.MNIST 이미지 손글씨 인식.ipynb--
import urllib.request as req
import gzip, os, os.path
savepath = "./mnist"
baseurl = "http://yann.lecun.com/exdb/mnist"
files = [
"train-images-idx3-ubyte.gz", # 학습용 데이터 (6만개)
"train-labels-idx1-ubyte.gz", # 학습용 target 값 (레이블)
"t10k-images-idx3-ubyte.gz", # 테스트용 데이터 (1만개)
"t10k-labels-idx1-ubyte.gz", # 테스트용 target값 (레이블)
]
if not os.path.exists(savepath) :
os.mkdir(savepath)
for f in files :
url = baseurl + "/" + f
loc = savepath + "/" + f
print("download : ", url)
if not os.path.exists(loc) :
req.urlretrieve(url, loc) # url 파일을 다운로드 받아 loc으로 저장.
for f in files :
gz_file = savepath + "/" + f
raw_file = savepath + "/" + f.replace(".gz", "") # 압축 해제한 결과 파일명
with gzip.open(gz_file, "rb") as fp :
body = fp.read() # 압축 푼후 읽기
with open(raw_file, "wb") as w :
w.write(body) # 읽은 내용을 저장하기
print('압축해제 완료')
#그런데 왜 파일이 하나씩일까? --> MNIST 데이터 세트의 데이터는 자체적인 데이터베이스 형식이기 때문
머신러닝할때 바이너리 상태의 데이터로 가공/학습시키기는 적잖케 어렵다.
텍스트 상태의 데이터(cf. CSV0로 변환한뒤 학습시키는게 훨씬 직관적이고 수월하다
파이썬에서 binary 데이터 다루는 모듈인 struct 를 사용해서 CSV 로 전환한다
import struct
lbl_f = open("./mnist/train-labels-idx1-ubyte", "rb")
lbl_f.read(8) # '현재 파일 위치'로 부터 8byte 읽기
lbl_f.read(8) # 그 다음의 8byte 읽기
lbl_f.seek(0) # 파일의 맨 처음으로 '현재 파일 위치 이동
lbl_f.read(4)
lbl_f.seek(1) # '현재 파일 위치'를 파일 처음에서 1byte 뒤로 이동
lbl_f.read(4)
lbl_f.seek(0)
(mag, lbl_count) = struct.unpack('>II', lbl_f.read(8))
mag, lbl_count
struct.unpack("B", lbl_f.read(1))[0]
lbl_f.seek(0)
(mag, lbl_count) = struct.unpack('>II', lbl_f.read(8))
for idx in range(lbl_count) :
label = struct.unpack("B", lbl_f.read(1))[0]
img_f = open("./mnist/train-images-idx3-ubyte", "rb")
img_f.seek(0)
mag, img_count = struct.unpack(">II", img_f.read(8))
print(mag, img_count)
rows, cols = struct.unpack(">II", img_f.read(8))
print(rows, cols)
pixels = rows * cols
pixels
bdata = img_f.read(pixels) # bytes 객체 리턴
bdata
type(bdata)
bdata[0]
sdata = list(map(lambda n:str(n), bdata))
print(sdata)
",".join(sdata)
학습시킬 분량 (maxdata)를 정해서 CSV파일로 추출
def to_csv(name, maxdata) : # name(CSV파일명) 으로 저장
# 레이블 파일과 이미지 파일 열기
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")
# 다운받은 MNIST 데이터는 label 과 데이터(image) 가 각각 따로 있었지만
# 이를 하나의 CSV 파일에 저장
# 헤더 정보 읽기
mag, lbl_count = struct.unpack(">II", lbl_f.read(8))
mag, img_count = struct.unpack(">II", img_f.read(8))
# 이미지의 경우
# rows. cols 정보 읽기
rows, cols = struct.unpack(">II", img_f.read(8))
pixel = rows * cols
# 이미지의 '레이블'과 '데이터'를 읽고 CSV파일로 저장
res = []
for idx in range(lbl_count) : # 레이블의 개수만큼 (데이터의 개수와 동일)
if idx > maxdata : break
# 레이블
label = struct.unpack("B", lbl_f.read(1))[0]
# 데이터 (binary -> str)
bdata = img_f.read(pixels)
sdata = list(map(lambda n:str(n), bdata))
# CSV만들기
csv_f.write(str(label)+ ",") # label을 첫번째 컬럼으로 지정
csv_f.write(",".join(sdata) + "\n") # 28x28 = 784 개의 컬럼으로 이미지 데이터 저장
csv_f.close()
lbl_f.close()
img_f.close()
to_csv("train", 1000)
to_csv("t10k", 500)
import pandas as pd
pd.read_csv("./mnist/train.csv", header=None)
from sklearn import model_selection, svm, metrics
0.0 ~ 1.0 사이의 값으로 변환
def load_csv(fname) :
labels = []
images = []
with open(fname, "r") as f :
for line in f :
cols = line.split(",")
labels.append(int(cols.pop(0))) # 첫번째 컬럼 (label) 추출
# 나머지 28 x 28 개의 픽셀 데이터
vals = list(map(lambda n:int(n) / 256, cols)) # normalizing
images.append(vals)
return {"labels": labels, "images": images}
data = load_csv("./mnist/train.csv")
test = load_csv("./mnist/t10k.csv")
len(data["labels"])
clf = svm.SVC()
clf.fit(data["images"], data["labels"])
import joblib
import os
savefile = "mnist.pkl"
pkfile = os.path.join(savepath, savefile)
joblib.dump(clf, pkfile)
clf = None
clf = joblib.load(pkfile)
predict = clf.predict(test["images"])
predict
ac_score = metrics.accuracy_score(test['labels'], predict)
ac_score
cl_report = metrics.classification_report(test['labels'], predict)
print(cl_report)
to_csv("train", 60000)
data = load_csv("./mnist/train.csv")
test = load_csv("./mnist/t10k.csv")
clf = svm.SVC()
clf.fit(data['images'], data['labels'])
predict = clf.predict(test["images"])
ac_score = metrics.accuracy_score(test['labels'], predict)
print('정답률 = ', ac_score)
cl_report = metrics.classification_report(test['labels'], predict)
print(cl_report)
from PIL import Image
import PIL.ImageOps as ops
img = Image.open(os.path.join(savepath, "test.bmp"))
img
img.size # (rows, cols)
img.getdata() # pixel 데이터
list(img.getdata())[:10] # (R,G,B) 채널
len(list(img.getdata())) # pixel의 개수 rows x cols (300x300)
mono8img = img.convert('L')
mono8img
invImg = ops.invert(mono8img)
invImg
resizeImg = invImg.resize((28,28))
resizeImg
print(list(resizeImg.getdata())) # 0 ~ 255
dataImg = list(map(lambda n: int(n)/256, list(resizeImg.getdata())))
print(dataImg)
clf.predict([dataImg])