解析基于Pytorch的残差神经网络(ResNet18模型),并使用数据集CIFAR10来进行预测与训练

news2024/9/30 1:34:04

解析基于Pytorch的残差神经网络(ResNet18模型),并使用数据集CIFAR10来进行预测与训练

1.0、什么是残差神经网络

注:本人才疏学浅,如有纰漏,请不吝赐教

残差神经网络其实是与卷积神经网络分不开的,我们知道卷积神经网络可以由很多个卷积层,激活层,池化层组成,多少个都没问题,但是随着层数增加,需要训练一轮的计算量也增加,这也不是最接受不了的,最无奈的是,随着层数增加,网络会呈现负优化,下面详解原因。

​ 我们知道,卷积核作用是提取特征、训练卷积神经网络就是优化卷积核以减小预测值与真实值的差距,即:损失值。一个卷积核可以专注于提取一个特征,一般一个卷积层会有多个卷积核进行特征提取,如果是线性问题,我们其实只需要一层卷积就可以了,或者说大部分问题其实可以只使用一层卷积,然后不断的训练这层卷积中的卷积核,而我们之所以需要多层卷积,是希望后续的卷积层提取更高纬度的特征(这段理不理解无所谓,因为我也讲的不是很明白,或许后面我再更新)

​ 但是随着卷积层的增加,我们一般层与层之间的输入会依赖于上一层的输出,但是捏,这样有个问题,如果上一层的输出没有有效的提取到特征,如:某个卷积核是用来判断图像中间是否为一条横线,但由于这个卷积核太差,不能提取到关于横线的特征,那么此卷积核的输出就废了,后面的卷积层再怎么根据这个输出进行卷也没啥用了,即此卷积核的输出为无效数据,那不g了、所以就想了一个办法:

​ 假如现在有三层卷积:A,B,C、A层卷积后的输出为A1,B层会将A1作为输入进行卷积得到B1,但由于B1为无效数据,此时不能直接将B1作为输入放入C层,所以我们可以将A1与B1相加作为C层的输入,这样做的好处是,即使B1没多大用,但A1是有用的,这样C层的卷积还是能够获得一定的特征。

​ 总的来说,残差神经网络相当于增加了每一个输出在后面卷积的权重

2.0、如何利用Pytorch编写一个残差神经网络

这里我以 ResNet18模型 为例,这个模型是Pytorch提供的一个残差神经网络模型,18可以简单理解为层数,数值越大层数越多,但是具体只什么层,我不清楚,,,

2.1、官网模型结构

我们可以使用如下代码获取官方给的模型(我们下面的下面会复现这个模型)

import torchvision
# True表示需不需要使用官方提供的模型参数、模型就相当于一个骨架,我们对模型进行训练得到的数据会反馈给模型,让模型由骨架转变为有五脏六腑的人类,,,模型参数就相当于五脏六腑、具体使用还要看是否符合你需要训练的数据集,如,如果都是对图片进行分类,那就可以为True
resnet = torchvision.models.resnet18(pretrained=True)
print(resnet)

运行代码我们会看到这样的输出:

ResNet(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=1000, bias=True)
)
进程已结束,退出代码0

我们将其分割来看:

1、由一个开头的卷积层加上4个残差块已及最后一个全连接层组成

开头需要一个卷积层,是因为残差神经网络需要一个A1一样的输出作为后续的输入

全连接层是用来将数据变成一维,然后进行分类或者你需要的操作,,,(不理解也没关系,等下再洗将)

ResNet(
    开始的卷积层
    (layer1): Sequential()# 残差块
    (layer2): Sequential()
    (layer3): Sequential()
    (layer4): Sequential()
	全连接层
)

2.2、使用ResNet18模型处理CIFAR10训练集

CIFAR10训练集是啥,可以直接看我上一篇讲卷积神经网络的博客,里面有注释:博客

以下是数据集的官网解释:官网

大体意思是图片是32X32大小的,通道数是3通道(即RGB三颜色),

