Skip to content

Latest commit

 

History

History
1606 lines (1293 loc) · 61.6 KB

学习计划和记录.md

File metadata and controls

1606 lines (1293 loc) · 61.6 KB

主体大纲:

要快速掌握 PyTorch 进行深度学习的基础,可以按照以下学习计划表进行。这个计划表将 PyTorch 学习拆分成几个小任务,每个部分包括学习目标、例子说明和代码训练。该计划大约需要 4 周时间,每周完成一个主要主题。

第 1 周:PyTorch 基础

任务 1.1:安装和环境设置

  • 学习目标:安装 PyTorch 并设置开发环境。
  • 例子说明:
    pip install torch torchvision torchaudio
  • 代码训练:安装完成后,验证安装。
    import torch
    print(torch.__version__)

任务 1.2:张量操作

  • 学习目标:理解和操作张量。
  • 例子说明:
    x = torch.tensor([[1, 2], [3, 4]])
    print(x)
  • 代码训练:创建和操作不同维度的张量。
    x = torch.ones(5, 3)
    y = torch.rand(5, 3)
    z = x + y
    print(z)

任务 1.3:自动求导

  • 学习目标:理解自动求导机制。
  • 例子说明:
    x = torch.ones(2, 2, requires_grad=True)
    y = x + 2
    z = y * y * 3
    out = z.mean()
    out.backward()
    print(x.grad)
  • 代码训练:对简单函数进行梯度计算。

第 2 周:神经网络基础

任务 2.1:构建简单的神经网络

  • 学习目标:使用 torch.nn 构建神经网络。
  • 例子说明:
    import torch.nn as nn
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.fc1 = nn.Linear(784, 128)
            self.fc2 = nn.Linear(128, 10)
    
        def forward(self, x):
            x = torch.flatten(x, 1)
            x = torch.relu(self.fc1(x))
            x = self.fc2(x)
            return x
  • 代码训练:构建一个简单的前馈神经网络。

任务 2.2:损失函数和优化器

  • 学习目标:理解损失函数和优化器。
  • 例子说明:
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
  • 代码训练:设置损失函数和优化器。

第 3 周:训练和评估模型

任务 3.1:加载数据

  • 学习目标:使用 torchvision 加载数据。
  • 例子说明:
    from torchvision import datasets, transforms
    transform = transforms.Compose([transforms.ToTensor()])
    trainset = datasets.FashionMNIST(root='./data', train=True, download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
  • 代码训练:加载并预处理数据。

任务 3.2:训练循环

  • 学习目标:实现训练循环。
  • 例子说明:
    for epoch in range(2):
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            optimizer.zero_grad()
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            if i % 2000 == 1999:
                print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 2000}')
                running_loss = 0.0
  • 代码训练:实现完整的训练循环。

任务 3.3:评估模型

  • 学习目标:评估模型性能。
  • 例子说明:
    correct = 0
    total = 0
    with torch.no_grad():
        for data in testloader:
            images, labels = data
            outputs = net(images)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    print(f'Accuracy: {100 * correct / total}')
  • 代码训练:在测试集上评估模型性能。

第 4 周:进阶主题

任务 4.1:迁移学习

  • 学习目标:使用预训练模型进行迁移学习。
  • 例子说明:
    import torchvision.models as models
    model = models.resnet18(pretrained=True)
    for param in model.parameters():
        param.requires_grad = False
    model.fc = nn.Linear(model.fc.in_features, 10)
  • 代码训练:微调预训练模型。

任务 4.2:自定义数据集

  • 学习目标:加载和使用自定义数据集。
  • 例子说明:
    from torchvision.io import read_image
    class CustomDataset(Dataset):
        def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
            self.img_labels = pd.read_csv(annotations_file)
            self.img_dir = img_dir
            self.transform = transform
            self.target_transform = target_transform
    
        def __len__(self):
            return len(self.img_labels)
    
        def __getitem__(self, idx):
            img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
            image = read_image(img_path)
            label = self.img_labels.iloc[idx, 1]
            if self.transform:
                image = self.transform(image)
            if self.target_transform:
                label = self.target_transform(label)
            return image, label
  • 代码训练:加载并使用自定义数据集。

任务 4.3:模型保存和加载

  • 学习目标:保存和加载模型。
  • 例子说明:
    torch.save(model.state_dict(), 'model.pth')
    model.load_state_dict(torch.load('model.pth'))
  • 代码训练:保存和加载训练好的模型。

具体实行

张量

在深度学习中,张量(tensor)是最基本的数据结构,它类似于多维数组或矩阵。张量可以存储并操作各种类型的数据,包括整数、浮点数和布尔值。在 PyTorch 中,张量是由 torch.Tensor 类表示的。

