第二章 逻辑分类模型

news2024/9/21 5:34:43

目录

  • 一、逻辑回归基本模型
  • 二、处理多维特征输入
  • 三、加载数据集
  • 四、多分类问题

一、逻辑回归基本模型

基本模型: y ^ = σ ( x ∗ ω + b ) \hat{y} = \sigma (x * \omega + b) y^=σ(xω+b),其中 σ ( ) \sigma() σ() 表示 sigmod 函数 σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+ex1

二分类问题损失函数:二分类交叉熵(Binary Cross Entropy,BCE) l o s s = − ( y   l o g y ^ + ( 1 − y )   l o g ( 1 − y ^ ) ) loss = -(y\ log\hat{y} + (1-y)\ log(1-\hat{y})) loss=(y logy^+(1y) log(1y^))

Mini-Batch 版本: l o s s = − 1 N ∑ n = 1 N y n   l o g y n ^ + ( 1 − y n )   l o g ( 1 − y n ^ ) loss = -\frac{1}{N} \sum_{n=1}^N y_n\ log\hat{y_n} + (1-y_n)\ log(1-\hat{y_n}) loss=N1n=1Nyn logyn^+(1yn) log(1yn^)

代码实现:

import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt

x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])


class LogisticRegressionModel(torch.nn.Module):
    def __init__(self):
        super(LogisticRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(1, 1)

    def forward(self, x):
        y_pred = F.sigmoid(self.linear(x))
        return y_pred


model = LogisticRegressionModel()
criterion = torch.nn.BCELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000):
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

x = np.linspace(0, 10, 200)
x_t = torch.Tensor(x).view((200, 1))  # view作用相当于reshape
y_t = model(x_t)
y = y_t.data.numpy()  # 获取矩阵
plt.plot(x, y)
plt.plot([0, 10], [0.5, 0.5], c='r')
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid()
plt.show()

二、处理多维特征输入

数据:

这是一个由 10 个 sample(每行称为一个 sample),每个 sample 有 8 个 feature 构成的数据集。

多维度数据输入的时候,模型会发生变化,即变成多维度逻辑回归模型

y ^ ( i ) = σ ( x ( i ) ∗ ω + b )    ⇒    y ^ ( i ) = σ ( ∑ n = 1 8 x n ( i ) ∗ ω n + b ) = σ ( [ x 1 ( i ) ⋯ x 8 ( i ) ] [ ω 1 ⋮ ω 8 ] + b ) = σ ( z ( i ) ) \begin{aligned} \hat{y}^{(i)} = \sigma(x^{(i)} * \omega + b) \ \ \Rightarrow \ \ \hat{y}^{(i)} &= \sigma(\sum_{n=1}^8 x^{(i)}_n * \omega_n + b) \\ &= \sigma( \begin{bmatrix} x_1^{(i)} &\cdots &x_8^{(i)} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \vdots \\ \omega_8 \end{bmatrix} +b )\\ &=\sigma(z^{(i)}) \end{aligned} y^(i)=σ(x(i)ω+b)    y^(i)=σ(n=18xn(i)ωn+b)=σ([x1(i)x8(i)] ω1ω8 +b)=σ(z(i))

对于有 N 个 samples,即 Mini-Batch(N samples),其矩阵运算如下:

[ y ^ ( 1 ) ⋮ y ^ ( N ) ] = [ σ ( z ( 1 ) ) ⋮ σ ( z ( N ) ) ] = σ ( [ z ( 1 ) ⋮ z ( N ) ] ) \begin{bmatrix} \hat{y}^{(1)} \\ \vdots \\ \hat{y}^{(N)} \end{bmatrix}= \begin{bmatrix} \sigma(z^{(1)}) \\ \vdots \\ \sigma(z^{(N)}) \end{bmatrix} =\sigma( \begin{bmatrix} z^{(1)} \\ \vdots \\ z^{(N)} \end{bmatrix}) y^(1)y^(N) = σ(z(1))σ(z(N)) =σ( z(1)z(N) )

