昇思MindSpore学习笔记6-03计算机视觉--ResNet50图像分类

摘要:

        记录MindSpore AI框架使用ResNet50神经网络模型,选择Bottleneck残差网络结构对CIFAR-10数据集进行分类的过程、步骤和方法。包括环境准备、下载数据集、数据集加载和预处理、构建模型、模型训练、模型测试等。

一、

1.图像分类

最基础的计算机视觉应用

有监督学习类别

给定一张图像(猫、狗、飞机、汽车等等)

        判断图像所属的类别

使用ResNet50网络

        对CIFAR-10数据集进行分类

2.ResNet网络

ResNet50网络

        2015年微软实验室提出

        ILSVRC2015图像分类竞赛第一名

        传统卷积神经网络

                一系列卷积层和池化层堆叠

                堆叠到一定深度时会出现退化问题

56层网络与20层网络训练误差和测试误差图

        CIFAR-10数据集

        56层网络比20层网络训练误差和测试误差更大

        随着网络加深,误差并没有减小

3.残差网络结构

Residual Network

        减轻退化问题

        实现搭建较深的网络结构(突破1000层)

ResNet网络在CIFAR-10数据集上的训练误差与测试误差图

        虚线         训练误差

        实线         测试误差

        网络层数越深,训练误差和测试误差越小

二、环境准备

%%capture captured_output
# 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
# 查看当前 mindspore 版本
!pip show mindspore

输出:

Name: mindspore
Version: 2.2.14
Summary: MindSpore is a new open source deep learning training/inference framework that could be used for mobile, edge and cloud scenarios.
Home-page: https://www.mindspore.cn
Author: The MindSpore Authors
Author-email: contact@mindspore.cn
License: Apache 2.0
Location: /home/nginx/miniconda/envs/jupyter/lib/python3.9/site-packages
Requires: asttokens, astunparse, numpy, packaging, pillow, protobuf, psutil, scipy
Required-by: 

三、数据集准备与加载

1.数据集

CIFAR-10数据集

        60000张32*32的彩色图像

                50000张训练图片

                10000张评估图片

        10个类别

        每类有6000张图

2.下载数据集

download接口

        下载

        解压

        仅支持解析二进制版本的CIFAR-10文件(CIFAR-10 binary version)

from download import download
​
url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz"
​
download(url, "./datasets-cifar10-bin", kind="tar.gz", replace=True)

输出:

Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz (162.2 MB)file_sizes: 100%|█████████████████████████████| 170M/170M [00:01<00:00, 113MB/s]
Extracting tar.gz file...
Successfully downloaded / unzipped to ./datasets-cifar10-bin
'./datasets-cifar10-bin'

数据集目录结构:

datasets-cifar10-bin/cifar-10-batches-bin
├── batches.meta.text
├── data_batch_1.bin
├── data_batch_2.bin
├── data_batch_3.bin
├── data_batch_4.bin
├── data_batch_5.bin
├── readme.html
└── test_batch.bin

3.加载数据

mindspore.dataset.Cifar10Dataset接口

        加载数据集

        图像增强操作

import mindspore as ms
import mindspore.dataset as ds
import mindspore.dataset.vision as vision
import mindspore.dataset.transforms as transforms
from mindspore import dtype as mstype
​
data_dir = "./datasets-cifar10-bin/cifar-10-batches-bin"  # 数据集根目录
batch_size = 256  # 批量大小
image_size = 32  # 训练图像空间大小
workers = 4  # 并行线程个数
num_classes = 10  # 分类数量
​
def create_dataset_cifar10(dataset_dir, usage, resize, batch_size, workers):
​data_set = ds.Cifar10Dataset(dataset_dir=dataset_dir,usage=usage,num_parallel_workers=workers,shuffle=True)
​trans = []if usage == "train":trans += [vision.RandomCrop((32, 32), (4, 4, 4, 4)),vision.RandomHorizontalFlip(prob=0.5)]
​trans += [vision.Resize(resize),vision.Rescale(1.0 / 255.0, 0.0),vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),vision.HWC2CHW()]
​target_trans = transforms.TypeCast(mstype.int32)
​# 数据映射操作data_set = data_set.map(operations=trans,input_columns='image',num_parallel_workers=workers)
​data_set = data_set.map(operations=target_trans,input_columns='label',num_parallel_workers=workers)
​# 批量操作data_set = data_set.batch(batch_size)
​return data_set
​
​
# 获取处理后的训练与测试数据集
​
dataset_train = create_dataset_cifar10(dataset_dir=data_dir,usage="train",resize=image_size,batch_size=batch_size,workers=workers)
step_size_train = dataset_train.get_dataset_size()
​
dataset_val = create_dataset_cifar10(dataset_dir=data_dir,usage="test",resize=image_size,batch_size=batch_size,workers=workers)
step_size_val = dataset_val.get_dataset_size()

