第10讲:卷积 神经网络(基础篇)

视频教程

1.卷积神经网络

python对所有特征融合 pytorch三个特征层融合_卷积


说明:

  • 首先明确输入的张量维度多少,输出的张量维度多少,利用各种层(做特征提取),进行这个维度上或者是每个维度上尺寸大小的变化,最终把它映射到想要的输出的这个空间里面
  • Feature Extraction:特征提取包括卷积、下采样
  • Classification:全连接
2.n个输入通道与m个输出通道

python对所有特征融合 pytorch三个特征层融合_python对所有特征融合_02


说明:

  • 3通道的输入,需要3通道的卷积核,进行数乘相加,输出
  • 每一个卷积核它的通道数量要求和输入通道是一样的

    说明;
  • 卷积核的总数有m个 = 输出通道的数目m个
  • 卷积核的总数有多少个和你输出通道的数量是一样的
    so~
  • 卷积层要求输入输出是四维张量(B,C,W,H),全连接层的输入与输出都是二维张量(B,Input_feature)。
  • 卷积层:明确:1.输入输出通道C,2.卷积核的size
3.代码图解

python对所有特征融合 pytorch三个特征层融合_python对所有特征融合_03


图1:卷积过程

python对所有特征融合 pytorch三个特征层融合_python对所有特征融合_04


图2:各个层描述

python对所有特征融合 pytorch三个特征层融合_卷积_05


图3:计算结果

4.代码
import torch
from torchvision import transforms#图像处理
from torchvision import datasets#加载数据
from torch.utils.data import DataLoader#为了构建Dataloader
import torch.nn.functional as F#为了使用relu激活函数
import torch.optim as optim#优化器的包

# 1.prepare dataset
batch_size = 64
#要使用dataset,dataloader所以要设置batch容量
transform = transforms.Compose([transforms.ToTensor(),
                               transforms.Normalize((0.1307,), (0.3081,))])
#ToTensor讲原始图片转成图像张量(维度1->3,像素值属于【0,1】
#Normalize(均值,标准差)像素值切换成0,1分布

#加载训练集
train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)

#加载测试集,都是pytorch看你需求自己下载的
test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)

#2.Design Model
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #定义卷积模型:
        # 第一个卷积层(图片channel是1所以第一个参数为输入通道1
        #第二个参数:输出通道10(即这个卷积层需要10个卷积核
        #第三个参数:卷积核尺寸:5*5)  
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
        #第二层同上:输入通道=上一层的输出通道
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
        #需要一个池化层作用主要是通过下采样降低参数量
        self.pooling = torch.nn.MaxPool2d(2)
        #需要线性层做分类,通过view操作变成一维向量(图一:4*4*20=320)
        self.fc = torch.nn.Linear(320,10)
    
    
    def forward(self, x):
        # Flatten data from (n, 1, 28, 28) to (n, 784)
        batch_size = x.size(0)#batch大小是输入x的第0个维度:样本n
        #输入x经过第一个卷积层 + 池化层 + relu激活
        x = F.relu(self.pooling(self.conv1(x)))
        #重复经历
        x = F.relu(self.pooling(self.conv2(x)))
        #将处理后二维的图片20x4x4张量转成向量,作为全连接网络的输入
        x = x.view(batch_size,-1)
        #用全连接层做转换,最后要用交叉熵计算损失,注意不要激活
        x = self.fc(x)
        return x
    
model = Net()#实例化为model        

#如果需要把计算迁移到GPU,添加这两句:
# device = torch.device("cuda:0" if torch.cuda.is_available()else"cpu")
# model.to(device)

#3.construct Loss and Optimizer
#损失函数,来计算我们模型输出的值和标准值的差距
criterion = torch.nn.CrossEntropyLoss()
#定义一个优化器,他会反向的更改相应层的权重来训练模型
optimizer = optim.SGD(model.parameters(),lr=0.01, momentum=0.5)

#4.Train and  Test
def train(epoch):#封装训练函数
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader,0):
        inputs, target = data
        #输入x,输出y
        optimizer.zero_grad()
        #清空过往梯度
        
        #forward + backward + updata
        outputs = model(inputs)
        #forward 计算y^
        loss = criterion(outputs, target)
        #(y^,y)计算损失值
        loss.backward()
        #反向传播,计算当前梯度
        optimizer.step()
        #根据梯度更新网络参数
        
        running_loss += loss.item()
        #损失累计
        #!loss拿出的值,而非构建计算图
        #每300下输出一次数据
        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():#以下不用计算梯度
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            _, predicted  = torch.max(outputs.data, dim = 1)
            #输出数据,dim =1检索每行最大值,并输出下标
            #(不关心最大值是多少,所以用_,predicted是下标)
            #dim = 1横向降维,dim = 0纵向降维
            total += labels.size(0)
            #正确率:两个张量的比较
            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()

结果:
[1, 300] loss: 0.661
[1, 600] loss: 0.178
[1, 900] loss: 0.141
Accuracy on test set:96 %
[2, 300] loss: 0.110
[2, 600] loss: 0.108
[2, 900] loss: 0.090
Accuracy on test set:97 %
[3, 300] loss: 0.087
[3, 600] loss: 0.075
[3, 900] loss: 0.075
Accuracy on test set:98 %
[4, 300] loss: 0.066
[4, 600] loss: 0.069
[4, 900] loss: 0.064
Accuracy on test set:98 %
[5, 300] loss: 0.061
[5, 600] loss: 0.054
[5, 900] loss: 0.059
Accuracy on test set:98 %
[6, 300] loss: 0.055
[6, 600] loss: 0.050
[6, 900] loss: 0.049
Accuracy on test set:98 %
[7, 300] loss: 0.042
[7, 600] loss: 0.051
[7, 900] loss: 0.048
Accuracy on test set:98 %
[8, 300] loss: 0.040
[8, 600] loss: 0.044
[8, 900] loss: 0.045
Accuracy on test set:98 %
[9, 300] loss: 0.041
[9, 600] loss: 0.041
[9, 900] loss: 0.039
Accuracy on test set:98 %
[10, 300] loss: 0.036
[10, 600] loss: 0.036
[10, 900] loss: 0.043
Accuracy on test set:98 %

5.参考

Pytorch的nn.Conv2d()详解另外一个小伙伴笔记