其中:
z ( 1 ) = [ x 1 ( 1 ) ⋯ x 8 ( 1 ) ] [ ω 1 ⋮ ω 8 ] + b ⋮ z ( N ) = [ x 1 ( N ) ⋯ x 8 ( N ) ] [ ω 1 ⋮ ω 8 ] + b \begin{aligned} z^{(1)} &= \begin{bmatrix} x_1^{(1)} &\cdots &x_8^{(1)} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \vdots \\ \omega_8 \end{bmatrix} + b \\ &\vdots \\ z^{(N)} &= \begin{bmatrix} x_1^{(N)} &\cdots &x_8^{(N)} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \vdots \\ \omega_8 \end{bmatrix} + b \\ \end{aligned} z(1)z(N)=[x1(1)x8(1)] ω1ω8 +b=[x1(N)x8(N)] ω1ω8 +b

可转换为矩阵运算(注意矩阵维度的变换):

[ z ( 1 ) ⋮ z ( N ) ] N × 1 = [ x 1 ( 1 ) ⋯ x 8 ( 1 ) ⋮ ⋱ ⋮ x 1 ( N ) ⋯ x 8 ( N ) ] N × 8 [ ω 1 ⋮ ω 8 ] 8 × 1 + [ b ⋮ b ] N × 1 \begin{bmatrix} z^{(1)} \\ \vdots \\ z^{(N)} \end{bmatrix}_{N \times 1} = \begin{bmatrix} x_1^{(1)} &\cdots &x_8^{(1)} \\ \vdots &\ddots &\vdots \\ x_1(N) &\cdots &x_8^{(N)} \end{bmatrix}_{N \times 8} \begin{bmatrix} \omega_1 \\ \vdots \\ \omega_8 \end{bmatrix}_{8 \times 1} + \begin{bmatrix} b\\ \vdots\\ b \end{bmatrix}_{N \times 1} z(1)z(N) N×1= x1(1)x1(N)x8(1)x8(N) N×8 ω1ω8 8×1+ bb N×1

矩阵变换,实质上是一种空间变换的函数,上述变换过程就将输入 feature=8 的空间映射到输出 feature=1 的空间。同样,也可以实现从 feature=8 映射到输出 feature=x 的空间,其中 x 可以自行设置。

上面过程都是线性变换的,需要在每一次映射之后引入一个非线性函数(比如 sigmod 函数),使得该神经网络可以去拟合一个非线性的变换。

这里的目标是将 feature=8 映射到 feature=1,但是由上面矩阵变换的性质,这里可以分步将 feature 从 8 降到 1,这样这个分类的神经网络模型就可以由很多层构成,这样我们模型的拟合能力就越强,如下图:

上图中 feature 降维的过程是 8 → 6 → 4 → 1。

代码实现:

import numpy as np
import torch

xy = np.loadtxt('./Data/diabetes.csv.gz', delimiter=',', dtype=np.float32)  # 分隔符为',',读取数据格式一般为浮点数32位即可
x_data = torch.from_numpy(xy[:, :-1])  # 最后一列不取
y_data = torch.from_numpy(xy[:, [-1]])  # [-1]表示只取最后一列,并且形成矩阵


class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear1 = torch.nn.Linear(8, 6)  # 第一层feature从8到6
        self.linear2 = torch.nn.Linear(6, 4)  # 第二层feature从6到4
        self.linear3 = torch.nn.Linear(4, 1)  # 第二层feature从4到1
        self.sigmoid = torch.nn.Sigmoid()

    def forward(self, x):
        x = self.sigmoid(self.linear1(x))
        x = self.sigmoid(self.linear2(x))
        x = self.sigmoid(self.linear3(x))
        return x


model = Model()

criterion = torch.nn.BCELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000):
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

三、加载数据集

Pytorch 中有两个工具:

  • Dataset:构建数据集,支持索引,在 Pytorch 中,它是一个抽象类,只能被继承,不能被实例化。
  • DataLoader:从 Dataset 中拿出一个 Mini-Batch 这样一组数据用于训练,在 Pytorch 中,它是一个类,可以被实例化。