4.显示CIFAR-10训练数据集

import matplotlib.pyplot as plt
import numpy as np
​
data_iter = next(dataset_train.create_dict_iterator())
​
images = data_iter["image"].asnumpy()
labels = data_iter["label"].asnumpy()
print(f"Image shape: {images.shape}, Label shape: {labels.shape}")
​
# 训练数据集中,前六张图片所对应的标签
print(f"Labels: {labels[:6]}")
​
classes = []
​
with open(data_dir + "/batches.meta.txt", "r") as f:for line in f:line = line.rstrip()if line:classes.append(line)
​
# 训练数据集的前六张图片
plt.figure()
for i in range(6):plt.subplot(2, 3, i + 1)image_trans = np.transpose(images[i], (1, 2, 0))mean = np.array([0.4914, 0.4822, 0.4465])std = np.array([0.2023, 0.1994, 0.2010])image_trans = std * image_trans + meanimage_trans = np.clip(image_trans, 0, 1)plt.title(f"{classes[labels[i]]}")plt.imshow(image_trans)plt.axis("off")
plt.show()

输出:

Image shape: (256, 3, 32, 32), Label shape: (256,)
Labels: [3 3 6 4 7 4]

四、构建网络

残差网络结构(Residual Network)

        有效减轻ResNet退化问题

        实现更深的网络结构设计

        提高网络的训练精度

        堆叠残差网络构建ResNet50网络

1.构建残差网络结构

残差网络结构图

残差网络由两个分支构成

        主分支

                堆叠系列卷积操作得到

                输出的特征矩阵()

        shortcuts(图中弧线表示)

                从输入直接到输出

        主分支F(x)加上shortcuts输出的特征矩阵x得到F(x)+x

        Relu激活函数

        输出

残差网络结构主要由两种

        Building Block

                用于较浅的ResNet网络,如ResNet18和ResNet34

        Bottleneck

                用于层数较深的ResNet网络,如ResNet50、ResNet101和ResNet152

Building Block

Building Block结构图

主分支有两层卷积网络结构:

        第一层网络

                输入channel为64

                3×33×3卷积层

                Batch Normalization层

                Relu激活函数层

                输出channel为64

        第二层网络

                输入channel为64

                3×33×3的卷积层

                Batch Normalization层

                输出channel为64

        融合

                主分支输出的特征矩阵

                shortcuts输出的特征矩阵

                保证shape相同

        输出Relu激活函数

主分支与shortcuts输出的特征矩阵相加

        如果shape不相同

                如输出channel是输入channel的一倍时,

                        shortcuts需要使用数量与输出channel相等

                        大小为1×11×1的卷积核进行卷积操作

                若输出的图像较输入图像缩小一倍

                        设置shortcuts中卷积操作中的stride为2

                        主分支第一层卷积操作的stride也需设置为2

定义ResidualBlockBase类实现Building Block结构代码:

