Tensor常见操作、自动微分及手动构建模型

news2024/9/20 22:48:32

有关张量(Tensor)的创建、常见属性及数据转换 见此链接https://blog.csdn.net/m0_68153457/article/details/141686846?spm=1001.2014.3001.5501

一、Tensor常见操作

1.tensor相关运算

在进行相关运算前,我们要学会获取元素的值,即把单个元素tensor转换为python数值

import torch

def test():
    data1=torch.tensor([10])
    print(data1.item())
    #10
    data2=torch.tensor(5)
    print(data2.item())
    #5

    #以上可看出与tensor的维度无关

    data3=torch.tensor([1,2,3])
    print(data3.item())
    #报错

    #说明若有多个元素则报错

    pass 

if __name__=="__main__":
    test()

元素值运算

import torch

def test():
    #注意"-"的区别
    a=torch.randint(1,9,(3,3))
    print(a)
    print("---------")
    #没有"-"时不会替换原始值
    print(a.add(1))
    print(a.sub(1))
    print(a.mul(1))
    print(a.div(1))
    print(a.pow(2))
    print("---------")

    b=a.float()#此处不改为浮点数会报错
    #有"-"时会替换原始值
    b.add_(1)
    b.sub_(1)
    b.mul_(1)
    b.div_(1)
    b.pow_(2)
    print(b)

    pass 

if __name__=="__main__":
    test()

阿达玛积

阿达玛积指的是矩阵对应位置的元素相乘,可以使用mul函数或者*来实现

ps:torch.mul(a, b) 是矩阵a和b对应位相乘,a和b的维度必须相等

import torch

def test():
    a=torch.tensor([[1,2],[3,4]])
    b=torch.tensor([[1,1],[2,2]])
    print(a*b)
    print("----------")
    print(a.mul(b))
    
    pass 

if __name__=="__main__":
    test()

Tensor相乘

与高等数学中矩阵的乘法类似,n行m列矩阵乘m行p列矩阵得n行p列矩阵

使用@或者matmul完成Tensor的乘法

import torch

def test():
    a=torch.tensor([[1,2],[3,4]])
    b=torch.tensor([[1,1],[2,2]])
    print(a@b)
    print("----------")
    print(a.matmul(b))

    pass 

if __name__=="__main__":
    test()

2.索引操作

张量也是有序序列,我们可以根据每个元素在系统内的顺序位置,来找出特定的元素,也就是索引。

n维张量的简单索引

与python索引相似,格式为[start:end:step],在python中step可以去负数,但在tensor中step必须>0,默认值为1

一维张量的索引
import torch

def test():
    a=torch.arange(0,10)
    print(a)
    #tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    print(a[0:5])
    # tensor([0, 1, 2, 3, 4])
    print(a[0:4:2])
    # tensor([0, 2])

#要转换为单独的数需要用上面提到的item()
    pass 

if __name__=="__main__":
    test()
二维张量的索引
import torch

def test():
    a=torch.arange(1,17).reshape(4,4)
    print(a)
    print(a[0,1])
    print(a[0][1])
    print(a[::2,::2])
    # 用逗号隔开时,取第一行和第三行的第一列和第三列的元素。
    print(a[::2][::2])
    # 在两个中括号中时,先取了第一行和第三行,构成一个新的二维张量,然后又间隔2并对所有张量进行索引。
    pass 

if __name__=="__main__":
    test()

三维张量的索引

与二维张量的索引类似,都是围绕"形状"进行索引

import torch

def test():
    a=torch.arange(1,9).reshape(2,2,2)
    print(a)
    print(a[0,1,1])
    print(a[0][1][1])
    print(a[1,::2,::2])
    print(a[1][::1][::1])
    pass 

if __name__=="__main__":
    test()

布尔索引

import torch

def test():
    a=torch.arange(1,9).reshape(2,2,2)
    print(a)
    print("-------")
    # 1. 索引第2个元素大于5的所有行
    print(a[a[:,1]>5])
    print("-------")

    # 索引第1行值大于3的所有的元素所在的列
    print(a[:,a[0]>3])
    print("-------")

    # 3. 第二列是偶数, 且第一列大于2的行
    print(a[(a[:, 1] % 2 == 0) & (a[:, 0] > 2)])
    print("-------")
    pass 

if __name__=="__main__":
    test()

索引赋值

import torch

def test():
    a=torch.arange(0,10)
    print(a)
    #tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    a[5]=100
    print(a)
    # tensor([  0,   1,   2,   3,   4, 100,   6,   7,   8,   9])
    pass 

if __name__=="__main__":
    test()

3.张量拼接

要堆叠的张量必须具有相同的形状。

        cat:在现有维度上拼接,不会增加新维度。

        stack:在新维度上堆叠,会增加一个维度。

torch.cat

concatenate 的缩写

import torch

def test():
    a=torch.tensor([[1,1],[2,2]])    
    b=torch.tensor([[3,3],[4,4]]) 
    print(torch.cat([a,b],dim=0))
    print(torch.cat([a,b],dim=1))
    pass 

