Udacity机器人软件工程师课程笔记(二十八) - 卷积神经网络实例 - Fashion-MNIST数据集
1.Fashion-MNIST數(shù)據(jù)集
Fashion-MNIST數(shù)據(jù)集包括一個(gè)包含60,000個(gè)示例的訓(xùn)練集和一個(gè)包含10,000個(gè)示例的測試集。每個(gè)示例是一個(gè)28x28灰度圖像,與來自以下10個(gè)類的標(biāo)簽相關(guān)聯(lián):
- T恤/上衣
- 褲子
- 套衫
- 連衣裙
- 外套
- 涼鞋
- 襯衫
- 運(yùn)動(dòng)鞋
- 包
- 短靴
Source: https://github.com/zalandoresearch/fashion-mnist/
由于給的樣例是.ipynb格式的,因?yàn)槲伊?xí)慣使用pycharm,因此我將程序改到.py格式,但是由于內(nèi)容較多,只能一點(diǎn)一點(diǎn)來研究相關(guān)程序。
2.cnn_preprocess.py
這個(gè)程序預(yù)處理數(shù)據(jù),給神經(jīng)網(wǎng)絡(luò)提供訓(xùn)練數(shù)據(jù)。
(1)探索數(shù)據(jù)
import helper
import numpy as np
# 模塊 pickle 實(shí)現(xiàn)了對(duì)一個(gè) Python 對(duì)象結(jié)構(gòu)的二進(jìn)制序列化和反序列化。
# 這里用來讀取fashion-mnist.p程序
import picklefilename = "fashion-mnist.p"sample_id = 17
helper.display_stats(filename, sample_id)
這是helper.py中的程序:
def _load_label_names():"""從文件中加載標(biāo)簽名稱"""return ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle_boot']def load_dataset(dataset_folder_path):"""加載訓(xùn)練和測試數(shù)據(jù)集"""with open(dataset_folder_path, mode='rb') as file:pickle_data = pickle.load(file)# 整理訓(xùn)練和測試數(shù)據(jù)train_features = pickle_data[0].reshape((len(pickle_data[0]), 1, 28, 28)).transpose(0, 2, 3, 1)train_labels = pickle_data[1]test_features = pickle_data[2].reshape((len(pickle_data[2]), 1, 28, 28)).transpose(0, 2, 3, 1)test_labels = pickle_data[3] return train_features, train_labels, test_features, test_labelsdef display_stats(dataset_folder_path, sample_id):"""顯示數(shù)據(jù)集的狀態(tài)"""train_features, train_labels, test_features, test_labels = load_dataset(dataset_folder_path)if not (0 <= sample_id < len(train_features)):print('{} samples in training set. {} is out of range.'.format(len(train_features), sample_id))return Noneprint('Samples: {}'.format(len(train_features)))# 用于統(tǒng)計(jì)相關(guān)標(biāo)簽數(shù)據(jù)print('Label Counts: {}'.format(dict(zip(*np.unique(train_labels, return_counts=True)))))print('First 20 Labels: {}'.format(train_labels[:20]))sample_image = train_features[sample_id]sample_label = train_labels[sample_id]label_names = _load_label_names()print('\nExample of Image {}:'.format(sample_id))print('Image - Min Value: {} Max Value: {}'.format(sample_image.min(), sample_image.max()))print('Image - Shape: {}'.format(sample_image.shape))print('Label - Label Id: {} Name: {}'.format(sample_label, label_names[sample_label]))plt.axis('off')plt.imshow(sample_image.squeeze(), cmap="gray")plt.show()
輸出如下:
Samples: 60000
Label Counts: {0: 6000, 1: 6000, 2: 6000, 3: 6000, 4: 6000, 5: 6000, 6: 6000, 7: 6000, 8: 6000, 9: 6000}
First 20 Labels: [9 0 0 3 0 2 7 2 5 5 0 9 5 5 7 9 1 0 6 4]Example of Image 17:
Image - Min Value: 0 Max Value: 254
Image - Shape: (28, 28, 1)
Label - Label Id: 0 Name: t-shirt
(2)數(shù)據(jù)預(yù)處理
實(shí)現(xiàn)normalize函數(shù)以獲取圖像數(shù)據(jù)x,并將其作為歸一化的Numpy數(shù)組返回。值應(yīng)在0到1范圍內(nèi)。返回對(duì)象的形狀應(yīng)與x相同。
import problem_unittests as tests
def normalize(x):"""將0到1范圍內(nèi)的樣本圖像數(shù)據(jù)列表進(jìn)行規(guī)范化"""# TODO: Implement Functionoutput = np.array([image/255 for image in x])return output
(3)one-hot碼
實(shí)現(xiàn)該one_hot_encode功能。輸入,x是標(biāo)簽列表。實(shí)現(xiàn)該功能以將標(biāo)簽列表作為One-Hot編碼的Numpy數(shù)組返回。標(biāo)簽的可能值為0到9。“one-hot code”功能應(yīng)在每次調(diào)用one_hot_encode之間為每個(gè)值返回相同的編碼。
def one_hot_encode(x):"""一個(gè)獨(dú)熱碼的樣本標(biāo)簽列表。為每個(gè)標(biāo)簽返回一個(gè)獨(dú)熱碼向量。"""# TODO: Implement Functionone_hot = np.eye(10)[x]return None
(4)預(yù)處理和保存
預(yù)處理所有數(shù)據(jù),并將其保存,是由10%的訓(xùn)練數(shù)據(jù)進(jìn)行驗(yàn)證。
def _preprocess_and_save(normalize, one_hot_encode, features, labels, filename):"""對(duì)數(shù)據(jù)進(jìn)行預(yù)處理并保存到文件中"""features = normalize(features)labels = one_hot_encode(labels)pickle.dump((features, labels), open(filename, 'wb'))def preprocess_and_save_data(dataset_folder_path, normalize, one_hot_encode):"""預(yù)處理訓(xùn)練和驗(yàn)證數(shù)據(jù)"""valid_features = []valid_labels = []train_features, train_labels, test_features, test_labels = load_dataset(dataset_folder_path)validation_count = int(len(train_features) * 0.1)# 對(duì)新的培訓(xùn)數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,train_features[:-validation_count],train_labels[:-validation_count],'preprocess_train' + '.p')# 使用部分訓(xùn)練batch進(jìn)行驗(yàn)證valid_features.extend(train_features[-validation_count:])valid_labels.extend(train_labels[-validation_count:])# 對(duì)所有驗(yàn)證數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,np.array(valid_features),np.array(valid_labels),'preprocess_validation.p')# 對(duì)所有測試數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,np.array(test_features),np.array(test_labels),'preprocess_test.p')
完整cnn_preprocess.py程序
import helper
import numpy as np
import problem_unittests as tests
import picklefilename = "fashion-mnist.p"def normalize(x):"""將0到1范圍內(nèi)的樣本圖像數(shù)據(jù)列表進(jìn)行歸一化"""output = np.array([image / 255 for image in x])return outputdef one_hot_encode(x):"""一個(gè)獨(dú)熱碼的樣本標(biāo)簽列表。為每個(gè)標(biāo)簽返回一個(gè)獨(dú)熱碼向量。"""one_hot = np.eye(10)[x]return one_hot# 對(duì)所有數(shù)據(jù)進(jìn)行預(yù)處理
helper.preprocess_and_save_data(filename, normalize, one_hot_encode)
3.cnn_train.py
import helper
import numpy as np
import problem_unittests as tests
import pickle
import tensorflow as tfdef neural_net_image_input(image_shape):"""返回一批圖像輸入的張量"""input_image = tf.placeholder(tf.float32, shape=(None, *image_shape), name="x")return input_imagedef neural_net_label_input(n_classes):"""返回一個(gè)batch標(biāo)簽輸入的張量"""input_label = tf.placeholder(tf.int32, shape=(None, n_classes), name="y")return input_labeldef neural_net_keep_prob_input():"""返回一個(gè)保持概率的張量"""keep_prob = tf.placeholder(tf.float32, name="keep_prob")return keep_probdef conv2d_maxpool(x_tensor, conv_num_outputs, conv_ksize, conv_strides, pool_ksize, pool_strides):"""對(duì)x_張量應(yīng)用卷積和最大池化"""filter_size = [conv_ksize[0], conv_ksize[1], x_tensor.get_shape().as_list()[3], conv_num_outputs]weight = tf.Variable(tf.truncated_normal(filter_size, stddev=0.01))conv = tf.nn.conv2d(x_tensor, weight, [1, conv_strides[0], conv_strides[1], 1], padding="SAME")bias = tf.Variable(tf.zeros([conv_num_outputs]))conv = tf.nn.bias_add(conv, bias)conv = tf.nn.relu(conv)conv = tf.nn.max_pool(conv, [1, pool_ksize[0], pool_ksize[1], 1], [1, pool_strides[0], pool_strides[1], 1],padding="SAME")return convdef flatten(x_tensor):"""將x_張量壓平到(批處理大小,壓平圖像大小),以方便接下來構(gòu)建全連接層"""conv_flatten = tf.contrib.layers.flatten(x_tensor)return conv_flattendef fully_conn(x_tensor, num_outputs):""":使用權(quán)值和偏置將一個(gè)全連接層應(yīng)用到x_tensor上"""fc_layer = tf.layers.dense(x_tensor, num_outputs, activation=tf.nn.relu)return fc_layerdef output(x_tensor, num_outputs):"""使用權(quán)值和偏置應(yīng)用一個(gè)輸出層"""output_layer = tf.layers.dense(x_tensor, num_outputs, activation=None)return output_layerdef conv_net(x, keep_prob):"""創(chuàng)建一個(gè)卷積神經(jīng)網(wǎng)絡(luò)模型: x: 持有圖像數(shù)據(jù)的占位張量。: keep_prob: 持有dropout的占位張量保持概率。: return:表示logits的張量"""conv_layer1 = conv2d_maxpool(x, conv_num_outputs=64, conv_ksize=(5, 5), conv_strides=(2, 2),pool_ksize=(2, 2), pool_strides=(2, 2))conv_layer1 = tf.nn.dropout(conv_layer1, keep_prob)conv_layer2 = conv2d_maxpool(conv_layer1, conv_num_outputs=128, conv_ksize=(3, 3), conv_strides=(2, 2),pool_ksize=(2, 2), pool_strides=(2, 2))conv_layer2 = tf.nn.dropout(conv_layer2, keep_prob)flat_layer = flatten(conv_layer2)fc_layer1 = fully_conn(flat_layer, 256)fc_layer2 = fully_conn(fc_layer1, 128)fc_layer3 = fully_conn(fc_layer2, 64)output_layer = output(fc_layer3, 10)return output_layerdef train_neural_network(session, optimizer, keep_probability, feature_batch, label_batch):"""對(duì)批處理圖像和標(biāo)簽的會(huì)話進(jìn)行優(yōu)化: session: 當(dāng)前TensorFlow會(huì)話: optimizer: TensorFlow優(yōu)化函數(shù): keep_probability: 保持概率: feature_batch: 批量Numpy圖像數(shù)據(jù): label_batch: 批量Numpy標(biāo)簽數(shù)據(jù)"""session.run(optimizer, feed_dict={x: feature_batch, y: label_batch, keep_prob: keep_probability})def print_stats(session, feature_batch, label_batch, cost, accuracy):"""打印關(guān)于損失和驗(yàn)證準(zhǔn)確性的信息: session: 當(dāng)前TensorFlow會(huì)話: feature_batch: 批量Numpy圖像數(shù)據(jù): label_batch: 批量Numpy標(biāo)簽數(shù)據(jù): cost: TensorFlow成本函數(shù): accuracy: TensorFlow精度函數(shù)"""l = session.run(cost, feed_dict={x: feature_batch, y: label_batch, keep_prob: 1.0})validation_accuracy = session.run(accuracy, feed_dict={x: valid_features, y: valid_labels, keep_prob: 1.0})print("The loss is: {0}, and the Validation Accuracy is: {1}".format(l, validation_accuracy))valid_features, valid_labels = pickle.load(open('preprocess_validation.p', mode='rb'))# 可調(diào)整參數(shù)
epochs = 5
batch_size = 64
keep_probability = 0.5# gpu參數(shù)
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)# 刪除以前的 weights, bias, inputs, etc..
tf.reset_default_graph()# Inputs
x = neural_net_image_input((28, 28, 1))
y = neural_net_label_input(10)
keep_prob = neural_net_keep_prob_input()# Model
logits = conv_net(x, keep_prob)# 命名為logits張量,這樣就可以在訓(xùn)練后從磁盤加載
logits = tf.identity(logits, name='logits')# 損失和優(yōu)化器
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.AdamOptimizer().minimize(cost)# 正確率
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32), name='accuracy')# 模型保存路徑
save_model_path = './image_classification'with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:# 初始化變量sess.run(tf.global_variables_initializer())# 訓(xùn)練周期for epoch in range(epochs):for batch_features, batch_labels in helper.load_preprocess_training_batch(batch_size):train_neural_network(sess, optimizer, keep_probability, batch_features, batch_labels)print('Epoch {:>2}: '.format(epoch + 1), end='')print_stats(sess, batch_features, batch_labels, cost, accuracy)# 保存模型saver = tf.train.Saver()save_path = saver.save(sess, save_model_path)
其輸出為:
Epoch 1: The loss is: 0.5249987244606018, and the Validation Accuracy is: 0.8186666369438171
Epoch 2: The loss is: 0.4325884282588959, and the Validation Accuracy is: 0.8506666421890259
Epoch 3: The loss is: 0.38672173023223877, and the Validation Accuracy is: 0.8629999756813049
Epoch 4: The loss is: 0.34116020798683167, and the Validation Accuracy is: 0.8736666440963745
Epoch 5: The loss is: 0.311458021402359, and the Validation Accuracy is: 0.8741666674613953
之后我們就可以加載訓(xùn)練好的模型來測試其效果了。
4.cnn_test.py
我們使用cnn_test.py函數(shù)來確定最終的正確率,并畫出判斷結(jié)果。
import tensorflow as tf
import pickle
import helper
import random
import matplotlib.pyplot as plt
# 可調(diào)整參數(shù)
epochs = 5
batch_size = 64
keep_probability = 0.5
save_model_path = './image_classification'
n_samples = 4
top_n_predictions = 3def test_model():"""根據(jù)測試數(shù)據(jù)集測試保存的模型"""test_features, test_labels = pickle.load(open('preprocess_test.p', mode='rb'))loaded_graph = tf.Graph()config = tf.ConfigProto(device_count={'GPU': 0})with tf.Session(config=config, graph=loaded_graph) as sess:# 加載模型loader = tf.train.import_meta_graph(save_model_path + '.meta')loader.restore(sess, save_model_path)# 從加載的模型中獲取張量loaded_x = loaded_graph.get_tensor_by_name('x:0')loaded_y = loaded_graph.get_tensor_by_name('y:0')loaded_keep_prob = loaded_graph.get_tensor_by_name('keep_prob:0')loaded_logits = loaded_graph.get_tensor_by_name('logits:0')loaded_acc = loaded_graph.get_tensor_by_name('accuracy:0')# 批量獲取內(nèi)存限制的準(zhǔn)確性test_batch_acc_total = 0test_batch_count = 0for test_feature_batch, test_label_batch in helper.batch_features_labels(test_features, test_labels,batch_size):test_batch_acc_total += sess.run(loaded_acc,feed_dict={loaded_x: test_feature_batch, loaded_y: test_label_batch, loaded_keep_prob: 1.0})test_batch_count += 1print('Testing Accuracy: {}\n'.format(test_batch_acc_total / test_batch_count))# 打印隨機(jī)抽樣random_test_features, random_test_labels = tuple(zip(*random.sample(list(zip(test_features, test_labels)), n_samples)))random_test_predictions = sess.run(tf.nn.top_k(tf.nn.softmax(loaded_logits), top_n_predictions),feed_dict={loaded_x: random_test_features, loaded_y: random_test_labels, loaded_keep_prob: 1.0})helper.display_image_predictions(random_test_features, random_test_labels, random_test_predictions)test_model()
plt.show()
輸出結(jié)果如下:
Testing Accuracy: 0.8765923566878981
5.helper.py
因?yàn)槭褂胮ycharm的關(guān)系,我對(duì)helper.py進(jìn)行了少許更改。
import pickle
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelBinarizerdef _load_label_names():"""從文件中加載標(biāo)簽名稱"""return ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle_boot']def load_dataset(dataset_folder_path):"""加載訓(xùn)練和測試數(shù)據(jù)集"""with open(dataset_folder_path, mode='rb') as file:pickle_data = pickle.load(file)train_features = pickle_data[0].reshape((len(pickle_data[0]), 1, 28, 28)).transpose(0, 2, 3, 1)print(train_features.shape)train_labels = pickle_data[1]test_features = pickle_data[2].reshape((len(pickle_data[2]), 1, 28, 28)).transpose(0, 2, 3, 1)test_labels = pickle_data[3] return train_features, train_labels, test_features, test_labelsdef display_stats(dataset_folder_path, sample_id):"""顯示數(shù)據(jù)集的狀態(tài)"""train_features, train_labels, test_features, test_labels = load_dataset(dataset_folder_path)if not (0 <= sample_id < len(train_features)):print('{} samples in training set. {} is out of range.'.format(len(train_features), sample_id))return Noneprint('Samples: {}'.format(len(train_features)))print('Label Counts: {}'.format(dict(zip(*np.unique(train_labels, return_counts=True)))))print('First 20 Labels: {}'.format(train_labels[:20]))sample_image = train_features[sample_id]sample_label = train_labels[sample_id]label_names = _load_label_names()print('\nExample of Image {}:'.format(sample_id))print('Image - Min Value: {} Max Value: {}'.format(sample_image.min(), sample_image.max()))print('Image - Shape: {}'.format(sample_image.shape))print('Label - Label Id: {} Name: {}'.format(sample_label, label_names[sample_label]))plt.axis('off')plt.imshow(sample_image.squeeze(), cmap="gray")plt.show()def _preprocess_and_save(normalize, one_hot_encode, features, labels, filename):"""對(duì)數(shù)據(jù)進(jìn)行預(yù)處理并保存到文件中"""features = normalize(features)labels = one_hot_encode(labels)pickle.dump((features, labels), open(filename, 'wb'))def preprocess_and_save_data(dataset_folder_path, normalize, one_hot_encode):"""預(yù)處理訓(xùn)練和驗(yàn)證數(shù)據(jù)"""valid_features = []valid_labels = []train_features, train_labels, test_features, test_labels = load_dataset(dataset_folder_path)validation_count = int(len(train_features) * 0.1)# 對(duì)新的培訓(xùn)數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,train_features[:-validation_count],train_labels[:-validation_count],'preprocess_train' + '.p')# 使用部分訓(xùn)練batch進(jìn)行驗(yàn)證valid_features.extend(train_features[-validation_count:])valid_labels.extend(train_labels[-validation_count:])# 對(duì)所有驗(yàn)證數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,np.array(valid_features),np.array(valid_labels),'preprocess_validation.p')# 對(duì)所有測試數(shù)據(jù)進(jìn)行預(yù)處理和保存_preprocess_and_save(normalize,one_hot_encode,np.array(test_features),np.array(test_labels),'preprocess_test.p')def batch_features_labels(features, labels, batch_size):"""將特征和標(biāo)簽分成批次"""assert features is not None, 'features is None!'assert labels is not None, 'labels is None!'for start in range(0, len(features), batch_size):end = min(start + batch_size, len(features))yield features[start:end], labels[start:end]def load_preprocess_training_batch(batch_size):"""載預(yù)處理的訓(xùn)練數(shù)據(jù),并以<batch_size>或更小的批量返回"""filename = 'preprocess_train' + '.p'features, labels = pickle.load(open(filename, mode='rb'))# 返回批量<batch_size>或更小的訓(xùn)練數(shù)據(jù)return batch_features_labels(features, labels, batch_size)def display_image_predictions(features, labels, predictions):n_classes = 10label_names = _load_label_names()label_binarizer = LabelBinarizer()label_binarizer.fit(range(n_classes))label_ids = label_binarizer.inverse_transform(np.array(labels))fig, axies = plt.subplots(nrows=4, ncols=2)fig.tight_layout()fig.suptitle('Softmax Predictions', fontsize=20, y=1.1)n_predictions = 3margin = 0.05ind = np.arange(n_predictions)width = (1. - 2. * margin) / n_predictionsfor image_i, (feature, label_id, pred_indicies, pred_values) in enumerate(zip(features, label_ids, predictions.indices, predictions.values)):pred_names = [label_names[pred_i] for pred_i in pred_indicies]correct_name = label_names[label_id]axies[image_i][0].imshow(feature.squeeze(), cmap='gray')axies[image_i][0].set_title(correct_name)axies[image_i][0].set_axis_off()axies[image_i][1].barh(ind + margin, pred_values[::-1], width)axies[image_i][1].set_yticks(ind + margin)axies[image_i][1].set_yticklabels(pred_names[::-1])axies[image_i][1].set_xticks([0, 0.5, 1.0])
以下是所有本次程序使用或者建立的數(shù)據(jù),其中problem_unittests.py是一個(gè)關(guān)于某些模塊的測試程序,在主要程序中使用不到,只做編寫程序時(shí)測試之用。
接下來便是完全卷積網(wǎng)絡(luò)了。
總結(jié)
以上是生活随笔為你收集整理的Udacity机器人软件工程师课程笔记(二十八) - 卷积神经网络实例 - Fashion-MNIST数据集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Udacity机器人软件工程师课程笔记(
- 下一篇: Udacity机器人软件工程师课程笔记(