from typing import Type, Union, List, Optional
import mindspore.nn as nn
from mindspore.common.initializer import Normal
​
# 初始化卷积层与BatchNorm的参数
weight_init = Normal(mean=0, sigma=0.02)
gamma_init = Normal(mean=1, sigma=0.02)
​
class ResidualBlockBase(nn.Cell):expansion: int = 1  # 最后一个卷积核数量与第一个卷积核数量相等
​def __init__(self, in_channel: int, out_channel: int,stride: int = 1, norm: Optional[nn.Cell] = None,down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlockBase, self).__init__()if not norm:self.norm = nn.BatchNorm2d(out_channel)else:self.norm = norm
​self.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)self.conv2 = nn.Conv2d(in_channel, out_channel,kernel_size=3, weight_init=weight_init)self.relu = nn.ReLU()self.down_sample = down_sample
​def construct(self, x):"""ResidualBlockBase construct."""identity = x  # shortcuts分支
​out = self.conv1(x)  # 主分支第一层:3*3卷积层out = self.norm(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm(out)
​if self.down_sample is not None:identity = self.down_sample(x)out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)
​return out

Bottleneck

Bottleneck结构图

Bottleneck结构的参数数量更少

更适合层数较深的网络

主分支有三层卷积结构

        1×11×1的卷积层

                输入channel为256

                通过数量为64

                        降维

                Batch Normalization层

                Relu激活函数层

                输出channel为64

        3×33×3卷积层

                通过数量为64

                Batch Normalization层

                Relu激活函数层

                输出channel为64

        1×11×1的卷积层

                升维

                通过数量为256

                Batch Normalization层

                输出channel为256

        融合

                主分支输出的特征矩阵

                shortcuts输出的特征矩阵

                保证特征矩阵shape相同

        输出Relu激活函数

主分支与shortcuts输出的特征矩阵相加

        如果shape不相同

                如输出channel是输入channel的一倍时,

                        shortcuts上需要使用数量与输出channel相等

                        大小为1×11×1的卷积核进行卷积操作

                如输出的图像较输入图像缩小一倍

                        设置shortcuts中卷积操作中的stride为2

                        主分支第二层卷积操作的stride也需设置为2

定义ResidualBlock类实现Bottleneck结构代码:

class ResidualBlock(nn.Cell):expansion = 4  # 最后一个卷积核的数量是第一个卷积核数量的4倍
​def __init__(self, in_channel: int, out_channel: int,stride: int = 1, down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlock, self).__init__()
​self.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=1, weight_init=weight_init)self.norm1 = nn.BatchNorm2d(out_channel)self.conv2 = nn.Conv2d(out_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)self.norm2 = nn.BatchNorm2d(out_channel)self.conv3 = nn.Conv2d(out_channel, out_channel * self.expansion,kernel_size=1, weight_init=weight_init)self.norm3 = nn.BatchNorm2d(out_channel * self.expansion)
​self.relu = nn.ReLU()self.down_sample = down_sample
​def construct(self, x):
​identity = x  # shortscuts分支
​out = self.conv1(x)  # 主分支第一层:1*1卷积层out = self.norm1(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm2(out)out = self.relu(out)out = self.conv3(out)  # 主分支第三层:1*1卷积层out = self.norm3(out)
​if self.down_sample is not None:identity = self.down_sample(x)
​out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)
​return out

2.构建ResNet50网络

ResNet网络层结构

以输入彩色图像224×224为例

        通过数量64

        卷积核大小为7×7

        stride为2的卷积层conv1

        该层输出图片大小为112×112

输出channel为64;

通过3×3最大下采样池化层

        输出图片大小为56×56

输出channel为64;

再堆叠4个残差网络块

        conv2_x

        conv3_x

        conv4_x

        conv5_x

        输出图片大小为7×7

输出channel为2048

最后通过

        平均池化层

        全连接层

        Softmax

得到分类概率。

以ResNet50网络中的conv2_x为例

每个残差网络块

由3个Bottleneck结构堆叠而成

        每个Bottleneck

                输入channel为64

                输出channel为256

示例

定义make_layer实现残差块的构建,

参数如下:

last_out_channel:上一个残差网络输出的通道数

block:                 残差网络的类别

                                        ResidualBlockBase

                                        ResidualBlock

channel:             残差网络输入的通道数

block_nums:      残差网络块堆叠的个数

stride:                 卷积移动的步幅