if __name__=="__main__":
    test()

torch.stack

import torch

def test():
    a=torch.tensor([[1,1],[2,2]])    
    b=torch.tensor([[3,3],[4,4]]) 
    print(torch.stack([a,b],dim=0))
    print(torch.stack([a,b],dim=1))
    pass 

if __name__=="__main__":
    test()

4.形状操作

reshape:更灵活,但涉及内存复制

view:高效,但需要张量在内存中是连续的

①reshape

改变张量的形状,但元素个数不能改变

代码示例:布尔索引示例代码中已有示例

②view

view进行形状变换的特征:

  • 张量在内存中是连续的;

  • 返回的是原始张量视图,不重新分配内存,效率更高;

  • 如果张量在内存中不连续,view 将无法执行,并抛出错误。

import torch

def task():
    t1=torch.tensor([[1,1],[2,2]])
    #contiguous连续的
    print("正常的张量:",t1.is_contiguous())

    t2=t1.t()
    print("转置后的张量:",t2.is_contiguous())
    print(t2)
    print("----------")

    # -1表示自动计算
    t3=t2.view(2,-1)
    print(t3)
    print("----------")

    tensor=torch.tensor([[1,2,3],[4,5,6]])
    print(tensor)
    tensor_new=tensor.view(3,2)
    print(tensor_new)

    pass

if __name__ == "__main__":
    task()

③transpose

交换张量的两个维度

import torch

def task():
    data=torch.randint(0,10,(3,3))
    print(data,data.shape)
    data_new=data.transpose(-2,1)
    print(data_new,data_new.shape)
    pass

if __name__ == "__main__":
    task()

④permute

改变张量的所有维度顺序。与 transpose 类似,但它可以交换多个维度。

import torch

def task():
    data=torch.randint(0,10,(3,3,3))
    print(data,data.shape)
    data_new=data.permute(1,0,2)
    print(data_new,data_new.shape)
    pass

if __name__ == "__main__":
    task()

⑤flatten

将张量展平为一维向量,

tensor.flatten(start_dim=0, end_dim=-1)

start_dim从哪个维度开始展,end_dim在哪个维度结束展平,默认值为 -1,表示展平到最后一个维度

import torch

def task():
    data=torch.randint(0,10,(3,3))
    print(data,data.shape)
    data_new1=data.flatten(0,-1)
    print(data_new1,data_new1.shape)
    data_new2=data.flatten(0,1)
    print(data_new2,data_new2.shape)
    data_new3=data.flatten(1,-1)
    print(data_new3,data_new3.shape)

    pass

if __name__ == "__main__":
    task()

⑥升维和降维

  • unsqueeze:用于在指定位置插入一个大小为 1 的新维度。——升维

  • squeeze:用于移除所有大小为 1 的维度,或者移除指定维度的大小为 1 的维度。——降维

import torch

def task():
    data=torch.randint(0,10,(3,3))
    print(data,data.shape)
    data_new1=data.squeeze(0)
    print(data_new1,data_new1.shape)
    data_new2=data.unsqueeze(0)
    print(data_new2,data_new2.shape)

    pass

if __name__ == "__main__":
    task()
# tensor([[5, 9, 0],
#         [2, 5, 1],
#         [3, 7, 9]]) torch.Size([3, 3])
# tensor([[5, 9, 0],
#         [2, 5, 1],
#         [3, 7, 9]]) torch.Size([3, 3])
# tensor([[[5, 9, 0],
#          [2, 5, 1],
#          [3, 7, 9]]]) torch.Size([1, 3, 3])

5.张量分割

chunk函数能够按照某个维度(dim)对张量进行均匀切分(chunks),并且返回结果是原张量的视图。

chunk(tensor, chunks, dim)

import torch

def task():
    data=torch.randint(0,10,(3,3,4))
    print(data)
    print("--------------")
    data_new=data.chunk(2,2)
    print(data_new)

    pass

if __name__ == "__main__":
    task()

6.广播机制

原理类似Numpy广播机制:https://blog.csdn.net/m0_68153457/article/details/140977333?spm=1001.2014.3001.5501

张量广播机制需遵循以下原则

  • 每个张量的维度至少为1

  • 满足右对齐

import torch

def task():
    data1=torch.tensor([[1,1],[2,2]])
    data2=torch.tensor([3,3])
    print(data1.shape,data2.shape)
    print(data1+data2)
    print("--------------")

    data3=torch.tensor([[[1,1],[2,2],[3,3]]])
    data4=torch.tensor([[4,4],[5,5],[6,6]])
    print(data3.shape,data4.shape)
    print(data3+data4)


    pass

if __name__ == "__main__":
    task()

7.数学运算

#此节需要记住api的特点特征,代码比较简单,不过多编写。

基本运算

floor: 向下取整;

ceil:向上取整;

round:四舍五入;

trunc:裁剪,只保留整数部分;

frac:只保留小数部分;

fix:向零方向舍入;

%:取余。