常见函数用法

  1. tensor.ones: torch.ones(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor

size:张量的形状(例如 torch.ones(2, 3) 创建一个 2x3 的张量)。 out:可选的,用于存储输出的张量。 dtype:张量的数据类型(例如 torch.float32)。 layout:张量的布局(默认是 torch.strided)。 device:张量所在的设备(例如 torch.device('cpu') 或 torch.device('cuda'))。 requires_grad:如果为 True,则记录对该张量的操作,以便进行自动求导。

  1. tensor.band torch.bitwise_and(input, other, *, out=None) -> Tensor input:第一个输入张量。 other:第二个输入张量或标量。 out:可选的,用于存储输出的张量。

解释张量

  1. 维度(Dimension):张量可以是任意维度的,从标量(0 维)到高阶张量(N 维)都可以。
  2. 形状(Shape):张量的形状是指它各个维度的大小。
  3. 数据类型(Data Type):张量中的数据可以是不同类型的,例如整数、浮点数等。

如何实现张量

在 PyTorch 中,可以使用 torch.Tensor 类来创建和操作张量。以下是一些常用的方法来创建张量:

  1. 从 Python 列表或 NumPy 数组创建

    import torch
    import numpy as np
    
    # 从 Python 列表创建
    tensor_list = torch.tensor([[1, 2, 3], [4, 5, 6]])
    
    # 从 NumPy 数组创建
    numpy_array = np.array([[1, 2, 3], [4, 5, 6]])
    tensor_numpy = torch.tensor(numpy_array)
  2. 使用特定值创建

    # 创建全零张量
    zeros_tensor = torch.zeros(2, 3)
    
    # 创建全一张量
    ones_tensor = torch.ones(2, 3)
    
    # 创建随机张量
    random_tensor = torch.rand(2, 3)
  3. 从现有张量创建

    # 从现有张量创建
    new_tensor = torch.randn_like(zeros_tensor)
  4. 通过改变数据类型创建

    # 创建指定数据类型的张量
    float_tensor = torch.tensor([1, 2, 3], dtype=torch.float32)

示例和代码

下面是一个示例,展示如何创建和操作张量:

import torch

# 创建张量
tensor1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print("Tensor 1:")
print(tensor1)

# 获取张量形状
print("Shape of Tensor 1:", tensor1.shape)

# 获取张量数据类型
print("Data type of Tensor 1:", tensor1.dtype)

# 改变张量形状
tensor2 = tensor1.view(3, 2)
print("\nTensor 2 (Reshaped):")
print(tensor2)

# 张量运算
tensor_sum = tensor1 + tensor2
print("\nTensor Sum:")
print(tensor_sum)

# 改变数据类型
float_tensor = tensor1.float()
print("\nFloat Tensor:")
print(float_tensor)

以上代码创建了两个张量,展示了如何获取张量的形状和数据类型,以及如何对张量进行操作和运算。通过这些操作,您可以更好地理解和使用张量在深度学习中的重要性。

进行线性回归的项目训练

num_epochs

num_epochs(训练轮数)在训练神经网络模型中起着至关重要的作用,它决定了模型在训练数据集上迭代的次数。其作用和意义可以从以下几个方面来理解:

  1. 学习进度的控制 num_epochs 控制了模型对训练数据的反复学习次数。一次完整的训练轮(epoch)意味着模型对整个训练数据集进行了一次前向传播和反向传播的过程。多次迭代能够帮助模型逐渐调整参数,从而更好地拟合训练数据。

  2. 训练充分性

  • 过少的训练轮数(欠拟合): 如果 num_epochs 设置得太小,模型可能没有足够的机会学习数据中的特征,从而导致欠拟合,即模型在训练集和测试集上的性能都不佳。
  • 过多的训练轮数(过拟合): 如果 num_epochs 设置得过大,模型可能会过度拟合训练数据,学习到数据中的噪声,从而在测试集上的泛化能力变差。
  1. 损失函数的优化 在每一轮训练中,模型会根据损失函数的值来更新参数。随着训练轮数的增加,损失函数的值通常会逐渐减小,模型的性能会不断提高。然而,当训练到一定程度后,损失函数的改善会趋于平缓甚至停止,说明模型已经接近或达到最优状态。

  2. 早停机制 在实际训练过程中,我们通常不会预先确定一个非常大的 num_epochs 值,而是结合早停(Early Stopping)机制来防止过拟合。早停机制通过监控模型在验证集上的性能,当性能不再提升时提前停止训练。

  3. 训练和计算资源 更多的训练轮数意味着更多的计算时间和资源消耗。在设置 num_epochs 时需要权衡模型性能和训练资源之间的关系,找到一个合适的平衡点。

实际应用中的考虑
  1. 验证集性能监控:通常在每个训练轮结束后,会在验证集上评估模型性能。如果在多个训练轮数上验证集性能不再提升,可以考虑停止训练。

  2. 绘制学习曲线:通过绘制训练损失和验证损失随训练轮数的变化曲线(学习曲线),可以更直观地观察模型的训练过程,帮助调整 num_epochs 及其他超参数。

  3. 实验和调整:在实际项目中,可能需要进行多次实验,通过调整 num_epochs 和其他参数来找到最佳的训练配置。

总结

num_epochs 是控制模型训练过程中的一个重要超参数。它的主要作用是确保模型有足够的时间和机会学习训练数据中的特征,同时需要谨慎选择以避免过拟合或欠拟合。通过合理设置 num_epochs 以及结合其他技巧如早停机制,可以有效地训练出性能优良的模型。

穷举法实现线性回归

import numpy as np import matplotlib.pyplot as plt

x_data = [1.0, 2.0, 3.0] y_data = [2.0, 4.0, 6.0]

def forward(x): return x*w

def loss(x, y): y_pred = forward(x) return (y_pred - y)**2

w_list = [] mse_list = [] for w in np.arange(0.0, 4.1, 0.1): print("w=", w) l_sum = 0 for x_val, y_val in zip(x_data, y_data): y_pred_val = forward(x_val) loss_val = loss(x_val, y_val) l_sum += loss_val print('\t', x_val, y_val, y_pred_val, loss_val) print('MSE=', l_sum/3) w_list.append(w) mse_list.append(l_sum/3)

plt.plot(w_list,mse_list) plt.ylabel('Loss') plt.xlabel('w') plt.show()

梯度下降计算损失函数

梯度下降法是一种优化算法,用于通过迭代更新参数来最小化损失函数。它广泛应用于深度学习和机器学习模型的训练中。梯度下降法的核心思想是沿着损失函数梯度的方向,以一定的步长更新参数,使损失函数逐步减小,直到达到最小值或接近最小值。

数学推导

  1. 定义损失函数: 设损失函数为 ( J(\theta) ),其中 ( \theta ) 为参数向量。

  2. 梯度计算: 梯度是损失函数对参数的偏导数,记为 ( \nabla_\theta J(\theta) )。它表示损失函数在参数空间中的变化率。

  3. 参数更新: 在每次迭代中,参数按以下公式更新: [ \theta = \theta - \alpha \nabla_\theta J(\theta) ] 其中,( \alpha ) 为学习率,控制每次更新的步长。

  4. 梯度下降过程

    • 初始化参数 ( \theta )。
    • 重复以下步骤,直到收敛:
      1. 计算当前参数下的梯度 ( \nabla_\theta J(\theta) )。
      2. 按梯度更新参数 ( \theta )。

示例:线性回归中的梯度下降

下面是一个简单的线性回归例子,使用梯度下降法来最小化均方误差 (MSE)。

代码实现
import numpy as np
import matplotlib.pyplot as plt

# 数据
x_data = np.array([1.0, 2.0, 3.0])
y_data = np.array([2.0, 4.0, 6.0])

# 初始化参数
w = 0.0
b = 0.0
learning_rate = 0.01
num_iterations = 1000

# 定义前向计算函数
def forward(x):
    return w * x + b

# 定义损失函数(均方误差)
def compute_loss(x, y):
    y_pred = forward(x)
    return np.mean((y_pred - y) ** 2)

# 定义梯度计算
def compute_gradients(x, y):
    y_pred = forward(x)
    grad_w = np.mean(2 * (y_pred - y) * x)
    grad_b = np.mean(2 * (y_pred - y))
    return grad_w, grad_b

# 梯度下降法
losses = []
for i in range(num_iterations):
    grad_w, grad_b = compute_gradients(x_data, y_data)
    w -= learning_rate * grad_w
    b -= learning_rate * grad_b
    loss = compute_loss(x_data, y_data)
    losses.append(loss)
    if i % 100 == 0:
        print(f"Iteration {i}: w={w:.4f}, b={b:.4f}, loss={loss:.4f}")

# 绘制损失变化曲线
plt.plot(range(num_iterations), losses)
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.title('Loss over iterations')
plt.show()

# 绘制拟合结果
plt.scatter(x_data, y_data, color='red')
plt.plot(x_data, forward(x_data), color='blue')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Linear regression result')
plt.show()

代码解释

  1. 数据定义

    x_data = np.array([1.0, 2.0, 3.0])
    y_data = np.array([2.0, 4.0, 6.0])
  2. 初始化参数

    w = 0.0
    b = 0.0
    learning_rate = 0.01
    num_iterations = 1000
  3. 前向计算函数

    def forward(x):
        return w * x + b
  4. 损失函数

    def compute_loss(x, y):
        y_pred = forward(x)
        return np.mean((y_pred - y) ** 2)
  5. 梯度计算

    def compute_gradients(x, y):
        y_pred = forward(x)
        grad_w = np.mean(2 * (y_pred - y) * x)
        grad_b = np.mean(2 * (y_pred - y))
        return grad_w, grad_b
  6. 梯度下降法

    losses = []
    for i in range(num_iterations):
        grad_w, grad_b = compute_gradients(x_data, y_data)
        w -= learning_rate * grad_w
        b -= learning_rate * grad_b
        loss = compute_loss(x_data, y_data)
        losses.append(loss)
        if i % 100 == 0:
            print(f"Iteration {i}: w={w:.4f}, b={b:.4f}, loss={loss:.4f}")
  7. 绘制损失变化曲线

    plt.plot(range(num_iterations), losses)
    plt.xlabel('Iteration')
    plt.ylabel('Loss')
    plt.title('Loss over iterations')
    plt.show()
  8. 绘制拟合结果

    plt.scatter(x_data, y_data, color='red')
    plt.plot(x_data, forward(x_data), color='blue')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title('Linear regression result')
    plt.show()

数学原理总结

通过上述代码,我们使用梯度下降法来最小化线性回归模型的损失函数。梯度下降法的数学原理是利用损失函数的梯度信息,逐步调整模型参数,最终使得损失函数达到最小值。具体步骤包括计算梯度、更新参数,并重复这一过程直到损失函数收敛。通过可视化损失变化曲线和拟合结果,我们可以直观地观察到模型训练过程和最终效果。

反向传播

Tensor和tensor等用法和区别

在 PyTorch 中,Tensortensor 是两个相关但不同的概念,而 torch.FloatTensor 是其中的一种特定类型。让我们逐一解释它们的区别:

1. Tensortensor
  • torch.Tensor:

    • torch.Tensor 是 PyTorch 中的基本数据结构,代表多维数组。它可以存储任意数据类型,如浮点数、整数等。
    • 通过 torch.Tensor 可以创建一个默认类型的张量,通常是浮点型的张量(根据 PyTorch 的默认设置)。
    import torch
    a = torch.Tensor([1, 2, 3])
    print(a)  # 默认是 torch.FloatTensor
  • torch.tensor:

    • torch.tensor 是一个工厂方法,用于创建张量。与 torch.Tensor 不同,它可以明确指定数据类型,并且提供了一些额外的功能,如自动类型推断和在创建时指定设备(CPU 或 GPU)。
    b = torch.tensor([1, 2, 3], dtype=torch.float32)
    print(b)
2. torch.FloatTensor
  • torch.FloatTensor:

    • torch.FloatTensor 是一个特定类型的张量,专门用于存储 32 位浮点数。虽然在早期版本的 PyTorch 中使用得比较多,但现在更多地使用 torch.tensortorch.Tensor 来创建张量。
    c = torch.FloatTensor([1, 2, 3])
    print(c)
详细区别总结
  • 类型默认值:

    • torch.Tensor 创建的张量类型是默认的浮点型(通常是 torch.FloatTensor)。
    • torch.tensor 创建张量时可以指定类型,不指定时会自动推断。
  • 使用习惯:

    • torch.Tensor 直接调用构造函数,类似于 NumPy 的数组创建方式。
    • torch.tensor 是现代 PyTorch 的推荐使用方式,提供更灵活的创建方式。
  • 特定类型:

    • torch.FloatTensor 是显式指定的浮点型张量类型。

在现代 PyTorch 中,推荐使用 torch.tensortorch.Tensor 来创建张量,因为它们更灵活且与最新的 API 一致。

示例代码
import torch

# 使用 torch.Tensor 创建默认浮点型张量
a = torch.Tensor([1, 2, 3])
print(a)  # 默认是 torch.FloatTensor

# 使用 torch.tensor 创建并指定数据类型
b = torch.tensor([1, 2, 3], dtype=torch.float32)
print(b)

# 使用 torch.FloatTensor 显式创建浮点型张量
c = torch.FloatTensor([1, 2, 3])
print(c)

总之,torch.tensortorch.Tensor 是现代 PyTorch 推荐使用的方法,而 torch.FloatTensor 则是早期方法,现代 PyTorch 中较少直接使用。

实现线性回归模型是学习 PyTorch 的一个很好的起点。下面,我们一步一步地实现一个简单的线性回归模型,并解释每一步使用的函数和概念。

步骤 1: 导入必要的库

首先,我们需要导入 PyTorch 以及其他一些常用的库。

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
步骤 2: 准备数据

我们将创建一些简单的数据来训练我们的模型。假设我们的目标是学习一个简单的线性关系 ( y = 2x + 1 )。

# 生成数据
x_data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_data = torch.tensor([[3.0], [5.0], [7.0], [9.0]])
步骤 3: 定义模型

在 PyTorch 中,我们可以使用 nn.Module 来定义我们的模型。对于线性回归,我们需要一个包含单个线性层的简单模型。

class LinearRegressionModel(nn.Module):
    def __init__(self):
        super(LinearRegressionModel, self).__init__()
        self.linear = nn.Linear(1, 1)  # 输入和输出都是1维

    def forward(self, x):
        return self.linear(x)
步骤 4: 实例化模型

接下来,我们实例化模型。

model = LinearRegressionModel()
步骤 5: 定义损失函数和优化器

我们使用均方误差(MSE)作为损失函数,并使用随机梯度下降(SGD)作为优化器。

criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
步骤 6: 训练模型

现在,我们训练模型。我们将数据传递给模型,计算损失,反向传播损失并更新模型的参数。

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    model.train()
    
    # 前向传播
    y_pred = model(x_data)
    
    # 计算损失
    loss = criterion(y_pred, y_data)
    
    # 反向传播
    optimizer.zero_grad()  # 梯度清零
    loss.backward()  # 计算梯度
    optimizer.step()  # 更新参数

    # 每100个epoch打印一次损失
    if (epoch+1) % 100 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
步骤 7: 可视化结果

训练完成后,我们可以可视化拟合结果。

# 可视化结果
model.eval()
with torch.no_grad():
    predicted = model(x_data).detach().numpy()
    plt.plot(x_data.numpy(), y_data.numpy(), 'ro', label='Original data')
    plt.plot(x_data.numpy(), predicted, label='Fitted line')
    plt.legend()
    plt.show()
解释每一步使用的函数
  1. torch.tensor: 用于创建张量,是 PyTorch 中的基本数据结构。
  2. nn.Module: PyTorch 中所有神经网络模块的基类。通过子类化 nn.Module,我们可以定义我们自己的网络。
  3. nn.Linear: 定义一个线性层,它实现了线性变换 ( y = wx + b )。
  4. nn.MSELoss: 计算均方误差损失。
  5. optim.SGD: 随机梯度下降优化器。model.parameters() 返回模型中的所有参数。
  6. optimizer.zero_grad: 将所有参数的梯度缓存清零。因为 PyTorch 默认会累积梯度,因此在每次反向传播之前需要清零。
  7. loss.backward: 计算损失相对于参数的梯度。
  8. optimizer.step: 执行一步优化更新。
  9. model.train(): 将模型设置为训练模式。这会启用一些特定于训练的操作(例如 dropout)。
  10. model.eval(): 将模型设置为评估模式。这会禁用一些特定于训练的操作,从而提高推理的效率和准确性。
  11. torch.no_grad(): 在评估模型时,禁用梯度计算,以加速计算并节省显存。
拓展知识点
  1. Autograd: PyTorch 的自动微分引擎,能够自动计算梯度。
  2. Module 和 Parameter: nn.Module 是 PyTorch 中构建神经网络的基础,Parameter 是一种张量,它会自动被 nn.Module 注册为模型的参数。
  3. 优化算法: PyTorch 提供了多种优化算法,包括 SGD、Adam、RMSprop 等。
  4. 数据加载和预处理: 使用 torch.utils.data.Datasettorch.utils.data.DataLoader 进行数据加载和预处理。
  5. GPU 加速: 使用 .to(device) 方法将模型和数据移动到 GPU 上以加速计算。
  6. 通过这些步骤和解释,你应该能够理解如何使用 PyTorch 实现简单的线性回归模型,并掌握基本的 PyTorch 使用方法。随着深入学习,你可以探索更复杂的模型和技术,例如卷积神经网络(CNNs)、递归神经网络(RNNs)以及各种深度学习的优化和正则化技巧。
## import the packages
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
  1. 导入必要的库
    • numpy:用于数值计算,虽然这里我们并没有直接用到。
    • torch:PyTorch 的核心库,用于构建和训练神经网络。
    • torch.nn:PyTorch 的神经网络模块,提供了许多常用的神经网络层和损失函数。
    • torch.optim:PyTorch 的优化器模块,提供了各种优化算法。
    • matplotlib.pyplot:用于数据可视化。
## prepare the data 
x_data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_data = torch.tensor([[3.0], [5.0], [7.0], [9.0]])
  1. 准备数据
    • x_datay_data 是训练数据,使用 torch.tensor 将它们转换为 PyTorch 张量。
## model define 
class LinearRegressionModel(nn.Module):  # Corrected the class name and parent class
    def __init__(self):
        super(LinearRegressionModel, self).__init__()
        self.linear = nn.Linear(1, 1)  # Corrected the attribute initialization

    def forward(self, x):
        return self.linear(x)
  1. 定义模型
    • 定义一个继承自 nn.Module 的线性回归模型类 LinearRegressionModel
    • __init__ 方法中,初始化一个线性层 self.linear,它接收一个输入特征并输出一个预测值。
    • forward 方法中,定义前向传播,即将输入 x 通过线性层进行计算并返回结果。
## instantiate the model
model = LinearRegressionModel()
  1. 实例化模型
    • 创建一个 LinearRegressionModel 的实例 model
## define the loss function and optimizer
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
  1. 定义损失函数和优化器
    • criterion 是均方误差损失函数 nn.MSELoss(),用于计算预测值与真实值之间的差异。
    • optimizer 是随机梯度下降优化器 optim.SGD,用于更新模型参数。model.parameters() 返回模型的所有参数,lr 是学习率。
## main part of training the model
num_epochs = 10000  # Corrected the variable name
for epoch in range(num_epochs):  # Use range() to iterate over the number of epochs
    model.train()
  1. 模型训练部分
    • num_epochs 定义训练的总轮数。
    • 使用 for epoch in range(num_epochs) 循环进行训练。
    • model.train() 将模型设置为训练模式,启用训练特定的操作(如 dropout)。
    ## forward pass
    y_pred = model(x_data)
  1. 前向传播
    • 将输入数据 x_data 传入模型,得到预测值 y_pred
    ## loss calculation
    loss = criterion(y_pred, y_data)
  1. 损失计算
    • 使用损失函数 criterion 计算预测值 y_pred 与真实值 y_data 之间的均方误差损失。
    ## backward pass
    optimizer.zero_grad()  # Clear the gradients
    loss.backward()  # Compute the gradients
    optimizer.step()  # Update the parameters
  1. 反向传播和参数更新
    • optimizer.zero_grad() 清除所有参数的梯度缓存。
    • loss.backward() 计算损失对模型参数的梯度。
    • optimizer.step() 根据计算的梯度更新模型参数。
    if (epoch + 1) % 500 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
  1. 打印损失
    • 每训练500个周期,打印一次当前的训练周期数和损失值。
## visualization of the result
model.eval()
with torch.no_grad():
    predicted = model(x_data).detach().numpy()
    plt.plot(x_data.numpy(), y_data.numpy(), 'ro', label='Original data')
    plt.plot(x_data.numpy(), predicted, label='Fitted line')
    plt.legend()
    plt.show()  # Corrected the show() method
  1. 结果可视化
    • model.eval() 将模型设置为评估模式,禁用训练特定的操作。
    • torch.no_grad() 禁用梯度计算,以加快计算速度和节省内存。
    • 使用模型对输入数据进行预测,并将预测结果从张量转换为 NumPy 数组。
    • 使用 matplotlib 绘制原始数据和拟合直线,并显示图例和图表。

通过逐行解释,理解了每个步骤的作用和相应的 PyTorch 函数的使用。这个过程演示了如何构建、训练和评估一个简单的线性回归模型。

线性回归

以下是对代码逐行解释和拓展知识点。

## import the packages
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
  1. 导入必要的库
    • numpy:用于数值计算。
    • torch:PyTorch 的核心库,用于构建和训练神经网络。
    • torch.nn:PyTorch 的神经网络模块,提供了许多常用的神经网络层和损失函数。
    • torch.optim:PyTorch 的优化器模块,提供了各种优化算法。
    • matplotlib.pyplot:用于数据可视化。
## prepare the data 
x_data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_data = torch.tensor([[3.0], [5.0], [7.0], [9.0]])
  1. 准备数据
    • x_datay_data 是训练数据,使用 torch.tensor 将它们转换为 PyTorch 张量。
## model define 
class LinearRegressionModel(nn.Module):
    def __init__(self):
        super(LinearRegressionModel, self).__init__()
        self.linear = nn.Linear(1, 1)

    def forward(self, x):
        return self.linear(x)
  1. 定义模型
    • 定义一个继承自 nn.Module 的线性回归模型类 LinearRegressionModel
    • __init__ 方法中,初始化一个线性层 self.linear,它接收一个输入特征并输出一个预测值。
    • forward 方法中,定义前向传播,即将输入 x 通过线性层进行计算并返回结果。
## instantiate the model
model = LinearRegressionModel()
  1. 实例化模型
    • 创建一个 LinearRegressionModel 的实例 model
## define the loss function and optimizer
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
  1. 定义损失函数和优化器
    • criterion 是均方误差损失函数 nn.MSELoss(),用于计算预测值与真实值之间的差异。
    • optimizer 是随机梯度下降优化器 optim.SGD,用于更新模型参数。model.parameters() 返回模型的所有参数,lr 是学习率。
## lists to store losses and parameters for visualization
losses = []
w_values = []
b_values = []
  1. 初始化列表以存储损失和参数
    • losses:用于存储每个 epoch 的损失值。
    • w_valuesb_values:分别用于存储每个 epoch 的权重和偏置。
## main part of training the model
num_epochs = 10000
for epoch in range(num_epochs):
    model.train()

    ## forward pass
    y_pred = model(x_data)

    ## loss calculation
    loss = criterion(y_pred, y_data)

    ## backward pass
    optimizer.zero_grad()  # Clear the gradients
    loss.backward()  # Compute the gradients
    optimizer.step()  # Update the parameters

    ## store the loss and parameters
    losses.append(loss.item())
    w_values.append(model.linear.weight.item())
    b_values.append(model.linear.bias.item())

    if (epoch + 1) % 500 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
  1. 模型训练部分
    • num_epochs 定义训练的总轮数。
    • 使用 for epoch in range(num_epochs) 循环进行训练。
    • model.train() 将模型设置为训练模式。
    • 前向传播:将输入数据 x_data 传入模型,得到预测值 y_pred
    • 损失计算:使用损失函数 criterion 计算预测值 y_pred 与真实值 y_data 之间的均方误差损失。
    • 反向传播和参数更新
      • optimizer.zero_grad() 清除所有参数的梯度缓存。
      • loss.backward() 计算损失对模型参数的梯度。
      • optimizer.step() 根据计算的梯度更新模型参数。
    • 存储损失和参数:将当前的损失值和模型参数(权重和偏置)存储到对应的列表中。
    • 打印损失:每训练500个周期,打印一次当前的训练周期数和损失值。
## visualization of the result
model.eval()
with torch.no_grad():
    predicted = model(x_data).detach().numpy()
    plt.plot(x_data.numpy(), y_data.numpy(), 'ro', label='Original data')
    plt.plot(x_data.numpy(), predicted, label='Fitted line')
    plt.legend()
    plt.show()
  1. 结果可视化
    • model.eval() 将模型设置为评估模式。
    • torch.no_grad() 禁用梯度计算,以加快计算速度和节省内存。
    • 使用模型对输入数据进行预测,并将预测结果从张量转换为 NumPy 数组。
    • 使用 matplotlib 绘制原始数据和拟合直线,并显示图例和图表。
## visualize the loss over epochs
plt.figure()
plt.plot(range(num_epochs), losses, label='Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss over Epochs')
plt.legend()
plt.show()
  1. 可视化损失函数
    • 创建一个新的图形窗口。
    • 使用 plt.plot(range(num_epochs), losses, label='Loss') 绘制损失值随 epoch 变化的图像。
    • 设置图像的标题、标签和图例,并显示图像。
## visualize the parameter updates
plt.figure()
plt.plot(range(num_epochs), w_values, label='Weight')
plt.plot(range(num_epochs), b_values, label='Bias')
plt.xlabel('Epoch')
plt.ylabel('Parameter value')
plt.title('Parameter updates over Epochs')
plt.legend()
plt.show()
  1. 可视化参数更新
    • 创建一个新的图形窗口。
    • 使用 plt.plot(range(num_epochs), w_values, label='Weight')plt.plot(range(num_epochs), b_values, label='Bias') 绘制模型参数(权重和偏置)随 epoch 变化的图像。
    • 设置图像的标题、标签和图例,并显示图像。

知识点拓展

  1. 模型定义

    • 继承 nn.Module 并实现 __init__forward 方法是定义 PyTorch 模型的标准方法。
    • nn.Linear 是一种常用的神经网络层,代表一个全连接层。
  2. 损失函数和优化器

    • nn.MSELoss 计算均方误差损失,是回归任务常用的损失函数。
    • optim.SGD 是随机梯度下降优化器,常用于小型和中型模型的训练。
  3. 梯度计算和参数更新

    • loss.backward() 计算损失对所有模型参数的梯度。
    • optimizer.step() 更新模型参数。
  4. 训练和评估模式

    • model.train() 启用训练模式(如 dropout)。
    • model.eval() 启用评估模式(禁用 dropout)。
  5. 数据可视化

    • matplotlib 是一个强大的数据可视化库,常用于绘制训练过程中的损失曲线和参数变化。

logistics 回归

下面是使用PyTorch实现逻辑回归的代码示例,并对每行代码及其背后的数学原理进行详细解释。

代码示例

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# 生成一些二分类数据
X, y = make_classification(n_samples=1000, n_features=10, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 转换为张量
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).view(-1, 1)
y_test = torch.tensor(y_test, dtype=torch.float32).view(-1, 1)

# 定义逻辑回归模型
class LogisticRegressionModel(nn.Module):
    def __init__(self, input_dim):
        super(LogisticRegressionModel, self).__init__()
        self.linear = nn.Linear(input_dim, 1)
    
    def forward(self, x):
        return torch.sigmoid(self.linear(x))

# 初始化模型
model = LogisticRegressionModel(input_dim=10)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
    model.train()
    
    # 前向传播
    outputs = model(X_train)
    loss = criterion(outputs, y_train)
    
    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

# 评估模型
model.eval()
with torch.no_grad():
    predictions = model(X_test)
    predicted_classes = predictions.round()
    accuracy = (predicted_classes.eq(y_test).sum() / y_test.shape[0]).item()
    print(f'Accuracy: {accuracy:.4f}')

逐行解释

  1. import torch
    import torch.nn as nn
    import torch.optim as optim
    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split

    解释:导入必要的库。torch用于构建和训练深度学习模型,nn包含神经网络的模块和类,optim包含优化器模块。make_classificationtrain_test_split用于生成和分割数据集。

  2. X, y = make_classification(n_samples=1000, n_features=10, n_classes=2, random_state=42)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    解释:生成一个二分类数据集并分割为训练集和测试集,训练集占80%,测试集占20%。

  3. X_train = torch.tensor(X_train, dtype=torch.float32)
    X_test = torch.tensor(X_test, dtype=torch.float32)
    y_train = torch.tensor(y_train, dtype=torch.float32).view(-1, 1)
    y_test = torch.tensor(y_test, dtype=torch.float32).view(-1, 1)

    解释:将numpy数组转换为PyTorch张量,并将标签调整为列向量。

  4. class LogisticRegressionModel(nn.Module):
        def __init__(self, input_dim):
            super(LogisticRegressionModel, self).__init__()
            self.linear = nn.Linear(input_dim, 1)
        
        def forward(self, x):
            return torch.sigmoid(self.linear(x))

    解释:定义逻辑回归模型:

    • __init__方法初始化线性层,输入维度为input_dim,输出维度为1。
    • forward方法实现前向传播,使用sigmoid激活函数将线性组合转换为概率值。
  5. model = LogisticRegressionModel(input_dim=10)

    解释:实例化逻辑回归模型,输入特征维度为10。

  6. criterion = nn.BCELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.01)

    解释:定义损失函数和优化器:

    • nn.BCELoss():二分类交叉熵损失函数。
    • optim.Adam(model.parameters(), lr=0.01):Adam优化器,学习率为0.01。
  7. num_epochs = 100
    for epoch in range(num_epochs):
        model.train()
        
        outputs = model(X_train)
        loss = criterion(outputs, y_train)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if (epoch+1) % 10 == 0:
            print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

    解释:训练模型:

    • num_epochs = 100:训练100个周期。
    • model.train():设置模型为训练模式。
    • outputs = model(X_train):前向传播计算输出。
    • loss = criterion(outputs, y_train):计算损失。
    • optimizer.zero_grad():梯度清零。
    • loss.backward():反向传播计算梯度。
    • optimizer.step():更新权重。
    • 每10个周期打印一次损失值。
  8. model.eval()
    with torch.no_grad():
        predictions = model(X_test)
        predicted_classes = predictions.round()
        accuracy = (predicted_classes.eq(y_test).sum() / y_test.shape[0]).item()
        print(f'Accuracy: {accuracy:.4f}')

    解释:评估模型:

    • model.eval():设置模型为评估模式。
    • with torch.no_grad():在评估过程中关闭梯度计算。
    • predictions = model(X_test):计算测试集的预测值。
    • predicted_classes = predictions.round():将概率值四舍五入为0或1。
    • accuracy = (predicted_classes.eq(y_test).sum() / y_test.shape[0]).item():计算准确率。
    • 打印准确率。