def make_layer(last_out_channel, block: Type[Union[ResidualBlockBase, ResidualBlock]],channel: int, block_nums: int, stride: int = 1):down_sample = None  # shortcuts分支
​if stride != 1 or last_out_channel != channel * block.expansion:
​down_sample = nn.SequentialCell([nn.Conv2d(last_out_channel, channel * block.expansion,kernel_size=1, stride=stride, weight_init=weight_init),nn.BatchNorm2d(channel * block.expansion, gamma_init=gamma_init)])
​layers = []layers.append(block(last_out_channel, channel, stride=stride, down_sample=down_sample))
​in_channel = channel * block.expansion# 堆叠残差网络for _ in range(1, block_nums):
​layers.append(block(in_channel, channel))
​return nn.SequentialCell(layers)

ResNet50网络

5个卷积结构

1个平均池化层

1个全连接层

以CIFAR-10数据集为例:

conv1

        输入图片大小为32×32

        输入channel为3

        卷积层

                卷积核数量为64

                卷积核大小为7×7

                stride为2

        Batch Normalization层

        Reul激活函数

        输出feature map大小为16×16

        输出channel为64

conv2_x

        输入feature map大小为16×16

        输入channel为64

        最大下采样池化操作

                卷积核大小为3×3

                stride为2

        堆叠3个Bottleneck

                [1×1,64;

                 3×3,64;

                 1×1,256]结构

        输出feature map大小为8×8

        输出channel为256

conv3_x

        输入feature map大小为8×8

        输入channel为256

        堆叠4个Bottleneck

                [1×1,128;

                 3×3,128;

                 1×1,512]结构

        输出feature map大小为4×4

        输出channel为512

conv4_x

        输入feature map大小为4×4

        输入channel为512

        堆叠6个Bottleneck

                [1×1,256;

                 3×3,256;

                 1×1,1024]结构

        输出feature map大小为2×2

        输出channel为1024

conv5_x

        输入feature map大小为2×2

        输入channel为1024

        堆叠3个Bottleneck

                [1×1,512;

                 3×3,512;

                 1×1,2048]结构。

        输出feature map大小为1×1

        输出channel为2048

average pool & fc

        输入channel为2048

        输出channel为分类的类别数

ResNet50模型构建代码

函数resnet50参数:

        num_classes: 分类的类别数

                                 默认类别数为1000。

        Pretrained :   下载对应的训练模型

                                 加载预训练模型中的参数

from mindspore import load_checkpoint, load_param_into_net
​
class ResNet(nn.Cell):def __init__(self, block: Type[Union[ResidualBlockBase, ResidualBlock]],layer_nums: List[int], num_classes: int, input_channel: int) -> None:super(ResNet, self).__init__()
​self.relu = nn.ReLU()# 第一个卷积层,输入channel为3(彩色图像),输出channel为64self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, weight_init=weight_init)self.norm = nn.BatchNorm2d(64)# 最大池化层,缩小图片的尺寸self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')# 各个残差网络结构块定义self.layer1 = make_layer(64, block, 64, layer_nums[0])self.layer2 = make_layer(64 * block.expansion, block, 128, layer_nums[1], stride=2)self.layer3 = make_layer(128 * block.expansion, block, 256, layer_nums[2], stride=2)self.layer4 = make_layer(256 * block.expansion, block, 512, layer_nums[3], stride=2)# 平均池化层self.avg_pool = nn.AvgPool2d()# flattern层self.flatten = nn.Flatten()# 全连接层self.fc = nn.Dense(in_channels=input_channel, out_channels=num_classes)
​def construct(self, x):
​x = self.conv1(x)x = self.norm(x)x = self.relu(x)x = self.max_pool(x)
​x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)
​x = self.avg_pool(x)x = self.flatten(x)x = self.fc(x)
​return xdef _resnet(model_url: str, block: Type[Union[ResidualBlockBase, ResidualBlock]],layers: List[int], num_classes: int, pretrained: bool, pretrained_ckpt: str,input_channel: int):model = ResNet(block, layers, num_classes, input_channel)
​if pretrained:# 加载预训练模型download(url=model_url, path=pretrained_ckpt, replace=True)param_dict = load_checkpoint(pretrained_ckpt)load_param_into_net(model, param_dict)
​return model
​
​
def resnet50(num_classes: int = 1000, pretrained: bool = False):"""ResNet50模型"""resnet50_url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt"resnet50_ckpt = "./LoadPretrainedModel/resnet50_224_new.ckpt"return _resnet(resnet50_url, ResidualBlock, [3, 4, 6, 3], num_classes,pretrained, resnet50_ckpt, 2048)