三角函数

torch.cos(input,out=None)

torch.cosh(input,out=None) # 双曲余弦函数

torch.sin(input,out=None)

torch.sinh(input,out=None) # 双曲正弦函数

torch.tan(input,out=None)

torch.tanh(input,out=None) # 双曲正切函数

统计学函数

torch.mean(): 计算张量的平均值。

torch.sum(): 计算张量的元素之和。

torch.std(): 计算张量的标准差。

torch.var(): 计算张量的方差。

torch.median(): 计算张量的中位数。

torch.max(): 计算张量的最大值。

torch.min(): 计算张量的最小值。

torch.sort(): 对张量进行排序。

torch.topk(): 返回张量中的前 k 个最大值或最小值。

torch.histc(): 计算张量的直方图。

torch.unique(): 返回张量中的唯一值。

torch.bincount(): 计算张量中每个元素的出现次数。

8.保存和加载

 保存:

torch.save(x,position)

加载:

 torch.load(position)

9.并行化

在 PyTorch 中,你可以查看和设置用于 CPU 运算的线程数。PyTorch 使用多线程来加速 CPU 运算,但有时你可能需要调整线程数来优化性能

注意:

  • 线程数设置过高可能会导致线程竞争,反而降低性能;

  • 线程数设置过低可能会导致计算资源未得到充分利用;

  • 当使用 GPU 进行计算时,线程数设置对性能影响较小,因为 GPU 计算并不依赖于 CPU 线程数。

查看线程数

使用 torch.get_num_threads() 来查看当前 PyTorch 使用的线程数

import torch


def get_threads():
    # 获取pytorch运行的线程数
    print(torch.get_num_threads())#4

    pass


if __name__ == "__main__":
    get_threads()

设置线程数

使用 torch.set_num_threads() 设置 PyTorch 使用的线程数

import torch

def set_get_threads():
    # 设置pytorch运行的线程数
    torch.set_num_threads(4)
    print(torch.get_num_threads())#4


if __name__ == "__main__":
    set_get_threads()

二、自动微分

自动求导是深度学习框架的重要组成部分。自动微分为深度网络学习中的梯度的计算提供了便捷

1.基础概念

  1. 张量

    Torch中一切皆为张量,属性requires_grad决定是否对其进行梯度计算。默认是 False,如需计算梯度则设置为True。

  2. 计算图

    torch.autograd通过创建一个动态计算图来跟踪张量的操作,每个张量是计算图中的一个节点,节点之间的操作构成图的边。

  3. 反向传播

    使用tensor.backward()方法执行反向传播,从而计算张量的梯度。这个过程会自动计算每个张量对损失函数的梯度。

  4. 梯度

    计算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。

2.计算梯度

使用tensor.backward()方法执行反向传播,从而计算张量的梯度

标量梯度计算

import torch

def task():

    #单标量

    #创建一个张量,只有浮点型和复数型的张量才需要梯度,此处该张量必须为浮点类型
    x=torch.tensor(7, requires_grad=True, dtype=torch.float32)

    y=x**3+x*2+1
    #计算梯度————反向传播
    y.backward()
    #读取梯度值
    print(x.grad)#tensor(149.)

    #多标量
    x1=torch.tensor(8, requires_grad=True, dtype=torch.float32)
    x2=torch.tensor(1, requires_grad=True, dtype=torch.float32)
    y=x1**2+x2*2+2
    y.backward()
    print(x1.grad,x2.grad)#tensor(16.) tensor(2.)
    pass

if __name__ == "__main__":
    task()

向量梯度计算

import torch

def task():

    #单向量

    #创建一个张量,只有浮点型和复数型的张量才需要梯度,此处该张量必须为浮点类型
    x=torch.tensor([1,2,3], requires_grad=True, dtype=torch.float32)

    y=x**3+x*2+1
    #需要变为标量:求和或者求均值都可以
    # z=y.sum() #tensor([ 5., 14., 29.])
    z=y.mean()#tensor([1.6667, 4.6667, 9.6667])


    #计算梯度————反向传播
    z.backward()
    #读取梯度值
    print(x.grad)

    #多向量
    x1=torch.tensor([1,2,3], requires_grad=True, dtype=torch.float32)
    x2=torch.tensor([4,5,6], requires_grad=True, dtype=torch.float32)
    y=x1**2+x2*2+2
    #z=y.sum()#tensor([2., 4., 6.]) tensor([2., 2., 2.])
    z=y.mean()#tensor([0.6667, 1.3333, 2.0000]) tensor([0.6667, 0.6667, 0.6667])

    z.backward()
    print(x1.grad,x2.grad)
    pass

if __name__ == "__main__":
    task()

3.梯度上下文控制

梯度计算的上下文控制和设置对于管理计算图、内存消耗、以及计算效率至关重要

控制梯度计算

import torch

