【轩说Pytorch】逻辑回归

逻辑回归

逻辑回归是指用类似线性回归的手段,解决分类问题。在多类别分类中,一般采用softmax 方法。

比如图片分类、恶意软件分类、文字分类问题。

Softmax:
y ^ = s o f t m a x ( o ) 意味着 y i = e x p ( o i ) Σ k e x p ( o k ) \hat y=softmax(o)意味着\\ y_i=\frac{exp(o_i)}{\mathop\Sigma\limits_{k} exp(o_k)} y^=softmax(o)意味着yi=kΣexp(ok)exp(oi)
对类别进行embedding,最简单的编码方式为one-hot编码。预测分布和真实概率的差异可以看作是“损失函数值”,通常用“交叉熵”来做。设 y ^ \hat y y^是预测分布, y y y是真是分布

类别1234
真是分布(y)0100
预测分布(softmax)0.060.90.020.02

CrossEntropyLoss
L o s s = Σ i y i ( − l o g y ^ i ) = 0 ⋅ ( − l o g 0.06 ) + 1 ⋅ ( − l o g 0.9 ) + 0 ⋅ ( − l o g 0.02 ) + 0 ⋅ ( − l o g 0.02 ) = − l o g ( y t a r g e t C l a s s ) Loss=\mathop\Sigma\limits_{i} y_i(-log\hat y_i)=0\cdot(-log0.06)+1\cdot (-log0.9)+0\cdot (-log0.02)+0\cdot (-log0.02) \\ =-log(y_{targetClass}) Loss=iΣyi(logy^i)=0(log0.06)+1(log0.9)+0(log0.02)+0(log0.02)=log(ytargetClass)

