pytorch基础知识和api

基础知识

点积 矩阵-向量积 矩阵乘法 按元素乘法称为_Hadamard积_

# 1. 点积  对应元素相乘然后求和
torch.dot(x, y) = torch.sum(x * y)
# 2. 矩阵-向量积 (martex-vector)
torch.mv(A, x)
# 3. 矩阵乘法  (martex-martex) 
torch.mm(A, B) 
# 上述矩阵乘法支持支二维,下面的更加泛化
torch.matmul(X, w)
# 4. 按对应的元素乘法称为Hadamard积
A * B = torch.dot(A, B)

自动微分

2.5. 自动微分 — 动手学深度学习 2.0.0 documentation
有标量微分和非标量微分 (标量就是只有一个值)

import torch

x = torch.arange(4.0)    # tensor([0., 1., 2., 3.])
x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)
print(x.grad)  # 默认值是None

y = 2 * torch.dot(x, x) # 得到一个标量
y.backward()            # 标量情况下:反向传播计算梯度  
print(x.grad)           # tensor([ 0.,  4.,  8., 12.])

# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = 2 * x * x          # 得到一个非标量
y.backward(torch.ones_like(x))   # 等价于 y.sum().backward()
print(x.grad)          # tensor([ 0.,  4.,  8., 12.])

线性神经网络

线性回归 y = w*X + b

自己实现
  1. 生成数据:
def synthetic_data(w, b, num_examples):  
    """生成y=Xw+b+噪声"""
    X = torch.normal(0, 1, (num_examples, len(w))) #正态分布
    y = torch.matmul(X, w) + b    # 矩阵乘法
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape((-1, 1))

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
  1. 读取数据
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # 这些样本是随机读取的,没有特定的顺序
    random.shuffle(indices)
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])
        yield features[batch_indices], labels[batch_indices]     # 异步返回  相当于多个return

batch_size = 10
for X, y in data_iter(batch_size, features, labels):
    print(X, '\n', y)   # 获取batch_size大小的 样本 和 标签
    break
  1. 初始化参数
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
  1. 定义线性模型 和 损失函数
def linreg(X, w, b): 
    """线性回归模型"""
    return torch.matmul(X, w) + b

def squared_loss(y_hat, y):  #@save
    """均方损失"""
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
  1. 定义优化算法
# params 就是 w、b    
def sgd(params, lr, batch_size):  
    """小批量随机梯度下降"""
    with torch.no_grad():     # 禁用该上下文内的所有操作对计算图的跟踪,从而不会计算梯度,为了自定义梯度下降?
        for param in params:
            param -= lr * param.grad / batch_size    # x += y 是原地赋值 引用 所以参数全局改变
            param.grad.zero_()
  1. 训练
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss

for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):
        l = loss(net(X, w, b), y)  # X和y的小批量损失
        # 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,
        # 并以此计算关于[w,b]的梯度
        l.sum().backward()
        sgd([w, b], lr, batch_size)  # 使用参数的梯度更新参数
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

# epoch 1, loss 0.042790
# epoch 2, loss 0.000162
# epoch 3, loss 0.000051
  1. 检验
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')

# w的估计误差: tensor([-1.3804e-04,  5.7936e-05], grad_fn=<SubBackward0>)
# b的估计误差: tensor([0.0006], grad_fn=<RsubBackward1>)
api实现
  1. 生成数据 (与之前一样)
def synthetic_data(w, b, num_examples):  
    """生成y=Xw+b+噪声"""
    X = torch.normal(0, 1, (num_examples, len(w))) #正态分布
    y = torch.matmul(X, w) + b    # 矩阵乘法
    y += torch.normal(0, 0.01, y.shape)
    return X, y.reshape((-1, 1))

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
  1. 读取数据 (用API DataoLoader)
# data_arrays = (X, y)
def load_array(data_arrays, batch_size, is_train=True):  
    """构造一个PyTorch数据迭代器"""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train) # 是否打乱

batch_size = 10
data_iter = load_array((features, labels), batch_size)

print(next(iter(data_iter))) # 打印
  1. 自定义模型和 损失函数
# nn是神经网络的缩写
from torch import nn

# 第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1
net = nn.Sequential(nn.Linear(2, 1))

# 计算均方误差使用的是MSELoss类,也称为L2平方范数。 默认情况下,它返回所有样本损失的平均值。
loss = nn.MSELoss()
  1. 初始化参数
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
  1. 定义优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
  1. 训练
num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y)
        trainer.zero_grad()
        l.backward()
        trainer.step() # 用反向传播的结果 更新参数
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')
  1. 检验
w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)

Softmax 回归

自己实现
  1. 数据集准备
def load_data_fashion_mnist(batch_size, resize=None):  
    """下载Fashion-MNIST数据集,然后将其加载到内存中"""
    trans = [transforms.ToTensor()]
    if resize:
        trans.insert(0, transforms.Resize(resize))
    trans = transforms.Compose(trans)
    mnist_train = torchvision.datasets.FashionMNIST(
        root="../data", train=True, transform=trans, download=True)
    mnist_test = torchvision.datasets.FashionMNIST(
        root="../data", train=False, transform=trans, download=True)
    return (data.DataLoader(mnist_train, batch_size, shuffle=True,
                            num_workers=4),
            data.DataLoader(mnist_test, batch_size, shuffle=False,
                            num_workers=4))

