周报-240705

学习内容

1、Numpy的广播机制

2、随机梯度下降算法

3、正态分布与平方损失

4、线性回归的从零开始实现

5、softmax回归

学习时间

2024.6.27~2024.7.5

学习笔记

Numpy的广播机制

目的:解决不同形状的矩阵间的运算

机制规则:

将两个数组的维度大小右对齐,然后比较对应维度上的数值,

如果数值相等或其中有一个为1或者为空,则能进行广播运算,

输出的维度大小为取数值大的数值。否则不能进行数组运算。

例子:

随机梯度下降算法

目的:寻找一组参数, 这组参数能最小化在所有训练样本上的总损失。

以下仅讨论损失函数与b的关系。

当b不向下移动时,即损失函数导数为0,即最小值点

损失函数是针对某一样本的,当我们对所有样本用损失函数计算得到一个平均的值,该函数我们叫做成本函数(下面的g函数)

学习率:参数更新的步长(设置不当将影响函数收敛,反复震荡)

减少迭代次数和内存开销,先取小部分随机样本来收敛函数,即小批量随机梯度下降(minibatch stochastic gradient descent)

(防止在最低点附近反复震荡,为了让梯度下降的更平滑,保留上次下降的方向与后一次合成,即动量随机梯度下降算法)

如何自动调整学习率?

在训练之初地较大帮助快速收敛,在后面随着梯度下降而减小,防止震荡。

矢量化加速

略(用矢量代替for循环,效率更高)

正态分布与平方损失

可视化正态分布

​
import math  
import numpy as np  
import matplotlib.pyplot as plt  # 假设d2l.plot是基于matplotlib的封装  
  
# 假设的d2l.plot函数,这里我们使用matplotlib.pyplot作为替代  
def plot_normal(x, ys, xlabel, ylabel, figsize, legend):  
    plt.figure(figsize=figsize)  
    for y, l in zip(ys, legend):  
        plt.plot(x, y, label=l)  
    plt.xlabel(xlabel)  
    plt.ylabel(ylabel)  
    plt.legend()  
    plt.show()  
  
# 修正后的正态分布函数  
def normal(x, mu, sigma):  
    p = 1 / (math.sqrt(2 * math.pi) * sigma)  
    return p * np.exp(-0.5 * ((x - mu) / sigma)**2)  
  
# 生成x的数组  
x = np.arange(-7, 7, 0.01)  
  
# 均值和标准差对  
params = [(0, 1), (0, 2), (3, 1)]  
  
# 使用修正后的normal函数和plot_normal进行可视化  
ys = [normal(x, mu, sigma) for mu, sigma in params]  
plot_normal(x, ys, xlabel='x', ylabel='p(x)', figsize=(4.5, 2.5),  
            legend=[f'mean {mu}, std {sigma}' for mu, sigma in params])

​

改变均值会产生沿𝑥轴的偏移,增加方差将会分散分布、降低其峰值。

以下为用最大似然估计证明了最小二乘法是正确的:

假设了观测中包含噪声,其中噪声服从正态分布。 噪声正态分布如下式:

其中,𝜖∼𝑁(0,𝜎2)。

线性回归的从零开始实现

生成合成数据集

我们的合成数据集是一个矩阵𝑋∈𝑅1000×2。(1000是样本数,2是维度)

import random  
import torch  
import matplotlib.pyplot as plt  # 导入matplotlib.pyplot  
  
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)  
  
print('features:', features[0], '\nlabel:', labels[0])  
  
# 设置图形大小(这里我们直接调用matplotlib的rcParams)  
plt.rcParams['figure.figsize'] = (6.0, 4.0)  
  
# 绘制散点图  
plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), s=10)  # 设置点的大小为10  
plt.xlabel('Feature')  # 添加x轴标签  
plt.ylabel('Label')    # 添加y轴标签  
plt.title('Synthetic Data Scatter Plot')  # 添加图形标题  
plt.show()  # 显示图形

注:

1、torch.normal(mean, std, *, size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) 是PyTorch中的一个函数,用于生成从指定均值(mean)和标准差(std)的正态(高斯)分布中抽取的随机数。
X = torch.normal(0, 1, (num_examples, len(w)))

在这个例子中,mean=0 和 std=1 表示生成的是标准正态分布(均值为0,标准差为1)的随机数。
size=(num_examples, len(w)) 指定了生成张量的形状。这里,num_examples 是样本数量,len(w) 是每个样本的特征数量(或者说权重向量w的长度)。因此,生成的张量X是一个二维数组,其中包含了num_examples行和len(w)列。

2、reshape方法的参数中,-1有特殊的含义。它告诉NumPy自动计算该维度的大小,以便使总的元素数量保持不变。这在你不知道某一维度应该有多少元素,但知道其他维度的大小时非常有用。

结果图:

读取数据集

