当前位置:   article > 正文

李沐深度学习-d2lzh_pytorch模块实现_d2lzh pytorch

d2lzh pytorch

d2lzh_pytorch 模块

import random
import torch
import matplotlib_inline
from matplotlib import pyplot as plt
import torchvision
import torchvision.transforms as transforms
import torchvision.datasets
import sys
from collections import OrderedDict


# ---------------------------------------------------------------------------------------------
# 图表展示
def use_svg_display():
    # 用矢量图表示
    matplotlib_inline.backend_inline.set_matplotlib_formats('svg')


def set_figsize(figsize=(3.5, 2.5)):
    use_svg_display()
    # 设置图的尺寸
    plt.rcParams['figure.figsize'] = figsize


# ---------------------------------------------------------------------------------------------
# 读取数据
# 获取总的样本数量,然后打乱顺序,用batch-size获取每一部分索引去索引对应样本中的数据,使用yield返回
'''
函数详解:
torch.linspace(start, end, steps, dtype) → Tensor  从start开始到end结束,生成steps个数据点,数据类型为dtype
torch.index_select(input, dim, index)   索引张量中的子集
**
    input:需要进行索引操作的输入张量
    dim:张量维度  0,1
    index:索引号,是张量类型
**
yield: 使用yield的函数返回迭代器对象,每次使用时会保存变量信息,使用next()或者使用for可以循环访问迭代器中的内容
'''


def data_iter(batch_size, features, labels):
    num_examples = len(features)  # features   nxm
    indices = list(range(num_examples))  # 借助range生成索引序列
    random.shuffle(indices)  # 把list列表中的值打乱顺序
    for i in range(0, num_examples, batch_size):
        j = torch.LongTensor(indices[i:min(i + batch_size, num_examples)])  # 这里的i是对标乱序表中的下标索引号
        yield features.index_select(0, j), labels.index_select(0, j)  # 0维度,有1000个样本,j就是他们的下标


# ---------------------------------------------------------------------------------------------

# 定义模型
def linreg(X, w, b):
    return torch.mm(X, w) + b  # 传进来的参数和样本特征都符合矩阵形式 w,b都是列矩阵  X:1000x2  w:2x1  b:1x1
    # 这里使用了广播


# ---------------------------------------------------------------------------------------------

# 定义损失函数
def square_loss(y_hat, y):
    # 保证y_hat和y同型,pytorch中的MSELoss没有除以2的操作
    return (y_hat - y.view(y_hat.size())) ** 2 / 2  # 这里是多个样本的预测值和实际值之间的差值,返回nxm大小的张量


# 这里的得到的也是一个小批量的样本的损失张量

# ---------------------------------------------------------------------------------------------
# 定义优化算法
# 这里使用的是sgd算法,使用小批量梯度和(参数求导后的和:梯度会自动累加,不用自己加和梯度)除以小批量样本个数来求小批量平均值
def sgd(params, lr, batch_size):
    for param in params:
        param.data -= lr * param.grad / batch_size  # 这里更改param时使用的是param.data,这样就不会影响反向梯度
        # 这里的param指的是w1,w2,b


# 这里应该是小批量中的每个loss运行完,得到小批量每个样本的梯度然后pytorch自动进行了梯度累加,之后一个小批量得到一个累加和后的
# 梯度w1,w2,b
# ---------------------------------------------------------------------------------------------

'''
FashionMNIST 数据集
'''


# ----------------------------------------------------------将数值标签转换成文本标签
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):
    use_svg_display()
    # 这里的_表示忽略(不使用)的变量
    _, figs = plt.subplots(1, len(images), figsize=(12, 12))  # 设置一行 len(images)个数量,每个figsize大小的画布
    # figs 返回的是一个画布对象,这个对象有imshow,set_tittle,axes_get_xasis().set_visible,
    # axes.get_yaxis().set_visible()这几种函数调用方式,用来给figs里面添加图像
    for f, img, lbl, in zip(figs, images, labels):  # 这个画布对象循环往里面添加图像信息
        f.imshow(img.view((28, 28)).numpy())  # img承接图像信息,将tensor转化为numpy  这里参数为数组元素
        f.set_title(lbl)
        f.axes.get_xaxis().set_visible(False)
        f.axes.get_yaxis().set_visible(False)
    plt.savefig("路径")


# ----------------------------------------------------------------获取并读取FashionMNIST数据集函数,返回小批量train,test
def load_data_fashion_mnist(batch_size):
    mnist_train = torchvision.datasets.FashionMNIST(root='路径',
                                                    train=True, download=True, transform=transforms.ToTensor())
    mnist_test = torchvision.datasets.FashionMNIST(root='路径',
                                                   train=False, download=True, transform=transforms.ToTensor())
    '''
    上面的mnist_train,mnist_test都是torch.utils.data.Dataset的子类,所以可以使用len()获取数据集的大小
    训练集和测试集中的每个类别的图像数分别是6000,1000,两个数据集分别有10个类别
    '''
    # mnist是torch.utils.data.dataset的子类,因此可以将其传入torch.utils.data.DataLoader来创建一个DataLoader实例来读取数据
    # 在实践中,数据读取一般是训练的性能瓶颈,特别是模型较简单或者计算硬件性能比较高的时候
    # DataLoader一个很有用的功能就是允许多进程来加速读取  使用num_works来设置4个进程读取数据
    if sys.platform.startswith('win'):
        num_workers = 0
    else:
        num_workers = 4
    train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True,
                                             num_workers=num_workers)
    test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False,
                                            num_workers=num_workers)
    return train_iter, test_iter