batch_size = 256
train_iter, test_iter = load_data_fashion_mnist(batch_size)
  1. 初始化模型参数
num_inputs = 784     # 图像=28*28*1 = 784
num_outputs = 10     # 输出10分类

W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
b = torch.zeros(num_outputs, requires_grad=True)
  1. Softmax操作
def softmax(X):
    X_exp = torch.exp(X)
    partition = X_exp.sum(1, keepdim=True) # 列维度降维,对每一行求和
    return X_exp / partition  # 这里应用了广播机制
  1. 定义模型和损失函数
def net(X):
    return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)

# 交叉损失
def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])
  1. 分类精度
def accuracy(y_hat, y):  
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = y_hat.argmax(axis=1) # 找到每一行中 最大的列的索引
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())

# 在测试集上测试
def evaluate_accuracy(net, data_iter):  
    """计算在指定数据集上模型的精度"""
    if isinstance(net, torch.nn.Module):
        net.eval()  # 将模型设置为评估模式
    metric = Accumulator(2)  # 正确预测数、预测总数  # 保存中间变量
    with torch.no_grad():
        for X, y in data_iter:
            metric.add(accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]
class Accumulator:  #保存中间变量的类
    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n

    def add(self, *args):
        self.data = [a + float(b) for a, b in zip(self.data, args)]

    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]
  1. 训练
def train_epoch_ch3(net, train_iter, loss, updater):  
    """训练模型一个迭代周期(定义见第3章)"""
    # 将模型设置为训练模式
    if isinstance(net, torch.nn.Module):
        net.train()
    # 训练损失总和、训练准确度总和、样本数
    metric = Accumulator(3)
    for X, y in train_iter:
        # 计算梯度并更新参数
        y_hat = net(X)
        l = loss(y_hat, y)
        if isinstance(updater, torch.optim.Optimizer):
            # 使用PyTorch内置的优化器和损失函数
            updater.zero_grad()
            l.mean().backward()
            updater.step()
        else:
            # 使用定制的优化器和损失函数
            l.sum().backward()
            updater(X.shape[0])
        metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
    # 返回训练损失和训练精度
    return metric[0] / metric[2], metric[1] / metric[2]
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save
    """训练模型(定义见第3章)"""
    
    for epoch in range(num_epochs):
        train_metrics = train_epoch_ch3(net, train_iter, loss, updater)
        test_acc = evaluate_accuracy(net, test_iter)


lr = 0.1
def updater(batch_size):
    return d2l.sgd([W, b], lr, batch_size)
num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)
  1. 预测
def predict_ch3(net, test_iter, n=6): 
    """预测标签(定义见第3章)"""
    for X, y in test_iter:
        break
    trues = d2l.get_fashion_mnist_labels(y)
    preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
    titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
    d2l.show_images(
        X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])

predict_ch3(net, test_iter)
api实现
  1. 数据集准备(和之前一样)
  2. 初始化模型参数
# PyTorch不会隐式地调整输入的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
# 原始数据[1,28,28] Linear的输入是一个确定的数,所以要先展开,
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);
  1. 重新审视Softmax的实现
# 如果你设置reduction='mean',那么损失函数会返回批次中所有样本损失的平均值;
# 如果你设置reduction='sum',则返回所有样本损失的总和。
# 					  none 每个样本的损失值
loss = nn.CrossEntropyLoss(reduction='none')
  1. 优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.1)
  1. 训练
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

多层感知机

多层感知机

自己实现
# 1. 数据集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

num_inputs, num_outputs, num_hiddens = 784, 10, 256

# 2. 初始化参数
W1 = nn.Parameter(torch.randn(
    num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(
    num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2]

# 3. 激活函数
def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X, a)

# 4. 模型
def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X@W1 + b1)  # 这里“@”代表矩阵乘法
    return (H@W2 + b2)

# 5. 损失函数
loss = nn.CrossEntropyLoss(reduction='none')

# 6. 训练
num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

在这里插入图片描述

api实现
# 1. 模型
net = nn.Sequential(nn.Flatten(),
                    nn.Linear(784, 256),
                    nn.ReLU(),
                    nn.Linear(256, 10))

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights)


# 2、 训练 下面是一样的,只有上面不一样
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

深度学习计算

自定义块

  1. 普通方式
net = nn.Sequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
  1. 自定义方式
class MLP(nn.Module):
    # 用模型参数声明层。这里,我们声明两个全连接的层
    def __init__(self):
        # 调用MLP的父类Module的构造函数来执行必要的初始化。
        # 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
        super().__init__()
        self.hidden = nn.Linear(20, 256)  # 隐藏层
        self.out = nn.Linear(256, 10)  # 输出层

    # 定义模型的前向传播,即如何根据输入X返回所需的模型输出
    # 反向传播自动计算微分
    def forward(self, X):
        # 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
        return self.out(F.relu(self.hidden(X)))

初始化参数

# 我们还可以对某些块应用不同的初始化方法。 例如,下面我们使用Xavier初始化方法初始化第一个神经网络层, 然后将第三个神经网络层初始化为常量值42。
def init_xavier(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
def init_42(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 42)

net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就你叫Martin?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值