深度学习-->卷积神经网络(Net)

LeNet:

 

# LeNet


import d2lzh as d2l
import mxnet as mx
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import loss as gloss, nn
import time

# 构建模型

# 输入数据:神经网络的输入是一个4维张量,形状为(批量大小, 通道数, 高度, 宽度)。这里的通道数表示图像的颜色通道数,对于灰度图像为1,对于RGB图像为3。
#
# 第1个卷积层:输入的4维张量通过第一个卷积层。这个卷积层会对输入进行卷积操作,得到6个输出通道的特征图。使用sigmoid激活函数处理特征图。
#
# 第1个最大池化层:经过第1个卷积层的输出被送入第1个最大池化层。最大池化层将特征图的空间维度(高度和宽度)减小一半,并保留每个2x2区域内的最大值。
#
# 第2个卷积层:第1个最大池化层的输出被送入第2个卷积层。这个卷积层将6个输入通道的特征图转换为16个输出通道的特征图。同样使用sigmoid激活函数。
#
# 第2个最大池化层:经过第2个卷积层的输出被送入第2个最大池化层。这个池化层也会将特征图的空间维度减小一半。
#
# 全连接层1:第2个最大池化层的输出被展平为一个1维张量,并送入全连接层1。这个全连接层有120个神经元,使用sigmoid激活函数。
#
# 全连接层2:全连接层1的输出被送入全连接层2。这个全连接层有84个神经元,同样使用sigmoid激活函数。
#
# 输出层:全连接层2的输出被送入输出层。这是一个没有显式激活函数的全连接层,通常称为“输出层”。它有10个神经元,对应于最终的分类类别数量。
#
# 输出结果:输出层的结果就是最终的预测结果,其中每个神经元对应一个类别的预测概率。通常,我们会选取概率最高的类别作为最终的预测类别。


net = nn.Sequential()  # 创建一个空的神经网络容器
net.add(nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid'),
        # 添加第一个卷积层,有6个输出通道,卷积核大小为5x5,使用sigmoid激活函数
        nn.MaxPool2D(pool_size=2, strides=2),
        # 添加第一个最大池化层,池化窗口大小为2x2,步幅为2
        nn.Conv2D(channels=16, kernel_size=5, activation='sigmoid'),
        # 添加第二个卷积层,有16个输出通道,卷积核大小为5x5,使用sigmoid激活函数
        nn.MaxPool2D(pool_size=2, strides=2),
        # 添加第二个最大池化层,池化窗口大小为2x2,步幅为2
        # Dense会默认将(批量大小, 通道, 高, 宽)形状的输入转换成
        # (批量大小, 通道 * 高 * 宽)形状的输入
        nn.Dense(120, activation='sigmoid'),
        # 添加一个全连接层,有120个神经元,使用sigmoid激活函数.
        # 进入这个全连接层之前,会被展平,也就是从一个4维张量(batch_size, channels, height, width)
        # 转换为一个2维张量(batch_size, channels * height * width)。激活函数使用sigmoid。
        nn.Dense(84, activation='sigmoid'),
        # 添加另一个全连接层,有84个神经元,使用sigmoid激活函数
        nn.Dense(10))  # 最后添加一个输出层,有10个神经元,用于分类任务

ctx = d2l.try_gpu()

# 构造样本

# 构造一个高和宽均为28的单通道数据样本,并逐层进行前向计算来查看每个层的输出形状。

# 创建输入数据

x = nd.random_uniform(shape=(1, 1, 28, 28))  # 创建一个形状为(1, 1, 28, 28)的随机输入张量

net.initialize()  # 初始化神经网络

# 对每一层进行前向计算,并打印输出形状

for layer in net:  # 对神经网络中的每一层进行循环遍历
    x = layer(x)  # 将输入数据通过当前层进行前向计算
    print(layer.name, 'output shape:\t', x.shape)  # 打印当前层的名称和输出形状

# 获取数据和训练模型

batch_size = 256  # 定义批量大小
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)  # 加载Fashion-MNIST数据集


# 计算精确率
def evaluate_accuracy(data_iter, net):  # 定义计算精确率的函数
    acc_sum, n = 0.0, 0  # 初始化正确分类数和样本总数

    for x, y in data_iter:  # 对数据迭代器进行遍历,获取输入和标签
        y = y.astype('float32')  # 将标签转换为浮点数类型
        acc_sum += (net(x).argmax(axis=1) == y).sum().asscalar()  # 统计正确分类的个数
        n += y.size  # 统计样本总数
    return acc_sum / n  # 返回精确率(正确分类数除以样本总数)


# 训练模型
def train(net, train_iter, test_iter, batch_size, trainer, num_epochs):  # 定义训练模型的函数
    loss = gloss.SoftmaxCrossEntropyLoss()  # 定义交叉熵损失函数

    for epoch in range(num_epochs):  # 对每个epoch进行循环
        train_loss, train_acc, n, start = 0.0, 0.0, 0, time.time()  # 初始化训练损失、训练精确率、样本数和起始时间
        for data, label in train_iter:  # 对训练数据进行迭代
            data, label = data.as_in_context(ctx), label.as_in_context(ctx)
            with autograd.record():  # 开启自动求导
                output = net(data)  # 进行前向计算,获取模型输出
                _loss = loss(output, label).sum()  # 计算损失

            _loss.backward()  # 反向传播,计算梯度
            trainer.step(batch_size)  # 更新模型参数
            label = label.astype('float32')  # 将标签转换为浮点数类型

            train_loss += _loss.asscalar()  # 累加训练损失
            train_acc += (output.argmax(axis=1) == label).sum().asscalar()  # 累加训练精确率

            n += label.size  # 累加样本数
        test_acc = evaluate_accuracy(test_iter, net)  # 计算测试精确率

        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, ''time %.1f sec' % (
            epoch + 1, train_loss / n, train_acc / n, test_acc, time.time() - start))  # 打印每个epoch的训练损失、训练精确率、测试精确率和训练时间


