11.用深度学习方法为图像中的物体进行分类

这几个库现在更新了,用书上的会出错,未解决,建议直接学新的

# -*- coding: utf-8 -*-
"""
Created on Sun Oct 14 09:09:58 2018

@author: asus
"""
#11 用深度学习方法为图像中的物体进行分类
import os
batch1_filename = os.path.join(
        "E:\\books\Python数据挖掘入门与实践\用深度学习方法为图像中的物体进行分类",
        "cifar-10-batches-py", "data_batch_1")

def unpickle(file):
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict

batch1 = unpickle(batch1_filename)
#这一批图像文件读进来后为一个字典结构,包含numpy数组形式的图像数据、图像类别、文件名
#以及该批文件的简短说明(training batch 1 of 5 表示训练集共五批,这是第一批)。
#提取一张图像
image_index = 100
image = batch1[b'data'][image_index]
#图像数据格式与matplotlib(绘制图像)所使用的有所不同,因此,要改变数组形状,对矩阵进行
#转换。
image = image.reshape((32, 32, 3), order='F')
import numpy as np
image = np.rot90(image, -1)
#之后,就可以用matplotlib绘制图像
%matplotlib inline
from matplotlib import pyplot as plt
plt.imshow(image)

#11.3 深度神经网络
#深度神经网络和基本神经网络的差别在于规模大小。至少包含两层隐含层的神经网络被称为深度
#神经网络。实际工作者遇到的深度神经网络通常规模很大,每层神经元数量和层次都非常多。

#神经网络接收很基础的特征作为输出——就计算机视觉而言,输入为简单的像素值。神经网络算法
#把这些数据整合起来向网络中传输,在这个过程中,基本的特征组合为复杂的特征。计算机依靠
#它们进行分类。

#11.3.3 Theano简介
#Theano使用来创建和运行数学表达式的工具。在Theano中,我们定义函数要做什么而不是怎么做
#这样才能以最佳的方式对表达式进行求值。
#我们可以用Theano来定义函数,处理标量、数组和矩阵以及其他数学表达式。如我们可以创建计
#算直角三角形斜边长度的函数。
import theano
from theano import tensor as T
a = T.dscalar() #标量
b = T.dscalar()
c = T.sqrt(a ** 2 + b ** 2) #c是一个表达式,即不是函数,也不是数值

f = theano.function([a,b], c) #函数 f(3,4)
#这个函数接收a、b,返回经过计算得到的结果,也就是输出值c

#11.3.4 Lasagne简介
#该库是专门用来构建神经网络的,实践了几种比较新的神经网络层和组成这些层的模块
#内置网络层(Network-in-network layers):这些小神经网络比传统的神经网络层更容易解释。
#删除层(Dropout layers):训练过程随机删除神经元,放置产生神经网络常见的过拟合问题。
#噪音层(Noise layers):为神经元引入噪音,也是为了解决过拟合问题。

#本章使用卷积层(convolution layers, 层级结构模拟人类视觉工作原理)。卷积层使用少量的
#相互连接的神经元,分析一部分输入值,便于神经网络实现对数据的标准转换,比如对图像数据
#的转换。视觉分析实验,就是用卷积层对图像进行转换。

#用第一章的Iris数据集测试卷积神经网络
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data.astype(np.float32)
y_true = iris.target.astype(np.int32)
#Lasagne对数据类型有特殊要求,因此,需要把类别值转换为int32类型(在原始数据集中用int64
#类型存储)。
#把数据集分为训练集和测试集两部分
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y_true, random_state=14)

#接着,分别创建卷积神经网络各层。
#首先,创建输入层,其神经元数量跟数据集特征数量相同。可以指定每一批输入的数量(设置为10)
#这样Lasagne可以在训练阶段做些优化。
import lasagne
input_layer = lasagne.layers.InputLayer(shape=(10, X.shape[1]))
#接着创建隐含层。该层从输入层接收输入(由第一个参数指定),该层一共有12个神经元,使用非
#线性的sigmoid函数。
hidden_layer = lasagne.layers.DenseLayer(
        input_layer, num_units=12, 
        nonlinearity=lasagne.nonlinearities.sigmoid)