代码编写步骤:

1、获取数据集、将数据集处理为模型需要的形式

2、创建残差神经网络模型

3、创建损失函数

4、创建优化器

5、训练:

​ 1.读取一定数量的图片

​ 2、将图片放入模型进行预测

​ 3、将预测结果与真实值比较

​ 4、梯度清零、反向传播

6、测试:

​ 1.读取一定数量的图片

​ 2、将图片放入模型进行预测

​ 3、将预测结果取概率最高的作为输出并与真实值比较

​ 4、获取所有比较结果就可以得出此轮预测的正确率

代码就不写了,因为与我的卷积神经网络的博客中一样,只是模型需要变成残差神经网络就行

我们具体看残差神经网络的模型是如何编写的:

1、编写残差块:你们可以将残差块比作一个个小的模型

​ 分为定义与运行顺序:在__ init __()方法中会定义需要用到的东西,如卷积,池化,激活,归一化等等、在 forward(self, x):中会写明我们以怎样的顺序去运行卷积,池化,激活,归一化.

2、编写残差神经网络的模型

​ 和残差块中差不多、就不重复写了

代码:

# 定义残差块==========================================================================
'''
stride:卷积核滑动步长,为1则输出特征图大小与输入一致,如果为2则输出特征图为原来一半,通道数为原来2倍(因为整体不变)
downsample=None:默认为None时表示不需要进行A1+B1作为C层输入的操作、这会发生在第一个残差块中
'''
class ResidualBlock(nn.Module):
    def __init__(self, conv, bn, planes, stride=1, downsample=None):
        super(ResidualBlock, self).__init__()
        self.conv1 = conv # 就是一个卷积层,只不过由外部作为参数传入
        self.bn1 = bn# 归一化,就是将里面的每一个值映射为0->1区间,为了防止过拟合,过拟合是啥呢,我也不太清楚,但是反应的结果就是训练时的损失值很小,但是测试时的损失值很大
        self.relu = nn.ReLU(inplace=True)# 激活函数,也是一个映射,具体百度或者看我卷积神经网络的博客
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        self.downsample = downsample# 外部会传入此参数,决定是否进行A1+B1作为C层输入的操作
        self.stride = stride # 卷积核大小

    def forward(self, x):
        identity = x  # 这里就相当于先吧A1存储,如果后续需要用到就使用
        out = self.conv1(x) # 下面4步骤依次为:卷积、归一、激活、卷积、归一
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)

        # 然后判断需要需要进行A1+B1作为C层输入的操作、如果需要,因为x的值与最新的out维度大小啥的是不匹配的,需要加一些操作使其匹配
        # 因为要将out向量与identity相加求和再传递给下一个残差块,但是out是经过卷积了,且第一次卷积,卷积核数为2,
        # 即,经过第一次卷积后特征图大小减半,但由于全部特征图应该保持不变,所以我们将输入通道数由64变为128,
        # 也因此、为了identity与out匹配,即也需要将identity从64的通道数变为128,故加此一层
        if self.downsample is not None:
            identity = self.downsample(x)

        out = out + identity # 相当于 A1+B1
        out = self.relu(out) # 激活

        return out # 作为返回值,这样下一个残差块获得的输入就是 A1+B1 了
    
    
========================编写残差神经网络模型=========================================
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