逻辑回归案例:fashion-mnist分类

  1. 导包

    import torch
    import torchvision
    from torch.utils import  data
    import numpy as np
    import matplotlib.pyplot as plt
    from torch import  nn
    
  2. 加载mnist数据集

    def load_fashion_mnist_data(batch_size,resize=None):
        trans=[torchvision.transforms.ToTensor()]
        if resize:
            trans.append[torchvision.transforms.Resize(resize)]
        trans=torchvision.transforms.Compose(trans)
        mnist_train_dataset=torchvision.datasets.FashionMNIST(root="../data/",train=True,transform=trans,download=True)
        mnist_test_dataset=torchvision.datasets.FashionMNIST(root="../data/",train=False,transform=trans,download=True)
        mnist_train_dataloader=data.DataLoader(dataset=mnist_train_dataset,batch_size=batch_size,shuffle=True,num_workers=0)
        mnist_test_dataloader=data.DataLoader(dataset=mnist_test_dataset,batch_size=batch_size,shuffle=True,num_workers=0)
        return mnist_train_dataset,mnist_test_dataset,mnist_train_dataloader, mnist_test_dataloader
    
    batch_size=256
    mnist_train_dataset,mnist_test_dataset,mnist_train_dataloader,mnist_test_dataloader=load_fashion_mnist_data(batch_size)
    
  3. 查看dataset的结构(配对)

    print(mnist_train_dataset[0][0].shape,mnist_train_dataset[0][1])
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VV7pI58t-1677761367074)(./逻辑回归.assets/image-20230302193933307.png)]

  4. 查看dataloader的结构和大小(成组)

    X,y=next(iter(mnist_test_iter))
    print(X.shape,y.shape)
    print(y[:10])
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k0osXgrh-1677761367075)(./逻辑回归.assets/image-20230302193518166.png)]

  5. 写出y值和图片类别的对应函数,用于最后测试

    def get_fashion_mnist_labels(labels):
        text_labels=['t-shirt','trouser','pullover','dress','coat','sandal','shirt','sneaker','bag','ankle boot']
        return text_labels[labels]
    
  6. 构建模型,本例不用卷积,将图片视为28*28=784维度向量,放入神经网络中运算.nn.Flatten会将tensor第一维度不动,后面全部拉平:(batchsize,channel,w,h)->(batchsize,-1)

    num_inputs=784
    num_outputs=10
    net=nn.Sequential(nn.Flatten(),nn.Linear(num_inputs,num_outputs))
    
  7. 初始化模型参数.Pytorch 中的 model.apply(fn) 会递归地将函数 fn 应用到父模块的每个子模块以及model这个父模块自身。通常用于初始化模型的参数

    def init_weights(m):
        if(type(m)==nn.Linear):
            nn.init.normal_(m.weight.data,std=0.01)
    net.apply(init_weights)
    
  8. 定义损失函数和优化器。 n n . C r o s s E n t r o p y L o s s ( ) nn.CrossEntropyLoss() nn.CrossEntropyLoss()中自带softmax过程,所以定义网络时不需要加入softmax层。

    其中 n n . C r o s s E n t r o p y L o s s ( ) ( y ^ , y ) nn.CrossEntropyLoss( ) (\hat y,y) nn.CrossEntropyLoss()(y^,y)接受的参数 y ^ \hat y y^ T e n s o r ( s i z e = ( b s , 10 ) ) Tensor(size=(bs,10)) Tensor(size=(bs,10)), y y y T e n s o r ( s i z e = ( b s ) ) Tensor(size=(bs)) Tensor(size=(bs)),拿上述介绍交叉熵损失时用的表格分布举例子: y ^ [ i ] = [ 0.06 , 0.9 , 0.02 , 0.02 ] , y [ i ] = 2 \hat y[i]=[0.06,0.9,0.02,0.02],y[i]=2 y^[i]=[0.06,0.9,0.02,0.02],y[i]=2 ,而 l o s s ( y ^ , y ) [ i ] = − l o g y ^ [ y [ i ] ] = − l o g 0.9 , 最终 l o s s ( y ^ , y ) = m e a n ( l o s s ( s i z e = ( b s ) ) ) loss(\hat y,y)[i]=-log\hat y[y[i]]=-log0.9 ,最终loss(\hat y,y)=mean(loss(size=(bs))) loss(y^,y)[i]=logy^[y[i]]=log0.9,最终loss(y^,y)=mean(loss(size=(bs))) ,成为一个标量。但如果loss=nn.CrossEntropyLoss(reduction=None),则不会最终求均值,返回的是 l o s s ( s i z e = ( b s ) ) loss(size=(bs)) loss(size=(bs))向量。

    简而言之,虽然神经网络output的是预测的onehot编码,但是在用API求损失时,传进去的真实分布用数据集提供的真实label值即可,不需要把label也变成one-hot形式。label值即是每个类别对应的号,在CrossEntropyLoss中,会自动将其视为一个在下标是label值地方为 1、其他位为0的onehot编码。最终神经网络也会成功拟合一个离散分布,分布的X取值范围为种类个数,分布的峰值P(x)对应的随机变量x等于真实label值。

    loss=nn.CrossEntropyLoss()
    optim=torch.optim.SGD(net.parameters(),lr=0.1)
    
  9. 定义accuracy函数,用于反馈预测正确率

    y h a t : T e n s o r ( s i z e = ( b s , 10 ) ) , y : T e n s o r ( s i z e = ( b s ) ) y_{hat}:Tensor(size=(bs,10)),y:Tensor(size=(bs)) yhat:Tensor(size=(bs,10)),y:Tensor(size=(bs))

    def accuracy(y_hat,y):
        y_hat=y_hat.argmax(axis=1)
        comp=(y_hat==y)
        return float(comp.type(y.dtype).sum())/len(y)
    
  10. 训练网络
    网络模型小,数据量大——会导致欠拟合【train的loss还未到令人满意的程度就无法下降了,test的loss也是无法下降】
    网络模型大,数据量小——会导致过拟合【train的loss持续下降,但是test的loss下降到最低点后无法继续减小,或者反而上升】
    显然本样例是欠拟合的model,且仅仅2个epoch左右,模型的train的loss就不再下降,不会表现得更好了。

    def train(train_iter,test_iter,net,loss,optim,num_epochs):
        if isinstance(net,nn.Module):
            net.train()
        for epoch in range(num_epochs):
            for X,y in train_iter:
                y_hat=net(X)
                l=loss(y_hat,y)
                optim.zero_grad()
                l.backward()
                optim.step()
            test_X,text_y=next(iter(test_iter))
            test_acc=accuracy(net(test_X),text_y)
            print(f"epoch {epoch+1}:test_acc={test_acc:.4f}")
    num_epochs=10
    train(mnist_train_dataloader,mnist_test_dataloader,net,loss,optim,num_epochs)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K8rlJLAy-1677761367076)(./逻辑回归.assets/image-20230302201422348.png)]

  11. 测试图片分类结果

    def show_img_2D(images,labels,y_hat):
        plt.figure()
        for i,idx in enumerate(np.random.randint(0,labels.numel(),6)):
            plt.subplot(2,3,i+1)
            plt.imshow(images[idx][0],cmap="gray")
            plt.title(f"truth:{get_fashion_mnist_labels(labels[idx])} \nguess:{get_fashion_mnist_labels(y_hat[idx])}")
            plt.tight_layout()
        plt.show()
    
    def predict(net, test_iter, n=6):
        X, y = next(iter(test_iter))
        y_hat = net(X).argmax(axis=1)
        show_img_2D(X,y,y_hat)
    
    predict(net,mnist_test_dataloader)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSwWAvbE-1677761367076)(./逻辑回归.assets/image-20230302202032325.png)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值