(9) PyTorch 深層学習: 畳み込みニューラル ネットワーク (GoogleNet ネットワーク アーキテクチャの開始モジュール モジュールは、畳み込みニューラル ネットワーク アーキテクチャです)

1. GoogleNet ネットワーク構造: (一般的に使用される基本的なネットワーク アーキテクチャ。メイン アーキテクチャとしてよく使用され、独自のニーズに合わせて変更されます)

青いブロック: たたみ込み

赤いブロック: プーリング

黄:ソフトマックス

緑: ステッチ レイヤー

たとえば、畳み込みカーネルが 3x3 または 5x5 の場合など、ニューラル ネットワークを構築するときに選択が難しいハイパーパラメータもあります。GoogleNet はこれらすべての畳み込みを使用して結果をまとめます. 畳み込みカーネルは使いやすく、その重みは比較的大きく、他のルートの重みは重要ではありません.いくつかの候補が提供されます。最適なものを選択してください。

ここに画像の説明を挿入

上の写真のフレームがインセプション モジュールです。図のインセプションモジュール以外にも種類があります。例えば:

ここに画像の説明を挿入

黄色のブロックは 1x1 畳み込みカーネル (畳み込みカーネルのチャネルは入力チャネル (16) に依存) であり、チャネル数を増減できます。(1x1 畳み込みカーネルの役割は後述)

2. 畳み込みニューラル ネットワークの最大のジレンマは、計算量が多すぎることです。下の図に示すように、最初の畳み込み (192 チャネル -> 32 チャネル、畳み込みカーネル サイズ 5x5) には 120,422,400 回の計算があり、チャネル数 (192 -> 16) は 1x1 畳み込みカーネルの関数によって変更されます。ボリュームを通すのと同じ チャネルを変更するための製品カーネル サイズは 5x5 (16→32) モデルは複雑に見えますが、実際の計算量 (12433648) は前の 10 分の 1 です。他の畳み込み重みを引き続き試すことができます。(1x1 畳み込みは、ニューラル ネットワーク内のニューラル ネットワークと呼ばれることもあります)。1x1 畳み込みカーネルは、チャネル数を変更することもできます。

ここに画像の説明を挿入

3. 以下の図に示すように、ネットワーク構造を調整し、最後に構造ブロックをつなぎ合わせます。

ここに画像の説明を挿入

4. 上記のネットワーク構造の各ブランチのコードは次のとおりです。

import

# 分支1:卷积层构造(输入通道:in_channels,输出通道:24,卷积核大小:1)
self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)
# 分支1:均值池化
branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
# 分支1:对均值池化层得到的层进行卷积
branch_pool = self.branch_pool(branch_pool)

# 分支2:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
self.branch_1x1 = nn.Conv2d(in_channels, 16, kernel_size=1)
branch_1x1 = self.branch_1x1(x)

# 分支3:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
self.branch_5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
# 分支3:卷积层构造(输入通道:16,输出通道:24,卷积核大小:5)
self.branch_5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)

branch_5x5 = self.branch_5x5_1(x)
branch_5x5 = self.branch_5x5_2(branch_5x5)

# 分支4:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
self.branch_3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch_3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
self.branch_3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

branch_3x3 = self.branch_3x3_1(x)
branch_3x3 = self.branch_3x3_2(branch_3x3)
branch_3x3 = self.branch_3x3_3(branch_3x3)

# 将上面4个分支的结果拼接在一起
output = [branch_pool, branch_1x1, branch_5x5, branch_3x3]
return torch.cat(output, dim=1)  # 沿着维度1(dim=1)将output拼接起来(维度:0,12,3

5. 上記のコードを以前のブログ投稿 (8)、完全なコードに統合します。

############## GoogleNet网络架构中的 inception module 模块为本次网络架构
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),      # 将PIL格式图像转换成Tensor矩阵向量(维度28x28转换成1x28x28,1:为RGB通道)【 [0...255]--->[0,1] 】
    transforms.Normalize((0.1307, ), (0.3081, ))   # 均一化处理(均值、标准差)
])
# 训练集数据
train_dataset = datasets.MNIST(root='../dataset/mnist/',
                               train=True,
                               download=True,
                               transform=transform)