在上一节的代码中,每一次梯度下降将所有数据都进行了运算,会比较浪费时间。如果每次梯度下降仅使用一个点的梯度,这样带来的好处是可以克服求导时的鞍点,这样训练出的模型性能可能会更好,但是训练时优化的时间会非常长。所以折中便是用部分数据进行梯度下降,即一个 Mini-Batch。

几个概念需要了解:

  • Epoch:One forward pass and one backword pass of all the training examples,即所有样本都进行过一次前馈、反馈传播训练就成为一次 Epoch。
  • Batch-Size:The number of training examples in one forward backward pass,即一次训练所使用的样本数量,或者说是一次 Epoch 的样本数量。
  • Iterations:Number of passes, each pass using batch-size number of examples,举一个例子,假设由 10000 个样本,Batch-Size = 1000, 那么 Iterations = 10000 / Batch-Size =10。

DataLoader 的工作流程:

import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader


class DiabetesDataset(Dataset):
    def __init__(self, filePath):
        xy = np.loadtxt(filePath, delimiter=',', dtype=np.float32)
        self.len = xy.shape[0]  # 有多少个sample
        self.x_data = torch.from_numpy(xy[:, :-1])  # 最后一列不要
        self.y_data = torch.from_numpy(xy[:, [-1]])  # 仅取最后一列且形成矩阵

    def __getitem__(self, item):  # 根据索引返回数据
        return self.x_data[item], self.y_data[item]

    def __len__(self):  # 返回数据中sample的个数
        return self.len


dataset = DiabetesDataset('./Data/diabetes.csv.gz')
# print(len(dataset))
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True)  # 读取数据进程数目设置为2,但是这里设置多线程会报错


class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear1 = torch.nn.Linear(8, 6)
        self.linear2 = torch.nn.Linear(6, 4)
        self.linear3 = torch.nn.Linear(4, 1)
        self.sigmoid = torch.nn.Sigmoid()

    def forward(self, x):
        x = self.sigmoid(self.linear1(x))
        x = self.sigmoid(self.linear2(x))
        x = self.sigmoid(self.linear3(x))
        return x


model = Model()

criterion = torch.nn.BCELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(100):  # 对所有数据100次
    for i, (x, y) in enumerate(train_loader, 0):
        # 这里x、y自动转换为了tensor
        # 每一次取出一个batch-size=32,共759个samples,所以iterations=759/32=23
        y_pred = model(x)
        loss = criterion(y_pred, y)
        print(epoch, i, loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

四、多分类问题

针对 MNIST 数据集,其中存在 10 中手写数字标签( 0 ∼ 10 0\sim10 010),如下图所示:

按照二分类问题的思路,在每一层结束的时候使用激活函数 sigmoid,那么最终输出的结果就会十个值,如下图所示:

并且 ∑ n = 1 10 y ^ n ≠ 1 \sum_{n=1}^{10} \hat{y}_n \ne 1 n=110y^n=1这样并不能很好地预测出结果,为了使输出结果能够给相互抑制且呈现出一个分布状态,使用 Softmax 作为最后一层的激活函数,如下图所示:

在 Softmax 层中的计算:假设最后一层的输出位 Z l ∈ R K Z^l \in R^K ZlRK,则有 P ( y = i ) = e Z i ∑ j = 0 K − 1 e Z j P(y=i) = \frac{e^{Z_i}}{\sum_{j=0}^{K-1} e^{Z_j}} P(y=i)=j=0K1eZjeZi其中 i ∈ { 0 , ⋯   , K − 1 } i \in \{0, \cdots, K-1 \} i{0,,K1}

将上式应用到 MNIST 数据集中,就会有 P ( y = i ) > 0 P(y=i) > 0 P(y=i)>0,并且 ∑ i = 1 10 P ( y = i ) = 1 \sum_{i=1}^{10} P(y=i)= 1 i=110P(y=i)=1

对于多分类问题的损失函数:交叉熵损失函数

  • 如果使用 Numpy 来实现:

代码如下:

import numpy as np

y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
y_pred = np.exp(z) / np.exp(z).sum()
loss = (-y * np.log(y_pred)).sum()
print(loss)
  • 如果使用 Pytorch 来实现:

代码实现如下:

import torch

y = torch.LongTensor([0])  # y必须是一个 LongTensor
z = torch.Tensor([[0.2, 0.1, -0.1]])  # 最后一层不能使用激活函数
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z, y)
print(loss.item())