def task():
    x = torch.tensor(11.9, requires_grad=True)
    print(x.requires_grad)#True

    # 1. 默认y的requires_grad=True
    y = x**2 + 2 * x + 3
    print(y.requires_grad)#True

    # 2. 如果不需要y计算梯度 -with进行上下文管理
    with torch.no_grad():
        y = x**2 + 2 * x + 3
    print(y.requires_grad)#False

    # 3. 如果不需要y计算梯度-使用装饰器
    @torch.no_grad()
    def y_fn(x):
        return x**2 + 2 * x + 3

    y = y_fn(x)
    print(y.requires_grad)#False

    pass

if __name__ == "__main__":
    task()

累计梯度

默认情况下,当我们重复对一个自变量进行梯度计算时,梯度是累加的

import torch

def task():
    x = torch.tensor([1,2,3,4], requires_grad=True,dtype=float)
    for i in range(4):
        y=x**2+x*2+1
        z=y.mean()
        z.backward()
        print(x.grad)

    pass

if __name__ == "__main__":
    task()

# tensor([1.0000, 1.5000, 2.0000, 2.5000], dtype=torch.float64)
# tensor([2., 3., 4., 5.], dtype=torch.float64)
# tensor([3.0000, 4.5000, 6.0000, 7.5000], dtype=torch.float64)
# tensor([ 4.,  6.,  8., 10.], dtype=torch.float64)

        大多数情况下是不需要梯度累加的

梯度清零

import torch

def test():
    x=torch.tensor([1,2,3],requires_grad=True,dtype=float)
    y=x**2+x*2+2
    z=y.mean()
    #反向传播前先对梯度进行清零
    if x.grad is not None:
        x.grad.zero_()

    z.backward()
    print(x.grad)
    pass

if __name__=="__main__":
    test()
#tensor([1.3333, 2.0000, 2.6667], dtype=torch.float64)

示例——求函数最优解

def test1():
    x=np.arange(-10,10,0.1)
    y=x**2+x*3+4
    #绘制表格
    plt.grid()
    plt.plot(x,y)
    plt.show()

def test2():
    #初始化x值
    x=torch.tensor(5,requires_grad=True,dtype=float)
    # 2. 找到损失函数的最小值:迭代进行梯度下降
    for i in range(1000):
        # 2.1 计算损失函数
        y = x**2+x*3+4
        # 2.2 梯度清零
        if x.grad is not None:
            x.grad.data.zero_()

        y.backward()

        # 梯度下降
        x.data.sub_(0.01 * x.grad.data)
        print(x.item(), y.item())



if __name__ == "__main__":
    test1()
    test2()

4.梯度计算小结

转换错误

当requires_grad=True时,在调用numpy转换为ndarray时报错如下:

RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.

错误处理

使用detach()方法创建张量的叶子节点即可

import torch

def test():
    x=torch.tensor([1,2,3],requires_grad=True,dtype=float)
    print(x.detach().numpy())#[1. 2. 3.]
    print(x.detach())#tensor([1., 2., 3.], dtype=torch.float64)
    pass

if __name__=="__main__":
    test()

叶子结点

detach()产生的张量是作为叶子结点存在的,并且该张量和原张量共享数据,只是该张量不需要计算梯度。

import torch

def test():
    x=torch.tensor([1,2,3],requires_grad=True,dtype=float)
    x_new=x.detach()
    print("是两个东西:",id(x),id(x_new))
    print("数据是共享的:",id(x.data),id(x_new.data))

    x_new[0]=100
    print(x,x_new)

    
    pass

if __name__=="__main__":
    test()

三、手动构建模型

名词定义
Epoch(时代)使用训练集的全部数据对模型进行一次完整训练,被称为“一代训练”
Batch(批处理)使用训练集中的一小部分样本对模型权重进行一次反向传播的参数更新,这一小部分样本被称为“一批数据”
Iteration(迭代)使用一个Batch数据对模型进行一次参数更新的过程,被称为“一次训练”

1.数据处理

构建数据集

 使用 sklearn 的 make_regression 方法来构建一个模拟的回归数据集。

    make_regression 方法的参数解释:
    - n_samples: 生成的样本数量,决定了数据集的规模。
    - n_features: 生成的特征数量,决定了数据维度。
    - noise: 添加到目标变量的噪声标准差,用于模拟真实世界数据的不完美。
    - coef: 如果为 True, 会返回生成数据的真实系数,用于了解特征与目标变量间的真实关系。
    - random_state: 随机数生成的种子,确保在多次运行中能够复现相同的结果。

    返回:
    - X: 生成的特征矩阵。
    - y: 生成的目标变量。
    - coef: 如果在调用时 coef 参数为 True,则还会返回真实系数。

——coef 系数

——bias偏差

import torch
import random
import math
import numpy as np
from sklearn.datasets import make_regression
import pandas as pd

def build_dataset():
    n=random.randint(1,5)
    x,y,coef=make_regression(n_samples=1000,n_features=5,bias=14.5,noise=n,coef=True,random_state=0)
    #将数据转换为张量
    x=torch.tensor(x,dtype=float)
    y=torch.tensor(y,dtype=float)
    coef=torch.tensor(coef,dtype=float)

    return x,y,coef