数学原理逐行解释

  1. Sigmoid激活函数

    $$ \sigma(z) = \frac{1}{1 + e^{-z}} $$

    将输入的线性组合转换为0到1之间的概率值。

  2. 线性组合

  3. $$ z = mathbf{w}^T \mathbf{x} + b $$

    其中,(\mathbf{w})是权重向量,(\mathbf{x})是输入特征向量,(b)是偏置。

  4. 损失函数(二分类交叉熵): [ L = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i)] ] 其中,(y_i)是真实标签,(\hat{y}_i)是预测的概率值,(N)是样本总数。

  5. 梯度下降和优化: 通过Adam优化器更新权重:

    $$ \theta = \theta - \eta \cdot \nabla_{\theta} L $$

    其中,(\eta)是学习率,(\nabla_{\theta} L)是损失函数相对于权重的梯度。

    以上是使用PyTorch实现逻辑回归的代码示例及其数学原理的详细解释。如果有任何问题或需要进一步的详细解释,请告诉我!

多维特征输入

import torch
import numpy as np
import matplotlib.pyplot as plt
import os

# Check the current working directory
print(f"Current working directory: {os.getcwd()}")
  1. 导入必要的库

    • torch:PyTorch库,用于构建和训练神经网络。
    • numpy:用于处理数组和矩阵的库。
    • matplotlib.pyplot:用于绘制图表的库。
    • os:用于操作系统相关功能的库。
  2. 打印当前工作目录:确保当前工作目录正确,以便找到数据文件。

