Pytorch入门

Pytorch

1.0 手动实现梯度下降

import torch

weight=torch.zeros(2,1 ,requires_grad=True)
X=torch.tensor([[1.,1.],[3.,1.]],requires_grad=True)
y=torch.tensor([2.,4],requires_grad=True).reshape(2,1)
eps=0.01
for k in range(1000):
    grad = torch.mm(X.t(), (torch.mm(X, weight) - y)) / 2
    weight = weight - eps * grad
print(weight)

1.1 单层网络

import torch
from sympy.codegen.ast import float32

torch.random.manual_seed(111)
X=torch.tensor([[0,0],[1,0],[0,1],[1,1]],dtype=torch.float32)
output=torch.nn.Linear(2,1)
zhat=output(X)
print(zhat)

使用nn.Linear实现单层神经网络预测,2是输入层的特征个数,1是输出层的维度,我们的截距b在这里被省

略了,在输入里面也不需要单独的写一列的1,因为最后会自动加上,如果不需要可以取消

1.2 逻辑回归正向传播

import torch
from sympy.codegen.ast import float32

X=torch.tensor([[1,0,0],[1,1,0],[1,0,1],[1,1,1]],dtype=torch.float32)

andgate=torch.tensor([[0],[0],[0],[1]],dtype=torch.float32)

w=torch.tensor([-0.2,0.15,0.15],dtype=torch.float32)

def LogisticR(X,w):
    zhat=torch.mv(X,w)
    sigma=1/(1+torch.exp(-zhat))
    # sigma=torch.sigmoid(zhat)
    andhat=torch.tensor([int(x) for x in sigma>=0.5 ],dtype=torch.float32)
    return sigma,andhat
    # andhat=torch.tensor([ 1 if i>=0.5 else 0 for i in zhat])

sigma,andhat=LogisticR(X,w)
print(sigma)
print(andhat)

1.3 多层神经网络构建

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self,in_features=10,out_feature=2):
        """
        Args:
        in_features:输入神经网络的特征数目(输入层上神经元的数目)
        out_features:神经网络的输出的数目(输出层上神经元的数目)
        """
        super().__init__()
        self.linear1 =nn.Linear(in_features,13,bias=True)
        self.linear2= nn.Linear(13,8,bias=True)
        self.output=nn.Linear(8,out_feature)

    def forward(self,x):
        z1=self.linear1(x)
        sigma1=torch.relu(z1)
        z2=self.linear2(sigma1)
        sigma2=torch.sigmoid(z2)
        z3=self.output(sigma2)
        sigma3=F.softmax(z3,dim=1)
        return sigma3

X=torch.rand(500,20,dtype=torch.float32)
y=torch.randint(low=0,high=3,size=(500,1),dtype=torch.float32)
input_=X.shape[1]
output_=len(y.unique())
torch.random.manual_seed(420)
net=Model(input_,output_)

print(net.forward(X).shape)

注意,在内部乘时,权重在前,特征矩阵在后

所以我们输入的(500,20)会变成(20,500) 和一个个和内部的权重矩阵相乘,比如第一层的特征矩阵为(13,20) 所以

第一层的输出结果为(13,500) 我们经过多层,最后的结果为(3,500) 但到计算完毕内部会将其调转过来,变成

(500,3)的矩阵来便于观察

1.4 MSE

MSE作为损失函数一般用于回归类

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import MSELoss

#预测值
yhat= torch.randn(size=(50,),dtype=torch.float32)
#真实值
y=torch.randn(size=(50,),dtype=torch.float32)

#reduction 有两种值,一个是mean 一个是sum ,sum就不除数据个数,默认是mean
criterion= MSELoss(reduction="mean")

loss=criterion(yhat,y)
print(loss) # 求得均方的值

1.5 二分类交叉熵损失函数

交叉熵损失函数一般用在二分类任务

单个样本:

\[L = - \left[ y \cdot \log(\hat{y}) + (1 - y) \cdot \log(1 - \hat{y}) \right] \]

批量样本:

\[J = - \frac{1}{N} \sum_{i=1}^{N} \left[ y_i \cdot \log(\hat{y}_i) + (1 - y_i) \cdot \log(1 - \hat{y}_i) \right] \]

这里的自变量是w, w是特征矩阵,在这里包含在yhat里