五、模型训练与评估

ResNet50预训练模型微调:

调用resnet50构造ResNet50模型

        设置pretrained参数为True

        自动下载ResNet50预训练模型

        加载预训练模型中的参数到网络中。

定义优化器和损失函数

逐epoch打印训练的损失值和评估精度

保存评估精度最高的ckpt文件(resnet50-best.ckpt)到当前路径的./BestCheckPoint

预训练模型

全连接层(fc)输出大小(对应参数num_classes)默认为1000

CIFAR10数据集共有10个分类

重置全连接层输出大小为10

展示5个epochs的训练过程

# 定义ResNet50网络
network = resnet50(pretrained=True)
​
# 全连接层输入层的大小
in_channel = network.fc.in_channels
fc = nn.Dense(in_channels=in_channel, out_channels=10)
# 重置全连接层
network.fc = fc

输出:

Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt (97.7 MB)file_sizes: 100%|█████████████████████████████| 102M/102M [00:00<00:00, 109MB/s]
Successfully downloaded file to ./LoadPretrainedModel/resnet50_224_new.ckpt
# 设置学习率
num_epochs = 5
lr = nn.cosine_decay_lr(min_lr=0.00001, max_lr=0.001, total_step=step_size_train * num_epochs,step_per_epoch=step_size_train, decay_epoch=num_epochs)
# 定义优化器和损失函数
opt = nn.Momentum(params=network.trainable_params(), learning_rate=lr, momentum=0.9)
loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
​
def forward_fn(inputs, targets):logits = network(inputs)loss = loss_fn(logits, targets)return loss
​
grad_fn = ms.value_and_grad(forward_fn, None, opt.parameters)
​
def train_step(inputs, targets):loss, grads = grad_fn(inputs, targets)opt(grads)return loss
import os
​
# 创建迭代器
data_loader_train = dataset_train.create_tuple_iterator(num_epochs=num_epochs)
data_loader_val = dataset_val.create_tuple_iterator(num_epochs=num_epochs)
​
# 最佳模型存储路径
best_acc = 0
best_ckpt_dir = "./BestCheckpoint"
best_ckpt_path = "./BestCheckpoint/resnet50-best.ckpt"
​
if not os.path.exists(best_ckpt_dir):os.mkdir(best_ckpt_dir)
import mindspore.ops as ops
​
def train(data_loader, epoch):"""模型训练"""losses = []network.set_train(True)
​for i, (images, labels) in enumerate(data_loader):loss = train_step(images, labels)if i % 100 == 0 or i == step_size_train - 1:print('Epoch: [%3d/%3d], Steps: [%3d/%3d], Train Loss: [%5.3f]' %(epoch + 1, num_epochs, i + 1, step_size_train, loss))losses.append(loss)
​return sum(losses) / len(losses)
​
def evaluate(data_loader):"""模型验证"""network.set_train(False)
​correct_num = 0.0  # 预测正确个数total_num = 0.0  # 预测总数
​for images, labels in data_loader:logits = network(images)pred = logits.argmax(axis=1)  # 预测结果correct = ops.equal(pred, labels).reshape((-1, ))correct_num += correct.sum().asnumpy()total_num += correct.shape[0]
​acc = correct_num / total_num  # 准确率
​return acc# 开始循环训练
print("Start Training Loop ...")
​
for epoch in range(num_epochs):curr_loss = train(data_loader_train, epoch)curr_acc = evaluate(data_loader_val)
​print("-" * 50)print("Epoch: [%3d/%3d], Average Train Loss: [%5.3f], Accuracy: [%5.3f]" % (epoch+1, num_epochs, curr_loss, curr_acc))print("-" * 50)
​# 保存当前预测准确率最高的模型if curr_acc > best_acc:best_acc = curr_accms.save_checkpoint(network, best_ckpt_path)
​
print("=" * 80)
print(f"End of validation the best Accuracy is: {best_acc: 5.3f}, "f"save the best ckpt file in {best_ckpt_path}", flush=True)