if __name__=="__main__":
    #构建一批数据集
    x,y,coef=build_dataset()
    #将特征数据x转换为DataFrame,并添加列名
    features_names=[f"feature_{i+1}" for i in range(x.shape[1])]
    x_df=pd.DataFrame(x,columns=features_names)

    #创建包含目标变量y的Series
    y_series=pd.Series(y,name="Target")

    #将特征和目标变量数据合并为一个完整的数据集
    data_df=pd.concat([x_df,y_series],axis=1)


    print(f"前五行的数据:\n{data_df.head()}")

    print(f"生成数据的真实系数:\n{coef}")

构建数据加载器

import torch
import random
import math
import numpy as np
from sklearn.datasets import make_regression
import pandas as pd

def build_dataset():
    n=random.randint(1,5)
    x,y,coef=make_regression(n_samples=1000,n_features=5,bias=14.5,noise=n,coef=True,random_state=0)
    #将数据转换为张量
    x=torch.tensor(x,dtype=float)
    y=torch.tensor(y,dtype=float)
    coef=torch.tensor(coef,dtype=float)

    return x,y,coef

def data_loader(x,y,batch_size=16):
    # 将数据集转换为迭代器,以便在训练过程中进行批量处理

    #获取样本数量
    num_samples=x.shape[0]
    #构建数据索引
    index=list(range(num_samples))

    #打乱数据顺序
    random.shuffle(index)

    #计算总的批次数量:向上取整
    num_batches=math.ceil(num_samples / batch_size)


    for i in range(num_batches):
        start=i*batch_size
        end=min((i+1)*batch_size,num_samples)

        #切片数据
        x_train=x[index[start:end]]
        y_train=y[index[start:end]]

        #异步响应数据集
        yield x_train,y_train

运行结果就省略了吧。。。。太长了

2.模型函数

def linear_regression(x, w, b):
    return torch.matmul(x, w) + b

  1. 点积运算(Matmul)torch.matmul(x, w) 计算输入 xx 与权重 ww 的矩阵乘法。这里假设 xx 是一个一维向量或二维张量,而 ww 是一个权重矩阵,其形状适合进行矩阵乘法。

  2. 加偏置:然后将上述结果与偏置项 bb 相加。偏置项 bb 通常是标量或向量,它的尺寸应该与 xwxw 的结果相匹配,使得两者能够进行逐元素加法操作。

示例

如果我们有一个二维输入数据集 xx,每个样本有多个特征,ww 就是一个矩阵,其中每一行对应于输入特征的一个权重向量。bb 是一个向量,每个元素对应输出维度上的偏置。

例如,如果 xx 是一个形状为 (N, D) 的张量(N 个样本,每个样本有 D 个特征),ww 是一个形状为 (D, M) 的权重矩阵(从 D 个输入特征映射到 M 个输出),那么 torch.matmul(x, w) 的结果将是 (N, M) 形状的张量。接着加上一个形状为 (M,) 的偏置向量 bb,最终输出也将是 (N, M) 形状的张量。

这就是函数 linear_regression(x, w, b) 的基本作用。

import torch
x=torch.tensor([[1],[2],[3]])
w=torch.tensor([[1,2,3]])
b=torch.tensor([1])

def linear_regression(x,w,b):
    y=torch.matmul(x,w)+b
    return y

y=linear_regression(x,w,b)
print(y)
# tensor([[ 2,  3,  4],
#         [ 3,  5,  7],
#         [ 4,  7, 10]])

3.损失函数

def mean_squared_error(y_pred, y_true):
    return torch.mean((y_pred - y_true) ** 2)

函数 mean_squared_error 实现了均方误差(Mean Squared Error, MSE)的计算。均方误差是一个常用的损失函数,用于评估预测值 y_{\text{pred}}ypred​ 与真实值 y_{\text{true}}ytrue​ 之间的差异。它是通过计算预测值与真实值之间差的平方的平均值来得到的。

参数说明

  • y_pred: 预测值,通常是一个张量,形状为 (N,) 或 (N, 1),其中 N 是样本数量。
  • y_true: 真实值,也是一个张量,形状与 y_pred 相同。

返回值

  • 返回一个标量张量,表示所有样本的均方误差。

详细步骤

  1. 计算差值diff = y_pred - y_true 计算每个样本的预测值与真实值之间的差。
  2. 计算平方squared_diff = diff ** 2 对每个差值求平方。
  3. 计算均值mse = torch.mean(squared_diff) 求所有样本差值平方的平均值。

示例代码

import torch

y_true = torch.tensor([1.0, 2.0, 3.0])
y_pred = torch.tensor([1.5, 1.8, 2.9])

# 定义均方误差函数
def mean_squared_error(y_pred, y_true):
    diff = y_pred - y_true
    squared_diff = diff ** 2
    mse = torch.mean(squared_diff)
    return mse

# 计算均方误差
mse = mean_squared_error(y_pred, y_true)
print("均方误差:", mse.item())  # 使用 .item() 将张量转换为 Python 数字
# 均方误差: 0.10000000149011612

