要快速掌握 PyTorch 进行深度学习的基础,可以按照以下学习计划表进行。这个计划表将 PyTorch 学习拆分成几个小任务,每个部分包括学习目标、例子说明和代码训练。该计划大约需要 4 周时间,每周完成一个主要主题。
- 学习目标:安装 PyTorch 并设置开发环境。
- 例子说明:
pip install torch torchvision torchaudio
- 代码训练:安装完成后,验证安装。
import torch print(torch.__version__)
- 学习目标:理解和操作张量。
- 例子说明:
x = torch.tensor([[1, 2], [3, 4]]) print(x)
- 代码训练:创建和操作不同维度的张量。
x = torch.ones(5, 3) y = torch.rand(5, 3) z = x + y print(z)
- 学习目标:理解自动求导机制。
- 例子说明:
x = torch.ones(2, 2, requires_grad=True) y = x + 2 z = y * y * 3 out = z.mean() out.backward() print(x.grad)
- 代码训练:对简单函数进行梯度计算。
- 学习目标:使用
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
- 代码训练:构建一个简单的前馈神经网络。
- 学习目标:理解损失函数和优化器。
- 例子说明:
criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
- 代码训练:设置损失函数和优化器。
- 学习目标:使用
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)
- 代码训练:加载并预处理数据。
- 学习目标:实现训练循环。
- 例子说明:
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
- 代码训练:实现完整的训练循环。
- 学习目标:评估模型性能。
- 例子说明:
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}')
- 代码训练:在测试集上评估模型性能。
- 学习目标:使用预训练模型进行迁移学习。
- 例子说明:
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)
- 代码训练:微调预训练模型。
- 学习目标:加载和使用自定义数据集。
- 例子说明:
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
- 代码训练:加载并使用自定义数据集。
- 学习目标:保存和加载模型。
- 例子说明:
torch.save(model.state_dict(), 'model.pth') model.load_state_dict(torch.load('model.pth'))
- 代码训练:保存和加载训练好的模型。
在深度学习中,张量(tensor)是最基本的数据结构,它类似于多维数组或矩阵。张量可以存储并操作各种类型的数据,包括整数、浮点数和布尔值。在 PyTorch 中,张量是由 torch.Tensor
类表示的。
- 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,则记录对该张量的操作,以便进行自动求导。
-
tensor.band torch.bitwise_and(input, other, *, out=None) -> Tensor input:第一个输入张量。 other:第二个输入张量或标量。 out:可选的,用于存储输出的张量。
- 维度(Dimension):张量可以是任意维度的,从标量(0 维)到高阶张量(N 维)都可以。
- 形状(Shape):张量的形状是指它各个维度的大小。
- 数据类型(Data Type):张量中的数据可以是不同类型的,例如整数、浮点数等。
在 PyTorch 中,可以使用 torch.Tensor
类来创建和操作张量。以下是一些常用的方法来创建张量:
-
从 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)
-
使用特定值创建:
# 创建全零张量 zeros_tensor = torch.zeros(2, 3) # 创建全一张量 ones_tensor = torch.ones(2, 3) # 创建随机张量 random_tensor = torch.rand(2, 3)
-
从现有张量创建:
# 从现有张量创建 new_tensor = torch.randn_like(zeros_tensor)
-
通过改变数据类型创建:
# 创建指定数据类型的张量 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
控制了模型对训练数据的反复学习次数。一次完整的训练轮(epoch)意味着模型对整个训练数据集进行了一次前向传播和反向传播的过程。多次迭代能够帮助模型逐渐调整参数,从而更好地拟合训练数据。 -
训练充分性
- 过少的训练轮数(欠拟合): 如果
num_epochs
设置得太小,模型可能没有足够的机会学习数据中的特征,从而导致欠拟合,即模型在训练集和测试集上的性能都不佳。 - 过多的训练轮数(过拟合): 如果
num_epochs
设置得过大,模型可能会过度拟合训练数据,学习到数据中的噪声,从而在测试集上的泛化能力变差。
-
损失函数的优化 在每一轮训练中,模型会根据损失函数的值来更新参数。随着训练轮数的增加,损失函数的值通常会逐渐减小,模型的性能会不断提高。然而,当训练到一定程度后,损失函数的改善会趋于平缓甚至停止,说明模型已经接近或达到最优状态。
-
早停机制 在实际训练过程中,我们通常不会预先确定一个非常大的
num_epochs
值,而是结合早停(Early Stopping)机制来防止过拟合。早停机制通过监控模型在验证集上的性能,当性能不再提升时提前停止训练。 -
训练和计算资源 更多的训练轮数意味着更多的计算时间和资源消耗。在设置
num_epochs
时需要权衡模型性能和训练资源之间的关系,找到一个合适的平衡点。
-
验证集性能监控:通常在每个训练轮结束后,会在验证集上评估模型性能。如果在多个训练轮数上验证集性能不再提升,可以考虑停止训练。
-
绘制学习曲线:通过绘制训练损失和验证损失随训练轮数的变化曲线(学习曲线),可以更直观地观察模型的训练过程,帮助调整
num_epochs
及其他超参数。 -
实验和调整:在实际项目中,可能需要进行多次实验,通过调整
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()
梯度下降法是一种优化算法,用于通过迭代更新参数来最小化损失函数。它广泛应用于深度学习和机器学习模型的训练中。梯度下降法的核心思想是沿着损失函数梯度的方向,以一定的步长更新参数,使损失函数逐步减小,直到达到最小值或接近最小值。
-
定义损失函数: 设损失函数为 ( J(\theta) ),其中 ( \theta ) 为参数向量。
-
梯度计算: 梯度是损失函数对参数的偏导数,记为 ( \nabla_\theta J(\theta) )。它表示损失函数在参数空间中的变化率。
-
参数更新: 在每次迭代中,参数按以下公式更新: [ \theta = \theta - \alpha \nabla_\theta J(\theta) ] 其中,( \alpha ) 为学习率,控制每次更新的步长。
-
梯度下降过程:
- 初始化参数 ( \theta )。
- 重复以下步骤,直到收敛:
- 计算当前参数下的梯度 ( \nabla_\theta J(\theta) )。
- 按梯度更新参数 ( \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()
-
数据定义:
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()
通过上述代码,我们使用梯度下降法来最小化线性回归模型的损失函数。梯度下降法的数学原理是利用损失函数的梯度信息,逐步调整模型参数,最终使得损失函数达到最小值。具体步骤包括计算梯度、更新参数,并重复这一过程直到损失函数收敛。通过可视化损失变化曲线和拟合结果,我们可以直观地观察到模型训练过程和最终效果。
在 PyTorch 中,Tensor
和 tensor
是两个相关但不同的概念,而 torch.FloatTensor
是其中的一种特定类型。让我们逐一解释它们的区别:
-
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)
-
torch.FloatTensor
:torch.FloatTensor
是一个特定类型的张量,专门用于存储 32 位浮点数。虽然在早期版本的 PyTorch 中使用得比较多,但现在更多地使用torch.tensor
和torch.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.tensor
和 torch.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.tensor
和 torch.Tensor
是现代 PyTorch 推荐使用的方法,而 torch.FloatTensor
则是早期方法,现代 PyTorch 中较少直接使用。
首先,我们需要导入 PyTorch 以及其他一些常用的库。
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
我们将创建一些简单的数据来训练我们的模型。假设我们的目标是学习一个简单的线性关系 ( 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]])
在 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)
接下来,我们实例化模型。
model = LinearRegressionModel()
我们使用均方误差(MSE)作为损失函数,并使用随机梯度下降(SGD)作为优化器。
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
现在,我们训练模型。我们将数据传递给模型,计算损失,反向传播损失并更新模型的参数。
# 训练模型
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}')
训练完成后,我们可以可视化拟合结果。
# 可视化结果
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()
torch.tensor
: 用于创建张量,是 PyTorch 中的基本数据结构。nn.Module
: PyTorch 中所有神经网络模块的基类。通过子类化nn.Module
,我们可以定义我们自己的网络。nn.Linear
: 定义一个线性层,它实现了线性变换 ( y = wx + b )。nn.MSELoss
: 计算均方误差损失。optim.SGD
: 随机梯度下降优化器。model.parameters()
返回模型中的所有参数。optimizer.zero_grad
: 将所有参数的梯度缓存清零。因为 PyTorch 默认会累积梯度,因此在每次反向传播之前需要清零。loss.backward
: 计算损失相对于参数的梯度。optimizer.step
: 执行一步优化更新。model.train()
: 将模型设置为训练模式。这会启用一些特定于训练的操作(例如 dropout)。model.eval()
: 将模型设置为评估模式。这会禁用一些特定于训练的操作,从而提高推理的效率和准确性。torch.no_grad()
: 在评估模型时,禁用梯度计算,以加速计算并节省显存。
- Autograd: PyTorch 的自动微分引擎,能够自动计算梯度。
- Module 和 Parameter:
nn.Module
是 PyTorch 中构建神经网络的基础,Parameter
是一种张量,它会自动被nn.Module
注册为模型的参数。 - 优化算法: PyTorch 提供了多种优化算法,包括 SGD、Adam、RMSprop 等。
- 数据加载和预处理: 使用
torch.utils.data.Dataset
和torch.utils.data.DataLoader
进行数据加载和预处理。 - GPU 加速: 使用
.to(device)
方法将模型和数据移动到 GPU 上以加速计算。 - 通过这些步骤和解释,你应该能够理解如何使用 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
- 导入必要的库:
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]])
- 准备数据:
x_data
和y_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)
- 定义模型:
- 定义一个继承自
nn.Module
的线性回归模型类LinearRegressionModel
。 - 在
__init__
方法中,初始化一个线性层self.linear
,它接收一个输入特征并输出一个预测值。 - 在
forward
方法中,定义前向传播,即将输入x
通过线性层进行计算并返回结果。
- 定义一个继承自
## instantiate the model
model = LinearRegressionModel()
- 实例化模型:
- 创建一个
LinearRegressionModel
的实例model
。
- 创建一个
## define the loss function and optimizer
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
- 定义损失函数和优化器:
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()
- 模型训练部分:
num_epochs
定义训练的总轮数。- 使用
for epoch in range(num_epochs)
循环进行训练。 model.train()
将模型设置为训练模式,启用训练特定的操作(如 dropout)。
## forward pass
y_pred = model(x_data)
- 前向传播:
- 将输入数据
x_data
传入模型,得到预测值y_pred
。
- 将输入数据
## loss calculation
loss = criterion(y_pred, y_data)
- 损失计算:
- 使用损失函数
criterion
计算预测值y_pred
与真实值y_data
之间的均方误差损失。
- 使用损失函数
## backward pass
optimizer.zero_grad() # Clear the gradients
loss.backward() # Compute the gradients
optimizer.step() # Update the parameters
- 反向传播和参数更新:
optimizer.zero_grad()
清除所有参数的梯度缓存。loss.backward()
计算损失对模型参数的梯度。optimizer.step()
根据计算的梯度更新模型参数。
if (epoch + 1) % 500 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
- 打印损失:
- 每训练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
- 结果可视化:
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
- 导入必要的库:
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]])
- 准备数据:
x_data
和y_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)
- 定义模型:
- 定义一个继承自
nn.Module
的线性回归模型类LinearRegressionModel
。 - 在
__init__
方法中,初始化一个线性层self.linear
,它接收一个输入特征并输出一个预测值。 - 在
forward
方法中,定义前向传播,即将输入x
通过线性层进行计算并返回结果。
- 定义一个继承自
## instantiate the model
model = LinearRegressionModel()
- 实例化模型:
- 创建一个
LinearRegressionModel
的实例model
。
- 创建一个
## define the loss function and optimizer
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
- 定义损失函数和优化器:
criterion
是均方误差损失函数nn.MSELoss()
,用于计算预测值与真实值之间的差异。optimizer
是随机梯度下降优化器optim.SGD
,用于更新模型参数。model.parameters()
返回模型的所有参数,lr
是学习率。
## lists to store losses and parameters for visualization
losses = []
w_values = []
b_values = []
- 初始化列表以存储损失和参数:
losses
:用于存储每个 epoch 的损失值。w_values
和b_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}')
- 模型训练部分:
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()
- 结果可视化:
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()
- 可视化损失函数:
- 创建一个新的图形窗口。
- 使用
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()
- 可视化参数更新:
- 创建一个新的图形窗口。
- 使用
plt.plot(range(num_epochs), w_values, label='Weight')
和plt.plot(range(num_epochs), b_values, label='Bias')
绘制模型参数(权重和偏置)随 epoch 变化的图像。 - 设置图像的标题、标签和图例,并显示图像。
-
模型定义:
- 继承
nn.Module
并实现__init__
和forward
方法是定义 PyTorch 模型的标准方法。 nn.Linear
是一种常用的神经网络层,代表一个全连接层。
- 继承
-
损失函数和优化器:
nn.MSELoss
计算均方误差损失,是回归任务常用的损失函数。optim.SGD
是随机梯度下降优化器,常用于小型和中型模型的训练。
-
梯度计算和参数更新:
loss.backward()
计算损失对所有模型参数的梯度。optimizer.step()
更新模型参数。
-
训练和评估模式:
model.train()
启用训练模式(如 dropout)。model.eval()
启用评估模式(禁用 dropout)。
-
数据可视化:
matplotlib
是一个强大的数据可视化库,常用于绘制训练过程中的损失曲线和参数变化。
下面是使用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}')
-
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_classification
和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)
解释:生成一个二分类数据集并分割为训练集和测试集,训练集占80%,测试集占20%。
-
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张量,并将标签调整为列向量。
-
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激活函数将线性组合转换为概率值。
-
model = LogisticRegressionModel(input_dim=10)
解释:实例化逻辑回归模型,输入特征维度为10。
-
criterion = nn.BCELoss() optimizer = optim.Adam(model.parameters(), lr=0.01)
解释:定义损失函数和优化器:
nn.BCELoss()
:二分类交叉熵损失函数。optim.Adam(model.parameters(), lr=0.01)
:Adam优化器,学习率为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}')
解释:训练模型:
num_epochs = 100
:训练100个周期。model.train()
:设置模型为训练模式。outputs = model(X_train)
:前向传播计算输出。loss = criterion(outputs, y_train)
:计算损失。optimizer.zero_grad()
:梯度清零。loss.backward()
:反向传播计算梯度。optimizer.step()
:更新权重。- 每10个周期打印一次损失值。
-
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()
:计算准确率。- 打印准确率。
-
Sigmoid激活函数:
$$ \sigma(z) = \frac{1}{1 + e^{-z}} $$ 将输入的线性组合转换为0到1之间的概率值。
-
线性组合:
-
$$ z = mathbf{w}^T \mathbf{x} + b $$
其中,(\mathbf{w})是权重向量,(\mathbf{x})是输入特征向量,(b)是偏置。
-
损失函数(二分类交叉熵): [ 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)是样本总数。
-
梯度下降和优化: 通过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()}")
-
导入必要的库:
torch
:PyTorch库,用于构建和训练神经网络。numpy
:用于处理数组和矩阵的库。matplotlib.pyplot
:用于绘制图表的库。os
:用于操作系统相关功能的库。
-
打印当前工作目录:确保当前工作目录正确,以便找到数据文件。
# 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.")
- 确保文件路径正确:指定数据文件的路径,并检查文件是否存在。如果文件不存在,则抛出
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]])
- 准备数据集:
- 使用
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
- 设计模型:
- 创建一个继承自
torch.nn.Module
的Model
类。 - 在初始化函数
__init__
中定义三层全连接层(linear layers),每层后接一个Sigmoid激活函数。 forward
方法定义了前向传播过程,将输入数据依次通过每一层和激活函数。
- 创建一个继承自
model = Model()
- 实例化模型:创建模型的实例。
# Construct loss and optimizer
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
- 构建损失函数和优化器:
criterion
:二元交叉熵损失函数,用于衡量模型输出与真实标签之间的差距。optimizer
:随机梯度下降优化器,用于更新模型参数,学习率设为0.001。
epoch_list = []
loss_list = []
nums_epoch = 10000
- 初始化训练参数:
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()
- 训练循环:
- 对于每一个训练周期(epoch),执行以下步骤:
- 前向传播:将输入数据
x_data
传入模型,得到预测值y_pred
。 - 计算损失:使用损失函数
criterion
计算预测值与真实值之间的损失。 - 每100个epoch打印一次当前的损失值。
- 将当前epoch编号和损失值分别添加到
epoch_list
和loss_list
中。 - 反向传播:调用
optimizer.zero_grad()
清零梯度,loss.backward()
计算梯度,optimizer.step()
更新模型参数。
- 前向传播:将输入数据
- 对于每一个训练周期(epoch),执行以下步骤:
# Plot the loss curve
plt.plot(epoch_list, loss_list)
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.title('Loss Curve')
plt.show()
- 绘制损失曲线:
- 使用
matplotlib
绘制训练过程中损失值随epoch变化的曲线图,横轴为epoch编号,纵轴为损失值。
- 使用
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()
-
定义
Model
类:这个类继承自torch.nn.Module
,用于定义一个神经网络模型。 -
初始化函数
__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
- 定义前向传播函数
forward
:-
def forward(self, x)
:定义前向传播函数,该函数接收输入x
,并返回输出结果。所有torch.nn.Module
子类都需要定义这个方法,用于指定数据如何通过网络进行前向传播。 -
x = self.sigmoid(self.linear1(x))
:将输入x
传递给第一个全连接层self.linear1
,得到的输出通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给x
。这一行可以分解为:self.linear1(x)
:计算线性变换,输出维度为6。self.sigmoid(...)
:对线性变换结果应用 Sigmoid 激活函数。
-
x = self.sigmoid(self.linear2(x))
:将经过第一个线性层和激活函数后的输出x
传递给第二个全连接层self.linear2
,得到的输出再次通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给x
。这一行同样可以分解为:self.linear2(x)
:计算线性变换,输出维度为4。self.sigmoid(...)
:对线性变换结果应用 Sigmoid 激活函数。
-
x = self.sigmoid(self.linear3(x))
:将经过第二个线性层和激活函数后的输出x
传递给第三个全连接层self.linear3
,得到的输出再一次通过 Sigmoid 激活函数进行非线性变换,然后将结果赋值给x
。这一行也可以分解为:self.linear3(x)
:计算线性变换,输出维度为1。self.sigmoid(...)
:对线性变换结果应用 Sigmoid 激活函数。
-
return x
:返回最终输出x
,这是经过三层全连接层和三次 Sigmoid 激活后的结果。
-
总结:这个 Model
类定义了一个简单的三层全连接神经网络,每层使用 Sigmoid 激活函数进行非线性变换。前向传播过程中,输入数据依次通过每个线性层和激活函数,最终输出一个 (0, 1) 范围内的值,通常用于二分类任务的概率预测。
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
- 导入必要的库:引入了numpy进行数值计算,matplotlib进行数据可视化,os进行文件操作,sklearn的预处理和模型选择模块进行数据标准化和分割数据集,sklearn的邻近算法模块进行KNN分类,sklearn的度量模块进行评估。
print(f"Current working directory: {os.getcwd()}")
- 打印当前工作目录:帮助确定文件的路径。
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.")
- 检查文件路径:确保数据文件存在。如果文件不存在,抛出文件未找到的异常。
xy = np.genfromtxt(file_path, delimiter=',', dtype=np.float32, skip_header=1)
x_data = xy[:, :-1]
y_data = xy[:, -1]
- 读取数据:使用
numpy
从CSV文件中读取数据,跳过文件头。x_data
包含特征数据,y_data
包含标签数据。
scaler = StandardScaler()
x_data = scaler.fit_transform(x_data)
- 标准化特征:使用
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)
- 划分数据集:将数据集划分为训练集和验证集,验证集占20%,通过设定随机种子
random_state
确保结果可重复。
k = 5
knn = KNeighborsClassifier(n_neighbors=k)
- 定义KNN分类器:选择K值为5,初始化KNN分类器。
knn.fit(x_train, y_train)
- 训练KNN分类器:使用训练集训练KNN分类器。
y_train_pred = knn.predict(x_train)
y_val_pred = knn.predict(x_val)
- 预测训练集和验证集:对训练集和验证集进行预测。
train_accuracy = accuracy_score(y_train, y_train_pred)
val_accuracy = accuracy_score(y_val, y_val_pred)
- 计算准确率:计算训练集和验证集的准确率。
print(f'Train Accuracy: {train_accuracy:.4f}')
print(f'Validation Accuracy: {val_accuracy:.4f}')
- 打印准确率:输出训练集和验证集的准确率。
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))
- 打印分类报告和混淆矩阵:输出分类报告(包括精确度、召回率和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()
- 可视化训练集和验证集准确率:绘制训练集和验证集准确率的曲线图。
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] # 返回患病的概率
- 定义预测函数:定义一个函数
predict_knn
,用于预测输入数据的患病概率。首先标准化输入数据,然后使用predict_proba
方法预测概率。
example_input = [6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0] # 示例数据点
- 示例输入数据:提供一个示例输入数据点。
predicted_prob = predict_knn(knn, example_input, scaler)
print(f"Predicted probability of having the disease: {predicted_prob:.4f}")
- 预测概率并输出:调用
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.")
- 根据阈值打印最终诊断:根据设定的阈值(例如0.5),输出最终诊断结果。
K近邻(K-Nearest Neighbors, KNN)是一种基于实例的学习算法,它在分类和回归任务中都非常有效。其核心思想是:给定一个待分类的输入实例,找到训练集中与该实例最相似的K个实例,然后通过这K个实例的类别来预测该输入实例的类别。
- 计算距离:对于每一个待分类的实例,计算其与训练集中所有实例的距离。常用的距离度量方法有欧氏距离、曼哈顿距离等。对于特征向量 (\mathbf{x}) 和 (\mathbf{y}),欧氏距离计算公式为: [ d(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2} ]
- 选择最近的K个邻居:根据计算出的距离,对所有训练实例进行排序,选择距离最小的K个实例。
- 投票决策:
- 分类任务:对K个邻居的类别进行投票,票数最多的类别即为预测类别(多数表决法)。
- 回归任务:对K个邻居的数值进行平均,作为预测值。
- 存储训练集:将训练数据集存储在内存中。
- 计算距离:对于每一个待分类的实例,计算它与训练集中所有实例的距离。
- 选择K个最近邻居:找到距离最近的K个训练实例。
- 投票或平均:根据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分类器的性能。
- 最佳K值的选择
- 最佳K值:37
- 训练集准确率:77.36%
- 验证集准确率:77.27%
最佳K值的选择通过交叉验证确定,在本例中为37。这个K值在训练集和验证集上都取得了较高的准确率,表明模型在这两个数据集上的性能较为均衡。
-
准确率、精确度、召回率和F1分数
-
分类报告:
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
- 解释:
- 精确度(Precision):对于模型预测为正类(有病)的样本,有多少比例是真正有病的。
- 类别0(无病):0.77
- 类别1(有病):0.78
- 召回率(Recall):对于实际为正类的样本,模型正确识别出了多少。
- 类别0(无病):0.92
- 类别1(有病):0.51
- F1分数:精确度和召回率的调和平均数,用来衡量模型的综合性能。
- 类别0(无病):0.84
- 类别1(有病):0.62
- 分析:
- 模型对类别0(无病)的预测性能较好,精确度和召回率都较高,F1分数为0.84。
- 模型对类别1(有病)的预测性能相对较差,尤其是召回率(0.51),这意味着有很多实际有病的样本没有被正确识别出来。
- 综合来看,模型的整体准确率为77.27%,但在类别1上的表现需要改进。
- 混淆矩阵
Confusion Matrix on Validation Set:
[[91 8]
[27 28]]
- 解释:
- True Positives (TP):28,正确预测为有病的样本数量。
- True Negatives (TN):91,正确预测为无病的样本数量。
- False Positives (FP):8,错误预测为有病的无病样本数量(误报)。
- False Negatives (FN):27,错误预测为无病的有病样本数量(漏报)。
- 分析:
- 高误报率:8个无病样本被错误预测为有病,可能导致不必要的进一步检测或治疗。
- 高漏报率:27个有病样本被错误预测为无病,可能导致患者得不到及时治疗。
- 类别不平衡:类别1(有病)样本较少(55个),这可能导致模型对这一类别的预测性能较差。
- 预测结果分析
- 示例输入:给定示例输入的预测概率为0.5405,高于0.5的阈值,因此模型预测有较高的患病概率。
- 实际应用:在实际应用中,可以根据业务需求调整阈值。如果希望减少漏报,可以降低阈值;如果希望减少误报,可以提高阈值。
- 进一步改进模型的建议
数据增强和采样: - 增加类别1(有病)的样本数量,平衡数据集。 - 使用过采样(如SMOTE)或欠采样技术。
特征选择和工程: - 进一步分析特征的重要性,去除冗余或不相关特征。 - 进行特征组合或生成新的特征。
模型调优: - 尝试不同的距离度量方法(如曼哈顿距离)。 - 调整K值范围,进一步细化网格搜索。
集成学习方法: - 使用多个KNN分类器的集成(如Bagging)来提升模型的稳健性。