输出:

Start Training Loop ...
Epoch: [  1/  5], Steps: [  1/196], Train Loss: [2.412]
Epoch: [  1/  5], Steps: [101/196], Train Loss: [1.384]
Epoch: [  1/  5], Steps: [196/196], Train Loss: [0.991]
--------------------------------------------------
Epoch: [  1/  5], Average Train Loss: [1.590], Accuracy: [0.606]
--------------------------------------------------
Epoch: [  2/  5], Steps: [  1/196], Train Loss: [1.030]
Epoch: [  2/  5], Steps: [101/196], Train Loss: [0.892]
Epoch: [  2/  5], Steps: [196/196], Train Loss: [0.968]
--------------------------------------------------
Epoch: [  2/  5], Average Train Loss: [0.994], Accuracy: [0.692]
--------------------------------------------------
Epoch: [  3/  5], Steps: [  1/196], Train Loss: [0.774]
Epoch: [  3/  5], Steps: [101/196], Train Loss: [0.950]
Epoch: [  3/  5], Steps: [196/196], Train Loss: [0.642]
--------------------------------------------------
Epoch: [  3/  5], Average Train Loss: [0.836], Accuracy: [0.721]
--------------------------------------------------
Epoch: [  4/  5], Steps: [  1/196], Train Loss: [0.804]
Epoch: [  4/  5], Steps: [101/196], Train Loss: [0.824]
Epoch: [  4/  5], Steps: [196/196], Train Loss: [0.924]
--------------------------------------------------
Epoch: [  4/  5], Average Train Loss: [0.766], Accuracy: [0.737]
--------------------------------------------------
Epoch: [  5/  5], Steps: [  1/196], Train Loss: [0.843]
Epoch: [  5/  5], Steps: [101/196], Train Loss: [0.756]
Epoch: [  5/  5], Steps: [196/196], Train Loss: [0.965]
--------------------------------------------------
Epoch: [  5/  5], Average Train Loss: [0.737], Accuracy: [0.738]
--------------------------------------------------
================================================================================
End of validation the best Accuracy is:  0.738, save the best ckpt file in ./BestCheckpoint/resnet50-best.ckpt

六、可视化模型预测

定义visualize_model函数

使用验证精度最高的模型

预测CIFAR-10测试数据集

预测结果可视化

        预测字体颜色为蓝色 表示预测正确

        预测字体颜色为红色 表示预测错误

5 epochs模型在验证数据集的预测准确率在70%左右

        6张图片中会有2张预测失败

要达到理想的训练效果,训练80个epochs

import matplotlib.pyplot as plt
​
def visualize_model(best_ckpt_path, dataset_val):num_class = 10  # 对狼和狗图像进行二分类net = resnet50(num_class)# 加载模型参数param_dict = ms.load_checkpoint(best_ckpt_path)ms.load_param_into_net(net, param_dict)# 加载验证集的数据进行验证data = next(dataset_val.create_dict_iterator())images = data["image"]labels = data["label"]# 预测图像类别output = net(data['image'])pred = np.argmax(output.asnumpy(), axis=1)
​# 图像分类classes = []
​with open(data_dir + "/batches.meta.txt", "r") as f:for line in f:line = line.rstrip()if line:classes.append(line)
​# 显示图像及图像的预测值plt.figure()for i in range(6):plt.subplot(2, 3, i + 1)# 若预测正确,显示为蓝色;若预测错误,显示为红色color = 'blue' if pred[i] == labels.asnumpy()[i] else 'red'plt.title('predict:{}'.format(classes[pred[i]]), color=color)picture_show = np.transpose(images.asnumpy()[i], (1, 2, 0))mean = np.array([0.4914, 0.4822, 0.4465])std = np.array([0.2023, 0.1994, 0.2010])picture_show = std * picture_show + meanpicture_show = np.clip(picture_show, 0, 1)plt.imshow(picture_show)plt.axis('off')
​plt.show()
​
​
# 使用测试数据集进行验证
visualize_model(best_ckpt_path=best_ckpt_path, dataset_val=dataset_val)