# 加载训练集数据
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
# 测试集数据集
test_dataset = datasets.MNIST(root='../dataset/mnist/',
                              train=False,
                              download=True,
                              transform=transform)
# 加载测试集数据集
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)

class Inception_A(torch.nn.Module):
    def __init__(self, in_channels):
        super(Inception_A, self).__init__()
        # 分支1:卷积层构造(输入通道:in_channels,输出通道:24,卷积核大小:1)
        self.branch_pool = torch.nn.Conv2d(in_channels, 24, kernel_size=1)

        # 分支2:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
        self.branch_1x1 = torch.nn.Conv2d(in_channels, 16, kernel_size=1)

        # 分支3:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
        self.branch_5x5_1 = torch.nn.Conv2d(in_channels, 16, kernel_size=1)
        # 分支3:卷积层构造(输入通道:16,输出通道:24,卷积核大小:5)
        self.branch_5x5_2 = torch.nn.Conv2d(16, 24, kernel_size=5, padding=2)

        # 分支4:卷积层构造(输入通道:in_channels,输出通道:16,卷积核大小:1)
        self.branch_3x3_1 = torch.nn.Conv2d(in_channels, 16, kernel_size=1)
        self.branch_3x3_2 = torch.nn.Conv2d(16, 24, kernel_size=3, padding=1)
        self.branch_3x3_3 = torch.nn.Conv2d(24, 24, kernel_size=3, padding=1)

    # 前向传播
    def forward(self, x):
        # 分支1:均值池化
        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
        # 分支1:对均值池化层得到的层进行卷积
        branch_pool = self.branch_pool(branch_pool)
        # 分支2:卷积
        branch_1x1 = self.branch_1x1(x)
        # 分支3:卷积
        branch_5x5 = self.branch_5x5_1(x)
        branch_5x5 = self.branch_5x5_2(branch_5x5)
        # 分支4:卷积
        branch_3x3 = self.branch_3x3_1(x)
        branch_3x3 = self.branch_3x3_2(branch_3x3)
        branch_3x3 = self.branch_3x3_3(branch_3x3)

        output = [branch_pool, branch_1x1, branch_5x5, branch_3x3]
        return torch.cat(output, dim=1)    # 沿着维度1(dim=1)将output拼接起来(维度:0,12,3class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)  # 1个通道-->10个通道
        self.conv2 = torch.nn.Conv2d(88, 20, kernel_size=5) # 经过上面4个分支得到88层,所以设计88层

        self.incep1 = Inception_A(in_channels=10)
        self.incep2 = Inception_A(in_channels=20)

        self.mp = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(1408, 10)


    def forward(self, x):
        in_size = x.size(0)
        x = F.relu(self.mp(self.conv1(x)))  # 首先进行conv1(x)卷积,得到10层通道,然后mp最大值池化,relu激活
        x = self.incep1(x)                  # (即Google-Net神经网络后,得到88层)
        x = F.relu(self.mp(self.conv2(x)))  # conv2(x)卷积将88-->20层,然后mp最大值池化,relu激活
        x = self.incep2(x)                  # 经过Google-Net神经网络后,又得到88层
        x = x.view(in_size, -1)             # 展开变成向量
        x = self.fc(x)                      # 进行全连接,进行分类
        return x


# 想使用模型,就实例化即可,可以直接调用
model = Net()

# 将模型放到GPU上运行,需要加如下两行代码(训练集、测试集中的输入值、实际值也需要加载到GPU上)
# device = torch.device("cude: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 循环训练 #########################
def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 准备数据(input:输入,target:实际值)
        inputs, target = data
        # 将输入、实际值加载到GPU
        # inputs, target = inputs.to(device), target.to(device)
        # 梯度清0
        optimizer.zero_grad()
        # 前向传播(经过设计的神经网络)
        outputs = model(inputs)
        # 交叉熵损失函数计算
        loss = criterion(outputs, target)
        # 反向传播
        loss.backward()
        # 参数优化
        optimizer.step()
        # 累计loss
        running_loss += loss.item()
        # 数据集一共有batch_idx个数据,每隔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
            # 将输入、实际值加载到GPU中
            # inputs, target = inputs.to(device), target.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            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()


ここに画像の説明を挿入

内容は主にステーションbのアップマスター:劉二さんについてです。

おすすめ

転載: blog.csdn.net/K_AAbb/article/details/125836113