#接着创建输出层,它接受来自隐含层的输入,输出层共有三个神经元,使用非线性的softmax函
#数主要用于神经网络的最后一层。
output_layer = lasagne.layers.DenseLayer(hidden_layer, num_units=3,nonlinearity
                                         =lasagne.nonlinearities.softmax)

#为了训练刚创建的网络,我们需要定义几个Theano训练函数。在这之前,需要定义一个Theano表
#达式和函数。我们先来为神经网络的输入数据、输入结果和实际输出结果声明变量。
import theano.tensor as T
net_input = T.matrix('net_input')
net_output = output_layer.get_output(net_input)
true_output = T.ivector('true_output')
#接着定义损失函数,训练函数如何提升网络效果需要参考它的返回值——训练神经网络时,我们以
#最小化损失函数的返回值为前提。我们用类别交叉熵表示损失,这是一种衡量分类数据分类效果
#好坏的标准。损失函数表示的是网络的期望输出和实际输出两者之间的差距。
loss = T.mean(T.nnet.categorical_crossentropy(net_output, true_output))
#接着定义修改网络权重的函数。我们获取到网络的所有参数,创建调整权重的函数,使损失降低
#到最小。
all_params = lasagne.layers.get_all_params(output_layer)
updates = lasagne.updates.sgd(loss, all_params, learning_rate=0.1)
#最后,创建两个Theano函数,先是训练网络,然后获取网络的输出,以用于后续测试。
import theano
train = theano.function([net_input, true_output], loss, updates=updates)
get_output = theano.function([net_input], net_output)
#然后调用训练函数,在训练集上进行一轮迭代,接收训练数据,预测类别,与给定类别作比较,
#更新特征权重,以最小化损失。然后再进行1000次迭代,逐渐改进神经网络。
for n in range(1000):
    train(X_train, y_train)
#接着,对输出计算F值,以评估分类效果。
y_output = get_output(X_test)
import numpy as np
y_pred = np.argmax(y_output, axis=1)
from sklearn.metrics import f1_score
print(f1_score(y_test, y_pred))

#11.3.5 用nolearn实现神经网络
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from skimage.transform import resize
from skimage import transform as tf
from skimage.measure import label, regionprops
from sklearn.utils import check_random_state
from sklearn.preprocessing import OneHotEncoder
from sklearn.cross_validation import train_test_split

def create_captcha(text, shear=0, size=(100, 24)):
    im = Image.new("L", size, "black")
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype(r"Coval.otf", 22)
    draw.text((2, 2), text, fill=1, font=font)
    image = np.array(im)
    affine_tf = tf.AffineTransform(shear=shear)
    image = tf.warp(image, affine_tf)
    return image / image.max()


def segment_image(image):
    labeled_image = label(image > 0)
    subimages = []
    for region in regionprops(labeled_image):
        start_x, start_y, end_x, end_y = region.bbox
        subimages.append(image[start_x:end_x,start_y:end_y])
    if len(subimages) == 0:
        return [image,]
    return subimages

random_state = check_random_state(14)
letters = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
shear_values = np.arange(0, 0.5, 0.05)

def generate_sample(random_state=None):
    random_state = check_random_state(random_state)
    letter = random_state.choice(letters)
    shear = random_state.choice(shear_values)
    return create_captcha(letter, shear=shear, size=(20, 20)), letters.index(letter)
dataset, targets = zip(*(generate_sample(random_state) for i in range(3000)))
dataset = np.array(dataset, dtype='float')
targets =  np.array(targets)

onehot = OneHotEncoder()
y = onehot.fit_transform(targets.reshape(targets.shape[0],1))
y = y.todense().astype(np.float32)

dataset = np.array([resize(segment_image(sample)[0], (20, 20)) for sample in dataset])
X = dataset.reshape((dataset.shape[0], dataset.shape[1] * dataset.shape[2]))
X = X / X.max()
X = X.astype(np.float32)

X_train, X_test, y_train, y_test = \
    train_test_split(X, y, train_size=0.9, random_state=14)

#神经网络由一系列的层组成。在nolearn中实现神经网络,只徐定义它由Lasagne哪几种类型的层
#组成就行,跟PyBrain做法大同小异。
from lasagne import layers
layers=[
        ('input', layers.InputLayer),
        ('hidden', layers.DenseLayer),
        ('output', layers.DenseLayer),
        ]
