Udacity深度学习DeepLearning课程作业1-notMNIST

前言:Udacity上有一个免费的《深度学习单项课程。虽然是免费的课程,但保持了Udacity一贯的水准。其课程主要是神经网络的实际应用。因此,该课程能较好的提升实际项目水平。但是,如果需要提升理论水平,则可以同步学习Coursera上hinton的《机器学习》课程,里面有很深入和系统的讲解了深度学习的所有基础理论。
该课程的入门作业是notMnist字符的分类。其中,notMnist数据是一组按字符分类的图像文件夹,其共有A、B、C、D、E、F、G、H、I、J共10个文件夹。其中,每一张图像均维28*28。完成该作业能够夯实两个重要基础:1是实现了一个分类项目的所有流程;2是实现对数据进行归一化、随机化和数据清洗。这是非常关键的预处理步骤。其具体的处理方法如下:
预处理方法 对于一组数据,第一步并不是将数据马上用于训练模型,而是要对数据进行预处理。预处理的步骤主要包括:

  • (1)归一化 图像数据的取值范围是[0,255],原始的样本值一般都是过
    大的。因此,要使用如下公式对图像数据进行归一化。 x= (x-128)/255
    样本数值较大还存在2个不利于学习的影响:1是参数训练时存在多个样本的求和,因此,存在数据的截断以及大小数据相加带来的偏差。2是样本值过大影响到模型的初始化。模型的初始化时需要神经网络的分类尽可能的随机,即logit值越小越好,这样softmax的值才能趋向与均值。但是,如果样本的值较大,即使参数w是随机的小值,但由于x太大,导致logit的值较大,经由softmax计算后的结果趋向于1和0,影响初始化的随机性。
  • (2)随机化 由于最开始的样本数据是以文件夹区分好类别的,但是,在训练时,数据需要以随机化的形式输入,否则训练难以稳定。
  • (3)数据清洗 由于训练集、验证集和测试集中可能有数据是重复的。如果重复得太多,那么最后得分类结果得真实性会受到影响。因此,需要对3个样本集进行数据得清洗,使其没有相互没有交集。
    其作业是挂在jupyter上并由多个代码块组成,包括从网页上下载数据、解压数据、数据预处理、模型训练和测试等多个代码块。下面就按照代码块的顺序进行讲解和完成作业。

代码块1-载入模块

from __future__ import print_function
import matplotlib.pyplot as plt#绘图模块
import numpy as np#矩阵模块
import os
import sys
import tarfile#文件解压模块
from IPython.display import display, Image
from scipy import ndimage
from sklearn.linear_model import LogisticRegression#回归模块
from six.moves.urllib.request import urlretrieve#下载模块
from six.moves import cPickle as pickle#压缩模块
# Config the matplotlib backend as plotting inline in IPython
%matplotlib inline

代码块2-下载文件

注:由于该网络地址下载数据太慢,因此,建议不使用该函数进行数据下载。而是自己将数据下载到本地文件夹中。下载的网址如下:

http://yaroslavvb.com/upload/notMNIST/

代码块3-解压文件并存储解压后的文件地址

由于该代码块的解压速度太慢,因此,利用解压工具解压该文件。并将解压后的文件夹地址存储起来,为后续的调用做好准备即可。下文代码删除了作业中解压部分的代码,而保留存储文件夹路径的代码。

num_classes = 10
np.random.seed(133)

#创建每一个类别的文件夹名
def maybe_extract(filename, force=False):
  root = os.path.splitext(os.path.splitext(filename)[0])[0]  # remove .tar.gz
  data_folders = [os.path.join(root, d) for d in sorted(os.listdir(root))
    if os.path.isdir(os.path.join(root, d))]
  if len(data_folders) != num_classes:
    raise Exception(
      'Expected %d folders, one per class. Found %d instead.' % (
        num_classes, len(data_folders)))
  return data_folders

#本地存储notMnist数据的的文件夹
train_filename = 'C:\\ProgramInstall\\PythonCode\\notMNIST_large'  
test_filename = 'C:\\ProgramInstall\\PythonCode\\notMNIST_small'
train_folders = maybe_extract(train_filename)
test_folders = maybe_extract(test_filename)

问题1-显示解压后的图像

