Advertisement

《动手学深度学习》笔记---3.5&3.6&3.7

阅读量:

3.5 图像分类数据集(Fashion-MNIST)

3.5.1 获取数据集

复制代码
    # 手动下载数据集,参考文章:https://www.cnblogs.com/liwill/p/13591499.html
    # r 是只读,没有文件时会报错,不覆盖。参考文章:https://www.cnblogs.com/dadong616/p/6824859.html
    %matplotlib inline
    import d2lzh as d2l
    from mxnet.gluon import data as gdata
    import sys
    import time
    mnist_train = gdata.vision.FashionMNIST(root=r'C:\Users\your_username\.mxnet\datasets\fashion-mnist', train=True)
    mnist_test  = gdata.vision.FashionMNIST(root=r'C:\Users\your_username\.mxnet\datasets\fashion-mnist', train=False)
复制代码
    len(mnist_train), len(mnist_test)
    feature, label = mnist_train[0]
    # 变量feature是高和宽均为28像素的图像,每个像素的数值为0到255之间8位无符号整数(unit8),使用三维NDArray存储,最后一维是通道数。
    # 1:灰度图像
    feature.shape, feature.dtype
复制代码
    output:
    (60000, 10000)
    ((28, 28, 1), numpy.uint8)
复制代码
    # 图像标签使用numpy标量表示,类型为32位整数(int32)
    label, type(label), label.dtype, type(int(label))
复制代码
    output:
    (2, numpy.int32, dtype('int32'), int)
复制代码
    # Fashion-MNIST共包含10个类别,分别为t-shirt、trouser、pullover、dress、coat、sandal、shirt、sneaker、bag、ankle boot
    # 以下函数将数值标签转成相应的文本标签
    # int(i)将int32转成int,因为list数据类型的索引是int型
    def get_fashion_mnist_labels(labels):
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]
复制代码
    # 定义一个可以在一行里画出多张图像和对应标签的函数
    
    def show_fashion_mnist(images, labels):
    d2l.use_svg_display()
    #这里的_表示我们忽略(不使用)的变量
    _,figs = d2l.plt.subplots(1, len(images), figsize = (12, 12))
    for f, img, lbl in zip(figs, images, labels):      # zip函数将对应位置的figs,images,labels的元素打包成一个个元组
        f.imshow(img.reshape((28,28)).asnumpy())       # 原来的图像是(28,28,1),转成(28.28)numpy类型
        f.set_title(lbl)
        f.axes.get_xaxis().set_visible(True)     # 显示横纵坐标
        f.axes.get_yaxis().set_visible(False)
    X, y = mnist_train[0:9]
    show_f在这里插入图片描述
    ashion_mnist(X, get_fashion_mnist_labels(y))
输出图像
复制代码
    # 验证list的索引的数据类型,是int
    a = [0, 1, 2 , 3]
    type(a.index(1))
复制代码
    output:
    int

3.5.2 读取小批量

复制代码
    # 读取小批量
    # 发现一个疑问:当batch_size可被mnist_train整除时,读取batch_size张图片;不能整除时,读取的图片数量小于batch_size
    # 有的样本被舍弃了
    batch_size = 256
    # 通过ToTensor实例将unit8转成32位浮点数,并除以255使得所有像素值均在0-1之间;还将图像通道从最后一维移到最前一维
    transformer = gdata.vision.transforms.ToTensor()    
    # Gluon的DataLoader允许使用多进程来加速数据读取(Windows除外),通过设置num_workers来设置进程数
    if sys.platform.startswith('win'):
    num_workers = 0
    else:
    num_workers = 4
    
    # 通过transform_first函数将ToTensor的变化应用到每个数据样本(图像+标签)的第一个元素,即图像之上
    train_iter = gdata.DataLoader(mnist_train.transform_first(transformer),
                              batch_size, shuffle = True,
                              num_workers = num_workers)
    test_iter =  gdata.DataLoader(mnist_test.transform_first(transformer),
                              batch_size, shuffle = False,
                              num_workers = num_workers)
    
    # 查看读取一遍训练数据需要的时间
    start = time.time()
    for X, y in train_iter:
    continue
    '%.2f sec' % (time.time() - start)
复制代码
    output:
    '6.96 sec'
复制代码
    # 查看读取的图片数量
    X.shape
复制代码
    output:
    (96, 1, 28, 28)

3.6 softmax回归的从零开始实现

3.6.1 读取数据集

复制代码
    %matplotlib inline
    import d2lzh as d2l
    from mxnet import autograd, nd
    
    # 3.6.1 读取数据集
    # 使用Fashion-MNIST数据集,大小并设置成256
    # 参考3.5.1 获取数据集,将手动下载的4个图像压缩包,放在C:\Users\<username>\.mxnet\datasets\fashion-mnist文件夹内,不用解压
    batch_size = 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