输出:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/44159.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用6000万茅台案,了解什么是外挂?

近日&#xff0c;一起涉案金额高达6000余万元的案件出现在人们视野中。此前浙江丽水云和县公安局侦破了一起非法利用软件抢购电商平台茅台酒案。 据了解&#xff0c;犯罪嫌疑人以非法牟利为目的&#xff0c;开发了抢购软件&#xff0c;以有偿原价抢购电商平台飞天茅台酒为噱头&…

Raspberry Pi 使用 Halio 实现 13Top/s AI 加速

Raspberry Pi 5 现在可以选择用于神经网络、人工智能和机器学习的 AI 协处理器。 AI 套件包含最近宣布的用于容纳 NVMe 内存驱动器的相同 M.2 HAT&#xff0c;但装载了 13Top/s Hailo-8L AI 处理器。 据 Raspberry Pi 介绍&#xff0c;连接是通过其单通道“以 8Gbit/s 的速度…

PyCharm在线版,一周使用总结!!!

前言 过去一周&#xff0c;对pycharm在线版进行了使用&#xff0c;对云原生开发工具有了全新的认识&#xff0c;云原生开发是一种现代化的软件开发和部署方法&#xff0c;它充分利用了云计算的优势&#xff0c;特别是容器化、微服务、持续集成/持续部署&#xff08;CI/CD&…

Finalshell如何使用ssh秘钥连接服务器

[TOC](Finalshell如何使用ssh秘钥连接服务器)背景 最近在开发项目&#xff0c;需要部署到客户服务器&#xff0c;且不好暴露我们的gitlab地址去下载部署&#xff0c;只好回到解放前&#xff0c;使用工具上传文件到客户服务器部署&#x1f602; 但是手写scp命令太麻烦&#x…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第58集-agent机器人助理自动群发短信

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第58集-agent机器人助理自动群发短信 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写…

20个实验数据创造AI蛋白质里程碑!上海交大联合上海AI Lab发布FSFP,有效优化蛋白质预训练模型

蛋白质&#xff0c;这些微小而强大的生物分子&#xff0c;是生命活动的基础&#xff0c;在生物体内扮演着多种角色。然而&#xff0c;要精确地调整和优化蛋白质功能&#xff0c;以适应特定的工业或医疗需求&#xff0c;却是一项极具挑战性的任务。传统上&#xff0c;科学家们依…

python入门综合篇—资源爬取与exe打包(图形界面)

了解我的人都知道&#xff0c;我是一个谨言慎行且兴趣爱好广泛的IT&#xff0c;作为一个合格的前端&#xff0c;没事捣鼓一下python很合理吧&#xff0c;再没事搞搞java和php也很合乎逻辑吧&#xff0c;实在没事&#xff0c;玩玩linux服务器也是合乎常理的吧。所以&#xff0c;…

LlamaFactory可视化微调大模型 - 参数详解

LlamaFactory 前言 LLaMA Factory 是一个用于微调大型语言模型的强大工具,特别是针对 LLaMA 系列模型。 可以适应不同的模型架构和大小。 支持多种微调技术,如全参数微调、LoRA( Low-Rank Adaptation )、QLoRA( Quantized LoRA )等。 还给我们提供了简单实用的命令行…

Odoo免费开源ERP如何处理汽车零部件企业的OE编码问题

业务背景 汽车零部件企业在每个汽配零件都有OE编号&#xff0c;即原厂编号&#xff0c;Original Equipment Number。一个配件&#xff0c;可能可以在多个车型上使用&#xff0c;对应的&#xff0c;就有多个可兼容的OE编号。 客户下单时候&#xff0c;直接报OE编号&#xff0c…