def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    # 这些样本是随机读取的,没有特定的顺序
    random.shuffle(indices)
    #。循环的范围是0到num_examples,步长为batch_size。
    #但是,由于range函数不会超出上限,所以使用min(i + batch_size, num_examples)来确保不会超出样本总数。
    for i in range(0, num_examples, batch_size):
        #在每次迭代中,生成当前批次的索引张量,然后利用这些索引从features和labels中索引出对应的批次数据和标签。
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])
        #每次迭代for循环时返回下一个批次的数据和标签,直到所有数据都被遍历完。
        yield features[batch_indices], labels[batch_indices]
#每个批次的样本数
batch_size = 10

for X, y in data_iter(batch_size, features, labels):
    print(X, '\n', y)
    #只打印出第一个批次的数据和标签。
    break

初始化模型参数、定义模型、定义损失函数、定义优化算法、训练


import random  
import torch  
#上面有------------------------------------------------------------------------------------------
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)  

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)], dtype=torch.long)  
        yield features[batch_indices], labels[batch_indices]  
#----------------------------------------------------------------------------------------------------------



#初始化模型参数
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)  
b = torch.zeros(1, requires_grad=True)  
#定义模型
def linreg(X, w, b):  
    """线性回归模型"""  
    return torch.matmul(X, w) + b  
  
def squared_loss(y_hat, y):  
    """均方损失"""  
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  
  
def sgd(params, lr, batch_size):  
    """小批量随机梯度下降"""  
    #上下文管理器,用于暂时禁用对返回的所有Tensor的梯度跟踪。
    #在这里,所有计算得到的Tensor都不会记录梯度信息,减少内存消耗并加速计算。
    with torch.no_grad():  
        for param in params:  
            param -= lr * param.grad / batch_size  
            #更新完参数后,清零梯度
            param.grad.zero_()  
  
lr = 0.03  
num_epochs = 3  
  
for epoch in range(num_epochs):  
    for X, y in data_iter(batch_size=10, features=features, labels=labels):  
        l = squared_loss(linreg(X, w, b), y)  
        l.sum().backward()  
        sgd([w, b], lr, len(X))  # 注意这里batch_size应替换为当前批次的大小len(X)  
    with torch.no_grad():  
        train_l = squared_loss(linreg(features, w, b), labels)  
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')  
  
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')  
print(f'b的估计误差: {true_b - b.item()}')

softmax回归

回归和分类的区别:

回归:单连续的输出,自然区间R,跟真实值的区别作为损失。

分类:有多个输出,输出i是第i类的置信度

回归是问“多少”,分类是问“哪一个”。

softmax回归实际是一个分类问题,用于解决多分类问题,前面提到的logistic用于解决二分类问题。

softmax回归运算

softmax回归:对线性加权和进行softmax运算,将输入映射到每个类别的得分。然后,使用softmax函数将这些得分转换为概率分布,每个类别的概率都在0和1之间,且所有类别的概率之和为1。

                                                        softmax(y_{i})=\frac{exp(y_{i})}{\sum_{i}^{}exp(y_{i})}

将每一类计算出后再输出概率最大的类别  argmax \: y\hat{}_{_{i}}  作为预测。

Softmax回归对样本i ii分类的矢量计算表达式为

                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

Softmax回归的决策函数可以表示为:​​​​​​​y\hat{}=argmax \: y\hat{}_{_{i}}

损失函数

这里的损失函数采用交叉熵损失函数,

对于二分类问题,交叉熵损失函数的定义如下:

     

其中,y_{i }​是第i个样本的真实标签(0或1),p_{i}是模型预测该样本为正类的概率,N是样本总数。

对于多分类问题,交叉熵损失函数的定义则变为:

                             

其中,y_{i,k}是第i个样本属于第k个类别的真实标签(0或1),p_{i,k}是模型预测的第i个样本属于第k个类别的概率,N是样本总数,K是类别总数。

采用交叉熵损失函数,Softmax回归模型的损失函数为:

                                        ​​​​​​​

假设第i个样本的真实标签是类别c(其中c是1到K之间的一个整数),那么该样本的交叉熵损失可以简化为:        ​​​​​​​        ​​​​​​​        

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        L_{i}=-\log y\hat{}_{i,c}

其中,y\hat{}_{i,c}是模型预测的第i个样本属于类别c的概率。

对于整个训练集,损失函数则是所有样本损失的平均值:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        L(y,y\hat{})=-\frac{1}{N}\sum_{i=1}^{N}\log y\hat{}_{i,c}

y\hat{_{i}}=softmax(y_{i})=\frac{exp(y_{i})}{\sum_{i}^{}exp(y_{i})}带入上式得(这里的O_{j}就是y\hat{}_{j})

        ​​​​​​​        ​​​​​​​        

考虑相对于任何未规范化的预测O_{j}的导数,我们得到:

        

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值