# 训练模型

lr, num_epochs = 0.9, 5  # 定义学习率和训练的epoch数
net.initialize(force_reinit=True, init=init.Xavier())  # 强制初始化神经网络的参数,使用Xavier初始化方法

trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': lr})  # 定义优化器
train(net, train_iter, test_iter, batch_size, trainer, num_epochs)  # 训练模型,获取训练和测试精确率

 

AlexNet:

import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import data as gdata, nn
import os
import sys

net = nn.Sequential()
# 使用较大的11 x 11窗口来捕获物体。同时使用步幅4来较大幅度减小输出高和宽。这里使用的输出通
# 道数比LeNet中的也要大很多
net.add(nn.Conv2D(96, kernel_size=11, strides=4, activation='relu'),
        nn.MaxPool2D(pool_size=3, strides=2),
        # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
        nn.Conv2D(256, kernel_size=5, padding=2, activation='relu'),
        nn.MaxPool2D(pool_size=3, strides=2),
        # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
        # 前两个卷积层后不使用池化层来减小输入的高和宽
        nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
        nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
        nn.Conv2D(256, kernel_size=3, padding=1, activation='relu'),
        nn.MaxPool2D(pool_size=3, strides=2),
        # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
        nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
        nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
        # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
        nn.Dense(10))

X = nd.random.uniform(shape=(1, 1, 224, 224))
net.initialize()
for layer in net:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)

def load_data_fashion_mnist(batch_size, resize=None, root=os.path.join(
        '~', '.mxnet', 'datasets', 'fashion-mnist')):
    root = os.path.expanduser(root)  # 展开用户路径'~'
    transformer = []
    if resize:
        transformer += [gdata.vision.transforms.Resize(resize)]
    transformer += [gdata.vision.transforms.ToTensor()]
    transformer = gdata.vision.transforms.Compose(transformer)
    mnist_train = gdata.vision.FashionMNIST(root=root, train=True)
    mnist_test = gdata.vision.FashionMNIST(root=root, train=False)
    num_workers = 0 if sys.platform.startswith('win32') else 4
    train_iter = gdata.DataLoader(
        mnist_train.transform_first(transformer), batch_size, shuffle=True,
        num_workers=num_workers)
    test_iter = gdata.DataLoader(
        mnist_test.transform_first(transformer), batch_size, shuffle=False,
        num_workers=num_workers)
    return train_iter, test_iter

batch_size = 1
# 如出现“out of memory”的报错信息,可减小batch_size或resize
train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)

lr, num_epochs, ctx = 0.01, 5, d2l.try_gpu()
net.initialize(force_reinit=True, ctx=ctx, init=init.Xavier())
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': lr})
d2l.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx, num_epochs)

 

VGG:

import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn


# 定义一个VGG块,指定卷积层的数量num_convs和输出通道数num_channels
def vgg_block(num_convs, num_channels):
    blk = nn.Sequential()
    # 连续添加num_convs个卷积层,每个卷积层输出通道数为num_channels,卷积核大小为3x3,并使用ReLU激活函数
    for _ in range(num_convs):
        blk.add(nn.Conv2D(num_channels, kernel_size=3, padding=1, activation='relu'))
    # 添加一个2x2窗口大小的最大池化层,步幅为2,用于对特征图的高和宽减半
    blk.add(nn.MaxPool2D(pool_size=2, strides=2))
    return blk


# 创建一个具有2个卷积层和128个输出通道的VGG块
blk = vgg_block(2, 128)
blk.initialize()
x = nd.random_uniform(shape=(2, 3, 16, 16))  # 创建一个随机输入,shape为(batch_size, channels, height, width)
y = blk(x)  # 通过VGG块进行前向传播,得到输出
print(y.shape)  # 打印输出的形状

# 定义VGG网络的配置,包含每个VGG块的卷积层数量和输出通道数
conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))


# 使用给定的配置定义VGG网络
def vgg(conv_arch):
    net = nn.Sequential()
    # 添加多个VGG块,每个块都有指定的卷积层数量和输出通道数
    for (num_convs, num_channels) in conv_arch:
        net.add(vgg_block(num_convs, num_channels))
    # 添加全连接层作为分类器
    net.add(nn.Dense(4096, activation='relu'), nn.Dropout(0.5),
            nn.Dense(4096, activation='relu'), nn.Dropout(0.5),
            nn.Dense(10))  # 输出层,假设有10个分类类别
    return net


# 创建VGG网络的实例
net = vgg(conv_arch)
net.initialize()

# 创建一个随机输入,shape为(batch_size=1, channels=1, height=224, width=224)
X = nd.random.uniform(shape=(1, 1, 224, 224))

# 通过网络进行前向传播,并打印每个块的输出形状
for blk in net:
    X = blk(X)
    print(blk.name, '输出形状:\t', X.shape)

 

posted @ 2023-08-04 15:55  o-Sakurajimamai-o  阅读(90)  评论(0)    收藏  举报
-- --