根據我上一篇文章下載完MNIST資料集後,下一步就是看看keras是如何對它進行分類的。
參考部落格:
http://blog.csdn.net/vs412237401/article/details/51983440
之際複製該blog中的代碼發現在我這兒運行不通,初步判斷是因為Window和Linux系統路徑方面差別,處理有點兒問題,所以對此修改了一點
先看原文:
def load_mnist(path, kind='train'): """Load MNIST data from `path`""" labels_path = os.path.join(path, '%s-labels-idx1-ubyte' % kind) images_path = os.path.join(path, '%s-images-idx3-ubyte' % kind) with open(labels_path, 'rb') as lbpath: magic, n = struct.unpack('>II', lbpath.read(8)) labels = np.fromfile(lbpath, dtype=np.uint8) with open(images_path, 'rb') as imgpath: magic, num, rows, cols = struct.unpack(">IIII", imgpath.read(16)) images = np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784) return images, labels X_train, y_train = load_mnist('../data', kind='train') print('Rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1])) X_test, y_test = load_mnist('../data', kind='t10k') print('Rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1])) 我的理解是他把MNIST資料集檔案直接存放在該python工程檔案夾下data檔案夾內了。
對於windows使用者,感覺上述代碼問題點在於:
1.load_mnist('../data', kind='train'),對於window系統,分隔字元應該是 \,然而即使改了這個地方,仍然行不通,不知道是不是前面路徑縮寫的原因;
2.把上面的路徑不用簡寫,完整寫出來,並在字串前加r,仍然行不通。。。錯誤出現在with open(labels_path, 'rb') as lbpath:
3.即使路徑手動調出來了,labels_path = os.path.join(path, '%s-labels-idx1-ubyte' % kind),這句給出的是你的壓縮包的檔案路徑,讀出來的是壓縮包,也不對。magic, num, rows, cols = struct.unpack(">IIII", imgpath.read(16))讀出的參數是錯的。
鑒於以上問題調了半天,想出以下解決對策
1.將MNIST解壓縮後的檔案直接放在該python工程檔案夾下,並修改上述代碼,以下直接貼出修改後的全部代碼
import osimport structimport numpy as npdef load_mnist( kind='train'): """Load MNIST data from `path`""" labels_path = ('%s-labels.idx1-ubyte' % kind) images_path = ('%s-images.idx3-ubyte' % kind) with open(labels_path, 'rb') as lbpath: magic, n = struct.unpack('>II', lbpath.read(8)) labels = np.fromfile(lbpath, dtype=np.uint8) print magic, n,labels with open(images_path, 'rb') as imgpath: magic, num, rows, cols = struct.unpack(">IIII", imgpath.read(16)) print magic, num, rows, cols images = np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784) #28*28=784 return images, labelsX_train, y_train = load_mnist( kind='train')print('Rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1]))X_test, y_test = load_mnist( kind='t10k')print('Rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1]))import theanotheano.config.floatX = 'float32'X_train = X_train.astype(theano.config.floatX)X_test = X_test.astype(theano.config.floatX)from keras.utils import np_utilsprint('First 3 data: ', X_train[:3])print('First 3 labels: ', y_train[:3])y_train_ohe = np_utils.to_categorical(y_train) #change numbers to 0/1 mode,for example change 5 to [0 0 0 0 1 0 0 0 0 0]print('First 3 labels (one-hot):', y_train_ohe[:3])from keras.models import Sequentialfrom keras.layers.core import Densefrom keras.optimizers import SGDnp.random.seed(1)model = Sequential()model.add(Dense(input_dim=X_train.shape[1], output_dim=50, init='uniform', activation='tanh'))model.add(Dense(input_dim=50, output_dim=50, init='uniform', activation='tanh'))model.add(Dense(input_dim=50, output_dim=y_train_ohe.shape[1], init='uniform', activation='softmax'))sgd = SGD(lr=0.001, decay=1e-7, momentum=.9)model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=["accuracy"])model.fit(X_train, y_train_ohe, nb_epoch=50, batch_size=300, verbose=1, validation_split=0.1)y_train_pred = model.predict_classes(X_train, verbose=0)print('First 3 predictions: ', y_train_pred[:3])train_acc = np.sum(y_train == y_train_pred, axis=0) / X_train.shape[0]print('Training accuracy: %.8f%%' % (train_acc * 100))y_test_pred = model.predict_classes(X_test, verbose=0)test_acc = np.sum(y_test == y_test_pred, axis=0) / X_test.shape[0]print('Test accuracy: %.8f%%' % (test_acc * 100))
以上代碼可以順利跑完了,但是跑出來的分類結果卻跟期待的不太一樣
53400/54000 [============================>.] - ETA: 0s - loss: 0.2002 - acc: 0.940953700/54000 [============================>.] - ETA: 0s - loss: 0.2003 - acc: 0.940954000/54000 [==============================] - 2s - loss: 0.2002 - acc: 0.9409 - val_loss: 0.1840 - val_acc: 0.9478('First 3 predictions: ', array([3, 0, 4]))Training accuracy: 0.00000000%Test accuracy: 0.00000000%
特意將準確率列印到小數點後8位,準確率居然為0。。。。what happened。。
難道標籤錯亂。。有點兒方,尋找答案中。。。。
後記:
經過debug,發現問題出在我的python除法運算上,兩個整數相除,還是整數。python版本導致,貌似3.0以上版本沒有此問題。
如果想得到float結果,將其中一個強行轉化為float型,如
1/2 = 0
1/float(2)=0.5
其實有兩種處理方法,請參考下文:
http://blog.csdn.net/yygydjkthh/article/details/39377265
最後5行代碼應該修正為:
train_acc = np.sum(y_train == y_train_pred, axis=0) /float( X_train.shape[0])print('Training accuracy: %.8f%%' % (train_acc * 100))y_test_pred = model.predict_classes(X_test, verbose=0)test_acc = np.sum(y_test == y_test_pred, axis=0) / float(X_test.shape[0])print('Test accuracy: %.8f%%' % (test_acc * 100))
至此,完成使用keras對MNIST手寫數字分類執行個體的運行。
接下來,繼續學習理論知識和python的使用。