输出的结果 均方误差 (MSE)表示预测值与真实值之间的平均误差大小。越接近于 0,表示预测越准确。

4.优化器

def sgd(w, b, dw, db, learning_rate, batch_size):
    w.data -= learning_rate * dw.data / batch_size
    b.data -= learning_rate * db.data / batch_size
    return w, b

参数说明

  • w:权重张量,通常是模型中的权重参数。
  • b:偏置张量,通常是模型中的偏置参数。
  • dw:权重的梯度,即损失函数相对于权重的导数。
  • db:偏置的梯度,即损失函数相对于偏置的导数。
  • learning_rate:学习率,控制每次更新步长的大小。
  • batch_size:批量大小,表示当前使用的样本数量。

返回值

  • 返回更新后的权重 w 和偏置 b

详细步骤

  1. 计算权重更新w.data -= learning_rate * dw.data / batch_size,这里的 dw.data 是权重的梯度,通过除以 batch_size 并乘以 learning_rate 来确定更新步长。
  2. 计算偏置更新b.data -= learning_rate * db.data / batch_size,这里的 db.data 是偏置的梯度,同样通过除以 batch_size 并乘以 learning_rate 来确定更新步长。

示例代码

import torch

def sgd(w, b, dw, db, learning_rate, batch_size):
    w.data -= learning_rate * dw.data / batch_size
    b.data -= learning_rate * db.data / batch_size
    return w, b

# 初始化权重和偏置
w = torch.tensor([0.5], requires_grad=True)
b = torch.tensor([0.0], requires_grad=True)

# 假设我们已经计算出了梯度
dw = torch.tensor([0.2])
db = torch.tensor([0.1])

# 设置学习率和批量大小
learning_rate = 0.01
batch_size = 10

# 更新权重和偏置
w, b = sgd(w, b, dw, db, learning_rate, batch_size)

print("更新后的权重:", w.item())
print("更新后的偏置:", b.item())

# 更新后的权重: 0.4997999966144562
# 更新后的偏置: -0.00010000000474974513

5.参数初始化

# 初始化参数
def initialize_params(n_features):
    # 随机初始化权重w,并将偏置b初始化为0
    w = torch.randn(n_features, requires_grad=True, dtype=torch.float32)
    b = torch.tensor(0.0, requires_grad=True, dtype=torch.float32)
    return w, b

函数 initialize_params 用于初始化线性回归模型中的参数,包括权重 w 和偏置 b

参数说明

  • n_features:输入特征的数量,即每个样本的维度。

返回值

  • 返回初始化后的权重 w 和偏置 b

详细步骤

  1. 初始化权重 w

    • 使用 torch.randn 函数生成一个形状为 (n_features,) 的一维张量。
    • requires_grad=True 表示这个张量需要计算梯度,以便在反向传播过程中更新。
    • dtype=torch.float32 指定张量的数据类型为 32 位浮点数。
  2. 初始化偏置 b

    • 使用 torch.tensor 创建一个标量张量,值为 0.0。
    • 同样设置 requires_grad=True 以便计算梯度。
    • 数据类型同样为 torch.float32

示例代码

import torch

# 初始化参数
def initialize_params(n_features):
    # 随机初始化权重 w,并将偏置 b 初始化为 0
    w = torch.randn(n_features, requires_grad=True, dtype=torch.float32)
    b = torch.tensor(0.0, requires_grad=True, dtype=torch.float32)
    return w, b

# 假设我们有 3 个特征
n_features = 3

# 初始化参数
w, b = initialize_params(n_features)

# 假设我们有一些输入数据 x
x = torch.tensor([[1.0, 2.0, 3.0],[4.0, 5.0, 6.0]], dtype=torch.float32)

# 定义线性回归函数
def linear_regression(x, w, b):
    return torch.matmul(x, w) + b

# 计算预测值
y_pred = linear_regression(x, w, b)

print("预测值:", y_pred)

# 预测值: tensor([ 6.3001, 11.5534], grad_fn=<AddBackward0>)

6.训练函数和项目整合

import torch
from sklearn.datasets import make_regression
import random
import math


# 数据集创建
def build_datasets(n_features=1):
    noise = 3
    bias = 0.0
    x, y, ceof = make_regression(
        n_samples=1000,  # 样本数量
        n_features=n_features,  # 特征数量
        noise=noise,
        coef=True,  # 是否返回系数
        bias=bias,  # 偏置
        random_state=42,  # 随机数种子
    )
    # 转换为张量
    x = torch.tensor(x, dtype=torch.float32)
    y = torch.tensor(y, dtype=torch.float32)
    ceof = torch.tensor(ceof, dtype=torch.float32)
    bias = torch.tensor(bias, dtype=torch.float32)

    return x, y, ceof, bias