使用二分类交叉熵损失函数的原理是极大似然估计

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,1),dtype=torch.float32)
y=torch.randint(low=0,high=2,size=(m,1))
zhat=torch.mm(X,w)
sigma=torch.sigmoid(zhat)
loss=-(1/m)*torch.sum((y*torch.log(sigma)+(1-y)*torch.log((1-sigma))))


注意张量运算的规则以及广播机制

使用BCELOSS

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,1),dtype=torch.float32)
y=torch.randint(low=0,high=2,size=(m,1),dtype=torch.float32)
zhat=torch.mm(X,w)
sigma=torch.sigmoid(zhat)
criterion=nn.BCELoss()
loss= criterion(sigma,y)
print(loss)

使用另一个函数

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,1),dtype=torch.float32)
y=torch.randint(low=0,high=2,size=(m,1),dtype=torch.float32)
zhat=torch.mm(X,w)
criterion=nn.BCEWithLogitsLoss()
loss= criterion(zhat,y)
print(loss)

BCEWithLogitsLoss 自带sigmoid 函数,所以直接使用zhat,注意,这两个函数真实值都在后面

BCEWithLogitsLoss的sigmoid精度更高一点

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,1),dtype=torch.float32)
y=torch.randint(low=0,high=2,size=(m,1),dtype=torch.float32)
zhat=torch.mm(X,w)
criterion=nn.BCEWithLogitsLoss(reduction="mean")
loss= criterion(zhat,y)
print(loss)

同样可以指定reduction的类型

1.6 多分类交叉熵损失函数

多分类交叉熵损失函数的数学形式。它使用了 \(\sigma\)(Sigma)来表示模型的输出概率(通常是 Softmax 的结果),使用 \(\ln\) 表示自然对数。

公式

\[L(w) = - \sum_{i=1}^{m} y_i \ln \sigma_i \]

:图片中的 subscript(下标)\(y_{i(k=j)}\) 写法比较特殊,通常在标准数学表达中简化为 \(y_i\)。该下标的含义是表示“当类别索引 \(i\) 等于真实类别标签 \(k\)(或 \(j\))时,\(y\) 取值为 1,否则为 0”。


符号详细解释

这个公式主要用于计算单个样本在多分类任务中的损失:

  • \(L(w)\):损失函数(Loss Function),\(w\) 代表模型的权重参数。
  • \(-\):负号。因为 \(\ln(\text{概率})\) 是负数,加上负号使损失变为正数。
  • \(\sum_{i=1}^{m}\):求和符号。
    • \(m\):代表类别的总数量(Class numbers)。
    • \(i\):当前遍历的类别索引。
  • \(y_i\)真实标签(Ground Truth)。
    • 这是一个 One-hot 向量的第 \(i\) 个元素。
    • 如果图片属于类别 \(i\),则 \(y_i = 1\);否则 \(y_i = 0\)
    • (这也解释了图片中 \(y_{i(k=j)}\) 这种写法的意图:它是指代真实类别的指示变量)。
  • \(\ln\):自然对数(以 \(e\) 为底)。
  • \(\sigma_i\)预测概率
    • 通常指模型经过 Softmax 激活函数后,输出的属于第 \(i\) 类的概率。
    • \(\sigma\) 在这里代表 Softmax 函数输出。)。

具体实现:

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,3),dtype=torch.float32)
y=torch.randint(low=0,high=3,size=(m,),dtype=torch.float32)
zhat=torch.mm(X,w)
logsm=nn.LogSoftmax(dim=1)
logsigma=logsm(zhat)
criterion=nn.NLLLoss()
loss=criterion(logsigma,y.long())
print(loss)

使用NLLLoss(负对数似然)和logsoftmax

第二种方式直接使用CrossEntropyLoss

import torch
import torch.nn as nn
m= 3*pow(10,3)
torch.manual_seed(420)
X=torch.rand((m,4),dtype=torch.float32)
w=torch.rand((4,3),dtype=torch.float32)
y=torch.randint(low=0,high=3,size=(m,),dtype=torch.float32)
zhat=torch.mm(X,w)
criterion=nn.CrossEntropyLoss()
loss=criterion(zhat,y.long())
print(loss)
posted @ 2026-01-05 23:21  折翼的小鸟先生  阅读(3)  评论(0)    收藏  举报