'''
bias=False:偏置,此处表示不需要
num_classes=10:类别数
nn.ReLU(inplace=True):使用了inplace=True参数。这个参数的作用是直接在原有的张量上进行计算,而不是新创建一个张量。这样可以节省一定的内存空间,同时也可以提高计算效率。
'''
# 定义ResNet18模型
class ResNet18(nn.Module):
    def __init__(self, num_classes=10):
        super(ResNet18, self).__init__()
        # 具体方法参数在卷积神经网络博客中有详细介绍,我这里只说为啥是这个值
        # 因为图片是三通道,输出通道是64、然后将卷积核设置为7X7(它这里是简写),卷积核步长:2,将图片四周多加3块,变成35X35,这样更好提取边缘特征
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        
        self.bn1 = nn.BatchNorm2d(64)  # 归一化 维度不变,变的只有里面的值
        self.relu = nn.ReLU(inplace=True)
        # 池化
        self.pool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
        # 64:通道数,2:残差块数量、blocks:只循环执行次数,为2时执行一次
        self.layer1 = self._make_layer(planes=64, blocks=2)
        self.layer2 = self._make_layer(planes=128, blocks=2, stride=2)
        self.layer3 = self._make_layer(planes=256, blocks=2, stride=2)
        self.layer4 = self._make_layer(planes=512, blocks=2, stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512, num_classes)

    def _make_layer(self, planes, blocks, stride=1):
        downsample = None # 先初始化
        # 大致意思是,我们将第一个残差块不进行 A1+B1的操作,将后续的残差块进行,为啥我也不知道
        if stride != 1 or planes != 64:
            # 此处就是为 A1能够与B1相加做准备,将A1进行卷积与归一后其维度才与B1相同
            downsample = nn.Sequential(
                nn.Conv2d(int(planes/stride), planes, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes),
            )
		# 用来存储一个  self.layer1(x) 方法中需要多少个残差块,这由不同深度的残差神经网络去决定,这里是两个,固定一个加上通过变量blocks的值去决定是否还加,这样写也就是为了扩展性,不这样写也行
        layers = []
        '''
                 参数为啥要这样写 nn.Conv2d(int(planes/stride), planes, kernel_size=3, stride=stride
         正常情况下,如果stride=1,那么通道数应该是输入多少输出就是多少,但由于stride有等于2的情况,所以我们在初始通道数需要进行除法,但是除法后值是浮点数,而参数需要整型,所以使用int(),而且我这里这样写是为了迎合:
         self.layer1 = self._make_layer(planes=64, blocks=2)
         即我们开始定义的输入,因为planes变量是作为输出的定义,所以我们需要计算输入值、当输入变成:
         self.layer2 = self._make_layer(planes=128, blocks=2, stride=2)
         时,为了保证输入是输出的一半,所以这样写、也可以自己改
        '''
        layers.append(ResidualBlock(nn.Conv2d(int(planes/stride), planes, kernel_size=3, stride=stride, padding=1, bias=False), nn.BatchNorm2d(planes), planes, 1, downsample))
        for i in range(1, blocks):
            layers.append(ResidualBlock(nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False),
                                        nn.BatchNorm2d(planes), planes))

        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.pool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        # # 全局平均池化层、它的作用是将每个特征图上的所有元素取平均,得到一个指定大小的输出。在 ResNet18 中,该池化层的输出大小为 。(batch_size, 512, 1, 1)用于最终的分类任务
        x = self.avgpool(x)
        # # 作用是将张量  沿着第 1 个维度进行压平,即将  转换为一个 1 维张量,
        x = torch.flatten(x, 1)
        # # 这里对应模型的 self.fc = nn.Linear(512, num_classes),就是将一维向量经过映射缩小到 10,因为CIFAR10是个10分类问题
        x = self.fc(x)

        return x

然后、将此模型替代我上一篇卷积神经网络中的模型,进行训练与测试:
结果:
可以看到,只经过700次训练就有50%的正确率