# 数据加载器
def data_loader(x, y, batch_size):
    # 样本数量
    length = x.shape[0]
    # 组装索引列表
    idx = [i for i in range(length)]
    # 打乱
    random.shuffle(idx)

    # 总共需要取多少次:32
    batch_num = math.ceil(length / batch_size)
    for i in range(batch_num):
        index = idx[i * batch_size : (i + 1) * batch_size]
        yield x[index], y[index]


# 线性模型
def model(x, w, b):
    return torch.matmul(x, w) + b


# 参数初始化小函数
# def init_wandb(feature):
#     w = torch.randn(feature, 1, requires_grad=True)
#     b = torch.zeros(1, requires_grad=True)
#     return w, b
def init_wandb(feature):
    w = torch.randn(feature, requires_grad=True)
    b = torch.tensor(0.0, requires_grad=True, dtype=torch.float32)
    return w, b


# 损失函数
def mseLoss(ypred, label):
    return torch.mean((ypred - label) ** 2)


# 优化器
def sgd(w, b, lr=1e-2, batch_size=1):
    w.data = w.data - lr * (w.grad.data)
    b.data = b.data - lr * (b.grad.data)
    return w, b


def train():
    # 数据集
    feature = 5
    x, y, ceof, bias = build_datasets(feature)

    # 定义一些基本的训练参数
    epochs = 100  # 训练代次
    lr = 1e-2  # 学习率
    batch_size = 32  # 批处理大小

    # 模型参数初始化
    w, b = init_wandb(feature)

    for i in range(epochs):
        # 构建数据加载器
        for x_batch, target in data_loader(x, y, batch_size):
            # 使用模型预测值
            ypred = model(x_batch, w, b)
            # 计算损失
            loss = mseLoss(ypred, target)

            # 梯度清零
            if w.grad is not None:
                w.grad.zero_()

            if b.grad is not None:
                b.grad.zero_()

            # 反向传播
            loss.backward()
            # 梯度更新
            w, b = sgd(w, b, lr, batch_size)

        print(f"Epoch {i}:", w, b)#略

    print("训练的权重参数:", w)
    print("真实的权重参数:", ceof)

#训练的权重参数: tensor([28.4494, 46.0176, 16.7525, 24.6441, 19.0856], requires_grad=True)
#真实的权重参数: tensor([28.6280, 46.0712, 16.8237, 24.7463, 18.9935])


if __name__ == "__main__":
    train()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2096784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用本地IP无法访问前端项目的问题

说明&#xff1a;记录一次使用本机IP无法访问前端项目的问题 场景&解决 前端项目在我本机电脑上部署完成&#xff0c;我想通过局域网的IP把地址发给测试&#xff0c;发现使用localhost和127.0.0.0都能访问到前端项目&#xff0c;但是这个地址只能在自己的电脑上访问。 解…

Java响应式编程

Java响应式编程是一种基于异步和非阻塞的编程范式&#xff0c;旨在处理现代应用中日益增长的高并发、海量数据以及低延迟需求。通过响应式编程&#xff0c;开发者能够以更加优雅和高效的方式编写能够应对这些挑战的应用程序。 Quick start import reactor.core.publisher.Flux…

认知杂谈44

今天分享 有人说的一段争议性的话 《耐心雕琢人生&#xff1a;终身学习&#xff0c;绘就多彩画卷》 嘿&#xff0c;咱都知道&#xff0c;老有人说二十一天就能养成个新习惯&#xff0c;听着好像挺容易挺快的哈。 I I 可实际上呢&#xff0c;靠这种速成法养出来的习惯&#xff…

uniapp生命周期函数

常见页面生命周期函数 onLoad(options): 页面加载时触发&#xff0c;可以接收启动页面时的参数 onShow: onReady: 页面初次渲染完成时触发。 onHide: 页面被隐藏时触发 onUnload: 页面被关闭时触发 onLoad作用 获取url传递的参数,可以使用onLoad来获取,具体实现可以查看 如何获…

MySQL进阶篇1

一、存储引擎 1.1 MySQL体系结构 1.2 存储引擎简介 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的&#xff0c;而不是基于库的&#xff0c;所以存储引擎也可被称为表类型。 1.3 存储引擎特点 1.4 存储引擎选择 存储引擎没有好坏之分&am…

Ubuntu22.04安装 docker和docker-compose环境

Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;它使开发者能够打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff08;…

深度学习入门笔记

深度学习入门笔记 感知机逻辑与门与非门或门多层感知机异或门 神经网络激活函数输出层设计损失函数均方误差 MSE交叉熵误差 反向传播算法计算图局部计算计算图反向传播反向传播 参数更新训练过程总结 该篇文章为本人学习笔记的一部分。笔记基于《深度学习入门 基于python理论实…

Navicat连接Mongodb成功了,但是无法显示数据库怎么办?

不知道你是否遇到过&#xff1f;Navicat连接Mongodb成功了&#xff0c;但是无法显示数据库怎么办&#xff1f; 解决办法 这个问题比较坑&#xff0c;对于第一次接触的小伙伴&#xff0c;可能会一脸懵逼&#xff0c;原因就是在Navicat中默认会不显示隐藏的项目&#xff0c;如果不…