# -------------------------------------------------------------查看mnist前10个图像和标签
def check_mnist():
    mnist_train = torchvision.datasets.FashionMNIST(root='路径',
                                                    train=True, download=True, transform=transforms.ToTensor())
    mnist_test = torchvision.datasets.FashionMNIST(root='路径',
                                                   train=False, download=True, transform=transforms.ToTensor())
    X, y = [], []
    for i in range(10):
        X.append(mnist_train[i][0])  # 循环获取图像张量矩阵
        y.append(mnist_train[i][1])  # 循环获取图像对应数值标签
    show_fashion_mnist(X, get_fashion_mnist_labels(y))
    # feature, label = mnist_train[0]
    # print(feature.shape, label)  CxHxW
    # feature对应高和宽均为28像素的图像,因为使用了transforms.ToTensor(),所以每个像素的数值对应于【0.0,1.0】的32位浮点数
    # C 是通道数,RGB,灰色图像,通道数为1,H,W分别为高,宽
    # mnist_train[0] 是一个元祖,它包含两部分,图像数据结构和图像标签值,图像的数据结构是1x28x28结构,是一个浮点数矩阵,代表一个图像


# -------------------------------------------------------------------------评价模型net在数据集data_iter上的准确率
def evaluate_accuracy(test_iter, net):
    acc_sum, n, x = 0.0, 0, 0.0
    for X, y in test_iter:  # 返回一个批量的数据元组迭代对象
        if isinstance(net, torch.nn.Module):
            net.eval()  # 评估模式,这会关闭dropout
            acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()  # 将net模型的预测y与标签y进行了准确率比较
            net.train()  # 改回训练模式
        else:  # 自定义模型
            if ('is_training' in net.__code__.co_varnames):  # 就是说如果net函数的参数中如果有is_training这个参数
                # 将is_training 设置为False
                acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()
            else:
                acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
        n += y.shape[0]  # 累加获得样本个数
        x = acc_sum / n
    return x


# -------------------------------------------------------------------------训练模型函数
def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, optimizer=None):
    for epochs in range(num_epochs):  # 循环周期
        train_l_sum, train_acc_sum, n = 0.0, 0.0, 0  # 预先定义 训练损失,训练精度,批量个数
        for X, y in train_iter:  # 批量更新
            y_hat = net(X)
            l = loss(y_hat, y).sum()  # 损失计算

            # 梯度清零
            if optimizer is not None:
                optimizer.zero_grad()
            elif params is not None and params[0].grad is not None:  # 权重存在并且权重的梯度存在
                for param in params:
                    param.grad.data.zero_()
            l.backward()  # 反向传播
            # 梯度更新操作
            if optimizer is None:
                sgd(params, lr, batch_size)  # 调用sgd进行梯度下降操作
            else:
                optimizer.step()  # softmax回归的简洁实现将要用到

            train_l_sum += l.item()  # 损失累加
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()  # (y_hat.argmax(dim=1) == y)
            # 取出y_hat每一行中最大的概率索引和y比较,结果为tensor,元素值为0/1
            n += y.shape[0]  # 计算一个批量中标签的个数
        test_acc = evaluate_accuracy(test_iter, net)  # 一个循环之后进行测试集的准确度计算
        print(f'epoch %d,loss %.4f,train_acc %.3f,test_acc %.3f'
              % (epochs + 1, train_l_sum / n, train_acc_sum / n, test_acc))


# x = torch.tensor([[0.1, 0.4, 0.2], [1, 0.06, 0.5]])
# print((x.argmax(dim=1)==torch.tensor([[1,1]])).float())

# -------------------------------------------------------------------------x的形状转换功能函数
class FlattenLayer(torch.nn.Module):
    def __init__(self):
        super(FlattenLayer, self).__init__()  # 初始化函数,自动调用forward函数

    def forward(self, x):  # x shape: (batch,*,*,....)
        return x.view(x.shape[0], -1)  # 转换成(batch_size,特征数)形状


# 这样就方便定义模型
net = torch.nn.Sequential(
    # FlattenLayer()
    # torch.nn.Linear(num_inputs,num_outputs)
    OrderedDict([
        ('flatten', FlattenLayer()),
        ('linear', torch.nn.Linear(2, 3))
    ])
)

'''
-------------------------------------------------------------------作图函数
'''


def semilogy(x_vals, y_vals, xlabel, ylabel, label, x2_vals=None, y2_vals=None, legend=None):
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.semilogy(x_vals, y_vals)  # y轴使用对数尺度
    if x2_vals and y2_vals:
        plt.semilogy(x2_vals, y2_vals, linestyle=':')
        plt.legend(legend)
        plt.savefig("路径" + label + "模拟.png")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/939100
推荐阅读
相关标签
  

闽ICP备14008679号