3.6.2 初始化模型参数

复制代码
    #  3.6.2 初始化模型参数
    # 样本向量化,输入向量长度= 28 * 28 = 784,该项量中的每个元素对应图像的每个像素
    # 图像有10个类别,单层神经网络的输出个数为10,因此,softmax回归的权重和偏差分别为784*10, 1*10
    # 对每一个像素都有对应的权重、偏差与之做线性叠加
    
    num_inputs = 784
    num_outputs = 10
    w = nd.random.normal(scale = 0.01, shape = (num_inputs, num_outputs))
    b = nd.zeros(num_outputs)
    
    # 为模型参数附上梯度
    w.attach_grad()
    b.attach_grad()

3.6.3 实现softmax运算

复制代码
    # 3.6.3 实现softmax运算
    # 多维NDArray按维度操作。axis=0,按列;axis=1,按行。并在结果中保留行和列这两个维度(keepdims=True)。
    X = nd.array([[1, 2, 3],[4, 5, 6]])
    X.sum(axis = 0, keepdims = True), X.sum(axis = 1, keepdims = True)
    # 矩阵X的行数是样本数(共有784行),列数是输出个数。比如第一列有784个数,是输入的784个像素在第一个输出类别上的输出概率
    # softmax运算会通过exp函数对每个元素做指数运算,再对exp矩阵同行元素求和,最后令矩阵的每行各个元素与该行元素之和相除
    # 最终得到的矩阵每行元素和为1且非负
    # softmax运算输出矩阵中的任意一行元素代表了一个样本(像素)在各个输出类别上的预测概率。
    
    def softmax(X):
    X_exp = X.exp()                # 对X中的每个元素求exp
    partition = X_exp.sum(axis = 1, keepdims = True)    # 对每一行累加后,再求exp
    return X_exp / partition  # 用了广播机制,每行各元素对该行元素之后相除
    
    # 使用随机矩阵对softmax函数进行了验证
    # softmax函数把随机输入的矩阵 的每个元素变成了非负数,且每一行之和为1
    X = nd.random.normal(shape = (2,5))
    X_prob = softmax(X)
    X_prob, X_prob.sum(axis = 1)

3.6.4 定义模型

复制代码
    # 3.6.4 定义模型
    # 通过reshape函数将每张原始图像改成长度为num_inputs的向量
    
    def net(X):
    return softmax(nd.dot(X.reshape((-1, num_inputs)), w) + b)

3.6.5 定义损失函数

复制代码
    # 3.6.5 定义损失函数
    # 使用pick函数,来得到标签的预测概率
    # y_hat是2个样本在3个类别的预测概率,变量y是这2个样本的标签类别
    # 通过pick函数,得到2个样本的标签预测概率
    # 我的理解:就是y_hat的每一行数据是对每一种类别的预测概率,比如:类别1:0.1,类别2:0.3,类别3:0.6。
    # y是索引,pick函数是按照y中的元素(y_hat的索引)来挑出y_hat中对应的元素值
    y_hat = nd.array([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
    y = nd.array([0, 2], dtype = 'int32')
    nd.pick(y_hat, y)
    
    # 定义交叉熵损失函数
    def cross_entropy(y_hat, y):
    return -nd.pick(y_hat, y).log()

3.6.6 定义分类准确率

复制代码
    # 3.6.6 定义分类准确率
    # 分类准确率就是正确预测数量与总预测数量之比
    # y_hat.argmax(axis = 1)返回矩阵y_hat每行中最大元素的索引
    
    def accuracy(y_hat, y):
    # 相等条件判别式,由于标签类型是整数,需要先将y变换成浮点数再判断相等
    return (y_hat.argmax(axis = 1) == y.astype('float32')).mean().asscalar()  
    #accuracy(y_hat, y)
    # 评价模型net在数据集data_iter上的准确率
    def evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0        # 注意这种赋值方式
    for X, y in data_iter:
        y = y.astype('float32')
        acc_sum += (net(X).argmax(axis = 1) == y).sum().asscalar()  # net(X)相当于y_hat
        n += y.size
        return acc_sum / n
    evaluate_accuracy(test_iter, net)  # 接近类别个数10的导数0.1

3.6.7 训练模型

复制代码
    num_epochs, lr = 5, 0.1
    def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params = None, lr = None, trainer = None):
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
        for X, y in train_iter:
            with autograd.record():
                y_hat = net(X)                   # 将X传入net训练,得到预测值
                l = loss(y_hat, y).sum()
            l.backward()
            if trainer is None:
                d2l.sgd(params, lr, batch_size)
            else:
                trainer.step(batch_size)
            y = y.astype('float32')
            train_l_sum += l.asscalar()
            train_acc_sum += (y_hat.argmax(axis = 1) == y).sum().asscalar()
            n += y.size
        test_acc =  evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
             % (epoch +1, train_l_sum/n, train_acc_sum / n, test_acc))
    train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [w,b], lr)
