2.线性模型
3.梯度下降算法
4.反向传播(用pytorch算梯度)
5.用pytorch实现线性回归
6.logistic回归
7.处理多维特征的输入
8.加载数据集
9.多分类问题
10.卷积神经网络(基础篇)_哔哩哔哩_bilibili
10.1卷积神经网络
10.1.1 卷积神经网络工作流程:
- 输入数据:输入通常是图像等网格结构数据,通常经过归一化等预处理。
- 卷积层:通过卷积核在输入上滑动,提取局部特征,输出特征图,通常接ReLU等非线性激活函数。
- 池化层:对特征图进行下采样,减少尺寸,保留重要特征,常用最大池化或平均池化。
- 多层堆叠:卷积层和池化层交替堆叠,逐层提取更抽象的特征。
- 全连接层:将特征图展平为一维向量,通过全连接层(仅由线性层串行构成)进行分类。
- 输出层:根据任务输出结果,如分类任务通过Softmax输出概率分布。
10.2 卷积层(Convolutional Layer)
10.2.1 单通道卷积
在单通道二维图像处理中,卷积操作涉及一个卷积核在图像上滑动,计算卷积核与图像局部区域的内积(仅数乘)。具体来说,假设有图像 I和卷积核 K,2D卷积操作可以表示为,如下图所示:
卷积层作用测试:
import torch
in_channels=5 # 输入通道数
out_channels=10 # 输出通道数
kernel_size=3 # 卷积核大小
batch_size=1 # 批大小
width=100 # 图像宽度
height=100 # 图像高度# 输入数据 批大小 ,输入通道数,图像宽度,图像高度
input=torch.randn(batch_size,in_channels,width,height)
#torch.randn函数会根据给定的形状生成一个服从标准正态分布(均值为0,标准差为1)的随机张量。# 卷积层 输入通道数,输出通道数,卷积核大小
#卷积层作用:对输入数据进行特征提取,提取出图像中有用的特征,并输出到下一层进行进一步处理。
conv_layer=torch.nn.Conv2d(in_channels,out_channels,kernel_size)# 卷积输出
output=conv_layer(input)print(f"输入数据尺寸:{input.shape}")
print(f"卷积层权重尺寸:{conv_layer.weight.shape}")
print(f"卷积输出尺寸:{output.shape}")
运行结果:
卷积后的
10.2.2 多通道卷积
如图所示,是多通道的卷积基本原理:图像分配一个多通道卷积核,图像的的每个通道分配到多通道卷积核的一个通道,而后每个通道根据单通道的计算方式计算,得到一个矩阵,一共可以得到多个矩阵,将这多个个矩阵求和,最终得到的结果就是多通道卷积的结果。下图为3通道和n通道卷积工作图:
注:图像通道数=卷积核通道数
若想要输出的通道数不止一个,可以增加m个同种类型的卷积核,依次进行卷积运算,将得到的m个单层通道的卷积结果罗列起来,就得到了m个通道的输出,过程如下图所示:
10.2.3 卷积层常用参数:
padding:
当想要改变输出结果的width、height时,就需要padding,如下图所示,原输出为一个 3 x 3 的矩阵,若想要将其一个 5 x 5 的矩阵时,padding操作就是在输入图像周围进行填充,填充数值为0。
测试代码:
import torchinput = [3,4,6,5,7,
2,4,6,8,2,
1,6,7,8,4,
9,7,4,6,2,
3,7,5,4,1]input=torch.Tensor(input).view(1,1,5,5)
#使用torch.Tensor(input)将这个列表转换为PyTorch的张量。
#view(1,1,5,5)将这个一维张量转换为一个四维张量,形状为1x1x5x5,
#即一个批次(batch size为1)输入通道(input channels为1)、5x5大小的图像。conv_layer=torch.nn.Conv2d(1,1,kernel_size=3,padding=1,bias=False)
#使用torch.nn.Conv2d创建一个二维卷积层。
#输入通道数为1,输出通道数为1。
#kernel_size=3表示卷积核的大小为3x3。
#padding=1表示在输入的每个维度上填充一层宽度为1的边界(用零填充),这样输出的大小与输入的大小相同。
#bias=False表示不使用偏置参数。kernel=torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
# 定义了一个3x3的卷积核,其值为1到9。
# 使用view(1,1,3,3)将一维张量转换为四维张量,形状为1x1x3x3,符合Conv2d层的权重形状要求。
# 将这个卷积核赋值给卷积层的权重conv_layer.weight.data。conv_layer.weight.data=kerneloutput=conv_layer(input)
print(output)
运行结果:
stride:
stride就是卷积核窗口在遍历图像时,每走一步的步长。如下图所示,是stride=2时的卷积步骤:
测试代码:
input = [3,4,6,5,7,
2,4,6,8,2,
1,6,7,8,4,
9,7,4,6,2,
3,7,5,4,1]input=torch.Tensor(input).view(1,1,5,5)
#使用torch.Tensor(input)将这个列表转换为PyTorch的张量。
#view(1,1,5,5)将这个一维张量转换为一个四维张量,形状为1x1x5x5,
#即一个批次(batch size为1)输入通道(input channels为1)、5x5大小的图像。conv_layer=torch.nn.Conv2d(1,1,kernel_size=3,stride=2,bias=False)
#使用torch.nn.Conv2d创建一个二维卷积层。
#输入通道数为1,输出通道数为1。
#kernel_size=3表示卷积核的大小为3x3。
#stride=2表示在输入的宽度和高度方向上,每隔2个元素移动一次。
#bias=False表示不使用偏置参数。kernel=torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
# 定义了一个3x3的卷积核,其值为1到9。
# 使用view(1,1,3,3)将一维张量转换为四维张量,形状为1x1x3x3,符合Conv2d层的权重形状要求。
# 将这个卷积核赋值给卷积层的权重conv_layer.weight.data。conv_layer.weight.data=kerneloutput=conv_layer(input)
print(output)
运行结果:
10.3 最大池化层(Max Pooling Layer)
最大池化通过在特征图的局部区域内取最大值来生成新的特征图。它在空间维度(高度和宽度)上进行操作,但不改变通道数。
假设输入特征图的形状为 [H×W×C],其中 H 是高度,W 是宽度,C 是通道数。最大池化的操作过程如下:
- 划分窗口:将特征图划分为多个不重叠的局部区域(窗口)。窗口的大小(例如 2×2)和步幅(通常与窗口大小相同)是预先设定的参数。
- 取最大值:在每个局部窗口内,取所有元素的最大值。
- 生成输出特征图:将这些最大值组成新的特征图。输出特征图的形状为 [H′×W′×C],其中 H′ 和 W′ 是输出特征图的高度和宽度。
测试代码:
import torchinput = [3,4,6,5,
2,4,6,8,
1,6,7,8,
9,7,4,6,
]input = torch.Tensor(input).view(1, 1, 4, 4)
maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)
#这里创建了一个最大池化层(MaxPool2d),kernel_size=2表示池化窗口的大小为2x2。
#最大池化层的作用是从输入的每个2x2区域中选择最大的值,
#以此来缩减特征图(feature map)的尺寸。output = maxpooling_layer(input)
print(output)
运行结果:
10.4 课上练习:
课上代码:
import torch
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt#1.定义数据预处理
#1.1 重新定义transform
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])#1.2 加载训练数据集
train_dataset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定义训练数据加载器
train_loader=DataLoader(train_dataset, batch_size=64, shuffle=True)#测试集
test_dataset = datasets.MNIST('../dataset/mnist',train=False,transform=transform)
test_loader=DataLoader(test_dataset, batch_size=64, shuffle=False)#2.定义网络结构
# 两个卷积层(conv1和conv2),分别用于提取图像特征。
# 一个池化层(pool),用于减少特征图的尺寸,保留重要信息。
# 一个全连接层(fc1),用于将提取的特征映射到10维的输出向量,对应于MNIST数据集中的10个数字类别。
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()#输入通道为1,输出通道为10,卷积核大小为5self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)# 定义第一个卷积层,输入通道数为1(因为MNIST图像为灰度图),# 输出通道数为10(即提取10种特征),卷积核大小为5x5。# H*W的图像转换为10个H*W的特征图(H`=H-5+1, W`=W-5+1)。#输入通道为10,输出通道为20,卷积核大小为5self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)# 定义第二个卷积层,输入通道数为10(来自conv1的输出),输出通道数为20(即提取20种特征),卷积核大小为5x5。# H*W的图像转换为10个H*W的特征图(H`=H-5+1, W`=W-5+1)。#池化层,池化核大小为2self.pool = torch.nn.MaxPool2d(2)# 定义一个最大池化层,池化核大小为2x2。# 池化层的主要作用是减少特征图的尺寸,同时保留重要信息。# 图像的尺寸减半H`=H/2, W`=W/2#全连接层,输入维度为320,输出维度为10self.fc1 = torch.nn.Linear(320, 10)# 定义一个全连接层,输入维度为320# (计算方法为20 * 4 * 4,因为经过两次卷积和池化后,输出的特征图尺寸为20x4x4),# 输出维度为10(对应于MNIST数据集中的10个数字类别)。def forward(self, x):batch_size = x.size(0) #获取batch_sizex=F.relu(self.pool(self.conv1(x)))#图像10x28x28,经过第一个卷积层后,图像变为 10x24x24,经过池化层后,图像变为 10x12x12。#ReLU函数的作用是将输入小于0的部分归零,大于0的部分保持不变,有助于提高模型的训练效率。x=F.relu(self.pool(self.conv2(x)))#图像10x12x12,经过第二个卷积层后,图像变为 20x8x8,经过池化层后,图像变为 20x4x4。#展平特征图x=x.view(batch_size,-1)# -1 表示自动计算展平后的维度大小。# 对于第二个卷积层后的特征图,形状为 (batch_size, 20, 4, 4),# 展平后的形状为 (batch_size, 20 * 4 * 4),x=self.fc1(x)return xmodel = Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)#3.定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)#4.训练与测试
#4.1定义训练函数
def train(epoch):running_loss = 0.0for i, data in enumerate(train_loader, 0):inputs, labels = datainputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()#forward + backward + updateoutputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()if i % 300 == 299: # print every 300 mini-batchesprint('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 300))running_loss = 0.0#4.2定义测试函数
preRate_list = []
def Net_test():correct = 0total = 0with torch.no_grad():for data in test_loader:inputs, targets = datainputs, targets = inputs.to(device), targets.to(device)outputs = model(inputs)_, predicted = torch.max(outputs.data, dim=1)total += targets.size(0)correct += (predicted == targets).sum().item()preRate_list.append(100 * correct / total)print('Accuracy of the network test images: %d %% [ %d / %d ]' % (100 * correct / total, correct, total))#4.3开始训练与测试
for epoch in range(10):train(epoch)Net_test()#5.绘制准确率与轮数的关系图
epoch_list=list(range(len(preRate_list)))
plt.plot(epoch_list,preRate_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy vs Epoch')
plt.show()
运行结果: