打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
AI算法卷积神经网络CNN原理与实现(定义测试及训练过程)

   (定义测试及训练过程)


https://m.toutiao.com/is/BK95h3Q/ 


1 算法思想

卷积神经网络通过所设计的卷积核与图像进行卷积操作,提取图像中的某些特征。通过卷积网络层数的加深,提取的特征从局部到整体,从而对物体进行识别。

2 算法推导

2.1 边缘特征检测示例

图1. 图像边缘检测

假如有一张图像,想让计算机搞清楚图片上有什么物体,可以做的事情是检测图像的水平边缘与垂直边缘。

(1)卷积操作

如图1所示,是一个6*6的灰度图像,构造一个3*3的矩阵,在卷积神经网络中,通常称为filter(过滤器),对6*6的图像进行卷积操作得到4*4的矩阵。

图2. 卷积操作

如图2所示,3*3的filter与6*6的灰度图像左上角3*3区域进行卷积3*1+0*0+1*(-1)+1*1+5*0+8*(-1)+2*1+7*0+2*(-1)=-5,从而得到4*4左上角的-5。

(2)边缘提取

图3. 垂直边缘提取

为什么这种卷积操作可以得到图像的边缘?

如图3所示,原图是6*6的灰度图像,10的部分为亮区域,0的部分为暗区域。从10->0为垂直边缘。用一个3*3的过滤器,对图像进行卷积操作,得到图像中间亮,两边暗。亮暗交接处为边缘。

(3)过滤器类型

图4. 垂直过滤器与水平过滤器

通过图4的垂直过滤器与水平过滤器可实现垂直边缘与水平边缘检测。

图5. 过滤器类型

图5列出了一些常用的过滤器,如sobel算子,scharr算子等。在卷积神经网络中,把这些过滤器当成我们要学习的参数,卷积网络训练的目标就是去理解过滤器的参数。

2.2 边缘填充padding

图6. padding示意图

(1)为什么进行padding?

按照上述的描述,图片每经过一次卷积运算,会存在以下两个问题:

  • 图片会缩小导致无法进行深层卷积运算;
  • 原始图片边缘信息对输出贡献得少,输出图片丢失边缘信息。

(2)怎样进行padding?

  • 假设输入的图片大小:

  • 过滤器的大小:

  • 两个水平与垂直边缘padding大小:

  • 则经过卷积操作的输出:

2.3 卷积步长stride

图7. 卷积步长为2

  • 对于input=7*7,filter=3*3,stride=2,padding=0;
  • 经卷积操作输出:
  • 通用表示:
    ,
    表示向下取整。

2.4 彩色图像的卷积

以上讲述的卷积都是灰度图像的,如果想要在RGB图像上进行卷积,过滤器的大小不再是3*3,而是3*3*3,最后的3对应为通道数(channels)。卷积生成图像中,每个位置的像素值,为3*3*3的过滤器与图像相应位置相乘累加。如图8所示,过滤器依次在RGB图像上滑动,最终生成的图像大小为4*4。

图8. 单一filter彩色图像卷积

另外一个问题是,如果我们在不仅仅在图像总检测一种类型的特征,而是要同时检测垂直边缘、水平边缘、45度边缘等,也就是多个过滤器的问题。如果有两个过滤器,最终生成图像为4*4*2的立方体,这里的2来源于我们采用了2个过滤器。

图9. 多个filter彩色图像卷积

写成通用的形式:

  • 输入维度:

  • 每个滤波器的维度:

  • 权重维度:

  • 偏置维度:

  • 输出维度:

  • 其中:

2.5 池化层Pooling

图10. Max pooling示意图

在卷积神经网络中,除了使用卷积层外,还使用池化层来缩减模型大小,提高计算速度。池化层分为最大池化层(max pooling)与平均池化层(average pooling)。池化层中的max pooling是求每个过滤器滑动区域内的最大值;average pooling是求每个过滤器滑动区域内的平均值。

  • 经过padding后的输出:

  • 一般情况下padding=0,输出表示:

2.6 简单卷积神经网络示例LeNet-5

LeNet(LeNet-5)由两个卷积层和三个全连接层构成。

  • 这两卷积层的卷积核均为5*5,第一个卷积层的输出通道为6,第二卷积层的输出通道为16。
  • 每个池化层窗口的大小为2*2,步长为2。
  • 三个全连接层分别有120、84和10个输出。

3 算法实现

(1)下载数据集

import torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimfrom torchvision import datasets, transformsimport timefrom matplotlib import pyplot as pltpipline_train = transforms.Compose([ #随机旋转图片 transforms.RandomHorizontalFlip(), #將圖片尺寸resize到32x32 transforms.Resize((32,32)), #將圖片轉化為Tensor格式 transforms.ToTensor(), #正則化(當模型出現過擬合的情況時,用來降低模型的複雜度) transforms.Normalize((0.1307,),(0.3081,))])pipline_test = transforms.Compose([ #將圖片尺寸resize到32x32 transforms.Resize((32,32)), transforms.ToTensor(), transforms.Normalize((0.1307,),(0.3081,))])#下載数据集train_set = datasets.MNIST(root='./data', train=True, download=True, transform=pipline_train)test_set = datasets.MNIST(root='./data', train=False, download=True, transform=pipline_test)#載入数据集trainloader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)testloader = torch.utils.data.DataLoader(test_set, batch_size=32, shuffle=False)

(2)搭建LeNet-5网络结构,并确定前向传递过程

class LeNet(nn.Module):    def __init__(self):        super(LeNet, self).__init__()        self.conv1 = nn.Conv2d(1, 6, 5)        self.relu = nn.ReLU()        self.maxpool1 = nn.MaxPool2d(2, 2)        self.conv2 = nn.Conv2d(6, 16, 5)        self.maxpool2 = nn.MaxPool2d(2, 2)        self.fc1 = nn.Linear(16*5*5, 120)        self.fc2 = nn.Linear(120, 84)        self.fc3 = nn.Linear(84, 10)    def forward(self, x):        x = self.conv1(x)        x = self.relu(x)        x = self.maxpool1(x)        x = self.conv2(x)        x = self.maxpool2(x)        x = x.view(-1, 16*5*5)        x = F.relu(self.fc1(x))        x = F.relu(self.fc2(x))        x = self.fc3(x)        output = F.log_softmax(x, dim=1)        return output

(3)将定义好的网络结构部署至CPU/GPU上,并定义优化器

#建立模型,部署gpu或cpudevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')model = LeNet().to(device)#定义优化器optimizer = optim.Adam(model.parameters(), lr=0.001)

(4)定义训练过程

def train_runner(model, device, trainloader, optimizer, epoch):    #訓練模型, 啟用 BatchNormalization 和 Dropout, 將BatchNormalization和Dropout置為True    model.train()    total = 0    correct =0.0    #enumerate迭代已載入的数据集    for i, data in enumerate(trainloader, 0):        inputs, labels = data        #把模型部署到device上        inputs, labels = inputs.to(device), labels.to(device)        #初始化梯度        optimizer.zero_grad()        #儲存訓練結果        outputs = model(inputs)        #計算損失和        #多分類情況通常使用cross_entropy(交叉熵損失函式), 而對於二分類問題, 通常使用sigmoid        loss = F.cross_entropy(outputs, labels)        #获取最大概率的預測結果        #dim=1表示返回每一行的最大值對應的列下標        predict = outputs.argmax(dim=1)        total += labels.size(0)        correct += (predict == labels).sum().item()        #反向傳播        loss.backward()        #更新参数        optimizer.step()        if i % 1000 == 0:            #loss.item()表示當前loss的數值            print('Train Epoch{} \t Loss: {:.6f}, accuracy: {:.6f}%'.format(epoch, loss.item(), 100*(correct/total)))            Loss.append(loss.item())            Accuracy.append(correct/total)    return loss.item(), correct/total

(5)定义测试过程

def test_runner(model, device, testloader): #模型驗證, 必須要寫, 否則只要有輸入数据, 即使不訓練, 它也會改變權值 model.eval() #統計模型正確率, 設定初始值 correct = 0.0 test_loss = 0.0 total = 0 #torch.no_grad將不會計算梯度, 也不會進行反向傳播 with torch.no_grad(): for data, label in testloader: data, label = data.to(device), label.to(device) output = model(data) test_loss += F.cross_entropy(output, label).item() predict = output.argmax(dim=1) #計算正確數量 total += label.size(0) correct += (predict == label).sum().item() #計算損失值 print('test_avarage_loss: {:.6f}, accuracy: {:.6f}%'.format(test_loss/total, 100*(correct/total)))

(6)执行训练与测试

if __name__=='__main__':    epoch = 5    Loss = []    Accuracy = []    for epoch in range(1, epoch + 1):        print('start_time', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))        loss, acc = train_runner(model, device, trainloader, optimizer, epoch)        Loss.append(loss)        Accuracy.append(acc)        test_runner(model, device, testloader)        print('end_time: ', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), '\n')    print(model)    torch.save(model, './models/model-mnist.pth') #儲存模型    print('Finished Training')    plt.subplot(2, 1, 1)    plt.plot(Loss)    plt.title('Loss')    plt.show()    plt.subplot(2, 1, 2)    plt.plot(Accuracy)    plt.title('Accuracy')    plt.show()

(7)保存网络模型

print(model)torch.save(model, './models/model-mnist.pth') #儲存模型
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
可视化卷积神经网络的特征和过滤器
利用PyTorch实现LeNet-5
UC头条:[Python机器学习]实验14 手写体卷积神经网络1
PyTorch之LeNet-5:利用PyTorch实现最经典的LeNet-5卷积神经网络对手写数字图片识别CNN
深入浅出卷积神经网络及实现!
深度学习第23讲:PyTorch入门及快速上手指南
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服