# Ensure the file path is correct
file_path = 'E:/Python-projects/pytorch/练习/diabetes.csv'
if not os.path.isfile(file_path):
    raise FileNotFoundError(f"{file_path} not found in the current directory.")
  1. 确保文件路径正确:指定数据文件的路径,并检查文件是否存在。如果文件不存在,则抛出 FileNotFoundError
# Prepare dataset
xy = np.genfromtxt(file_path, delimiter=',', dtype=np.float32, skip_header=1)
x_data = torch.from_numpy(xy[:, :-1])
y_data = torch.from_numpy(xy[:, [-1]])
  1. 准备数据集
    • 使用 np.genfromtxt 函数加载CSV文件,指定逗号分隔,数据类型为浮点数,并跳过第一行(列标题)。
    • x_data:提取所有行,除了最后一列的所有列(特征数据)。
    • y_data:提取所有行,只保留最后一列(标签数据)。
    • numpy 数组转换为 torch 张量。
# Design model using class
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
  1. 设计模型
    • 创建一个继承自 torch.nn.ModuleModel 类。
    • 在初始化函数 __init__ 中定义三层全连接层(linear layers),每层后接一个Sigmoid激活函数。
    • forward 方法定义了前向传播过程,将输入数据依次通过每一层和激活函数。