#Problem1: Display a sample of the images that we just download
nums_image_show = 2#显示的图像张数
for index_class in range(num_classes):
    #i from 0 to 9
    imagename_list = os.listdir(train_folders[index_class])
    imagename_list_indice = imagename_list[0:nums_image_show]
    for index_image in range(nums_image_show):
        path = train_folders[index_class] +'\\' + imagename_list_indice[index_image]
        display(Image(filename = path))

其结果如下图所示:

代码块4-加载和归一化图像数据

该代码块主要实现了3个功能:1是将本地硬盘中的每类图像文件夹中的图像数据读到一个3维的dataset对象中,第1维是图像个数索引,其余2维则是图像数据。其中主要是利用了scipy模块中的ndarray对象兑取硬盘中的图像数据。2是将读取到的图像数据按照上文所述的公式进行了归一化。3是将ndarray对象打包为pickle格式并存储在工作目录下,每个类别有一个.pickle文件。并将打包后.pickle文件的地址存储为train_datasets和test_datasets返回。

注:将数据打包为.pickle文件更便于数据的调用与处理。因为,图像的原始数据是使用循环打入到对象中的,如果每次使用图像数据均需要循环来加载,这样加大了代码量。而对.pickle文件只需要读取一次即可,而无需使用循环。

问题2 显示从pickle文件中读取的图像

#Problem2 Displaying a sample of the labels and images from the ndarray

# Config the matplotlib backend as plotting inline in IPython
%matplotlib inline
import matplotlib.pyplot as plt
def load_and_displayImage_from_pickle(data_filename_set,NumClass,NumImage):
    if(NumImage <= 0):
        print('NumImage <= 0')
        return
    plt.figure('subplot')
    for index,pickle_file in enumerate(data_filename_set):
        with open(pickle_file,'rb') as f:
            data = pickle.load(f)
            ImageList = data[0:NumImage,:,:]
            for i,Image in enumerate(ImageList):
                #NumClass代表类别,每个类别一行;NumImage代表每个类显示的图像张数
                plt.subplot(NumClass, NumImage, index*NumImage+i+1)
                plt.imshow(Image)
            index = index+1        
#显示10类,每类显示5张图片        
load_and_displayImage_from_pickle(train_datasets,10,5)    
load_and_displayImage_from_pickle(test_datasets,10,5) 

其结果如下图所示:

问题3-检测数据是否平衡

数据是否平衡的意思是各类样本的大小是否相当。

def show_sum_of_different_class(data_filename_set):
    plt.figure(1)
    #read .pickle file
    sumofdifferentclass = []
    for pickle_file in data_filename_set:
        with open(pickle_file,'rb') as f:
            data = pickle.load(f)
            print(len(data))
            sumofdifferentclass.append(len(data))

    #show the data
    x = range(10)
    plt.bar(x,sumofdifferentclass)    
    plt.show()

print('train_datasets:\n')    
show_sum_of_different_class(train_datasets)  
print('test_datasets:\n')    
show_sum_of_different_class(test_datasets) 

其结果如下图所示:

代码块5-将不同类别的数据混合并将得到验证集

该模块实现了2个功能:1是将不同类别的数据进行混合。之前是每个类别一个数据对象。现在,为了便于后续的训练,需将不同类别的数据存储为一个大的数据对象,即该对象同时包含A、B…J共个类别的样本。2是从训练集中提取一部分作为验证集。

代码块6-将混合后的数据进行随机化

上一步只是将数据进行和混合并存储为一个大的数据对象,此步则将混合后的数据对象中的数据进行了随机化处理。只有随机化后的数据训练模型时才会有较为稳定的效果。

问题4 从验证混合后的数据