针对 MNIST 数据集的多分类识别:

最终精度只能达到 97%

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

batch_size = 64
transform = transforms.Compose(
    [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])  # 归一化并将图像从单通道转换为多通道,即28x28转换为1x28x28

train_dataset = datasets.MNIST(root='./Data/mnist/', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)

test_dataset = datasets.MNIST(root='./Data/mnist', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)


class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.l1 = torch.nn.Linear(784, 512)
        self.l2 = torch.nn.Linear(512, 256)
        self.l3 = torch.nn.Linear(256, 128)
        self.l4 = torch.nn.Linear(128, 64)
        self.l5 = torch.nn.Linear(64, 10)

    def forward(self, x):
        x = x.view(-1, 784)
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        x = self.l5(x)  # 最后一层不激活
        return x


model = Net()

criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)  # 添加了动量


def train(epoch):  # 将每一轮训练封装成一个函数
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0


def test():
    correct = 0  # 预测正确的数目
    total = 0  # 总共的数目
    with torch.no_grad():  # with范围内的代码不计算梯度
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)  # 返回(最大值, 最大值下标)
            total += labels.size(0)  # label是一个矩阵
            correct += (predicted == labels).sum().item()
    print('Accuracy on test set: %d %%' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

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

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

相关文章

LMS,RGB,XYZ色彩空间转换

前言 首先需要指明本文中描述的R,G,B并非通常的sRGB中的三个分量R,G,B,而是波长分别为700nm,546.1nm,435.8nm的单色红光,单色绿光,单色蓝光。sRGB中的RGB中的红色、绿色、蓝色已经不是单色光了。虽然习惯上大家都叫RGB…

文法的FIRST集

求文法的FIRST集和FOLLOW集的步骤如下: 求FIRST集 如果符号是终结符,则FIRST集合为该终结符本身。如果符号是非终结符,则将该非终结符可以推导出的所有串的FIRST集合合并,得到该非终结符的FIRST集合。如果一个非终结符可以推导出…

Linux篇5

Shell常用命令 1. 磁盘管理类1.1 du:查看文件和目录占用的磁盘空间1.2 df:查看磁盘空间使用情况1.3 free:查看内存使用情况1.4 lsblk:查看设备挂载情况1.5 mount/umount:挂载/卸载1.6 fdisk:分区 2. 进程管…

双模齐下,提质增效:CODING 携手知微共创 BizDevOps 体系新篇章

为了提升工作和管理效率,工具建设是许多企业不得不面对的现实,然而在工具建设落地过程中,往往存在一系列的问题。如不同组织、部门之间互不相通,各自为政,工具流程与实际工作所需不符,导致工具建设的结果是…

(1分钟速览)g2o入门指南--笔记版

在slam后端中,优化的框架很多,有ceres,g2o,gtsam这些。要想真正掌握slam后端的优化内容,这些框架是必不可少的上手练习的内容。本文则介绍有关g2o的相关内容,作为一个入门指南,目标:…

使用教程 | 基于TSMaster如何实现LIN RBS 剩余总线仿真

本文导读 RBS 全称是:residual bus simulation,也就是所谓的剩余总线仿真。主要是基于车载网络数据库,如 CAN/LIN/FlexRay/以太网数据库,仿真该网络内部各个节点的通讯行为。 本文主要讲解 TSMaster 中 LIN RBS 的操作流程。 “ …

aosp11/12/13 壁纸高斯模糊,毛玻璃SurfaceFlinger层面原理-第二节千里马framework实战

hi,粉丝朋友们! 上一个blog已经详细讲解了系统中自带相关接口实现窗口的高斯模糊相关效果,具体点击这里 https://blog.csdn.net/learnframework/article/details/130767893 1、补充app层面实现方式 更多framework干货知识手把手教学 Log.i…

Restful API

Restful API 一、RESTful API是什么意思二、对比三、小知识四、用 apifox 进行测试1. GET2. POST3. PUT4. DELETE 一、RESTful API是什么意思 REST 与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻…

操作系统实验三 内存分配及回收研究

前言 本次实验跟前两次相比简单许多,主要是体会底层的一些运行机制。其实,要说简单,也不是真的很简单,毕竟还是存在一些更底层的东西需要我们去探讨。接下来就让我们通过实验来感受一下。 1.实验目的 掌握Linux操作系统的内存分…

地表水灌区取水计量设施包含哪些设备?

方案背景 根据《关于强化取水口取水监测计量的意见》、《十四五”节水型社会建设规划》以及《2022年水资源管理工作要点》等政策要求,为强化水资源管理,做好水资源税改革,构建节水型社会,要全面加强取水计量监测设施建设&#xff…

【计算机系统基础3】数据的存储与运算

3.程序调试与实践:数据存储与运算 3.1真值与机器数 真值: 数据在现实世界中的表示 机器数: 数据在计算机内部的二进制编码表示 温度:零下3.5度 习惯写法:-3.5 (数据的真值/数据的实际值) 3.1.1整数的编码 带符号整数&…

15:13进去面试,5分钟就完事了,问的实在是太......

干了两年外包,本来想出来正儿八经找个互联网公司上班,没想到算法死在另一家厂子。 自从加入这家外包公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到11月一纸通知,所有人不许加班,薪资…

2023年值得关注的低代码平台推荐

低代码平台在数字化转型的浪潮中受到越来越多企业的青睐,因为它们提供了一种更容易、更快的方式来开发网络和移动应用程序。低代码平台只需要最少的编码知识,使公司能够在很短的时间内开发出定制的应用程序,而这只是使用传统的搭建手段所需时…

参数传递之传名,传地址,得结果,传值

编译原理速成,参数传递之传名,传地址,得结果,传值(四)_哔哩哔哩_bilibili 学习自上面的文章。 题目1: (1)传名。 (2)传地址。(注意观察,AB变成了临时变量T1,…

jvm之G1 GC

写在前面 jdk9以及之后的版本已经将默认的垃圾收集器parallel更换为G1.本文就一起来看下。 1:G1介绍 parallel GC的设计目标是高吞吐量,CMS GC的设计目标是低延迟,而G1的设计目标不是这二者中的任何一个,其设计目标是让GC的STW…

我的世界Fabric mod开发-快速漏斗

前往我的主页以阅读完整内容,并获取源码 DearXuan的主页 MOD介绍 使用漏斗链进行分类或传递物品时,常常会发现漏斗速度太慢,难以收集全部掉落物.或者漏斗太多,影响性能.而现有的漏斗加速mod则是引入新的快速漏斗,存在各种兼容问题.开服时发现paper服务器可以修改原…

华为OD机试真题 Java 实现【区间连接器】【2023Q1 200分】

一、题目描述 有一组区间 [a0, b0], [a1, b1], … (a, b 表示起点, 终点),区间有可能重叠、相邻,重叠或相邻则可以合并为更大的区间; 给定一组连接器[x1, x2, x3, …](x 表示连接器的最大可连接长度,即 x>gap&…

支付宝沙箱支付(java电脑版)

目录 下载支付demo配置环境AlipayConfig 下载支付demo 网址&#xff1a;https://open.alipay.com/ 下载并打开项目发现无法运行&#xff1a; 手动转化项目&#xff1a; 等待下载整理一下maven pom 通过tomat部署运行测试。 导入阿里支付的pom依赖 <dependency> &l…

都2023了,你竟然还不知道网络安全该怎么学

前言 网络安全是指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然或恶意原因而遭受破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。网络安全因何而重要&#xff1f; 截至2023年4月,我国网民规模为_11.51亿_&#xff0c…

模板初阶(泛型编程)

模板初阶 &#x1f506;泛型编程&#x1f506;函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化模板参数的匹配原则 &#x1f506;类模板类模板的定义格式类模板的实例化类模板与模板类的区别 &#x1f506;结语 &#x1f506;泛型编程 泛型编程&#xff1a;编…