复制代码
    output:
    
    epoch 1, loss 0.7875, train acc 0.747, test acc 0.820
    epoch 2, loss 0.5750, train acc 0.810, test acc 0.840
    epoch 3, loss 0.5298, train acc 0.823, test acc 0.832
    epoch 4, loss 0.5058, train acc 0.830, test acc 0.832
    epoch 5, loss 0.4898, train acc 0.833, test acc 0.840

data_iter的探索学习

复制代码
    # data_iter的探索学习
    # 评价模型net在数据集data_iter上的准确率
    def evaluate_accuracy_test(data_iter, net):
    acc_sum, n = 0.0, 0        # 注意这种赋值方式
    i = 0
    for X, y in data_iter:    # 只循环了1次
        i +=  1
        y = y.astype('float32')
        acc_sum += (net(X).argmax(axis = 1) == y).sum().asscalar()  # net(X)相当于y_hat
        n += y.size
        return  i #acc_sum / n
    evaluate_accuracy_test(test_iter, net)  # 接近类别个数10的导数0.1
复制代码
    output:
    1

3.6.8 预测

复制代码
    # 3.6.8 预测
    # i = 0
    for X, y in test_iter:
    #     i = i + 1
    break
    true_labels = d2l.get_fashion_mnist_labels(y.asnumpy())
    pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(axis = 1).asnumpy())
    titles = [true + '\n' + pred  for true, pred in zip(true_labels, pred_labels)]
    
    d2l.show_fashion_mnist(X[0:9], titles[0:9])
    print('i = %d' % i)
    X.shape
复制代码
    output:
    i = 0
    (256, 1, 28, 28)
模型预测结果_从零实现

3.7 softmax回归的简洁实现

3.7.1 读取数据集

复制代码
    %matplotlib inline
    import d2lzh as d2l
    from mxnet import gluon, init
    from mxnet.gluon import loss as gloss, nn
    
    # 3.7.1 读取数据集
    batch_size = 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

3.7.2 定义和初始化模型

复制代码
    net = nn.Sequential()
    net.add(nn.Dense(10))
    net.initialize(init.Normal(sigma = 0.01))

3.7.3 softmax和交叉熵损失函数

复制代码
    loss = gloss.SoftmaxCrossEntropyLoss()

3.7.4 定义优化算法

复制代码
    trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})

3.7.5 训练模型

复制代码
    num_epochs = 5
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, trainer)

3.7.6 预测

复制代码
    # 3.7.6 预测
    # i = 0
    for X, y in test_iter:
    #     i = i + 1
    break
    true_labels = d2l.get_fashion_mnist_labels(y.asnumpy())
    pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(axis = 1).asnumpy())
    titles = [true + '\n' + pred  for true, pred in zip(true_labels, pred_labels)]
    
    d2l.show_fashion_mnist(X[0:9], titles[0:9])
    print('i = %d' % i)
    X.shape
复制代码
    output:
    epoch 1, loss 0.7895, train acc 0.746, test acc 0.805
    epoch 2, loss 0.5736, train acc 0.811, test acc 0.813
    epoch 3, loss 0.5286, train acc 0.824, test acc 0.833
    epoch 4, loss 0.5063, train acc 0.830, test acc 0.835
    epoch 5, loss 0.4895, train acc 0.835, test acc 0.837
    i = 1
复制代码
    output:
    
    (256, 1, 28, 28)
模型预测结果_简洁实现

accuracy函数探索学习

复制代码
    # accuracy函数探索学习
    # 为多行输出而引入的包
    from IPython.core.interactiveshell import InteractiveShell
    InteractiveShell.ast_node_interactivity = "all"
    
    test_hat = nd.array([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
    test = nd.array([0, 2], dtype = 'int32')
    test_result = test_hat.argmax(axis = 1) == test.astype('float32')   # 找出test_hat每一行中最大元素的索引 与 test的对应位置比较
    test_result     # 返回0、1,分别代表假和真;并且返回结果和变量test的形状相同
    print('test_result的平均值 : %.1f' %test_result.mean().asscalar())
复制代码
    output:
    [0. 1.]
    <NDArray 2 @cpu(0)>
    test_result的平均值 : 0.5

for循环探索学习

复制代码
    number = nd.array([1, 2, 3, 4, 5])
    num_loop = 0   # 初始化循环次数是0
    for num in number:
    num_loop += 1
    
    print('for循环次数: %d' %num_loop)
复制代码
    output:
    for循环次数: 5

全部评论 (0)

还没有任何评论哟~