产品/运营经理的数据分析思维和学习路径

数据分析是产品经理和运营同学必知必会的技能之一&#xff0c;该技能会贯穿到产品经理和运营同学的整个职业生涯。 产品经理不需要成为数据分析方面的专家&#xff0c;但分析哪些数据、如何分析数据、如何用数据辅助决策、如何用数据驱动业务&#xff0c;这些是产品和运营同学…

C++学习笔记之指针(基础)

C学习笔记之指针&#xff08;基础&#xff09; https://www.runoob.com/cplusplus/cpp-pointers.html C/C中的指针内容是早就盛名在外了&#xff0c;当然了&#xff0c;想要随心所欲地使用也是要做很多功课的&#xff0c;先简单了解下吧~ 首先&#xff0c;我们需要了解一点内存…

STM32基础篇:RTC × Unix时间戳 × BKP

Unix时间戳 最早是在Unix系统使用的&#xff0c;之后很多由Unix演变而来的系统也都继承了Unix时间戳的规定。目前&#xff0c;Linux、Windows、安卓这些系统&#xff0c;其底层的计时系统都是使用Unix时间戳。 Uinx时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/…

论文速读|ReKep:空间时间理论的关系关键点约束,用于机器人操作

项目地址&#xff1a;ReKep | Spatio-Temporal ReasoningReKep | Spatio-Temporal Reasoning of Relational Keypoint Constraints for Robotic ManipulationReKep | Spatio-Temporal Reasoning ReKep&#xff08;Relational Keypoint Constraints&#xff09;是一种基于视觉的…

Nebula: 无服务器计算中的性能和能源效率 - WebAssembly与Docker的比较研究

这篇论文的标题是《Nebula: Performance and Energy Efficiency in Serverless Computing - A Comparative Study of WebAssembly and Docker》&#xff0c;作者是 Marius Nilsen Kluften&#xff0c;来自奥斯陆大学&#xff08;University of Oslo&#xff09;的信息学系。论文…

android仿assistivetouch悬浮窗实现(带功能实现)

一、悬浮窗点击后的界面&#xff1a; 主要有四个功能&#xff0c;返回、应用程序、退出和主界面。其他功能也可以类似添加。 界面布局代码就不贴出来了&#xff0c;源码&#xff08;切记需要签名才能让功能实现&#xff09;&#xff1a;下载地址 二、主要是检测系统启动或者a…

时序数据库荣登巅峰,被央视报道了!

8月30日&#xff0c;事务处理性能委员会TPC正式公布了最新的国际权威数据库性能基准榜单&#xff0c;“清华系”发起研制的Apache IoTDB开发的国产化时序数据库软件TimechoDB&#xff0c;在性能和系统成本维度上双双打破世界纪录。在央视《24小时》节目中&#xff0c;1分34秒重…

《黑神话:悟空》与游戏经济学的深度剖析

《黑神话&#xff1a;悟空》作为近年来备受瞩目的国产3A游戏大作&#xff0c;自其发布以来&#xff0c;不仅在游戏界内引起了轰动&#xff0c;更在多个消费领域产生了深远的影响。这款游戏不仅以其卓越的品质和深刻的文化内涵吸引了大量玩家的关注&#xff0c;还通过一系列连锁…

神策埋点 sensorsdata.es6.min.js、sensorsdata.min.js 触发eslint 语法检查,导致打包不成功

问题描述&#xff1a; 在使用神策埋点时&#xff0c;下载的web js sdk&#xff0c;打包时eslint 语法检查&#xff0c;会导致打包不成功。npm start没问题。 主要错误是&#xff1a; Line 1:204272: Expected an assignment or function call and instead saw an expression …

[Python]之深拷贝与浅拷贝

Python之深拷贝与浅拷贝 概述: ​ 大白话解释就是 深拷贝拷贝的多, 浅拷贝拷贝的少. 深浅拷贝区别就是: 拷贝的层级的多与少. 深浅拷贝都能操作可变类型 和 不可变类型, 但是深浅拷贝一般操作的都是 可变类型, 几乎不会出操作不可变类型的. 可变类型 和 不可变类型的划分依…

openssl RSA 密钥(key)、证书签名请求(csr)、证书(cer)的生成和例子

1. RSA 密钥(key)、证书签名请求&#xff08;csr&#xff09;、证书&#xff08;cer&#xff09;的生成顺序 2. 具体操作 a. 生成 RSA 密钥&#xff08;私钥&#xff09; openssl genrsa -aes256 -out ca.key 2048b. 生成证书签名请求(csr) # C-----国家&#xff08;Country…

Oracle超详细(数据库编程)

目录 一、数据类型 &#xff08;一&#xff09;数值型数据类型 &#xff08;二&#xff09;字符型数据类型 &#xff08;三&#xff09;日期和时间型数据类型 &#xff08;四&#xff09;大对象和二进制数据类型 &#xff08;五&#xff09;其他数据类型 &#xff08;六&…