model = Model()
  1. 实例化模型:创建模型的实例。
# Construct loss and optimizer
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
  1. 构建损失函数和优化器
    • criterion:二元交叉熵损失函数,用于衡量模型输出与真实标签之间的差距。
    • optimizer:随机梯度下降优化器,用于更新模型参数,学习率设为0.001。
epoch_list = []
loss_list = []
nums_epoch = 10000
  1. 初始化训练参数
    • epoch_list:用于存储每个epoch的编号。
    • loss_list:用于存储每个epoch的损失值。
    • nums_epoch:设定训练的总轮数为10000。
# Training cycle: forward, backward, update
for epoch in range(nums_epoch):
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    if epoch % 100 == 0:
        print(f'Epoch [{epoch}/{nums_epoch}], Loss: {loss.item():.4f}')
    epoch_list.append(epoch)
    loss_list.append(loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
  1. 训练循环
    • 对于每一个训练周期(epoch),执行以下步骤:
      • 前向传播:将输入数据 x_data 传入模型,得到预测值 y_pred
      • 计算损失:使用损失函数 criterion 计算预测值与真实值之间的损失。
      • 每100个epoch打印一次当前的损失值。
      • 将当前epoch编号和损失值分别添加到 epoch_listloss_list 中。
      • 反向传播:调用 optimizer.zero_grad() 清零梯度,loss.backward() 计算梯度,optimizer.step() 更新模型参数。
# Plot the loss curve
plt.plot(epoch_list, loss_list)
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.title('Loss Curve')
plt.show()
  1. 绘制损失曲线
    • 使用 matplotlib 绘制训练过程中损失值随epoch变化的曲线图,横轴为epoch编号,纵轴为损失值。

类函数的详细解释:当然,以下是 Model 类的逐行解释:

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()
  1. 定义 Model:这个类继承自 torch.nn.Module,用于定义一个神经网络模型。

  2. 初始化函数 __init__

    • super(Model, self).__init__():调用父类 torch.nn.Module 的初始化方法。这是初始化任何 nn.Module 子类的标准做法,确保父类的初始化方法被调用,从而正确初始化对象。

    • self.linear1 = torch.nn.Linear(8, 6):定义第一个全连接层(线性层),输入维度为8,输出维度为6。这意味着第一层接收8个输入特征,并输出6个特征。

    • self.linear2 = torch.nn.Linear(6, 4):定义第二个全连接层,输入维度为6,输出维度为4。这意味着第二层接收6个输入特征,并输出4个特征。

    • self.linear3 = torch.nn.Linear(4, 1):定义第三个全连接层,输入维度为4,输出维度为1。这意味着第三层接收4个输入特征,并输出1个特征。

    • self.sigmoid = torch.nn.Sigmoid():定义一个 Sigmoid 激活函数。Sigmoid 函数将输入映射到 (0, 1) 范围内,常用于输出概率值。

def forward(self, x):
    x = self.sigmoid(self.linear1(x))
    x = self.sigmoid(self.linear2(x))
    x = self.sigmoid(self.linear3(x))
    return x
  1. 定义前向传播函数 forward
    • def forward(self, x):定义前向传播函数,该函数接收输入 x,并返回输出结果。所有 torch.nn.Module 子类都需要定义这个方法,用于指定数据如何通过网络进行前向传播。

    • x = self.sigmoid(self.linear1(x)):将输入 x 传递给第一个全连接层 self.linear1,得到的输出通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给 x。这一行可以分解为:

      1. self.linear1(x):计算线性变换,输出维度为6。
      2. self.sigmoid(...):对线性变换结果应用 Sigmoid 激活函数。
    • x = self.sigmoid(self.linear2(x)):将经过第一个线性层和激活函数后的输出 x 传递给第二个全连接层 self.linear2,得到的输出再次通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给 x。这一行同样可以分解为:

      1. self.linear2(x):计算线性变换,输出维度为4。
      2. self.sigmoid(...):对线性变换结果应用 Sigmoid 激活函数。
    • x = self.sigmoid(self.linear3(x)):将经过第二个线性层和激活函数后的输出 x 传递给第三个全连接层 self.linear3,得到的输出再一次通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给 x。这一行也可以分解为:

      1. self.linear3(x):计算线性变换,输出维度为1。
      2. self.sigmoid(...):对线性变换结果应用 Sigmoid 激活函数。
    • return x:返回最终输出 x,这是经过三层全连接层和三次 Sigmoid 激活后的结果。

总结:这个 Model 类定义了一个简单的三层全连接神经网络,每层使用 Sigmoid 激活函数进行非线性变换。前向传播过程中,输入数据依次通过每个线性层和激活函数,最终输出一个 (0, 1) 范围内的值,通常用于二分类任务的概率预测。

以diabetes为例子进行的各种算法实践

KNN算法

项目逐行解释和说明
import numpy as np
import matplotlib.pyplot as plt
import os
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
  1. 导入必要的库:引入了numpy进行数值计算,matplotlib进行数据可视化,os进行文件操作,sklearn的预处理和模型选择模块进行数据标准化和分割数据集,sklearn的邻近算法模块进行KNN分类,sklearn的度量模块进行评估。
print(f"Current working directory: {os.getcwd()}")
  1. 打印当前工作目录:帮助确定文件的路径。
file_path = 'E:/Python-projects/pytorch/练习/diabetes.csv'
if not os.path.isfile(file_path):
    raise FileNotFoundError(f"{file_path} not found in the current directory.")
  1. 检查文件路径:确保数据文件存在。如果文件不存在,抛出文件未找到的异常。
xy = np.genfromtxt(file_path, delimiter=',', dtype=np.float32, skip_header=1)
x_data = xy[:, :-1]
y_data = xy[:, -1]
  1. 读取数据:使用numpy从CSV文件中读取数据,跳过文件头。x_data包含特征数据,y_data包含标签数据。
scaler = StandardScaler()
x_data = scaler.fit_transform(x_data)
  1. 标准化特征:使用StandardScaler标准化特征数据,使每个特征的均值为0,标准差为1,有助于提高模型性能。
x_train, x_val, y_train, y_val = train_test_split(x_data, y_data, test_size=0.2, random_state=42)
  1. 划分数据集:将数据集划分为训练集和验证集,验证集占20%,通过设定随机种子random_state确保结果可重复。
k = 5
knn = KNeighborsClassifier(n_neighbors=k)
  1. 定义KNN分类器:选择K值为5,初始化KNN分类器。
knn.fit(x_train, y_train)
  1. 训练KNN分类器:使用训练集训练KNN分类器。
y_train_pred = knn.predict(x_train)
y_val_pred = knn.predict(x_val)
  1. 预测训练集和验证集:对训练集和验证集进行预测。
train_accuracy = accuracy_score(y_train, y_train_pred)
val_accuracy = accuracy_score(y_val, y_val_pred)
  1. 计算准确率:计算训练集和验证集的准确率。
print(f'Train Accuracy: {train_accuracy:.4f}')
print(f'Validation Accuracy: {val_accuracy:.4f}')
  1. 打印准确率:输出训练集和验证集的准确率。
print("\nClassification Report on Validation Set:\n", classification_report(y_val, y_val_pred))
print("\nConfusion Matrix on Validation Set:\n", confusion_matrix(y_val, y_val_pred))
  1. 打印分类报告和混淆矩阵:输出分类报告(包括精确度、召回率和F1分数)和混淆矩阵。
epochs = range(1, 2)
train_acc_list = [train_accuracy]
val_acc_list = [val_accuracy]

plt.plot(epochs, train_acc_list, label='Train Accuracy')
plt.plot(epochs, val_acc_list, label='Validation Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.title('Accuracy Curves')
plt.legend()
plt.show()
  1. 可视化训练集和验证集准确率:绘制训练集和验证集准确率的曲线图。
def predict_knn(knn_model, input_data, scaler):
    input_data = scaler.transform([input_data])  # 标准化输入数据
    output = knn_model.predict_proba(input_data)
    return output[0][1]  # 返回患病的概率
  1. 定义预测函数:定义一个函数predict_knn,用于预测输入数据的患病概率。首先标准化输入数据,然后使用predict_proba方法预测概率。
example_input = [6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0]  # 示例数据点
  1. 示例输入数据:提供一个示例输入数据点。
predicted_prob = predict_knn(knn, example_input, scaler)
print(f"Predicted probability of having the disease: {predicted_prob:.4f}")
  1. 预测概率并输出:调用predict_knn函数预测示例数据点的患病概率,并输出结果。
threshold = 0.5
if predicted_prob >= threshold:
    print("The model predicts that there is a high probability of having the disease.")
else:
    print("The model predicts that there is a low probability of having the disease.")
  1. 根据阈值打印最终诊断:根据设定的阈值(例如0.5),输出最终诊断结果。
KNN算法的数学原理和推导

K近邻(K-Nearest Neighbors, KNN)是一种基于实例的学习算法,它在分类和回归任务中都非常有效。其核心思想是:给定一个待分类的输入实例,找到训练集中与该实例最相似的K个实例,然后通过这K个实例的类别来预测该输入实例的类别。

数学原理:
  1. 计算距离:对于每一个待分类的实例,计算其与训练集中所有实例的距离。常用的距离度量方法有欧氏距离、曼哈顿距离等。对于特征向量 (\mathbf{x}) 和 (\mathbf{y}),欧氏距离计算公式为: [ d(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2} ]
  2. 选择最近的K个邻居:根据计算出的距离,对所有训练实例进行排序,选择距离最小的K个实例。
  3. 投票决策
    • 分类任务:对K个邻居的类别进行投票,票数最多的类别即为预测类别(多数表决法)。
    • 回归任务:对K个邻居的数值进行平均,作为预测值。
算法步骤:
  1. 存储训练集:将训练数据集存储在内存中。
  2. 计算距离:对于每一个待分类的实例,计算它与训练集中所有实例的距离。
  3. 选择K个最近邻居:找到距离最近的K个训练实例。
  4. 投票或平均:根据K个最近邻居的类别或数值进行投票或平均,得到最终的预测结果。

KNN算法简单直观,适用于小规模数据集。在处理大规模数据集时,计算距离的开销较大,因此在实际应用中常结合KD树、球树等数据结构进行优化,以提高效率。

分析结果分析和解释

准确率(Accuracy):准确率表示模型在训练集和验证集上的表现,通过计算正确预测的实例占总实例数的比例来衡量。高准确率表明模型在数据集上的表现较好。

分类报告(Classification Report):分类报告提供了更详细的评估指标,包括精确度(Precision)、召回率(Recall)和F1分数(F1-Score)。这些指标帮助我们了解模型在不同类别上的表现。

精确度(Precision):表示在所有被预测为正类的实例中,实际为正类的比例。 召回率(Recall):表示在所有实际为正类的实例中,被正确预测为正类的比例。 F1分数(F1-Score):精确度和召回率的调和平均数,用于综合评价模型的表现。 混淆矩阵(Confusion Matrix):混淆矩阵显示了模型在验证集上的预测结果,其中每个元素表示真实标签和预测标签的组合。混淆矩阵帮助我们直观地了解模型的分类性能。

真阳性(TP):正确预测为正类的实例数。 假阳性(FP):错误预测为正类的实例数。 真阴性(TN):正确预测为负类的实例数。 假阴性(FN):错误预测为负类的实例数。 通过以上分析和解释,我们可以全面了解模型的性能,并根据需要进行改进。KNN算法虽然简单,但通过合理选择K值和特征标准化,可以获得较好的分类效果

计算距离:对于一个新的数据点,计算它与训练集中所有数据点的距离。 选择K个最近邻:找出距离最近的K个邻居。 投票/平均:在分类任务中,对K个邻居的类别进行投票,选出最多的类别作为预测类别;在回归任务中,对K个邻居的值进行平均,作为预测结果。 提高KNN性能的方法 选择合适的K值:K值的选择对KNN的性能影响很大。通常可以通过交叉验证来选择最佳的K值。 数据标准化:标准化或归一化特征可以避免某些特征在距离计算中占据主导地位。 距离度量方法:不同的距离度量方法(如欧氏距离、曼哈顿距离等)对KNN的性能有不同的影响。可以根据具体问题选择合适的距离度量方法。

优化改进
详细分析KNN分类结果

根据你提供的结果,我们可以通过多个角度来详细分析KNN分类器的性能。

  1. 最佳K值的选择
  • 最佳K值:37
  • 训练集准确率:77.36%
  • 验证集准确率:77.27%

最佳K值的选择通过交叉验证确定,在本例中为37。这个K值在训练集和验证集上都取得了较高的准确率,表明模型在这两个数据集上的性能较为均衡。

  1. 准确率、精确度、召回率和F1分数

  2. 分类报告:

Classification Report on Validation Set:
              precision    recall  f1-score   support

         0.0       0.77      0.92      0.84        99
         1.0       0.78      0.51      0.62        55

    accuracy                           0.77       154
   macro avg       0.77      0.71      0.73       154
weighted avg       0.77      0.77      0.76       154
  1. 解释:
  • 精确度(Precision):对于模型预测为正类(有病)的样本,有多少比例是真正有病的。
    • 类别0(无病):0.77
    • 类别1(有病):0.78
  • 召回率(Recall):对于实际为正类的样本,模型正确识别出了多少。
    • 类别0(无病):0.92
    • 类别1(有病):0.51
  • F1分数:精确度和召回率的调和平均数,用来衡量模型的综合性能。
    • 类别0(无病):0.84
    • 类别1(有病):0.62
  1. 分析:
  • 模型对类别0(无病)的预测性能较好,精确度和召回率都较高,F1分数为0.84。
  • 模型对类别1(有病)的预测性能相对较差,尤其是召回率(0.51),这意味着有很多实际有病的样本没有被正确识别出来。
  • 综合来看,模型的整体准确率为77.27%,但在类别1上的表现需要改进。
  1. 混淆矩阵
Confusion Matrix on Validation Set:
 [[91  8]
 [27 28]]
  1. 解释:
  • True Positives (TP):28,正确预测为有病的样本数量。
  • True Negatives (TN):91,正确预测为无病的样本数量。
  • False Positives (FP):8,错误预测为有病的无病样本数量(误报)。
  • False Negatives (FN):27,错误预测为无病的有病样本数量(漏报)。
  1. 分析
  • 高误报率:8个无病样本被错误预测为有病,可能导致不必要的进一步检测或治疗。
  • 高漏报率:27个有病样本被错误预测为无病,可能导致患者得不到及时治疗。
  • 类别不平衡:类别1(有病)样本较少(55个),这可能导致模型对这一类别的预测性能较差。
  1. 预测结果分析
  • 示例输入:给定示例输入的预测概率为0.5405,高于0.5的阈值,因此模型预测有较高的患病概率。
  • 实际应用:在实际应用中,可以根据业务需求调整阈值。如果希望减少漏报,可以降低阈值;如果希望减少误报,可以提高阈值。
  1. 进一步改进模型的建议

数据增强和采样: - 增加类别1(有病)的样本数量,平衡数据集。 - 使用过采样(如SMOTE)或欠采样技术。

特征选择和工程: - 进一步分析特征的重要性,去除冗余或不相关特征。 - 进行特征组合或生成新的特征。

模型调优: - 尝试不同的距离度量方法(如曼哈顿距离)。 - 调整K值范围,进一步细化网格搜索。

集成学习方法: - 使用多个KNN分类器的集成(如Bagging)来提升模型的稳健性。