PyDev console: starting.
Python 3.9.16 (main, Mar  8 2023, 10:39:24) [MSC v.1916 64 bit (AMD64)] on win32
runfile('C:\\Users\\11606\\PycharmProjects\\pythonProject\\src\\train.py', wdir='C:\\Users\\11606\\PycharmProjects\\pythonProject\\src')
Files already downloaded and verified
Files already downloaded and verified
训练数据集长度:50000
测试数据集长度:10000
ResNet18(
  (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu): ReLU(inplace=True)
  (pool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
  (layer1): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
    (1): ResidualBlock(
      (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer2): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResidualBlock(
      (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer3): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResidualBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (layer4): Sequential(
    (0): ResidualBlock(
      (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResidualBlock(
      (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
  (fc): Linear(in_features=512, out_features=10, bias=True)
)
----------0 轮训练开始
训练次数:100,loss:1.7689638137817383
训练次数:200,loss:1.4394694566726685
训练次数:300,loss:1.338126301765442
训练次数:400,loss:1.412974238395691
训练次数:500,loss:1.241265892982483
训练次数:600,loss:1.250759482383728
训练次数:700,loss:1.3602595329284668
整体测试集上的Loss:226.82027339935303
整体测试集上的正确率:0.505899965763092
模型已保存
----------1 轮训练开始
训练次数:800,loss:1.1243025064468384

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

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

相关文章

Java项目无法启动排查

Java项目无法启动排查 1.启动服务发现 无法写入日志也无法启动项目2.df查看磁盘占用情况 、free -h查看内存占用、top查看CPU使用率负载率3.此时磁盘满4.清理磁盘5.定时任务 1.启动服务发现 无法写入日志也无法启动项目 2.df查看磁盘占用情况 、free -h查看内存占用、top查看C…

计及源荷不确定性的综合能源生产单元运行调度与容量配置优化研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

java贸易企业工作信息管理与利润返现系统sxA5进销存程序

目 录 摘 要 I Abstract II 第1章 绪论 1 1.1 课题背景 1 1.2 研究现状 1 本章小结 1 第2章 可行性分析 2 2.1 经济可行性 2 2.2 技术可行性 2 2.3 操作可行性 2 2.4 业务流程分析 3 本章小结 3 第3章 需求分析 4 3.1 需求分析 4 …

数据库基础篇 《3. 基本的SELECT语句》

目录 1. SQL概述 1.1 SQL背景知识 1.2 SQL语言排行榜 1.3 SQL 分类 2. SQL语言的规则与规范 2.1 基本规则 2.2 SQL大小写规范 (建议遵守) 2.3 注释 2.4 命名规则(暂时了解) 2.5 数据导入指令 3. 基本的SELECT语句 3.0…

【攻城狮计划】Renesas RA2E1 运行 命名

🚩WRITE IN FRONT🚩 🔎介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四"🔎🏅荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2022博客之星TOP10…

法大大合同批量下载

1.测试需求 法大大网上80万合同需要下载下来 其实总共1392392页,20885871万条合同数据要下载下来的 2.测试需求分析与验证 2.1调通接口,取到合同列表页信息 遇到的问题: 登录页面有图形验证码,不好处理 解决: 手动登录后用已经有的cookie,如果超时需要重新登录抓取co…

ChatGPT闲谈——火出圈的为什么是 OpenAI?

ChatGPT 走入大众视野之后,AIGC 行业迎来了爆发,尤其是上个月,仿佛每一天都可能是「历史性」的一天。 现在各大网站已经有非常多的优秀创作者进行总结和分析,都是值得一阅的好文。今天本文也分享了关于ChatGPT的看法,有…

顺序表—C语言实现数据结构

本期带大家一起来用C语言代码实现顺序表🌈🌈🌈 文章目录 一、顺序表的概念✅二、顺序表的结构✅三、顺序表的实现(动态顺序表)✅一、🔶定义顺序表结构体🔶二、🔶接口的实现&#x1…

【原理图专题】案例:从集成的电平转换芯片换成三极管分立电平转换怎么就报异常

本案例是一个已经小批量量产的设备,不是我测试出来的,但是也算是我之前一手造成的,因为原理图这部分是我修改的。 异常发现最近生产的整机有部分非接读卡时无法控制到蜂鸣器发声音。我们的设计是这样的,有两个MCU互相通信,一个MCU是控制蜂鸣器的,另一个MCU通过SPI与非接芯…

UEFI Driver Services

为UEFI驱动程序提供的UEFI引导服务和UEFI运行时服务一般可分为三个方面: 驱动通常使用很少使用的服务不应该使用的服务 UEFI驱动程序通常使用的服务 下表列出了UEFI驱动程序通常使用的UEFI服务。接下来,讨论将简要描述每种服务,它们为什么…

scala函数参数

目录 可变参数如果参数列表在存在多个参数,那么可变参数一般放置在最后参数默认值,一般将有默认值的参数放置在参数列表的后面带名参数(一般不使用,除多个参数有默认值且只需给极少个参数赋值的情况) 可变参数 当有不…

无线测温在线监测系统工作原理与产品选型

摘要:本文首先介绍了无线测温在线监测系统的基本工作原理以及软硬件组成,重点介绍了在线监测的无线测温技术特点。在此研究基础上,探讨了无线测温在线监测系统在实际工作场景中的应用案例,证明了其在温度检测方面的重要应用价值。…

浅谈数字化工厂五大核心系统

一、什么是数字化工厂 数字化工厂是将数字技术应用于工厂生产、管理和运营中的一种方式,可以帮助企业提高生产效率和质量,降低成本和风险,提高竞争力和市场份额。数字化工厂是中小制造业企业自主建设制造业信息化的途径。 简道云数字化工厂解…

stm32虚拟串口无法连接,驱动安装,DFU驱动安装

虚拟usb串口设备 插上设备后, COM这里多了一个端口, 但是其用串口调试助手无法打开 在其他设备这里多了一个STM32xx Virtual COM, 更新驱动程序 浏览我的电脑以查找驱动程序让我从计算机上的可用驱动列表中选取端口(COM和LPT)厂商: STMicroelectronics 型号: STMicroelectroni…

倾斜摄影三维模型、激光点云、正射影像、数字高程模型如何实现在线浏览?

四维轻云是成都远石技术团队基于浏览器打造的一款地理空间数据管理云平台,可实现TB级大规模倾斜摄影三维模型发布管理,并支持私有化部署和高阶功能定制化开发。 1、注册登录 首先在四维轻云官网点击「立即试用」按钮,进入登录页面并点击「注…

手写vue(三)模板渲染解析

一、目标 创建一个Vue实例时,我们可以传入el配置项,去指定一个DOM元素作为Vue容器,而这个Vue容器中,可以使用例如插值表达式等Vue框架提供的语法,并且能够渲染到浏览器页面上。 而浏览器并不能解析这些Vue语法&#xf…

Ubuntu20.04软件安装大全

目录 Ubuntu20.04 软件安装大全前言1. Windows和Ubuntu双系统安装1.1 下载Ubuntu系统镜像1.2 磁盘分区1.3 GPT分区安装Ubuntu1.4 系统完成后的一些设置1.5 遇到的一些小bug 2. 换源2.1 apt换源2.2 pip换源 3. 显卡驱动安装3.1 卸载显卡驱动3.2 准备工作3.3 驱动安装3.4 验证 4.…

分享5款小软件,让你打造更舒适的办公电脑

每次发现实用的小工具,都会有种小小的成就感,这也是我喜欢收集和分享高效工具的原因。 图标定制软件——CustomizerGod CustomizerGod是一款强大的电脑图标定制软件,可以让你随心所欲地改变系统中的任何图标。你可以使用CustomizerGod来修改桌面、任务…

Node 01-Buffer

Buffer(缓冲器) 概念 Buffer 是一个类似于数组的 对象 ,用于表示固定长度的字节序列 Buffer 本质是一段内存空间,专门用来处理 二进制数据 。 特点 Buffer 大小固定且无法调整Buffer 性能较好,可以直接对计算机内存…

AI智能课程第一讲:chatgpt介绍

AI应用现状 用AI艺术创作 一个小女孩打折手电筒在侏罗世纪公园找恐龙。 AI用于医疗行业 AI辅助驾驶 AI广告投放上的应用 什么是chatgpt? chatgpt相关技术的发展 为什么用chatgpt写代码会特别的快呢? 因为它集成了GitHub上所有开发者的库公用资源&…