'''Problem4 Convince yourself that the data is still good after shuffling!
'''
#data_set是数据集,NumImage是显示的图像张数
def displayImage_from_dataset(data_set,NumImage):
    if(NumImage <= 0):
        print('NumImage <= 0')
        return
    plt.figure('subplot')
    ImageList = data_set[0:NumImage,:,:]
    for index,Image in enumerate(ImageList):
        #NumClass代表类别,每个类别一行;NumImage代表每个类显示的图像张数
        plt.subplot(NumImage//5+1, 5, index+1)
        plt.imshow(Image)
        index = index+1    
    plt.show()
displayImage_from_dataset(train_dat```
set,50)   

其结果如下图所示,下图也表明图像数据确实是不同类别随机分布的。

代码块7-将不同的样本及存为.pickle文件

问题5-数据清洗

一般来说,训练集、验证集和测试集中会有数据的重合,但是,如果重合的数据太多则会影响到测试结果的准确程度。因此,需要对数据进行清洗,使彼此之间步存在交集。

注:ndarray数据无法使用set的方式来求取交集。但如果使用循环对比的方式在数据量大的情况下会非常慢,因此,下文的做法使先将数据哈希化,再通过哈希的键值来判断数据是否相等。由于哈希的键值是字符串,因此比对起来效率会高很多。

#先使用hash
import hashlib

#使用sha的作用是将二维数据和哈希值之间进行一一对应,这样,通过比较哈希值就能将二维数组是否相等比较出来
def extract_overlap_hash_where(dataset_1,dataset_2):

    dataset_hash_1 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_1])
    dataset_hash_2 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_2])
    overlap = {}
    for i, hash1 in enumerate(dataset_hash_1):
        duplicates = np.where(dataset_hash_2 == hash1)
        if len(duplicates[0]):
            overlap[i] = duplicates[0]
    return overlap

#display the overlap
def display_overlap(overlap,source_dataset,target_dataset):
    overlap = {k: v for k,v in overlap.items() if len(v) >= 3}
    item = np.random.choice(list(overlap.keys()))
    imgs = np.concatenate(([source_dataset[item]],target_dataset[overlap[item][0:7]]))
    plt.suptitle(item)
    for i,img in enumerate(imgs):
        plt.subplot(2,4,i+1)
        plt.axis('off')
        plt.imshow(img)
    plt.show()

#数据清洗
def sanitize(dataset_1,dataset_2,labels_1):
    dataset_hash_1 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_1])
    dataset_hash_2 = np.array([hashlib.sha256(img).hexdigest() for img in dataset_2])
    overlap = []
    for i,hash1 in enumerate(dataset_hash_1):
        duplictes = np.where(dataset_hash_2 == hash1)
        if len(duplictes[0]):
            overlap.append(i)
    return np.delete(dataset_1,overlap,0),np.delete(labels_1, overlap, None)


overlap_test_train = extract_overlap_hash_where(test_dataset,train_dataset)
print('Number of overlaps:', len(overlap_test_train.keys()))
display_overlap(overlap_test_train, test_dataset, train_dataset)

test_dataset_sanit,test_labels_sanit = sanitize(test_dataset,train_dataset,test_labels)
print('Overlapping images removed from test_dataset: ', len(test_dataset) - len(test_dataset_sanit))

valid_dataset_sanit, valid_labels_sanit = sanitize(valid_dataset, train_dataset, valid_labels)
print('Overlapping images removed from valid_dataset: ', len(valid_dataset) - len(valid_dataset_sanit))

print('Training:', train_dataset.shape, train_labels.shape)
print('Validation:', valid_labels_sanit.shape, valid_labels_sanit.shape)
print('Testing:', test_dataset_sanit.shape, test_labels_sanit.shape)

pickle_file_sanit = 'notMNIST_sanit.pickle'
try:
    f = open(pickle_file_sanit,'wb')
    save = {
        'train_dataset':train_dataset,
        'train_labels': train_labels,
        'valid_dataset': valid_dataset,
        'valid_labels': valid_labels,
        'test_dataset': test_dataset,
        'test_labels': test_labels,
    }
    pickle.dump(save,f,pickle.HIGHEST_PROTOCOL)
    f.close()
except Exception as e:
  print('Unable to save data to', pickle_file, ':', e)
  raise

statinfo = os.stat(pickle_file_sanit)
print('Compressed pickle size:', statinfo.st_size)

问题6-模型训练

该模型是使用逻辑回归模型进行的训练。

def train_and_predict(sample_size):
    regr = LogisticRegression()
    X_train = train_dataset[:sample_size].reshape(sample_size,784)
    y_train = train_labels[:sample_size]
    regr.fit(X_train,y_train)
    X_test = test_dataset.reshape(test_dataset.shape[0],28*28)
    y_test = test_labels

    pred_labels = regr.predict(X_test)
    print('Accuracy:', regr.score(X_test, y_test), 'when sample_size=', sample_size)

for sample_size in [50,100,1000,5000,len(train_dataset)]:
    train_and_predict(sample_size)

后两个问题的答案来源与以下博文 http://www.hankcs.com/ml/notmnist.html

本文转载自http://blog.csdn.net/u013698770/article/details/54645326

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容