Python数据处理之高效校验各种空值技巧详解

概要 在编程中,处理空值是一个常见且重要的任务。空值可能会导致程序异常,因此在进行数据处理时,必须确保数据的有效性。Python 提供了多种方法来处理不同数据对象的空值校验。本文将详细介绍如何对Python中的各种数据对象进行空值校验,并包含相应的示例代码,帮助全面掌握…

高速电吹风方案介绍,多档温度风速调节,转速可达105000RPM

高速电吹风是这几年很火的一种电动小家电&#xff0c;能够在较短时间内完成头发干燥&#xff0c;减少对头发的热损伤。可以通过高速电机和风扇来产生高速风流&#xff0c;迅速将头发表面的水分吹干。高速电吹风通常配有多种档位风速和温度可以设置&#xff0c;用户可以根据需要…

大数据笔记--kafka工具AKHQ

目录 一、项目背景 二、项目目标 三、项目部署 1、前提条件 2、流程 2.1、准备工作 2.2、安装AKHQ 2.3、配置AKHQ 2.4、启动AKHQ 四、验证 一、项目背景 日常运维工作中&#xff0c;越来越多的团队成员&#xff0c;包括开发人员、数据分析师和业务运营团队&#xff0…

Linux——开发工具

1.yum yum是centos中的一个软件下载安装管理客户端&#xff0c;可以下载需要的软件或者解决依赖关系问题&#xff08;如动态库&#xff09;。程序都是来源于一段源代码&#xff0c;为了方便下载&#xff0c;源代码被提前在不同的环境下编译好生成对应的yum软件包&#xff0c;存…

运营商如何通过PCDN技术提高用户服务

随着网络技术的快速发展&#xff0c;用户对网络服务的要求也在不断提高。为了满足这些需求&#xff0c;运营商需要不断创新和优化自身的技术和服务。而 PCDN (Personal Content Delivery Network)技术作为一种新兴的内容分发网络解决方案&#xff0c;为运营商提高用户服务提供了…

Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统

文章目录 Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统TFTP服务搭建测试 NFS服务搭建测试 uboot配置TFTP服务搭建测试 NFS服务搭建测试 U-BOOT配置 Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统 TFTP服务搭建 sudo apt install tftpd-hpa su…

智能车载防窒息系统设计

摘要 随着汽车行业的快速发展&#xff0c;车辆安全问题越来越受到人们的关注。其中&#xff0c;车载防窒息系统是一项重要的安全设备。本论文基于STM32单片机&#xff0c;设计了一种智能车载防窒息系统。该系统主要包括氧气浓度检测模块、温湿度检测模块、声音检测模块、光线检…

『ComfyUI』从小白到入门全套教程,奶奶看了都会了!赶紧收藏!

本文简介 Stable Diffusion WebUI 应该是大多数人第一次接触 SD 绘画的工具&#xff0c;这款工具简单易上手&#xff0c;但操作流程相对固定。如果你想拥有更自由的工作流&#xff0c;可以试试 ComfyUI。而且很多新的模型和功能在刚出现时 ComfyUI 的支持度都比较高&#xff0…

拥抱应用创新,拒绝无谓的模型竞争

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

TikTok海外运营,云手机多种变现方法

从现阶段来看&#xff0c;TikTok 的用户基数不断增长&#xff0c;已然成为全球创业者和品牌的全新竞争舞台。其用户数量近乎 20 亿&#xff0c;年轻用户占据主导&#xff0c;市场渗透率也逐年提高。不管是大型企业、著名品牌&#xff0c;还是个体创业者&#xff0c;都绝不能小觑…

matlab 有倾斜的椭圆函数图像绘制

matlab 有倾斜的椭圆函数图像绘制 有倾斜的椭圆函数图像绘制xy交叉项引入斜线负向斜线成分正向斜线成分 x^2 y^2 xy 1 &#xff08;负向&#xff09;绘制结果 x^2 y^2 - xy 1 &#xff08;正向&#xff09;绘制结果 有倾斜的椭圆函数图像绘制 为了确定椭圆的长轴和短轴的…