from lasagne import updates
from nolearn.lasagne import NeuralNet
from lasagne.nonlinearities import sigmoid, softmax
net1 = NeuralNet(layers=layers,
                 input_shape=X.shape,
                 hidden_num_units=100,
                 output_num_units=26,
                 hidden_nonlinearity=sigmoid,
                 output_nonlinearity=softmax,
                 hidden_b=np.zeros((100,), dtype=np.float64),
                 update=updates.momentum,
                 update_learning_rate=0.9,
                 update_momentum=0.1,
                 regression=True,
                 max_epochs=1000,
                 )
net1.fit(X_train, y_train)

y_pred = net1.predict(X_test)
y_pred = y_pred.argmax(axis=1)
assert len(y_pred) == len(X_test)
if len(y_test.shape) > 1:
    y_test = y_test.argmax(axis=1)
print(f1_score(y_test, y_pred))

#11.4 GPU优化

#11.6 应用
#用CIFAR图像创建数据集。保留像素结构——像素的行列号。
import os
import numpy as np
batches = []
for i in range(1, 6):
    batch_filename = os.path.join(
        "E:\\books\Python数据挖掘入门与实践\用深度学习方法为图像中的物体进行分类",
        "cifar-10-batches-py", "data_batch_{}".format(i))
    batches.append(unpickle(batch_filename))
    break
#把每批次的图像文件一次添加到数据里。
X = np.vstack([batch[b'data'] for batch in batches])
#然后,把像素归一化,并将其强制转换为32位浮点型数据(GPU进行计算的虚拟机唯一支持的数据
#类型)。
X = np.array(X) / X.max()
X = X.astype(np.float32)
#类别的处理方法相同,只不过我们使用hstack,它为数组末尾追加一列数据。然后使用
#OneHotEncoder把它转换为只含有一维有效编码的数组。
from sklearn.preprocessing import OneHotEncoder
y = np.hstack(batch[b'labels'] for batch in batches).flatten()
y = OneHotEncoder().fit_transform(y.reshape(y.shape[0],1)).todense()
y = y.astype(np.float32)
#把数据集切分为训练集和测试集。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
#调整数组形状以保留原始图像的数据结构。图像原本是32像素见方,每个像素由三个值组成(分别
#表示红、绿、蓝的颜色值)。

#11.6.2 创建神经网络
#创建神经网络的各层
from lasagne import layers
layers = [
        ('input', layers.InputLayer),
        ('conv1', layers.Conv2DLayer),
        ('pool1', layers.MaxPool2DLayer),
        ('conv2', layers.Conv2DLayer),
        ('pool2', layers.MaxPool2DLayer),
        ('conv3', layers.Conv2DLayer),
        ('pool3', layers.MaxPool2DLayer),
        ('hidden4', layers.DenseLayer),
        ('hidden5', layers.DenseLayer),
        ('output', layers.DenseLayer),
        ]
#最后三层使用密集层,但是前面使用三组卷积层和池化层。此外,我们必须以输入层开始。这样
#一共有10层。输入数据跟数据集同型,而不只跟输入层的神经元数量相同,输入层和输出层的大
#小仍由数据集来定。
#开是创建神经网络
import theano
import lasagne
from nolearn.lasagne import NeuralNet 
from lasagne.nonlinearities import sigmoid, softmax
nnet = NeuralNet(layers=layers, input_shape=(None, 3, 32, 32),
                 conv1_num_filters=32,
                 conv1_filter_size=(3, 3),
                 conv2_num_filters=64,
                 conv2_filter_size=(2, 2),
                 conv3_num_filters=128,
                 conv3_filter_size=(2, 2),
                 pool1_ds=(2,2),
                 pool2_ds=(2,2),
                 pool3_ds=(2,2),
                 hidden4_num_units=500,
                 hidden5_num_units=500,
                 output_num_units=10,
                 output_nonlinearity=softmax,
                 updata_learning_rate=0.01,
                 update_momentum=0.9,
                 regression=True,
                 max_epochs=3,
                 verbose=1)

#11.6.3 组装起来
nnet.fit(X_train, y_train)
from sklearn.metrics import f1_score
y_pred = nnet.predict(X_test)
print(f1_score(y_test.argmax(axis=1), y_pred.argmax(axis=1)))






你可能感兴趣的:(python数据挖掘入门与实践)